108 lines
3.7 KiB
TypeScript
108 lines
3.7 KiB
TypeScript
import { Link as RouterLink } from 'react-router-dom';
|
|
import Box from '@mui/material/Box';
|
|
import Typography from '@mui/material/Typography';
|
|
import TextField from '@mui/material/TextField';
|
|
import FormControlLabel from '@mui/material/FormControlLabel';
|
|
import Checkbox from '@mui/material/Checkbox';
|
|
import Divider from '@mui/material/Divider';
|
|
import GoogleIcon from '@mui/icons-material/Google';
|
|
import AppleIcon from '@mui/icons-material/Apple';
|
|
import { useForm } from 'react-hook-form';
|
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { LuxeButton } from '@/components/ui';
|
|
import { loginSchema, type LoginFormData } from '@/validators/auth';
|
|
import { ROUTES } from '@/constants';
|
|
|
|
export function LoginPage() {
|
|
const { t } = useTranslation();
|
|
const {
|
|
register,
|
|
handleSubmit,
|
|
formState: { errors, isSubmitting },
|
|
} = useForm<LoginFormData>({
|
|
resolver: zodResolver(loginSchema),
|
|
defaultValues: { rememberMe: false },
|
|
});
|
|
|
|
const onSubmit = async (_data: LoginFormData) => {
|
|
await new Promise((r) => setTimeout(r, 800));
|
|
};
|
|
|
|
return (
|
|
<Box>
|
|
<Typography variant="h4" sx={{ mb: 1, fontFamily: '"Playfair Display", serif' }}>
|
|
{t('auth.welcomeBack')}
|
|
</Typography>
|
|
<Typography variant="body2" color="text.secondary" sx={{ mb: 4 }}>
|
|
Sign in to access your dashboard and saved profiles.
|
|
</Typography>
|
|
|
|
<Box component="form" onSubmit={handleSubmit(onSubmit)} noValidate>
|
|
<TextField
|
|
{...register('email')}
|
|
label={t('auth.email')}
|
|
type="email"
|
|
fullWidth
|
|
margin="normal"
|
|
autoComplete="email"
|
|
error={!!errors.email}
|
|
helperText={errors.email?.message}
|
|
/>
|
|
<TextField
|
|
{...register('password')}
|
|
label={t('auth.password')}
|
|
type="password"
|
|
fullWidth
|
|
margin="normal"
|
|
autoComplete="current-password"
|
|
error={!!errors.password}
|
|
helperText={errors.password?.message}
|
|
/>
|
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mt: 1 }}>
|
|
<FormControlLabel
|
|
control={<Checkbox {...register('rememberMe')} size="small" />}
|
|
label={<Typography variant="body2">Remember me</Typography>}
|
|
/>
|
|
<Typography
|
|
component={RouterLink}
|
|
to={ROUTES.AUTH.FORGOT_PASSWORD}
|
|
variant="body2"
|
|
sx={{ color: 'gold.main', textDecoration: 'none' }}
|
|
>
|
|
{t('auth.forgotPassword')}
|
|
</Typography>
|
|
</Box>
|
|
|
|
<LuxeButton type="submit" variant="contained" fullWidth sx={{ mt: 3, py: 1.5 }} disabled={isSubmitting}>
|
|
{isSubmitting ? t('common.loading') : t('common.login')}
|
|
</LuxeButton>
|
|
</Box>
|
|
|
|
<Divider sx={{ my: 3 }}>
|
|
<Typography variant="caption" color="text.secondary">
|
|
{t('auth.orContinueWith')}
|
|
</Typography>
|
|
</Divider>
|
|
|
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
|
<LuxeButton variant="outlined" fullWidth startIcon={<GoogleIcon />} aria-label="Sign in with Google">
|
|
Google
|
|
</LuxeButton>
|
|
<LuxeButton variant="outlined" fullWidth startIcon={<AppleIcon />} aria-label="Sign in with Apple">
|
|
Apple
|
|
</LuxeButton>
|
|
</Box>
|
|
|
|
<Typography variant="body2" color="text.secondary" sx={{ mt: 4, textAlign: 'center' }}>
|
|
{t('auth.noAccount')}{' '}
|
|
<Typography component={RouterLink} to={ROUTES.AUTH.REGISTER} variant="body2" sx={{ color: 'gold.main', fontWeight: 600 }}>
|
|
{t('common.register')}
|
|
</Typography>
|
|
</Typography>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
export default LoginPage;
|