Use apiClient factory to dynamically resolved different values at runtime

This commit is contained in:
Alejandro Celaya
2023-07-26 20:04:50 +02:00
parent 3a0cea1268
commit d49da185d3
33 changed files with 146 additions and 80 deletions

View File

@@ -1,11 +1,11 @@
import { createAction, createSlice } from '@reduxjs/toolkit';
import { flatten, prop, range, splitEvery } from 'ramda';
import type { ShlinkState } from '../../../src/container/types';
import type { DateInterval } from '../../../src/utils/helpers/dateIntervals';
import { dateToMatchingInterval } from '../../../src/utils/helpers/dateIntervals';
import { createAsyncThunk } from '../../../src/utils/helpers/redux';
import type { ShlinkPaginator, ShlinkVisits, ShlinkVisitsParams } from '../../api-contract';
import { parseApiError } from '../../api-contract/utils';
import type { RootState } from '../../container/store';
import { createAsyncThunk } from '../../utils/redux';
import type { CreateVisit, Visit } from '../types';
import type { LoadVisits, VisitsInfo, VisitsLoaded } from './types';
import { createNewVisits } from './visitCreation';
@@ -24,7 +24,7 @@ interface VisitsAsyncThunkOptions<T extends LoadVisits = LoadVisits, R extends V
typePrefix: string;
createLoaders: (params: T) => [VisitsLoader, LastVisitLoader];
getExtraFulfilledPayload: (params: T) => Partial<R>;
shouldCancel: (getState: () => ShlinkState) => boolean;
shouldCancel: (getState: () => RootState) => boolean;
}
export const createVisitsAsyncThunk = <T extends LoadVisits = LoadVisits, R extends VisitsLoaded = VisitsLoaded>(

View File

@@ -26,10 +26,10 @@ const initialState: DomainVisits = {
progress: 0,
};
export const getDomainVisits = (apiClient: ShlinkApiClient) => createVisitsAsyncThunk({
export const getDomainVisits = (apiClientFactory: () => ShlinkApiClient) => createVisitsAsyncThunk({
typePrefix: `${REDUCER_PREFIX}/getDomainVisits`,
createLoaders: ({ domain, query = {}, doIntervalFallback = false }: LoadDomainVisits) => {
const { getDomainVisits: getVisits } = apiClient;
const { getDomainVisits: getVisits } = apiClientFactory();
const visitsLoader = async (page: number, itemsPerPage: number) => getVisits(
domain,
{ ...query, page, itemsPerPage },

View File

@@ -14,10 +14,10 @@ const initialState: VisitsInfo = {
progress: 0,
};
export const getNonOrphanVisits = (apiClient: ShlinkApiClient) => createVisitsAsyncThunk({
export const getNonOrphanVisits = (apiClientFactory: () => ShlinkApiClient) => createVisitsAsyncThunk({
typePrefix: `${REDUCER_PREFIX}/getNonOrphanVisits`,
createLoaders: ({ query = {}, doIntervalFallback = false }) => {
const { getNonOrphanVisits: shlinkGetNonOrphanVisits } = apiClient;
const { getNonOrphanVisits: shlinkGetNonOrphanVisits } = apiClientFactory();
const visitsLoader = async (page: number, itemsPerPage: number) =>
shlinkGetNonOrphanVisits({ ...query, page, itemsPerPage });
const lastVisitLoader = lastVisitLoaderForLoader(doIntervalFallback, shlinkGetNonOrphanVisits);

View File

@@ -23,10 +23,10 @@ const initialState: VisitsInfo = {
const matchesType = (visit: OrphanVisit, orphanVisitsType?: OrphanVisitType) =>
!orphanVisitsType || orphanVisitsType === visit.type;
export const getOrphanVisits = (apiClient: ShlinkApiClient) => createVisitsAsyncThunk({
export const getOrphanVisits = (apiClientFactory: () => ShlinkApiClient) => createVisitsAsyncThunk({
typePrefix: `${REDUCER_PREFIX}/getOrphanVisits`,
createLoaders: ({ orphanVisitsType, query = {}, doIntervalFallback = false }: LoadOrphanVisits) => {
const { getOrphanVisits: getVisits } = apiClient;
const { getOrphanVisits: getVisits } = apiClientFactory();
const visitsLoader = async (page: number, itemsPerPage: number) => getVisits({ ...query, page, itemsPerPage })
.then((result) => {
const visits = result.data.filter((visit) => isOrphanVisit(visit) && matchesType(visit, orphanVisitsType));

View File

@@ -24,10 +24,10 @@ const initialState: ShortUrlVisits = {
progress: 0,
};
export const getShortUrlVisits = (apiClient: ShlinkApiClient) => createVisitsAsyncThunk({
export const getShortUrlVisits = (apiClientFactory: () => ShlinkApiClient) => createVisitsAsyncThunk({
typePrefix: `${REDUCER_PREFIX}/getShortUrlVisits`,
createLoaders: ({ shortCode, query = {}, doIntervalFallback = false }: LoadShortUrlVisits) => {
const { getShortUrlVisits: shlinkGetShortUrlVisits } = apiClient;
const { getShortUrlVisits: shlinkGetShortUrlVisits } = apiClientFactory();
const visitsLoader = async (page: number, itemsPerPage: number) => shlinkGetShortUrlVisits(
shortCode,
{ ...query, page, itemsPerPage },

View File

@@ -23,10 +23,10 @@ const initialState: TagVisits = {
progress: 0,
};
export const getTagVisits = (apiClient: ShlinkApiClient) => createVisitsAsyncThunk({
export const getTagVisits = (apiClientFactory: () => ShlinkApiClient) => createVisitsAsyncThunk({
typePrefix: `${REDUCER_PREFIX}/getTagVisits`,
createLoaders: ({ tag, query = {}, doIntervalFallback = false }: LoadTagVisits) => {
const { getTagVisits: getVisits } = apiClient;
const { getTagVisits: getVisits } = apiClientFactory();
const visitsLoader = async (page: number, itemsPerPage: number) => getVisits(
tag,
{ ...query, page, itemsPerPage },

View File

@@ -1,7 +1,7 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { createAsyncThunk } from '../../../src/utils/helpers/redux';
import type { ShlinkApiClient, ShlinkVisitsOverview } from '../../api-contract';
import { createAsyncThunk } from '../../utils/redux';
import type { CreateVisit } from '../types';
import { groupNewVisitsByType } from '../types/helpers';
import { createNewVisits } from './visitCreation';
@@ -39,9 +39,9 @@ const initialState: VisitsOverview = {
const countBots = (visits: CreateVisit[]) => visits.filter(({ visit }) => visit.potentialBot).length;
export const loadVisitsOverview = (apiClient: ShlinkApiClient) => createAsyncThunk(
export const loadVisitsOverview = (apiClientFactory: () => ShlinkApiClient) => createAsyncThunk(
`${REDUCER_PREFIX}/loadVisitsOverview`,
(): Promise<ParsedVisitsOverview> => apiClient.getVisitsOverview().then(
(): Promise<ParsedVisitsOverview> => apiClientFactory().getVisitsOverview().then(
({ nonOrphanVisits, visitsCount, orphanVisits, orphanVisitsCount }) => ({
nonOrphanVisits: {
total: nonOrphanVisits?.total ?? visitsCount,

View File

@@ -54,23 +54,23 @@ export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
bottle.serviceFactory('VisitsParser', () => visitsParser);
// Actions
bottle.serviceFactory('getShortUrlVisits', getShortUrlVisits, 'apiClient');
bottle.serviceFactory('getShortUrlVisits', getShortUrlVisits, 'apiClientFactory');
bottle.serviceFactory('cancelGetShortUrlVisits', prop('cancelGetVisits'), 'shortUrlVisitsReducerCreator');
bottle.serviceFactory('getTagVisits', getTagVisits, 'apiClient');
bottle.serviceFactory('getTagVisits', getTagVisits, 'apiClientFactory');
bottle.serviceFactory('cancelGetTagVisits', prop('cancelGetVisits'), 'tagVisitsReducerCreator');
bottle.serviceFactory('getDomainVisits', getDomainVisits, 'apiClient');
bottle.serviceFactory('getDomainVisits', getDomainVisits, 'apiClientFactory');
bottle.serviceFactory('cancelGetDomainVisits', prop('cancelGetVisits'), 'domainVisitsReducerCreator');
bottle.serviceFactory('getOrphanVisits', getOrphanVisits, 'apiClient');
bottle.serviceFactory('getOrphanVisits', getOrphanVisits, 'apiClientFactory');
bottle.serviceFactory('cancelGetOrphanVisits', prop('cancelGetVisits'), 'orphanVisitsReducerCreator');
bottle.serviceFactory('getNonOrphanVisits', getNonOrphanVisits, 'apiClient');
bottle.serviceFactory('getNonOrphanVisits', getNonOrphanVisits, 'apiClientFactory');
bottle.serviceFactory('cancelGetNonOrphanVisits', prop('cancelGetVisits'), 'nonOrphanVisitsReducerCreator');
bottle.serviceFactory('createNewVisits', () => createNewVisits);
bottle.serviceFactory('loadVisitsOverview', loadVisitsOverview, 'apiClient');
bottle.serviceFactory('loadVisitsOverview', loadVisitsOverview, 'apiClientFactory');
// Reducers
bottle.serviceFactory('visitsOverviewReducerCreator', visitsOverviewReducerCreator, 'loadVisitsOverview');