Client - init utils methods needed for charts
This commit is contained in:
parent
0c516b9986
commit
3b8ac44433
@ -12,6 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"date-fns": "^2.23.0",
|
||||||
"register-service-worker": "^1.7.1",
|
"register-service-worker": "^1.7.1",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
"vue-i18n": "^9.1.0",
|
"vue-i18n": "^9.1.0",
|
||||||
@ -70,9 +71,13 @@
|
|||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"import/order": [
|
"import/order": [
|
||||||
"error", {
|
"error",
|
||||||
|
{
|
||||||
"newlines-between": "always",
|
"newlines-between": "always",
|
||||||
"alphabetize": { "order": "asc", "caseInsensitive": true}
|
"alphabetize": {
|
||||||
|
"order": "asc",
|
||||||
|
"caseInsensitive": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2,10 +2,10 @@ import { ActionContext } from 'vuex'
|
|||||||
|
|
||||||
import { STATS_STORE } from '@/store/constants'
|
import { STATS_STORE } from '@/store/constants'
|
||||||
import { IRootState } from '@/store/modules/root/interfaces'
|
import { IRootState } from '@/store/modules/root/interfaces'
|
||||||
import { IUserStatisticsPayload, TStatistics } from '@/types/statistics'
|
import { IUserStatisticsPayload, TStatisticsFromApi } from '@/types/statistics'
|
||||||
|
|
||||||
export interface IStatisticsState {
|
export interface IStatisticsState {
|
||||||
statistics: TStatistics
|
statistics: TStatisticsFromApi
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IStatisticsActions {
|
export interface IStatisticsActions {
|
||||||
@ -16,5 +16,5 @@ export interface IStatisticsActions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IStatisticsGetters {
|
export interface IStatisticsGetters {
|
||||||
[STATS_STORE.GETTERS.USER_STATS](state: IStatisticsState): TStatistics
|
[STATS_STORE.GETTERS.USER_STATS](state: IStatisticsState): TStatisticsFromApi
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,13 @@ import { MutationTree } from 'vuex'
|
|||||||
import { STATS_STORE } from '@/store/constants'
|
import { STATS_STORE } from '@/store/constants'
|
||||||
import { IStatisticsState } from '@/store/modules/statistics/interfaces'
|
import { IStatisticsState } from '@/store/modules/statistics/interfaces'
|
||||||
import { TStatisticsMutations } from '@/store/modules/statistics/types'
|
import { TStatisticsMutations } from '@/store/modules/statistics/types'
|
||||||
import { TStatistics } from '@/types/statistics'
|
import { TStatisticsFromApi } from '@/types/statistics'
|
||||||
|
|
||||||
export const mutations: MutationTree<IStatisticsState> & TStatisticsMutations =
|
export const mutations: MutationTree<IStatisticsState> & TStatisticsMutations =
|
||||||
{
|
{
|
||||||
[STATS_STORE.MUTATIONS.UPDATE_USER_STATS](
|
[STATS_STORE.MUTATIONS.UPDATE_USER_STATS](
|
||||||
state: IStatisticsState,
|
state: IStatisticsState,
|
||||||
statistics: TStatistics
|
statistics: TStatisticsFromApi
|
||||||
) {
|
) {
|
||||||
state.statistics = statistics
|
state.statistics = statistics
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { IStatisticsState } from '@/store/modules/statistics/interfaces'
|
import { IStatisticsState } from '@/store/modules/statistics/interfaces'
|
||||||
import { TStatistics } from '@/types/statistics'
|
import { TStatisticsFromApi } from '@/types/statistics'
|
||||||
|
|
||||||
export const statisticsState: IStatisticsState = {
|
export const statisticsState: IStatisticsState = {
|
||||||
statistics: <TStatistics>{},
|
statistics: <TStatisticsFromApi>{},
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ import {
|
|||||||
IStatisticsActions,
|
IStatisticsActions,
|
||||||
IStatisticsGetters,
|
IStatisticsGetters,
|
||||||
} from '@/store/modules/statistics/interfaces'
|
} from '@/store/modules/statistics/interfaces'
|
||||||
import { TStatistics } from '@/types/statistics'
|
import { TStatisticsFromApi } from '@/types/statistics'
|
||||||
|
|
||||||
export type TStatisticsMutations<S = IStatisticsState> = {
|
export type TStatisticsMutations<S = IStatisticsState> = {
|
||||||
[STATS_STORE.MUTATIONS.UPDATE_USER_STATS](
|
[STATS_STORE.MUTATIONS.UPDATE_USER_STATS](
|
||||||
state: S,
|
state: S,
|
||||||
statistics: TStatistics
|
statistics: TStatisticsFromApi
|
||||||
): void
|
): void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
fittrackee_client/src/types/generic.ts
Normal file
3
fittrackee_client/src/types/generic.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export type genericObject = {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
@ -1,12 +1,3 @@
|
|||||||
export interface IStatistics {
|
|
||||||
nb_workouts: number
|
|
||||||
total_distance: number
|
|
||||||
total_duration: number
|
|
||||||
}
|
|
||||||
export type TStatistics = {
|
|
||||||
[key in string | number]: IStatistics
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IStatisticsParams {
|
export interface IStatisticsParams {
|
||||||
from: string
|
from: string
|
||||||
to: string
|
to: string
|
||||||
@ -18,3 +9,37 @@ export interface IUserStatisticsPayload {
|
|||||||
filterType: string
|
filterType: string
|
||||||
params: IStatisticsParams
|
params: IStatisticsParams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IStatisticsDateParams {
|
||||||
|
duration: string
|
||||||
|
start: Date
|
||||||
|
end: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TDatasetKeys = 'nb_workouts' | 'total_duration' | 'total_distance'
|
||||||
|
|
||||||
|
export type TStatistics = Record<TDatasetKeys, number>
|
||||||
|
|
||||||
|
export type TSportStatistics = {
|
||||||
|
[key in number]: TStatistics
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TStatisticsFromApi = {
|
||||||
|
[key in string]: TSportStatistics
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IStatisticsChartDataset {
|
||||||
|
label: string
|
||||||
|
backgroundColor: string[]
|
||||||
|
data: (number | null)[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TStatisticsDatasets = Record<
|
||||||
|
TDatasetKeys,
|
||||||
|
IStatisticsChartDataset[]
|
||||||
|
>
|
||||||
|
|
||||||
|
export interface IStatisticsChartData {
|
||||||
|
labels: string[]
|
||||||
|
datasets: TStatisticsDatasets
|
||||||
|
}
|
||||||
|
7
fittrackee_client/src/types/workouts.ts
Normal file
7
fittrackee_client/src/types/workouts.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export interface ISport {
|
||||||
|
has_workouts: boolean
|
||||||
|
id: number
|
||||||
|
img: string
|
||||||
|
is_active: boolean
|
||||||
|
label: string
|
||||||
|
}
|
42
fittrackee_client/src/utils/dates.ts
Normal file
42
fittrackee_client/src/utils/dates.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import {
|
||||||
|
addDays,
|
||||||
|
addMonths,
|
||||||
|
addYears,
|
||||||
|
startOfMonth,
|
||||||
|
startOfWeek,
|
||||||
|
startOfYear,
|
||||||
|
} from 'date-fns'
|
||||||
|
|
||||||
|
export const startDate = (
|
||||||
|
duration: string,
|
||||||
|
day: Date,
|
||||||
|
weekStartingMonday: boolean
|
||||||
|
): Date => {
|
||||||
|
switch (duration) {
|
||||||
|
case 'week':
|
||||||
|
return startOfWeek(day, { weekStartsOn: weekStartingMonday ? 1 : 0 })
|
||||||
|
case 'year':
|
||||||
|
return startOfYear(day)
|
||||||
|
case 'month':
|
||||||
|
return startOfMonth(day)
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Invalid duration, expected: "week", "month", "year", got: "${duration}"`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const incrementDate = (duration: string, day: Date): Date => {
|
||||||
|
switch (duration) {
|
||||||
|
case 'week':
|
||||||
|
return addDays(day, 7)
|
||||||
|
case 'year':
|
||||||
|
return addYears(day, 1)
|
||||||
|
case 'month':
|
||||||
|
return addMonths(day, 1)
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Invalid duration, expected: "week", "month", "year", got: "${duration}"`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
103
fittrackee_client/src/utils/statistics.ts
Normal file
103
fittrackee_client/src/utils/statistics.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { format } from 'date-fns'
|
||||||
|
|
||||||
|
import { genericObject } from '@/types/generic'
|
||||||
|
import {
|
||||||
|
IStatisticsChartData,
|
||||||
|
IStatisticsChartDataset,
|
||||||
|
IStatisticsDateParams,
|
||||||
|
TDatasetKeys,
|
||||||
|
TStatisticsDatasets,
|
||||||
|
TStatisticsFromApi,
|
||||||
|
} from '@/types/statistics'
|
||||||
|
import { ISport } from '@/types/workouts'
|
||||||
|
import { incrementDate, startDate } from '@/utils/dates'
|
||||||
|
|
||||||
|
// date format from api
|
||||||
|
const dateFormats: genericObject = {
|
||||||
|
week: 'yyyy-MM-dd',
|
||||||
|
month: 'yyyy-MM',
|
||||||
|
year: 'yyyy',
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: TDatasetKeys[] = ['nb_workouts', 'total_duration', 'total_distance']
|
||||||
|
|
||||||
|
export const getDateKeys = (
|
||||||
|
params: IStatisticsDateParams,
|
||||||
|
weekStartingMonday: boolean
|
||||||
|
): Date[] => {
|
||||||
|
const days = []
|
||||||
|
for (
|
||||||
|
let day = startDate(params.duration, params.start, weekStartingMonday);
|
||||||
|
day <= params.end;
|
||||||
|
day = incrementDate(params.duration, day)
|
||||||
|
) {
|
||||||
|
days.push(day)
|
||||||
|
}
|
||||||
|
return days
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatisticsChartDataset = (
|
||||||
|
sportLabel: string
|
||||||
|
): IStatisticsChartDataset =>
|
||||||
|
Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: sportLabel,
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const getDatasets = (displayedSports: ISport[]): TStatisticsDatasets => {
|
||||||
|
const datasets: TStatisticsDatasets = {
|
||||||
|
nb_workouts: [],
|
||||||
|
total_distance: [],
|
||||||
|
total_duration: [],
|
||||||
|
}
|
||||||
|
displayedSports.map((sport) => {
|
||||||
|
datasets.nb_workouts.push(getStatisticsChartDataset(sport.label))
|
||||||
|
datasets.total_distance.push(getStatisticsChartDataset(sport.label))
|
||||||
|
datasets.total_duration.push(getStatisticsChartDataset(sport.label))
|
||||||
|
})
|
||||||
|
return datasets
|
||||||
|
}
|
||||||
|
|
||||||
|
export const formatStats = (
|
||||||
|
params: IStatisticsDateParams,
|
||||||
|
weekStartingMonday: boolean,
|
||||||
|
sports: ISport[],
|
||||||
|
displayedSportsId: number[],
|
||||||
|
apiStats: TStatisticsFromApi
|
||||||
|
): IStatisticsChartData => {
|
||||||
|
const dayKeys = getDateKeys(params, weekStartingMonday)
|
||||||
|
const dateFormat = dateFormats[params.duration]
|
||||||
|
const displayedSports = sports.filter((sport) =>
|
||||||
|
displayedSportsId.length == 0 ? true : displayedSportsId.includes(sport.id)
|
||||||
|
)
|
||||||
|
const labels: string[] = []
|
||||||
|
const datasets = getDatasets(displayedSports)
|
||||||
|
const sportsId: Record<string, number> = {}
|
||||||
|
displayedSports.map(
|
||||||
|
(displayedSport) => (sportsId[displayedSport.label] = displayedSport.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
dayKeys.map((key) => {
|
||||||
|
const date: string = format(key, dateFormat)
|
||||||
|
labels.push(date)
|
||||||
|
data.map((datasetKey) => {
|
||||||
|
datasets[datasetKey].map((dataset) =>
|
||||||
|
dataset.data.push(
|
||||||
|
apiStats !== {} &&
|
||||||
|
date in apiStats &&
|
||||||
|
sportsId[dataset.label] in apiStats[date]
|
||||||
|
? apiStats[date][sportsId[dataset.label]][datasetKey]
|
||||||
|
: null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
labels,
|
||||||
|
datasets,
|
||||||
|
}
|
||||||
|
}
|
25
fittrackee_client/tests/unit/utils/constants.ts
Normal file
25
fittrackee_client/tests/unit/utils/constants.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { ISport } from '@/types/workouts'
|
||||||
|
|
||||||
|
export const sports: ISport[] = [
|
||||||
|
{
|
||||||
|
has_workouts: false,
|
||||||
|
id: 1,
|
||||||
|
img: '/img/sports/cycling-sport.png',
|
||||||
|
is_active: true,
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
has_workouts: false,
|
||||||
|
id: 2,
|
||||||
|
img: '/img/sports/cycling-transport.png',
|
||||||
|
is_active: false,
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
has_workouts: true,
|
||||||
|
id: 3,
|
||||||
|
img: '/img/sports/hiking.png',
|
||||||
|
is_active: true,
|
||||||
|
label: 'Hiking',
|
||||||
|
},
|
||||||
|
]
|
137
fittrackee_client/tests/unit/utils/dates.spec.ts
Normal file
137
fittrackee_client/tests/unit/utils/dates.spec.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import { assert, expect } from 'chai'
|
||||||
|
|
||||||
|
import { incrementDate, startDate } from '@/utils/dates'
|
||||||
|
|
||||||
|
describe('startDate (week starting Sunday)', () => {
|
||||||
|
const testsParams = [
|
||||||
|
{
|
||||||
|
description: "returns start day for 'month' duration",
|
||||||
|
inputDuration: 'month',
|
||||||
|
inputDate: 'August 21, 2021 20:00:00',
|
||||||
|
expectedDate: 'August 1, 2021 00:00:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "returns start day for 'week' duration",
|
||||||
|
inputDuration: 'week',
|
||||||
|
inputDate: 'August 21, 2021 20:00:00',
|
||||||
|
expectedDate: 'August 15, 2021 00:00:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "returns start day for 'year' duration",
|
||||||
|
inputDuration: 'year',
|
||||||
|
inputDate: 'August 21, 2021 20:00:00',
|
||||||
|
expectedDate: 'January 1, 2021 00:00:00',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
testsParams.map((testParams) =>
|
||||||
|
it(testParams.description, () => {
|
||||||
|
const day: Date = new Date(testParams.inputDate)
|
||||||
|
const expected: Date = new Date(testParams.expectedDate)
|
||||||
|
assert.deepEqual(
|
||||||
|
startDate(testParams.inputDuration, day, false),
|
||||||
|
expected
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('startDate (week starting Monday)', () => {
|
||||||
|
const testsParams = [
|
||||||
|
{
|
||||||
|
description: "returns start day for 'month' duration",
|
||||||
|
inputDuration: 'month',
|
||||||
|
inputDate: 'August 21, 2021 20:00:00',
|
||||||
|
expectedDate: 'August 1, 2021 00:00:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'returns start day for week duration',
|
||||||
|
inputDuration: 'week',
|
||||||
|
inputDate: 'August 21, 2021 20:00:00',
|
||||||
|
expectedDate: 'August 16, 2021 00:00:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "returns start day for 'year' duration",
|
||||||
|
inputDuration: 'year',
|
||||||
|
inputDate: 'August 21, 2021 20:00:00',
|
||||||
|
expectedDate: 'January 1, 2021 00:00:00',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
testsParams.map((testParams) =>
|
||||||
|
it(testParams.description, () => {
|
||||||
|
const day: Date = new Date(testParams.inputDate)
|
||||||
|
const expected: Date = new Date(testParams.expectedDate)
|
||||||
|
assert.deepEqual(startDate(testParams.inputDuration, day, true), expected)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('startDate (week starting Monday)', () => {
|
||||||
|
it('it throws an exception if duration is invalid', () => {
|
||||||
|
const day: Date = new Date('August 21, 2021 20:00:00')
|
||||||
|
expect(() => startDate('invalid duration', day, true)).to.throw(
|
||||||
|
'Invalid duration, expected: "week", "month", "year", got: "invalid duration"'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('dateIncrement', () => {
|
||||||
|
const testsParams = [
|
||||||
|
{
|
||||||
|
description: "returns incremented day for 'month' duration",
|
||||||
|
inputDuration: 'month',
|
||||||
|
inputDate: 'August 21, 2021 20:00:00',
|
||||||
|
expectedDate: 'September 21, 2021 20:00:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'returns incremented day for week duration',
|
||||||
|
inputDuration: 'week',
|
||||||
|
inputDate: 'August 21, 2021 20:00:00',
|
||||||
|
expectedDate: 'August 28, 2021 20:00:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'returns incremented day for week duration (February w/ 28 days)',
|
||||||
|
inputDuration: 'week',
|
||||||
|
inputDate: 'February 22, 2021 20:00:00',
|
||||||
|
expectedDate: 'March 1, 2021 20:00:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'returns incremented day for week duration (February w/ 29 days)',
|
||||||
|
inputDuration: 'week',
|
||||||
|
inputDate: 'February 22, 2020 20:00:00',
|
||||||
|
expectedDate: 'February 29, 2020 20:00:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "returns incremented day for 'year' duration",
|
||||||
|
inputDuration: 'year',
|
||||||
|
inputDate: 'August 21, 2021 20:00:00',
|
||||||
|
expectedDate: 'August 21, 2022 20:00:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "returns incremented day for 'year' duration (February, 29)",
|
||||||
|
inputDuration: 'year',
|
||||||
|
inputDate: 'February 29, 2020 20:00:00',
|
||||||
|
expectedDate: 'February 28, 2021 20:00:00',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
testsParams.map((testParams) =>
|
||||||
|
it(testParams.description, () => {
|
||||||
|
const day: Date = new Date(testParams.inputDate)
|
||||||
|
const expected: Date = new Date(testParams.expectedDate)
|
||||||
|
assert.deepEqual(incrementDate(testParams.inputDuration, day), expected)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('dateIncrement', () => {
|
||||||
|
it('it throws an exception if duration is invalid', () => {
|
||||||
|
const day: Date = new Date('August 21, 2021 20:00:00')
|
||||||
|
expect(() => incrementDate('invalid duration', day)).to.throw(
|
||||||
|
'Invalid duration, expected: "week", "month", "year", got: "invalid duration"'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
516
fittrackee_client/tests/unit/utils/statistics.spec.ts
Normal file
516
fittrackee_client/tests/unit/utils/statistics.spec.ts
Normal file
@ -0,0 +1,516 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { sports } from './constants'
|
||||||
|
|
||||||
|
import {
|
||||||
|
IStatisticsChartData,
|
||||||
|
TStatisticsDatasets,
|
||||||
|
TStatisticsFromApi,
|
||||||
|
} from '@/types/statistics'
|
||||||
|
import { formatStats, getDateKeys, getDatasets } from '@/utils/statistics'
|
||||||
|
|
||||||
|
describe('getDateKeys (week starting Sunday)', () => {
|
||||||
|
const testsParams = [
|
||||||
|
{
|
||||||
|
description: 'returns date keys for "week" duration',
|
||||||
|
inputParams: {
|
||||||
|
duration: 'week',
|
||||||
|
start: new Date('August 01, 2021 00:00:00'),
|
||||||
|
end: new Date('August 31, 2021 23:59:59.999'),
|
||||||
|
},
|
||||||
|
inputWeekStartingMonday: false,
|
||||||
|
expected: [
|
||||||
|
'August 1, 2021 00:00:00',
|
||||||
|
'August 8, 2021 00:00:00',
|
||||||
|
'August 15, 2021 00:00:00',
|
||||||
|
'August 22, 2021 00:00:00',
|
||||||
|
'August 29, 2021 00:00:00',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'returns date keys for "month" duration',
|
||||||
|
inputParams: {
|
||||||
|
duration: 'month',
|
||||||
|
start: new Date('September 01, 2020 00:00:00'),
|
||||||
|
end: new Date('August 31, 2021 23:59:59.999'),
|
||||||
|
},
|
||||||
|
inputWeekStartingMonday: false,
|
||||||
|
expected: [
|
||||||
|
'September 1, 2020 00:00:00',
|
||||||
|
'October 1, 2020 00:00:00',
|
||||||
|
'November 1, 2020 00:00:00',
|
||||||
|
'December 1, 2020 00:00:00',
|
||||||
|
'January 1, 2021 00:00:00',
|
||||||
|
'February 1, 2021 00:00:00',
|
||||||
|
'March 1, 2021 00:00:00',
|
||||||
|
'April 1, 2021 00:00:00',
|
||||||
|
'May 1, 2021 00:00:00',
|
||||||
|
'June 1, 2021 00:00:00',
|
||||||
|
'July 1, 2021 00:00:00',
|
||||||
|
'August 1, 2021 00:00:00',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'returns date keys for "month" duration',
|
||||||
|
inputParams: {
|
||||||
|
duration: 'year',
|
||||||
|
start: new Date('January 1, 2012 00:00:00'),
|
||||||
|
end: new Date('December 31, 2021 23:59:59.999'),
|
||||||
|
},
|
||||||
|
inputWeekStartingMonday: false,
|
||||||
|
expected: [
|
||||||
|
'January 1, 2012 00:00:00',
|
||||||
|
'January 1, 2013 00:00:00',
|
||||||
|
'January 1, 2014 00:00:00',
|
||||||
|
'January 1, 2015 00:00:00',
|
||||||
|
'January 1, 2016 00:00:00',
|
||||||
|
'January 1, 2017 00:00:00',
|
||||||
|
'January 1, 2018 00:00:00',
|
||||||
|
'January 1, 2019 00:00:00',
|
||||||
|
'January 1, 2020 00:00:00',
|
||||||
|
'January 1, 2021 00:00:00',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
testsParams.map((testParams) =>
|
||||||
|
it(testParams.description, () => {
|
||||||
|
const expected: Date[] = testParams.expected.map(
|
||||||
|
(date_string: string) => new Date(date_string)
|
||||||
|
)
|
||||||
|
assert.deepEqual(getDateKeys(testParams.inputParams, false), expected)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('getDateKeys (week starting Monday)', () => {
|
||||||
|
const testsParams = [
|
||||||
|
{
|
||||||
|
description: 'returns date keys for "week" duration',
|
||||||
|
inputParams: {
|
||||||
|
duration: 'week',
|
||||||
|
start: new Date('August 01, 2021 00:00:00'),
|
||||||
|
end: new Date('August 31, 2021 23:59:59.999'),
|
||||||
|
},
|
||||||
|
inputWeekStartingMonday: false,
|
||||||
|
expected: [
|
||||||
|
'July 26, 2021 00:00:00',
|
||||||
|
'August 2, 2021 00:00:00',
|
||||||
|
'August 9, 2021 00:00:00',
|
||||||
|
'August 16, 2021 00:00:00',
|
||||||
|
'August 23, 2021 00:00:00',
|
||||||
|
'August 30, 2021 00:00:00',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'returns date keys for "month" duration',
|
||||||
|
inputParams: {
|
||||||
|
duration: 'month',
|
||||||
|
start: new Date('September 01, 2020 00:00:00'),
|
||||||
|
end: new Date('August 31, 2021 23:59:59.999'),
|
||||||
|
},
|
||||||
|
inputWeekStartingMonday: false,
|
||||||
|
expected: [
|
||||||
|
'September 1, 2020 00:00:00',
|
||||||
|
'October 1, 2020 00:00:00',
|
||||||
|
'November 1, 2020 00:00:00',
|
||||||
|
'December 1, 2020 00:00:00',
|
||||||
|
'January 1, 2021 00:00:00',
|
||||||
|
'February 1, 2021 00:00:00',
|
||||||
|
'March 1, 2021 00:00:00',
|
||||||
|
'April 1, 2021 00:00:00',
|
||||||
|
'May 1, 2021 00:00:00',
|
||||||
|
'June 1, 2021 00:00:00',
|
||||||
|
'July 1, 2021 00:00:00',
|
||||||
|
'August 1, 2021 00:00:00',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'returns date keys for "month" duration',
|
||||||
|
inputParams: {
|
||||||
|
duration: 'year',
|
||||||
|
start: new Date('January 1, 2012 00:00:00'),
|
||||||
|
end: new Date('December 31, 2021 23:59:59.999'),
|
||||||
|
},
|
||||||
|
inputWeekStartingMonday: false,
|
||||||
|
expected: [
|
||||||
|
'January 1, 2012 00:00:00',
|
||||||
|
'January 1, 2013 00:00:00',
|
||||||
|
'January 1, 2014 00:00:00',
|
||||||
|
'January 1, 2015 00:00:00',
|
||||||
|
'January 1, 2016 00:00:00',
|
||||||
|
'January 1, 2017 00:00:00',
|
||||||
|
'January 1, 2018 00:00:00',
|
||||||
|
'January 1, 2019 00:00:00',
|
||||||
|
'January 1, 2020 00:00:00',
|
||||||
|
'January 1, 2021 00:00:00',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
testsParams.map((testParams) =>
|
||||||
|
it(testParams.description, () => {
|
||||||
|
const expected: Date[] = testParams.expected.map(
|
||||||
|
(date_string: string) => new Date(date_string)
|
||||||
|
)
|
||||||
|
assert.deepEqual(getDateKeys(testParams.inputParams, true), expected)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('getDatasets', () => {
|
||||||
|
it('returns chart datasets (when no displayed data provided)', () => {
|
||||||
|
const expected: TStatisticsDatasets = {
|
||||||
|
nb_workouts: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hiking',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_distance: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hiking',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_duration: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hiking',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
assert.deepEqual(getDatasets(sports), expected)
|
||||||
|
})
|
||||||
|
it('returns chart datasets with only displayed sports', () => {
|
||||||
|
const expected: TStatisticsDatasets = {
|
||||||
|
nb_workouts: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_distance: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_duration: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
assert.deepEqual(getDatasets([sports[1]]), expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('formatStats', () => {
|
||||||
|
it('returns empty datasets if no data and no displayed sport provided', () => {
|
||||||
|
const inputStats: TStatisticsFromApi = {}
|
||||||
|
const inputParams = {
|
||||||
|
duration: 'month',
|
||||||
|
start: new Date('May 1, 2021 00:00:00'),
|
||||||
|
end: new Date('July 31, 2021 23:59:59.999'),
|
||||||
|
}
|
||||||
|
const expected: IStatisticsChartData = {
|
||||||
|
labels: ['2021-05', '2021-06', '2021-07'],
|
||||||
|
datasets: {
|
||||||
|
nb_workouts: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hiking',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_distance: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hiking',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_duration: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hiking',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.deepEqual(
|
||||||
|
formatStats(inputParams, false, sports, [], inputStats),
|
||||||
|
expected
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns empty datasets if no data and displayed sport provided', () => {
|
||||||
|
const inputStats: TStatisticsFromApi = {}
|
||||||
|
const inputParams = {
|
||||||
|
duration: 'month',
|
||||||
|
start: new Date('May 1, 2021 00:00:00'),
|
||||||
|
end: new Date('July 31, 2021 23:59:59.999'),
|
||||||
|
}
|
||||||
|
const expected: IStatisticsChartData = {
|
||||||
|
labels: ['2021-05', '2021-06', '2021-07'],
|
||||||
|
datasets: {
|
||||||
|
nb_workouts: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_distance: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_duration: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, null],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.deepEqual(
|
||||||
|
formatStats(inputParams, false, sports, [2], inputStats),
|
||||||
|
expected
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns empty datasets if data and no displayed sport provided', () => {
|
||||||
|
const inputStats: TStatisticsFromApi = {
|
||||||
|
'2021-05': {
|
||||||
|
1: {
|
||||||
|
nb_workouts: 1,
|
||||||
|
total_distance: 10,
|
||||||
|
total_duration: 3000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'2021-06': {
|
||||||
|
1: {
|
||||||
|
nb_workouts: 1,
|
||||||
|
total_distance: 15,
|
||||||
|
total_duration: 3500,
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
nb_workouts: 2,
|
||||||
|
total_distance: 20,
|
||||||
|
total_duration: 3000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'2021-07': {
|
||||||
|
3: {
|
||||||
|
nb_workouts: 2,
|
||||||
|
total_distance: 12,
|
||||||
|
total_duration: 5000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const inputParams = {
|
||||||
|
duration: 'month',
|
||||||
|
start: new Date('May 1, 2021 00:00:00'),
|
||||||
|
end: new Date('July 31, 2021 23:59:59.999'),
|
||||||
|
}
|
||||||
|
const expected: IStatisticsChartData = {
|
||||||
|
labels: ['2021-05', '2021-06', '2021-07'],
|
||||||
|
datasets: {
|
||||||
|
nb_workouts: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [1, 1, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, 2, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hiking',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, 2],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_distance: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [10, 15, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, 20, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hiking',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, 12],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_duration: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [3000, 3500, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cycling (Transport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, 3000, null],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hiking',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [null, null, 5000],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.deepEqual(
|
||||||
|
formatStats(inputParams, false, sports, [], inputStats),
|
||||||
|
expected
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns empty datasets if data and displayed sport provided', () => {
|
||||||
|
const inputStats: TStatisticsFromApi = {
|
||||||
|
'2021-05': {
|
||||||
|
1: {
|
||||||
|
nb_workouts: 1,
|
||||||
|
total_distance: 10,
|
||||||
|
total_duration: 3000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'2021-06': {
|
||||||
|
1: {
|
||||||
|
nb_workouts: 1,
|
||||||
|
total_distance: 15,
|
||||||
|
total_duration: 3500,
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
nb_workouts: 2,
|
||||||
|
total_distance: 20,
|
||||||
|
total_duration: 3000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'2021-07': {
|
||||||
|
3: {
|
||||||
|
nb_workouts: 2,
|
||||||
|
total_distance: 20,
|
||||||
|
total_duration: 3000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const inputParams = {
|
||||||
|
duration: 'month',
|
||||||
|
start: new Date('May 1, 2021 00:00:00'),
|
||||||
|
end: new Date('July 31, 2021 23:59:59.999'),
|
||||||
|
}
|
||||||
|
const expected: IStatisticsChartData = {
|
||||||
|
labels: ['2021-05', '2021-06', '2021-07'],
|
||||||
|
datasets: {
|
||||||
|
nb_workouts: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [1, 1, null],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_distance: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [10, 15, null],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total_duration: [
|
||||||
|
{
|
||||||
|
label: 'Cycling (Sport)',
|
||||||
|
backgroundColor: [],
|
||||||
|
data: [3000, 3500, null],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.deepEqual(
|
||||||
|
formatStats(inputParams, false, sports, [1], inputStats),
|
||||||
|
expected
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
@ -3542,6 +3542,11 @@ data-urls@^1.1.0:
|
|||||||
whatwg-mimetype "^2.2.0"
|
whatwg-mimetype "^2.2.0"
|
||||||
whatwg-url "^7.0.0"
|
whatwg-url "^7.0.0"
|
||||||
|
|
||||||
|
date-fns@^2.23.0:
|
||||||
|
version "2.23.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.23.0.tgz#4e886c941659af0cf7b30fafdd1eaa37e88788a9"
|
||||||
|
integrity sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA==
|
||||||
|
|
||||||
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
|
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
|
Loading…
Reference in New Issue
Block a user