diff --git a/fittrackee_client/src/components/Common/StatsChart/Chart.vue b/fittrackee_client/src/components/Common/StatsChart/Chart.vue index 9f82ff43..742ef221 100644 --- a/fittrackee_client/src/components/Common/StatsChart/Chart.vue +++ b/fittrackee_client/src/components/Common/StatsChart/Chart.vue @@ -40,6 +40,10 @@ type: Boolean, required: true, }, + useImperialUnits: { + type: Boolean, + required: true, + }, }, setup(props) { const { t } = useI18n() @@ -80,7 +84,12 @@ ticks: { maxTicksLimit: 6, callback: function (value) { - return formatTooltipValue(props.displayedData, +value, false) + return formatTooltipValue( + props.displayedData, + +value, + props.useImperialUnits, + false + ) }, }, afterFit: function (scale: LayoutItem) { @@ -108,7 +117,12 @@ .reduce((total, value) => getSum(total, value), 0) return context.datasetIndex === props.displayedSportIds.length - 1 && total > 0 - ? formatTooltipValue(props.displayedData, total, false) + ? formatTooltipValue( + props.displayedData, + total, + props.useImperialUnits, + false + ) : null }, }, @@ -132,7 +146,8 @@ if (context.parsed.y !== null) { label += formatTooltipValue( props.displayedData, - context.parsed.y + context.parsed.y, + props.useImperialUnits ) } return label @@ -144,7 +159,11 @@ }) return ( `${t('common.TOTAL')}: ` + - formatTooltipValue(props.displayedData, sum) + formatTooltipValue( + props.displayedData, + sum, + props.useImperialUnits + ) ) }, }, diff --git a/fittrackee_client/src/components/Common/StatsChart/index.vue b/fittrackee_client/src/components/Common/StatsChart/index.vue index b62650c7..64192a21 100644 --- a/fittrackee_client/src/components/Common/StatsChart/index.vue +++ b/fittrackee_client/src/components/Common/StatsChart/index.vue @@ -58,6 +58,7 @@ :displayedData="displayedData" :displayedSportIds="displayedSportIds" :fullStats="fullStats" + :useImperialUnits="user.imperial_units" /> @@ -134,7 +135,8 @@ props.user.weekm, props.sports, props.displayedSportIds, - statistics.value + statistics.value, + props.user.imperial_units ) ) diff --git a/fittrackee_client/src/utils/statistics.ts b/fittrackee_client/src/utils/statistics.ts index 0e60f90c..360da5cd 100644 --- a/fittrackee_client/src/utils/statistics.ts +++ b/fittrackee_client/src/utils/statistics.ts @@ -25,6 +25,7 @@ import { } from '@/types/statistics' import { incrementDate, getStartDate } from '@/utils/dates' import { sportColors } from '@/utils/sports' +import { convertDistance, units } from '@/utils/units' const dateFormats: Record> = { week: { @@ -94,12 +95,35 @@ export const getDatasets = (displayedSports: ISport[]): TStatisticsDatasets => { return datasets } +export const convertStatsValue = ( + datasetKey: TStatisticsDatasetKeys, + value: number, + useImperialUnits: boolean +): number => { + switch (datasetKey) { + case 'total_distance': + case 'total_ascent': + case 'total_descent': { + const unitFrom = datasetKey === 'total_distance' ? 'km' : 'm' + const unitTo = useImperialUnits ? units[unitFrom].defaultTarget : unitFrom + return useImperialUnits + ? convertDistance(value, unitFrom, unitTo, 2) + : value + } + default: + case 'nb_workouts': + case 'total_duration': + return value + } +} + export const formatStats = ( params: IStatisticsDateParams, weekStartingMonday: boolean, sports: ISport[], displayedSportsId: number[], - apiStats: TStatisticsFromApi + apiStats: TStatisticsFromApi, + useImperialUnits: boolean ): IStatisticsChartData => { const dayKeys = getDateKeys(params, weekStartingMonday) const dateFormat = dateFormats[params.duration] @@ -123,7 +147,11 @@ export const formatStats = ( apiStats !== {} && date in apiStats && sportsId[dataset.label] in apiStats[date] - ? apiStats[date][sportsId[dataset.label]][datasetKey] + ? convertStatsValue( + datasetKey, + apiStats[date][sportsId[dataset.label]][datasetKey], + useImperialUnits + ) : 0 ) }) diff --git a/fittrackee_client/src/utils/tooltip.ts b/fittrackee_client/src/utils/tooltip.ts index a9b69762..67eedf55 100644 --- a/fittrackee_client/src/utils/tooltip.ts +++ b/fittrackee_client/src/utils/tooltip.ts @@ -1,19 +1,23 @@ import { TStatisticsDatasetKeys } from '@/types/statistics' import { formatDuration } from '@/utils/duration' +import { units } from '@/utils/units' export const formatTooltipValue = ( displayedData: TStatisticsDatasetKeys, value: number, + useImperialUnits: boolean, formatWithUnits = true ): string => { + const unitFrom = 'km' + const unitTo = useImperialUnits ? units[unitFrom].defaultTarget : unitFrom switch (displayedData) { case 'total_duration': return formatDuration(value, formatWithUnits) case 'total_distance': - return value.toFixed(2) + ' km' + return `${value.toFixed(2)} ${unitTo}` case 'total_ascent': case 'total_descent': - return (value / 1000).toFixed(2) + ' km' + return `${(value / 1000).toFixed(2)} ${unitTo}` default: return value.toString() } diff --git a/fittrackee_client/tests/unit/utils/statistics.spec.ts b/fittrackee_client/tests/unit/utils/statistics.spec.ts index 7f1b7dfc..bba3fe5e 100644 --- a/fittrackee_client/tests/unit/utils/statistics.spec.ts +++ b/fittrackee_client/tests/unit/utils/statistics.spec.ts @@ -316,7 +316,7 @@ describe('formatStats', () => { }, } assert.deepEqual( - formatStats(inputParams, false, sports, [], inputStats), + formatStats(inputParams, false, sports, [], inputStats, false), expected ) }) @@ -369,7 +369,7 @@ describe('formatStats', () => { }, } assert.deepEqual( - formatStats(inputParams, false, sports, [2], inputStats), + formatStats(inputParams, false, sports, [2], inputStats, false), expected ) }) @@ -427,7 +427,7 @@ describe('formatStats', () => { }, } assert.deepEqual( - formatStats(inputParams, false, sports, [], inputStats), + formatStats(inputParams, false, sports, [], inputStats, false), expected ) }) @@ -515,7 +515,7 @@ describe('formatStats', () => { }, } assert.deepEqual( - formatStats(inputParams, false, sports, [1], inputStats), + formatStats(inputParams, false, sports, [1], inputStats, false), expected ) }) @@ -605,7 +605,7 @@ describe('formatStats (duration)', () => { }, } assert.deepEqual( - formatStats(inputParams, false, sports, [1], inputStats), + formatStats(inputParams, false, sports, [1], inputStats, false), expected ) }) @@ -692,7 +692,7 @@ describe('formatStats (duration)', () => { }, } assert.deepEqual( - formatStats(inputParams, false, sports, [1], inputStats), + formatStats(inputParams, false, sports, [1], inputStats, false), expected ) }) @@ -780,7 +780,7 @@ describe('formatStats (duration)', () => { }, } assert.deepEqual( - formatStats(inputParams, false, sports, [1], inputStats), + formatStats(inputParams, false, sports, [1], inputStats, false), expected ) }) @@ -868,7 +868,95 @@ describe('formatStats (duration)', () => { }, } assert.deepEqual( - formatStats(inputParams, true, sports, [1], inputStats), + formatStats(inputParams, true, sports, [1], inputStats, false), + expected + ) + }) + + it('returns datasets after conversion to imperial units', () => { + const inputStats: TStatisticsFromApi = { + '2021-10-03': { + 1: { + nb_workouts: 1, + total_distance: 10, + total_duration: 3000, + total_ascent: 150, + total_descent: 100, + }, + }, + '2021-10-10': { + 1: { + nb_workouts: 1, + total_distance: 15, + total_duration: 3500, + total_ascent: 250, + total_descent: 150, + }, + 2: { + nb_workouts: 2, + total_distance: 20, + total_duration: 3000, + total_ascent: 150, + total_descent: 200, + }, + }, + '2021-10-17': { + 3: { + nb_workouts: 2, + total_distance: 20, + total_duration: 3000, + total_ascent: 100, + total_descent: 100, + }, + }, + } + const inputParams = { + duration: 'week', + start: new Date('October 03, 2021 00:00:00'), + end: new Date('October 23, 2021 23:59:59.999'), + } + const expected: IStatisticsChartData = { + labels: ['03/10/2021', '10/10/2021', '17/10/2021'], + datasets: { + nb_workouts: [ + { + label: 'Cycling (Sport)', + backgroundColor: ['#4c9792'], + data: [1, 1, 0], + }, + ], + total_distance: [ + { + label: 'Cycling (Sport)', + backgroundColor: ['#4c9792'], + data: [6.21, 9.32, 0], + }, + ], + total_duration: [ + { + label: 'Cycling (Sport)', + backgroundColor: ['#4c9792'], + data: [3000, 3500, 0], + }, + ], + total_ascent: [ + { + label: 'Cycling (Sport)', + backgroundColor: ['#4c9792'], + data: [492.13, 820.21, 0], + }, + ], + total_descent: [ + { + label: 'Cycling (Sport)', + backgroundColor: ['#4c9792'], + data: [328.08, 492.13, 0], + }, + ], + }, + } + assert.deepEqual( + formatStats(inputParams, false, sports, [1], inputStats, true), expected ) }) diff --git a/fittrackee_client/tests/unit/utils/tooltip.spec.ts b/fittrackee_client/tests/unit/utils/tooltip.spec.ts index 33ca8886..f86fac10 100644 --- a/fittrackee_client/tests/unit/utils/tooltip.spec.ts +++ b/fittrackee_client/tests/unit/utils/tooltip.spec.ts @@ -42,7 +42,56 @@ describe('formatTooltipValue', () => { assert.equal( formatTooltipValue( testParams.inputDisplayedData, - testParams.inputValue + testParams.inputValue, + false + ), + testParams.expectedResult + ) + }) + }) +}) + +describe('formatTooltipValue after conversion to imperial units', () => { + const testsParams = [ + { + description: 'returns 30 if input is workouts count', + inputDisplayedData: datasetKeys[0], // 'nb_workouts' + inputValue: 30, + expectedResult: '30', + }, + { + description: 'returns 00m:03s if input is total duration', + inputDisplayedData: datasetKeys[1], // 'total_duration' + inputValue: 30, + expectedResult: '00m 30s', + }, + { + description: 'returns 30 mi if input is total distance', + inputDisplayedData: datasetKeys[2], // 'total_distance' + inputValue: 30, + expectedResult: '30.00 mi', + }, + { + description: 'returns 0.03 mi if input is total ascent', + inputDisplayedData: datasetKeys[3], // 'total_distance' + inputValue: 30, + expectedResult: '0.03 mi', + }, + { + description: 'returns 0.03 mi if input is total descent', + inputDisplayedData: datasetKeys[4], // 'total_distance' + inputValue: 30, + expectedResult: '0.03 mi', + }, + ] + + testsParams.map((testParams) => { + it(testParams.description, () => { + assert.equal( + formatTooltipValue( + testParams.inputDisplayedData, + testParams.inputValue, + true ), testParams.expectedResult ) @@ -90,6 +139,7 @@ describe('formatTooltipValue (formatWithUnits = false)', () => { formatTooltipValue( testParams.inputDisplayedData, testParams.inputValue, + false, false ), testParams.expectedResult