@wger-project/react-components 25.10.16 → 25.11.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/build/chunks/{browser-ponyfill-DL_vVusK.js → browser-ponyfill-CyEkMYuR.js} +3 -3
- package/build/chunks/{browser-ponyfill-DL_vVusK.js.map → browser-ponyfill-CyEkMYuR.js.map} +1 -1
- package/build/locales/de/translation.json +334 -334
- package/build/locales/en/translation.json +12 -2
- package/build/locales/fil/translation.json +3 -0
- package/build/locales/fr/translation.json +347 -337
- package/build/locales/hr/translation.json +344 -244
- package/build/locales/it/translation.json +333 -333
- package/build/locales/ko/translation.json +327 -327
- package/build/locales/pt_PT/translation.json +330 -330
- package/build/locales/sk/translation.json +26 -1
- package/build/locales/sl/translation.json +321 -321
- package/build/locales/ta/translation.json +325 -325
- package/build/locales/uk/translation.json +344 -334
- package/build/locales/zh_Hans/translation.json +332 -332
- package/build/main.js +137 -236
- package/build/main.js.map +1 -1
- package/package.json +13 -13
- package/src/components/BodyWeight/Form/WeightForm.tsx +3 -4
- package/src/components/BodyWeight/WeightChart/index.tsx +26 -29
- package/src/components/Exercises/Detail/Head/ExerciseDeleteDialog.tsx +3 -4
- package/src/components/Exercises/ExerciseOverview.tsx +4 -4
- package/src/components/Exercises/Filter/NameAutcompleter.tsx +41 -39
- package/src/components/Exercises/Filter/NameAutocompleter.test.tsx +2 -1
- package/src/components/Measurements/Screens/MeasurementCategoryDetail.test.tsx +4 -2
- package/src/components/Measurements/widgets/MeasurementChart.tsx +27 -30
- package/src/components/Nutrition/components/BmiCalculator.tsx +40 -42
- package/src/components/Nutrition/widgets/IngredientAutcompleter.tsx +1 -1
- package/src/components/Nutrition/widgets/charts/MacrosPieChart.tsx +17 -19
- package/src/components/Nutrition/widgets/charts/NutritionDiaryChart.tsx +39 -38
- package/src/components/Nutrition/widgets/charts/NutritionalValuesDashboardChart.tsx +27 -29
- package/src/components/Nutrition/widgets/charts/NutritionalValuesPlannedLoggedChart.tsx +20 -19
- package/src/components/Nutrition/widgets/forms/NutritionDiaryEntryForm.tsx +15 -4
- package/src/components/WorkoutRoutines/Detail/RoutineDetailsTable.tsx +3 -3
- package/src/components/WorkoutRoutines/Detail/WorkoutStats.tsx +17 -19
- package/src/components/WorkoutRoutines/models/Day.ts +16 -6
- package/src/components/WorkoutRoutines/models/SlotEntry.ts +7 -2
- package/src/components/WorkoutRoutines/widgets/DayDetails.tsx +4 -4
- package/src/components/WorkoutRoutines/widgets/LogWidgets.tsx +35 -38
- package/src/components/WorkoutRoutines/widgets/RoutineDetailsCard.tsx +8 -11
- package/src/components/WorkoutRoutines/widgets/SlotDetails.tsx +4 -4
- package/src/components/WorkoutRoutines/widgets/forms/DayForm.tsx +21 -9
- package/src/components/WorkoutRoutines/widgets/forms/DayTypeSelect.tsx +66 -0
- package/src/components/WorkoutRoutines/widgets/forms/SessionForm.test.tsx +0 -2
- package/src/components/WorkoutRoutines/widgets/forms/SessionLogsForm.tsx +4 -4
- package/src/components/WorkoutRoutines/widgets/forms/SlotEntryForm.test.tsx +12 -10
- package/src/components/WorkoutRoutines/widgets/forms/SlotEntryForm.tsx +2 -1
- package/src/components/WorkoutRoutines/widgets/forms/SlotForm.tsx +1 -1
- package/src/services/exerciseTranslation.ts +24 -9
- package/src/services/responseType.ts +3 -29
- package/src/tests/exercises/searchResponse.ts +47 -22
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NutritionalValues } from "components/Nutrition/helpers/nutritionalValues";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
|
-
import { Bar, BarChart, CartesianGrid, Legend,
|
|
4
|
+
import { Bar, BarChart, CartesianGrid, Legend, Tooltip, XAxis, YAxis } from 'recharts';
|
|
5
5
|
import { generateChartColors } from "utils/colors";
|
|
6
6
|
import { numberLocale } from "utils/numbers";
|
|
7
7
|
|
|
@@ -50,46 +50,47 @@ export const NutritionDiaryChart = ({ showPlanned, planned, today, avg7Days }: N
|
|
|
50
50
|
];
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
unit={t('nutrition.gramShort')}
|
|
76
|
-
name={t('nutrition.planned')}
|
|
77
|
-
fill={colorGenerator.next().value!}
|
|
78
|
-
/>
|
|
79
|
-
}
|
|
80
|
-
<Bar
|
|
81
|
-
dataKey="today"
|
|
82
|
-
unit={t('nutrition.gramShort')}
|
|
83
|
-
name={t('nutrition.today')}
|
|
84
|
-
fill={colorGenerator.next().value!}
|
|
85
|
-
/>
|
|
53
|
+
<BarChart
|
|
54
|
+
data={data}
|
|
55
|
+
margin={{
|
|
56
|
+
top: 20,
|
|
57
|
+
right: 30,
|
|
58
|
+
left: 20,
|
|
59
|
+
bottom: 5,
|
|
60
|
+
}}
|
|
61
|
+
responsive
|
|
62
|
+
width={"100%"}
|
|
63
|
+
height={300}
|
|
64
|
+
>
|
|
65
|
+
<CartesianGrid strokeDasharray="3 4" />
|
|
66
|
+
<XAxis dataKey="name" />
|
|
67
|
+
<YAxis
|
|
68
|
+
type="number"
|
|
69
|
+
orientation="left"
|
|
70
|
+
unit={t('nutrition.gramShort')}
|
|
71
|
+
/>
|
|
72
|
+
<Tooltip formatter={(value: number) => numberLocale(value, i18n.language)} />
|
|
73
|
+
<Legend />
|
|
74
|
+
{showPlanned &&
|
|
86
75
|
<Bar
|
|
87
|
-
dataKey="
|
|
76
|
+
dataKey="planned"
|
|
88
77
|
unit={t('nutrition.gramShort')}
|
|
89
|
-
name={t('nutrition.
|
|
78
|
+
name={t('nutrition.planned')}
|
|
90
79
|
fill={colorGenerator.next().value!}
|
|
91
80
|
/>
|
|
92
|
-
|
|
93
|
-
|
|
81
|
+
}
|
|
82
|
+
<Bar
|
|
83
|
+
dataKey="today"
|
|
84
|
+
unit={t('nutrition.gramShort')}
|
|
85
|
+
name={t('nutrition.today')}
|
|
86
|
+
fill={colorGenerator.next().value!}
|
|
87
|
+
/>
|
|
88
|
+
<Bar
|
|
89
|
+
dataKey="avg7Days"
|
|
90
|
+
unit={t('nutrition.gramShort')}
|
|
91
|
+
name={t('nutrition.7dayAvg')}
|
|
92
|
+
fill={colorGenerator.next().value!}
|
|
93
|
+
/>
|
|
94
|
+
</BarChart>
|
|
94
95
|
);
|
|
95
96
|
};
|
|
@@ -3,7 +3,7 @@ import { NutritionalValues } from "components/Nutrition/helpers/nutritionalValue
|
|
|
3
3
|
import { LinearPlannedLoggedChart } from "components/Nutrition/widgets/charts/LinearPlannedLoggedChart";
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
|
-
import { Cell, Pie, PieChart
|
|
6
|
+
import { Cell, Pie, PieChart } from 'recharts';
|
|
7
7
|
import { numberLocale } from "utils/numbers";
|
|
8
8
|
|
|
9
9
|
|
|
@@ -32,34 +32,32 @@ export const NutritionalValuesDashboardChart = (props: {
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
return <Stack direction={'row'}>
|
|
35
|
-
<
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
</PieChart>
|
|
62
|
-
</ResponsiveContainer>
|
|
35
|
+
<PieChart responsive width={'50%'} height={140}>
|
|
36
|
+
<Pie
|
|
37
|
+
// cx={0}
|
|
38
|
+
// cy={'10'}
|
|
39
|
+
height={100}
|
|
40
|
+
data={data}
|
|
41
|
+
startAngle={200}
|
|
42
|
+
endAngle={-20}
|
|
43
|
+
innerRadius={60}
|
|
44
|
+
outerRadius={70}
|
|
45
|
+
paddingAngle={2}
|
|
46
|
+
dataKey="value"
|
|
47
|
+
>
|
|
48
|
+
{data.map((entry, index) => (
|
|
49
|
+
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
|
|
50
|
+
))}
|
|
51
|
+
</Pie>
|
|
52
|
+
<g>
|
|
53
|
+
<text x={'50%'} y={'45%'} fontSize="1.25em" textAnchor="middle">{/*fill="#333"*/}
|
|
54
|
+
{t('nutrition.valueEnergyKcal', { value: numberLocale(energyDiff, i18n.language) })}
|
|
55
|
+
</text>
|
|
56
|
+
<text x={'50%'} y={'60%'} fontSize="1em" textAnchor="middle">
|
|
57
|
+
{props.planned.energy > 0 && t(energyPercentage < 100 ? 'nutrition.valueRemaining' : 'nutrition.valueTooMany')}
|
|
58
|
+
</text>
|
|
59
|
+
</g>
|
|
60
|
+
</PieChart>
|
|
63
61
|
<Stack width={'50%'} spacing={1}>
|
|
64
62
|
<LinearPlannedLoggedChart
|
|
65
63
|
title={t('nutrition.protein')}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NutritionalValues } from "components/Nutrition/helpers/nutritionalValues";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
|
-
import { Bar, BarChart, CartesianGrid,
|
|
4
|
+
import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from 'recharts';
|
|
5
5
|
import { generateChartColors } from "utils/colors";
|
|
6
6
|
|
|
7
7
|
|
|
@@ -32,23 +32,24 @@ export const NutritionalValuesPlannedLoggedChart = (props: {
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
return (
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
35
|
+
<BarChart
|
|
36
|
+
data={data}
|
|
37
|
+
layout="vertical"
|
|
38
|
+
margin={{
|
|
39
|
+
left: 60,
|
|
40
|
+
}}
|
|
41
|
+
responsive
|
|
42
|
+
width={"100%"}
|
|
43
|
+
height={150}
|
|
44
|
+
>
|
|
45
|
+
<CartesianGrid strokeDasharray="3 4" />
|
|
46
|
+
<XAxis type={'number'} unit={'%'} />
|
|
47
|
+
<YAxis type={'category'} dataKey={'name'} />
|
|
48
|
+
<Bar
|
|
49
|
+
dataKey="value"
|
|
50
|
+
unit={'%'}
|
|
51
|
+
fill={colorGenerator.next().value!}
|
|
52
|
+
/>
|
|
53
|
+
</BarChart>
|
|
53
54
|
);
|
|
54
55
|
};
|
|
@@ -39,6 +39,8 @@ export const NutritionDiaryEntryForm = ({ planId, entry, mealId, meals, closeFn
|
|
|
39
39
|
.min(1, t('forms.minValue', { value: '1' })),
|
|
40
40
|
ingredient: yup
|
|
41
41
|
.number()
|
|
42
|
+
.nullable()
|
|
43
|
+
.moreThan(0, t('forms.fieldRequired'))
|
|
42
44
|
.required(t('forms.fieldRequired')),
|
|
43
45
|
datetime: yup
|
|
44
46
|
.date()
|
|
@@ -51,7 +53,7 @@ export const NutritionDiaryEntryForm = ({ planId, entry, mealId, meals, closeFn
|
|
|
51
53
|
initialValues={{
|
|
52
54
|
datetime: new Date(),
|
|
53
55
|
amount: 0,
|
|
54
|
-
ingredient:
|
|
56
|
+
ingredient: null,
|
|
55
57
|
}}
|
|
56
58
|
validationSchema={validationSchema}
|
|
57
59
|
onSubmit={async (values) => {
|
|
@@ -66,7 +68,7 @@ export const NutritionDiaryEntryForm = ({ planId, entry, mealId, meals, closeFn
|
|
|
66
68
|
planId: planId,
|
|
67
69
|
amount: newAmount,
|
|
68
70
|
datetime: values.datetime,
|
|
69
|
-
ingredientId: values.ingredient
|
|
71
|
+
ingredientId: values.ingredient!
|
|
70
72
|
});
|
|
71
73
|
editDiaryQuery.mutate(newDiaryEntry);
|
|
72
74
|
} else {
|
|
@@ -75,7 +77,7 @@ export const NutritionDiaryEntryForm = ({ planId, entry, mealId, meals, closeFn
|
|
|
75
77
|
planId: planId,
|
|
76
78
|
amount: newAmount,
|
|
77
79
|
datetime: values.datetime,
|
|
78
|
-
ingredientId: values.ingredient
|
|
80
|
+
ingredientId: values.ingredient!,
|
|
79
81
|
mealId: selectedMeal,
|
|
80
82
|
}));
|
|
81
83
|
}
|
|
@@ -90,7 +92,16 @@ export const NutritionDiaryEntryForm = ({ planId, entry, mealId, meals, closeFn
|
|
|
90
92
|
<Form>
|
|
91
93
|
<Stack spacing={2}>
|
|
92
94
|
<IngredientAutocompleter
|
|
93
|
-
callback={(value: Ingredient | null) =>
|
|
95
|
+
callback={(value: Ingredient | null) => {
|
|
96
|
+
formik.setFieldTouched('ingredient', true);
|
|
97
|
+
formik.setFieldValue('ingredient', value?.id ?? null);
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
100
|
+
{formik.touched.ingredient && formik.errors.ingredient && (
|
|
101
|
+
<div style={{ color: 'crimson', fontSize: '0.7rem', marginLeft: '12px' }}>
|
|
102
|
+
{formik.errors.ingredient}
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
94
105
|
<TextField
|
|
95
106
|
fullWidth
|
|
96
107
|
id="amount"
|
|
@@ -212,7 +212,7 @@ export const RoutineTable = (props: {
|
|
|
212
212
|
borderBottomWidth: showLogs ? 0 : null
|
|
213
213
|
}}>{slotEntry.exercise?.getTranslation(language).name}</TableCell>
|
|
214
214
|
{iterations.map((iteration) => {
|
|
215
|
-
const setConfig = props.routine.getSetConfigData(day.id
|
|
215
|
+
const setConfig = props.routine.getSetConfigData(day.id!, iteration, slotEntry.id!);
|
|
216
216
|
|
|
217
217
|
return <React.Fragment key={iteration}>
|
|
218
218
|
<TableCell align={'center'} sx={sx}>
|
|
@@ -268,7 +268,7 @@ export const RoutineTable = (props: {
|
|
|
268
268
|
<small>{t('nutrition.logged')}</small>
|
|
269
269
|
</TableCell>
|
|
270
270
|
{iterations.map((iteration) => {
|
|
271
|
-
const setConfig = props.routine.getSetConfigData(day.id
|
|
271
|
+
const setConfig = props.routine.getSetConfigData(day.id!, iteration, slotEntry.id!);
|
|
272
272
|
const iterationLogs = groupedLogs[iteration] ?? [];
|
|
273
273
|
|
|
274
274
|
const logs = iterationLogs.filter((log) => log.slotEntryId === slotEntry.id);
|
|
@@ -330,7 +330,7 @@ export const RoutineTable = (props: {
|
|
|
330
330
|
sx={{ backgroundColor: theme.palette.action.hover }}
|
|
331
331
|
className={classes.stickyColumn}
|
|
332
332
|
>
|
|
333
|
-
<b>{day.
|
|
333
|
+
<b>{day.displayName}</b>
|
|
334
334
|
</TableCell>
|
|
335
335
|
<TableCell sx={{ backgroundColor: theme.palette.action.hover }} colSpan={5 * iterations.length}>
|
|
336
336
|
</TableCell>
|
|
@@ -209,25 +209,23 @@ export const WorkoutStats = () => {
|
|
|
209
209
|
|
|
210
210
|
<Grid size={12}>
|
|
211
211
|
<Box width="100%" height={400}>
|
|
212
|
-
<
|
|
213
|
-
<
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
{
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
</LineChart>
|
|
230
|
-
</ResponsiveContainer>
|
|
212
|
+
<LineChart width="100%" height="100%" responsive>
|
|
213
|
+
<CartesianGrid strokeDasharray="3 3" />
|
|
214
|
+
<XAxis dataKey="category" type="category" allowDuplicatedCategory={false} />
|
|
215
|
+
<YAxis dataKey="value" />
|
|
216
|
+
<Tooltip
|
|
217
|
+
formatter={(value: number) => Number.isInteger(value) ? value.toFixed(0) : value.toFixed(2)} />
|
|
218
|
+
<Legend
|
|
219
|
+
layout={"vertical"}
|
|
220
|
+
verticalAlign="middle"
|
|
221
|
+
align="right"
|
|
222
|
+
wrapperStyle={{ paddingLeft: "20px" }}
|
|
223
|
+
/>
|
|
224
|
+
{chartData.map((s) => (
|
|
225
|
+
<Line dataKey="value" data={s.data} name={s.name} key={s.name}
|
|
226
|
+
stroke={colorGenerator.next()!.value!} />
|
|
227
|
+
))}
|
|
228
|
+
</LineChart>
|
|
231
229
|
</Box>
|
|
232
230
|
</Grid>
|
|
233
231
|
|
|
@@ -4,6 +4,8 @@ import { Slot } from "components/WorkoutRoutines/models/Slot";
|
|
|
4
4
|
import i18n from 'i18next';
|
|
5
5
|
import { Adapter } from "utils/Adapter";
|
|
6
6
|
|
|
7
|
+
export type DayType = 'custom' | 'enom' | 'amrap' | 'hiit' | 'tabata' | 'edt' | 'rft' | 'afap';
|
|
8
|
+
|
|
7
9
|
interface DayConstructorParams {
|
|
8
10
|
id?: number;
|
|
9
11
|
routineId: number | null;
|
|
@@ -12,7 +14,7 @@ interface DayConstructorParams {
|
|
|
12
14
|
description?: string;
|
|
13
15
|
isRest?: boolean;
|
|
14
16
|
needLogsToAdvance?: boolean;
|
|
15
|
-
type?:
|
|
17
|
+
type?: DayType;
|
|
16
18
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
19
|
config?: any | null;
|
|
18
20
|
slots?: Slot[];
|
|
@@ -30,7 +32,7 @@ export class Day {
|
|
|
30
32
|
description: string;
|
|
31
33
|
isRest: boolean;
|
|
32
34
|
needLogsToAdvance: boolean;
|
|
33
|
-
type:
|
|
35
|
+
type: DayType;
|
|
34
36
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
37
|
config: any | null;
|
|
36
38
|
|
|
@@ -53,6 +55,14 @@ export class Day {
|
|
|
53
55
|
return this.type !== 'custom';
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
public get displayNameWithType(): string {
|
|
59
|
+
return this.isSpecialType ? `${this.type.toUpperCase()} - ${this.displayName}` : this.displayName;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public get displayName(): string {
|
|
63
|
+
return this.isRest ? i18n.t('routines.restDay') : this.name;
|
|
64
|
+
}
|
|
65
|
+
|
|
56
66
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
67
|
static fromJson(json: any): Day {
|
|
58
68
|
return adapter.fromJson(json);
|
|
@@ -73,9 +83,6 @@ export class Day {
|
|
|
73
83
|
});
|
|
74
84
|
}
|
|
75
85
|
|
|
76
|
-
public getDisplayName(): string {
|
|
77
|
-
return this.isRest ? i18n.t('routines.restDay') : this.name;
|
|
78
|
-
}
|
|
79
86
|
|
|
80
87
|
toJson() {
|
|
81
88
|
return adapter.toJson(this);
|
|
@@ -83,7 +90,10 @@ export class Day {
|
|
|
83
90
|
|
|
84
91
|
}
|
|
85
92
|
|
|
86
|
-
|
|
93
|
+
/*
|
|
94
|
+
* Returns the display name of the day, or "Rest day" if it's a rest day or null
|
|
95
|
+
*/
|
|
96
|
+
export const getDayName = (day: Day | null): string => day === null || day.isRest ? i18n.t('routines.restDay') : day.displayNameWithType;
|
|
87
97
|
|
|
88
98
|
|
|
89
99
|
class DayAdapter implements Adapter<Day> {
|
|
@@ -133,11 +133,16 @@ export class SlotEntry {
|
|
|
133
133
|
order: overrides?.order ?? other.order,
|
|
134
134
|
comment: overrides?.comment ?? other.comment,
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
// NOTE: temporarily commented out to avoid issues. The constructor will see the
|
|
137
|
+
// unit objects and set the ids accordingly, ignoring the explicit IDs. This is
|
|
138
|
+
// probably OK since we always load the whole routine again after an edit, but
|
|
139
|
+
// it is a bit ugly.
|
|
140
|
+
|
|
141
|
+
// repetitionUnit: overrides?.repetitionUnit ?? (other.repetitionUnit ?? undefined),
|
|
137
142
|
repetitionUnitId: overrides?.repetitionUnitId ?? other.repetitionUnitId,
|
|
138
143
|
repetitionRounding: overrides?.repetitionRounding ?? other.repetitionRounding,
|
|
139
144
|
|
|
140
|
-
weightUnit: overrides?.weightUnit ?? (other.weightUnit ?? undefined),
|
|
145
|
+
// weightUnit: overrides?.weightUnit ?? (other.weightUnit ?? undefined),
|
|
141
146
|
weightUnitId: overrides?.weightUnitId ?? other.weightUnitId,
|
|
142
147
|
weightRounding: overrides?.weightRounding ?? other.weightRounding,
|
|
143
148
|
});
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import Grid from '@mui/material/Grid';
|
|
25
25
|
import { LoadingPlaceholder, LoadingProgressIcon } from "components/Core/LoadingWidget/LoadingWidget";
|
|
26
26
|
import { NameAutocompleter } from "components/Exercises/Filter/NameAutcompleter";
|
|
27
|
+
import { Exercise } from "components/Exercises/models/exercise";
|
|
27
28
|
import { useProfileQuery } from "components/User/queries/profile";
|
|
28
29
|
import { Day } from "components/WorkoutRoutines/models/Day";
|
|
29
30
|
import { Slot } from "components/WorkoutRoutines/models/Slot";
|
|
@@ -43,7 +44,6 @@ import { SlotDetails } from "components/WorkoutRoutines/widgets/SlotDetails";
|
|
|
43
44
|
import React, { useState } from "react";
|
|
44
45
|
import { useTranslation } from "react-i18next";
|
|
45
46
|
import { Link } from "react-router-dom";
|
|
46
|
-
import { ExerciseSearchResponse } from "services/responseType";
|
|
47
47
|
import { SNACKBAR_AUTO_HIDE_DURATION, WEIGHT_UNIT_KG, WEIGHT_UNIT_LB } from "utils/consts";
|
|
48
48
|
import { makeLink, WgerLink } from "utils/url";
|
|
49
49
|
|
|
@@ -135,7 +135,7 @@ export const DayDragAndDropGrid = (props: {
|
|
|
135
135
|
provided.draggableProps.style ?? {}
|
|
136
136
|
)}
|
|
137
137
|
|
|
138
|
-
label={day.
|
|
138
|
+
label={day.displayName}
|
|
139
139
|
value={day.id}
|
|
140
140
|
icon={<DragIndicatorIcon />}
|
|
141
141
|
iconPosition="start"
|
|
@@ -381,13 +381,13 @@ export const DayDetails = (props: {
|
|
|
381
381
|
&& <Grid size={12}>
|
|
382
382
|
<Box height={20} />
|
|
383
383
|
<NameAutocompleter
|
|
384
|
-
callback={(exercise:
|
|
384
|
+
callback={(exercise: Exercise | null) => {
|
|
385
385
|
if (exercise === null) {
|
|
386
386
|
return;
|
|
387
387
|
}
|
|
388
388
|
addSlotEntryQuery.mutate(new SlotEntry({
|
|
389
389
|
slotId: slot.id!,
|
|
390
|
-
exerciseId: exercise.
|
|
390
|
+
exerciseId: exercise.id!,
|
|
391
391
|
type: 'normal',
|
|
392
392
|
order: slot.entries.length + 1,
|
|
393
393
|
weightUnitId: userProfileQuery.data!.useMetric ? WEIGHT_UNIT_KG : WEIGHT_UNIT_LB,
|
|
@@ -27,7 +27,6 @@ import { useTranslation } from "react-i18next";
|
|
|
27
27
|
import {
|
|
28
28
|
CartesianGrid,
|
|
29
29
|
Legend,
|
|
30
|
-
ResponsiveContainer,
|
|
31
30
|
Scatter,
|
|
32
31
|
ScatterChart,
|
|
33
32
|
Tooltip,
|
|
@@ -292,43 +291,41 @@ export const TimeSeriesChart = (props: { data: WorkoutLog[] }) => {
|
|
|
292
291
|
|
|
293
292
|
return (
|
|
294
293
|
<Box>
|
|
295
|
-
<
|
|
296
|
-
<
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
</ScatterChart>
|
|
331
|
-
</ResponsiveContainer>
|
|
294
|
+
<ScatterChart responsive width={"100%"} height={250}>
|
|
295
|
+
<XAxis
|
|
296
|
+
dataKey="time"
|
|
297
|
+
domain={["auto", "auto"]}
|
|
298
|
+
name="Time"
|
|
299
|
+
tickFormatter={unixTime => luxonDateTimeToLocale(DateTime.fromMillis(unixTime))}
|
|
300
|
+
type="number"
|
|
301
|
+
/>
|
|
302
|
+
<YAxis
|
|
303
|
+
domain={["auto", "auto"]}
|
|
304
|
+
dataKey="value"
|
|
305
|
+
name="Value"
|
|
306
|
+
unit="kg"
|
|
307
|
+
/>
|
|
308
|
+
|
|
309
|
+
{Array.from(result).map(([key, value]) => {
|
|
310
|
+
const color = colorGenerator.next().value!;
|
|
311
|
+
const formattedData = formatData(value);
|
|
312
|
+
|
|
313
|
+
return <Scatter
|
|
314
|
+
key={key}
|
|
315
|
+
data={formattedData}
|
|
316
|
+
fill={color}
|
|
317
|
+
line={{ stroke: color }}
|
|
318
|
+
lineType="joint"
|
|
319
|
+
lineJointType="monotoneX"
|
|
320
|
+
name={key?.toString()}
|
|
321
|
+
/>;
|
|
322
|
+
}
|
|
323
|
+
)}
|
|
324
|
+
|
|
325
|
+
<Tooltip content={<ExerciseLogTooltip />} />
|
|
326
|
+
<CartesianGrid strokeDasharray="3 3" />
|
|
327
|
+
<Legend />
|
|
328
|
+
</ScatterChart>
|
|
332
329
|
</Box>
|
|
333
330
|
);
|
|
334
331
|
};
|
|
@@ -111,10 +111,7 @@ export function SetConfigDataDetails(props: {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
|
|
114
|
-
function SlotDataList(props: {
|
|
115
|
-
slotData: SlotData,
|
|
116
|
-
index: number,
|
|
117
|
-
}) {
|
|
114
|
+
function SlotDataList(props: { slotData: SlotData }) {
|
|
118
115
|
return (
|
|
119
116
|
<Grid
|
|
120
117
|
container
|
|
@@ -163,6 +160,9 @@ export const DayDetailsCard = (props: { dayData: RoutineDayData, routineId: numb
|
|
|
163
160
|
const theme = useTheme();
|
|
164
161
|
const [t, i18n] = useTranslation();
|
|
165
162
|
|
|
163
|
+
const isToday = isSameDay(props.dayData.date, new Date());
|
|
164
|
+
const subheader = <Typography sx={{ whiteSpace: 'pre-line' }}>{props.dayData.day?.description}</Typography>;
|
|
165
|
+
|
|
166
166
|
return (
|
|
167
167
|
<Card sx={{ minWidth: 275 }}>
|
|
168
168
|
<CardHeader
|
|
@@ -178,19 +178,16 @@ export const DayDetailsCard = (props: { dayData: RoutineDayData, routineId: numb
|
|
|
178
178
|
<Addchart />
|
|
179
179
|
</IconButton>
|
|
180
180
|
</Tooltip>}
|
|
181
|
-
title={getDayName(props.dayData.day)}
|
|
182
|
-
avatar={
|
|
183
|
-
subheader={
|
|
181
|
+
title={<Typography variant={"h5"}>{getDayName(props.dayData.day)}</Typography>}
|
|
182
|
+
avatar={isToday ? <TodayIcon /> : null}
|
|
183
|
+
subheader={subheader}
|
|
184
184
|
/>
|
|
185
185
|
{props.dayData.slots.length > 0 && <CardContent sx={{ padding: 0, marginBottom: 0 }}>
|
|
186
186
|
<Stack>
|
|
187
187
|
{props.dayData.slots.map((slotData, index) => (
|
|
188
188
|
<div key={index}>
|
|
189
189
|
<Box padding={1}>
|
|
190
|
-
<SlotDataList
|
|
191
|
-
slotData={slotData}
|
|
192
|
-
index={index}
|
|
193
|
-
/>
|
|
190
|
+
<SlotDataList slotData={slotData} />
|
|
194
191
|
</Box>
|
|
195
192
|
<Divider />
|
|
196
193
|
</div>
|
|
@@ -4,6 +4,7 @@ import EditOffIcon from '@mui/icons-material/EditOff';
|
|
|
4
4
|
import { Alert, AlertTitle, IconButton, Typography } from "@mui/material";
|
|
5
5
|
import Grid from '@mui/material/Grid';
|
|
6
6
|
import { NameAutocompleter } from "components/Exercises/Filter/NameAutcompleter";
|
|
7
|
+
import { Exercise } from "components/Exercises/models/exercise";
|
|
7
8
|
import { useLanguageQuery } from "components/Exercises/queries";
|
|
8
9
|
import { BaseConfig } from "components/WorkoutRoutines/models/BaseConfig";
|
|
9
10
|
import { Slot } from "components/WorkoutRoutines/models/Slot";
|
|
@@ -21,7 +22,6 @@ import {
|
|
|
21
22
|
import React, { useState } from "react";
|
|
22
23
|
import { useTranslation } from "react-i18next";
|
|
23
24
|
import { getLanguageByShortName } from "services";
|
|
24
|
-
import { ExerciseSearchResponse } from "services/responseType";
|
|
25
25
|
|
|
26
26
|
/*
|
|
27
27
|
* Converts a number to an alphabetic string, useful for counting
|
|
@@ -95,12 +95,12 @@ export const SlotEntryDetails = (props: {
|
|
|
95
95
|
|
|
96
96
|
const isPending = editSlotEntryQuery.isPending || deleteSlotEntryQuery.isPending;
|
|
97
97
|
|
|
98
|
-
const handleExerciseChange = (
|
|
99
|
-
if (
|
|
98
|
+
const handleExerciseChange = (exercise: Exercise | null) => {
|
|
99
|
+
if (exercise === null) {
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
editSlotEntryQuery.mutate(SlotEntry.clone(props.slotEntry, { exerciseId:
|
|
103
|
+
editSlotEntryQuery.mutate(SlotEntry.clone(props.slotEntry, { exerciseId: exercise.id! }));
|
|
104
104
|
setEditExercise(false);
|
|
105
105
|
};
|
|
106
106
|
|