@wger-project/react-components 25.12.5 → 26.2.26
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/build/assets/ajax-loader.gif +0 -0
- package/build/assets/index.css +1 -1
- package/build/assets/slick.svg +14 -0
- package/build/locales/ar/translation.json +347 -236
- package/build/locales/cs/translation.json +257 -253
- package/build/locales/de/translation.json +13 -3
- package/build/locales/en/translation.json +4 -1
- package/build/locales/es/translation.json +26 -4
- package/build/locales/fr/translation.json +10 -1
- package/build/locales/hi/translation.json +4 -1
- package/build/locales/hr/translation.json +15 -3
- package/build/locales/mk/translation.json +138 -0
- package/build/locales/nl/translation.json +118 -11
- package/build/locales/pt/translation.json +338 -338
- package/build/locales/pt_BR/translation.json +15 -3
- package/build/locales/ru/translation.json +43 -3
- package/build/locales/ta/translation.json +1 -1
- package/build/locales/uk/translation.json +13 -1
- package/build/locales/zh_Hans/translation.json +25 -1
- package/build/locales/zh_Hant/translation.json +255 -243
- package/build/main.js +170 -170
- package/build/main.js.map +1 -1
- package/package.json +15 -13
- package/src/components/BodyWeight/TableDashboard/TableDashboard.tsx +4 -6
- package/src/components/Calendar/Components/CalendarComponent.test.tsx +18 -22
- package/src/components/Calendar/Components/CalendarComponent.tsx +11 -8
- package/src/components/Calendar/Components/CalendarHeader.tsx +3 -3
- package/src/components/Calendar/Components/Entries.tsx +8 -3
- package/src/components/Dashboard/CalendarCard.tsx +16 -0
- package/src/components/Dashboard/ConfigurableDashboard.test.ts +129 -0
- package/src/components/Dashboard/ConfigurableDashboard.tsx +352 -89
- package/src/components/Dashboard/DashboardCard.tsx +3 -2
- package/src/components/Dashboard/MeasurementCard.test.tsx +75 -0
- package/src/components/Dashboard/MeasurementCard.tsx +101 -0
- package/src/components/Dashboard/RoutineCard.tsx +1 -1
- package/src/components/Dashboard/TrophiesCard.test.tsx +63 -0
- package/src/components/Dashboard/TrophiesCard.tsx +84 -0
- package/src/components/Dashboard/WeightCard.test.tsx +0 -10
- package/src/components/Measurements/Screens/MeasurementCategoryOverview.tsx +1 -1
- package/src/components/Measurements/models/Category.ts +13 -2
- package/src/components/Measurements/models/Entry.ts +13 -2
- package/src/components/Trophies/components/TrophiesDetail.test.tsx +34 -0
- package/src/components/Trophies/components/TrophiesDetail.tsx +88 -0
- package/src/components/Trophies/models/trophy.test.ts +33 -0
- package/src/components/Trophies/models/trophy.ts +75 -0
- package/src/components/Trophies/models/userTrophy.test.ts +38 -0
- package/src/components/Trophies/models/userTrophy.ts +67 -0
- package/src/components/Trophies/models/userTrophyProgression.test.ts +43 -0
- package/src/components/Trophies/models/userTrophyProgression.ts +68 -0
- package/src/components/Trophies/queries/trophies.ts +31 -0
- package/src/components/Trophies/services/trophies.ts +22 -0
- package/src/components/Trophies/services/userTrophies.ts +33 -0
- package/src/components/Trophies/services/userTrophyProgression.ts +16 -0
- package/src/components/WorkoutRoutines/Detail/RoutineDetail.tsx +1 -1
- package/src/components/WorkoutRoutines/Detail/TemplateDetail.tsx +1 -1
- package/src/components/WorkoutRoutines/models/Routine.test.ts +17 -0
- package/src/components/WorkoutRoutines/models/Routine.ts +20 -3
- package/src/components/WorkoutRoutines/widgets/RoutineDetailsCard.tsx +1 -1
- package/src/components/index.ts +0 -2
- package/src/pages/Calendar/index.tsx +2 -2
- package/src/pages/WeightOverview/index.tsx +1 -1
- package/src/routes.tsx +6 -1
- package/src/services/measurements.ts +10 -17
- package/src/tests/trophies/trophiesTestData.ts +80 -0
- package/src/utils/consts.ts +18 -3
- package/src/utils/url.test.ts +32 -1
- package/src/utils/url.ts +24 -3
- package/src/components/Carousel/carousel.module.css +0 -43
- package/src/components/Carousel/carousel.module.css.map +0 -1
- package/src/components/Carousel/carousel.module.scss +0 -46
- package/src/components/Carousel/index.tsx +0 -66
- package/src/components/Dashboard/GoalCard.tsx +0 -71
package/src/utils/url.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import i18n from "i18n";
|
|
2
|
+
import { getAcceptLanguage, makeHeader, makeLink, makeUrl, WgerLink } from "utils/url";
|
|
2
3
|
|
|
3
4
|
describe("test url utility", () => {
|
|
4
5
|
|
|
@@ -67,6 +68,7 @@ describe("test the header utility", () => {
|
|
|
67
68
|
test('generate header', () => {
|
|
68
69
|
const result = makeHeader('123');
|
|
69
70
|
expect(result).toStrictEqual({
|
|
71
|
+
'Accept-Language': 'en',
|
|
70
72
|
'Authorization': `Token 123`,
|
|
71
73
|
'Content-Type': 'application/json',
|
|
72
74
|
});
|
|
@@ -75,6 +77,7 @@ describe("test the header utility", () => {
|
|
|
75
77
|
test('generate header - token from config', () => {
|
|
76
78
|
const result = makeHeader();
|
|
77
79
|
expect(result).toStrictEqual({
|
|
80
|
+
'Accept-Language': 'en',
|
|
78
81
|
'Authorization': `Token 122333444455555666666`,
|
|
79
82
|
'Content-Type': 'application/json',
|
|
80
83
|
});
|
|
@@ -123,5 +126,33 @@ describe("test the makeLink helper", () => {
|
|
|
123
126
|
const result = makeLink(WgerLink.WEIGHT_OVERVIEW, 'de',);
|
|
124
127
|
expect(result).toEqual('/de/weight/overview');
|
|
125
128
|
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe("test the getAcceptLanguage helper", () => {
|
|
132
|
+
|
|
133
|
+
beforeEach(() => {
|
|
134
|
+
// @ts-expect-error - test helper assignment
|
|
135
|
+
i18n.languages = undefined;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("returns default when languages is undefined", () => {
|
|
139
|
+
// @ts-expect-error - test helper assignment
|
|
140
|
+
i18n.languages = undefined;
|
|
141
|
+
expect(getAcceptLanguage()).toBe("en");
|
|
142
|
+
});
|
|
126
143
|
|
|
144
|
+
test("returns default when languages is an empty array", () => {
|
|
145
|
+
i18n.languages = [];
|
|
146
|
+
expect(getAcceptLanguage()).toBe("en");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("returns single language code", () => {
|
|
150
|
+
i18n.languages = ["de"];
|
|
151
|
+
expect(getAcceptLanguage()).toBe("de");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("joins multiple language codes with comma", () => {
|
|
155
|
+
i18n.languages = ["de-DE", "fr-FR"];
|
|
156
|
+
expect(getAcceptLanguage()).toBe("de-DE, fr-FR");
|
|
157
|
+
});
|
|
127
158
|
});
|
package/src/utils/url.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AxiosRequestConfig } from "axios";
|
|
2
2
|
import { IS_PROD, VITE_API_KEY, VITE_API_SERVER } from "config";
|
|
3
|
+
import i18n from "i18n";
|
|
3
4
|
import slug from "slug";
|
|
4
5
|
|
|
5
6
|
interface makeUrlInterface {
|
|
@@ -50,8 +51,10 @@ export function makeUrl(path: string, params?: makeUrlInterface) {
|
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
export enum WgerLink {
|
|
54
|
+
// Dashboard
|
|
53
55
|
DASHBOARD,
|
|
54
56
|
|
|
57
|
+
// Routines
|
|
55
58
|
ROUTINE_OVERVIEW,
|
|
56
59
|
ROUTINE_DETAIL,
|
|
57
60
|
ROUTINE_EDIT,
|
|
@@ -70,16 +73,20 @@ export enum WgerLink {
|
|
|
70
73
|
PRIVATE_TEMPLATE_OVERVIEW,
|
|
71
74
|
PUBLIC_TEMPLATE_OVERVIEW,
|
|
72
75
|
|
|
76
|
+
// Exercises
|
|
73
77
|
EXERCISE_DETAIL,
|
|
74
78
|
EXERCISE_OVERVIEW,
|
|
75
79
|
EXERCISE_CONTRIBUTE,
|
|
76
80
|
|
|
81
|
+
// Body weight
|
|
77
82
|
WEIGHT_OVERVIEW,
|
|
78
83
|
WEIGHT_ADD,
|
|
79
84
|
|
|
85
|
+
// Measurements
|
|
80
86
|
MEASUREMENT_OVERVIEW,
|
|
81
87
|
MEASUREMENT_DETAIL,
|
|
82
88
|
|
|
89
|
+
// Nutrition
|
|
83
90
|
NUTRITION_OVERVIEW,
|
|
84
91
|
NUTRITION_DETAIL,
|
|
85
92
|
NUTRITION_PLAN_PDF,
|
|
@@ -88,7 +95,9 @@ export enum WgerLink {
|
|
|
88
95
|
|
|
89
96
|
INGREDIENT_DETAIL,
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
// Other
|
|
99
|
+
CALENDAR,
|
|
100
|
+
TROPHIES,
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
type UrlParams = { id: number, id2?: number, slug?: string, date?: string };
|
|
@@ -182,6 +191,9 @@ export function makeLink(link: WgerLink, language?: string, params?: UrlParams):
|
|
|
182
191
|
case WgerLink.INGREDIENT_DETAIL:
|
|
183
192
|
return `/${language}/nutrition/ingredient/${params!.id}/view`;
|
|
184
193
|
|
|
194
|
+
case WgerLink.TROPHIES:
|
|
195
|
+
return `/${language}/trophies`;
|
|
196
|
+
|
|
185
197
|
// Dashboard
|
|
186
198
|
case WgerLink.DASHBOARD:
|
|
187
199
|
default:
|
|
@@ -222,7 +234,7 @@ export function makeHeader(token?: string) {
|
|
|
222
234
|
|
|
223
235
|
const out: AxiosRequestConfig['headers'] = {};
|
|
224
236
|
out['Content-Type'] = 'application/json';
|
|
225
|
-
|
|
237
|
+
out['Accept-Language'] = getAcceptLanguage();
|
|
226
238
|
if (token) {
|
|
227
239
|
out['Authorization'] = `Token ${token}`;
|
|
228
240
|
}
|
|
@@ -231,7 +243,16 @@ export function makeHeader(token?: string) {
|
|
|
231
243
|
if (IS_PROD && csrfCookie != undefined) {
|
|
232
244
|
out['X-CSRFToken'] = csrfCookie;
|
|
233
245
|
}
|
|
234
|
-
|
|
235
246
|
return out;
|
|
236
247
|
}
|
|
237
248
|
|
|
249
|
+
export function getAcceptLanguage(): string {
|
|
250
|
+
const languages = i18n.languages || [];
|
|
251
|
+
if (languages.length === 0) {
|
|
252
|
+
return 'en';
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return languages.map((language) => {
|
|
256
|
+
return language;
|
|
257
|
+
}).join(', ');
|
|
258
|
+
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
.carousel {
|
|
2
|
-
overflow: hidden;
|
|
3
|
-
margin: 2rem 0;
|
|
4
|
-
}
|
|
5
|
-
@media screen and (min-width: 700px) {
|
|
6
|
-
.carousel {
|
|
7
|
-
display: none;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
.carousel .inner {
|
|
11
|
-
white-space: nowrap;
|
|
12
|
-
transition: transform 0.3s;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.carousel_item {
|
|
16
|
-
display: inline-flex;
|
|
17
|
-
align-items: center;
|
|
18
|
-
justify-content: center;
|
|
19
|
-
height: 200px;
|
|
20
|
-
background-color: #7795bd;
|
|
21
|
-
color: #fff;
|
|
22
|
-
border-radius: 10px;
|
|
23
|
-
}
|
|
24
|
-
.indicators {
|
|
25
|
-
display: flex;
|
|
26
|
-
justify-content: center;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.indicators > button {
|
|
30
|
-
margin: 5px;
|
|
31
|
-
border: none;
|
|
32
|
-
background-color: #2a4c7d;
|
|
33
|
-
color: #fff;
|
|
34
|
-
border-radius: 50%;
|
|
35
|
-
cursor: pointer;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.indicators > button.active {
|
|
39
|
-
background-color: green;
|
|
40
|
-
color: #fff;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/*# sourceMappingURL=carousel.module.css.map */
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sourceRoot":"","sources":["carousel.module.scss"],"names":[],"mappings":"AAAA;EACI;EACA;;AAEA;EAJJ;IAKQ;;;AAGJ;EACI;EACA;;;AAIN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAOF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA","file":"carousel.module.css"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
.carousel {
|
|
2
|
-
overflow: hidden;
|
|
3
|
-
margin: 2rem 0;
|
|
4
|
-
|
|
5
|
-
@media screen and (min-width: 700px) {
|
|
6
|
-
display: none;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.inner {
|
|
10
|
-
white-space: nowrap;
|
|
11
|
-
transition: transform 0.3s;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.carousel_item {
|
|
16
|
-
display: inline-flex;
|
|
17
|
-
align-items: center;
|
|
18
|
-
justify-content: center;
|
|
19
|
-
height: 200px;
|
|
20
|
-
background-color: rgb(119, 149, 189);
|
|
21
|
-
color: #fff;
|
|
22
|
-
border-radius: 10px;
|
|
23
|
-
|
|
24
|
-
img {
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.indicators {
|
|
30
|
-
display: flex;
|
|
31
|
-
justify-content: center;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.indicators > button {
|
|
35
|
-
margin: 5px;
|
|
36
|
-
border: none;
|
|
37
|
-
background-color: #2a4c7d;
|
|
38
|
-
color: #fff;
|
|
39
|
-
border-radius: 50%;
|
|
40
|
-
cursor: pointer;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.indicators > button.active {
|
|
44
|
-
background-color: green;
|
|
45
|
-
color: #fff;
|
|
46
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import styles from './carousel.module.css';
|
|
3
|
-
|
|
4
|
-
export interface CarouselItemProps {
|
|
5
|
-
children: React.ReactNode;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export const CarouselItem = ({ children }: CarouselItemProps) => {
|
|
9
|
-
return (
|
|
10
|
-
<div className={styles.carousel_item}>
|
|
11
|
-
{children}
|
|
12
|
-
</div>
|
|
13
|
-
);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export interface CarouselProps {
|
|
17
|
-
children: React.ReactNode | React.ReactNode[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const Carousel: React.FC<CarouselProps> = ({ children }: CarouselProps) => {
|
|
21
|
-
const [activeIndex, setActiveIndex] = useState(0);
|
|
22
|
-
|
|
23
|
-
const updateIndex = (newIndex: number) => {
|
|
24
|
-
if (newIndex < 0) {
|
|
25
|
-
newIndex = React.Children.count(children) - 1;
|
|
26
|
-
|
|
27
|
-
} else if (newIndex >= React.Children.count(children)) {
|
|
28
|
-
newIndex = 0;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
setActiveIndex(newIndex);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<div className={styles.carousel}>
|
|
40
|
-
<div
|
|
41
|
-
className={styles.inner}
|
|
42
|
-
style={{ transform: `translateX(-${activeIndex * 100}%)` }}
|
|
43
|
-
>
|
|
44
|
-
{React.Children.map(children, (child) => {
|
|
45
|
-
if (React.isValidElement(child)) {
|
|
46
|
-
return React.cloneElement(child);
|
|
47
|
-
}
|
|
48
|
-
})}
|
|
49
|
-
</div>
|
|
50
|
-
<div className={styles.indicators}>
|
|
51
|
-
{React.Children.map(children, (child, index) => {
|
|
52
|
-
return (
|
|
53
|
-
<button
|
|
54
|
-
className={`${index === activeIndex ? "active" : ""}`}
|
|
55
|
-
onClick={() => {
|
|
56
|
-
updateIndex(index);
|
|
57
|
-
}}
|
|
58
|
-
>
|
|
59
|
-
{index + 1}
|
|
60
|
-
</button>
|
|
61
|
-
);
|
|
62
|
-
})}
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
|
-
};
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import TrendingUpIcon from "@mui/icons-material/TrendingUp";
|
|
2
|
-
import { Button, IconButton, List, ListItem, ListItemText, Typography } from "@mui/material";
|
|
3
|
-
import Tooltip from "@mui/material/Tooltip";
|
|
4
|
-
import { DashboardCard } from "components/Dashboard/DashboardCard";
|
|
5
|
-
import React from "react";
|
|
6
|
-
// import { useTranslation } from "react-i18next";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Example of a new widget using DashboardCard
|
|
10
|
-
*
|
|
11
|
-
* This demonstrates how simple it is to create a new dashboard widget.
|
|
12
|
-
* All the responsive layout logic is handled by DashboardCard!
|
|
13
|
-
*/
|
|
14
|
-
export const GoalsCard = () => {
|
|
15
|
-
// const { t } = useTranslation();
|
|
16
|
-
|
|
17
|
-
// Your data fetching logic here
|
|
18
|
-
const goals = [
|
|
19
|
-
{ id: 1, title: "Lose 5kg", progress: 60 },
|
|
20
|
-
{ id: 2, title: "Run 5km", progress: 80 },
|
|
21
|
-
{ id: 3, title: "Bench 100kg", progress: 45 },
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<DashboardCard
|
|
26
|
-
title="My Goals"
|
|
27
|
-
subheader="Track your fitness goals"
|
|
28
|
-
// Optional header action (top-right icon)
|
|
29
|
-
headerAction={
|
|
30
|
-
<Tooltip title="View trends">
|
|
31
|
-
<IconButton>
|
|
32
|
-
<TrendingUpIcon />
|
|
33
|
-
</IconButton>
|
|
34
|
-
</Tooltip>
|
|
35
|
-
}
|
|
36
|
-
// Actions at the bottom of the card
|
|
37
|
-
actions={
|
|
38
|
-
<>
|
|
39
|
-
<Button size="small">See All Goals</Button>
|
|
40
|
-
<Button size="small" variant="contained">
|
|
41
|
-
Add Goal
|
|
42
|
-
</Button>
|
|
43
|
-
</>
|
|
44
|
-
}
|
|
45
|
-
>
|
|
46
|
-
{/* Your card content goes here */}
|
|
47
|
-
<List>
|
|
48
|
-
{goals.map((goal) => (
|
|
49
|
-
<ListItem key={goal.id}>
|
|
50
|
-
<ListItemText
|
|
51
|
-
primary={goal.title}
|
|
52
|
-
secondary={
|
|
53
|
-
<Typography variant="body2" color="text.secondary">
|
|
54
|
-
Progress: {goal.progress}%
|
|
55
|
-
</Typography>
|
|
56
|
-
}
|
|
57
|
-
/>
|
|
58
|
-
</ListItem>
|
|
59
|
-
))}
|
|
60
|
-
</List>
|
|
61
|
-
</DashboardCard>
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// To add this widget to the dashboard, just add it to AVAILABLE_WIDGETS in ConfigurableDashboard.tsx:
|
|
66
|
-
// {
|
|
67
|
-
// id: 'goals',
|
|
68
|
-
// type: 'goals',
|
|
69
|
-
// component: GoalsCard,
|
|
70
|
-
// defaultLayout: { w: 4, h: 6, x: 0, y: 6, minW: 3, minH: 4 },
|
|
71
|
-
// }
|