validate otp
This commit is contained in:
@@ -6,7 +6,7 @@ import { setSession, getSession, getUser } from '../utils/token';
|
|||||||
// @types
|
// @types
|
||||||
import { ActionMap, AuthState, AuthUser, JWTContextType } from '../@types/auth';
|
import { ActionMap, AuthState, AuthUser, JWTContextType } from '../@types/auth';
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
import { Navigate, useLocation } from 'react-router-dom';
|
// import { Navigate, useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
enum Types {
|
enum Types {
|
||||||
Initial = 'INITIALIZE',
|
Initial = 'INITIALIZE',
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import { useState, ReactNode } from 'react';
|
|||||||
import { Navigate, useLocation } from 'react-router-dom';
|
import { Navigate, useLocation } from 'react-router-dom';
|
||||||
// hooks
|
// hooks
|
||||||
import useAuth from '../hooks/useAuth';
|
import useAuth from '../hooks/useAuth';
|
||||||
// pages
|
|
||||||
import Login from '../pages/auth/Login';
|
|
||||||
// components
|
// components
|
||||||
import LoadingScreen from '../components/LoadingScreen';
|
import LoadingScreen from '../components/LoadingScreen';
|
||||||
|
|
||||||
@@ -26,7 +24,7 @@ export default function AuthGuard({ children }: AuthGuardProps) {
|
|||||||
if (pathname !== requestedLocation) {
|
if (pathname !== requestedLocation) {
|
||||||
setRequestedLocation(pathname);
|
setRequestedLocation(pathname);
|
||||||
}
|
}
|
||||||
return <Navigate to="/auth/login" replace={true}/>;
|
return <Navigate to="/auth/login" replace={true} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestedLocation && pathname !== requestedLocation) {
|
if (requestedLocation && pathname !== requestedLocation) {
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import Image from '../../components/Image';
|
|||||||
import { LoginEmailForm, LoginPhoneForm } from '../../sections/auth/login';
|
import { LoginEmailForm, LoginPhoneForm } from '../../sections/auth/login';
|
||||||
import Logo from '../../components/Logo';
|
import Logo from '../../components/Logo';
|
||||||
// react
|
// react
|
||||||
import { useState } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -36,13 +37,20 @@ const ContentStyle = styled(Card)(({ theme }) => ({
|
|||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const { method } = useAuth();
|
const { method } = useAuth();
|
||||||
|
const location = useLocation();
|
||||||
const [formPhone, setFormPhone] = useState(false);
|
const [formPhone, setFormPhone] = useState(false);
|
||||||
|
// const { setForm } = location.state;
|
||||||
|
|
||||||
const handlerChange = (event: any, setForm: boolean) => {
|
const handlerChange = (event: any, setForm: boolean) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setFormPhone(setForm);
|
setFormPhone(setForm);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('setForm');
|
||||||
|
// setFormPhone(setForm ? setForm : true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title="Login">
|
<Page title="Login">
|
||||||
<RootStyle>
|
<RootStyle>
|
||||||
|
|||||||
134
frontend/client-portal/src/pages/auth/OtpValidation.tsx
Executable file
134
frontend/client-portal/src/pages/auth/OtpValidation.tsx
Executable file
@@ -0,0 +1,134 @@
|
|||||||
|
import { capitalCase } from 'change-case';
|
||||||
|
// @mui
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Divider,
|
||||||
|
Grid,
|
||||||
|
Link,
|
||||||
|
Stack,
|
||||||
|
IconButton,
|
||||||
|
Typography,
|
||||||
|
} from '@mui/material';
|
||||||
|
// hooks
|
||||||
|
import useAuth from '../../hooks/useAuth';
|
||||||
|
// components
|
||||||
|
import Page from '../../components/Page';
|
||||||
|
import Image from '../../components/Image';
|
||||||
|
import Iconify from '../../components/Iconify';
|
||||||
|
// sections
|
||||||
|
import { VerifyCodeForm } from '../../sections/auth/verify-code';
|
||||||
|
// react
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
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 OtpValidation() {
|
||||||
|
const { method } = useAuth();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const formPhone = false;
|
||||||
|
|
||||||
|
const handlerChange = (event: any, setForm: boolean) => {
|
||||||
|
event.preventDefault();
|
||||||
|
// setFormPhone(setForm);
|
||||||
|
navigate('/auth/login', { state: { setForm: setForm } });
|
||||||
|
};
|
||||||
|
|
||||||
|
const otpRequestHandler = (event: any) => {
|
||||||
|
event.preventDefault();
|
||||||
|
alert('otp sudah dikirim ulang!');
|
||||||
|
};
|
||||||
|
|
||||||
|
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 }}>
|
||||||
|
<Stack direction="column" justifyContent="flex-start" sx={{ mb: 5 }}>
|
||||||
|
<Stack direction="row" alignItems="center">
|
||||||
|
<IconButton sx={{ marginRight: '10px' }}>
|
||||||
|
<Iconify icon="heroicons-outline:arrow-narrow-left" sx={{ color: '#424242' }} />
|
||||||
|
</IconButton>
|
||||||
|
<Typography variant="h5">Verifikasi OTP</Typography>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
{/* <Box sx={{ flexGrow: 1 }}> */}
|
||||||
|
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
|
||||||
|
Masukkan kode OTP anda disini
|
||||||
|
</Typography>
|
||||||
|
{/* </Box> */}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<VerifyCodeForm />
|
||||||
|
|
||||||
|
<Stack alignItems="center" sx={{ marginTop: 5 }}>
|
||||||
|
<Typography variant="caption" sx={{ color: 'text.secondary' }} gutterBottom>
|
||||||
|
Tidak Mendapatkan Kode?
|
||||||
|
</Typography>
|
||||||
|
<Link
|
||||||
|
variant="subtitle2"
|
||||||
|
href=""
|
||||||
|
align="center"
|
||||||
|
underline="hover"
|
||||||
|
onClick={(event) => otpRequestHandler(event)}
|
||||||
|
>
|
||||||
|
Kirim Ulang Kode OTP
|
||||||
|
</Link>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Divider sx={{ marginTop: 5 }}>Atau</Divider>
|
||||||
|
|
||||||
|
<Stack sx={{ marginTop: 5 }}>
|
||||||
|
{formPhone === false ? (
|
||||||
|
<Link
|
||||||
|
href=""
|
||||||
|
align="center"
|
||||||
|
underline="hover"
|
||||||
|
onClick={(event) => handlerChange(event, true)}
|
||||||
|
>
|
||||||
|
Masuk menggunakan nomor handphone
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<Link
|
||||||
|
href=""
|
||||||
|
align="center"
|
||||||
|
underline="hover"
|
||||||
|
onClick={(event) => handlerChange(event, false)}
|
||||||
|
>
|
||||||
|
Masuk menggunakan email
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</ContentStyle>
|
||||||
|
</RootStyle>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
import { capitalCase } from 'change-case';
|
|
||||||
import { Link as RouterLink } from 'react-router-dom';
|
|
||||||
// @mui
|
|
||||||
import { styled } from '@mui/material/styles';
|
|
||||||
import { Box, Card, Link, Container, Typography, Tooltip } from '@mui/material';
|
|
||||||
// hooks
|
|
||||||
import useAuth from '../../hooks/useAuth';
|
|
||||||
import useResponsive from '../../hooks/useResponsive';
|
|
||||||
// routes
|
|
||||||
import { PATH_AUTH } from '../../routes/paths';
|
|
||||||
// components
|
|
||||||
import Page from '../../components/Page';
|
|
||||||
import Logo from '../../components/Logo';
|
|
||||||
import Image from '../../components/Image';
|
|
||||||
// sections
|
|
||||||
import { RegisterForm } from '../../sections/auth/register';
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
const RootStyle = styled('div')(({ theme }) => ({
|
|
||||||
[theme.breakpoints.up('md')]: {
|
|
||||||
display: 'flex',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const HeaderStyle = styled('header')(({ theme }) => ({
|
|
||||||
top: 0,
|
|
||||||
zIndex: 9,
|
|
||||||
lineHeight: 0,
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
position: 'absolute',
|
|
||||||
padding: theme.spacing(3),
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
[theme.breakpoints.up('md')]: {
|
|
||||||
alignItems: 'flex-start',
|
|
||||||
padding: theme.spacing(7, 5, 0, 7),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const SectionStyle = styled(Card)(({ theme }) => ({
|
|
||||||
width: '100%',
|
|
||||||
maxWidth: 464,
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'center',
|
|
||||||
margin: theme.spacing(2, 0, 2, 2),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const ContentStyle = styled('div')(({ theme }) => ({
|
|
||||||
maxWidth: 480,
|
|
||||||
margin: 'auto',
|
|
||||||
display: 'flex',
|
|
||||||
minHeight: '100vh',
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'center',
|
|
||||||
padding: theme.spacing(12, 0),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
export default function Register() {
|
|
||||||
const { method } = useAuth();
|
|
||||||
|
|
||||||
const smUp = useResponsive('up', 'sm');
|
|
||||||
|
|
||||||
const mdUp = useResponsive('up', 'md');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page title="Register">
|
|
||||||
<RootStyle>
|
|
||||||
<HeaderStyle>
|
|
||||||
<Logo />
|
|
||||||
{smUp && (
|
|
||||||
<Typography variant="body2" sx={{ mt: { md: -2 } }}>
|
|
||||||
Already have an account? {''}
|
|
||||||
<Link variant="subtitle2" component={RouterLink} to={PATH_AUTH.login}>
|
|
||||||
Login
|
|
||||||
</Link>
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</HeaderStyle>
|
|
||||||
|
|
||||||
{mdUp && (
|
|
||||||
<SectionStyle>
|
|
||||||
<Typography variant="h3" sx={{ px: 5, mt: 10, mb: 5 }}>
|
|
||||||
Manage the job more effectively with Minimal
|
|
||||||
</Typography>
|
|
||||||
<Image
|
|
||||||
visibleByDefault
|
|
||||||
disabledEffect
|
|
||||||
alt="register"
|
|
||||||
src="https://minimal-assets-api.vercel.app/assets/illustrations/illustration_register.png"
|
|
||||||
/>
|
|
||||||
</SectionStyle>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Container>
|
|
||||||
<ContentStyle>
|
|
||||||
<Box sx={{ mb: 5, display: 'flex', alignItems: 'center' }}>
|
|
||||||
<Box sx={{ flexGrow: 1 }}>
|
|
||||||
<Typography variant="h4" gutterBottom>
|
|
||||||
Get started absolutely free.
|
|
||||||
</Typography>
|
|
||||||
<Typography sx={{ color: 'text.secondary' }}>
|
|
||||||
Free forever. No credit card needed.
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Tooltip title={capitalCase(method)}>
|
|
||||||
<>
|
|
||||||
<Image
|
|
||||||
disabledEffect
|
|
||||||
src={`https://minimal-assets-api.vercel.app/assets/icons/auth/ic_${method}.png`}
|
|
||||||
sx={{ width: 32, height: 32 }}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<RegisterForm />
|
|
||||||
|
|
||||||
<Typography variant="body2" align="center" sx={{ color: 'text.secondary', mt: 3 }}>
|
|
||||||
By registering, I agree to Minimal
|
|
||||||
<Link underline="always" color="text.primary" href="#">
|
|
||||||
Terms of Service
|
|
||||||
</Link>
|
|
||||||
{''}and{''}
|
|
||||||
<Link underline="always" color="text.primary" href="#">
|
|
||||||
Privacy Policy
|
|
||||||
</Link>
|
|
||||||
.
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
{!smUp && (
|
|
||||||
<Typography variant="body2" sx={{ mt: 3, textAlign: 'center' }}>
|
|
||||||
Already have an account?{' '}
|
|
||||||
<Link variant="subtitle2" to={PATH_AUTH.login} component={RouterLink}>
|
|
||||||
Login
|
|
||||||
</Link>
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</ContentStyle>
|
|
||||||
</Container>
|
|
||||||
</RootStyle>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import { Link as RouterLink } from 'react-router-dom';
|
|
||||||
// @mui
|
|
||||||
import { styled } from '@mui/material/styles';
|
|
||||||
import { Box, Button, Container, Typography } from '@mui/material';
|
|
||||||
// layouts
|
|
||||||
import LogoOnlyLayout from '../../layouts/LogoOnlyLayout';
|
|
||||||
// routes
|
|
||||||
import { PATH_AUTH } from '../../routes/paths';
|
|
||||||
// components
|
|
||||||
import Page from '../../components/Page';
|
|
||||||
// sections
|
|
||||||
import { ResetPasswordForm } from '../../sections/auth/reset-password';
|
|
||||||
// assets
|
|
||||||
import { SentIcon } from '../../assets';
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
const RootStyle = styled('div')(({ theme }) => ({
|
|
||||||
display: 'flex',
|
|
||||||
minHeight: '100%',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
padding: theme.spacing(12, 0),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
export default function ResetPassword() {
|
|
||||||
const [email, setEmail] = useState('');
|
|
||||||
|
|
||||||
const [sent, setSent] = useState(false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page title="Reset Password" sx={{ height: 1 }}>
|
|
||||||
<RootStyle>
|
|
||||||
<LogoOnlyLayout />
|
|
||||||
|
|
||||||
<Container>
|
|
||||||
<Box sx={{ maxWidth: 480, mx: 'auto' }}>
|
|
||||||
{!sent ? (
|
|
||||||
<>
|
|
||||||
<Typography variant="h3" paragraph>
|
|
||||||
Forgot your password?
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Typography sx={{ color: 'text.secondary', mb: 5 }}>
|
|
||||||
Please enter the email address associated with your account and We will email you
|
|
||||||
a link to reset your password.
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<ResetPasswordForm
|
|
||||||
onSent={() => setSent(true)}
|
|
||||||
onGetEmail={(value) => setEmail(value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
fullWidth
|
|
||||||
size="large"
|
|
||||||
component={RouterLink}
|
|
||||||
to={PATH_AUTH.login}
|
|
||||||
sx={{ mt: 1 }}
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Box sx={{ textAlign: 'center' }}>
|
|
||||||
<SentIcon sx={{ mb: 5, mx: 'auto', height: 160 }} />
|
|
||||||
|
|
||||||
<Typography variant="h3" gutterBottom>
|
|
||||||
Request sent successfully
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Typography>
|
|
||||||
We have sent a confirmation email to
|
|
||||||
<strong>{email}</strong>
|
|
||||||
<br />
|
|
||||||
Please check your email.
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
size="large"
|
|
||||||
variant="contained"
|
|
||||||
component={RouterLink}
|
|
||||||
to={PATH_AUTH.login}
|
|
||||||
sx={{ mt: 5 }}
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Container>
|
|
||||||
</RootStyle>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import { Link as RouterLink } from 'react-router-dom';
|
|
||||||
// @mui
|
|
||||||
import { styled } from '@mui/material/styles';
|
|
||||||
import { Box, Button, Link, Container, Typography } from '@mui/material';
|
|
||||||
// layouts
|
|
||||||
import LogoOnlyLayout from '../../layouts/LogoOnlyLayout';
|
|
||||||
// routes
|
|
||||||
import { PATH_AUTH } from '../../routes/paths';
|
|
||||||
// components
|
|
||||||
import Page from '../../components/Page';
|
|
||||||
import Iconify from '../../components/Iconify';
|
|
||||||
// sections
|
|
||||||
import { VerifyCodeForm } from '../../sections/auth/verify-code';
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
const RootStyle = styled('div')(({ theme }) => ({
|
|
||||||
display: 'flex',
|
|
||||||
height: '100%',
|
|
||||||
alignItems: 'center',
|
|
||||||
padding: theme.spacing(12, 0),
|
|
||||||
}));
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
export default function VerifyCode() {
|
|
||||||
return (
|
|
||||||
<Page title="Verify" sx={{ height: 1 }}>
|
|
||||||
<RootStyle>
|
|
||||||
<LogoOnlyLayout />
|
|
||||||
|
|
||||||
<Container>
|
|
||||||
<Box sx={{ maxWidth: 480, mx: 'auto' }}>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
component={RouterLink}
|
|
||||||
to={PATH_AUTH.login}
|
|
||||||
startIcon={<Iconify icon={'eva:arrow-ios-back-fill'} width={20} height={20} />}
|
|
||||||
sx={{ mb: 3 }}
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Typography variant="h3" paragraph>
|
|
||||||
Please check your email!
|
|
||||||
</Typography>
|
|
||||||
<Typography sx={{ color: 'text.secondary' }}>
|
|
||||||
We have emailed a 6-digit confirmation code to acb@domain, please enter the code in
|
|
||||||
below box to verify your email.
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Box sx={{ mt: 5, mb: 3 }}>
|
|
||||||
<VerifyCodeForm />
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Typography variant="body2" align="center">
|
|
||||||
Don’t have a code?
|
|
||||||
<Link variant="subtitle2" underline="none" onClick={() => {}}>
|
|
||||||
Resend code
|
|
||||||
</Link>
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
</Container>
|
|
||||||
</RootStyle>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ import LogoOnlyLayout from '../layouts/LogoOnlyLayout';
|
|||||||
// components
|
// components
|
||||||
import LoadingScreen from '../components/LoadingScreen';
|
import LoadingScreen from '../components/LoadingScreen';
|
||||||
import GuestGuard from '../guards/GuestGuard';
|
import GuestGuard from '../guards/GuestGuard';
|
||||||
import { RegisterForm } from '../sections/auth/register';
|
|
||||||
import { AuthProvider } from '../contexts/LaravelAuthContext';
|
import { AuthProvider } from '../contexts/LaravelAuthContext';
|
||||||
import AuthGuard from '../guards/AuthGuard';
|
import AuthGuard from '../guards/AuthGuard';
|
||||||
|
|
||||||
@@ -39,11 +38,11 @@ export default function Router() {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'register',
|
path: 'otp-validation',
|
||||||
element: (
|
element: (
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<GuestGuard>
|
<GuestGuard>
|
||||||
<RegisterForm />
|
<OtpValidation />
|
||||||
</GuestGuard>
|
</GuestGuard>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
),
|
),
|
||||||
@@ -113,6 +112,7 @@ export default function Router() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Login = Loadable(lazy(() => import('../pages/auth/Login')));
|
const Login = Loadable(lazy(() => import('../pages/auth/Login')));
|
||||||
|
const OtpValidation = Loadable(lazy(() => import('../pages/auth/OtpValidation')));
|
||||||
|
|
||||||
// Dashboard
|
// Dashboard
|
||||||
const Dashboard = Loadable(lazy(() => import('../pages/Dashboard')));
|
const Dashboard = Loadable(lazy(() => import('../pages/Dashboard')));
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ export default function LoginPhoneForm() {
|
|||||||
const onSubmit = async (data: FormValuesProps) => {
|
const onSubmit = async (data: FormValuesProps) => {
|
||||||
try {
|
try {
|
||||||
await axios.post('/otp-request', { phone_or_email: 0 + data.phone });
|
await axios.post('/otp-request', { phone_or_email: 0 + data.phone });
|
||||||
// console.log(response);
|
navigate('/auth/otp-validation', { state: { phone_or_email: 0 + data.phone } });
|
||||||
// navigate('/dashboard');
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
reset();
|
reset();
|
||||||
setError('afterSubmit', { ...error, message: error.response.data.message });
|
setError('afterSubmit', { ...error, message: error.response.data.message });
|
||||||
|
|||||||
@@ -1,110 +0,0 @@
|
|||||||
import * as Yup from 'yup';
|
|
||||||
import { useState } from 'react';
|
|
||||||
// form
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
|
||||||
// @mui
|
|
||||||
import { Stack, IconButton, InputAdornment, Alert } from '@mui/material';
|
|
||||||
import { LoadingButton } from '@mui/lab';
|
|
||||||
// hooks
|
|
||||||
import useAuth from '../../../hooks/useAuth';
|
|
||||||
import useIsMountedRef from '../../../hooks/useIsMountedRef';
|
|
||||||
// components
|
|
||||||
import Iconify from '../../../components/Iconify';
|
|
||||||
import { FormProvider, RHFTextField } from '../../../components/hook-form';
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
type FormValuesProps = {
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
firstName: string;
|
|
||||||
lastName: string;
|
|
||||||
afterSubmit?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function RegisterForm() {
|
|
||||||
const { register } = useAuth();
|
|
||||||
|
|
||||||
const isMountedRef = useIsMountedRef();
|
|
||||||
|
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
|
||||||
|
|
||||||
const RegisterSchema = Yup.object().shape({
|
|
||||||
firstName: Yup.string().required('First name required'),
|
|
||||||
lastName: Yup.string().required('Last name required'),
|
|
||||||
email: Yup.string().email('Email must be a valid email address').required('Email is required'),
|
|
||||||
password: Yup.string().required('Password is required'),
|
|
||||||
});
|
|
||||||
|
|
||||||
const defaultValues = {
|
|
||||||
firstName: '',
|
|
||||||
lastName: '',
|
|
||||||
email: '',
|
|
||||||
password: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
const methods = useForm<FormValuesProps>({
|
|
||||||
resolver: yupResolver(RegisterSchema),
|
|
||||||
defaultValues,
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
reset,
|
|
||||||
setError,
|
|
||||||
handleSubmit,
|
|
||||||
formState: { errors, isSubmitting },
|
|
||||||
} = methods;
|
|
||||||
|
|
||||||
const onSubmit = async (data: FormValuesProps) => {
|
|
||||||
try {
|
|
||||||
await register(data.email, data.password, data.firstName, data.lastName);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
reset();
|
|
||||||
if (isMountedRef.current) {
|
|
||||||
setError('afterSubmit', { ...error, message: error.message });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
|
||||||
<Stack spacing={3}>
|
|
||||||
{!!errors.afterSubmit && <Alert severity="error">{errors.afterSubmit.message}</Alert>}
|
|
||||||
|
|
||||||
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
|
|
||||||
<RHFTextField name="firstName" label="First name" />
|
|
||||||
<RHFTextField name="lastName" label="Last name" />
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<RHFTextField name="email" label="Email address" />
|
|
||||||
|
|
||||||
<RHFTextField
|
|
||||||
name="password"
|
|
||||||
label="Password"
|
|
||||||
type={showPassword ? 'text' : 'password'}
|
|
||||||
InputProps={{
|
|
||||||
endAdornment: (
|
|
||||||
<InputAdornment position="end">
|
|
||||||
<IconButton edge="end" onClick={() => setShowPassword(!showPassword)}>
|
|
||||||
<Iconify icon={showPassword ? 'eva:eye-fill' : 'eva:eye-off-fill'} />
|
|
||||||
</IconButton>
|
|
||||||
</InputAdornment>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<LoadingButton
|
|
||||||
fullWidth
|
|
||||||
size="large"
|
|
||||||
type="submit"
|
|
||||||
variant="contained"
|
|
||||||
loading={isSubmitting}
|
|
||||||
>
|
|
||||||
Register
|
|
||||||
</LoadingButton>
|
|
||||||
</Stack>
|
|
||||||
</FormProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default as RegisterForm } from './RegisterForm';
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import * as Yup from 'yup';
|
|
||||||
// form
|
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
// @mui
|
|
||||||
import { Stack } from '@mui/material';
|
|
||||||
import { LoadingButton } from '@mui/lab';
|
|
||||||
// hooks
|
|
||||||
import useIsMountedRef from '../../../hooks/useIsMountedRef';
|
|
||||||
// components
|
|
||||||
import { FormProvider, RHFTextField } from '../../../components/hook-form';
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
type FormValuesProps = {
|
|
||||||
email: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
onSent: VoidFunction;
|
|
||||||
onGetEmail: (value: string) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function ResetPasswordForm({ onSent, onGetEmail }: Props) {
|
|
||||||
const isMountedRef = useIsMountedRef();
|
|
||||||
|
|
||||||
const ResetPasswordSchema = Yup.object().shape({
|
|
||||||
email: Yup.string().email('Email must be a valid email address').required('Email is required'),
|
|
||||||
});
|
|
||||||
|
|
||||||
const methods = useForm<FormValuesProps>({
|
|
||||||
resolver: yupResolver(ResetPasswordSchema),
|
|
||||||
defaultValues: { email: 'demo@minimals.cc' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
handleSubmit,
|
|
||||||
formState: { isSubmitting },
|
|
||||||
} = methods;
|
|
||||||
|
|
||||||
const onSubmit = async (data: FormValuesProps) => {
|
|
||||||
try {
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
||||||
if (isMountedRef.current) {
|
|
||||||
onSent();
|
|
||||||
onGetEmail(data.email);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
|
||||||
<Stack spacing={3}>
|
|
||||||
<RHFTextField name="email" label="Email address" />
|
|
||||||
|
|
||||||
<LoadingButton
|
|
||||||
fullWidth
|
|
||||||
size="large"
|
|
||||||
type="submit"
|
|
||||||
variant="contained"
|
|
||||||
loading={isSubmitting}
|
|
||||||
>
|
|
||||||
Reset Password
|
|
||||||
</LoadingButton>
|
|
||||||
</Stack>
|
|
||||||
</FormProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default as ResetPasswordForm } from './ResetPasswordForm';
|
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from 'notistack';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate, useLocation } 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
|
// @mui
|
||||||
import { OutlinedInput, Stack } from '@mui/material';
|
import { OutlinedInput, Stack } from '@mui/material';
|
||||||
import { LoadingButton } from '@mui/lab';
|
|
||||||
// routes
|
// routes
|
||||||
// import { PATH_DASHBOARD } from '../../../routes/paths';
|
// import { PATH_DASHBOARD } from '../../../routes/paths';
|
||||||
|
|
||||||
@@ -18,24 +17,22 @@ type FormValuesProps = {
|
|||||||
code2: string;
|
code2: string;
|
||||||
code3: string;
|
code3: string;
|
||||||
code4: string;
|
code4: string;
|
||||||
code5: string;
|
|
||||||
code6: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ValueNames = 'code1' | 'code2' | 'code3' | 'code4' | 'code5' | 'code6';
|
type ValueNames = 'code1' | 'code2' | 'code3' | 'code4';
|
||||||
|
|
||||||
export default function VerifyCodeForm() {
|
export default function VerifyCodeForm() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
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'),
|
||||||
code2: Yup.string().required('Code is required'),
|
code2: Yup.string().required('Code is required'),
|
||||||
code3: Yup.string().required('Code is required'),
|
code3: Yup.string().required('Code is required'),
|
||||||
code4: Yup.string().required('Code is required'),
|
code4: Yup.string().required('Code is required'),
|
||||||
code5: Yup.string().required('Code is required'),
|
|
||||||
code6: Yup.string().required('Code is required'),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
@@ -43,8 +40,6 @@ export default function VerifyCodeForm() {
|
|||||||
code2: '',
|
code2: '',
|
||||||
code3: '',
|
code3: '',
|
||||||
code4: '',
|
code4: '',
|
||||||
code5: '',
|
|
||||||
code6: '',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -62,6 +57,7 @@ export default function VerifyCodeForm() {
|
|||||||
const values = watch();
|
const values = watch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log('phone number : ' + phone_or_email);
|
||||||
document.addEventListener('paste', handlePasteClipboard);
|
document.addEventListener('paste', handlePasteClipboard);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
@@ -73,7 +69,7 @@ export default function VerifyCodeForm() {
|
|||||||
|
|
||||||
enqueueSnackbar('Verify success!');
|
enqueueSnackbar('Verify success!');
|
||||||
|
|
||||||
navigate('/dashboard', { replace: true });
|
// navigate('/dashboard', { replace: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
@@ -114,7 +110,7 @@ export default function VerifyCodeForm() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onChange={handleSubmit(onSubmit)}>
|
||||||
<Stack direction="row" spacing={2} justifyContent="center">
|
<Stack direction="row" spacing={2} justifyContent="center">
|
||||||
{Object.keys(values).map((name, index) => (
|
{Object.keys(values).map((name, index) => (
|
||||||
<Controller
|
<Controller
|
||||||
@@ -144,18 +140,6 @@ export default function VerifyCodeForm() {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<LoadingButton
|
|
||||||
fullWidth
|
|
||||||
size="large"
|
|
||||||
type="submit"
|
|
||||||
variant="contained"
|
|
||||||
loading={isSubmitting}
|
|
||||||
disabled={!isValid}
|
|
||||||
sx={{ mt: 3 }}
|
|
||||||
>
|
|
||||||
Verify
|
|
||||||
</LoadingButton>
|
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user