2024-07-28 03:09:52 +02:00

244 lines
7.8 KiB
TypeScript

import { Done } from '@mui/icons-material';
import {
Button,
CircularProgress,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Grid,
TextField,
Typography,
useMediaQuery,
useTheme,
} from '@mui/material';
import { useForm } from '@tanstack/react-form';
import { useMutation } from '@tanstack/react-query';
import { FC, FormEvent, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Api from '../../../api/Api';
import { UserCreate } from '../../../types/User';
import ErrorComponent from '../../Error/ErrorComponent';
interface Props {
open: boolean;
onClose: () => void;
}
const RegisterDialog: FC<Props> = ({ open, onClose }) => {
//eslint-disable-next-line @typescript-eslint/no-explicit-any
const [error, setError] = useState<any>();
const createMutation = useMutation({
mutationFn: ({ data }: { data: UserCreate }) => {
return Api.createUser(data);
},
});
const { t } = useTranslation();
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.only('xs'), { noSsr: true });
const form = useForm<UserCreate>({
defaultValues: {
username: '',
email: '',
password: '',
},
onSubmit: async ({ value }) => {
try {
createMutation.mutate(
{ data: value },
{
onSuccess: () => setError(undefined),
onError: setError,
}
);
//eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
setError(error);
}
},
});
const handleClose = () => {
form.reset();
setError(undefined);
onClose();
};
if (createMutation.isSuccess)
return (
<Dialog open={open} onClose={handleClose} fullWidth fullScreen={fullScreen}>
<DialogContent>
<Grid container spacing={2}>
<Grid item xs={12} sx={{ display: 'flex', justifyContent: 'center' }}>
<Done color="action" sx={{ fontSize: '200px' }} />
</Grid>
<Grid item xs={12} sx={{ display: 'flex', justifyContent: 'center' }}>
<Typography variant="h5">{t('Confirm header')}</Typography>
</Grid>
<Grid item xs={12} sx={{ display: 'flex', justifyContent: 'center' }}>
<Typography>{t('Confirm mail')}</Typography>
</Grid>
</Grid>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>{t('Close')}</Button>
</DialogActions>
</Dialog>
);
return (
<Dialog
open={open}
onClose={handleClose}
fullWidth
fullScreen={fullScreen}
PaperProps={{
component: 'form',
encType: 'multipart/form-data',
onSubmit: (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
e.stopPropagation();
form.handleSubmit();
},
onKeyDown: (event: React.KeyboardEvent<HTMLFormElement>) => {
if (event.key === 'Tab') {
event.stopPropagation();
}
},
noValidate: true,
}}
>
<DialogTitle>{t('Register')}</DialogTitle>
<DialogContent sx={{ gap: 2 }}>
<Grid container spacing={2}>
<Grid item xs={12}>
<form.Field
name="username"
validators={{
onChange: ({ value }) => (!value ? t('Username required') : undefined),
onChangeAsyncDebounceMs: 250,
onChangeAsync: async ({ value }) => {
return !value && t('Username required');
},
}}
children={(field) => {
return (
<>
<TextField
variant="outlined"
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
size="small"
label={t('Username')}
required
error={field.state.meta.isTouched && field.state.meta.errors.length > 0}
helperText={field.state.meta.isTouched ? field.state.meta.errors.join(',') : ''}
autoComplete="new-username"
fullWidth
margin="dense"
/>
</>
);
}}
/>
</Grid>
<Grid item xs={12}>
<form.Field
name="email"
validators={{
onChange: ({ value }) => (!value ? t('Email required') : undefined),
onChangeAsyncDebounceMs: 250,
onChangeAsync: async ({ value }) => {
return !value && t('Email required');
},
}}
children={(field) => {
return (
<>
<TextField
variant="outlined"
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
size="small"
label={t('Email')}
required
error={field.state.meta.isTouched && field.state.meta.errors.length > 0}
helperText={field.state.meta.isTouched ? field.state.meta.errors.join(',') : ''}
type="email"
autoComplete="new-email"
inputMode="email"
fullWidth
/>
</>
);
}}
/>
</Grid>
<Grid item xs={12}>
<form.Field
name="password"
validators={{
onChange: ({ value }) => (!value ? t('Password required') : undefined),
onChangeAsyncDebounceMs: 250,
onChangeAsync: async ({ value }) => {
return !value && t('Password required');
},
}}
children={(field) => {
return (
<>
<TextField
variant="outlined"
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
size="small"
label={t('Password')}
required
error={field.state.meta.isTouched && field.state.meta.errors.length > 0}
helperText={field.state.meta.isTouched ? field.state.meta.errors.join(',') : ''}
type="password"
autoComplete="new-password"
fullWidth
/>
</>
);
}}
/>
</Grid>
<Grid item xs={12}>
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
children={([canSubmit]) => (
<>
<Button
type="submit"
disabled={!canSubmit || createMutation.isPending}
variant="contained"
endIcon={createMutation.isPending && <CircularProgress color="inherit" size="20px" />}
>
{t('Register')}
</Button>
</>
)}
/>
</Grid>
<Grid item xs={12}>
{error && <ErrorComponent error={error} context="register" />}
</Grid>
</Grid>
</DialogContent>
</Dialog>
);
};
export default RegisterDialog;