Created section to display orphan visits stats

This commit is contained in:
Alejandro Celaya
2021-02-27 20:03:51 +01:00
parent 46d012b6ff
commit 5479210366
23 changed files with 342 additions and 36 deletions

View File

@@ -0,0 +1,69 @@
import { Action, Dispatch } from 'redux';
import { Visit, VisitsInfo, VisitsLoadFailedAction, VisitsLoadProgressChangedAction } from '../types';
import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
import { GetState } from '../../container/types';
import { getVisitsWithLoader } from './common';
import { CREATE_VISITS, CreateVisitsAction } from './visitCreation';
/* eslint-disable padding-line-between-statements */
export const GET_ORPHAN_VISITS_START = 'shlink/orphanVisits/GET_ORPHAN_VISITS_START';
export const GET_ORPHAN_VISITS_ERROR = 'shlink/orphanVisits/GET_ORPHAN_VISITS_ERROR';
export const GET_ORPHAN_VISITS = 'shlink/orphanVisits/GET_ORPHAN_VISITS';
export const GET_ORPHAN_VISITS_LARGE = 'shlink/orphanVisits/GET_ORPHAN_VISITS_LARGE';
export const GET_ORPHAN_VISITS_CANCEL = 'shlink/orphanVisits/GET_ORPHAN_VISITS_CANCEL';
export const GET_ORPHAN_VISITS_PROGRESS_CHANGED = 'shlink/orphanVisits/GET_ORPHAN_VISITS_PROGRESS_CHANGED';
/* eslint-enable padding-line-between-statements */
export interface OrphanVisitsAction extends Action<string> {
visits: Visit[];
}
type OrphanVisitsCombinedAction = OrphanVisitsAction
& VisitsLoadProgressChangedAction
& CreateVisitsAction
& VisitsLoadFailedAction;
const initialState: VisitsInfo = {
visits: [],
loading: false,
loadingLarge: false,
error: false,
cancelLoad: false,
progress: 0,
};
export default buildReducer<VisitsInfo, OrphanVisitsCombinedAction>({
[GET_ORPHAN_VISITS_START]: () => ({ ...initialState, loading: true }),
[GET_ORPHAN_VISITS_ERROR]: (_, { errorData }) => ({ ...initialState, error: true, errorData }),
[GET_ORPHAN_VISITS]: (_, { visits }) => ({ ...initialState, visits }),
[GET_ORPHAN_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),
[GET_ORPHAN_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),
[GET_ORPHAN_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),
[CREATE_VISITS]: (state, { createdVisits }) => {
const { visits } = state;
const newVisits = createdVisits.map(({ visit }) => visit);
return { ...state, visits: [ ...visits, ...newVisits ] };
},
}, initialState);
export const getOrphanVisits = (buildShlinkApiClient: ShlinkApiClientBuilder) => (query = {}) => async (
dispatch: Dispatch,
getState: GetState,
) => {
const { getOrphanVisits } = buildShlinkApiClient(getState);
const visitsLoader = async (page: number, itemsPerPage: number) => getOrphanVisits({ ...query, page, itemsPerPage });
const shouldCancel = () => getState().orphanVisits.cancelLoad;
const actionMap = {
start: GET_ORPHAN_VISITS_START,
large: GET_ORPHAN_VISITS_LARGE,
finish: GET_ORPHAN_VISITS,
error: GET_ORPHAN_VISITS_ERROR,
progress: GET_ORPHAN_VISITS_PROGRESS_CHANGED,
};
return getVisitsWithLoader(visitsLoader, {}, actionMap, dispatch, shouldCancel);
};
export const cancelGetOrphanVisits = buildActionCreator(GET_ORPHAN_VISITS_CANCEL);

View File

@@ -52,11 +52,10 @@ export default buildReducer<ShortUrlVisits, ShortUrlVisitsCombinedAction>({
[GET_SHORT_URL_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),
[GET_SHORT_URL_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),
[GET_SHORT_URL_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),
[CREATE_VISITS]: (state, { createdVisits }) => { // eslint-disable-line object-shorthand
[CREATE_VISITS]: (state, { createdVisits }) => {
const { shortCode, domain, visits } = state;
const newVisits = createdVisits
.filter(({ shortUrl }) => shortUrlMatches(shortUrl, shortCode, domain))
.filter(({ shortUrl }) => shortUrl && shortUrlMatches(shortUrl, shortCode, domain))
.map(({ visit }) => visit);
return { ...state, visits: [ ...visits, ...newVisits ] };

View File

@@ -46,10 +46,10 @@ export default buildReducer<TagVisits, TagsVisitsCombinedAction>({
[GET_TAG_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),
[GET_TAG_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),
[GET_TAG_VISITS_PROGRESS_CHANGED]: (state, { progress }) => ({ ...state, progress }),
[CREATE_VISITS]: (state, { createdVisits }) => { // eslint-disable-line object-shorthand
[CREATE_VISITS]: (state, { createdVisits }) => {
const { tag, visits } = state;
const newVisits = createdVisits
.filter(({ shortUrl }) => shortUrl.tags.includes(tag))
.filter(({ shortUrl }) => shortUrl?.tags.includes(tag))
.map(({ visit }) => visit);
return { ...state, visits: [ ...visits, ...newVisits ] };

View File

@@ -3,6 +3,7 @@ import { ShlinkVisitsOverview } from '../../api/types';
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
import { GetState } from '../../container/types';
import { buildReducer } from '../../utils/helpers/redux';
import { groupNewVisitsByType } from '../types/helpers';
import { CREATE_VISITS, CreateVisitsAction } from './visitCreation';
/* eslint-disable padding-line-between-statements */
@@ -31,10 +32,15 @@ export default buildReducer<VisitsOverview, GetVisitsOverviewAction & CreateVisi
[GET_OVERVIEW_START]: () => ({ ...initialState, loading: true }),
[GET_OVERVIEW_ERROR]: () => ({ ...initialState, error: true }),
[GET_OVERVIEW]: (_, { visitsCount, orphanVisitsCount }) => ({ ...initialState, visitsCount, orphanVisitsCount }),
[CREATE_VISITS]: ({ visitsCount, ...rest }, { createdVisits }) => ({
...rest,
visitsCount: visitsCount + createdVisits.length,
}),
[CREATE_VISITS]: ({ visitsCount, orphanVisitsCount = 0, ...rest }, { createdVisits }) => {
const { regularVisits, orphanVisits } = groupNewVisitsByType(createdVisits);
return {
...rest,
visitsCount: visitsCount + regularVisits.length,
orphanVisitsCount: orphanVisitsCount + orphanVisits.length,
};
},
}, initialState);
export const loadVisitsOverview = (buildShlinkApiClient: ShlinkApiClientBuilder) => () => async (