2021-10-04 13:53:48 +02:00
|
|
|
import {
|
|
|
|
addMonths,
|
|
|
|
addWeeks,
|
|
|
|
addYears,
|
|
|
|
endOfMonth,
|
|
|
|
endOfWeek,
|
|
|
|
endOfYear,
|
|
|
|
format,
|
|
|
|
startOfMonth,
|
|
|
|
startOfWeek,
|
|
|
|
startOfYear,
|
|
|
|
subMonths,
|
|
|
|
subWeeks,
|
|
|
|
subYears,
|
|
|
|
} from 'date-fns'
|
2021-08-22 20:16:04 +02:00
|
|
|
|
2022-11-01 18:12:42 +01:00
|
|
|
import createI18n from '@/i18n'
|
2021-09-25 11:28:40 +02:00
|
|
|
import { IChartDataset } from '@/types/chart'
|
2021-08-22 21:10:47 +02:00
|
|
|
import { ISport } from '@/types/sports'
|
2021-08-22 20:16:04 +02:00
|
|
|
import {
|
|
|
|
IStatisticsChartData,
|
|
|
|
IStatisticsDateParams,
|
2021-09-26 08:59:17 +02:00
|
|
|
TStatisticsDatasetKeys,
|
2021-08-22 20:16:04 +02:00
|
|
|
TStatisticsDatasets,
|
|
|
|
TStatisticsFromApi,
|
|
|
|
} from '@/types/statistics'
|
2022-11-01 18:12:42 +01:00
|
|
|
import { incrementDate, getStartDate, getDateFormat } from '@/utils/dates'
|
|
|
|
import { localeFromLanguage } from '@/utils/locales'
|
2021-09-20 12:18:40 +02:00
|
|
|
import { sportColors } from '@/utils/sports'
|
2021-11-14 13:33:07 +01:00
|
|
|
import { convertStatsDistance } from '@/utils/units'
|
2021-08-22 20:16:04 +02:00
|
|
|
|
2022-11-01 18:12:42 +01:00
|
|
|
const { locale } = createI18n.global
|
|
|
|
|
2021-10-04 15:37:22 +02:00
|
|
|
const dateFormats: Record<string, Record<string, string>> = {
|
|
|
|
week: {
|
|
|
|
api: 'yyyy-MM-dd',
|
2022-11-01 18:12:42 +01:00
|
|
|
chart: 'MM/dd/yyyy',
|
2021-10-04 15:37:22 +02:00
|
|
|
},
|
|
|
|
month: {
|
|
|
|
api: 'yyyy-MM',
|
|
|
|
chart: 'MM/yyyy',
|
|
|
|
},
|
|
|
|
year: {
|
|
|
|
api: 'yyyy',
|
|
|
|
chart: 'yyyy',
|
|
|
|
},
|
2021-08-22 20:16:04 +02:00
|
|
|
}
|
|
|
|
|
2021-09-26 08:59:17 +02:00
|
|
|
export const datasetKeys: TStatisticsDatasetKeys[] = [
|
2021-11-24 18:01:38 +01:00
|
|
|
'average_speed',
|
2021-09-04 21:36:59 +02:00
|
|
|
'nb_workouts',
|
|
|
|
'total_duration',
|
|
|
|
'total_distance',
|
2021-11-03 20:39:14 +01:00
|
|
|
'total_ascent',
|
|
|
|
'total_descent',
|
2021-09-04 21:36:59 +02:00
|
|
|
]
|
2021-08-22 20:16:04 +02:00
|
|
|
|
|
|
|
export const getDateKeys = (
|
|
|
|
params: IStatisticsDateParams,
|
|
|
|
weekStartingMonday: boolean
|
|
|
|
): Date[] => {
|
|
|
|
const days = []
|
|
|
|
for (
|
2021-10-23 15:44:25 +02:00
|
|
|
let day = getStartDate(params.duration, params.start, weekStartingMonday);
|
2021-08-22 20:16:04 +02:00
|
|
|
day <= params.end;
|
|
|
|
day = incrementDate(params.duration, day)
|
|
|
|
) {
|
|
|
|
days.push(day)
|
|
|
|
}
|
|
|
|
return days
|
|
|
|
}
|
|
|
|
|
|
|
|
const getStatisticsChartDataset = (
|
2021-09-04 19:40:27 +02:00
|
|
|
sportLabel: string,
|
2021-11-24 18:01:38 +01:00
|
|
|
color: string,
|
|
|
|
isLineChart = false
|
2021-09-25 11:28:40 +02:00
|
|
|
): IChartDataset => {
|
2021-11-24 18:01:38 +01:00
|
|
|
const dataset: IChartDataset = {
|
2021-09-21 14:49:49 +02:00
|
|
|
label: sportLabel,
|
|
|
|
backgroundColor: [color],
|
|
|
|
data: [],
|
|
|
|
}
|
2021-11-24 18:01:38 +01:00
|
|
|
if (isLineChart) {
|
|
|
|
dataset.type = 'line'
|
|
|
|
dataset.borderColor = [color]
|
|
|
|
dataset.spanGaps = true
|
|
|
|
}
|
|
|
|
return dataset
|
2021-09-21 14:49:49 +02:00
|
|
|
}
|
2021-08-22 20:16:04 +02:00
|
|
|
|
|
|
|
export const getDatasets = (displayedSports: ISport[]): TStatisticsDatasets => {
|
|
|
|
const datasets: TStatisticsDatasets = {
|
2021-11-24 18:01:38 +01:00
|
|
|
average_speed: [],
|
2021-08-22 20:16:04 +02:00
|
|
|
nb_workouts: [],
|
|
|
|
total_distance: [],
|
|
|
|
total_duration: [],
|
2021-11-03 20:39:14 +01:00
|
|
|
total_ascent: [],
|
|
|
|
total_descent: [],
|
2021-08-22 20:16:04 +02:00
|
|
|
}
|
|
|
|
displayedSports.map((sport) => {
|
2021-11-12 18:55:15 +01:00
|
|
|
const color = sport.color ? sport.color : sportColors[sport.label]
|
2021-11-24 18:01:38 +01:00
|
|
|
datasets.average_speed.push(
|
|
|
|
getStatisticsChartDataset(sport.label, color, true)
|
|
|
|
)
|
2021-09-04 19:40:27 +02:00
|
|
|
datasets.nb_workouts.push(getStatisticsChartDataset(sport.label, color))
|
|
|
|
datasets.total_distance.push(getStatisticsChartDataset(sport.label, color))
|
|
|
|
datasets.total_duration.push(getStatisticsChartDataset(sport.label, color))
|
2021-11-03 20:39:14 +01:00
|
|
|
datasets.total_ascent.push(getStatisticsChartDataset(sport.label, color))
|
|
|
|
datasets.total_descent.push(getStatisticsChartDataset(sport.label, color))
|
2021-08-22 20:16:04 +02:00
|
|
|
})
|
|
|
|
return datasets
|
|
|
|
}
|
|
|
|
|
2021-11-14 12:26:36 +01:00
|
|
|
export const convertStatsValue = (
|
|
|
|
datasetKey: TStatisticsDatasetKeys,
|
|
|
|
value: number,
|
|
|
|
useImperialUnits: boolean
|
|
|
|
): number => {
|
|
|
|
switch (datasetKey) {
|
2021-11-24 18:01:38 +01:00
|
|
|
case 'average_speed':
|
2021-11-14 12:26:36 +01:00
|
|
|
case 'total_distance':
|
|
|
|
case 'total_ascent':
|
2021-11-14 13:33:07 +01:00
|
|
|
case 'total_descent':
|
|
|
|
return convertStatsDistance(
|
2021-11-24 18:01:38 +01:00
|
|
|
['average_speed', 'total_distance'].includes(datasetKey) ? 'km' : 'm',
|
2021-11-14 13:33:07 +01:00
|
|
|
value,
|
|
|
|
useImperialUnits
|
|
|
|
)
|
2021-11-14 12:26:36 +01:00
|
|
|
default:
|
|
|
|
case 'nb_workouts':
|
|
|
|
case 'total_duration':
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-22 20:16:04 +02:00
|
|
|
export const formatStats = (
|
|
|
|
params: IStatisticsDateParams,
|
|
|
|
weekStartingMonday: boolean,
|
|
|
|
sports: ISport[],
|
|
|
|
displayedSportsId: number[],
|
2021-11-14 12:26:36 +01:00
|
|
|
apiStats: TStatisticsFromApi,
|
2022-11-01 18:12:42 +01:00
|
|
|
useImperialUnits: boolean,
|
|
|
|
userDateFormat: string
|
2021-08-22 20:16:04 +02:00
|
|
|
): IStatisticsChartData => {
|
|
|
|
const dayKeys = getDateKeys(params, weekStartingMonday)
|
|
|
|
const dateFormat = dateFormats[params.duration]
|
|
|
|
const displayedSports = sports.filter((sport) =>
|
2021-10-03 19:23:17 +02:00
|
|
|
displayedSportsId.includes(sport.id)
|
2021-08-22 20:16:04 +02:00
|
|
|
)
|
|
|
|
const labels: string[] = []
|
|
|
|
const datasets = getDatasets(displayedSports)
|
|
|
|
const sportsId: Record<string, number> = {}
|
|
|
|
displayedSports.map(
|
|
|
|
(displayedSport) => (sportsId[displayedSport.label] = displayedSport.id)
|
|
|
|
)
|
|
|
|
|
|
|
|
dayKeys.map((key) => {
|
2021-10-04 15:37:22 +02:00
|
|
|
const date: string = format(key, dateFormat.api)
|
2022-11-01 18:12:42 +01:00
|
|
|
const label: string = format(
|
|
|
|
key,
|
|
|
|
params.duration === 'week'
|
|
|
|
? getDateFormat(userDateFormat, locale.value)
|
|
|
|
: dateFormat.chart,
|
|
|
|
{ locale: localeFromLanguage[locale.value] }
|
|
|
|
)
|
2021-10-04 15:37:22 +02:00
|
|
|
labels.push(label)
|
2021-09-04 21:36:59 +02:00
|
|
|
datasetKeys.map((datasetKey) => {
|
2021-09-04 19:40:27 +02:00
|
|
|
datasets[datasetKey].map((dataset) => {
|
2021-08-22 20:16:04 +02:00
|
|
|
dataset.data.push(
|
2022-09-16 10:00:53 +02:00
|
|
|
date in apiStats && sportsId[dataset.label] in apiStats[date]
|
2021-11-14 12:26:36 +01:00
|
|
|
? convertStatsValue(
|
|
|
|
datasetKey,
|
|
|
|
apiStats[date][sportsId[dataset.label]][datasetKey],
|
|
|
|
useImperialUnits
|
|
|
|
)
|
2021-11-24 18:01:38 +01:00
|
|
|
: datasetKey === 'average_speed'
|
|
|
|
? null
|
2021-09-04 19:40:27 +02:00
|
|
|
: 0
|
2021-08-22 20:16:04 +02:00
|
|
|
)
|
2021-09-04 19:40:27 +02:00
|
|
|
})
|
2021-08-22 20:16:04 +02:00
|
|
|
})
|
|
|
|
})
|
|
|
|
return {
|
|
|
|
labels,
|
|
|
|
datasets,
|
|
|
|
}
|
|
|
|
}
|
2021-10-04 13:53:48 +02:00
|
|
|
|
|
|
|
export const getStatsDateParams = (
|
|
|
|
date: Date,
|
|
|
|
timeFrame: string,
|
|
|
|
weekStartingMonday: boolean
|
|
|
|
): IStatisticsDateParams => {
|
|
|
|
const weekStartsOn = weekStartingMonday ? 1 : 0
|
|
|
|
const start =
|
|
|
|
timeFrame === 'year'
|
|
|
|
? startOfYear(subYears(date, 9))
|
|
|
|
: timeFrame === 'week'
|
|
|
|
? startOfWeek(subMonths(date, 2), { weekStartsOn })
|
|
|
|
: startOfMonth(subMonths(date, 11)) // month
|
|
|
|
const end =
|
|
|
|
timeFrame === 'year'
|
|
|
|
? endOfYear(date)
|
|
|
|
: timeFrame === 'week'
|
|
|
|
? endOfWeek(date, { weekStartsOn })
|
|
|
|
: endOfMonth(date) // month
|
|
|
|
return {
|
|
|
|
duration: timeFrame,
|
|
|
|
end,
|
|
|
|
start,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const updateChartParams = (
|
|
|
|
chartParams: IStatisticsDateParams,
|
|
|
|
backward: boolean,
|
|
|
|
weekStartingMonday: boolean
|
|
|
|
): IStatisticsDateParams => {
|
|
|
|
const { duration, start, end } = chartParams
|
|
|
|
const weekStartsOn = weekStartingMonday ? 1 : 0
|
|
|
|
return {
|
|
|
|
duration,
|
|
|
|
end:
|
|
|
|
duration === 'year'
|
|
|
|
? endOfYear(backward ? subYears(end, 1) : addYears(end, 1))
|
|
|
|
: duration === 'week'
|
|
|
|
? endOfWeek(backward ? subWeeks(end, 1) : addWeeks(end, 1), {
|
|
|
|
weekStartsOn,
|
|
|
|
})
|
|
|
|
: endOfMonth(backward ? subMonths(end, 1) : addMonths(end, 1)),
|
|
|
|
start:
|
|
|
|
duration === 'year'
|
|
|
|
? startOfYear(backward ? subYears(start, 1) : addYears(start, 1))
|
|
|
|
: duration === 'week'
|
|
|
|
? startOfWeek(backward ? subWeeks(start, 1) : addWeeks(start, 1), {
|
|
|
|
weekStartsOn,
|
|
|
|
})
|
|
|
|
: startOfMonth(backward ? subMonths(start, 1) : addMonths(start, 1)),
|
|
|
|
}
|
|
|
|
}
|