From ba48104c5cc825c09b72c4b29085ad3fcdb3b0a3 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 13 Nov 2022 09:59:49 +0100 Subject: [PATCH] Refactored createVisitsReducer so that it expects an object param --- src/visits/reducers/common.ts | 28 +++++++++++++++----------- src/visits/reducers/domainVisits.ts | 16 +++++++-------- src/visits/reducers/nonOrphanVisits.ts | 14 ++++++------- src/visits/reducers/orphanVisits.ts | 15 +++++++------- src/visits/reducers/shortUrlVisits.ts | 16 +++++++-------- src/visits/reducers/tagVisits.ts | 14 ++++++------- 6 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/visits/reducers/common.ts b/src/visits/reducers/common.ts index af1eedd1..a5ae208f 100644 --- a/src/visits/reducers/common.ts +++ b/src/visits/reducers/common.ts @@ -20,20 +20,20 @@ type VisitsLoader = (page: number, itemsPerPage: number) => Promise Promise; interface VisitsAsyncThunkOptions { - name: string; + typePrefix: string; createLoaders: (params: T, getState: () => ShlinkState) => [VisitsLoader, LastVisitLoader]; getExtraFulfilledPayload: (params: T) => Partial; shouldCancel: (getState: () => ShlinkState) => boolean; } export const createVisitsAsyncThunk = ( - { name, createLoaders, getExtraFulfilledPayload, shouldCancel }: VisitsAsyncThunkOptions, + { typePrefix, createLoaders, getExtraFulfilledPayload, shouldCancel }: VisitsAsyncThunkOptions, ) => { - const progressChangedAction = createAction(`${name}/progressChanged`); - const largeAction = createAction(`${name}/large`); - const fallbackToIntervalAction = createAction(`${name}/fallbackToInterval`); + const progressChangedAction = createAction(`${typePrefix}/progressChanged`); + const largeAction = createAction(`${typePrefix}/large`); + const fallbackToIntervalAction = createAction(`${typePrefix}/fallbackToInterval`); - const asyncThunk = createAsyncThunk(name, async (params: T, { getState, dispatch }): Promise => { + const asyncThunk = createAsyncThunk(typePrefix, async (params: T, { getState, dispatch }): Promise => { const [visitsLoader, lastVisitLoader] = createLoaders(params, getState); const loadVisitsInParallel = async (pages: number[]): Promise => @@ -97,11 +97,15 @@ export const lastVisitLoaderForLoader = ( return async () => loader({ page: 1, itemsPerPage: 1 }).then(({ data }) => data[0]); }; +interface VisitsReducerOptions> { + name: string; + asyncThunkCreator: AT; + initialState: State; + filterCreatedVisits: (state: State, createdVisits: CreateVisit[]) => CreateVisit[]; +} + export const createVisitsReducer = >( - name: string, - asyncThunkCreator: AT, - initialState: State, - filterCreatedVisits: (state: State, createdVisits: CreateVisit[]) => CreateVisit[], + { name, asyncThunkCreator, initialState, filterCreatedVisits }: VisitsReducerOptions, ) => { const { asyncThunk, largeAction, fallbackToIntervalAction, progressChangedAction } = asyncThunkCreator; const { reducer, actions } = createSlice({ @@ -127,10 +131,10 @@ export const createVisitsReducer = { const { visits } = state; - // @ts-expect-error TODO Fix the state inferred type + // @ts-expect-error TODO Fix type inference const newVisits = filterCreatedVisits(state, payload.createdVisits).map(({ visit }) => visit); - return { ...state, visits: [...newVisits, ...visits] }; + return !newVisits.length ? state : { ...state, visits: [...newVisits, ...visits] }; }); }, }); diff --git a/src/visits/reducers/domainVisits.ts b/src/visits/reducers/domainVisits.ts index 9b258d09..a44d1cfc 100644 --- a/src/visits/reducers/domainVisits.ts +++ b/src/visits/reducers/domainVisits.ts @@ -27,7 +27,7 @@ const initialState: DomainVisits = { }; export const getDomainVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => createVisitsAsyncThunk({ - name: `${REDUCER_PREFIX}/getDomainVisits`, + typePrefix: `${REDUCER_PREFIX}/getDomainVisits`, createLoaders: ({ domain, query = {}, doIntervalFallback = false }: LoadDomainVisits, getState) => { const { getDomainVisits: getVisits } = buildShlinkApiClient(getState); const visitsLoader = async (page: number, itemsPerPage: number) => getVisits( @@ -43,17 +43,17 @@ export const getDomainVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => }); export const domainVisitsReducerCreator = ( - getVisitsCreator: ReturnType, -) => createVisitsReducer( - REDUCER_PREFIX, - // @ts-expect-error TODO Fix type inference - getVisitsCreator, + asyncThunkCreator: ReturnType, +) => createVisitsReducer({ + name: REDUCER_PREFIX, initialState, - ({ domain, query = {} }, createdVisits) => { + // @ts-expect-error TODO Fix type inference + asyncThunkCreator, + filterCreatedVisits: ({ domain, query = {} }, createdVisits) => { const { startDate, endDate } = query; return createdVisits.filter( ({ shortUrl, visit }) => shortUrl && domainMatches(shortUrl, domain) && isBetween(visit.date, startDate, endDate), ); }, -); +}); diff --git a/src/visits/reducers/nonOrphanVisits.ts b/src/visits/reducers/nonOrphanVisits.ts index 6edde6a0..83db3f43 100644 --- a/src/visits/reducers/nonOrphanVisits.ts +++ b/src/visits/reducers/nonOrphanVisits.ts @@ -15,7 +15,7 @@ const initialState: VisitsInfo = { }; export const getNonOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => createVisitsAsyncThunk({ - name: `${REDUCER_PREFIX}/getNonOrphanVisits`, + typePrefix: `${REDUCER_PREFIX}/getNonOrphanVisits`, createLoaders: ({ query = {}, doIntervalFallback = false }, getState) => { const { getNonOrphanVisits: shlinkGetNonOrphanVisits } = buildShlinkApiClient(getState); const visitsLoader = async (page: number, itemsPerPage: number) => @@ -29,13 +29,13 @@ export const getNonOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) }); export const nonOrphanVisitsReducerCreator = ( - getVisitsCreator: ReturnType, -) => createVisitsReducer( - REDUCER_PREFIX, - getVisitsCreator, + asyncThunkCreator: ReturnType, +) => createVisitsReducer({ + name: REDUCER_PREFIX, initialState, - ({ query = {} }, createdVisits) => { + asyncThunkCreator, + filterCreatedVisits: ({ query = {} }, createdVisits) => { const { startDate, endDate } = query; return createdVisits.filter(({ visit }) => isBetween(visit.date, startDate, endDate)); }, -); +}); diff --git a/src/visits/reducers/orphanVisits.ts b/src/visits/reducers/orphanVisits.ts index 3b1bf87a..269aa764 100644 --- a/src/visits/reducers/orphanVisits.ts +++ b/src/visits/reducers/orphanVisits.ts @@ -24,13 +24,12 @@ const matchesType = (visit: OrphanVisit, orphanVisitsType?: OrphanVisitType) => !orphanVisitsType || orphanVisitsType === visit.type; export const getOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => createVisitsAsyncThunk({ - name: `${REDUCER_PREFIX}/getOrphanVisits`, + typePrefix: `${REDUCER_PREFIX}/getOrphanVisits`, createLoaders: ({ orphanVisitsType, query = {}, doIntervalFallback = false }: LoadOrphanVisits, getState) => { const { getOrphanVisits: getVisits } = buildShlinkApiClient(getState); const visitsLoader = async (page: number, itemsPerPage: number) => getVisits({ ...query, page, itemsPerPage }) .then((result) => { const visits = result.data.filter((visit) => isOrphanVisit(visit) && matchesType(visit, orphanVisitsType)); - return { ...result, data: visits }; }); const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, getVisits); @@ -42,13 +41,13 @@ export const getOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => }); export const orphanVisitsReducerCreator = ( - getVisitsCreator: ReturnType, -) => createVisitsReducer( - REDUCER_PREFIX, - getVisitsCreator, + asyncThunkCreator: ReturnType, +) => createVisitsReducer({ + name: REDUCER_PREFIX, initialState, - ({ query = {} }, createdVisits) => { + asyncThunkCreator, + filterCreatedVisits: ({ query = {} }, createdVisits) => { const { startDate, endDate } = query; return createdVisits.filter(({ visit, shortUrl }) => !shortUrl && isBetween(visit.date, startDate, endDate)); }, -); +}); diff --git a/src/visits/reducers/shortUrlVisits.ts b/src/visits/reducers/shortUrlVisits.ts index dc434850..1c434787 100644 --- a/src/visits/reducers/shortUrlVisits.ts +++ b/src/visits/reducers/shortUrlVisits.ts @@ -25,7 +25,7 @@ const initialState: ShortUrlVisits = { }; export const getShortUrlVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => createVisitsAsyncThunk({ - name: `${REDUCER_PREFIX}/getShortUrlVisits`, + typePrefix: `${REDUCER_PREFIX}/getShortUrlVisits`, createLoaders: ({ shortCode, query = {}, doIntervalFallback = false }: LoadShortUrlVisits, getState) => { const { getShortUrlVisits: shlinkGetShortUrlVisits } = buildShlinkApiClient(getState); const visitsLoader = async (page: number, itemsPerPage: number) => shlinkGetShortUrlVisits( @@ -46,17 +46,17 @@ export const getShortUrlVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) }); export const shortUrlVisitsReducerCreator = ( - getVisitsCreator: ReturnType, -) => createVisitsReducer( - REDUCER_PREFIX, - // @ts-expect-error TODO Fix type inference - getVisitsCreator, + asyncThunkCreator: ReturnType, +) => createVisitsReducer({ + name: REDUCER_PREFIX, initialState, - ({ shortCode, domain, query = {} }, createdVisits) => { + // @ts-expect-error TODO Fix type inference + asyncThunkCreator, + filterCreatedVisits: ({ shortCode, domain, query = {} }: ShortUrlVisits, createdVisits) => { const { startDate, endDate } = query; return createdVisits.filter( ({ shortUrl, visit }) => shortUrl && shortUrlMatches(shortUrl, shortCode, domain) && isBetween(visit.date, startDate, endDate), ); }, -); +}); diff --git a/src/visits/reducers/tagVisits.ts b/src/visits/reducers/tagVisits.ts index 1c1dace5..66b86ca0 100644 --- a/src/visits/reducers/tagVisits.ts +++ b/src/visits/reducers/tagVisits.ts @@ -24,7 +24,7 @@ const initialState: TagVisits = { }; export const getTagVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => createVisitsAsyncThunk({ - name: `${REDUCER_PREFIX}/getTagVisits`, + typePrefix: `${REDUCER_PREFIX}/getTagVisits`, createLoaders: ({ tag, query = {}, doIntervalFallback = false }: LoadTagVisits, getState) => { const { getTagVisits: getVisits } = buildShlinkApiClient(getState); const visitsLoader = async (page: number, itemsPerPage: number) => getVisits( @@ -39,15 +39,15 @@ export const getTagVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => cr shouldCancel: (getState) => getState().tagVisits.cancelLoad, }); -export const tagVisitsReducerCreator = (getTagVisitsCreator: ReturnType) => createVisitsReducer( - REDUCER_PREFIX, - // @ts-expect-error TODO Fix type inference - getTagVisitsCreator, +export const tagVisitsReducerCreator = (asyncThunkCreator: ReturnType) => createVisitsReducer({ + name: REDUCER_PREFIX, initialState, - ({ tag, query = {} }, createdVisits) => { + // @ts-expect-error TODO Fix type inference + asyncThunkCreator, + filterCreatedVisits: ({ tag, query = {} }: TagVisits, createdVisits) => { const { startDate, endDate } = query; return createdVisits.filter( ({ shortUrl, visit }) => shortUrl?.tags.includes(tag) && isBetween(visit.date, startDate, endDate), ); }, -); +});