mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Migrated visits-loading actions to payload actions
This commit is contained in:
parent
a6ed0c811d
commit
a3cc3d5fc2
15 changed files with 136 additions and 127 deletions
|
@ -17,9 +17,6 @@ export const buildReducer = <State, AT extends Action>(map: ActionHandlerMap<Sta
|
||||||
return actionHandler ? actionHandler(currentState, action) : currentState;
|
return actionHandler ? actionHandler(currentState, action) : currentState;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
export const buildActionCreator = <T extends string>(type: T) => (): Action<T> => ({ type });
|
|
||||||
|
|
||||||
export const createAsyncThunk = <Returned, ThunkArg>(
|
export const createAsyncThunk = <Returned, ThunkArg>(
|
||||||
typePrefix: string,
|
typePrefix: string,
|
||||||
payloadCreator: AsyncThunkPayloadCreator<Returned, ThunkArg, { state: ShlinkState }>,
|
payloadCreator: AsyncThunkPayloadCreator<Returned, ThunkArg, { state: ShlinkState }>,
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { ShlinkVisitsParams } from '../api/types';
|
||||||
import { Topics } from '../mercure/helpers/Topics';
|
import { Topics } from '../mercure/helpers/Topics';
|
||||||
import { useGoBack } from '../utils/helpers/hooks';
|
import { useGoBack } from '../utils/helpers/hooks';
|
||||||
import { ReportExporter } from '../common/services/ReportExporter';
|
import { ReportExporter } from '../common/services/ReportExporter';
|
||||||
import { TagVisits as TagVisitsState } from './reducers/tagVisits';
|
import { LoadTagVisits, TagVisits as TagVisitsState } from './reducers/tagVisits';
|
||||||
import { TagVisitsHeader } from './TagVisitsHeader';
|
import { TagVisitsHeader } from './TagVisitsHeader';
|
||||||
import { VisitsStats } from './VisitsStats';
|
import { VisitsStats } from './VisitsStats';
|
||||||
import { NormalizedVisit } from './types';
|
import { NormalizedVisit } from './types';
|
||||||
|
@ -13,7 +13,7 @@ import { CommonVisitsProps } from './types/CommonVisitsProps';
|
||||||
import { toApiParams } from './types/helpers';
|
import { toApiParams } from './types/helpers';
|
||||||
|
|
||||||
export interface TagVisitsProps extends CommonVisitsProps {
|
export interface TagVisitsProps extends CommonVisitsProps {
|
||||||
getTagVisits: (tag: string, query?: ShlinkVisitsParams, doIntervalFallback?: boolean) => void;
|
getTagVisits: (params: LoadTagVisits) => void;
|
||||||
tagVisits: TagVisitsState;
|
tagVisits: TagVisitsState;
|
||||||
cancelGetTagVisits: () => void;
|
cancelGetTagVisits: () => void;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ export const TagVisits = (colorGenerator: ColorGenerator, { exportVisits }: Repo
|
||||||
const goBack = useGoBack();
|
const goBack = useGoBack();
|
||||||
const { tag = '' } = useParams();
|
const { tag = '' } = useParams();
|
||||||
const loadVisits = (params: ShlinkVisitsParams, doIntervalFallback?: boolean) =>
|
const loadVisits = (params: ShlinkVisitsParams, doIntervalFallback?: boolean) =>
|
||||||
getTagVisits(tag, toApiParams(params), doIntervalFallback);
|
getTagVisits({ tag, query: toApiParams(params), doIntervalFallback });
|
||||||
const exportCsv = (visits: NormalizedVisit[]) => exportVisits(`tag_${tag}_visits.csv`, visits);
|
const exportCsv = (visits: NormalizedVisit[]) => exportVisits(`tag_${tag}_visits.csv`, visits);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { flatten, prop, range, splitEvery } from 'ramda';
|
import { flatten, prop, range, splitEvery } from 'ramda';
|
||||||
import { Action, Dispatch } from 'redux';
|
import { Dispatch } from '@reduxjs/toolkit';
|
||||||
import { ShlinkPaginator, ShlinkVisits, ShlinkVisitsParams } from '../../api/types';
|
import { ShlinkPaginator, ShlinkVisits, ShlinkVisitsParams } from '../../api/types';
|
||||||
import { Visit } from '../types';
|
import { Visit } from '../types';
|
||||||
import { parseApiError } from '../../api/utils';
|
import { parseApiError } from '../../api/utils';
|
||||||
import { ApiErrorAction } from '../../api/types/actions';
|
import { ApiErrorAction } from '../../api/types/actions';
|
||||||
import { dateToMatchingInterval } from '../../utils/dates/types';
|
import { dateToMatchingInterval } from '../../utils/dates/types';
|
||||||
import { VisitsLoadProgressChangedAction } from './types';
|
import { VisitsLoaded, VisitsLoadProgressChangedAction } from './types';
|
||||||
|
|
||||||
const ITEMS_PER_PAGE = 5000;
|
const ITEMS_PER_PAGE = 5000;
|
||||||
const PARALLEL_REQUESTS_COUNT = 4;
|
const PARALLEL_REQUESTS_COUNT = 4;
|
||||||
|
@ -17,10 +17,10 @@ const calcProgress = (total: number, current: number): number => (current * 100)
|
||||||
type VisitsLoader = (page: number, itemsPerPage: number) => Promise<ShlinkVisits>;
|
type VisitsLoader = (page: number, itemsPerPage: number) => Promise<ShlinkVisits>;
|
||||||
type LastVisitLoader = () => Promise<Visit | undefined>;
|
type LastVisitLoader = () => Promise<Visit | undefined>;
|
||||||
|
|
||||||
export const getVisitsWithLoader = async <T extends Action<string> & { visits: Visit[] }>(
|
export const getVisitsWithLoader = async <T extends VisitsLoaded>(
|
||||||
visitsLoader: VisitsLoader,
|
visitsLoader: VisitsLoader,
|
||||||
lastVisitLoader: LastVisitLoader,
|
lastVisitLoader: LastVisitLoader,
|
||||||
extraFinishActionData: Partial<T>,
|
extraFulfilledPayload: Partial<T>,
|
||||||
actionsPrefix: string,
|
actionsPrefix: string,
|
||||||
dispatch: Dispatch,
|
dispatch: Dispatch,
|
||||||
shouldCancel: () => boolean,
|
shouldCancel: () => boolean,
|
||||||
|
@ -74,7 +74,7 @@ export const getVisitsWithLoader = async <T extends Action<string> & { visits: V
|
||||||
dispatch(
|
dispatch(
|
||||||
!visits.length && lastVisit
|
!visits.length && lastVisit
|
||||||
? { type: `${actionsPrefix}/fallbackToInterval`, payload: dateToMatchingInterval(lastVisit.date) }
|
? { type: `${actionsPrefix}/fallbackToInterval`, payload: dateToMatchingInterval(lastVisit.date) }
|
||||||
: { ...extraFinishActionData, visits, type: `${actionsPrefix}/fulfilled` },
|
: { type: `${actionsPrefix}/fulfilled`, payload: { ...extraFulfilledPayload, visits } },
|
||||||
);
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
dispatch<ApiErrorAction>({ type: `${actionsPrefix}/rejected`, errorData: parseApiError(e) });
|
dispatch<ApiErrorAction>({ type: `${actionsPrefix}/rejected`, errorData: parseApiError(e) });
|
||||||
|
@ -89,5 +89,5 @@ export const lastVisitLoaderForLoader = (
|
||||||
return async () => Promise.resolve(undefined);
|
return async () => Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
return async () => loader({ page: 1, itemsPerPage: 1 }).then((result) => result.data[0]);
|
return async () => loader({ page: 1, itemsPerPage: 1 }).then(({ data }) => data[0]);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { Action, Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { Visit } from '../types';
|
|
||||||
import { buildReducer } from '../../utils/helpers/redux';
|
import { buildReducer } from '../../utils/helpers/redux';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
import { ShlinkVisitsParams } from '../../api/types';
|
|
||||||
import { ApiErrorAction } from '../../api/types/actions';
|
import { ApiErrorAction } from '../../api/types/actions';
|
||||||
import { isBetween } from '../../utils/helpers/date';
|
import { isBetween } from '../../utils/helpers/date';
|
||||||
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
||||||
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
||||||
import { domainMatches } from '../../short-urls/helpers';
|
import { domainMatches } from '../../short-urls/helpers';
|
||||||
import { LoadVisits, VisitsFallbackIntervalAction, VisitsInfo, VisitsLoadProgressChangedAction } from './types';
|
import {
|
||||||
|
LoadVisits,
|
||||||
|
VisitsFallbackIntervalAction,
|
||||||
|
VisitsInfo,
|
||||||
|
VisitsLoaded,
|
||||||
|
VisitsLoadedAction,
|
||||||
|
VisitsLoadProgressChangedAction,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
const REDUCER_PREFIX = 'shlink/domainVisits';
|
const REDUCER_PREFIX = 'shlink/domainVisits';
|
||||||
export const GET_DOMAIN_VISITS_START = `${REDUCER_PREFIX}/getDomainVisits/pending`;
|
export const GET_DOMAIN_VISITS_START = `${REDUCER_PREFIX}/getDomainVisits/pending`;
|
||||||
|
@ -23,19 +28,15 @@ export const GET_DOMAIN_VISITS_FALLBACK_TO_INTERVAL = `${REDUCER_PREFIX}/getDoma
|
||||||
|
|
||||||
export const DEFAULT_DOMAIN = 'DEFAULT';
|
export const DEFAULT_DOMAIN = 'DEFAULT';
|
||||||
|
|
||||||
export interface DomainVisits extends VisitsInfo {
|
interface WithDomain {
|
||||||
domain: string;
|
domain: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadDomainVisits extends LoadVisits {
|
export interface DomainVisits extends VisitsInfo, WithDomain {}
|
||||||
domain: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomainVisitsAction extends Action<string> {
|
export interface LoadDomainVisits extends LoadVisits, WithDomain {}
|
||||||
visits: Visit[];
|
|
||||||
domain: string;
|
type DomainVisitsAction = VisitsLoadedAction<WithDomain>;
|
||||||
query?: ShlinkVisitsParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
type DomainVisitsCombinedAction = DomainVisitsAction
|
type DomainVisitsCombinedAction = DomainVisitsAction
|
||||||
& VisitsLoadProgressChangedAction
|
& VisitsLoadProgressChangedAction
|
||||||
|
@ -56,8 +57,8 @@ const initialState: DomainVisits = {
|
||||||
export default buildReducer<DomainVisits, DomainVisitsCombinedAction>({
|
export default buildReducer<DomainVisits, DomainVisitsCombinedAction>({
|
||||||
[`${REDUCER_PREFIX}/getDomainVisits/pending`]: () => ({ ...initialState, loading: true }),
|
[`${REDUCER_PREFIX}/getDomainVisits/pending`]: () => ({ ...initialState, loading: true }),
|
||||||
[`${REDUCER_PREFIX}/getDomainVisits/rejected`]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),
|
[`${REDUCER_PREFIX}/getDomainVisits/rejected`]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),
|
||||||
[`${REDUCER_PREFIX}/getDomainVisits/fulfilled`]: (state, { visits, domain, query }) => (
|
[`${REDUCER_PREFIX}/getDomainVisits/fulfilled`]: (state, { payload }: DomainVisitsAction) => (
|
||||||
{ ...state, visits, domain, query, loading: false, loadingLarge: false, error: false }
|
{ ...state, ...payload, loading: false, loadingLarge: false, error: false }
|
||||||
),
|
),
|
||||||
[`${REDUCER_PREFIX}/getDomainVisits/large`]: (state) => ({ ...state, loadingLarge: true }),
|
[`${REDUCER_PREFIX}/getDomainVisits/large`]: (state) => ({ ...state, loadingLarge: true }),
|
||||||
[`${REDUCER_PREFIX}/getDomainVisits/cancel`]: (state) => ({ ...state, cancelLoad: true }),
|
[`${REDUCER_PREFIX}/getDomainVisits/cancel`]: (state) => ({ ...state, cancelLoad: true }),
|
||||||
|
@ -87,7 +88,7 @@ export const getDomainVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) =>
|
||||||
);
|
);
|
||||||
const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, async (params) => getVisits(domain, params));
|
const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, async (params) => getVisits(domain, params));
|
||||||
const shouldCancel = () => getState().domainVisits.cancelLoad;
|
const shouldCancel = () => getState().domainVisits.cancelLoad;
|
||||||
const extraFinishActionData: Partial<DomainVisitsAction> = { domain, query };
|
const extraFinishActionData: Partial<VisitsLoaded<WithDomain>> = { domain, query };
|
||||||
const prefix = `${REDUCER_PREFIX}/getDomainVisits`;
|
const prefix = `${REDUCER_PREFIX}/getDomainVisits`;
|
||||||
|
|
||||||
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { Action, Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { Visit } from '../types';
|
|
||||||
import { buildReducer } from '../../utils/helpers/redux';
|
import { buildReducer } from '../../utils/helpers/redux';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
import { ShlinkVisitsParams } from '../../api/types';
|
|
||||||
import { ApiErrorAction } from '../../api/types/actions';
|
import { ApiErrorAction } from '../../api/types/actions';
|
||||||
import { isBetween } from '../../utils/helpers/date';
|
import { isBetween } from '../../utils/helpers/date';
|
||||||
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
||||||
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
||||||
import { LoadVisits, VisitsFallbackIntervalAction, VisitsInfo, VisitsLoadProgressChangedAction } from './types';
|
import {
|
||||||
|
LoadVisits,
|
||||||
|
VisitsFallbackIntervalAction,
|
||||||
|
VisitsInfo,
|
||||||
|
VisitsLoaded,
|
||||||
|
VisitsLoadedAction,
|
||||||
|
VisitsLoadProgressChangedAction,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
const REDUCER_PREFIX = 'shlink/orphanVisits';
|
const REDUCER_PREFIX = 'shlink/orphanVisits';
|
||||||
export const GET_NON_ORPHAN_VISITS_START = `${REDUCER_PREFIX}/getNonOrphanVisits/pending`;
|
export const GET_NON_ORPHAN_VISITS_START = `${REDUCER_PREFIX}/getNonOrphanVisits/pending`;
|
||||||
|
@ -20,12 +25,7 @@ export const GET_NON_ORPHAN_VISITS_CANCEL = `${REDUCER_PREFIX}/getNonOrphanVisit
|
||||||
export const GET_NON_ORPHAN_VISITS_PROGRESS_CHANGED = `${REDUCER_PREFIX}/getNonOrphanVisits/progressChanged`;
|
export const GET_NON_ORPHAN_VISITS_PROGRESS_CHANGED = `${REDUCER_PREFIX}/getNonOrphanVisits/progressChanged`;
|
||||||
export const GET_NON_ORPHAN_VISITS_FALLBACK_TO_INTERVAL = `${REDUCER_PREFIX}/getNonOrphanVisits/fallbackToInterval`;
|
export const GET_NON_ORPHAN_VISITS_FALLBACK_TO_INTERVAL = `${REDUCER_PREFIX}/getNonOrphanVisits/fallbackToInterval`;
|
||||||
|
|
||||||
export interface NonOrphanVisitsAction extends Action<string> {
|
type NonOrphanVisitsCombinedAction = VisitsLoadedAction
|
||||||
visits: Visit[];
|
|
||||||
query?: ShlinkVisitsParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
type NonOrphanVisitsCombinedAction = NonOrphanVisitsAction
|
|
||||||
& VisitsLoadProgressChangedAction
|
& VisitsLoadProgressChangedAction
|
||||||
& VisitsFallbackIntervalAction
|
& VisitsFallbackIntervalAction
|
||||||
& CreateVisitsAction
|
& CreateVisitsAction
|
||||||
|
@ -45,8 +45,8 @@ export default buildReducer<VisitsInfo, NonOrphanVisitsCombinedAction>({
|
||||||
[`${REDUCER_PREFIX}/getNonOrphanVisits/rejected`]: (_, { errorData }) => (
|
[`${REDUCER_PREFIX}/getNonOrphanVisits/rejected`]: (_, { errorData }) => (
|
||||||
{ ...initialState, error: true, errorData }
|
{ ...initialState, error: true, errorData }
|
||||||
),
|
),
|
||||||
[`${REDUCER_PREFIX}/getNonOrphanVisits/fulfilled`]: (state, { visits, query }) => (
|
[`${REDUCER_PREFIX}/getNonOrphanVisits/fulfilled`]: (state, { payload }: VisitsLoadedAction) => (
|
||||||
{ ...state, visits, query, loading: false, loadingLarge: false, error: false }
|
{ ...state, ...payload, loading: false, loadingLarge: false, error: false }
|
||||||
),
|
),
|
||||||
[`${REDUCER_PREFIX}/getNonOrphanVisits/large`]: (state) => ({ ...state, loadingLarge: true }),
|
[`${REDUCER_PREFIX}/getNonOrphanVisits/large`]: (state) => ({ ...state, loadingLarge: true }),
|
||||||
[`${REDUCER_PREFIX}/getNonOrphanVisits/cancel`]: (state) => ({ ...state, cancelLoad: true }),
|
[`${REDUCER_PREFIX}/getNonOrphanVisits/cancel`]: (state) => ({ ...state, cancelLoad: true }),
|
||||||
|
@ -73,7 +73,7 @@ export const getNonOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder)
|
||||||
shlinkGetNonOrphanVisits({ ...query, page, itemsPerPage });
|
shlinkGetNonOrphanVisits({ ...query, page, itemsPerPage });
|
||||||
const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, shlinkGetNonOrphanVisits);
|
const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, shlinkGetNonOrphanVisits);
|
||||||
const shouldCancel = () => getState().orphanVisits.cancelLoad;
|
const shouldCancel = () => getState().orphanVisits.cancelLoad;
|
||||||
const extraFinishActionData: Partial<NonOrphanVisitsAction> = { query };
|
const extraFinishActionData: Partial<VisitsLoaded> = { query };
|
||||||
const prefix = `${REDUCER_PREFIX}/getNonOrphanVisits`;
|
const prefix = `${REDUCER_PREFIX}/getNonOrphanVisits`;
|
||||||
|
|
||||||
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { Action, Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { OrphanVisit, OrphanVisitType, Visit } from '../types';
|
import { OrphanVisit, OrphanVisitType } from '../types';
|
||||||
import { buildReducer } from '../../utils/helpers/redux';
|
import { buildReducer } from '../../utils/helpers/redux';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
import { ShlinkVisitsParams } from '../../api/types';
|
|
||||||
import { isOrphanVisit } from '../types/helpers';
|
import { isOrphanVisit } from '../types/helpers';
|
||||||
import { ApiErrorAction } from '../../api/types/actions';
|
import { ApiErrorAction } from '../../api/types/actions';
|
||||||
import { isBetween } from '../../utils/helpers/date';
|
import { isBetween } from '../../utils/helpers/date';
|
||||||
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
||||||
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
||||||
import { LoadVisits, VisitsFallbackIntervalAction, VisitsInfo, VisitsLoadProgressChangedAction } from './types';
|
import {
|
||||||
|
LoadVisits,
|
||||||
|
VisitsFallbackIntervalAction,
|
||||||
|
VisitsInfo,
|
||||||
|
VisitsLoaded,
|
||||||
|
VisitsLoadedAction,
|
||||||
|
VisitsLoadProgressChangedAction,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
const REDUCER_PREFIX = 'shlink/orphanVisits';
|
const REDUCER_PREFIX = 'shlink/orphanVisits';
|
||||||
export const GET_ORPHAN_VISITS_START = `${REDUCER_PREFIX}/getOrphanVisits/pending`;
|
export const GET_ORPHAN_VISITS_START = `${REDUCER_PREFIX}/getOrphanVisits/pending`;
|
||||||
|
@ -21,16 +27,11 @@ export const GET_ORPHAN_VISITS_CANCEL = `${REDUCER_PREFIX}/getOrphanVisits/cance
|
||||||
export const GET_ORPHAN_VISITS_PROGRESS_CHANGED = `${REDUCER_PREFIX}/getOrphanVisits/progressChanged`;
|
export const GET_ORPHAN_VISITS_PROGRESS_CHANGED = `${REDUCER_PREFIX}/getOrphanVisits/progressChanged`;
|
||||||
export const GET_ORPHAN_VISITS_FALLBACK_TO_INTERVAL = `${REDUCER_PREFIX}/getOrphanVisits/fallbackToInterval`;
|
export const GET_ORPHAN_VISITS_FALLBACK_TO_INTERVAL = `${REDUCER_PREFIX}/getOrphanVisits/fallbackToInterval`;
|
||||||
|
|
||||||
export interface OrphanVisitsAction extends Action<string> {
|
|
||||||
visits: Visit[];
|
|
||||||
query?: ShlinkVisitsParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoadOrphanVisits extends LoadVisits {
|
export interface LoadOrphanVisits extends LoadVisits {
|
||||||
orphanVisitsType?: OrphanVisitType;
|
orphanVisitsType?: OrphanVisitType;
|
||||||
}
|
}
|
||||||
|
|
||||||
type OrphanVisitsCombinedAction = OrphanVisitsAction
|
type OrphanVisitsCombinedAction = VisitsLoadedAction
|
||||||
& VisitsLoadProgressChangedAction
|
& VisitsLoadProgressChangedAction
|
||||||
& VisitsFallbackIntervalAction
|
& VisitsFallbackIntervalAction
|
||||||
& CreateVisitsAction
|
& CreateVisitsAction
|
||||||
|
@ -48,8 +49,8 @@ const initialState: VisitsInfo = {
|
||||||
export default buildReducer<VisitsInfo, OrphanVisitsCombinedAction>({
|
export default buildReducer<VisitsInfo, OrphanVisitsCombinedAction>({
|
||||||
[`${REDUCER_PREFIX}/getOrphanVisits/pending`]: () => ({ ...initialState, loading: true }),
|
[`${REDUCER_PREFIX}/getOrphanVisits/pending`]: () => ({ ...initialState, loading: true }),
|
||||||
[`${REDUCER_PREFIX}/getOrphanVisits/rejected`]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),
|
[`${REDUCER_PREFIX}/getOrphanVisits/rejected`]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),
|
||||||
[`${REDUCER_PREFIX}/getOrphanVisits/fulfilled`]: (state, { visits, query }) => (
|
[`${REDUCER_PREFIX}/getOrphanVisits/fulfilled`]: (state, { payload }: VisitsLoadedAction) => (
|
||||||
{ ...state, visits, query, loading: false, loadingLarge: false, error: false }
|
{ ...state, ...payload, loading: false, loadingLarge: false, error: false }
|
||||||
),
|
),
|
||||||
[`${REDUCER_PREFIX}/getOrphanVisits/large`]: (state) => ({ ...state, loadingLarge: true }),
|
[`${REDUCER_PREFIX}/getOrphanVisits/large`]: (state) => ({ ...state, loadingLarge: true }),
|
||||||
[`${REDUCER_PREFIX}/getOrphanVisits/cancel`]: (state) => ({ ...state, cancelLoad: true }),
|
[`${REDUCER_PREFIX}/getOrphanVisits/cancel`]: (state) => ({ ...state, cancelLoad: true }),
|
||||||
|
@ -83,7 +84,7 @@ export const getOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) =>
|
||||||
});
|
});
|
||||||
const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, getVisits);
|
const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, getVisits);
|
||||||
const shouldCancel = () => getState().orphanVisits.cancelLoad;
|
const shouldCancel = () => getState().orphanVisits.cancelLoad;
|
||||||
const extraFinishActionData: Partial<OrphanVisitsAction> = { query };
|
const extraFinishActionData: Partial<VisitsLoaded> = { query };
|
||||||
const prefix = `${REDUCER_PREFIX}/getOrphanVisits`;
|
const prefix = `${REDUCER_PREFIX}/getOrphanVisits`;
|
||||||
|
|
||||||
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
||||||
|
|
|
@ -1,17 +1,22 @@
|
||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { Action, Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { shortUrlMatches } from '../../short-urls/helpers';
|
import { shortUrlMatches } from '../../short-urls/helpers';
|
||||||
import { Visit } from '../types';
|
|
||||||
import { ShortUrlIdentifier } from '../../short-urls/data';
|
import { ShortUrlIdentifier } from '../../short-urls/data';
|
||||||
import { buildReducer } from '../../utils/helpers/redux';
|
import { buildReducer } from '../../utils/helpers/redux';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
import { ShlinkVisitsParams } from '../../api/types';
|
|
||||||
import { ApiErrorAction } from '../../api/types/actions';
|
import { ApiErrorAction } from '../../api/types/actions';
|
||||||
import { isBetween } from '../../utils/helpers/date';
|
import { isBetween } from '../../utils/helpers/date';
|
||||||
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
||||||
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
||||||
import { LoadVisits, VisitsFallbackIntervalAction, VisitsInfo, VisitsLoadProgressChangedAction } from './types';
|
import {
|
||||||
|
LoadVisits,
|
||||||
|
VisitsFallbackIntervalAction,
|
||||||
|
VisitsInfo,
|
||||||
|
VisitsLoaded,
|
||||||
|
VisitsLoadedAction,
|
||||||
|
VisitsLoadProgressChangedAction,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
const REDUCER_PREFIX = 'shlink/shortUrlVisits';
|
const REDUCER_PREFIX = 'shlink/shortUrlVisits';
|
||||||
export const GET_SHORT_URL_VISITS_START = `${REDUCER_PREFIX}/getShortUrlVisits/pending`;
|
export const GET_SHORT_URL_VISITS_START = `${REDUCER_PREFIX}/getShortUrlVisits/pending`;
|
||||||
|
@ -24,10 +29,7 @@ export const GET_SHORT_URL_VISITS_FALLBACK_TO_INTERVAL = `${REDUCER_PREFIX}/getS
|
||||||
|
|
||||||
export interface ShortUrlVisits extends VisitsInfo, ShortUrlIdentifier {}
|
export interface ShortUrlVisits extends VisitsInfo, ShortUrlIdentifier {}
|
||||||
|
|
||||||
interface ShortUrlVisitsAction extends Action<string>, ShortUrlIdentifier {
|
type ShortUrlVisitsAction = VisitsLoadedAction<ShortUrlIdentifier>;
|
||||||
visits: Visit[];
|
|
||||||
query?: ShlinkVisitsParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LoadShortUrlVisits extends LoadVisits {
|
export interface LoadShortUrlVisits extends LoadVisits {
|
||||||
shortCode: string;
|
shortCode: string;
|
||||||
|
@ -53,12 +55,9 @@ const initialState: ShortUrlVisits = {
|
||||||
export default buildReducer<ShortUrlVisits, ShortUrlVisitsCombinedAction>({
|
export default buildReducer<ShortUrlVisits, ShortUrlVisitsCombinedAction>({
|
||||||
[`${REDUCER_PREFIX}/getShortUrlVisits/pending`]: () => ({ ...initialState, loading: true }),
|
[`${REDUCER_PREFIX}/getShortUrlVisits/pending`]: () => ({ ...initialState, loading: true }),
|
||||||
[`${REDUCER_PREFIX}/getShortUrlVisits/rejected`]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),
|
[`${REDUCER_PREFIX}/getShortUrlVisits/rejected`]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),
|
||||||
[`${REDUCER_PREFIX}/getShortUrlVisits/fulfilled`]: (state, { visits, query, shortCode, domain }) => ({
|
[`${REDUCER_PREFIX}/getShortUrlVisits/fulfilled`]: (state, { payload }: ShortUrlVisitsAction) => ({
|
||||||
...state,
|
...state,
|
||||||
visits,
|
...payload,
|
||||||
shortCode,
|
|
||||||
domain,
|
|
||||||
query,
|
|
||||||
loading: false,
|
loading: false,
|
||||||
loadingLarge: false,
|
loadingLarge: false,
|
||||||
error: false,
|
error: false,
|
||||||
|
@ -96,7 +95,7 @@ export const getShortUrlVisits = (buildShlinkApiClient: ShlinkApiClientBuilder)
|
||||||
async (params) => shlinkGetShortUrlVisits(shortCode, { ...params, domain: query.domain }),
|
async (params) => shlinkGetShortUrlVisits(shortCode, { ...params, domain: query.domain }),
|
||||||
);
|
);
|
||||||
const shouldCancel = () => getState().shortUrlVisits.cancelLoad;
|
const shouldCancel = () => getState().shortUrlVisits.cancelLoad;
|
||||||
const extraFinishActionData: Partial<ShortUrlVisitsAction> = { shortCode, query, domain: query.domain };
|
const extraFinishActionData: Partial<VisitsLoaded<ShortUrlIdentifier>> = { shortCode, query, domain: query.domain };
|
||||||
const prefix = `${REDUCER_PREFIX}/getShortUrlVisits`;
|
const prefix = `${REDUCER_PREFIX}/getShortUrlVisits`;
|
||||||
|
|
||||||
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { Action, Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { Visit } from '../types';
|
|
||||||
import { buildReducer } from '../../utils/helpers/redux';
|
import { buildReducer } from '../../utils/helpers/redux';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
import { ShlinkVisitsParams } from '../../api/types';
|
|
||||||
import { ApiErrorAction } from '../../api/types/actions';
|
import { ApiErrorAction } from '../../api/types/actions';
|
||||||
import { isBetween } from '../../utils/helpers/date';
|
import { isBetween } from '../../utils/helpers/date';
|
||||||
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
import { getVisitsWithLoader, lastVisitLoaderForLoader } from './common';
|
||||||
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
import { createNewVisits, CreateVisitsAction } from './visitCreation';
|
||||||
import { VisitsFallbackIntervalAction, VisitsInfo, VisitsLoadProgressChangedAction } from './types';
|
import {
|
||||||
|
LoadVisits,
|
||||||
|
VisitsFallbackIntervalAction,
|
||||||
|
VisitsInfo,
|
||||||
|
VisitsLoaded,
|
||||||
|
VisitsLoadedAction,
|
||||||
|
VisitsLoadProgressChangedAction,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
const REDUCER_PREFIX = 'shlink/tagVisits';
|
const REDUCER_PREFIX = 'shlink/tagVisits';
|
||||||
export const GET_TAG_VISITS_START = `${REDUCER_PREFIX}/getTagVisits/pending`;
|
export const GET_TAG_VISITS_START = `${REDUCER_PREFIX}/getTagVisits/pending`;
|
||||||
|
@ -24,12 +29,12 @@ export interface TagVisits extends VisitsInfo {
|
||||||
tag: string;
|
tag: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TagVisitsAction extends Action<string> {
|
export interface LoadTagVisits extends LoadVisits {
|
||||||
visits: Visit[];
|
|
||||||
tag: string;
|
tag: string;
|
||||||
query?: ShlinkVisitsParams;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TagVisitsAction = VisitsLoadedAction<{ tag: string }>;
|
||||||
|
|
||||||
type TagsVisitsCombinedAction = TagVisitsAction
|
type TagsVisitsCombinedAction = TagVisitsAction
|
||||||
& VisitsLoadProgressChangedAction
|
& VisitsLoadProgressChangedAction
|
||||||
& VisitsFallbackIntervalAction
|
& VisitsFallbackIntervalAction
|
||||||
|
@ -49,8 +54,8 @@ const initialState: TagVisits = {
|
||||||
export default buildReducer<TagVisits, TagsVisitsCombinedAction>({
|
export default buildReducer<TagVisits, TagsVisitsCombinedAction>({
|
||||||
[`${REDUCER_PREFIX}/getTagVisits/pending`]: () => ({ ...initialState, loading: true }),
|
[`${REDUCER_PREFIX}/getTagVisits/pending`]: () => ({ ...initialState, loading: true }),
|
||||||
[`${REDUCER_PREFIX}/getTagVisits/rejected`]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),
|
[`${REDUCER_PREFIX}/getTagVisits/rejected`]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),
|
||||||
[`${REDUCER_PREFIX}/getTagVisits/fulfilled`]: (state, { visits, tag, query }) => (
|
[`${REDUCER_PREFIX}/getTagVisits/fulfilled`]: (state, { payload }: TagVisitsAction) => (
|
||||||
{ ...state, visits, tag, query, loading: false, loadingLarge: false, error: false }
|
{ ...state, ...payload, loading: false, loadingLarge: false, error: false }
|
||||||
),
|
),
|
||||||
[`${REDUCER_PREFIX}/getTagVisits/large`]: (state) => ({ ...state, loadingLarge: true }),
|
[`${REDUCER_PREFIX}/getTagVisits/large`]: (state) => ({ ...state, loadingLarge: true }),
|
||||||
[`${REDUCER_PREFIX}/getTagVisits/cancel`]: (state) => ({ ...state, cancelLoad: true }),
|
[`${REDUCER_PREFIX}/getTagVisits/cancel`]: (state) => ({ ...state, cancelLoad: true }),
|
||||||
|
@ -70,9 +75,7 @@ export default buildReducer<TagVisits, TagsVisitsCombinedAction>({
|
||||||
}, initialState);
|
}, initialState);
|
||||||
|
|
||||||
export const getTagVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (
|
export const getTagVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (
|
||||||
tag: string,
|
{ tag, query = {}, doIntervalFallback = false }: LoadTagVisits,
|
||||||
query: ShlinkVisitsParams = {},
|
|
||||||
doIntervalFallback = false,
|
|
||||||
) => async (dispatch: Dispatch, getState: GetState) => {
|
) => async (dispatch: Dispatch, getState: GetState) => {
|
||||||
const { getTagVisits: getVisits } = buildShlinkApiClient(getState);
|
const { getTagVisits: getVisits } = buildShlinkApiClient(getState);
|
||||||
const visitsLoader = async (page: number, itemsPerPage: number) => getVisits(
|
const visitsLoader = async (page: number, itemsPerPage: number) => getVisits(
|
||||||
|
@ -81,7 +84,7 @@ export const getTagVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (
|
||||||
);
|
);
|
||||||
const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, async (params) => getVisits(tag, params));
|
const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, async (params) => getVisits(tag, params));
|
||||||
const shouldCancel = () => getState().tagVisits.cancelLoad;
|
const shouldCancel = () => getState().tagVisits.cancelLoad;
|
||||||
const extraFinishActionData: Partial<TagVisitsAction> = { tag, query };
|
const extraFinishActionData: Partial<VisitsLoaded<{ tag: string }>> = { tag, query };
|
||||||
const prefix = `${REDUCER_PREFIX}/getTagVisits`;
|
const prefix = `${REDUCER_PREFIX}/getTagVisits`;
|
||||||
|
|
||||||
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
return getVisitsWithLoader(visitsLoader, lastVisitLoader, extraFinishActionData, prefix, dispatch, shouldCancel);
|
||||||
|
|
|
@ -21,6 +21,13 @@ export interface LoadVisits {
|
||||||
doIntervalFallback?: boolean;
|
doIntervalFallback?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type VisitsLoaded<T = {}> = T & {
|
||||||
|
visits: Visit[];
|
||||||
|
query?: ShlinkVisitsParams;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type VisitsLoadedAction<T = {}> = PayloadAction<VisitsLoaded<T>>;
|
||||||
|
|
||||||
export type VisitsLoadProgressChangedAction = PayloadAction<number>;
|
export type VisitsLoadProgressChangedAction = PayloadAction<number>;
|
||||||
|
|
||||||
export type VisitsFallbackIntervalAction = PayloadAction<DateInterval>;
|
export type VisitsFallbackIntervalAction = PayloadAction<DateInterval>;
|
||||||
|
|
|
@ -1,22 +1,9 @@
|
||||||
import { Action } from 'redux';
|
import { Action } from 'redux';
|
||||||
import { buildActionCreator, buildReducer } from '../../../src/utils/helpers/redux';
|
import { buildReducer } from '../../../src/utils/helpers/redux';
|
||||||
|
|
||||||
describe('redux', () => {
|
describe('redux', () => {
|
||||||
beforeEach(jest.clearAllMocks);
|
beforeEach(jest.clearAllMocks);
|
||||||
|
|
||||||
describe('buildActionCreator', () => {
|
|
||||||
it.each([
|
|
||||||
['foo', { type: 'foo' }],
|
|
||||||
['bar', { type: 'bar' }],
|
|
||||||
['something', { type: 'something' }],
|
|
||||||
])('returns an action creator', (type, expected) => {
|
|
||||||
const actionCreator = buildActionCreator(type);
|
|
||||||
|
|
||||||
expect(actionCreator).toBeInstanceOf(Function);
|
|
||||||
expect(actionCreator()).toEqual(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('buildReducer', () => {
|
describe('buildReducer', () => {
|
||||||
const fooActionHandler = jest.fn(() => 'foo result');
|
const fooActionHandler = jest.fn(() => 'foo result');
|
||||||
const barActionHandler = jest.fn(() => 'bar result');
|
const barActionHandler = jest.fn(() => 'bar result');
|
||||||
|
|
|
@ -61,10 +61,10 @@ describe('domainVisitsReducer', () => {
|
||||||
|
|
||||||
it('return visits on GET_DOMAIN_VISITS', () => {
|
it('return visits on GET_DOMAIN_VISITS', () => {
|
||||||
const actionVisits = [{}, {}];
|
const actionVisits = [{}, {}];
|
||||||
const state = reducer(
|
const state = reducer(buildState({ loading: true, error: false }), {
|
||||||
buildState({ loading: true, error: false }),
|
type: GET_DOMAIN_VISITS,
|
||||||
{ type: GET_DOMAIN_VISITS, visits: actionVisits } as any,
|
payload: { visits: actionVisits },
|
||||||
);
|
} as any);
|
||||||
const { loading, error, visits } = state;
|
const { loading, error, visits } = state;
|
||||||
|
|
||||||
expect(loading).toEqual(false);
|
expect(loading).toEqual(false);
|
||||||
|
@ -201,7 +201,10 @@ describe('domainVisitsReducer', () => {
|
||||||
|
|
||||||
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_DOMAIN_VISITS_START });
|
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_DOMAIN_VISITS_START });
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(2, { type: GET_DOMAIN_VISITS, visits, domain, query: query ?? {} });
|
expect(dispatchMock).toHaveBeenNthCalledWith(2, {
|
||||||
|
type: GET_DOMAIN_VISITS,
|
||||||
|
payload: { visits, domain, query: query ?? {} },
|
||||||
|
});
|
||||||
expect(shlinkApiClient.getDomainVisits).toHaveBeenCalledTimes(1);
|
expect(shlinkApiClient.getDomainVisits).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,10 @@ describe('nonOrphanVisitsReducer', () => {
|
||||||
|
|
||||||
it('return visits on GET_NON_ORPHAN_VISITS', () => {
|
it('return visits on GET_NON_ORPHAN_VISITS', () => {
|
||||||
const actionVisits = [{}, {}];
|
const actionVisits = [{}, {}];
|
||||||
const state = reducer(
|
const state = reducer(buildState({ loading: true, error: false }), {
|
||||||
buildState({ loading: true, error: false }),
|
type: GET_NON_ORPHAN_VISITS,
|
||||||
{ type: GET_NON_ORPHAN_VISITS, visits: actionVisits } as any,
|
payload: { visits: actionVisits },
|
||||||
);
|
} as any);
|
||||||
const { loading, error, visits } = state;
|
const { loading, error, visits } = state;
|
||||||
|
|
||||||
expect(loading).toEqual(false);
|
expect(loading).toEqual(false);
|
||||||
|
@ -173,7 +173,10 @@ describe('nonOrphanVisitsReducer', () => {
|
||||||
|
|
||||||
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_NON_ORPHAN_VISITS_START });
|
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_NON_ORPHAN_VISITS_START });
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(2, { type: GET_NON_ORPHAN_VISITS, visits, query: query ?? {} });
|
expect(dispatchMock).toHaveBeenNthCalledWith(2, {
|
||||||
|
type: GET_NON_ORPHAN_VISITS,
|
||||||
|
payload: { visits, query: query ?? {} },
|
||||||
|
});
|
||||||
expect(ShlinkApiClient.getNonOrphanVisits).toHaveBeenCalledTimes(1);
|
expect(ShlinkApiClient.getNonOrphanVisits).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,10 @@ describe('orphanVisitsReducer', () => {
|
||||||
|
|
||||||
it('return visits on GET_ORPHAN_VISITS', () => {
|
it('return visits on GET_ORPHAN_VISITS', () => {
|
||||||
const actionVisits = [{}, {}];
|
const actionVisits = [{}, {}];
|
||||||
const state = reducer(
|
const state = reducer(buildState({ loading: true, error: false }), {
|
||||||
buildState({ loading: true, error: false }),
|
type: GET_ORPHAN_VISITS,
|
||||||
{ type: GET_ORPHAN_VISITS, visits: actionVisits } as any,
|
payload: { visits: actionVisits },
|
||||||
);
|
} as any);
|
||||||
const { loading, error, visits } = state;
|
const { loading, error, visits } = state;
|
||||||
|
|
||||||
expect(loading).toEqual(false);
|
expect(loading).toEqual(false);
|
||||||
|
@ -173,7 +173,10 @@ describe('orphanVisitsReducer', () => {
|
||||||
|
|
||||||
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_ORPHAN_VISITS_START });
|
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_ORPHAN_VISITS_START });
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(2, { type: GET_ORPHAN_VISITS, visits, query: query ?? {} });
|
expect(dispatchMock).toHaveBeenNthCalledWith(2, {
|
||||||
|
type: GET_ORPHAN_VISITS,
|
||||||
|
payload: { visits, query: query ?? {} },
|
||||||
|
});
|
||||||
expect(ShlinkApiClient.getOrphanVisits).toHaveBeenCalledTimes(1);
|
expect(ShlinkApiClient.getOrphanVisits).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,10 @@ describe('shortUrlVisitsReducer', () => {
|
||||||
|
|
||||||
it('return visits on GET_SHORT_URL_VISITS', () => {
|
it('return visits on GET_SHORT_URL_VISITS', () => {
|
||||||
const actionVisits = [{}, {}];
|
const actionVisits = [{}, {}];
|
||||||
const state = reducer(
|
const state = reducer(buildState({ loading: true, error: false }), {
|
||||||
buildState({ loading: true, error: false }),
|
type: GET_SHORT_URL_VISITS,
|
||||||
{ type: GET_SHORT_URL_VISITS, visits: actionVisits } as any,
|
payload: { visits: actionVisits },
|
||||||
);
|
} as any);
|
||||||
const { loading, error, visits } = state;
|
const { loading, error, visits } = state;
|
||||||
|
|
||||||
expect(loading).toEqual(false);
|
expect(loading).toEqual(false);
|
||||||
|
@ -195,10 +195,10 @@ describe('shortUrlVisitsReducer', () => {
|
||||||
|
|
||||||
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_SHORT_URL_VISITS_START });
|
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_SHORT_URL_VISITS_START });
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(
|
expect(dispatchMock).toHaveBeenNthCalledWith(2, {
|
||||||
2,
|
type: GET_SHORT_URL_VISITS,
|
||||||
{ type: GET_SHORT_URL_VISITS, visits, shortCode, domain, query: query ?? {} },
|
payload: { visits, shortCode, domain, query: query ?? {} },
|
||||||
);
|
});
|
||||||
expect(ShlinkApiClient.getShortUrlVisits).toHaveBeenCalledTimes(1);
|
expect(ShlinkApiClient.getShortUrlVisits).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -218,7 +218,9 @@ describe('shortUrlVisitsReducer', () => {
|
||||||
|
|
||||||
expect(ShlinkApiClient.getShortUrlVisits).toHaveBeenCalledTimes(expectedRequests);
|
expect(ShlinkApiClient.getShortUrlVisits).toHaveBeenCalledTimes(expectedRequests);
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(3, expect.objectContaining({
|
expect(dispatchMock).toHaveBeenNthCalledWith(3, expect.objectContaining({
|
||||||
visits: [...visitsMocks, ...visitsMocks, ...visitsMocks],
|
payload: expect.objectContaining({
|
||||||
|
visits: [...visitsMocks, ...visitsMocks, ...visitsMocks],
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,10 @@ describe('tagVisitsReducer', () => {
|
||||||
|
|
||||||
it('return visits on GET_TAG_VISITS', () => {
|
it('return visits on GET_TAG_VISITS', () => {
|
||||||
const actionVisits = [{}, {}];
|
const actionVisits = [{}, {}];
|
||||||
const state = reducer(
|
const state = reducer(buildState({ loading: true, error: false }), {
|
||||||
buildState({ loading: true, error: false }),
|
type: GET_TAG_VISITS,
|
||||||
{ type: GET_TAG_VISITS, visits: actionVisits } as any,
|
payload: { visits: actionVisits },
|
||||||
);
|
} as any);
|
||||||
const { loading, error, visits } = state;
|
const { loading, error, visits } = state;
|
||||||
|
|
||||||
expect(loading).toEqual(false);
|
expect(loading).toEqual(false);
|
||||||
|
@ -165,7 +165,7 @@ describe('tagVisitsReducer', () => {
|
||||||
it('dispatches start and error when promise is rejected', async () => {
|
it('dispatches start and error when promise is rejected', async () => {
|
||||||
const shlinkApiClient = buildApiClientMock(Promise.reject(new Error()));
|
const shlinkApiClient = buildApiClientMock(Promise.reject(new Error()));
|
||||||
|
|
||||||
await getTagVisits(() => shlinkApiClient)('foo')(dispatchMock, getState);
|
await getTagVisits(() => shlinkApiClient)({ tag })(dispatchMock, getState);
|
||||||
|
|
||||||
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_TAG_VISITS_START });
|
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_TAG_VISITS_START });
|
||||||
|
@ -187,11 +187,14 @@ describe('tagVisitsReducer', () => {
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await getTagVisits(() => shlinkApiClient)(tag, query)(dispatchMock, getState);
|
await getTagVisits(() => shlinkApiClient)({ tag, query })(dispatchMock, getState);
|
||||||
|
|
||||||
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_TAG_VISITS_START });
|
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_TAG_VISITS_START });
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(2, { type: GET_TAG_VISITS, visits, tag, query: query ?? {} });
|
expect(dispatchMock).toHaveBeenNthCalledWith(2, {
|
||||||
|
type: GET_TAG_VISITS,
|
||||||
|
payload: { visits, tag, query: query ?? {} },
|
||||||
|
});
|
||||||
expect(shlinkApiClient.getTagVisits).toHaveBeenCalledTimes(1);
|
expect(shlinkApiClient.getTagVisits).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -219,7 +222,7 @@ describe('tagVisitsReducer', () => {
|
||||||
.mockResolvedValueOnce(buildVisitsResult(lastVisits));
|
.mockResolvedValueOnce(buildVisitsResult(lastVisits));
|
||||||
const ShlinkApiClient = Mock.of<ShlinkApiClient>({ getTagVisits: getShlinkTagVisits });
|
const ShlinkApiClient = Mock.of<ShlinkApiClient>({ getTagVisits: getShlinkTagVisits });
|
||||||
|
|
||||||
await getTagVisits(() => ShlinkApiClient)(tag, {}, true)(dispatchMock, getState);
|
await getTagVisits(() => ShlinkApiClient)({ tag, doIntervalFallback: true })(dispatchMock, getState);
|
||||||
|
|
||||||
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_TAG_VISITS_START });
|
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_TAG_VISITS_START });
|
||||||
|
|
Loading…
Reference in a new issue