Skip to content

Commit 86028c3

Browse files
committed
feat: Language selection
1 parent 9cdbd07 commit 86028c3

File tree

16 files changed

+221
-27
lines changed

16 files changed

+221
-27
lines changed

client/public/static/i18n/en/common.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"home": "Home",
33
"account": "Account",
44
"userList": "User list",
5-
"Examples": "Examples",
5+
"examples": "Examples",
66
"giveAdminRights": "Give admin rights",
77
"cancel": "Cancel",
88
"save": "Save",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"users": "Users",
3+
"stat2": "Stat 2",
4+
"stat3": "Stat 3"
5+
}

client/public/static/i18n/en/user.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,8 @@
1111
"password": "Password",
1212
"passwordConfirm": "Confirm Password",
1313
"giveAdminRights": "Give admin rights",
14-
"newUserAdded": "New user added"
14+
"newUserAdded": "New user added",
15+
"lang": "Language",
16+
"fr": "French",
17+
"en": "English"
1518
}

client/public/static/i18n/fr/common.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"home": "Accueil",
33
"account": "Compte",
44
"userList": "Utilisateurs",
5-
"Examples": "Exemples",
5+
"examples": "Exemples",
66
"giveAdminRights": "Donner les droits admin",
77
"cancel": "Annuler",
88
"save": "Sauvegarder",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"users": "Utilisateurs",
3+
"stat2": "Stat 2",
4+
"stat3": "Stat 3"
5+
}

client/public/static/i18n/fr/user.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
"email": "Email",
99
"phone": "Téléphone",
1010
"password": "Mot de passe",
11-
"passwordConfirm": "Confirmer le mot de passe",
11+
"passwordConfirm": "Confirmer le mot de passe",
1212
"giveAdminRights": "Donner les droits d'administrateur",
13-
"newUserAdded": "Nouvel utilisateur ajouté"
14-
}
13+
"newUserAdded": "Nouvel utilisateur ajouté",
14+
"lang": "Langue",
15+
"fr": "Français",
16+
"en": "Anglais"
17+
}

client/src/api/HomeRoutes.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Fetch from '../utils/fetcher';
2+
3+
const HomeRoutes = {
4+
stats: () => Fetch<{ users: number, stat2: number, stat3: number }>('/api/home/stats'),
5+
};
6+
7+
export default HomeRoutes;

client/src/components/forms/UserForm.tsx

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
import { Prisma } from '@fullstack-typescript-monorepo/prisma';
1+
import { DEFAULT_LANGUAGE, Language } from '@fullstack-typescript-monorepo/core';
2+
import { Lang } from '@fullstack-typescript-monorepo/prisma';
23
import { LoadingButton } from '@mui/lab';
3-
import { Box, Checkbox, Divider, FormControlLabel, Grid, TextField } from '@mui/material';
4+
import { Box, Checkbox, Divider, FormControl, FormControlLabel, Grid, InputLabel, MenuItem, Select, TextField } from '@mui/material';
45
import React from 'react';
56
import { useTranslation } from 'react-i18next';
67
import { useNavigate } from 'react-router';
78
import UserRoutes from '../../api/UserRoutes';
89
import { useAlert } from '../../hooks/useAlert';
10+
import { useAuth } from '../../hooks/useAuth';
911
import useForm from '../../hooks/useForm';
1012
import { useLoader } from '../../hooks/useLoader';
1113
import catchError from '../../utils/catchError';
1214

