2024-12-04 15:35:04 +00:00
|
|
|
'use client';
|
|
|
|
import * as Yup from 'yup';
|
2024-12-08 12:05:09 +00:00
|
|
|
import { useEffect, useState } from 'react';
|
2024-12-04 15:35:04 +00:00
|
|
|
import { useMutation } from 'react-query';
|
|
|
|
import RouterLink from 'next/link';
|
|
|
|
import { useSearchParams } from 'next/navigation';
|
|
|
|
import { useRouter } from 'next-nprogress-bar';
|
|
|
|
import toast from 'react-hot-toast';
|
|
|
|
// formik
|
|
|
|
import { useFormik, Form, FormikProvider } from 'formik';
|
|
|
|
// cookies
|
|
|
|
import { createCookies } from 'src/hooks/cookies';
|
|
|
|
// redux
|
|
|
|
import { useDispatch } from 'react-redux';
|
|
|
|
import { setWishlist } from 'src/redux/slices/wishlist';
|
|
|
|
import { setLogin } from 'src/redux/slices/user';
|
|
|
|
// api
|
|
|
|
import * as api from 'src/services';
|
|
|
|
// mui
|
|
|
|
import {
|
|
|
|
Link,
|
|
|
|
Typography,
|
|
|
|
Stack,
|
|
|
|
Checkbox,
|
|
|
|
TextField,
|
|
|
|
IconButton,
|
|
|
|
InputAdornment,
|
2024-12-08 12:05:09 +00:00
|
|
|
FormControl,
|
|
|
|
FormControlLabel,
|
|
|
|
Select,
|
2025-02-24 01:47:56 +00:00
|
|
|
MenuItem,
|
|
|
|
Button
|
2024-12-04 15:35:04 +00:00
|
|
|
} from '@mui/material';
|
|
|
|
import { LoadingButton } from '@mui/lab';
|
|
|
|
// icons
|
|
|
|
import { MdOutlineVisibility, MdLock, MdOutlineVisibilityOff } from 'react-icons/md';
|
|
|
|
import { IoMdMail } from 'react-icons/io';
|
2024-12-12 19:46:38 +00:00
|
|
|
import { lang, langen, langjp } from '../lang/kr';
|
|
|
|
import getCookies from '../lang/langUtil';
|
2024-12-22 12:41:23 +00:00
|
|
|
import { Row } from '../customElements';
|
2024-12-04 15:35:04 +00:00
|
|
|
|
2024-12-08 12:05:09 +00:00
|
|
|
|
|
|
|
|
2024-12-04 15:35:04 +00:00
|
|
|
export default function LoginForm() {
|
2024-12-08 12:05:09 +00:00
|
|
|
const langIs = getCookies('lang');
|
2024-12-04 15:35:04 +00:00
|
|
|
const { push } = useRouter();
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
const searchParam = useSearchParams();
|
|
|
|
const redirect = searchParam.get('redirect');
|
|
|
|
const [loading, setloading] = useState(false);
|
|
|
|
const [showPassword, setShowPassword] = useState(false);
|
2024-12-08 12:05:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
const [langState, setLangState] = useState(langIs ? langIs : 'kr')
|
2024-12-04 15:35:04 +00:00
|
|
|
const { mutate } = useMutation(api.login, {
|
|
|
|
onSuccess: async (data) => {
|
|
|
|
dispatch(setLogin(data.user));
|
|
|
|
dispatch(setWishlist(data.user.wishlist));
|
2024-12-10 02:55:52 +00:00
|
|
|
await createCookies('token', data.token);
|
2024-12-04 15:35:04 +00:00
|
|
|
setloading(false);
|
2024-12-05 13:06:19 +00:00
|
|
|
toast.success(lang['Logged in successfully!']);
|
2024-12-04 15:35:04 +00:00
|
|
|
const isAdmin = data.user.role.includes('admin');
|
|
|
|
const isVendor = data.user.role.includes('vendor');
|
|
|
|
push(redirect || isAdmin ? '/admin/dashboard' : isVendor ? '/vendor/dashboard' : '/');
|
|
|
|
},
|
|
|
|
onError: (err) => {
|
|
|
|
setloading(false);
|
|
|
|
toast.error(err.response.data.message);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
const LoginSchema = Yup.object().shape({
|
2024-12-05 13:06:19 +00:00
|
|
|
email: Yup.string().email(lang['Enter valid email']).required(lang['Email is required']),
|
|
|
|
password: Yup.string()
|
|
|
|
.required(lang['Password is required'])
|
|
|
|
.min(8, lang['Password should be 8 characters or longer'])
|
2024-12-04 15:35:04 +00:00
|
|
|
});
|
|
|
|
const formik = useFormik({
|
|
|
|
initialValues: {
|
|
|
|
email: '',
|
|
|
|
password: '',
|
|
|
|
remember: true
|
|
|
|
},
|
|
|
|
validationSchema: LoginSchema,
|
|
|
|
|
|
|
|
onSubmit: async (values) => {
|
|
|
|
const { email, password } = values;
|
|
|
|
setloading(true);
|
|
|
|
mutate({ email, password });
|
|
|
|
}
|
|
|
|
});
|
2024-12-05 13:06:19 +00:00
|
|
|
const { errors, touched, values, handleSubmit, getFieldProps } = formik;
|
2024-12-08 12:05:09 +00:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
createCookies('lang', langState)
|
|
|
|
}, [langState]);
|
|
|
|
|
2024-12-04 15:35:04 +00:00
|
|
|
return (
|
|
|
|
<>
|
2024-12-12 19:46:38 +00:00
|
|
|
<Stack mb={5}>
|
|
|
|
<Typography textAlign="center" variant="h4" component="h1" textTransform="uppercase" gutterBottom>
|
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang).login}
|
|
|
|
</Typography>
|
|
|
|
</Stack>
|
2024-12-10 02:55:52 +00:00
|
|
|
<FormControl fullWidth sx={{ mb: '10px' }}>
|
|
|
|
<Typography variant="overline" color="text.primary" htmlFor="email" component={'label'}>
|
2024-12-12 19:46:38 +00:00
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang)["Select Language"]}
|
2024-12-10 02:55:52 +00:00
|
|
|
</Typography>
|
|
|
|
<Select
|
2024-12-08 12:05:09 +00:00
|
|
|
onChange={(e) => setLangState(e.target.value)}
|
|
|
|
value={langIs}
|
|
|
|
>
|
|
|
|
<MenuItem value="kr">KOREAN</MenuItem>
|
|
|
|
<MenuItem value="jp">JAPANESE</MenuItem>
|
|
|
|
<MenuItem value="en">ENGLISH</MenuItem>
|
|
|
|
</Select>
|
|
|
|
</FormControl>
|
2024-12-04 15:35:04 +00:00
|
|
|
<FormikProvider value={formik}>
|
|
|
|
<Form autoComplete="off" noValidate onSubmit={handleSubmit}>
|
|
|
|
<Stack spacing={3}>
|
|
|
|
<Stack gap={0.5} width={1}>
|
|
|
|
<Typography variant="overline" color="text.primary" htmlFor="email" component={'label'}>
|
2024-12-08 12:05:09 +00:00
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang).Email}
|
2024-12-04 15:35:04 +00:00
|
|
|
</Typography>
|
|
|
|
<TextField
|
|
|
|
id="email"
|
|
|
|
fullWidth
|
|
|
|
autoComplete="username"
|
|
|
|
type="email"
|
|
|
|
{...getFieldProps('email')}
|
|
|
|
error={Boolean(touched.email && errors.email)}
|
|
|
|
helperText={touched.email && errors.email}
|
|
|
|
InputProps={{
|
|
|
|
startAdornment: (
|
|
|
|
<InputAdornment position="start">
|
|
|
|
<IoMdMail size={24} />
|
|
|
|
</InputAdornment>
|
|
|
|
)
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Stack>
|
|
|
|
|
|
|
|
<Stack gap={0.5} width={1}>
|
|
|
|
<Typography variant="overline" color="text.primary" htmlFor="password" component={'label'}>
|
2024-12-08 12:05:09 +00:00
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang).Password}
|
2024-12-04 15:35:04 +00:00
|
|
|
</Typography>
|
|
|
|
<TextField
|
|
|
|
id="password"
|
|
|
|
fullWidth
|
|
|
|
autoComplete="current-password"
|
|
|
|
type={showPassword ? 'text' : 'password'}
|
|
|
|
{...getFieldProps('password')}
|
|
|
|
InputProps={{
|
|
|
|
startAdornment: (
|
|
|
|
<InputAdornment position="start">
|
|
|
|
<MdLock size={24} />
|
|
|
|
</InputAdornment>
|
|
|
|
),
|
|
|
|
endAdornment: (
|
|
|
|
<InputAdornment position="end">
|
|
|
|
<IconButton edge="end" onClick={() => setShowPassword((prev) => !prev)}>
|
|
|
|
{showPassword ? <MdOutlineVisibility size={24} /> : <MdOutlineVisibilityOff size={24} />}
|
|
|
|
</IconButton>
|
|
|
|
</InputAdornment>
|
|
|
|
)
|
|
|
|
}}
|
|
|
|
error={Boolean(touched.password && errors.password)}
|
|
|
|
helperText={touched.password && errors.password}
|
|
|
|
/>
|
|
|
|
</Stack>
|
|
|
|
</Stack>
|
|
|
|
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ my: 2 }}>
|
|
|
|
<FormControlLabel
|
|
|
|
control={<Checkbox {...getFieldProps('remember')} checked={values.remember} />}
|
2024-12-08 12:05:09 +00:00
|
|
|
label={({ kr: lang, en: langen, jp: langjp }[langIs] || lang)['Remember me']}
|
|
|
|
|
2024-12-04 15:35:04 +00:00
|
|
|
/>
|
|
|
|
<Link component={RouterLink} variant="subtitle2" href="/auth/forget-password">
|
2024-12-08 12:05:09 +00:00
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang)['Forgot password']}
|
2024-12-04 15:35:04 +00:00
|
|
|
</Link>
|
|
|
|
</Stack>
|
|
|
|
<LoadingButton fullWidth size="large" type="submit" variant="contained" loading={loading}>
|
2024-12-08 12:05:09 +00:00
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang).login}
|
|
|
|
|
2024-12-04 15:35:04 +00:00
|
|
|
</LoadingButton>
|
2024-12-22 12:41:23 +00:00
|
|
|
<Row sx={{justifyContent:'space-around'}}>
|
|
|
|
<Typography variant="subtitle2" mt={3} textAlign="center">
|
|
|
|
<Link href='/auth/register/?redirect=/create-shop' component={RouterLink}>
|
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang).vendor}
|
|
|
|
{' '}
|
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang).Register}
|
|
|
|
</Link>
|
|
|
|
</Typography>
|
|
|
|
<Typography variant="subtitle2" mt={3} textAlign="center">
|
|
|
|
<Link href={`/auth/register${redirect ? '?redirect=' + redirect : ''}`} component={RouterLink}>
|
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang).buyer}
|
|
|
|
{' '}
|
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang).Register}
|
|
|
|
</Link>
|
|
|
|
</Typography>
|
|
|
|
</Row>
|
2024-12-04 15:35:04 +00:00
|
|
|
<Typography variant="subtitle2" mt={3} textAlign="center">
|
2024-12-22 12:41:23 +00:00
|
|
|
<Link href="https://www.picshop.co.kr" target='_blank'>
|
|
|
|
{({ kr: lang, en: langen, jp: langjp }[langIs] || lang)['customer service']}
|
2024-12-04 15:35:04 +00:00
|
|
|
</Link>
|
2024-12-22 12:41:23 +00:00
|
|
|
</Typography>
|
2024-12-04 15:35:04 +00:00
|
|
|
</Form>
|
|
|
|
</FormikProvider>
|
2025-02-24 01:47:56 +00:00
|
|
|
<Button onClick={window.open('http://pf.kakao.com/_PrwzG/chat', '_blank')}>kakao</Button>
|
2024-12-04 15:35:04 +00:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|