feat: admin staff management
This commit is contained in:
parent
60d187b300
commit
3061b88343
|
|
@ -0,0 +1,10 @@
|
|||
import { useMemo } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
const useQuery = () => {
|
||||
const { search } = useLocation();
|
||||
|
||||
return useMemo(() => new URLSearchParams(search), [search]);
|
||||
};
|
||||
|
||||
export default useQuery;
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
|
||||
const useScript = ({
|
||||
src,
|
||||
async = true,
|
||||
type = 'text/javascript',
|
||||
noModule = false,
|
||||
}) => {
|
||||
const [status, setStatus] = useState(src ? 'loading' : 'idle');
|
||||
|
||||
useEffect(() => {
|
||||
if (!src) {
|
||||
setStatus('idle');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the script is already present
|
||||
let script = document.querySelector(`script[src="${src}"]`);
|
||||
|
||||
if (!script) {
|
||||
// Create script element and add it to the document head
|
||||
script = document.createElement('script');
|
||||
script.src = src;
|
||||
script.async = async;
|
||||
script.type = type;
|
||||
script.noModule = noModule;
|
||||
|
||||
// Set initial status
|
||||
setStatus('loading');
|
||||
|
||||
// Script event listeners
|
||||
const onScriptLoad = () => setStatus('ready');
|
||||
const onScriptError = () => setStatus('error');
|
||||
|
||||
script.addEventListener('load', onScriptLoad);
|
||||
script.addEventListener('error', onScriptError);
|
||||
|
||||
document.head.appendChild(script);
|
||||
|
||||
// Cleanup function
|
||||
return () => {
|
||||
script.removeEventListener('load', onScriptLoad);
|
||||
script.removeEventListener('error', onScriptError);
|
||||
document.head.removeChild(script);
|
||||
};
|
||||
} else {
|
||||
// If script is already present, update status accordingly
|
||||
setStatus('ready');
|
||||
}
|
||||
}, [src, async, type, noModule]);
|
||||
|
||||
return status;
|
||||
};
|
||||
|
||||
export default useScript;
|
||||
|
|
@ -10,10 +10,11 @@ import MockPayment from "../views/MockPayment";
|
|||
import Users from "../views/User";
|
||||
import ClinicSetup from "../views/ClinicSetup";
|
||||
import ClinicTranscripts from "../views/ClinicTranscripts";
|
||||
import ContractManagement from "../views/ContractManagement";
|
||||
import MasterDataManagement from "../views/MasterData";
|
||||
import PaymentManagement from "../views/PaymentManagement";
|
||||
import ClinicDocUpdater from "../views/ClinicDocUpdate";
|
||||
import ForgotPassword from "../views/ForgotPassword";
|
||||
import ResetPassword from "../views/ResetPassword";
|
||||
|
||||
export const routesData = [
|
||||
{
|
||||
|
|
@ -43,6 +44,14 @@ export const routesData = [
|
|||
path: "signup/your-details",
|
||||
component: YourDetailsForm,
|
||||
},
|
||||
{
|
||||
path: "forgotpassword",
|
||||
component: ForgotPassword,
|
||||
},
|
||||
{
|
||||
path: 'reset-password',
|
||||
component: ResetPassword,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,38 +1,83 @@
|
|||
import { axiosInstance } from "../config/api";
|
||||
|
||||
export const signup = (data) => {
|
||||
const url = '/auth/register';
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
const url = "/auth/register";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const createAdmin = (data) => {
|
||||
const url = "/admin/user";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const getAdmins = (params) => {
|
||||
|
||||
let searchParams = new URLSearchParams();
|
||||
searchParams.append("size", params?.pagination?.pageSize ?? 10);
|
||||
searchParams.append("page", params?.pagination.pageIndex ?? 0);
|
||||
searchParams.append("search", params?.globalFilter ?? "");
|
||||
|
||||
const url = `/admin/?${searchParams.toString()}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const getEmailOtp = (data) => {
|
||||
const url = '/auth/send-otp';
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, null, { params: data })
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
const url = "/auth/send-otp";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, null, { params: data })
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const verifyOtp = (data) => {
|
||||
const url = '/auth/verify-otp';
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
.catch((err) => {
|
||||
if(err.status==200){
|
||||
resolve(err)
|
||||
}else{
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
.then((response) => resolve(response))
|
||||
});
|
||||
};
|
||||
export const verifyOtp = (data) => {
|
||||
const url = "/auth/verify-otp";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
.catch((err) => {
|
||||
if (err.status == 200) {
|
||||
resolve(err);
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
})
|
||||
.then((response) => resolve(response));
|
||||
});
|
||||
};
|
||||
|
||||
export const forgotPassword = (data) => {
|
||||
const url = "/auth/admin/forget-password";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, null, { params: data })
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const resetPassword = (data) => {
|
||||
const url = "/auth/admin/reset-password";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
import { LoadingButton } from '@mui/lab';
|
||||
import { Box, InputLabel, TextField, Typography } from '@mui/material';
|
||||
import { useFormik } from 'formik';
|
||||
import { useRef } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import { NOTIFICATION } from '../../constants';
|
||||
import { forgotPassword } from '../../services/auth.services';
|
||||
import { pushNotification } from '../../utils/notification';
|
||||
import { useStyles } from './forgotPasswordStyles';
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.email('Invalid Email Address')
|
||||
.required('Email is required'),
|
||||
});
|
||||
|
||||
function ForgotPasswordForm({ onSubmit, setEmail }) {
|
||||
const classes = useStyles();
|
||||
|
||||
const emailRef = useRef(null);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: { email: '' },
|
||||
validationSchema,
|
||||
onSubmit: async (values) => {
|
||||
try {
|
||||
const response = await forgotPassword(values);
|
||||
if (response.status === 200) {
|
||||
// setTimer(15);
|
||||
setEmail(values.email);
|
||||
// setShowButton(false);
|
||||
pushNotification(response?.data?.message, NOTIFICATION.SUCCESS);
|
||||
onSubmit();
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.response?.data?.message) {
|
||||
formik.setErrors({
|
||||
email: error?.response?.data?.message,
|
||||
});
|
||||
emailRef.current.focus();
|
||||
}
|
||||
} finally {
|
||||
formik.setSubmitting(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmitClick = async (e) => {
|
||||
e.preventDefault();
|
||||
const formikError = await formik.validateForm();
|
||||
const errors = Object.keys(formikError);
|
||||
|
||||
if (errors.length) {
|
||||
// Find the first invalid field and focus it
|
||||
const firstErrorField = errors[0];
|
||||
const firstErrorRef = emailRef?.current;
|
||||
|
||||
if (firstErrorRef) {
|
||||
// Scroll to the first invalid field smoothly
|
||||
if (typeof firstErrorRef?.scrollIntoView === 'function') {
|
||||
firstErrorRef?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
});
|
||||
}
|
||||
|
||||
// Focus the field after a slight delay (to ensure scrolling completes first)
|
||||
setTimeout(() => firstErrorRef.focus(), 300);
|
||||
}
|
||||
|
||||
// Show error notification
|
||||
if (formik?.touched[firstErrorField])
|
||||
pushNotification(formikError[firstErrorField], NOTIFICATION.ERROR);
|
||||
}
|
||||
|
||||
formik.handleSubmit();
|
||||
};
|
||||
|
||||
return (
|
||||
<Box className={classes.right}>
|
||||
<form onSubmit={handleSubmitClick} className={classes.form}>
|
||||
<Box className={classes.formBody}>
|
||||
<Box className={classes.formHeader}>
|
||||
<Typography className={classes.subHeading}>
|
||||
Please provide the email address that you used when you signed up
|
||||
for your account.
|
||||
</Typography>
|
||||
</Box>
|
||||
<InputLabel
|
||||
shrink={false}
|
||||
htmlFor={'email'}
|
||||
className={classes.labelStyle}
|
||||
>
|
||||
<Typography
|
||||
className={classes.inputTitle}
|
||||
style={{
|
||||
fontSize: '0.8rem',
|
||||
}}
|
||||
>
|
||||
Email Address*
|
||||
</Typography>
|
||||
</InputLabel>
|
||||
<TextField
|
||||
style={{ marginTop: '2px' }}
|
||||
color="secondary"
|
||||
placeholder="Enter Email ID"
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
fullWidth
|
||||
name="email"
|
||||
value={formik.values.email}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
inputRef={emailRef}
|
||||
error={Boolean(formik.errors.email && formik.touched.email)}
|
||||
helperText={
|
||||
formik.errors.email && formik.touched.email
|
||||
? formik.errors.email
|
||||
: ''
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
{/* )} */}
|
||||
<Typography className={classes.sendEmailText}>
|
||||
We will send you an email that will allow you to reset your password.
|
||||
</Typography>
|
||||
<LoadingButton
|
||||
size="large"
|
||||
type="submit"
|
||||
variant="contained"
|
||||
className={classes.submitButton}
|
||||
loading={formik.isSubmitting}
|
||||
>
|
||||
Reset Password
|
||||
</LoadingButton>
|
||||
{/* <Box className={classes.formFooter}>
|
||||
<Typography className={classes.emailText}>
|
||||
If you no longer have access to this email account, please contact
|
||||
our support team at
|
||||
</Typography>
|
||||
<Typography className={classes.emailText}>
|
||||
<a href={`mailto:${CONTACT_EMAIL}`}>{CONTACT_EMAIL}</a>
|
||||
</Typography>
|
||||
</Box> */}
|
||||
</form>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ForgotPasswordForm;
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
import makeStyles from '@mui/styles/makeStyles';
|
||||
import backgroundImage from '../../assets/images/background/background.jpg';
|
||||
import { pxToRem } from '../../theme/typography';
|
||||
|
||||
export const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
height: '100vh',
|
||||
backgroundImage: `url(${backgroundImage})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
card: {
|
||||
width: '370px',
|
||||
maxHeight: '835px',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: '500px',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '500px',
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
width: '500px',
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
width: '500px',
|
||||
maxHeight: '735px',
|
||||
},
|
||||
boxShadow: 'none',
|
||||
borderRadius: theme.spacing(3.8),
|
||||
opacity: '0.95',
|
||||
},
|
||||
forgotPasswordHeader: {
|
||||
marginTop: theme.spacing(4.5),
|
||||
},
|
||||
right: {
|
||||
textAlign: 'center',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
form: {
|
||||
width: '65%',
|
||||
},
|
||||
formBody: {
|
||||
justifyContent: 'start',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
// height: '162.5px',
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
// height: '234px',
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
// height: '325px',
|
||||
},
|
||||
|
||||
'& .MuiTextField-root': {
|
||||
marginTop: theme.spacing(0.8),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
marginTop: theme.spacing(0.8),
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
marginTop: theme.spacing(0.8),
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
marginTop: theme.spacing(4),
|
||||
},
|
||||
},
|
||||
},
|
||||
formHeader: {
|
||||
marginTop: theme.spacing(1.2),
|
||||
marginBottom: theme.spacing(3),
|
||||
},
|
||||
formFooter: {
|
||||
marginBottom: theme.spacing(4.0),
|
||||
},
|
||||
heading: {
|
||||
fontFamily: 'Inter-Bold',
|
||||
// width: '70%',
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-start',
|
||||
lineHeight: 1.2,
|
||||
fontSize: pxToRem(27),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
fontSize: pxToRem(27),
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
fontSize: pxToRem(27),
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
fontSize: pxToRem(27),
|
||||
},
|
||||
},
|
||||
subHeading: {
|
||||
lineHeight: 1.1,
|
||||
textAlign: 'left',
|
||||
fontSize: pxToRem(12),
|
||||
marginTop: theme.spacing(0),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
fontSize: pxToRem(13),
|
||||
marginTop: theme.spacing(0),
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
fontSize: pxToRem(13),
|
||||
marginTop: theme.spacing(0),
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
fontSize: pxToRem(13),
|
||||
marginTop: theme.spacing(0),
|
||||
},
|
||||
},
|
||||
labelStyle: {
|
||||
marginBottom: '0px',
|
||||
fontSize: pxToRem(3.2),
|
||||
color: theme.palette.grey[10],
|
||||
// paddingBottom: '20px',
|
||||
},
|
||||
inputTitle: {
|
||||
'&.MuiTypography-body1': {
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.grey[10],
|
||||
},
|
||||
fontSize: pxToRem(12),
|
||||
textAlign: 'left',
|
||||
// opacity: '0.54',
|
||||
color: theme.palette.grey[10],
|
||||
marginBottom: theme.spacing(0.6),
|
||||
marginLeft: theme.spacing(0.6),
|
||||
},
|
||||
icon: {
|
||||
cursor: 'pointer',
|
||||
paddingLeft: '30px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '50px',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '50px',
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
width: '50px',
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
width: '50px',
|
||||
},
|
||||
},
|
||||
submitButton: {
|
||||
fontFamily: 'Inter-Regular',
|
||||
fontWeight: 500,
|
||||
marginTop: theme.spacing(1.0),
|
||||
marginBottom: theme.spacing(3.0),
|
||||
fontSize: pxToRem(12.8),
|
||||
justifyContent: 'center',
|
||||
borderRadius: '6px',
|
||||
padding: '20px',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: '20px',
|
||||
fontSize: pxToRem(12.8),
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
padding: '20px',
|
||||
fontSize: pxToRem(12.8),
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
height: '10px',
|
||||
fontSize: pxToRem(12.8),
|
||||
},
|
||||
},
|
||||
sendEmailText: {
|
||||
marginTop: theme.spacing(2.0),
|
||||
textAlign: 'left',
|
||||
fontSize: pxToRem(10.4),
|
||||
},
|
||||
emailText: {
|
||||
lineHeight: 1.1,
|
||||
fontSize: pxToRem(12.48),
|
||||
},
|
||||
emailSentMainDiv: {
|
||||
width: '70%',
|
||||
paddingTop: theme.spacing(3.4),
|
||||
paddingBottom: theme.spacing(7.0),
|
||||
fontSize: pxToRem(12.8),
|
||||
},
|
||||
}));
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
import { ArrowBackOutlined } from '@mui/icons-material';
|
||||
import { Box, Card, Grid, Typography } from '@mui/material';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import ForgotPasswordForm from './ForgotPasswordForm';
|
||||
import { useStyles } from './forgotPasswordStyles';
|
||||
import { useState } from 'react';
|
||||
|
||||
function ForgotPassword() {
|
||||
const navigate = useNavigate();
|
||||
const classes = useStyles();
|
||||
const [resetPasswordLinkSend, setResetPasswordLinkSend] = useState(false);
|
||||
const [email, setEmail] = useState('');
|
||||
|
||||
const handleFormSubmit = () => {
|
||||
setResetPasswordLinkSend(true);
|
||||
};
|
||||
const handleGoBackClick = () => {
|
||||
navigate('/auth/login');
|
||||
};
|
||||
return (
|
||||
<Box className={classes.root}>
|
||||
<Card className={classes.card}>
|
||||
<Grid container display="flex" justifyContent="center">
|
||||
{!resetPasswordLinkSend ? (
|
||||
<Grid item xs={12}>
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
className={classes.forgotPasswordHeader}
|
||||
>
|
||||
<Grid item xs={2}>
|
||||
<ArrowBackOutlined
|
||||
className={classes.icon}
|
||||
onClick={handleGoBackClick}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<Typography variant="Inter-bold" className={classes.heading}>
|
||||
Reset your Password
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Box>
|
||||
<ForgotPasswordForm
|
||||
onSubmit={handleFormSubmit}
|
||||
setEmail={setEmail}
|
||||
/>
|
||||
</Grid>
|
||||
) : (
|
||||
<Box className={classes.emailSentMainDiv}>
|
||||
{/* <Box width="90%"> */}
|
||||
<Typography
|
||||
variant="Gilroy-SemiBold"
|
||||
className={classes.heading}
|
||||
marginBottom="20px"
|
||||
>
|
||||
Email Sent
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="Gilroy-normal"
|
||||
className={classes.subheading}
|
||||
// marginBottom="30px"
|
||||
>
|
||||
{/* {` An email with instructions on how to reset your password has
|
||||
been sent to ${email}. It is valid for next 24 hrs.
|
||||
Check your spam or junk folder if you don’t see the email in
|
||||
your inbox.`} */}
|
||||
{`An email with instructions on how to reset your password has
|
||||
been sent to `}
|
||||
<span style={{ fontWeight: 'bold' }}>{email}</span>
|
||||
{`. It is valid for the next 24 hrs. Check your spam or junk folder if you don’t see the email in
|
||||
your inbox.`}
|
||||
</Typography>
|
||||
{/* </Box> */}
|
||||
</Box>
|
||||
)}
|
||||
</Grid>
|
||||
</Card>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ForgotPassword;
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
import { LoadingButton } from '@mui/lab';
|
||||
import {
|
||||
Box,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
TextField,
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import { useFormik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import { useStyles } from './resetPasswordStyles';
|
||||
import { useRef, useState } from 'react';
|
||||
import PasswordValidation from '../Login/component/PasswordValidation';
|
||||
import { VisibilityOffOutlined, VisibilityOutlined } from '@mui/icons-material';
|
||||
import useQuery from '../../hooks/useQuery';
|
||||
import {
|
||||
passwordLengthRegex,
|
||||
passwordLetterRegex,
|
||||
passwordNumberRegex,
|
||||
passwordSpacesRegex,
|
||||
} from '../../utils/regex';
|
||||
import { pushNotification } from '../../utils/notification';
|
||||
import { NOTIFICATION } from '../../constants';
|
||||
import { resetPassword } from '../../services/auth.services';
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
password: Yup.string()
|
||||
.matches(passwordLengthRegex, 'Password must be at least 8 characters')
|
||||
.matches(passwordLetterRegex, 'Password must contain at least one letter')
|
||||
.matches(passwordNumberRegex, 'Password must contain at least one number')
|
||||
.matches(passwordSpacesRegex, 'Password must not start or end with a space')
|
||||
.required('Password is required'),
|
||||
confirmPassword: Yup.string()
|
||||
.oneOf([Yup.ref('password'), null], 'Passwords must match')
|
||||
.required('Passwords must match'),
|
||||
});
|
||||
|
||||
function ResetPasswordForm({ onSubmit }) {
|
||||
const query = useQuery();
|
||||
const classes = useStyles();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||
|
||||
const fieldRefs = {
|
||||
password: useRef(null),
|
||||
confirmPassword: useRef(null),
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: { password: '', confirmPassword: '' },
|
||||
validationSchema,
|
||||
onSubmit: (values) => handleSubmit(values, formik),
|
||||
});
|
||||
|
||||
const handleSubmit = async (values, formik) => {
|
||||
try {
|
||||
values.token = query.get('token');
|
||||
|
||||
const requestBody = {
|
||||
token: values.token,
|
||||
password: values.password,
|
||||
};
|
||||
|
||||
const response = await resetPassword(requestBody);
|
||||
if (response.status === 200) {
|
||||
pushNotification(response?.data?.message, NOTIFICATION.SUCCESS);
|
||||
}
|
||||
onSubmit();
|
||||
} catch (error) {
|
||||
return;
|
||||
} finally {
|
||||
formik.setSubmitting(false);
|
||||
formik.resetForm();
|
||||
}
|
||||
};
|
||||
const handleTogglePasswordVisibility = (field) => {
|
||||
if (field === 'password') {
|
||||
setShowPassword((prevShowPassword) => !prevShowPassword);
|
||||
} else if (field === 'confirmPassword') {
|
||||
setShowConfirmPassword(
|
||||
(prevShowConfirmPassword) => !prevShowConfirmPassword
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmitClick = async (e) => {
|
||||
e.preventDefault();
|
||||
const formikErrors = await formik.validateForm();
|
||||
const errors = Object.keys(formikErrors);
|
||||
|
||||
if (errors.length) {
|
||||
// Find the first invalid field and focus it
|
||||
const firstErrorField = errors[0];
|
||||
const firstErrorRef = fieldRefs[firstErrorField]?.current;
|
||||
|
||||
if (firstErrorRef) {
|
||||
// Scroll to the first invalid field smoothly
|
||||
if (typeof firstErrorRef?.scrollIntoView === 'function') {
|
||||
firstErrorRef?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
});
|
||||
}
|
||||
|
||||
// Focus the field after a slight delay (to ensure scrolling completes first)
|
||||
setTimeout(() => firstErrorRef.focus(), 300);
|
||||
}
|
||||
|
||||
// Show error notification
|
||||
if (formik?.touched[firstErrorField])
|
||||
pushNotification(formikErrors[firstErrorField], NOTIFICATION.ERROR);
|
||||
}
|
||||
|
||||
formik.handleSubmit();
|
||||
};
|
||||
|
||||
return (
|
||||
<Box className={classes.right}>
|
||||
<form onSubmit={handleSubmitClick} className={classes.form}>
|
||||
<Box className={classes.formBody}>
|
||||
<Box className={classes.formHeader}>
|
||||
<Typography className={classes.subHeading}>
|
||||
Note: Password must be at least 8 characters, contain 1 letter and
|
||||
1 number, with no spaces at the beginning/end.
|
||||
</Typography>
|
||||
</Box>
|
||||
<InputLabel
|
||||
shrink={false}
|
||||
htmlFor={'password'}
|
||||
className={classes.labelStyle}
|
||||
>
|
||||
<Typography className={classes.inputTitle}>
|
||||
Enter New Password
|
||||
</Typography>
|
||||
</InputLabel>
|
||||
<TextField
|
||||
color="secondary"
|
||||
placeholder="Enter Password"
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
fullWidth
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
name="password"
|
||||
value={formik.values.password}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
inputRef={fieldRefs.password}
|
||||
error={Boolean(formik.errors.password && formik.touched.password)}
|
||||
helperText={
|
||||
formik.errors.password && formik.touched.password
|
||||
? formik.errors.password
|
||||
: ''
|
||||
}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<IconButton
|
||||
onClick={() => handleTogglePasswordVisibility('password')}
|
||||
edge="end"
|
||||
>
|
||||
{!showPassword ? (
|
||||
<VisibilityOffOutlined />
|
||||
) : (
|
||||
<VisibilityOutlined />
|
||||
)}
|
||||
</IconButton>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
{/* Password validation display */}
|
||||
{!formik.isValid && (
|
||||
<>
|
||||
<Typography className={classes.passwordCheckListTitle}>
|
||||
Note: Password must be
|
||||
</Typography>
|
||||
<Box className={classes.passwordCheckList}>
|
||||
<PasswordValidation
|
||||
isValid={passwordLengthRegex.test(formik.values.password)}
|
||||
text="at least 6 characters"
|
||||
/>
|
||||
<PasswordValidation
|
||||
isValid={passwordLetterRegex.test(formik.values.password)}
|
||||
text="at least 1 letter"
|
||||
/>
|
||||
<PasswordValidation
|
||||
isValid={passwordNumberRegex.test(formik.values.password)}
|
||||
text="at least 1 number"
|
||||
/>
|
||||
<PasswordValidation
|
||||
isValid={passwordSpacesRegex.test(formik.values.password)}
|
||||
text="with no spaces at the beginning/end"
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
<Box className={classes.confirmResetBox}>
|
||||
<InputLabel
|
||||
shrink={false}
|
||||
htmlFor={'confirmPassword'}
|
||||
className={classes.labelStyle}
|
||||
>
|
||||
<Typography className={classes.inputTitle}>
|
||||
Confirm New Password
|
||||
</Typography>
|
||||
</InputLabel>
|
||||
<TextField
|
||||
className={classes.resetPasswordTextField}
|
||||
color="secondary"
|
||||
placeholder="Confirm Password"
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
fullWidth
|
||||
type={showConfirmPassword ? 'text' : 'password'}
|
||||
name="confirmPassword"
|
||||
value={formik.values.confirmPassword}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
inputRef={fieldRefs.confirmPassword}
|
||||
error={Boolean(
|
||||
formik.errors.confirmPassword && formik.touched.confirmPassword
|
||||
)}
|
||||
helperText={
|
||||
formik.errors.confirmPassword && formik.touched.confirmPassword
|
||||
? formik.errors.confirmPassword
|
||||
: ''
|
||||
}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
handleTogglePasswordVisibility('confirmPassword')
|
||||
}
|
||||
edge="end"
|
||||
>
|
||||
{!showConfirmPassword ? (
|
||||
<VisibilityOffOutlined />
|
||||
) : (
|
||||
<VisibilityOutlined />
|
||||
)}
|
||||
</IconButton>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<LoadingButton
|
||||
size="large"
|
||||
type="submit"
|
||||
variant="contained"
|
||||
className={classes.submitButton}
|
||||
loading={formik.isSubmitting}
|
||||
>
|
||||
Save New Password
|
||||
</LoadingButton>
|
||||
</form>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ResetPasswordForm;
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
import { Box, Card, Grid, Typography } from '@mui/material';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import ResetPasswordForm from './ResetPasswordForm';
|
||||
import { useStyles } from './resetPasswordStyles';
|
||||
import { useState } from 'react';
|
||||
import ResetPasswordSuccessIcon from '../../assets/images/icon/ResetPasswordSuccessIcon.png';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
|
||||
function ResetPassword() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const classes = useStyles();
|
||||
const [resetPasswordLinkSend, setResetPasswordLinkSend] = useState(false);
|
||||
const handleFormSubmit = () => {
|
||||
setResetPasswordLinkSend(true);
|
||||
};
|
||||
|
||||
// Function to get URL parameters
|
||||
const getQueryParams = () => new URLSearchParams(location.search);
|
||||
|
||||
// Determine if we are resetting or creating a password based on URL params
|
||||
const queryParams = getQueryParams();
|
||||
const isCreatePassword = queryParams.get('createPassword') === 'true';
|
||||
|
||||
const headingText = !isCreatePassword ? 'Reset' : 'Create';
|
||||
const successMessage = !isCreatePassword
|
||||
? 'Password Reset Successful'
|
||||
: 'Create Password Successful';
|
||||
|
||||
return (
|
||||
<Box className={classes.root}>
|
||||
<Card className={classes.card}>
|
||||
<Grid container display="flex" justifyContent="center">
|
||||
{!resetPasswordLinkSend ? (
|
||||
<Grid item xs={12}>
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
className={classes.forgotPasswordHeader}
|
||||
>
|
||||
<Grid item xs={2}></Grid>
|
||||
<Grid item xs={10}>
|
||||
<Typography variant="Gilroy-bold" className={classes.heading}>
|
||||
{headingText} your Password
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Box>
|
||||
<ResetPasswordForm onSubmit={handleFormSubmit} />
|
||||
</Grid>
|
||||
) : (
|
||||
<Box paddingTop="35px" paddingBottom="5px" fontSize="0.8rem">
|
||||
<Box className={classes.successIcon}>
|
||||
<img
|
||||
className={classes.resetPasswordSuccessIcon}
|
||||
src={ResetPasswordSuccessIcon}
|
||||
/>
|
||||
</Box>
|
||||
<Box textAlign="center">
|
||||
<Typography
|
||||
variant="Gilroy-SemiBold"
|
||||
className={classes.resetPasswordheading}
|
||||
marginBottom="20px"
|
||||
>
|
||||
{successMessage}
|
||||
</Typography>
|
||||
<Grid item width="80%" margin="auto">
|
||||
<Typography
|
||||
variant="Gilroy-normal"
|
||||
className={classes.subheading}
|
||||
>
|
||||
Awesome, you have successfully{' '}
|
||||
{!isCreatePassword ? 'updated' : 'created'} your password.
|
||||
</Typography>
|
||||
</Grid>
|
||||
<LoadingButton
|
||||
className={classes.submitButton}
|
||||
size="small"
|
||||
width="60%"
|
||||
type="submit"
|
||||
variant="contained"
|
||||
onClick={() => navigate('/auth/login')}
|
||||
>
|
||||
Back to Login
|
||||
</LoadingButton>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Grid>
|
||||
</Card>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default ResetPassword;
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
import makeStyles from '@mui/styles/makeStyles';
|
||||
import backgroundImage from '../../assets/images/background/background.jpg';
|
||||
import { pxToRem } from '../../theme/typography';
|
||||
|
||||
export const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
height: '100vh',
|
||||
backgroundImage: `url(${backgroundImage})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
card: {
|
||||
width: '370px',
|
||||
maxHeight: '835px',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: '500px',
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '500px',
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
width: '500px',
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
width: '500px',
|
||||
maxHeight: '735px',
|
||||
},
|
||||
boxShadow: 'none',
|
||||
borderRadius: theme.spacing(3.8),
|
||||
opacity: '0.95',
|
||||
},
|
||||
forgotPasswordHeader: {
|
||||
marginTop: theme.spacing(4.5),
|
||||
},
|
||||
right: {
|
||||
textAlign: 'center',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
form: {
|
||||
width: '65%',
|
||||
},
|
||||
formBody: {
|
||||
justifyContent: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
// height: '162.5px',
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
// height: '234px',
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
// height: '325px',
|
||||
},
|
||||
|
||||
'& .MuiTextField-root': {
|
||||
marginTop: theme.spacing(0.4),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
marginTop: theme.spacing(0.4),
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
marginTop: theme.spacing(0.4),
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
marginTop: theme.spacing(0.4),
|
||||
},
|
||||
},
|
||||
},
|
||||
formHeader: {
|
||||
marginTop: theme.spacing(1.2),
|
||||
marginBottom: theme.spacing(3),
|
||||
},
|
||||
heading: {
|
||||
fontFamily: 'Inter-Bold',
|
||||
// width: '70%',
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-start',
|
||||
lineHeight: 1.2,
|
||||
fontSize: pxToRem(27),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
fontSize: pxToRem(27),
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
fontSize: pxToRem(27),
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
fontSize: pxToRem(27),
|
||||
},
|
||||
},
|
||||
successIcon: {
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
marginTop: theme.spacing(1.1),
|
||||
},
|
||||
resetPasswordheading: {
|
||||
// width: '70%',
|
||||
display: 'flex',
|
||||
fontFamily: 'Inter-Bold',
|
||||
justifyContent: 'center',
|
||||
marginTop: theme.spacing(3.8),
|
||||
lineHeight: 1.2,
|
||||
fontSize: pxToRem(27),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
fontSize: pxToRem(27),
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
fontSize: pxToRem(27),
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
fontSize: pxToRem(27),
|
||||
},
|
||||
},
|
||||
subHeading: {
|
||||
width: '90%',
|
||||
lineHeight: 1.1,
|
||||
textAlign: 'left',
|
||||
fontSize: pxToRem(12),
|
||||
marginTop: theme.spacing(0),
|
||||
marginBottom: theme.spacing(1.0),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
fontSize: pxToRem(13),
|
||||
marginTop: theme.spacing(0),
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
fontSize: pxToRem(13),
|
||||
marginTop: theme.spacing(0),
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
fontSize: pxToRem(13),
|
||||
marginTop: theme.spacing(0),
|
||||
},
|
||||
},
|
||||
resetPasswordTextField: {
|
||||
marginTop: '0px',
|
||||
},
|
||||
confirmResetBox: {
|
||||
marginTop: theme.spacing(1.2),
|
||||
},
|
||||
passwordCheckListTitle: {
|
||||
color: 'grey',
|
||||
fontSize: pxToRem(14.4),
|
||||
fontStyle: 'italic',
|
||||
textAlign: 'left',
|
||||
marginBottom: theme.spacing(0.4),
|
||||
},
|
||||
passwordCheckList: {
|
||||
color: 'grey',
|
||||
fontSize: pxToRem(14.4),
|
||||
paddingTop: '2px',
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
labelStyle: {
|
||||
marginBottom: '0px',
|
||||
fontSize: pxToRem(3.2),
|
||||
textAlign: 'left',
|
||||
color: theme.palette.grey[10],
|
||||
// paddingBottom: '20px',
|
||||
},
|
||||
inputTitle: {
|
||||
'&.MuiTypography-body1': {
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.grey[10],
|
||||
},
|
||||
fontSize: pxToRem(12),
|
||||
// opacity: '0.54',
|
||||
color: theme.palette.grey[10],
|
||||
marginBottom: theme.spacing(0.6),
|
||||
marginLeft: theme.spacing(0.6),
|
||||
},
|
||||
submitButton: {
|
||||
fontFamily: 'Inter-Regular',
|
||||
fontWeight: 500,
|
||||
marginTop: theme.spacing(2.2),
|
||||
marginBottom: theme.spacing(4.0),
|
||||
fontSize: pxToRem(12.8),
|
||||
justifyContent: 'center',
|
||||
borderRadius: '6px',
|
||||
padding: '20px',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
padding: '20px',
|
||||
fontSize: pxToRem(12.8),
|
||||
},
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
padding: '20px',
|
||||
fontSize: pxToRem(12.8),
|
||||
},
|
||||
[theme.breakpoints.up('xl')]: {
|
||||
height: '10px',
|
||||
fontSize: pxToRem(12.8),
|
||||
},
|
||||
},
|
||||
resetPasswordSuccessIcon: {
|
||||
width: '17%',
|
||||
},
|
||||
sendEmailText: {
|
||||
marginTop: theme.spacing(2.0),
|
||||
textAlign: 'center',
|
||||
fontSize: pxToRem(10.4),
|
||||
},
|
||||
emailText: {
|
||||
lineHeight: 1.1,
|
||||
fontSize: pxToRem(12.48),
|
||||
},
|
||||
}));
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import AddIcon from '@mui/icons-material/Add';
|
||||
import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew';
|
||||
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import PersonAddIcon from '@mui/icons-material/PersonAdd';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew";
|
||||
import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import PersonAddIcon from "@mui/icons-material/PersonAdd";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import {
|
||||
Alert,
|
||||
Box,
|
||||
|
|
@ -18,7 +18,6 @@ import {
|
|||
InputAdornment,
|
||||
Paper,
|
||||
Snackbar,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
|
|
@ -26,18 +25,26 @@ import {
|
|||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import CustomBreadcrumbs from '../../components/CustomBreadcrumbs';
|
||||
import PageHeader from '../../components/PageHeader';
|
||||
} from "@mui/material";
|
||||
import React, { useMemo, useRef, useState } from "react";
|
||||
import CustomBreadcrumbs from "../../components/CustomBreadcrumbs";
|
||||
import PageHeader from "../../components/PageHeader";
|
||||
import { createAdmin, getAdmins } from "../../services/auth.services";
|
||||
import { pushNotification } from "../../utils/notification";
|
||||
import { NOTIFICATION } from "../../constants";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useStyles } from "./staffStyles";
|
||||
import Table from "../../components/Table";
|
||||
|
||||
const StaffManagement = () => {
|
||||
const theme = useTheme();
|
||||
const classes = useStyles();
|
||||
const ref = useRef(null);
|
||||
// State for form fields
|
||||
const [firstName, setFirstName] = useState('');
|
||||
const [lastName, setLastName] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
const [emailError, setEmailError] = useState('');
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [emailError, setEmailError] = useState("");
|
||||
|
||||
// State for staff list
|
||||
const [staffList, setStaffList] = useState([]);
|
||||
|
|
@ -46,7 +53,7 @@ const StaffManagement = () => {
|
|||
const [openDialog, setOpenDialog] = useState(false);
|
||||
|
||||
// State for search
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
|
||||
// State for pagination
|
||||
const [page, setPage] = useState(1);
|
||||
|
|
@ -55,8 +62,8 @@ const StaffManagement = () => {
|
|||
// State for notification
|
||||
const [notification, setNotification] = useState({
|
||||
open: false,
|
||||
message: '',
|
||||
severity: 'success',
|
||||
message: "",
|
||||
severity: "success",
|
||||
});
|
||||
|
||||
// Email validation function
|
||||
|
|
@ -73,41 +80,37 @@ const StaffManagement = () => {
|
|||
const handleCloseDialog = () => {
|
||||
setOpenDialog(false);
|
||||
// Clear form
|
||||
setFirstName('');
|
||||
setLastName('');
|
||||
setEmail('');
|
||||
setEmailError('');
|
||||
setFirstName("");
|
||||
setLastName("");
|
||||
setEmail("");
|
||||
setEmailError("");
|
||||
};
|
||||
|
||||
// Handle form submission
|
||||
const handleSubmit = (e) => {
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Validate email
|
||||
if (!validateEmail(email)) {
|
||||
setEmailError('Please enter a valid email address');
|
||||
setEmailError("Please enter a valid email address");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add new staff member
|
||||
const newStaff = {
|
||||
id: staffList.length + 1,
|
||||
firstName,
|
||||
lastName,
|
||||
const payload = {
|
||||
username: `${firstName} ${lastName}`,
|
||||
email,
|
||||
};
|
||||
|
||||
setStaffList([...staffList, newStaff]);
|
||||
const response = await createAdmin(payload);
|
||||
|
||||
if (response?.data?.data) {
|
||||
pushNotification("Admin created successfully!", NOTIFICATION.SUCCESS);
|
||||
} else {
|
||||
pushNotification(response?.data?.message, NOTIFICATION.ERROR);
|
||||
}
|
||||
|
||||
// Close dialog
|
||||
handleCloseDialog();
|
||||
|
||||
// Show success notification
|
||||
setNotification({
|
||||
open: true,
|
||||
message: 'Staff member added successfully!',
|
||||
severity: 'success',
|
||||
});
|
||||
};
|
||||
|
||||
// Handle notification close
|
||||
|
|
@ -118,310 +121,392 @@ const StaffManagement = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const getData = async (filters) => {
|
||||
try {
|
||||
// Remove the type parameter since it's not defined
|
||||
let params = {
|
||||
...filters
|
||||
};
|
||||
|
||||
const resp = await getAdmins(params);
|
||||
console.log('API Response:', resp);
|
||||
|
||||
return {
|
||||
data: resp?.data?.data?.data,
|
||||
rowCount: resp?.data?.total || 0,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching admins:', error);
|
||||
return {
|
||||
data: [],
|
||||
rowCount: 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// ...................breadcrumbs array........................
|
||||
const breadcrumbs = [
|
||||
{
|
||||
label: 'Dashboard',
|
||||
path: '/',
|
||||
label: "Dashboard",
|
||||
path: "/",
|
||||
},
|
||||
{
|
||||
label: 'Staff Management',
|
||||
path: '/staff',
|
||||
label: "Staff Management",
|
||||
path: "/staff",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||
{/* <Typography
|
||||
variant="h4"
|
||||
component="h1"
|
||||
gutterBottom
|
||||
sx={{ fontWeight: 'bold', mb: 4, color: '#0a2d6b' }}
|
||||
>
|
||||
Staff Management
|
||||
</Typography> */}
|
||||
const columns = useMemo(() => [
|
||||
{
|
||||
size: 100,
|
||||
header: "Sr. No.",
|
||||
Cell: (props) => {
|
||||
const tableState = props?.table?.getState();
|
||||
const serialNumber = (
|
||||
props?.row?.index +
|
||||
1 +
|
||||
tableState?.pagination?.pageIndex * tableState?.pagination?.pageSize
|
||||
)
|
||||
?.toString()
|
||||
?.padStart(2, "0");
|
||||
return <span>{serialNumber}</span>;
|
||||
},
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
size: 280,
|
||||
accessorKey: "username",
|
||||
header: "User Name",
|
||||
enableColumnFilter: false,
|
||||
},
|
||||
{
|
||||
size: 220,
|
||||
accessorKey: "email",
|
||||
header: "User Email Address",
|
||||
enableColumnFilter: false,
|
||||
},
|
||||
]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<PageHeader
|
||||
pageTitle="Staff Management"
|
||||
hideAddButton
|
||||
// addButtonTitle="Add Staff"
|
||||
// onAddButtonClick={toggle}
|
||||
// addButtonIcon={<img src={AddIcon} />}
|
||||
// addButtonDisabled={false}
|
||||
// permissionName={'CREATE_USERS'}
|
||||
// infiniteDropdown
|
||||
// hideAddButton
|
||||
addButtonIcon={<AddIcon />}
|
||||
onAddButtonClick={handleOpenDialog}
|
||||
/>
|
||||
|
||||
<CustomBreadcrumbs breadcrumbs={breadcrumbs} />
|
||||
|
||||
<Paper elevation={3} sx={{ p: 0, mb: 4, overflow: 'hidden' }}>
|
||||
{/* Staff List Header with Add Button */}
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
p: 3,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" component="h2" sx={{ fontWeight: 'bold' }}>
|
||||
Staff List
|
||||
</Typography>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="error"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={handleOpenDialog}
|
||||
sx={{
|
||||
borderRadius: 50,
|
||||
textTransform: 'none',
|
||||
backgroundColor: '#ff3366',
|
||||
'&:hover': {
|
||||
backgroundColor: '#e61653',
|
||||
},
|
||||
}}
|
||||
>
|
||||
Add Admin
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{/* Search Box */}
|
||||
<Box sx={{ px: 3, pb: 2 }}>
|
||||
<TextField
|
||||
placeholder="Search user here"
|
||||
fullWidth
|
||||
size="small"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon color="action" />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
sx={{
|
||||
backgroundColor: '#fff',
|
||||
'& .MuiOutlinedInput-root': {
|
||||
borderRadius: 2,
|
||||
},
|
||||
<Box className={classes.tableMainDiv}>
|
||||
<Box>
|
||||
<Table
|
||||
hideTopToolbar
|
||||
columns={columns}
|
||||
getData={getData}
|
||||
options={{
|
||||
enableRowSelection: true,
|
||||
showTopBar: false,
|
||||
showFilters: true,
|
||||
}}
|
||||
searchText="Staff"
|
||||
showSearchBox={true}
|
||||
ref={ref}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Staff List Table */}
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow sx={{ backgroundColor: '#f5f5f5' }}>
|
||||
<TableCell sx={{ fontWeight: 'bold' }}>Sr. No.</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold' }}>User Name</TableCell>
|
||||
<TableCell sx={{ fontWeight: 'bold' }}>
|
||||
User Email Address
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{staffList.length > 0 ? (
|
||||
staffList
|
||||
.filter(
|
||||
(staff) =>
|
||||
`${staff.firstName} ${staff.lastName}`
|
||||
.toLowerCase()
|
||||
.includes(searchQuery.toLowerCase()) ||
|
||||
staff.email
|
||||
.toLowerCase()
|
||||
.includes(searchQuery.toLowerCase())
|
||||
)
|
||||
.slice((page - 1) * rowsPerPage, page * rowsPerPage)
|
||||
.map((staff, index) => (
|
||||
<TableRow key={staff.id}>
|
||||
<TableCell>
|
||||
{(page - 1) * rowsPerPage + index + 1}
|
||||
</TableCell>
|
||||
<TableCell>{`${staff.firstName} ${staff.lastName}`}</TableCell>
|
||||
<TableCell>{staff.email}</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={3}
|
||||
align="center"
|
||||
sx={{ py: 5, color: '#666' }}
|
||||
>
|
||||
No staff members added yet
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
{/* Pagination */}
|
||||
{staffList.length > 0 && (
|
||||
<Box
|
||||
</Box>
|
||||
<Box className={classes.tableMainDiv}>
|
||||
<Dialog
|
||||
open={openDialog}
|
||||
onClose={handleCloseDialog}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
p: 2,
|
||||
borderTop: '1px solid #eee',
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
pb: 1,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={() => setPage((prev) => Math.max(prev - 1, 1))}
|
||||
disabled={page === 1}
|
||||
startIcon={<ArrowBackIosNewIcon fontSize="small" />}
|
||||
sx={{ mx: 1, color: '#666' }}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<PersonAddIcon sx={{ mr: 1, color: "#0a2d6b" }} />
|
||||
<Typography
|
||||
variant="h6"
|
||||
component="span"
|
||||
sx={{ fontWeight: "bold", color: "#0a2d6b" }}
|
||||
>
|
||||
Add New Staff
|
||||
</Typography>
|
||||
</Box>
|
||||
<IconButton onClick={handleCloseDialog} size="small">
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
|
||||
<Divider />
|
||||
|
||||
<DialogContent>
|
||||
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 1 }}>
|
||||
<TextField
|
||||
label="First Name"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
value={firstName}
|
||||
onChange={(e) => setFirstName(e.target.value)}
|
||||
placeholder="First Name"
|
||||
required
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="Last Name"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
value={lastName}
|
||||
onChange={(e) => setLastName(e.target.value)}
|
||||
placeholder="Last Name"
|
||||
required
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="Email Address"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value);
|
||||
setEmailError("");
|
||||
}}
|
||||
placeholder="Email Address"
|
||||
error={!!emailError}
|
||||
helperText={emailError}
|
||||
required
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions sx={{ px: 3, pb: 3 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
disableElevation
|
||||
color="error"
|
||||
fullWidth
|
||||
onClick={handleSubmit}
|
||||
sx={{
|
||||
mx: 1,
|
||||
minWidth: '36px',
|
||||
backgroundColor: '#f0f0f0',
|
||||
color: '#333',
|
||||
'&:hover': {
|
||||
backgroundColor: '#e0e0e0',
|
||||
py: 1.5,
|
||||
backgroundColor: "#ff3366",
|
||||
"&:hover": {
|
||||
backgroundColor: "#e61653",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{page}
|
||||
Add Admin
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</Box>
|
||||
// <Container maxWidth="lg" sx={{ py: 4 }}>
|
||||
// {/* <Typography
|
||||
// variant="h4"
|
||||
// component="h1"
|
||||
// gutterBottom
|
||||
// sx={{ fontWeight: 'bold', mb: 4, color: '#0a2d6b' }}
|
||||
// >
|
||||
// Staff Management
|
||||
// </Typography> */}
|
||||
|
||||
<Button
|
||||
onClick={() => setPage((prev) => prev + 1)}
|
||||
disabled={page * rowsPerPage >= staffList.length}
|
||||
endIcon={<ArrowForwardIosIcon fontSize="small" />}
|
||||
sx={{ mx: 1, color: '#666' }}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
// <PageHeader
|
||||
// pageTitle="Staff Management"
|
||||
// hideAddButton
|
||||
// // addButtonTitle="Add Staff"
|
||||
// // onAddButtonClick={toggle}
|
||||
// // addButtonIcon={<img src={AddIcon} />}
|
||||
// // addButtonDisabled={false}
|
||||
// // permissionName={'CREATE_USERS'}
|
||||
// // infiniteDropdown
|
||||
// />
|
||||
|
||||
{/* Add Staff Dialog */}
|
||||
<Dialog
|
||||
open={openDialog}
|
||||
onClose={handleCloseDialog}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
pb: 1,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<PersonAddIcon sx={{ mr: 1, color: '#0a2d6b' }} />
|
||||
<Typography
|
||||
variant="h6"
|
||||
component="span"
|
||||
sx={{ fontWeight: 'bold', color: '#0a2d6b' }}
|
||||
>
|
||||
Add New Staff
|
||||
</Typography>
|
||||
</Box>
|
||||
<IconButton onClick={handleCloseDialog} size="small">
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
// <CustomBreadcrumbs breadcrumbs={breadcrumbs} />
|
||||
|
||||
<Divider />
|
||||
// <Paper elevation={3} sx={{ p: 0, mb: 4, overflow: 'hidden' }}>
|
||||
// {/* Staff List Header with Add Button */}
|
||||
// <Box
|
||||
// sx={{
|
||||
// display: 'flex',
|
||||
// justifyContent: 'space-between',
|
||||
// alignItems: 'center',
|
||||
// p: 3,
|
||||
// }}
|
||||
// >
|
||||
// <Typography variant="h6" component="h2" sx={{ fontWeight: 'bold' }}>
|
||||
// Staff List
|
||||
// </Typography>
|
||||
|
||||
<DialogContent>
|
||||
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 1 }}>
|
||||
<TextField
|
||||
label="First Name *"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
value={firstName}
|
||||
onChange={(e) => setFirstName(e.target.value)}
|
||||
placeholder="First Name"
|
||||
required
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
/>
|
||||
// <Button
|
||||
// variant="contained"
|
||||
// color="error"
|
||||
// startIcon={<AddIcon />}
|
||||
// onClick={handleOpenDialog}
|
||||
// sx={{
|
||||
// borderRadius: 50,
|
||||
// textTransform: 'none',
|
||||
// backgroundColor: '#ff3366',
|
||||
// '&:hover': {
|
||||
// backgroundColor: '#e61653',
|
||||
// },
|
||||
// }}
|
||||
// >
|
||||
// Add Admin
|
||||
// </Button>
|
||||
// </Box>
|
||||
|
||||
<TextField
|
||||
label="Last Name *"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
value={lastName}
|
||||
onChange={(e) => setLastName(e.target.value)}
|
||||
placeholder="Last Name"
|
||||
required
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
/>
|
||||
// {/* Search Box */}
|
||||
// <Box sx={{ px: 3, pb: 2 }}>
|
||||
// <TextField
|
||||
// placeholder="Search user here"
|
||||
// fullWidth
|
||||
// size="small"
|
||||
// value={searchQuery}
|
||||
// onChange={(e) => setSearchQuery(e.target.value)}
|
||||
// InputProps={{
|
||||
// startAdornment: (
|
||||
// <InputAdornment position="start">
|
||||
// <SearchIcon color="action" />
|
||||
// </InputAdornment>
|
||||
// ),
|
||||
// }}
|
||||
// sx={{
|
||||
// backgroundColor: '#fff',
|
||||
// '& .MuiOutlinedInput-root': {
|
||||
// borderRadius: 2,
|
||||
// },
|
||||
// }}
|
||||
// />
|
||||
// </Box>
|
||||
|
||||
<TextField
|
||||
label="Email Address *"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value);
|
||||
setEmailError('');
|
||||
}}
|
||||
placeholder="Email Address"
|
||||
error={!!emailError}
|
||||
helperText={emailError}
|
||||
required
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
// {/* Staff List Table */}
|
||||
// <TableContainer>
|
||||
// <Table>
|
||||
// <TableHead>
|
||||
// <TableRow sx={{ backgroundColor: '#f5f5f5' }}>
|
||||
// <TableCell sx={{ fontWeight: 'bold' }}>Sr. No.</TableCell>
|
||||
// <TableCell sx={{ fontWeight: 'bold' }}>User Name</TableCell>
|
||||
// <TableCell sx={{ fontWeight: 'bold' }}>
|
||||
// User Email Address
|
||||
// </TableCell>
|
||||
// </TableRow>
|
||||
// </TableHead>
|
||||
// <TableBody>
|
||||
// {staffList.length > 0 ? (
|
||||
// staffList
|
||||
// .filter(
|
||||
// (staff) =>
|
||||
// `${staff.firstName} ${staff.lastName}`
|
||||
// .toLowerCase()
|
||||
// .includes(searchQuery.toLowerCase()) ||
|
||||
// staff.email
|
||||
// .toLowerCase()
|
||||
// .includes(searchQuery.toLowerCase())
|
||||
// )
|
||||
// .slice((page - 1) * rowsPerPage, page * rowsPerPage)
|
||||
// .map((staff, index) => (
|
||||
// <TableRow key={staff.id}>
|
||||
// <TableCell>
|
||||
// {(page - 1) * rowsPerPage + index + 1}
|
||||
// </TableCell>
|
||||
// <TableCell>{`${staff.firstName} ${staff.lastName}`}</TableCell>
|
||||
// <TableCell>{staff.email}</TableCell>
|
||||
// </TableRow>
|
||||
// ))
|
||||
// ) : (
|
||||
// <TableRow>
|
||||
// <TableCell
|
||||
// colSpan={3}
|
||||
// align="center"
|
||||
// sx={{ py: 5, color: '#666' }}
|
||||
// >
|
||||
// No staff members added yet
|
||||
// </TableCell>
|
||||
// </TableRow>
|
||||
// )}
|
||||
// </TableBody>
|
||||
// </Table>
|
||||
// </TableContainer>
|
||||
|
||||
<DialogActions sx={{ px: 3, pb: 3 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="error"
|
||||
fullWidth
|
||||
onClick={handleSubmit}
|
||||
sx={{
|
||||
py: 1.5,
|
||||
backgroundColor: '#ff3366',
|
||||
'&:hover': {
|
||||
backgroundColor: '#e61653',
|
||||
},
|
||||
}}
|
||||
>
|
||||
Add Admin
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
// {/* Pagination */}
|
||||
// {staffList.length > 0 && (
|
||||
// <Box
|
||||
// sx={{
|
||||
// display: 'flex',
|
||||
// justifyContent: 'center',
|
||||
// p: 2,
|
||||
// borderTop: '1px solid #eee',
|
||||
// }}
|
||||
// >
|
||||
// <Button
|
||||
// onClick={() => setPage((prev) => Math.max(prev - 1, 1))}
|
||||
// disabled={page === 1}
|
||||
// startIcon={<ArrowBackIosNewIcon fontSize="small" />}
|
||||
// sx={{ mx: 1, color: '#666' }}
|
||||
// >
|
||||
// Previous
|
||||
// </Button>
|
||||
|
||||
{/* Notification */}
|
||||
<Snackbar
|
||||
open={notification.open}
|
||||
autoHideDuration={4000}
|
||||
onClose={handleCloseNotification}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||
>
|
||||
<Alert
|
||||
onClose={handleCloseNotification}
|
||||
severity={notification.severity}
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
{notification.message}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
</Container>
|
||||
// <Button
|
||||
// variant="contained"
|
||||
// disableElevation
|
||||
// sx={{
|
||||
// mx: 1,
|
||||
// minWidth: '36px',
|
||||
// backgroundColor: '#f0f0f0',
|
||||
// color: '#333',
|
||||
// '&:hover': {
|
||||
// backgroundColor: '#e0e0e0',
|
||||
// },
|
||||
// }}
|
||||
// >
|
||||
// {page}
|
||||
// </Button>
|
||||
|
||||
// <Button
|
||||
// onClick={() => setPage((prev) => prev + 1)}
|
||||
// disabled={page * rowsPerPage >= staffList.length}
|
||||
// endIcon={<ArrowForwardIosIcon fontSize="small" />}
|
||||
// sx={{ mx: 1, color: '#666' }}
|
||||
// >
|
||||
// Next
|
||||
// </Button>
|
||||
// </Box>
|
||||
// )}
|
||||
// </Paper>
|
||||
|
||||
// {/* Add Staff Dialog */}
|
||||
|
||||
// {/* Notification */}
|
||||
// <Snackbar
|
||||
// open={notification.open}
|
||||
// autoHideDuration={4000}
|
||||
// onClose={handleCloseNotification}
|
||||
// anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||
// >
|
||||
// <Alert
|
||||
// onClose={handleCloseNotification}
|
||||
// severity={notification.severity}
|
||||
// sx={{ width: '100%' }}
|
||||
// >
|
||||
// {notification.message}
|
||||
// </Alert>
|
||||
// </Snackbar>
|
||||
// </Container>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
import makeStyles from '@mui/styles/makeStyles';
|
||||
import { pxToRem } from '../../theme/typography';
|
||||
|
||||
export const useStyles = makeStyles((theme) => ({
|
||||
chipClass: {
|
||||
height: 'fit-content',
|
||||
minHeight: '30px',
|
||||
padding: '2px',
|
||||
alignItems: 'center',
|
||||
},
|
||||
statusColor: {
|
||||
color: theme.palette.primary.main,
|
||||
fontSize: pxToRem(10),
|
||||
},
|
||||
tabsBox: {
|
||||
display: 'flex',
|
||||
justifyContent: ' space-around',
|
||||
// width: '55%',
|
||||
marginTop: theme.spacing(0.5),
|
||||
marginRight: theme.spacing(5.0),
|
||||
alignItems: 'center',
|
||||
},
|
||||
secondaryButton: {
|
||||
width: '200px',
|
||||
height: '46px',
|
||||
borderRadius: '8px',
|
||||
justifyContent: 'space-evenly',
|
||||
fontSize: pxToRem(16),
|
||||
},
|
||||
tableActionIcons: {
|
||||
marginRight: theme.spacing(1.4),
|
||||
width: '15px',
|
||||
},
|
||||
companyNameTableColumn: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
companyName: {
|
||||
marginLeft: theme.spacing(1),
|
||||
fontSize: pxToRem(14),
|
||||
objectFit: 'contain',
|
||||
width: '260px',
|
||||
},
|
||||
companyNameLink: {
|
||||
textDecoration: 'none',
|
||||
color: theme.palette.grey[10],
|
||||
'&:hover': {
|
||||
color: theme.palette.info.main,
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
},
|
||||
companyWebsiteLabel: {
|
||||
fontSize: pxToRem(12),
|
||||
},
|
||||
companyNameLogo: {
|
||||
height: '40px',
|
||||
width: '40px',
|
||||
borderRadius: theme.shape.borderRadiusComponent,
|
||||
objectFit: 'contain',
|
||||
},
|
||||
sendEmailStatus: {
|
||||
fontSize: pxToRem(14),
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
sendEmailLastSentMailDate: {
|
||||
fontSize: pxToRem(12),
|
||||
},
|
||||
addDiscountCodeLink: {
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
addDiscountCodeLabel: {
|
||||
fontSize: pxToRem(14),
|
||||
backgroundColor: theme.palette.common.white,
|
||||
color: theme.palette.common.black,
|
||||
},
|
||||
customModel: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
},
|
||||
customModelBox: {
|
||||
paddingLeft: theme.spacing(5),
|
||||
paddingRight: theme.spacing(5),
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
// height: '100%',
|
||||
border: 'none',
|
||||
},
|
||||
newPlanTitleText: {
|
||||
fontSize: pxToRem(28),
|
||||
fontFamily: theme.fontFamily.bold,
|
||||
},
|
||||
newPlanSubTitleText: {
|
||||
fontSize: pxToRem(18),
|
||||
padding: theme.spacing(1),
|
||||
},
|
||||
addPlanSuccessIcon: {
|
||||
padding: theme.spacing(2),
|
||||
paddingTop: theme.spacing(1),
|
||||
},
|
||||
planAddedText: {
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.grey[54],
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center',
|
||||
},
|
||||
verifyIcon: {
|
||||
marginLeft: theme.spacing(0.3),
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.grey[54],
|
||||
},
|
||||
}));
|
||||
Loading…
Reference in New Issue