1315
interface Data {
1416
id?: number;
1517
admin: boolean;
18+
lang: Language;
1619
login: string;
1720
password: string;
1821
idperson?: number;
@@ -32,15 +35,17 @@ const UserForm = ({ data }: Props) => {
3235
const Loader = useLoader();
3336
const { t } = useTranslation('user');
3437
const navigate = useNavigate();
38+
const { user, updateData } = useAuth();
3539

3640
const { register, handleSubmit, formState: { isSubmitting }, reset } = useForm<Data>('user', {
3741
defaultValues: data,
3842
});
3943

4044
// Submit user data
4145
const onSubmit = async (formData: Data) => {
42-
const processedData: Prisma.UserUpdateInput = {
46+
const processedData = {
4347
admin: formData.admin,
48+
lang: formData.lang,
4449
login: formData.login,
4550
active: true,
4651
};
@@ -64,13 +69,25 @@ const UserForm = ({ data }: Props) => {
6469
update: personData,
6570
},
6671
}).then(() => {
72+
// Update user data if it's the current user
73+
if (user.id === formData.id) {
74+
updateData((prev) => ({
75+
...prev,
76+
...processedData,
77+
person: {
78+
...prev.person,
79+
...personData,
80+
},
81+
}));
82+
}
83+
6784
Alert.open('success', t('common:saved'));
6885
}).catch(catchError(Alert));
6986
Loader.close();
7087
} else { // Addition
71-
processedData.password = formData.password;
7288
await UserRoutes.insert({
7389
...processedData,
90+
password: formData.password,
7491
connexionToken: '',
7592
person: {
7693
create: personData,
@@ -87,12 +104,22 @@ const UserForm = ({ data }: Props) => {
87104
return (
88105
<form autoComplete="off" onSubmit={handleSubmit(onSubmit)}>
89106
<Grid container spacing={3} sx={{ pb: 2 }}>
90-
<Grid item xs={12}>
107+
<Grid item xs={12} sm={6}>
91108
<FormControlLabel
92109
control={<Checkbox {...register('admin', 'checkbox')} defaultChecked={data.admin} />}
93110
label={t('giveAdminRights')}
94111
/>
95112
</Grid>
113+
<Grid item xs={12} sm={6}>
114+
<FormControl fullWidth>
115+
<InputLabel>{t('lang')}</InputLabel>
116+
<Select {...register('lang', 'select', { required: true })} defaultValue={data.lang || DEFAULT_LANGUAGE}>
117+
{Object.keys(Lang).map((lang) => (
118+
<MenuItem key={lang} value={lang}>{t(lang)}</MenuItem>
119+
))}
120+
</Select>
121+
</FormControl>
122+
</Grid>
96123
<Grid item md={6} xs={12}>
97124
<TextField {...register('login', 'text', { required: true })} fullWidth />
98125
</Grid>

client/src/hooks/useAuth.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { DEFAULT_LANGUAGE } from '@fullstack-typescript-monorepo/core';
2-
import React, { useCallback, useContext, useMemo, useState } from 'react';
2+
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
33
import UserRoutes, { UserWithPerson } from '../api/UserRoutes';
4+
import { useLanguage } from './useLanguage';
45

56
interface AuthContextInterface {
67
user: UserWithPerson,
78
authed: boolean,
89
signin: (login: string, password: string) => Promise<UserWithPerson | null>,
910
signout: () => void,
10-
updateData: (data: UserWithPerson) => void,
11+
updateData: (data: React.SetStateAction<UserWithPerson>) => void,
1112
}
1213

1314
export const emptyUser: UserWithPerson = {
@@ -51,15 +52,22 @@ interface AuthProviderProps {
5152
}
5253

5354
export const AuthProvider = ({ children }: AuthProviderProps) => {
55+
const { setLanguage } = useLanguage();
5456
const [user, setUser] = useState<UserWithPerson>(emptyUser);
5557
const [authed, setAuthed] = useState(false);
5658

59+
// Update language when necessary
60+
useEffect(() => {
61+
setLanguage(user.lang);
62+
}, [user.lang, setLanguage]);
63+
5764
const signin = useCallback((
5865
login: string,
5966
password: string,
6067
) => UserRoutes.authenticate(login, password).then((response) => {
6168
localStorage.setItem('user', response.login);
6269
localStorage.setItem('token', response.connexionToken);
70+
6371
setUser(response);
6472
if (response) setAuthed(true);
6573
return response;
@@ -72,7 +80,7 @@ export const AuthProvider = ({ children }: AuthProviderProps) => {
7280
setUser(emptyUser);
7381
}, []);
7482

75-
const updateData = useCallback((data: UserWithPerson) => {
83+
const updateData = useCallback((data: React.SetStateAction<UserWithPerson>) => {
7684
setUser(data);
7785
}, []);
7886

client/src/layouts/DashboardLayout/NavBar/NavBar.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,22 @@ const NavBar = ({ onMobileClose, openMobile }: Props) => {
5151
{
5252
href: '/app/todo',
5353
icon: Quiz,
54-
title: t('TODO'),
54+
title: t('TODO 1'),
5555
},
5656
{
5757
href: '/app/todo',
5858
icon: Quiz,
59-
title: t('TODO'),
59+
title: t('TODO 2'),
6060
},
6161
{
6262
href: '/app/todo',
6363
icon: Quiz,
64-
title: t('TODO'),
64+
title: t('TODO 3'),
6565
},
6666
{
6767
href: '/app/todo',
6868
icon: Quiz,
69-
title: t('TODO'),
69+
title: t('TODO 4'),
7070
},
7171
],
7272
},

0 commit comments

Comments
 (0)