mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 17:40:23 +03:00
Replaced redux action to create one visit by action that allows multiple visits at once
This commit is contained in:
parent
ad437f655e
commit
6fc4963663
14 changed files with 73 additions and 55 deletions
|
@ -4,7 +4,7 @@ import { MercureInfo } from '../reducers/mercureInfo';
|
||||||
import { bindToMercureTopic } from './index';
|
import { bindToMercureTopic } from './index';
|
||||||
|
|
||||||
export interface MercureBoundProps {
|
export interface MercureBoundProps {
|
||||||
createNewVisit: (visitData: CreateVisit) => void;
|
createNewVisits: (createdVisits: CreateVisit[]) => void;
|
||||||
loadMercureInfo: Function;
|
loadMercureInfo: Function;
|
||||||
mercureInfo: MercureInfo;
|
mercureInfo: MercureInfo;
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,14 @@ export function boundToMercureHub<T = {}>(
|
||||||
const pendingUpdates = new Set<CreateVisit>();
|
const pendingUpdates = new Set<CreateVisit>();
|
||||||
|
|
||||||
return (props: MercureBoundProps & T) => {
|
return (props: MercureBoundProps & T) => {
|
||||||
const { createNewVisit, loadMercureInfo, mercureInfo } = props;
|
const { createNewVisits, loadMercureInfo, mercureInfo } = props;
|
||||||
const { interval } = mercureInfo;
|
const { interval } = mercureInfo;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onMessage = (visit: CreateVisit) => interval ? pendingUpdates.add(visit) : createNewVisit(visit);
|
const onMessage = (visit: CreateVisit) => interval ? pendingUpdates.add(visit) : createNewVisits([ visit ]);
|
||||||
|
|
||||||
interval && setInterval(() => {
|
interval && setInterval(() => {
|
||||||
pendingUpdates.forEach(createNewVisit);
|
createNewVisits([ ...pendingUpdates ]);
|
||||||
pendingUpdates.clear();
|
pendingUpdates.clear();
|
||||||
}, interval * 1000 * 60);
|
}, interval * 1000 * 60);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { assoc, assocPath, reject } from 'ramda';
|
import { assoc, assocPath, last, reject } from 'ramda';
|
||||||
import { Action, Dispatch } from 'redux';
|
import { Action, Dispatch } from 'redux';
|
||||||
import { shortUrlMatches } from '../helpers';
|
import { shortUrlMatches } from '../helpers';
|
||||||
import { CREATE_VISIT, CreateVisitAction } from '../../visits/reducers/visitCreation';
|
import { CREATE_VISITS, CreateVisitsAction } from '../../visits/reducers/visitCreation';
|
||||||
import { ShortUrl, ShortUrlIdentifier } from '../data';
|
import { ShortUrl, ShortUrlIdentifier } from '../data';
|
||||||
import { buildReducer } from '../../utils/helpers/redux';
|
import { buildReducer } from '../../utils/helpers/redux';
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
|
@ -31,7 +31,7 @@ export interface ListShortUrlsAction extends Action<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ListShortUrlsCombinedAction = (
|
export type ListShortUrlsCombinedAction = (
|
||||||
ListShortUrlsAction & EditShortUrlTagsAction & ShortUrlEditedAction & ShortUrlMetaEditedAction & CreateVisitAction
|
ListShortUrlsAction & EditShortUrlTagsAction & ShortUrlEditedAction & ShortUrlMetaEditedAction & CreateVisitsAction
|
||||||
);
|
);
|
||||||
|
|
||||||
const initialState: ShortUrlsList = {
|
const initialState: ShortUrlsList = {
|
||||||
|
@ -63,12 +63,17 @@ export default buildReducer<ShortUrlsList, ListShortUrlsCombinedAction>({
|
||||||
[SHORT_URL_TAGS_EDITED]: setPropFromActionOnMatchingShortUrl<EditShortUrlTagsAction>('tags'),
|
[SHORT_URL_TAGS_EDITED]: setPropFromActionOnMatchingShortUrl<EditShortUrlTagsAction>('tags'),
|
||||||
[SHORT_URL_META_EDITED]: setPropFromActionOnMatchingShortUrl<ShortUrlMetaEditedAction>('meta'),
|
[SHORT_URL_META_EDITED]: setPropFromActionOnMatchingShortUrl<ShortUrlMetaEditedAction>('meta'),
|
||||||
[SHORT_URL_EDITED]: setPropFromActionOnMatchingShortUrl<ShortUrlEditedAction>('longUrl'),
|
[SHORT_URL_EDITED]: setPropFromActionOnMatchingShortUrl<ShortUrlEditedAction>('longUrl'),
|
||||||
[CREATE_VISIT]: (state, { shortUrl: { shortCode, domain, visitsCount } }) => assocPath(
|
[CREATE_VISITS]: (state, { createdVisits }) => assocPath(
|
||||||
[ 'shortUrls', 'data' ],
|
[ 'shortUrls', 'data' ],
|
||||||
state.shortUrls && state.shortUrls.data && state.shortUrls.data.map(
|
state.shortUrls?.data?.map(
|
||||||
(shortUrl) => shortUrlMatches(shortUrl, shortCode, domain)
|
(currentShortUrl) => {
|
||||||
? assoc('visitsCount', visitsCount, shortUrl)
|
// Find the last of the new visit for this short URL, and pick the amount of visits from it
|
||||||
: shortUrl,
|
const lastVisit = last(
|
||||||
|
createdVisits.filter(({ shortUrl }) => shortUrlMatches(currentShortUrl, shortUrl.shortCode, shortUrl.domain)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return lastVisit ? assoc('visitsCount', lastVisit.shortUrl.visitsCount, currentShortUrl) : currentShortUrl;
|
||||||
|
},
|
||||||
),
|
),
|
||||||
state,
|
state,
|
||||||
),
|
),
|
||||||
|
|
|
@ -35,7 +35,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('ShortUrlsList', ShortUrlsList, 'ShortUrlsRow');
|
bottle.serviceFactory('ShortUrlsList', ShortUrlsList, 'ShortUrlsRow');
|
||||||
bottle.decorator('ShortUrlsList', connect(
|
bottle.decorator('ShortUrlsList', connect(
|
||||||
[ 'selectedServer', 'shortUrlsListParams', 'mercureInfo' ],
|
[ 'selectedServer', 'shortUrlsListParams', 'mercureInfo' ],
|
||||||
[ 'listShortUrls', 'resetShortUrlParams', 'createNewVisit', 'loadMercureInfo' ],
|
[ 'listShortUrls', 'resetShortUrlParams', 'createNewVisits', 'loadMercureInfo' ],
|
||||||
));
|
));
|
||||||
|
|
||||||
bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator', 'useStateFlagTimeout');
|
bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator', 'useStateFlagTimeout');
|
||||||
|
|
|
@ -56,6 +56,7 @@ const TagsSelector = (colorGenerator: ColorGenerator) => (
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
onSuggestionsFetchRequested={() => {}}
|
onSuggestionsFetchRequested={() => {}}
|
||||||
|
onSuggestionsClearRequested={() => {}}
|
||||||
onSuggestionSelected={(_, { suggestion }: SuggestionSelectedEventData<string>) => {
|
onSuggestionSelected={(_, { suggestion }: SuggestionSelectedEventData<string>) => {
|
||||||
addTag(suggestion);
|
addTag(suggestion);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { isEmpty, reject } from 'ramda';
|
import { isEmpty, reject } from 'ramda';
|
||||||
import { Action, Dispatch } from 'redux';
|
import { Action, Dispatch } from 'redux';
|
||||||
import { CREATE_VISIT, CreateVisitAction } from '../../visits/reducers/visitCreation';
|
import { CREATE_VISITS, CreateVisitsAction } from '../../visits/reducers/visitCreation';
|
||||||
import { buildReducer } from '../../utils/helpers/redux';
|
import { buildReducer } from '../../utils/helpers/redux';
|
||||||
import { ShlinkTags } from '../../utils/services/types';
|
import { ShlinkTags } from '../../utils/services/types';
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder';
|
import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder';
|
||||||
import { TagStats } from '../data';
|
import { TagStats } from '../data';
|
||||||
|
import { CreateVisit, Stats } from '../../visits/types';
|
||||||
import { DeleteTagAction, TAG_DELETED } from './tagDelete';
|
import { DeleteTagAction, TAG_DELETED } from './tagDelete';
|
||||||
import { EditTagAction, TAG_EDITED } from './tagEdit';
|
import { EditTagAction, TAG_EDITED } from './tagEdit';
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ interface FilterTagsAction extends Action<string> {
|
||||||
searchTerm: string;
|
searchTerm: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListTagsCombinedAction = ListTagsAction & DeleteTagAction & CreateVisitAction & EditTagAction & FilterTagsAction;
|
type ListTagsCombinedAction = ListTagsAction & DeleteTagAction & CreateVisitsAction & EditTagAction & FilterTagsAction;
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
tags: [],
|
tags: [],
|
||||||
|
@ -45,20 +46,31 @@ const initialState = {
|
||||||
error: false,
|
error: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type TagIncrease = [string, number];
|
||||||
|
|
||||||
const renameTag = (oldName: string, newName: string) => (tag: string) => tag === oldName ? newName : tag;
|
const renameTag = (oldName: string, newName: string) => (tag: string) => tag === oldName ? newName : tag;
|
||||||
const rejectTag = (tags: string[], tagToReject: string) => reject((tag) => tag === tagToReject, tags);
|
const rejectTag = (tags: string[], tagToReject: string) => reject((tag) => tag === tagToReject, tags);
|
||||||
const increaseVisitsForTags = (tags: string[], stats: TagsStatsMap) => tags.reduce((stats, tag) => {
|
const increaseVisitsForTags = (tags: TagIncrease[], stats: TagsStatsMap) => tags.reduce((stats, [ tag, increase ]) => {
|
||||||
if (!stats[tag]) {
|
if (!stats[tag]) {
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagStats = stats[tag];
|
const tagStats = stats[tag];
|
||||||
|
|
||||||
tagStats.visitsCount = tagStats.visitsCount + 1;
|
tagStats.visitsCount = tagStats.visitsCount + increase;
|
||||||
stats[tag] = tagStats;
|
stats[tag] = tagStats;
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
}, { ...stats });
|
}, { ...stats });
|
||||||
|
const calculateVisitsPerTag = (createdVisits: CreateVisit[]): TagIncrease[] => Object.entries(
|
||||||
|
createdVisits.reduce((acc, { shortUrl }) => {
|
||||||
|
shortUrl.tags.forEach((tag) => {
|
||||||
|
acc[tag] = (acc[tag] || 0) + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {} as Stats),
|
||||||
|
);
|
||||||
|
|
||||||
export default buildReducer<TagsList, ListTagsCombinedAction>({
|
export default buildReducer<TagsList, ListTagsCombinedAction>({
|
||||||
[LIST_TAGS_START]: () => ({ ...initialState, loading: true }),
|
[LIST_TAGS_START]: () => ({ ...initialState, loading: true }),
|
||||||
|
@ -78,9 +90,9 @@ export default buildReducer<TagsList, ListTagsCombinedAction>({
|
||||||
...state,
|
...state,
|
||||||
filteredTags: state.tags.filter((tag) => tag.toLowerCase().match(searchTerm)),
|
filteredTags: state.tags.filter((tag) => tag.toLowerCase().match(searchTerm)),
|
||||||
}),
|
}),
|
||||||
[CREATE_VISIT]: (state, { shortUrl }) => ({
|
[CREATE_VISITS]: (state, { createdVisits }) => ({
|
||||||
...state,
|
...state,
|
||||||
stats: increaseVisitsForTags(shortUrl.tags, state.stats),
|
stats: increaseVisitsForTags(calculateVisitsPerTag(createdVisits), state.stats),
|
||||||
}),
|
}),
|
||||||
}, initialState);
|
}, initialState);
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('TagsList', TagsList, 'TagCard');
|
bottle.serviceFactory('TagsList', TagsList, 'TagCard');
|
||||||
bottle.decorator('TagsList', connect(
|
bottle.decorator('TagsList', connect(
|
||||||
[ 'tagsList', 'selectedServer', 'mercureInfo' ],
|
[ 'tagsList', 'selectedServer', 'mercureInfo' ],
|
||||||
[ 'forceListTags', 'filterTags', 'createNewVisit', 'loadMercureInfo' ],
|
[ 'forceListTags', 'filterTags', 'createNewVisits', 'loadMercureInfo' ],
|
||||||
));
|
));
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuil
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
import { OptionalString } from '../../utils/utils';
|
import { OptionalString } from '../../utils/utils';
|
||||||
import { getVisitsWithLoader } from './common';
|
import { getVisitsWithLoader } from './common';
|
||||||
import { CREATE_VISIT, CreateVisitAction } from './visitCreation';
|
import { CREATE_VISITS, CreateVisitsAction } from './visitCreation';
|
||||||
|
|
||||||
/* eslint-disable padding-line-between-statements */
|
/* eslint-disable padding-line-between-statements */
|
||||||
export const GET_SHORT_URL_VISITS_START = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_START';
|
export const GET_SHORT_URL_VISITS_START = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_START';
|
||||||
|
@ -24,7 +24,7 @@ interface ShortUrlVisitsAction extends Action<string>, ShortUrlIdentifier {
|
||||||
visits: Visit[];
|
visits: Visit[];
|
||||||
}
|
}
|
||||||
|
|
||||||
type ShortUrlVisitsCombinedAction = ShortUrlVisitsAction & VisitsLoadProgressChangedAction & CreateVisitAction;
|
type ShortUrlVisitsCombinedAction = ShortUrlVisitsAction & VisitsLoadProgressChangedAction & CreateVisitsAction;
|
||||||
|
|
||||||
const initialState: ShortUrlVisits = {
|
const initialState: ShortUrlVisits = {
|
||||||
visits: [],
|
visits: [],
|
||||||
|
@ -49,14 +49,14 @@ export default buildReducer<ShortUrlVisits, ShortUrlVisitsCombinedAction>({
|
||||||
[GET_SHORT_URL_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),
|
[GET_SHORT_URL_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),
|
||||||
[GET_SHORT_URL_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),
|
[GET_SHORT_URL_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),
|
||||||
[GET_SHORT_URL_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),
|
[GET_SHORT_URL_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),
|
||||||
[CREATE_VISIT]: (state, { shortUrl, visit }) => { // eslint-disable-line object-shorthand
|
[CREATE_VISITS]: (state, { createdVisits }) => { // eslint-disable-line object-shorthand
|
||||||
const { shortCode, domain, visits } = state;
|
const { shortCode, domain, visits } = state;
|
||||||
|
|
||||||
if (!shortUrlMatches(shortUrl, shortCode, domain)) {
|
const newVisits = createdVisits
|
||||||
return state;
|
.filter(({ shortUrl }) => shortUrlMatches(shortUrl, shortCode, domain))
|
||||||
}
|
.map(({ visit }) => visit);
|
||||||
|
|
||||||
return { ...state, visits: [ ...visits, visit ] };
|
return { ...state, visits: [ ...visits, ...newVisits ] };
|
||||||
},
|
},
|
||||||
}, initialState);
|
}, initialState);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';
|
||||||
import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder';
|
import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder';
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
import { getVisitsWithLoader } from './common';
|
import { getVisitsWithLoader } from './common';
|
||||||
import { CREATE_VISIT, CreateVisitAction } from './visitCreation';
|
import { CREATE_VISITS, CreateVisitsAction } from './visitCreation';
|
||||||
|
|
||||||
/* eslint-disable padding-line-between-statements */
|
/* eslint-disable padding-line-between-statements */
|
||||||
export const GET_TAG_VISITS_START = 'shlink/tagVisits/GET_TAG_VISITS_START';
|
export const GET_TAG_VISITS_START = 'shlink/tagVisits/GET_TAG_VISITS_START';
|
||||||
|
@ -34,21 +34,20 @@ const initialState: TagVisits = {
|
||||||
progress: 0,
|
progress: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default buildReducer<TagVisits, TagVisitsAction & VisitsLoadProgressChangedAction & CreateVisitAction>({
|
export default buildReducer<TagVisits, TagVisitsAction & VisitsLoadProgressChangedAction & CreateVisitsAction>({
|
||||||
[GET_TAG_VISITS_START]: () => ({ ...initialState, loading: true }),
|
[GET_TAG_VISITS_START]: () => ({ ...initialState, loading: true }),
|
||||||
[GET_TAG_VISITS_ERROR]: () => ({ ...initialState, error: true }),
|
[GET_TAG_VISITS_ERROR]: () => ({ ...initialState, error: true }),
|
||||||
[GET_TAG_VISITS]: (_, { visits, tag }) => ({ ...initialState, visits, tag }),
|
[GET_TAG_VISITS]: (_, { visits, tag }) => ({ ...initialState, visits, tag }),
|
||||||
[GET_TAG_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),
|
[GET_TAG_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),
|
||||||
[GET_TAG_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),
|
[GET_TAG_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),
|
||||||
[GET_TAG_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),
|
[GET_TAG_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),
|
||||||
[CREATE_VISIT]: (state, { shortUrl, visit }) => { // eslint-disable-line object-shorthand
|
[CREATE_VISITS]: (state, { createdVisits }) => { // eslint-disable-line object-shorthand
|
||||||
const { tag, visits } = state;
|
const { tag, visits } = state;
|
||||||
|
const newVisits = createdVisits
|
||||||
|
.filter(({ shortUrl }) => shortUrl.tags.includes(tag))
|
||||||
|
.map(({ visit }) => visit);
|
||||||
|
|
||||||
if (!shortUrl.tags.includes(tag)) {
|
return { ...state, visits: [ ...visits, ...newVisits ] };
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ...state, visits: [ ...visits, visit ] };
|
|
||||||
},
|
},
|
||||||
}, initialState);
|
}, initialState);
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { Action } from 'redux';
|
import { Action } from 'redux';
|
||||||
import { CreateVisit } from '../types';
|
import { CreateVisit } from '../types';
|
||||||
|
|
||||||
export const CREATE_VISIT = 'shlink/visitCreation/CREATE_VISIT';
|
export const CREATE_VISITS = 'shlink/visitCreation/CREATE_VISITS';
|
||||||
|
|
||||||
export type CreateVisitAction = Action<typeof CREATE_VISIT> & CreateVisit;
|
export interface CreateVisitsAction extends Action<typeof CREATE_VISITS> {
|
||||||
|
createdVisits: CreateVisit[];
|
||||||
|
}
|
||||||
|
|
||||||
export const createNewVisit = ({ shortUrl, visit }: CreateVisit): CreateVisitAction => ({
|
export const createNewVisits = (createdVisits: CreateVisit[]): CreateVisitsAction => ({
|
||||||
type: CREATE_VISIT,
|
type: CREATE_VISITS,
|
||||||
shortUrl,
|
createdVisits,
|
||||||
visit,
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@ import ShortUrlVisits from '../ShortUrlVisits';
|
||||||
import { cancelGetShortUrlVisits, getShortUrlVisits } from '../reducers/shortUrlVisits';
|
import { cancelGetShortUrlVisits, getShortUrlVisits } from '../reducers/shortUrlVisits';
|
||||||
import { getShortUrlDetail } from '../reducers/shortUrlDetail';
|
import { getShortUrlDetail } from '../reducers/shortUrlDetail';
|
||||||
import MapModal from '../helpers/MapModal';
|
import MapModal from '../helpers/MapModal';
|
||||||
import { createNewVisit } from '../reducers/visitCreation';
|
import { createNewVisits } from '../reducers/visitCreation';
|
||||||
import { cancelGetTagVisits, getTagVisits } from '../reducers/tagVisits';
|
import { cancelGetTagVisits, getTagVisits } from '../reducers/tagVisits';
|
||||||
import TagVisits from '../TagVisits';
|
import TagVisits from '../TagVisits';
|
||||||
import { ConnectDecorator } from '../../container/types';
|
import { ConnectDecorator } from '../../container/types';
|
||||||
|
@ -15,12 +15,12 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('ShortUrlVisits', () => ShortUrlVisits);
|
bottle.serviceFactory('ShortUrlVisits', () => ShortUrlVisits);
|
||||||
bottle.decorator('ShortUrlVisits', connect(
|
bottle.decorator('ShortUrlVisits', connect(
|
||||||
[ 'shortUrlVisits', 'shortUrlDetail', 'mercureInfo' ],
|
[ 'shortUrlVisits', 'shortUrlDetail', 'mercureInfo' ],
|
||||||
[ 'getShortUrlVisits', 'getShortUrlDetail', 'cancelGetShortUrlVisits', 'createNewVisit', 'loadMercureInfo' ],
|
[ 'getShortUrlVisits', 'getShortUrlDetail', 'cancelGetShortUrlVisits', 'createNewVisits', 'loadMercureInfo' ],
|
||||||
));
|
));
|
||||||
bottle.serviceFactory('TagVisits', TagVisits, 'ColorGenerator');
|
bottle.serviceFactory('TagVisits', TagVisits, 'ColorGenerator');
|
||||||
bottle.decorator('TagVisits', connect(
|
bottle.decorator('TagVisits', connect(
|
||||||
[ 'tagVisits', 'mercureInfo' ],
|
[ 'tagVisits', 'mercureInfo' ],
|
||||||
[ 'getTagVisits', 'cancelGetTagVisits', 'createNewVisit', 'loadMercureInfo' ],
|
[ 'getTagVisits', 'cancelGetTagVisits', 'createNewVisits', 'loadMercureInfo' ],
|
||||||
));
|
));
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
|
@ -34,7 +34,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('getTagVisits', getTagVisits, 'buildShlinkApiClient');
|
bottle.serviceFactory('getTagVisits', getTagVisits, 'buildShlinkApiClient');
|
||||||
bottle.serviceFactory('cancelGetTagVisits', () => cancelGetTagVisits);
|
bottle.serviceFactory('cancelGetTagVisits', () => cancelGetTagVisits);
|
||||||
|
|
||||||
bottle.serviceFactory('createNewVisit', () => createNewVisit);
|
bottle.serviceFactory('createNewVisits', () => createNewVisits);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default provideServices;
|
export default provideServices;
|
||||||
|
|
|
@ -8,7 +8,7 @@ import reducer, {
|
||||||
import { SHORT_URL_TAGS_EDITED } from '../../../src/short-urls/reducers/shortUrlTags';
|
import { SHORT_URL_TAGS_EDITED } from '../../../src/short-urls/reducers/shortUrlTags';
|
||||||
import { SHORT_URL_DELETED } from '../../../src/short-urls/reducers/shortUrlDeletion';
|
import { SHORT_URL_DELETED } from '../../../src/short-urls/reducers/shortUrlDeletion';
|
||||||
import { SHORT_URL_META_EDITED } from '../../../src/short-urls/reducers/shortUrlMeta';
|
import { SHORT_URL_META_EDITED } from '../../../src/short-urls/reducers/shortUrlMeta';
|
||||||
import { CREATE_VISIT } from '../../../src/visits/reducers/visitCreation';
|
import { CREATE_VISITS } from '../../../src/visits/reducers/visitCreation';
|
||||||
import { ShortUrl } from '../../../src/short-urls/data';
|
import { ShortUrl } from '../../../src/short-urls/data';
|
||||||
import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient';
|
import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient';
|
||||||
import { ShlinkShortUrlsResponse } from '../../../src/utils/services/types';
|
import { ShlinkShortUrlsResponse } from '../../../src/utils/services/types';
|
||||||
|
@ -135,7 +135,7 @@ describe('shortUrlsListReducer', () => {
|
||||||
error: false,
|
error: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(reducer(state, { type: CREATE_VISIT, shortUrl } as any)).toEqual({
|
expect(reducer(state, { type: CREATE_VISITS, createdVisits: [{ shortUrl }] } as any)).toEqual({
|
||||||
shortUrls: {
|
shortUrls: {
|
||||||
data: [
|
data: [
|
||||||
{ shortCode, domain: 'example.com', visitsCount: 5 },
|
{ shortCode, domain: 'example.com', visitsCount: 5 },
|
||||||
|
|
|
@ -10,7 +10,7 @@ import reducer, {
|
||||||
GET_SHORT_URL_VISITS_PROGRESS_CHANGED,
|
GET_SHORT_URL_VISITS_PROGRESS_CHANGED,
|
||||||
ShortUrlVisits,
|
ShortUrlVisits,
|
||||||
} from '../../../src/visits/reducers/shortUrlVisits';
|
} from '../../../src/visits/reducers/shortUrlVisits';
|
||||||
import { CREATE_VISIT } from '../../../src/visits/reducers/visitCreation';
|
import { CREATE_VISITS } from '../../../src/visits/reducers/visitCreation';
|
||||||
import { rangeOf } from '../../../src/utils/utils';
|
import { rangeOf } from '../../../src/utils/utils';
|
||||||
import { Visit } from '../../../src/visits/types';
|
import { Visit } from '../../../src/visits/types';
|
||||||
import { ShlinkVisits } from '../../../src/utils/services/types';
|
import { ShlinkVisits } from '../../../src/utils/services/types';
|
||||||
|
@ -77,7 +77,7 @@ describe('shortUrlVisitsReducer', () => {
|
||||||
visits: visitsMocks,
|
visits: visitsMocks,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { visits } = reducer(prevState, { type: CREATE_VISIT, shortUrl, visit: {} } as any);
|
const { visits } = reducer(prevState, { type: CREATE_VISITS, createdVisits: [{ shortUrl, visit: {} }] } as any);
|
||||||
|
|
||||||
expect(visits).toEqual(expectedVisits);
|
expect(visits).toEqual(expectedVisits);
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ import reducer, {
|
||||||
GET_TAG_VISITS_PROGRESS_CHANGED,
|
GET_TAG_VISITS_PROGRESS_CHANGED,
|
||||||
TagVisits,
|
TagVisits,
|
||||||
} from '../../../src/visits/reducers/tagVisits';
|
} from '../../../src/visits/reducers/tagVisits';
|
||||||
import { CREATE_VISIT } from '../../../src/visits/reducers/visitCreation';
|
import { CREATE_VISITS } from '../../../src/visits/reducers/visitCreation';
|
||||||
import { rangeOf } from '../../../src/utils/utils';
|
import { rangeOf } from '../../../src/utils/utils';
|
||||||
import { Visit } from '../../../src/visits/types';
|
import { Visit } from '../../../src/visits/types';
|
||||||
import { ShlinkVisits } from '../../../src/utils/services/types';
|
import { ShlinkVisits } from '../../../src/utils/services/types';
|
||||||
|
@ -77,7 +77,7 @@ describe('tagVisitsReducer', () => {
|
||||||
visits: visitsMocks,
|
visits: visitsMocks,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { visits } = reducer(prevState, { type: CREATE_VISIT, shortUrl, visit: {} } as any);
|
const { visits } = reducer(prevState, { type: CREATE_VISITS, createdVisits: [{ shortUrl, visit: {} }] } as any);
|
||||||
|
|
||||||
expect(visits).toEqual(expectedVisits);
|
expect(visits).toEqual(expectedVisits);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { Mock } from 'ts-mockery';
|
import { Mock } from 'ts-mockery';
|
||||||
import { CREATE_VISIT, createNewVisit } from '../../../src/visits/reducers/visitCreation';
|
import { CREATE_VISITS, createNewVisits } from '../../../src/visits/reducers/visitCreation';
|
||||||
import { ShortUrl } from '../../../src/short-urls/data';
|
import { ShortUrl } from '../../../src/short-urls/data';
|
||||||
import { Visit } from '../../../src/visits/types';
|
import { Visit } from '../../../src/visits/types';
|
||||||
|
|
||||||
describe('visitCreationReducer', () => {
|
describe('visitCreationReducer', () => {
|
||||||
describe('createNewVisit', () => {
|
describe('createNewVisits', () => {
|
||||||
const shortUrl = Mock.all<ShortUrl>();
|
const shortUrl = Mock.all<ShortUrl>();
|
||||||
const visit = Mock.all<Visit>();
|
const visit = Mock.all<Visit>();
|
||||||
|
|
||||||
it('just returns the action with proper type', () =>
|
it('just returns the action with proper type', () =>
|
||||||
expect(createNewVisit({ shortUrl, visit })).toEqual(
|
expect(createNewVisits([{ shortUrl, visit }])).toEqual(
|
||||||
{ type: CREATE_VISIT, shortUrl, visit },
|
{ type: CREATE_VISITS, createdVisits: [{ shortUrl, visit }] },
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue