mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
added LanguageSelector
This commit is contained in:
@@ -1,30 +1,22 @@
|
|||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import type { ChangeEventHandler, FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import ForwardIcon from '@mui/icons-material/Forward';
|
import ForwardIcon from '@mui/icons-material/Forward';
|
||||||
import { Box, Button, MenuItem, Paper, TextField, Typography } from '@mui/material';
|
import { Box, Button, Paper, Typography } from '@mui/material';
|
||||||
|
|
||||||
import * as AuthenticationApi from 'api/authentication';
|
import * as AuthenticationApi from 'api/authentication';
|
||||||
import { PROJECT_NAME } from 'api/env';
|
import { PROJECT_NAME } from 'api/env';
|
||||||
|
|
||||||
import { useRequest } from 'alova';
|
import { useRequest } from 'alova';
|
||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import { ValidatedPasswordField, ValidatedTextField } from 'components';
|
import {
|
||||||
|
LanguageSelector,
|
||||||
|
ValidatedPasswordField,
|
||||||
|
ValidatedTextField
|
||||||
|
} from 'components';
|
||||||
import { AuthenticationContext } from 'contexts/authentication';
|
import { AuthenticationContext } from 'contexts/authentication';
|
||||||
import DEflag from 'i18n/DE.svg';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import FRflag from 'i18n/FR.svg';
|
|
||||||
import GBflag from 'i18n/GB.svg';
|
|
||||||
import ITflag from 'i18n/IT.svg';
|
|
||||||
import NLflag from 'i18n/NL.svg';
|
|
||||||
import NOflag from 'i18n/NO.svg';
|
|
||||||
import PLflag from 'i18n/PL.svg';
|
|
||||||
import SKflag from 'i18n/SK.svg';
|
|
||||||
import SVflag from 'i18n/SV.svg';
|
|
||||||
import TRflag from 'i18n/TR.svg';
|
|
||||||
import { I18nContext } from 'i18n/i18n-react';
|
|
||||||
import type { Locales } from 'i18n/i18n-types';
|
|
||||||
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
|
||||||
import type { SignInRequest } from 'types';
|
import type { SignInRequest } from 'types';
|
||||||
import { onEnterCallback, updateValue } from 'utils';
|
import { onEnterCallback, updateValue } from 'utils';
|
||||||
import { SIGN_IN_REQUEST_VALIDATOR, validate } from 'validators';
|
import { SIGN_IN_REQUEST_VALIDATOR, validate } from 'validators';
|
||||||
@@ -32,7 +24,7 @@ import { SIGN_IN_REQUEST_VALIDATOR, validate } from 'validators';
|
|||||||
const SignIn: FC = () => {
|
const SignIn: FC = () => {
|
||||||
const authenticationContext = useContext(AuthenticationContext);
|
const authenticationContext = useContext(AuthenticationContext);
|
||||||
|
|
||||||
const { LL, setLocale, locale } = useContext(I18nContext);
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const [signInRequest, setSignInRequest] = useState<SignInRequest>({
|
const [signInRequest, setSignInRequest] = useState<SignInRequest>({
|
||||||
username: '',
|
username: '',
|
||||||
@@ -83,15 +75,6 @@ const SignIn: FC = () => {
|
|||||||
|
|
||||||
const submitOnEnter = onEnterCallback(signIn);
|
const submitOnEnter = onEnterCallback(signIn);
|
||||||
|
|
||||||
const onLocaleSelected: ChangeEventHandler<HTMLInputElement> = async ({
|
|
||||||
target
|
|
||||||
}) => {
|
|
||||||
const loc = target.value as Locales;
|
|
||||||
localStorage.setItem('lang', loc);
|
|
||||||
await loadLocaleAsync(loc);
|
|
||||||
setLocale(loc);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
display="flex"
|
||||||
@@ -115,55 +98,7 @@ const SignIn: FC = () => {
|
|||||||
>
|
>
|
||||||
<Typography variant="h4">{PROJECT_NAME}</Typography>
|
<Typography variant="h4">{PROJECT_NAME}</Typography>
|
||||||
|
|
||||||
<TextField
|
<LanguageSelector />
|
||||||
name="locale"
|
|
||||||
variant="outlined"
|
|
||||||
value={locale}
|
|
||||||
onChange={onLocaleSelected}
|
|
||||||
size="small"
|
|
||||||
select
|
|
||||||
>
|
|
||||||
<MenuItem key="de" value="de">
|
|
||||||
<img src={DEflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
DE
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="en" value="en">
|
|
||||||
<img src={GBflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
EN
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="fr" value="fr">
|
|
||||||
<img src={FRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
FR
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="it" value="it">
|
|
||||||
<img src={ITflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
IT
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="nl" value="nl">
|
|
||||||
<img src={NLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
NL
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="no" value="no">
|
|
||||||
<img src={NOflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
NO
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="pl" value="pl">
|
|
||||||
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
PL
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="sk" value="sk">
|
|
||||||
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
SK
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="sv" value="sv">
|
|
||||||
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
SV
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="tr" value="tr">
|
|
||||||
<img src={TRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
TR
|
|
||||||
</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
|
|
||||||
<Box display="flex" flexDirection="column" alignItems="center">
|
<Box display="flex" flexDirection="column" alignItems="center">
|
||||||
<ValidatedTextField
|
<ValidatedTextField
|
||||||
|
|||||||
84
interface/src/components/inputs/LanguageSelector.tsx
Normal file
84
interface/src/components/inputs/LanguageSelector.tsx
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import { type ChangeEventHandler, type FC, useContext } from 'react';
|
||||||
|
|
||||||
|
import { MenuItem, TextField } from '@mui/material';
|
||||||
|
|
||||||
|
import DEflag from 'i18n/DE.svg';
|
||||||
|
import FRflag from 'i18n/FR.svg';
|
||||||
|
import GBflag from 'i18n/GB.svg';
|
||||||
|
import ITflag from 'i18n/IT.svg';
|
||||||
|
import NLflag from 'i18n/NL.svg';
|
||||||
|
import NOflag from 'i18n/NO.svg';
|
||||||
|
import PLflag from 'i18n/PL.svg';
|
||||||
|
import SKflag from 'i18n/SK.svg';
|
||||||
|
import SVflag from 'i18n/SV.svg';
|
||||||
|
import TRflag from 'i18n/TR.svg';
|
||||||
|
import { I18nContext } from 'i18n/i18n-react';
|
||||||
|
import type { Locales } from 'i18n/i18n-types';
|
||||||
|
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
||||||
|
|
||||||
|
const LanguageSelector: FC = () => {
|
||||||
|
const { setLocale, locale } = useContext(I18nContext);
|
||||||
|
|
||||||
|
const onLocaleSelected: ChangeEventHandler<HTMLInputElement> = async ({
|
||||||
|
target
|
||||||
|
}) => {
|
||||||
|
const loc = target.value as Locales;
|
||||||
|
localStorage.setItem('lang', loc);
|
||||||
|
await loadLocaleAsync(loc);
|
||||||
|
setLocale(loc);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
name="locale"
|
||||||
|
variant="outlined"
|
||||||
|
value={locale}
|
||||||
|
onChange={onLocaleSelected}
|
||||||
|
size="small"
|
||||||
|
select
|
||||||
|
>
|
||||||
|
<MenuItem key="de" value="de">
|
||||||
|
<img src={DEflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
DE
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="en" value="en">
|
||||||
|
<img src={GBflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
EN
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="fr" value="fr">
|
||||||
|
<img src={FRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
FR
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="it" value="it">
|
||||||
|
<img src={ITflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
IT
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="nl" value="nl">
|
||||||
|
<img src={NLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
NL
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="no" value="no">
|
||||||
|
<img src={NOflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
NO
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="pl" value="pl">
|
||||||
|
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
PL
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="sk" value="sk">
|
||||||
|
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
SK
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="sv" value="sv">
|
||||||
|
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
SV
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="tr" value="tr">
|
||||||
|
<img src={TRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
||||||
|
TR
|
||||||
|
</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LanguageSelector;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export { default as BlockFormControlLabel } from './BlockFormControlLabel';
|
export { default as BlockFormControlLabel } from './BlockFormControlLabel';
|
||||||
export { default as ValidatedPasswordField } from './ValidatedPasswordField';
|
export { default as ValidatedPasswordField } from './ValidatedPasswordField';
|
||||||
export { default as ValidatedTextField } from './ValidatedTextField';
|
export { default as ValidatedTextField } from './ValidatedTextField';
|
||||||
|
export { default as LanguageSelector } from './LanguageSelector';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import type { ChangeEventHandler, FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
||||||
import AssessmentIcon from '@mui/icons-material/Assessment';
|
import AssessmentIcon from '@mui/icons-material/Assessment';
|
||||||
@@ -22,30 +22,17 @@ import {
|
|||||||
ListItemButton,
|
ListItemButton,
|
||||||
ListItemIcon,
|
ListItemIcon,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
MenuItem,
|
Popover
|
||||||
Popover,
|
|
||||||
TextField
|
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import { LanguageSelector } from 'components/inputs';
|
||||||
import LayoutMenuItem from 'components/layout/LayoutMenuItem';
|
import LayoutMenuItem from 'components/layout/LayoutMenuItem';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import DEflag from 'i18n/DE.svg';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import FRflag from 'i18n/FR.svg';
|
|
||||||
import GBflag from 'i18n/GB.svg';
|
|
||||||
import ITflag from 'i18n/IT.svg';
|
|
||||||
import NLflag from 'i18n/NL.svg';
|
|
||||||
import NOflag from 'i18n/NO.svg';
|
|
||||||
import PLflag from 'i18n/PL.svg';
|
|
||||||
import SKflag from 'i18n/SK.svg';
|
|
||||||
import SVflag from 'i18n/SV.svg';
|
|
||||||
import TRflag from 'i18n/TR.svg';
|
|
||||||
import { I18nContext } from 'i18n/i18n-react';
|
|
||||||
import type { Locales } from 'i18n/i18n-types';
|
|
||||||
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
|
||||||
|
|
||||||
const LayoutMenu: FC = () => {
|
const LayoutMenu: FC = () => {
|
||||||
const { me, signOut } = useContext(AuthenticatedContext);
|
const { me, signOut } = useContext(AuthenticatedContext);
|
||||||
const { locale, LL, setLocale } = useContext(I18nContext);
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
@@ -54,15 +41,6 @@ const LayoutMenu: FC = () => {
|
|||||||
|
|
||||||
const [menuOpen, setMenuOpen] = useState(true);
|
const [menuOpen, setMenuOpen] = useState(true);
|
||||||
|
|
||||||
const onLocaleSelected: ChangeEventHandler<HTMLInputElement> = async ({
|
|
||||||
target
|
|
||||||
}) => {
|
|
||||||
const loc = target.value as Locales;
|
|
||||||
localStorage.setItem('lang', loc);
|
|
||||||
await loadLocaleAsync(loc);
|
|
||||||
setLocale(loc);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget);
|
||||||
};
|
};
|
||||||
@@ -94,7 +72,7 @@ const LayoutMenu: FC = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={LL.MODULE()}
|
primary={LL.MODULES()}
|
||||||
primaryTypographyProps={{
|
primaryTypographyProps={{
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
mb: '2px',
|
mb: '2px',
|
||||||
@@ -173,7 +151,7 @@ const LayoutMenu: FC = () => {
|
|||||||
|
|
||||||
<Popover
|
<Popover
|
||||||
id={id}
|
id={id}
|
||||||
sx={{ mt: 1 }}
|
// sx={{ mb: 10 }}
|
||||||
open={open}
|
open={open}
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
@@ -187,77 +165,14 @@ const LayoutMenu: FC = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
p={2}
|
padding={2}
|
||||||
|
justifyContent="center"
|
||||||
|
flexDirection="column"
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: 2,
|
borderRadius: 3,
|
||||||
border: '2px solid grey'
|
border: '3px solid grey'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<List>
|
|
||||||
<ListItem disablePadding>
|
|
||||||
<Avatar sx={{ bgcolor: '#b1395f', color: 'white' }}>
|
|
||||||
<PersonIcon />
|
|
||||||
</Avatar>
|
|
||||||
<ListItemText
|
|
||||||
sx={{ pl: 2 }}
|
|
||||||
primary={me.username}
|
|
||||||
secondary={me.admin ? LL.ADMIN() : LL.GUEST()}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
<Box p={2}>
|
|
||||||
<TextField
|
|
||||||
name="locale"
|
|
||||||
InputProps={{ style: { fontSize: 10 } }}
|
|
||||||
variant="outlined"
|
|
||||||
value={locale}
|
|
||||||
onChange={onLocaleSelected}
|
|
||||||
size="small"
|
|
||||||
select
|
|
||||||
>
|
|
||||||
<MenuItem key="de" value="de">
|
|
||||||
<img src={DEflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
DE
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="en" value="en">
|
|
||||||
<img src={GBflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
EN
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="fr" value="fr">
|
|
||||||
<img src={FRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
FR
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="it" value="it">
|
|
||||||
<img src={ITflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
IT
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="nl" value="nl">
|
|
||||||
<img src={NLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
NL
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="no" value="no">
|
|
||||||
<img src={NOflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
NO
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="pl" value="pl">
|
|
||||||
<img src={PLflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
PL
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="sk" value="sk">
|
|
||||||
<img src={SKflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
SK
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="sv" value="sv">
|
|
||||||
<img src={SVflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
SV
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem key="tr" value="tr">
|
|
||||||
<img src={TRflag} style={{ width: 16, verticalAlign: 'middle' }} />
|
|
||||||
TR
|
|
||||||
</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -266,7 +181,21 @@ const LayoutMenu: FC = () => {
|
|||||||
>
|
>
|
||||||
{LL.SIGN_OUT()}
|
{LL.SIGN_OUT()}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
<List>
|
||||||
|
<ListItem disablePadding>
|
||||||
|
<Avatar sx={{ bgcolor: '#b1395f', color: 'white' }}>
|
||||||
|
<PersonIcon />
|
||||||
|
</Avatar>
|
||||||
|
<ListItemText
|
||||||
|
sx={{ pl: 2 }}
|
||||||
|
primary={me.username}
|
||||||
|
secondary={'(' + (me.admin ? LL.ADMINISTRATOR() : LL.GUEST()) + ')'}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
{/* <Box p={2}> */}
|
||||||
|
<LanguageSelector />
|
||||||
|
{/* </Box> */}
|
||||||
</Box>
|
</Box>
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user