Take into consideration types of visits when increasing tags visits

This commit is contained in:
Alejandro Celaya 2023-03-19 11:44:40 +01:00
parent 927ab76dbd
commit 1d6464fefb
2 changed files with 91 additions and 6 deletions

View file

@ -8,7 +8,7 @@ import type { createShortUrl } from '../../short-urls/reducers/shortUrlCreation'
import { supportedFeatures } from '../../utils/helpers/features'; import { supportedFeatures } from '../../utils/helpers/features';
import { createAsyncThunk } from '../../utils/helpers/redux'; import { createAsyncThunk } from '../../utils/helpers/redux';
import { createNewVisits } from '../../visits/reducers/visitCreation'; import { createNewVisits } from '../../visits/reducers/visitCreation';
import type { CreateVisit, Stats } from '../../visits/types'; import type { CreateVisit } from '../../visits/types';
import type { TagStats } from '../data'; import type { TagStats } from '../data';
import { tagDeleted } from './tagDelete'; import { tagDeleted } from './tagDelete';
import { tagEdited } from './tagEdit'; import { tagEdited } from './tagEdit';
@ -39,7 +39,8 @@ const initialState: TagsList = {
error: false, error: false,
}; };
type TagIncrease = [string, number]; type TagIncreaseRecord = Record<string, { bots: number; nonBots: number }>;
type TagIncrease = [string, { bots: number; nonBots: 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);
@ -48,21 +49,34 @@ const increaseVisitsForTags = (tags: TagIncrease[], stats: TagsStatsMap) => tags
return theStats; return theStats;
} }
const { bots, nonBots } = increase;
const tagStats = theStats[tag]; const tagStats = theStats[tag];
// TODO take into consideration bots, nonBots and total
return { return {
...theStats, ...theStats,
[tag]: { [tag]: {
...tagStats, ...tagStats,
visitsCount: tagStats.visitsCount + increase, visitsSummary: tagStats.visitsSummary && {
total: tagStats.visitsSummary.total + bots + nonBots,
bots: tagStats.visitsSummary.bots + bots,
nonBots: tagStats.visitsSummary.nonBots + nonBots,
},
visitsCount: tagStats.visitsCount + bots + nonBots,
}, },
}; };
}, { ...stats }); }, { ...stats });
const calculateVisitsPerTag = (createdVisits: CreateVisit[]): TagIncrease[] => Object.entries( const calculateVisitsPerTag = (createdVisits: CreateVisit[]): TagIncrease[] => Object.entries(
createdVisits.reduce<Stats>((acc, { shortUrl }) => { createdVisits.reduce<TagIncreaseRecord>((acc, { shortUrl, visit }) => {
shortUrl?.tags.forEach((tag) => { shortUrl?.tags.forEach((tag) => {
acc[tag] = (acc[tag] || 0) + 1; if (!acc[tag]) {
acc[tag] = { bots: 0, nonBots: 0 };
}
if (visit.potentialBot) {
acc[tag].bots += 1;
} else {
acc[tag].nonBots += 1;
}
}); });
return acc; return acc;

View file

@ -11,6 +11,8 @@ import {
listTags as listTagsCreator, listTags as listTagsCreator,
tagsListReducerCreator, tagsListReducerCreator,
} from '../../../src/tags/reducers/tagsList'; } from '../../../src/tags/reducers/tagsList';
import { createNewVisits } from '../../../src/visits/reducers/visitCreation';
import type { CreateVisit, Visit } from '../../../src/visits/types';
describe('tagsListReducer', () => { describe('tagsListReducer', () => {
const state = (props: Partial<TagsList>) => Mock.of<TagsList>(props); const state = (props: Partial<TagsList>) => Mock.of<TagsList>(props);
@ -118,6 +120,75 @@ describe('tagsListReducer', () => {
tags: expectedTags, tags: expectedTags,
}); });
}); });
it('increases amounts when visits are created', () => {
const createdVisits = [
Mock.of<CreateVisit>({
shortUrl: Mock.of<ShortUrl>({ tags: ['foo', 'bar'] }),
visit: Mock.of<Visit>({ potentialBot: true }),
}),
Mock.of<CreateVisit>({
shortUrl: Mock.of<ShortUrl>({ tags: ['foo', 'bar'] }),
visit: Mock.all<Visit>(),
}),
Mock.of<CreateVisit>({
shortUrl: Mock.of<ShortUrl>({ tags: ['bar'] }),
visit: Mock.all<Visit>(),
}),
Mock.of<CreateVisit>({
shortUrl: Mock.of<ShortUrl>({ tags: ['baz'] }),
visit: Mock.of<Visit>({ potentialBot: true }),
}),
];
const tagStats = (total: number) => ({
shortUrlsCount: 1,
visitsCount: total,
visitsSummary: {
total,
nonBots: total - 10,
bots: 10,
},
});
const stateBefore = state({
stats: {
foo: tagStats(100),
bar: tagStats(200),
baz: tagStats(150),
},
});
expect(reducer(stateBefore, createNewVisits(createdVisits))).toEqual(expect.objectContaining({
stats: {
foo: {
shortUrlsCount: 1,
visitsCount: 100 + 2,
visitsSummary: {
total: 100 + 2,
nonBots: 90 + 1,
bots: 10 + 1,
},
},
bar: {
shortUrlsCount: 1,
visitsCount: 200 + 3,
visitsSummary: {
total: 200 + 3,
nonBots: 190 + 2,
bots: 10 + 1,
},
},
baz: {
shortUrlsCount: 1,
visitsCount: 150 + 1,
visitsSummary: {
total: 150 + 1,
nonBots: 140,
bots: 10 + 1,
},
},
},
}));
});
}); });
describe('filterTags', () => { describe('filterTags', () => {