fix login & verify code
This commit is contained in:
BIN
frontend/.DS_Store
vendored
BIN
frontend/.DS_Store
vendored
Binary file not shown.
@@ -78,12 +78,9 @@ function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
console.log('initialize', state);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const accessToken = getSession();
|
const accessToken = getSession();
|
||||||
|
|
||||||
console.log('');
|
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
setSession(accessToken);
|
setSession(accessToken);
|
||||||
|
|
||||||
@@ -144,6 +141,8 @@ function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
user,
|
user,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return response.data;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.response.status !== 404) throw error.response;
|
if (error.response.status !== 404) throw error.response;
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import { Box, Divider, Typography, Stack, MenuItem, Avatar } from '@mui/material
|
|||||||
// components
|
// components
|
||||||
import MenuPopover from '../../../components/MenuPopover';
|
import MenuPopover from '../../../components/MenuPopover';
|
||||||
import { IconButtonAnimate } from '../../../components/animate';
|
import { IconButtonAnimate } from '../../../components/animate';
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from 'react-router-dom';
|
||||||
import useAuth from '../../../hooks/useAuth';
|
import useAuth from '../../../hooks/useAuth';
|
||||||
|
import useLocalStorage from '../../../hooks/useLocalStorage';
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -32,6 +33,10 @@ export default function AccountPopover() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { logout } = useAuth();
|
const { logout } = useAuth();
|
||||||
|
|
||||||
|
const [emailOrPhone, setEmailOrPhone] = useLocalStorage('emailOrPhone', '');
|
||||||
|
const [emailOrPhoneForm, setEmailOrPhoneForm] = useLocalStorage('emailOrPhoneForm', false);
|
||||||
|
const [loginOrVerifyCode, setLoginOrVerifyCode] = useLocalStorage('loginOrVerifyCode', false);
|
||||||
|
|
||||||
const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
|
const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
setOpen(event.currentTarget);
|
setOpen(event.currentTarget);
|
||||||
};
|
};
|
||||||
@@ -41,9 +46,12 @@ export default function AccountPopover() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
|
setEmailOrPhone('');
|
||||||
|
setEmailOrPhoneForm(false);
|
||||||
|
setLoginOrVerifyCode(false);
|
||||||
logout();
|
logout();
|
||||||
navigate('/auth/login');
|
navigate('/auth/login');
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -105,7 +113,9 @@ export default function AccountPopover() {
|
|||||||
|
|
||||||
<Divider sx={{ borderStyle: 'dashed' }} />
|
<Divider sx={{ borderStyle: 'dashed' }} />
|
||||||
|
|
||||||
<MenuItem sx={{ m: 1 }} onClick={handleLogout}>Logout</MenuItem>
|
<MenuItem sx={{ m: 1 }} onClick={handleLogout}>
|
||||||
|
Logout
|
||||||
|
</MenuItem>
|
||||||
</MenuPopover>
|
</MenuPopover>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
// @mui
|
/* ---------------------------------- @mui ---------------------------------- */
|
||||||
import { styled } from '@mui/material/styles';
|
import { styled } from '@mui/material/styles';
|
||||||
import { Box, Card, Divider, Grid, Link, Stack, Typography } from '@mui/material';
|
import { Box, Card, Divider, Grid, Link, Stack, Typography, IconButton } from '@mui/material';
|
||||||
// components
|
/* ------------------------------- components ------------------------------- */
|
||||||
import Page from '../../components/Page';
|
import Page from '../../components/Page';
|
||||||
import Image from '../../components/Image';
|
|
||||||
// sections
|
|
||||||
import { LoginEmailForm, LoginPhoneForm } from '../../sections/auth/login';
|
|
||||||
import Logo from '../../components/Logo';
|
import Logo from '../../components/Logo';
|
||||||
// react
|
import Iconify from '../../components/Iconify';
|
||||||
import { useState, useEffect } from 'react';
|
/* ---------------------------------- hooks --------------------------------- */
|
||||||
import { useLocation } from 'react-router-dom';
|
import useLocalStorage from '../../hooks/useLocalStorage';
|
||||||
|
/* -------------------------------- sections -------------------------------- */
|
||||||
|
import { LoginEmailForm, LoginPhoneForm, VerifyCodeForm } from '../../sections/auth/login';
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
/* --------------------------------- styled --------------------------------- */
|
||||||
|
|
||||||
const RootStyle = styled('div')(({ theme }) => ({
|
const RootStyle = styled('div')(({ theme }) => ({
|
||||||
[theme.breakpoints.up('md')]: {
|
[theme.breakpoints.up('md')]: {
|
||||||
@@ -33,20 +32,9 @@ const ContentStyle = styled(Card)(({ theme }) => ({
|
|||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const { state } = useLocation();
|
const [emailOrPhone, setEmailOrPhone] = useLocalStorage('emailOrPhone', '');
|
||||||
const [formPhone, setFormPhone] = useState(false);
|
const [emailOrPhoneForm, setEmailOrPhoneForm] = useLocalStorage('emailOrPhoneForm', false);
|
||||||
|
const [loginOrVerifyCode, setLoginOrVerifyCode] = useLocalStorage('loginOrVerifyCode', false);
|
||||||
const handlerChange = (event: any, setForm: boolean) => {
|
|
||||||
event.preventDefault();
|
|
||||||
setFormPhone(setForm);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (state !== null) {
|
|
||||||
setFormPhone(state.formPhone);
|
|
||||||
}
|
|
||||||
console.log(state);
|
|
||||||
}, [state]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title="Login">
|
<Page title="Login">
|
||||||
@@ -66,32 +54,87 @@ export default function Login() {
|
|||||||
</video>
|
</video>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={6} sx={{ padding: 3 }}>
|
<Grid item xs={6} sx={{ padding: 3 }}>
|
||||||
<Stack direction="row" alignItems="center" sx={{ mb: 5 }}>
|
{loginOrVerifyCode && emailOrPhone ? (
|
||||||
<Logo sx={{ width: 90, height: 90 }} />
|
<>
|
||||||
<Box sx={{ flexGrow: 1 }}>
|
<Stack direction="column" sx={{ mb: 5 }}>
|
||||||
<Typography variant="h4" gutterBottom>
|
<Stack direction="row" alignItems="center">
|
||||||
Sign in to LinkSehat
|
<IconButton
|
||||||
</Typography>
|
onClick={() => {
|
||||||
<Typography variant="body1" sx={{ color: 'text.secondary' }}>
|
localStorage.removeItem('emailOrPhone');
|
||||||
Enter your details below.
|
setLoginOrVerifyCode(false);
|
||||||
</Typography>
|
}}
|
||||||
</Box>
|
>
|
||||||
</Stack>
|
<Iconify
|
||||||
|
icon="heroicons-outline:arrow-narrow-left"
|
||||||
|
sx={{ marginRight: '10px' }}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
<Typography variant="h4" gutterBottom>
|
||||||
|
Verifikasi OTP
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
sx={{ color: 'text.secondary', textAlign: 'left' }}
|
||||||
|
>
|
||||||
|
Masukkan kode OTP anda disini
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
{formPhone ? (
|
<VerifyCodeForm
|
||||||
<LoginPhoneForm formPhone={formPhone} />
|
setEmailOrPhoneForm={setEmailOrPhoneForm}
|
||||||
|
setLoginOrVerifyCode={setLoginOrVerifyCode}
|
||||||
|
emailOrPhone={emailOrPhone}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Stack sx={{ marginTop: 5 }} spacing={1} alignItems="center">
|
||||||
|
<Typography>Tidak mendapatkan kode?</Typography>
|
||||||
|
<Link sx={{ cursor: 'pointer' }}>Kirim Ulang Kode OTP</Link>
|
||||||
|
</Stack>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<LoginEmailForm formPhone={formPhone} />
|
<>
|
||||||
|
<Stack direction="row" alignItems="center" sx={{ mb: 5 }}>
|
||||||
|
<Logo sx={{ width: 90, height: 90 }} />
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Typography variant="h4" gutterBottom>
|
||||||
|
Sign in to LinkSehat
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body1" sx={{ color: 'text.secondary' }}>
|
||||||
|
Enter your details below.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
{emailOrPhoneForm ? (
|
||||||
|
<LoginPhoneForm
|
||||||
|
setEmailOrPhone={setEmailOrPhone}
|
||||||
|
setLoginOrVerifyCode={setLoginOrVerifyCode}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<LoginEmailForm
|
||||||
|
setEmailOrPhone={setEmailOrPhone}
|
||||||
|
setLoginOrVerifyCode={setLoginOrVerifyCode}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Divider sx={{ marginTop: 5 }}>Atau</Divider>
|
<Divider sx={{ marginTop: 5 }}>Atau</Divider>
|
||||||
|
|
||||||
<Stack sx={{ marginTop: 5 }}>
|
<Stack sx={{ marginTop: 5 }}>
|
||||||
{formPhone ? (
|
{emailOrPhoneForm ? (
|
||||||
<Link
|
<Link
|
||||||
align="center"
|
align="center"
|
||||||
underline="hover"
|
underline="hover"
|
||||||
onClick={(event) => handlerChange(event, false)}
|
onClick={() => {
|
||||||
|
setEmailOrPhone('');
|
||||||
|
setLoginOrVerifyCode(false);
|
||||||
|
setEmailOrPhoneForm(false);
|
||||||
|
}}
|
||||||
|
sx={{ cursor: 'pointer' }}
|
||||||
>
|
>
|
||||||
Masuk menggunakan email
|
Masuk menggunakan email
|
||||||
</Link>
|
</Link>
|
||||||
@@ -99,7 +142,12 @@ export default function Login() {
|
|||||||
<Link
|
<Link
|
||||||
align="center"
|
align="center"
|
||||||
underline="hover"
|
underline="hover"
|
||||||
onClick={(event) => handlerChange(event, true)}
|
onClick={() => {
|
||||||
|
setEmailOrPhone('');
|
||||||
|
setLoginOrVerifyCode(false);
|
||||||
|
setEmailOrPhoneForm(true);
|
||||||
|
}}
|
||||||
|
sx={{ cursor: 'pointer' }}
|
||||||
>
|
>
|
||||||
Masuk menggunakan nomor handphone
|
Masuk menggunakan nomor handphone
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
|
||||||
// @mui
|
|
||||||
import { styled } from '@mui/material/styles';
|
|
||||||
import { Box, Card, Divider, IconButton, Grid, Link, Stack, Typography } from '@mui/material';
|
|
||||||
// components
|
|
||||||
import Page from '../../components/Page';
|
|
||||||
import Image from '../../components/Image';
|
|
||||||
import Iconify from '../../components/Iconify';
|
|
||||||
// sections
|
|
||||||
import { VerifyCodeForm } from '../../sections/auth/verify-code';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
const RootStyle = styled('div')(({ theme }) => ({
|
|
||||||
[theme.breakpoints.up('md')]: {
|
|
||||||
display: 'flex',
|
|
||||||
},
|
|
||||||
minHeight: '100vh',
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const ContentStyle = styled(Card)(({ theme }) => ({
|
|
||||||
[theme.breakpoints.up('md')]: {
|
|
||||||
maxHeight: '600px',
|
|
||||||
maxWidth: '1000px',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
export default function VerifyCode() {
|
|
||||||
const { state } = useLocation();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (state === null) {
|
|
||||||
navigate('/auth/login');
|
|
||||||
}
|
|
||||||
}, [state, navigate]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page title="Login">
|
|
||||||
<RootStyle>
|
|
||||||
<ContentStyle>
|
|
||||||
<Grid container>
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<Image visibleByDefault disabledEffect src="/images/login-image.gif" alt="login" />
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={6} sx={{ padding: 3, textAlign: 'center' }}>
|
|
||||||
<Stack direction="column" sx={{ mb: 5 }}>
|
|
||||||
<Stack direction="row" alignItems="center">
|
|
||||||
<IconButton
|
|
||||||
onClick={() =>
|
|
||||||
navigate('/auth/login', { state: { formPhone: state.formPhone } })
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Iconify
|
|
||||||
icon="heroicons-outline:arrow-narrow-left"
|
|
||||||
sx={{ marginRight: '10px' }}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
<Typography variant="h4" gutterBottom>
|
|
||||||
Verifikasi OTP
|
|
||||||
</Typography>
|
|
||||||
</Stack>
|
|
||||||
<Box sx={{ flexGrow: 1 }}>
|
|
||||||
<Typography variant="body1" sx={{ color: 'text.secondary', textAlign: 'left' }}>
|
|
||||||
Masukkan kode OTP anda disini
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<VerifyCodeForm phoneOrEmail={state.phoneOrEmail} />
|
|
||||||
|
|
||||||
<Typography sx={{ marginTop: 5 }}>Tidak mendapatkan kode?</Typography>
|
|
||||||
<Link sx={{ marginTop: 1 }}>Kirim Ulang Kode OTP</Link>
|
|
||||||
|
|
||||||
<Divider sx={{ marginTop: 5 }}>Atau</Divider>
|
|
||||||
|
|
||||||
<Stack sx={{ marginTop: 5 }}>
|
|
||||||
{state.formPhone ? (
|
|
||||||
<Link
|
|
||||||
align="center"
|
|
||||||
underline="hover"
|
|
||||||
onClick={() => navigate('/auth/login', { state: { formPhone: false } })}
|
|
||||||
>
|
|
||||||
Masuk menggunakan email
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<Link
|
|
||||||
align="center"
|
|
||||||
underline="hover"
|
|
||||||
onClick={() => navigate('/auth/login', { state: { formPhone: true } })}
|
|
||||||
>
|
|
||||||
Masuk menggunakan nomor handphone
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</ContentStyle>
|
|
||||||
</RootStyle>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -37,16 +37,6 @@ export default function Router() {
|
|||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'verify-code',
|
|
||||||
element: (
|
|
||||||
<AuthProvider>
|
|
||||||
<GuestGuard>
|
|
||||||
<VerifyCode />
|
|
||||||
</GuestGuard>
|
|
||||||
</AuthProvider>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -132,7 +122,6 @@ export default function Router() {
|
|||||||
|
|
||||||
// Auth
|
// Auth
|
||||||
const Login = Loadable(lazy(() => import('../pages/auth/Login')));
|
const Login = Loadable(lazy(() => import('../pages/auth/Login')));
|
||||||
const VerifyCode = Loadable(lazy(() => import('../pages/auth/VerifyCode')));
|
|
||||||
|
|
||||||
// Dashboard
|
// Dashboard
|
||||||
const Dashboard = Loadable(lazy(() => import('../pages/Dashboard/Dashboard')));
|
const Dashboard = Loadable(lazy(() => import('../pages/Dashboard/Dashboard')));
|
||||||
|
|||||||
@@ -1,34 +1,33 @@
|
|||||||
|
/* ----------------------------------- yup ---------------------------------- */
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { useNavigate } from 'react-router-dom';
|
/* ---------------------------------- form ---------------------------------- */
|
||||||
// form
|
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
// @mui
|
/* ---------------------------------- @mui ---------------------------------- */
|
||||||
import { Stack, Alert } from '@mui/material';
|
import { Stack, Alert } from '@mui/material';
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from '@mui/lab';
|
||||||
// hooks
|
/* ---------------------------------- hooks --------------------------------- */
|
||||||
import useAuth from '../../../hooks/useAuth';
|
import useAuth from '../../../hooks/useAuth';
|
||||||
import useIsMountedRef from '../../../hooks/useIsMountedRef';
|
import useIsMountedRef from '../../../hooks/useIsMountedRef';
|
||||||
// components
|
/* ------------------------------- components ------------------------------- */
|
||||||
import { FormProvider, RHFTextField } from '../../../components/hook-form';
|
import { FormProvider, RHFTextField } from '../../../components/hook-form';
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
/* ---------------------------------- types --------------------------------- */
|
||||||
|
|
||||||
|
type LoginFormProps = {
|
||||||
|
setEmailOrPhone: Function;
|
||||||
|
setLoginOrVerifyCode: Function;
|
||||||
|
};
|
||||||
|
|
||||||
type FormValuesProps = {
|
type FormValuesProps = {
|
||||||
email: string;
|
email: string;
|
||||||
afterSubmit?: string;
|
afterSubmit?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Props {
|
/* -------------------------------------------------------------------------- */
|
||||||
formPhone: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
export default function LoginForm({ setEmailOrPhone, setLoginOrVerifyCode }: LoginFormProps) {
|
||||||
|
|
||||||
export default function LoginForm({ formPhone }: Props) {
|
|
||||||
const { login } = useAuth();
|
const { login } = useAuth();
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const isMountedRef = useIsMountedRef();
|
const isMountedRef = useIsMountedRef();
|
||||||
|
|
||||||
const LoginSchema = Yup.object().shape({
|
const LoginSchema = Yup.object().shape({
|
||||||
@@ -54,8 +53,9 @@ export default function LoginForm({ formPhone }: Props) {
|
|||||||
const onSubmit = async (data: FormValuesProps) => {
|
const onSubmit = async (data: FormValuesProps) => {
|
||||||
try {
|
try {
|
||||||
await login(data.email);
|
await login(data.email);
|
||||||
|
setEmailOrPhone(data.email);
|
||||||
navigate('/auth/verify-code', { state: { phoneOrEmail: data.email, formPhone } });
|
setLoginOrVerifyCode(true);
|
||||||
|
reset();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,34 @@
|
|||||||
|
/* ----------------------------------- yup ---------------------------------- */
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { useNavigate } from 'react-router-dom';
|
/* ---------------------------------- form ---------------------------------- */
|
||||||
// form
|
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
// @mui
|
/* ---------------------------------- @mui ---------------------------------- */
|
||||||
import { Stack, Alert, InputAdornment } from '@mui/material';
|
import { Stack, Alert, InputAdornment } from '@mui/material';
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from '@mui/lab';
|
||||||
// components
|
/* ------------------------------- components ------------------------------- */
|
||||||
import { FormProvider, RHFTextField } from '../../../components/hook-form';
|
import { FormProvider, RHFTextField } from '../../../components/hook-form';
|
||||||
|
/* ---------------------------------- hooks --------------------------------- */
|
||||||
import useAuth from '../../../hooks/useAuth';
|
import useAuth from '../../../hooks/useAuth';
|
||||||
|
import useIsMountedRef from '../../../hooks/useIsMountedRef';
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
/* ---------------------------------- types --------------------------------- */
|
||||||
|
|
||||||
|
type LoginFormProps = {
|
||||||
|
setEmailOrPhone: Function;
|
||||||
|
setLoginOrVerifyCode: Function;
|
||||||
|
};
|
||||||
|
|
||||||
type FormValuesProps = {
|
type FormValuesProps = {
|
||||||
phone: string;
|
phone: string;
|
||||||
afterSubmit?: string;
|
afterSubmit?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Props {
|
/* -------------------------------------------------------------------------- */
|
||||||
formPhone: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function LoginPhoneForm({ formPhone }: Props) {
|
export default function LoginPhoneForm({ setEmailOrPhone, setLoginOrVerifyCode }: LoginFormProps) {
|
||||||
const { login } = useAuth();
|
const { login } = useAuth();
|
||||||
const navigate = useNavigate();
|
const isMountedRef = useIsMountedRef();
|
||||||
|
|
||||||
const LoginSchema = Yup.object().shape({
|
const LoginSchema = Yup.object().shape({
|
||||||
phone: Yup.string().required('Phone is required'),
|
phone: Yup.string().required('Phone is required'),
|
||||||
@@ -48,10 +53,15 @@ export default function LoginPhoneForm({ formPhone }: Props) {
|
|||||||
const onSubmit = async (data: FormValuesProps) => {
|
const onSubmit = async (data: FormValuesProps) => {
|
||||||
try {
|
try {
|
||||||
await login(0 + data.phone);
|
await login(0 + data.phone);
|
||||||
navigate('/auth/verify-code', { state: { phoneOrEmail: 0 + data.phone, formPhone } });
|
setEmailOrPhone(0 + data.phone);
|
||||||
|
setLoginOrVerifyCode(true);
|
||||||
|
reset();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
reset();
|
reset();
|
||||||
setError('afterSubmit', { ...error, message: error.response.data.message });
|
|
||||||
|
if (isMountedRef.current) {
|
||||||
|
setError('afterSubmit', { ...error, message: error.data.message });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,25 @@
|
|||||||
|
/* ---------------------------------- @mui ---------------------------------- */
|
||||||
|
import { OutlinedInput, Stack } from '@mui/material';
|
||||||
|
/* ----------------------------------- yup ---------------------------------- */
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
/* -------------------------------- snackbar -------------------------------- */
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from 'notistack';
|
||||||
import { useNavigate, useLocation } from 'react-router-dom';
|
/* ---------------------------------- react --------------------------------- */
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
// form
|
/* ---------------------------------- form ---------------------------------- */
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
// @mui
|
/* ---------------------------------- hooks --------------------------------- */
|
||||||
import { OutlinedInput, Stack } from '@mui/material';
|
|
||||||
import useAuth from '../../../hooks/useAuth';
|
import useAuth from '../../../hooks/useAuth';
|
||||||
// routes
|
|
||||||
// import { PATH_DASHBOARD } from '../../../routes/paths';
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
/* ---------------------------------- types --------------------------------- */
|
||||||
|
|
||||||
|
type VerifyCodeFormProps = {
|
||||||
|
emailOrPhone: string;
|
||||||
|
setEmailOrPhoneForm: Function;
|
||||||
|
setLoginOrVerifyCode: Function;
|
||||||
|
};
|
||||||
|
|
||||||
type FormValuesProps = {
|
type FormValuesProps = {
|
||||||
code1: string;
|
code1: string;
|
||||||
@@ -20,18 +28,25 @@ type FormValuesProps = {
|
|||||||
code4: string;
|
code4: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
|
||||||
phoneOrEmail: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ValueNames = 'code1' | 'code2' | 'code3' | 'code4';
|
type ValueNames = 'code1' | 'code2' | 'code3' | 'code4';
|
||||||
|
|
||||||
export default function VerifyCodeForm({ phoneOrEmail }: Props) {
|
type responseProps = {
|
||||||
|
status: string;
|
||||||
|
statusCode: number;
|
||||||
|
data: [];
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
export default function VerifyCodeForm({
|
||||||
|
emailOrPhone,
|
||||||
|
setEmailOrPhoneForm,
|
||||||
|
setLoginOrVerifyCode,
|
||||||
|
}: VerifyCodeFormProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
|
||||||
const { validateOtp } = useAuth();
|
const { validateOtp } = useAuth();
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
const { phone_or_email } = location.state;
|
|
||||||
|
|
||||||
const VerifyCodeSchema = Yup.object().shape({
|
const VerifyCodeSchema = Yup.object().shape({
|
||||||
code1: Yup.string().required('Code is required'),
|
code1: Yup.string().required('Code is required'),
|
||||||
@@ -47,13 +62,7 @@ export default function VerifyCodeForm({ phoneOrEmail }: Props) {
|
|||||||
code4: '',
|
code4: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const { watch, control, setValue, handleSubmit } = useForm({
|
||||||
watch,
|
|
||||||
control,
|
|
||||||
setValue,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { isSubmitting, isValid },
|
|
||||||
} = useForm({
|
|
||||||
mode: 'onBlur',
|
mode: 'onBlur',
|
||||||
resolver: yupResolver(VerifyCodeSchema),
|
resolver: yupResolver(VerifyCodeSchema),
|
||||||
defaultValues,
|
defaultValues,
|
||||||
@@ -62,15 +71,35 @@ export default function VerifyCodeForm({ phoneOrEmail }: Props) {
|
|||||||
const values = watch();
|
const values = watch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('phone number : ' + phone_or_email);
|
const handlePasteClipboard = (event: ClipboardEvent) => {
|
||||||
|
let data: string | string[] = event?.clipboardData?.getData('Text') || '';
|
||||||
|
|
||||||
|
data = data.split('');
|
||||||
|
|
||||||
|
[].forEach.call(document.querySelectorAll('#field-code'), (node: any, index) => {
|
||||||
|
node.value = data[index];
|
||||||
|
const fieldIndex = `code${index + 1}`;
|
||||||
|
setValue(fieldIndex as ValueNames, data[index]);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
document.addEventListener('paste', handlePasteClipboard);
|
document.addEventListener('paste', handlePasteClipboard);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [setValue]);
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onSubmit = async (data: FormValuesProps) => {
|
const onSubmit = async (data: FormValuesProps) => {
|
||||||
try {
|
try {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
await validateOtp(phoneOrEmail, Object.values(data).join(''));
|
// @ts-ignore
|
||||||
|
const response: responseProps = await validateOtp(emailOrPhone, Object.values(data).join(''));
|
||||||
|
|
||||||
|
if (response.data.length === 0) {
|
||||||
|
return enqueueSnackbar(response.message, {
|
||||||
|
variant: 'error',
|
||||||
|
autoHideDuration: 4000,
|
||||||
|
preventDuplicate: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
navigate('/dashboard');
|
navigate('/dashboard');
|
||||||
enqueueSnackbar('Verify success!', { variant: 'success' });
|
enqueueSnackbar('Verify success!', { variant: 'success' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -78,18 +107,6 @@ export default function VerifyCodeForm({ phoneOrEmail }: Props) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePasteClipboard = (event: ClipboardEvent) => {
|
|
||||||
let data: string | string[] = event?.clipboardData?.getData('Text') || '';
|
|
||||||
|
|
||||||
data = data.split('');
|
|
||||||
|
|
||||||
[].forEach.call(document.querySelectorAll('#field-code'), (node: any, index) => {
|
|
||||||
node.value = data[index];
|
|
||||||
const fieldIndex = `code${index + 1}`;
|
|
||||||
setValue(fieldIndex as ValueNames, data[index]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangeWithNextField = (
|
const handleChangeWithNextField = (
|
||||||
event: React.ChangeEvent<HTMLInputElement>,
|
event: React.ChangeEvent<HTMLInputElement>,
|
||||||
handleChange: (event: React.ChangeEvent<HTMLInputElement>) => void
|
handleChange: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export { default as LoginEmailForm } from './LoginEmailForm';
|
export { default as LoginEmailForm } from './LoginEmailForm';
|
||||||
export { default as LoginPhoneForm } from './LoginPhoneForm';
|
export { default as LoginPhoneForm } from './LoginPhoneForm';
|
||||||
|
export { default as VerifyCodeForm } from './VerifyCodeForm';
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default as VerifyCodeForm } from './VerifyCodeForm';
|
|
||||||
Reference in New Issue
Block a user