Separate Client Portal & Dashboard

This commit is contained in:
2022-05-23 10:38:16 +07:00
parent f2e84e6244
commit 89bb57f357
569 changed files with 60252 additions and 280 deletions

View File

@@ -0,0 +1,38 @@
// @mui
import { Grid, Button, Divider, Typography } from '@mui/material';
// components
import Iconify from '../../components/Iconify';
// ----------------------------------------------------------------------
export default function AuthFirebaseSocial() {
return (
<>
<Grid container spacing={2}>
<Grid item xs>
<Button fullWidth size="large" color="inherit" variant="outlined">
<Iconify icon={'eva:google-fill'} color="#DF3E30" width={24} height={24} />
</Button>
</Grid>
<Grid item xs>
<Button fullWidth size="large" color="inherit" variant="outlined">
<Iconify icon={'eva:facebook-fill'} color="#1877F2" width={24} height={24} />
</Button>
</Grid>
<Grid item xs>
<Button fullWidth size="large" color="inherit" variant="outlined">
<Iconify icon={'eva:twitter-fill'} color="#1C9CEA" width={24} height={24} />
</Button>
</Grid>
</Grid>
<Divider sx={{ my: 3 }}>
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
OR
</Typography>
</Divider>
</>
);
}

View File

@@ -0,0 +1,115 @@
import * as Yup from 'yup';
import { useState } from 'react';
import { Link as RouterLink, useNavigate } from 'react-router-dom';
// form
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
// @mui
import { Link, Stack, Alert, IconButton, InputAdornment } from '@mui/material';
import { LoadingButton } from '@mui/lab';
// routes
import { PATH_AUTH } from '../../../routes/paths';
// hooks
import useAuth from '../../../hooks/useAuth';
import useIsMountedRef from '../../../hooks/useIsMountedRef';
// components
import Iconify from '../../../components/Iconify';
import { FormProvider, RHFTextField, RHFCheckbox } from '../../../components/hook-form';
// ----------------------------------------------------------------------
type FormValuesProps = {
email: string;
password: string;
remember: boolean;
afterSubmit?: string;
};
export default function LoginForm() {
const { login } = useAuth();
const navigate = useNavigate();
const isMountedRef = useIsMountedRef();
const [showPassword, setShowPassword] = useState(false);
const LoginSchema = Yup.object().shape({
email: Yup.string().email('Email must be a valid email address').required('Email is required'),
password: Yup.string().required('Password is required'),
});
const defaultValues = {
email: '',
password: '',
remember: true,
};
const methods = useForm<FormValuesProps>({
resolver: yupResolver(LoginSchema),
defaultValues,
});
const {
reset,
setError,
handleSubmit,
formState: { errors, isSubmitting },
} = methods;
const onSubmit = async (data: FormValuesProps) => {
try {
await login(data.email, data.password );
navigate('/dashboard/one');
} 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>}
<RHFTextField name="email" label="Email address" />
<RHFTextField
name="password"
label="Password"
type={showPassword ? 'text' : 'password'}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => setShowPassword(!showPassword)} edge="end">
<Iconify icon={showPassword ? 'eva:eye-fill' : 'eva:eye-off-fill'} />
</IconButton>
</InputAdornment>
),
}}
/>
</Stack>
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ my: 2 }}>
<RHFCheckbox name="remember" label="Remember me" />
<Link component={RouterLink} variant="subtitle2" to={PATH_AUTH.resetPassword}>
Forgot password?
</Link>
</Stack>
<LoadingButton
fullWidth
size="large"
type="submit"
variant="contained"
loading={isSubmitting}
>
Login
</LoadingButton>
</FormProvider>
);
}

View File

@@ -0,0 +1 @@
export { default as LoginForm } from './LoginForm';

View File

@@ -0,0 +1,110 @@
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>
);
}

View File

@@ -0,0 +1 @@
export { default as RegisterForm } from './RegisterForm';

View File

@@ -0,0 +1,70 @@
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>
);
}

View File

@@ -0,0 +1 @@
export { default as ResetPasswordForm } from './ResetPasswordForm';

View File

@@ -0,0 +1,161 @@
import * as Yup from 'yup';
import { useSnackbar } from 'notistack';
import { useNavigate } from 'react-router-dom';
import { useEffect } from 'react';
// form
import { useForm, Controller } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
// @mui
import { OutlinedInput, Stack } from '@mui/material';
import { LoadingButton } from '@mui/lab';
// routes
// import { PATH_DASHBOARD } from '../../../routes/paths';
// ----------------------------------------------------------------------
type FormValuesProps = {
code1: string;
code2: string;
code3: string;
code4: string;
code5: string;
code6: string;
};
type ValueNames = 'code1' | 'code2' | 'code3' | 'code4' | 'code5' | 'code6';
export default function VerifyCodeForm() {
const navigate = useNavigate();
const { enqueueSnackbar } = useSnackbar();
const VerifyCodeSchema = Yup.object().shape({
code1: Yup.string().required('Code is required'),
code2: Yup.string().required('Code is required'),
code3: 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 = {
code1: '',
code2: '',
code3: '',
code4: '',
code5: '',
code6: '',
};
const {
watch,
control,
setValue,
handleSubmit,
formState: { isSubmitting, isValid },
} = useForm({
mode: 'onBlur',
resolver: yupResolver(VerifyCodeSchema),
defaultValues,
});
const values = watch();
useEffect(() => {
document.addEventListener('paste', handlePasteClipboard);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const onSubmit = async (data: FormValuesProps) => {
try {
await new Promise((resolve) => setTimeout(resolve, 500));
console.log('code:', Object.values(data).join(''));
enqueueSnackbar('Verify success!');
navigate('/dashboard', { replace: true });
} catch (error) {
console.error(error);
}
};
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 = (
event: React.ChangeEvent<HTMLInputElement>,
handleChange: (event: React.ChangeEvent<HTMLInputElement>) => void
) => {
const { maxLength, value, name } = event.target;
const fieldIndex = name.replace('code', '');
const fieldIntIndex = Number(fieldIndex);
if (value.length >= maxLength) {
if (fieldIntIndex < 6) {
const nextfield = document.querySelector(`input[name=code${fieldIntIndex + 1}]`);
if (nextfield !== null) {
(nextfield as HTMLElement).focus();
}
}
}
handleChange(event);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Stack direction="row" spacing={2} justifyContent="center">
{Object.keys(values).map((name, index) => (
<Controller
key={name}
name={`code${index + 1}` as ValueNames}
control={control}
render={({ field }) => (
<OutlinedInput
{...field}
id="field-code"
autoFocus={index === 0}
placeholder="-"
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
handleChangeWithNextField(event, field.onChange)
}
inputProps={{
maxLength: 1,
sx: {
p: 0,
textAlign: 'center',
width: { xs: 36, sm: 56 },
height: { xs: 36, sm: 56 },
},
}}
/>
)}
/>
))}
</Stack>
<LoadingButton
fullWidth
size="large"
type="submit"
variant="contained"
loading={isSubmitting}
disabled={!isValid}
sx={{ mt: 3 }}
>
Verify
</LoadingButton>
</form>
);
}

View File

@@ -0,0 +1 @@
export { default as VerifyCodeForm } from './VerifyCodeForm';