From 77d9ba449989560105ef0b1dcb3952bb0c83e975 Mon Sep 17 00:00:00 2001 From: whoalin1 Date: Fri, 23 Oct 2026 20:34:51 +0300 Subject: [PATCH 1/2] Show training log chart weights in the user's unit The exercise log chart always labelled its axis "kg" and plotted the raw logged weight, so lb logs (or kg logs for imperial users) were shown with the wrong unit. Use the display weight unit and convert kg/lb logs. Refs wger-project/wger#2149 --- .../screens/Detail/WorkoutLogs.test.tsx | 3 +++ .../Routines/widgets/LogWidgets.test.tsx | 27 +++++++++++++++++-- .../Routines/widgets/LogWidgets.tsx | 20 +++++++++----- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/components/Routines/screens/Detail/WorkoutLogs.test.tsx b/src/components/Routines/screens/Detail/WorkoutLogs.test.tsx index ac1458c4a..3b35b3f86 100644 --- a/src/components/Routines/screens/Detail/WorkoutLogs.test.tsx +++ b/src/components/Routines/screens/Detail/WorkoutLogs.test.tsx @@ -21,6 +21,9 @@ import { import type { Mock } from 'vitest'; vi.mock("@/components/Routines/queries"); +vi.mock('@/components/User/queries/profile', () => ({ + useProfileQuery: () => ({ isLoading: false, data: { useMetric: true } }), +})); const queryClient = new QueryClient(); diff --git a/src/components/Routines/widgets/LogWidgets.test.tsx b/src/components/Routines/widgets/LogWidgets.test.tsx index f1f928952..305db406f 100644 --- a/src/components/Routines/widgets/LogWidgets.test.tsx +++ b/src/components/Routines/widgets/LogWidgets.test.tsx @@ -1,7 +1,9 @@ import { render, screen } from '@testing-library/react'; import userEvent from "@testing-library/user-event"; import { useDeleteRoutineLogQuery, useEditRoutineLogQuery } from '@/components/Routines/queries'; -import { ExerciseLog } from "@/components/Routines/widgets/LogWidgets"; +import { WorkoutLog } from "@/components/Routines/models/WorkoutLog"; +import { ExerciseLog, formatData } from "@/components/Routines/widgets/LogWidgets"; +import { WEIGHT_UNIT_KG, WEIGHT_UNIT_LB } from "@/core/lib/consts"; import { testExerciseBenchPress } from "@/tests/exerciseTestdata"; import { testWorkoutLogs } from "@/tests/workoutLogsRoutinesTestData"; import type { Mock } from 'vitest'; @@ -10,6 +12,9 @@ vi.mock('@/components/Routines/queries', () => ({ useDeleteRoutineLogQuery: vi.fn(), useEditRoutineLogQuery: vi.fn() })); +vi.mock('@/components/User/queries/profile', () => ({ + useProfileQuery: () => ({ isLoading: false, data: { useMetric: true } }), +})); describe('ExerciseLog', () => { let mockDeleteMutate: Mock; @@ -75,4 +80,22 @@ describe('ExerciseLog', () => { expect(mockDeleteMutate).not.toHaveBeenCalled(); expect(mockEditMutate).toHaveBeenCalled(); }); -}); \ No newline at end of file +}); + +describe('formatData', () => { + const logIn = (weight: number | null, weightUnitId: number | null) => + new WorkoutLog({ ...testWorkoutLogs[0], weight: weight, weightUnitId: weightUnitId }); + + test('converts weights logged in kg or lb to the chart unit', () => { + const data = [logIn(100, WEIGHT_UNIT_LB), logIn(50, WEIGHT_UNIT_KG)]; + + expect(formatData(data, 'kg').map(entry => entry.value)).toEqual([45.36, 50]); + expect(formatData(data, 'lb').map(entry => entry.value)).toEqual([100, 110.23]); + }); + + test('passes other units and missing weights through unchanged', () => { + const data = [logIn(12, 3), logIn(null, WEIGHT_UNIT_LB)]; + + expect(formatData(data, 'lb').map(entry => entry.value)).toEqual([12, null]); + }); +}); diff --git a/src/components/Routines/widgets/LogWidgets.tsx b/src/components/Routines/widgets/LogWidgets.tsx index 7c33104d7..a290842db 100644 --- a/src/components/Routines/widgets/LogWidgets.tsx +++ b/src/components/Routines/widgets/LogWidgets.tsx @@ -18,6 +18,7 @@ import { } from "@mui/x-data-grid"; import { FormQueryErrors } from "@/core/ui/Widgets/FormError"; import { Exercise } from "@/components/Exercises"; +import { useDisplayWeightUnit } from "@/components/Measurements"; import { RIR_VALUES_SELECT_LIST } from "@/components/Routines/models/BaseConfig"; import { WorkoutLog } from "@/components/Routines/models/WorkoutLog"; import { useDeleteRoutineLogQuery, useEditRoutineLogQuery } from "@/components/Routines/queries"; @@ -36,8 +37,9 @@ import { } from "recharts"; import { NameType, ValueType } from "recharts/types/component/DefaultTooltipContent"; import { generateChartColors } from "@/core/lib/colors"; -import { PAGINATION_OPTIONS } from "@/core/lib/consts"; +import { PAGINATION_OPTIONS, WEIGHT_UNIT_KG, WEIGHT_UNIT_LB } from "@/core/lib/consts"; import { dateToLocale, luxonDateTimeToLocale } from "@/core/lib/date"; +import { convertWeight, WeightUnit } from "@/core/lib/weightUnit"; export const ExerciseLog = (props: { exercise: Exercise, routineId: number, logEntries: WorkoutLog[] | undefined }) => { @@ -243,13 +245,18 @@ export const ExerciseLog = (props: { exercise: Exercise, routineId: number, logE * Format the log entries so that they can be passed to the chart * * This is mostly due to the time, which needs to be a number to be shown - * in the scatter plot + * in the scatter plot. Weights logged in kg or lb are converted to the unit + * the chart is drawn in, other units are passed through unchanged. */ -const formatData = (data: WorkoutLog[]) => +export const formatData = (data: WorkoutLog[], unit: WeightUnit) => data.map((log) => { + const logUnit: WeightUnit | null = log.weightUnitId === WEIGHT_UNIT_KG + ? 'kg' + : log.weightUnitId === WEIGHT_UNIT_LB ? 'lb' : null; + return { id: log.id, - value: log.weight, + value: log.weight !== null && logUnit !== null ? convertWeight(log.weight, logUnit, unit) : log.weight, time: log.date.getTime(), entry: log, }; @@ -279,6 +286,7 @@ const ExerciseLogTooltip = ({ active, payload }: TooltipContentProps { + const weightUnit = useDisplayWeightUnit(); // Group by rep count // @@ -306,12 +314,12 @@ export const TimeSeriesChart = (props: { data: WorkoutLog[] }) => { domain={["auto", "auto"]} dataKey="value" name="Value" - unit="kg" + unit={weightUnit} /> {Array.from(result).map(([key, value]) => { const color = colorGenerator.next().value!; - const formattedData = formatData(value); + const formattedData = formatData(value, weightUnit); return Date: Sat, 24 Oct 2026 16:47:07 +0300 Subject: [PATCH 2/2] fix(routines): translate chart weight unit label Use t('server.kg')/t('server.lb') for the Y axis unit label per review feedback, instead of the raw unit string. --- src/components/Routines/widgets/LogWidgets.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Routines/widgets/LogWidgets.tsx b/src/components/Routines/widgets/LogWidgets.tsx index a290842db..6ee703a75 100644 --- a/src/components/Routines/widgets/LogWidgets.tsx +++ b/src/components/Routines/widgets/LogWidgets.tsx @@ -286,7 +286,9 @@ const ExerciseLogTooltip = ({ active, payload }: TooltipContentProps { + const { t } = useTranslation(); const weightUnit = useDisplayWeightUnit(); + const weightUnitLabel = t(weightUnit === 'lb' ? 'server.lb' : 'server.kg'); // Group by rep count // @@ -314,7 +316,7 @@ export const TimeSeriesChart = (props: { data: WorkoutLog[] }) => { domain={["auto", "auto"]} dataKey="value" name="Value" - unit={weightUnit} + unit={weightUnitLabel} /> {Array.from(result).map(([key, value]) => {