feat: clinic approval flow
This commit is contained in:
parent
970f8ebe1c
commit
8d2d652630
|
|
@ -22,3 +22,5 @@ dist-ssr
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
.env
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
"firebase": "^11.6.0",
|
"firebase": "^11.6.0",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"i": "^0.3.7",
|
"i": "^0.3.7",
|
||||||
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"material-react-table": "^3.2.1",
|
"material-react-table": "^3.2.1",
|
||||||
"npm": "^11.3.0",
|
"npm": "^11.3.0",
|
||||||
|
|
@ -4184,6 +4185,14 @@
|
||||||
"jss": "10.10.0"
|
"jss": "10.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jwt-decode": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
"firebase": "^11.6.0",
|
"firebase": "^11.6.0",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"i": "^0.3.7",
|
"i": "^0.3.7",
|
||||||
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"material-react-table": "^3.2.1",
|
"material-react-table": "^3.2.1",
|
||||||
"npm": "^11.3.0",
|
"npm": "^11.3.0",
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path fill="#000000" d="M164.9 24.6c-7.7-18.6-28-28.5-47.4-23.2l-88 24C12.1 30.2 0 46 0 64C0 311.4 200.6 512 448 512c18 0 33.8-12.1 38.6-29.5l24-88c5.3-19.4-4.6-39.7-23.2-47.4l-96-40c-16.3-6.8-35.2-2.1-46.3 11.6L304.7 368C234.3 334.7 177.3 277.7 144 207.3L193.3 167c13.7-11.2 18.4-30 11.6-46.3l-40-96z"/></svg>
|
||||||
|
After Width: | Height: | Size: 523 B |
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -1,5 +1,5 @@
|
||||||
export const API_BASE_URL =
|
export const API_BASE_URL =
|
||||||
import.meta.env.VITE_API_BASE_URL ?? '/api/v1/recruitments';
|
import.meta.env.VITE_API_BASE_URL;
|
||||||
export const IMAGE_LOCATION_BASE_URL = import.meta.env
|
export const IMAGE_LOCATION_BASE_URL = import.meta.env
|
||||||
.VITE_IMAGE_LOCATION_BASE_URL;
|
.VITE_IMAGE_LOCATION_BASE_URL;
|
||||||
export const BILLDESK_URL = import.meta.env.VITE_BILLDESK_URL;
|
export const BILLDESK_URL = import.meta.env.VITE_BILLDESK_URL;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import { FILE_TYPE, NOTIFICATION } from '../constants';
|
||||||
import uploadIcon from '../assets/images/icon/upload.svg';
|
import uploadIcon from '../assets/images/icon/upload.svg';
|
||||||
import PdfIcon from '../assets/images/icon/pdf.png';
|
import PdfIcon from '../assets/images/icon/pdf.png';
|
||||||
import DocIcon from '../assets/images/icon/doc.png';
|
import DocIcon from '../assets/images/icon/doc.png';
|
||||||
import { fileUpload } from '../services/file.upload.services';
|
import { fileUpload, getPresignedUrl, uploadToS3 } from '../services/file.upload.services';
|
||||||
import { IMAGE_LOCATION_BASE_URL } from '../common/envVariables';
|
import { IMAGE_LOCATION_BASE_URL } from '../common/envVariables';
|
||||||
|
|
||||||
const CustomFileUpload = forwardRef(function CustomFileUpload(
|
const CustomFileUpload = forwardRef(function CustomFileUpload(
|
||||||
|
|
@ -77,14 +77,9 @@ const CustomFileUpload = forwardRef(function CustomFileUpload(
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const makeFullUrlIfNeeded = (url) => {
|
const makeFullUrlIfNeeded = (url) => {
|
||||||
// Return early if url is undefined or empty
|
|
||||||
if(!url){
|
if(!url){
|
||||||
setOldUploadedFileUrl('');
|
return
|
||||||
setFileExtension('');
|
|
||||||
setImageName('');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const isHttp = url.startsWith('http://') || url.startsWith('https://');
|
const isHttp = url.startsWith('http://') || url.startsWith('https://');
|
||||||
if (!isHttp) {
|
if (!isHttp) {
|
||||||
setOldUploadedFileUrl(`${IMAGE_LOCATION_BASE_URL}${url}`);
|
setOldUploadedFileUrl(`${IMAGE_LOCATION_BASE_URL}${url}`);
|
||||||
|
|
@ -114,16 +109,50 @@ const CustomFileUpload = forwardRef(function CustomFileUpload(
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let formData = new FormData();
|
const filePayload = {
|
||||||
formData.append('file', value);
|
folder: "assests",
|
||||||
formData.append('fileName', value?.name);
|
file_name: value.name,
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const data = await fileUpload(formData);
|
const response = await getPresignedUrl(filePayload);
|
||||||
onUploadDone(documentName, data?.data?.data?.Key);
|
|
||||||
|
// Debug the response structure
|
||||||
|
console.log('API Response:', response);
|
||||||
|
|
||||||
|
// Check if we have a valid response with the expected structure
|
||||||
|
if (response?.data?.data?.Key) {
|
||||||
|
// Use the Key from the response
|
||||||
|
onUploadDone(documentName, response.data.data.Key);
|
||||||
|
await uploadToS3(value, response.data.data.api_url);
|
||||||
|
} else {
|
||||||
|
// If the expected structure is not found, try to find the key in a different location
|
||||||
|
// or use a fallback value
|
||||||
|
console.log('Response structure is different than expected');
|
||||||
|
|
||||||
|
// Try different possible paths to find the key
|
||||||
|
const key = response?.data?.Key ||
|
||||||
|
response?.data?.data?.key ||
|
||||||
|
response?.Key ||
|
||||||
|
value.name; // Fallback to the file name if key not found
|
||||||
|
|
||||||
|
console.log('Using key:', key);
|
||||||
|
onUploadDone(documentName, key);
|
||||||
|
|
||||||
|
// Try to find the API URL similarly
|
||||||
|
const apiUrl = response?.data?.data?.api_url ||
|
||||||
|
response?.data?.api_url ||
|
||||||
|
response?.api_url;
|
||||||
|
|
||||||
|
if (apiUrl) {
|
||||||
|
await uploadToS3(value, apiUrl);
|
||||||
|
} else {
|
||||||
|
console.error('Could not find API URL in response');
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.error(error);
|
console.error('Error in handleFileUpload:', error);
|
||||||
pushNotification('Error while uploading file', NOTIFICATION.ERROR);
|
pushNotification('Error while uploading file', NOTIFICATION.ERROR);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
import { Box, Button, Grid } from '@mui/material';
|
||||||
|
import { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch';
|
||||||
|
import React from 'react';
|
||||||
|
import { useStyles } from './styles/ImagePreviewComponentStyles';
|
||||||
|
import AddOutlinedIcon from '@mui/icons-material/AddOutlined';
|
||||||
|
import RemoveOutlinedIcon from '@mui/icons-material/RemoveOutlined';
|
||||||
|
import ZoomOutOutlinedIcon from '@mui/icons-material/ZoomOutOutlined';
|
||||||
|
import { FILE_EXTENTIONS_ICONS } from '../constants';
|
||||||
|
|
||||||
|
const ImagePreviewControls = ({ zoomIn, zoomOut, resetTransform }) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid className={classes.controlButtons}>
|
||||||
|
<Button
|
||||||
|
className={`${classes.zoomOutButton} ${classes.controlButton}`}
|
||||||
|
onClick={() => zoomOut()} // No need to wrap this in a function
|
||||||
|
>
|
||||||
|
<RemoveOutlinedIcon className={classes.iconSize} />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className={`${classes.zoomResetButton} ${classes.controlButton}`}
|
||||||
|
onClick={() => resetTransform()}
|
||||||
|
>
|
||||||
|
<ZoomOutOutlinedIcon className={classes.iconSize} />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className={`${classes.zoomInButton} ${classes.controlButton}`}
|
||||||
|
onClick={() => zoomIn()}
|
||||||
|
>
|
||||||
|
<AddOutlinedIcon className={classes.iconSize} />
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ImagePreviewComponent = ({
|
||||||
|
fileUrl,
|
||||||
|
fileExtension,
|
||||||
|
handleDownload,
|
||||||
|
ref,
|
||||||
|
}) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{fileExtension === 'pdf' ? (
|
||||||
|
<>
|
||||||
|
<Box className={classes.pdfAndDocPreviewBox}>
|
||||||
|
<img
|
||||||
|
alt="Uploaded file"
|
||||||
|
src={FILE_EXTENTIONS_ICONS[fileExtension]}
|
||||||
|
ref={ref}
|
||||||
|
height="145px"
|
||||||
|
width="auto"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className={classes.pdfAndDocPreviewDownloadButton}
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleDownload}
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
) : fileExtension === 'doc' ||
|
||||||
|
fileExtension === 'docx' ||
|
||||||
|
fileExtension ===
|
||||||
|
'vnd.openxmlformats-officedocument.wordprocessingml.document' ||
|
||||||
|
fileExtension === 'msword' ? (
|
||||||
|
<>
|
||||||
|
<Box className={classes.pdfAndDocPreviewBox}>
|
||||||
|
<img
|
||||||
|
alt="Uploaded file"
|
||||||
|
src={FILE_EXTENTIONS_ICONS[fileExtension]}
|
||||||
|
ref={ref}
|
||||||
|
height="145px"
|
||||||
|
width="auto"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className={classes.pdfAndDocPreviewDownloadButton}
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleDownload}
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<TransformWrapper>
|
||||||
|
{(utils) => (
|
||||||
|
<React.Fragment>
|
||||||
|
<Box className={classes.transFormImageBox}>
|
||||||
|
<TransformComponent
|
||||||
|
wrapperClass={classes.customTransFormWrapper}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="Uploaded file"
|
||||||
|
src={fileUrl}
|
||||||
|
ref={ref}
|
||||||
|
height="250px"
|
||||||
|
width="auto"
|
||||||
|
/>
|
||||||
|
</TransformComponent>
|
||||||
|
</Box>
|
||||||
|
<ImagePreviewControls {...utils} />
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
</TransformWrapper>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImagePreviewComponent;
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
import makeStyles from '@mui/styles/makeStyles';
|
||||||
|
import { pxToRem } from '../../theme/typography';
|
||||||
|
|
||||||
|
export const useStyles = makeStyles((theme) => ({
|
||||||
|
pdfAndDocPreviewBox: {
|
||||||
|
minHeight: '450px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
},
|
||||||
|
pdfAndDocPreviewDownloadButton: {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
fontFamily: theme?.fontFamily?.regular,
|
||||||
|
},
|
||||||
|
transFormImageBox: {
|
||||||
|
minHeight: '65vh',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
customTransFormWrapper: {
|
||||||
|
overflow: 'visible',
|
||||||
|
},
|
||||||
|
iconSize: {
|
||||||
|
fontSize: pxToRem(28),
|
||||||
|
},
|
||||||
|
controlButtons: {
|
||||||
|
marginTop: theme.spacing(1),
|
||||||
|
},
|
||||||
|
controlButton: {
|
||||||
|
color: theme.palette.common.white,
|
||||||
|
cursor: 'pointer',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: theme.spacing(0),
|
||||||
|
padding: theme.spacing(1.2),
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.9)',
|
||||||
|
color: theme.palette.common.white,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
zoomOutButton: {
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.7)',
|
||||||
|
borderTopLeftRadius: theme.spacing(0.8),
|
||||||
|
borderBottomLeftRadius: theme.spacing(0.8),
|
||||||
|
},
|
||||||
|
zoomResetButton: {
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.4)',
|
||||||
|
},
|
||||||
|
zoomInButton: {
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.7)',
|
||||||
|
borderTopRightRadius: theme.spacing(0.8),
|
||||||
|
borderBottomRightRadius: theme.spacing(0.8),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
@ -7,22 +7,22 @@ import store from '../redux/store';
|
||||||
|
|
||||||
export const axiosInstance = axios.create({
|
export const axiosInstance = axios.create({
|
||||||
baseURL: API_BASE_URL,
|
baseURL: API_BASE_URL,
|
||||||
crossDomain: true,
|
// crossDomain: true,
|
||||||
headers: {
|
// headers: {
|
||||||
'Content-Type': 'application/json',
|
// 'Content-Type': 'application/json',
|
||||||
'Access-Control-Allow-Origin': '*',
|
// // 'Access-Control-Allow-Origin': '*',
|
||||||
'Access-Control-Allow-Headers': '*',
|
// // 'Access-Control-Allow-Headers': '*',
|
||||||
},
|
// },
|
||||||
withCredentials: true,
|
// withCredentials: false,
|
||||||
timeout: 300000,
|
// timeout: 300000,
|
||||||
});
|
});
|
||||||
|
|
||||||
axiosInstance.interceptors.request.use(
|
axiosInstance.interceptors.request.use(
|
||||||
async function (config) {
|
async function (config) {
|
||||||
try {
|
try {
|
||||||
const token = JSON.parse(localStorage.getItem('redux'));
|
const token = JSON.parse(localStorage.getItem('redux'));
|
||||||
if (token?.data?.data) {
|
if (token?.login?.token) {
|
||||||
config.headers.Authorization = `${token?.data?.data}`;
|
config.headers.Authorization = `Bearer ${token?.login?.token}`;
|
||||||
}
|
}
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const companyId = state?.loginAsCompanyAdmin?.companyId; // Extract companyId
|
const companyId = state?.loginAsCompanyAdmin?.companyId; // Extract companyId
|
||||||
|
|
@ -47,7 +47,7 @@ axiosInstance.interceptors.request.use(
|
||||||
|
|
||||||
axiosInstance.interceptors.response.use(
|
axiosInstance.interceptors.response.use(
|
||||||
function (response) {
|
function (response) {
|
||||||
if (response?.data && response?.data?.error !== '') {
|
if (response?.data && response?.data?.error !== null) {
|
||||||
pushNotification(response?.data?.message, NOTIFICATION.ERROR);
|
pushNotification(response?.data?.message, NOTIFICATION.ERROR);
|
||||||
return Promise.reject(response);
|
return Promise.reject(response);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { initializeApp } from 'firebase/app';
|
import { initializeApp } from 'firebase/app';
|
||||||
import { getMessaging, onMessage } from 'firebase/messaging';
|
import { getMessaging, onMessage, isSupported } from 'firebase/messaging';
|
||||||
|
|
||||||
export const firebaseConfig = {
|
export const firebaseConfig = {
|
||||||
apiKey: "AIzaSyDBDwlnQsbIxKni_UzZxDjeIk0akK-vDPM",
|
apiKey: "AIzaSyDBDwlnQsbIxKni_UzZxDjeIk0akK-vDPM",
|
||||||
|
|
@ -12,7 +12,35 @@ export const firebaseConfig = {
|
||||||
|
|
||||||
const firebaseApp = initializeApp(firebaseConfig);
|
const firebaseApp = initializeApp(firebaseConfig);
|
||||||
export default firebaseApp;
|
export default firebaseApp;
|
||||||
export const messaging = getMessaging(firebaseApp);
|
|
||||||
|
|
||||||
export const onForegroundMessage = () =>
|
// Initialize messaging only if supported
|
||||||
new Promise((resolve) => onMessage(messaging, (payload) => resolve(payload)));
|
let messagingInstance = null;
|
||||||
|
|
||||||
|
// Check if messaging is supported before initializing
|
||||||
|
export const initializeMessaging = async () => {
|
||||||
|
try {
|
||||||
|
const isSupportedBrowser = await isSupported();
|
||||||
|
if (isSupportedBrowser) {
|
||||||
|
messagingInstance = getMessaging(firebaseApp);
|
||||||
|
return messagingInstance;
|
||||||
|
} else {
|
||||||
|
console.log('Firebase messaging is not supported in this browser');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error checking messaging support:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Safe getter for messaging
|
||||||
|
export const getMessagingInstance = () => messagingInstance;
|
||||||
|
|
||||||
|
// Safe onForegroundMessage function
|
||||||
|
export const onForegroundMessage = async () => {
|
||||||
|
const messaging = await initializeMessaging();
|
||||||
|
if (!messaging) {
|
||||||
|
return Promise.resolve(null); // Return resolved promise with null if messaging not supported
|
||||||
|
}
|
||||||
|
return new Promise((resolve) => onMessage(messaging, (payload) => resolve(payload)));
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,12 @@ export const NOTIFICATION = {
|
||||||
ERROR: 'error',
|
ERROR: 'error',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const USER_ROLES = {
|
||||||
|
SUPER_ADMIN: 'SUPER_ADMIN',
|
||||||
|
CLINIC_ADMIN: 'CLINIC_ADMIN',
|
||||||
|
}
|
||||||
|
|
||||||
export const CLINIC_TYPE = {
|
export const CLINIC_TYPE = {
|
||||||
UNREGISTERED: 'UNREGISTERED',
|
UNREGISTERED: 'UNREGISTERED',
|
||||||
REGISTERED: 'REGISTERED',
|
REGISTERED: 'REGISTERED',
|
||||||
|
|
@ -28,6 +34,8 @@ export const PERMISSIONS = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CLINIC_STATUS = {
|
export const CLINIC_STATUS = {
|
||||||
|
UNDER_REVIEW:"UNDER_REVIEW",
|
||||||
|
ACTIVE:"ACTIVE",
|
||||||
ON_HOLD: 'ON_HOLD',
|
ON_HOLD: 'ON_HOLD',
|
||||||
REJECTED: 'REJECTED',
|
REJECTED: 'REJECTED',
|
||||||
NOT_REVIEWED: 'NOT_REVIEWED',
|
NOT_REVIEWED: 'NOT_REVIEWED',
|
||||||
|
|
@ -145,6 +153,10 @@ export const numRegex = /^[0-9\b]+$/;
|
||||||
|
|
||||||
import PdfIcon from '../assets/images/icon/pdf.png';
|
import PdfIcon from '../assets/images/icon/pdf.png';
|
||||||
import DocIcon from '../assets/images/icon/doc.png';
|
import DocIcon from '../assets/images/icon/doc.png';
|
||||||
|
import JpegIcon from '../assets/images/icon/jpeg.png';
|
||||||
|
import JpgIcon from '../assets/images/icon/jpg.png';
|
||||||
|
import PngIcon from '../assets/images/icon/png.png';
|
||||||
|
import SvgIcon from '../assets/images/icon/svg.png';
|
||||||
|
|
||||||
export const FILE_EXTENTIONS_ICONS = {
|
export const FILE_EXTENTIONS_ICONS = {
|
||||||
pdf: PdfIcon,
|
pdf: PdfIcon,
|
||||||
|
|
@ -152,6 +164,10 @@ export const FILE_EXTENTIONS_ICONS = {
|
||||||
docx: DocIcon,
|
docx: DocIcon,
|
||||||
'vnd.openxmlformats-officedocument.wordprocessingml.document': DocIcon,
|
'vnd.openxmlformats-officedocument.wordprocessingml.document': DocIcon,
|
||||||
msword: DocIcon,
|
msword: DocIcon,
|
||||||
|
jpeg: JpegIcon,
|
||||||
|
jpg: JpgIcon,
|
||||||
|
png: PngIcon,
|
||||||
|
svg: SvgIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEBOUNCE_DELAY = 500;
|
export const DEBOUNCE_DELAY = 500;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { onMessage } from 'firebase/messaging';
|
import { onMessage } from 'firebase/messaging';
|
||||||
import { createContext, useEffect, useState } from 'react';
|
import { createContext, useEffect, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { messaging } from '../config/firebase';
|
import { initializeMessaging, getMessagingInstance } from '../config/firebase';
|
||||||
import { redirectByNotificationType } from '../views/Notifications/notificationUtils';
|
import { redirectByNotificationType } from '../views/Notifications/notificationUtils';
|
||||||
|
|
||||||
// Create the context
|
// Create the context
|
||||||
|
|
@ -12,8 +12,15 @@ const FirebaseProvider = (props) => {
|
||||||
const navigate = useNavigate(); // Initialize navigation without page reload
|
const navigate = useNavigate(); // Initialize navigation without page reload
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkNewMessage(messaging);
|
const setupMessaging = async () => {
|
||||||
}, [messaging]);
|
const messagingInstance = await initializeMessaging();
|
||||||
|
if (messagingInstance) {
|
||||||
|
checkNewMessage(messagingInstance);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setupMessaging();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const showBrowserNotifications = (payload) => {
|
const showBrowserNotifications = (payload) => {
|
||||||
// Handle notification click
|
// Handle notification click
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import ProfileSection from './ProfileSection';
|
||||||
import { useStyles } from '../mainLayoutStyles';
|
import { useStyles } from '../mainLayoutStyles';
|
||||||
import NotificationSection from './NotificationSection ';
|
import NotificationSection from './NotificationSection ';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { CLINIC_STATUS } from '../../../constants';
|
import { CLINIC_STATUS, USER_ROLES } from '../../../constants';
|
||||||
|
|
||||||
function Header() {
|
function Header() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
@ -21,7 +21,7 @@ function Header() {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Typography>
|
<Typography>
|
||||||
{user?.isBsAdmin ? null : `Welcome to ${user?.company?.name}`}
|
{user?.userType == USER_ROLES.SUPER_ADMIN.toLowerCase() ? null : `Welcome to ${user?.created_clinics?.[0]?.name}`}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box className={classes.profilDiv}>
|
<Box className={classes.profilDiv}>
|
||||||
<NotificationSection />
|
<NotificationSection />
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { useTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
// assets
|
// assets
|
||||||
import signoutImg from '../../../assets/images/icon/signout.svg';
|
import signoutImg from '../../../assets/images/icon/signout.svg';
|
||||||
|
import phoneImg from '../../../assets/images/icon/phone.svg';
|
||||||
|
|
||||||
import { useStyles } from '../mainLayoutStyles';
|
import { useStyles } from '../mainLayoutStyles';
|
||||||
import MainCard from './MainCard';
|
import MainCard from './MainCard';
|
||||||
|
|
@ -38,7 +39,7 @@ const ProfileSection = () => {
|
||||||
const anchorRef = useRef(null);
|
const anchorRef = useRef(null);
|
||||||
|
|
||||||
const user = useSelector((state) => state?.login?.user);
|
const user = useSelector((state) => state?.login?.user);
|
||||||
const isBsAdmin = user?.isBsAdmin;
|
const isSuperAdmin = user?.isSuperAdmin;
|
||||||
|
|
||||||
const companyStatus = useSelector(
|
const companyStatus = useSelector(
|
||||||
(state) => state?.login?.user?.company?.status
|
(state) => state?.login?.user?.company?.status
|
||||||
|
|
@ -66,7 +67,8 @@ const ProfileSection = () => {
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
|
|
||||||
{ id: 5, img: signoutImg, text: 'Sign Out', alt: 'signoutImg' },
|
{ id: 1, img: phoneImg, text: 'Contact Us', alt: 'contactUsImg' },
|
||||||
|
{ id: 2, img: signoutImg, text: 'Sign Out', alt: 'signoutImg' },
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
const renderProfile = (item, index) => (
|
const renderProfile = (item, index) => (
|
||||||
|
|
@ -76,6 +78,7 @@ const ProfileSection = () => {
|
||||||
<ListItem button key={`menu-item-${item.id}`} onClick={() => handleMenuItemClick(item)}>
|
<ListItem button key={`menu-item-${item.id}`} onClick={() => handleMenuItemClick(item)}>
|
||||||
<Box className={classes.listIcon}>
|
<Box className={classes.listIcon}>
|
||||||
<img
|
<img
|
||||||
|
style={{ width: "20px", height: "20px" }}
|
||||||
src={item.img}
|
src={item.img}
|
||||||
className={classes.iconImage}
|
className={classes.iconImage}
|
||||||
alt={item.alt}
|
alt={item.alt}
|
||||||
|
|
@ -94,10 +97,10 @@ const ProfileSection = () => {
|
||||||
const handleMenuItemClick = (item) => {
|
const handleMenuItemClick = (item) => {
|
||||||
switch (item.id) {
|
switch (item.id) {
|
||||||
case 1:
|
case 1:
|
||||||
navigate('/profile-settings');
|
// navigate('/contact-us');
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
navigate(`/profile`);
|
commonLogoutFunc();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
// setShowTransactionHistoryPopup(true);
|
// setShowTransactionHistoryPopup(true);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import { SIDEBAR_CONFIG } from "./sideBarConfig"; // Adjust path if necessary
|
||||||
const Sidebar = ({ onClose, showCloseIcon }) => {
|
const Sidebar = ({ onClose, showCloseIcon }) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { isBSAdmin } = isBSPortal();
|
const { isSuperAdmin } = isBSPortal();
|
||||||
const [activeLink, setActiveLink] = useState("Dashboard");
|
const [activeLink, setActiveLink] = useState("Dashboard");
|
||||||
const [accordianActiveLink, setAccordianActiveLink] = useState("All Jobs");
|
const [accordianActiveLink, setAccordianActiveLink] = useState("All Jobs");
|
||||||
const [parentRoute, setParentRoute] = useState("");
|
const [parentRoute, setParentRoute] = useState("");
|
||||||
|
|
@ -92,13 +92,13 @@ const Sidebar = ({ onClose, showCloseIcon }) => {
|
||||||
(companyStatus === CLINIC_STATUS.APPROVED &&
|
(companyStatus === CLINIC_STATUS.APPROVED &&
|
||||||
HIDE_FUNCTIONALITY &&
|
HIDE_FUNCTIONALITY &&
|
||||||
HIDE_MODULES.includes(item?.path)) ||
|
HIDE_MODULES.includes(item?.path)) ||
|
||||||
(isBSAdmin && HIDE_FUNCTIONALITY && HIDE_MODULES.includes(item?.path));
|
(isSuperAdmin && HIDE_FUNCTIONALITY && HIDE_MODULES.includes(item?.path));
|
||||||
|
|
||||||
// Only render if user has the required role
|
// Only render if user has the required role
|
||||||
if (hasRole) {
|
if (hasRole) {
|
||||||
// Determine if the link should be disabled
|
// Determine if the link should be disabled
|
||||||
const isDisabled =
|
const isDisabled =
|
||||||
(!isBSAdmin && companyStatus !== CLINIC_STATUS.APPROVED) || hideFeature;
|
(!isSuperAdmin && companyStatus !== CLINIC_STATUS.APPROVED) || hideFeature;
|
||||||
const targetPath = isDisabled ? "#" : `/${item.path}`;
|
const targetPath = isDisabled ? "#" : `/${item.path}`;
|
||||||
const isActive = activeLink === item.path; // Check if this link is the active one
|
const isActive = activeLink === item.path; // Check if this link is the active one
|
||||||
|
|
||||||
|
|
@ -239,7 +239,7 @@ const Sidebar = ({ onClose, showCloseIcon }) => {
|
||||||
{visibleChildren.map((subItem, subIndex) => {
|
{visibleChildren.map((subItem, subIndex) => {
|
||||||
// Determine if the sub-item link should be disabled
|
// Determine if the sub-item link should be disabled
|
||||||
const isSubDisabled =
|
const isSubDisabled =
|
||||||
!isBSAdmin && companyStatus !== CLINIC_STATUS.APPROVED; // Add hideFeature logic if needed for sub-items
|
!isSuperAdmin && companyStatus !== CLINIC_STATUS.APPROVED; // Add hideFeature logic if needed for sub-items
|
||||||
const subTargetPath = isSubDisabled ? "#" : `/${subItem.path}`;
|
const subTargetPath = isSubDisabled ? "#" : `/${subItem.path}`;
|
||||||
const isSubActive = combinedRoute === subItem.path; // Check if this child link is active
|
const isSubActive = combinedRoute === subItem.path; // Check if this child link is active
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,9 @@ import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined';
|
||||||
import SettingsIcon from '@mui/icons-material/Settings';
|
import SettingsIcon from '@mui/icons-material/Settings';
|
||||||
import ArticleIcon from '@mui/icons-material/Article';
|
import ArticleIcon from '@mui/icons-material/Article';
|
||||||
import ArticleOutlinedIcon from '@mui/icons-material/ArticleOutlined';
|
import ArticleOutlinedIcon from '@mui/icons-material/ArticleOutlined';
|
||||||
import TopicIcon from '@mui/icons-material/Topic';
|
import PaymentIcon from '@mui/icons-material/Payment';
|
||||||
import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
|
import PaymentOutlinedIcon from '@mui/icons-material/PaymentOutlined';
|
||||||
|
import { USER_ROLES } from '../../../constants';
|
||||||
import { USER_ROLES } from '../../../redux/userRoleSlice';
|
|
||||||
|
|
||||||
// Define the sidebar configuration with proper permission fields
|
// Define the sidebar configuration with proper permission fields
|
||||||
export const SIDEBAR_CONFIG = [
|
export const SIDEBAR_CONFIG = [
|
||||||
|
|
@ -48,6 +47,14 @@ export const SIDEBAR_CONFIG = [
|
||||||
// Only super admin can access admin staff management
|
// Only super admin can access admin staff management
|
||||||
roles: [USER_ROLES.SUPER_ADMIN]
|
roles: [USER_ROLES.SUPER_ADMIN]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: 'Payment Management',
|
||||||
|
path: 'payment-management',
|
||||||
|
icon: PaymentOutlinedIcon,
|
||||||
|
activeIcon: PaymentIcon,
|
||||||
|
// Only super admin can access payment management
|
||||||
|
roles: [USER_ROLES.SUPER_ADMIN]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: 'Doctor/Nurse Management',
|
text: 'Doctor/Nurse Management',
|
||||||
path: 'doctor',
|
path: 'doctor',
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ export const mockSuperAdmin = {
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "Super Admin User",
|
name: "Super Admin User",
|
||||||
email: "superadmin@example.com",
|
email: "superadmin@example.com",
|
||||||
isBsAdmin: true,
|
isSuperAdmin: true,
|
||||||
isAdmin: true,
|
isAdmin: true,
|
||||||
permissions: ["SUPER_ADMIN_PERMISSION"],
|
permissions: ["SUPER_ADMIN_PERMISSION"],
|
||||||
roles: [
|
roles: [
|
||||||
|
|
@ -25,7 +25,7 @@ export const mockClinicAdmin = {
|
||||||
id: 2,
|
id: 2,
|
||||||
name: "Clinic Admin User",
|
name: "Clinic Admin User",
|
||||||
email: "clinicadmin@example.com",
|
email: "clinicadmin@example.com",
|
||||||
isBsAdmin: false,
|
isSuperAdmin: false,
|
||||||
isAdmin: true,
|
isAdmin: true,
|
||||||
permissions: ["CLINIC_ADMIN_PERMISSION"],
|
permissions: ["CLINIC_ADMIN_PERMISSION"],
|
||||||
roles: [
|
roles: [
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export const setMockUser = (userType) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Export mock user types for convenience
|
// Export mock user types for convenience
|
||||||
export const MOCK_USER_TYPES = {
|
export const MOCK_USER_ROLES = {
|
||||||
SUPER_ADMIN: 'superAdmin',
|
SUPER_ADMIN: 'superAdmin',
|
||||||
CLINIC_ADMIN: 'clinicAdmin'
|
CLINIC_ADMIN: 'clinicAdmin'
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,3 @@
|
||||||
// User role constants
|
|
||||||
export const USER_ROLES = {
|
|
||||||
SUPER_ADMIN: 'SUPER_ADMIN',
|
|
||||||
CLINIC_ADMIN: 'CLINIC_ADMIN',
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initial state
|
// Initial state
|
||||||
const initialState = {
|
const initialState = {
|
||||||
role: null,
|
role: null,
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import ClinicSetup from "../views/ClinicSetup";
|
||||||
import ClinicTranscripts from "../views/ClinicTranscripts";
|
import ClinicTranscripts from "../views/ClinicTranscripts";
|
||||||
import ContractManagement from "../views/ContractManagement";
|
import ContractManagement from "../views/ContractManagement";
|
||||||
import MasterDataManagement from "../views/MasterData";
|
import MasterDataManagement from "../views/MasterData";
|
||||||
|
import PaymentManagement from "../views/PaymentManagement";
|
||||||
|
|
||||||
export const routesData = [
|
export const routesData = [
|
||||||
{
|
{
|
||||||
|
|
@ -26,6 +27,7 @@ export const routesData = [
|
||||||
{ path: "/clinicSetup", component: ClinicSetup },
|
{ path: "/clinicSetup", component: ClinicSetup },
|
||||||
{ path: "/transcripts", component: ClinicTranscripts },
|
{ path: "/transcripts", component: ClinicTranscripts },
|
||||||
{ path: "/masterData", component: MasterDataManagement },
|
{ path: "/masterData", component: MasterDataManagement },
|
||||||
|
{ path: "/payment-management", component: PaymentManagement },
|
||||||
],
|
],
|
||||||
isProtected: true,
|
isProtected: true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ const withPermission = (Component) => (props) => {
|
||||||
const companyStatus = useSelector(
|
const companyStatus = useSelector(
|
||||||
(state) => state?.login?.user?.company?.status
|
(state) => state?.login?.user?.company?.status
|
||||||
);
|
);
|
||||||
const { isBSAdmin } = false;
|
const { isSuperAdmin } = false;
|
||||||
// const { isBSAdmin } = isBSPortal();
|
// const { isSuperAdmin } = isBSPortal();
|
||||||
|
|
||||||
// If the user is a BS Admin, render the component without any checks
|
// If the user is a BS Admin, render the component without any checks
|
||||||
if (isBSAdmin === true) {
|
if (isSuperAdmin === true) {
|
||||||
return <Component {...props} />;
|
return <Component {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
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));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -1,21 +1,42 @@
|
||||||
|
import { axiosInstance } from "../config/api";
|
||||||
import { CLINIC_TYPE } from "../constants";
|
import { CLINIC_TYPE } from "../constants";
|
||||||
import { clinicsData, registeredClinicsData } from "../mock/clinics";
|
import { clinicsData, registeredClinicsData } from "../mock/clinics";
|
||||||
|
|
||||||
|
// export const getClinics = (params) => {
|
||||||
|
// switch (params.type) {
|
||||||
|
// case CLINIC_TYPE.UNREGISTERED:
|
||||||
|
// return { data: clinicsData };
|
||||||
|
// case CLINIC_TYPE.REGISTERED:
|
||||||
|
// return { data: registeredClinicsData };
|
||||||
|
// case CLINIC_TYPE.SUBSCRIBED:
|
||||||
|
// return { data: registeredClinicsData };
|
||||||
|
// default:
|
||||||
|
// return { data: clinicsData };
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
export const getClinics = (params) => {
|
export const getClinics = (params) => {
|
||||||
switch (params.type) {
|
console.log(params);
|
||||||
case CLINIC_TYPE.UNREGISTERED:
|
|
||||||
return { data: clinicsData };
|
let searchParams = new URLSearchParams();
|
||||||
case CLINIC_TYPE.REGISTERED:
|
searchParams.append("size", params?.pagination?.pageSize ?? 10);
|
||||||
return { data: registeredClinicsData };
|
searchParams.append("page", params?.pagination.pageIndex ?? 0);
|
||||||
case CLINIC_TYPE.SUBSCRIBED:
|
searchParams.append("filter_type", params?.type ?? CLINIC_TYPE.REGISTERED);
|
||||||
return { data: registeredClinicsData };
|
searchParams.append("search", params?.globalFilter ?? "");
|
||||||
default:
|
|
||||||
return { data: clinicsData };
|
let url = `/clinics/?${searchParams.toString()}`;
|
||||||
}
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axiosInstance
|
||||||
|
.get(url)
|
||||||
|
.then((response) => resolve(response))
|
||||||
|
.catch((err) => reject(err));
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getClinicsById = (id) => {
|
export const getLatestClinicId = () => {
|
||||||
const url = `/companies/${id}`;
|
const url = `/clinics/latest-id`;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axiosInstance
|
axiosInstance
|
||||||
.get(url)
|
.get(url)
|
||||||
|
|
@ -24,11 +45,31 @@ export const getClinics = (params) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateClinicStatus = (id, data) => {
|
export const getClinicsById = (id) => {
|
||||||
const url = `/companies/${id}/company-review`;
|
const url = `/clinics/${id}`;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axiosInstance
|
axiosInstance
|
||||||
.post(url, data)
|
.get(url)
|
||||||
|
.then((response) => resolve(response))
|
||||||
|
.catch((err) => reject(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateClinicStatus = (data) => {
|
||||||
|
const url = `/admin/clinic/status/`;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axiosInstance
|
||||||
|
.put(url, data)
|
||||||
|
.then((response) => resolve(response))
|
||||||
|
.catch((err) => reject(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateClinicDocs = (id, data) => {
|
||||||
|
const url = `/clinics/${id}`;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axiosInstance
|
||||||
|
.put(url, data)
|
||||||
.then((response) => resolve(response))
|
.then((response) => resolve(response))
|
||||||
.catch((err) => reject(err));
|
.catch((err) => reject(err));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { axiosInstance } from "../config/api";
|
||||||
|
|
||||||
|
export const getDashboardStats = () => {
|
||||||
|
const url = '/dashboard/';
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axiosInstance
|
||||||
|
.get(url)
|
||||||
|
.then((response) => resolve(response))
|
||||||
|
.catch((err) => reject(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const getSignupMasterPricing = () => {
|
||||||
|
const url = '/dashboard/signup-pricing-master/';
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axiosInstance
|
||||||
|
.get(url)
|
||||||
|
.then((response) => resolve(response))
|
||||||
|
.catch((err) => reject(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const setSignupMasterPricing = (data) => {
|
||||||
|
const url = '/dashboard/signup-pricing-master/';
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axiosInstance
|
||||||
|
.post(url, data)
|
||||||
|
.then((response) => resolve(response))
|
||||||
|
.catch((err) => reject(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -23,3 +23,27 @@ export const fileUpload = (data, type = null, companyId = null) => {
|
||||||
.catch((err) => reject(err));
|
.catch((err) => reject(err));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getPresignedUrl = (data) => {
|
||||||
|
const url = `/s3`;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axiosInstance
|
||||||
|
.post(url, data)
|
||||||
|
.then((response) => resolve(response))
|
||||||
|
.catch((err) => reject(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const uploadToS3 = (file, putUrl) =>{
|
||||||
|
const url = putUrl;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axiosInstance
|
||||||
|
.put(url, file, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => resolve(response))
|
||||||
|
.catch((err) => reject(err));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { jwtDecode } from "jwt-decode";
|
||||||
|
|
||||||
|
export const decodeJWT = (token) => {
|
||||||
|
return jwtDecode(token);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { logout } from "../services/users.service";
|
import { logout } from "../services/users.service";
|
||||||
import { deleteToken } from "firebase/messaging";
|
import { deleteToken } from "firebase/messaging";
|
||||||
import { messaging } from "../config/firebase";
|
import { getMessagingInstance } from "../config/firebase";
|
||||||
|
|
||||||
export const isLoggedIn = () => {
|
export const isLoggedIn = () => {
|
||||||
let redux = JSON.parse(localStorage.getItem("redux"));
|
let redux = JSON.parse(localStorage.getItem("redux"));
|
||||||
|
|
@ -27,8 +27,8 @@ export const resetLocalStorage = () => {
|
||||||
|
|
||||||
export const isBSPortal = () => {
|
export const isBSPortal = () => {
|
||||||
let redux = JSON.parse(localStorage.getItem("redux"));
|
let redux = JSON.parse(localStorage.getItem("redux"));
|
||||||
const isBSAdmin = redux?.login?.user?.isBsAdmin;
|
const isSuperAdmin = redux?.login?.user?.isSuperAdmin;
|
||||||
return { isBSAdmin };
|
return { isSuperAdmin };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const commonLogoutFunc = async (redirectPath = "/auth/login") => {
|
export const commonLogoutFunc = async (redirectPath = "/auth/login") => {
|
||||||
|
|
|
||||||
|
|
@ -29,90 +29,78 @@ const FileEvaluate = ({
|
||||||
const [reviewedLogoFiles, setReviewedLogoFiles] = useState([]);
|
const [reviewedLogoFiles, setReviewedLogoFiles] = useState([]);
|
||||||
const [notReviewedLogoFiles, setNotReviewedLogoFiles] = useState([]);
|
const [notReviewedLogoFiles, setNotReviewedLogoFiles] = useState([]);
|
||||||
const [reviewedOtherFiles, setReviewedOtherFiles] = useState([]);
|
const [reviewedOtherFiles, setReviewedOtherFiles] = useState([]);
|
||||||
const [notReviewedOtherFiles, setNotReviewedOtherFile] = useState([]);
|
const [notReviewedOtherFiles, setNotReviewedOtherFiles] = useState([]);
|
||||||
|
|
||||||
const getAscendingArray = (array) => {
|
// const getAscendingArray = (array) => {
|
||||||
const gstFiles = array.filter((file) => file.documentType === 'GST');
|
|
||||||
const panFiles = array.filter((file) => file.documentType === 'PAN');
|
|
||||||
const tanFiles = array.filter((file) => file.documentType === 'TAN');
|
|
||||||
const filteredArray = [];
|
|
||||||
const maxLength = Math.max(
|
|
||||||
gstFiles.length,
|
|
||||||
panFiles.length,
|
|
||||||
tanFiles.length
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let i = 0; i < maxLength; i++) {
|
|
||||||
if (gstFiles[i]) {
|
|
||||||
filteredArray.push(gstFiles[i]);
|
|
||||||
}
|
|
||||||
if (panFiles[i]) {
|
|
||||||
filteredArray.push(panFiles[i]);
|
|
||||||
}
|
|
||||||
if (tanFiles[i]) {
|
|
||||||
filteredArray.push(tanFiles[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filteredArray;
|
// return filteredArray;
|
||||||
};
|
// };
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// ...........reviewed logo file set...............
|
if (!Array.isArray(files)) return;
|
||||||
if (Array.isArray(files)) {
|
|
||||||
const filteredFiles = files.filter(
|
// Process all files at once to avoid multiple iterations
|
||||||
(file) =>
|
const reviewedLogo = [];
|
||||||
file.documentType === 'LOGO' &&
|
const notReviewedLogo = [];
|
||||||
(file.status === CLINIC_DOCUMENT_STATUS.APPROVED ||
|
const reviewedOther = [];
|
||||||
file.status === CLINIC_DOCUMENT_STATUS.REJECTED)
|
const notReviewedOther = [];
|
||||||
);
|
|
||||||
setReviewedLogoFiles(filteredFiles);
|
files.forEach(file => {
|
||||||
|
// Handle logo documents
|
||||||
|
if (file.logo_doc) {
|
||||||
|
if (file.logo_doc_is_verified) {
|
||||||
|
reviewedLogo.push({file: file.logo_doc, documentType: 'LOGO', isVerified: file.logo_doc_is_verified});
|
||||||
|
} else {
|
||||||
|
notReviewedLogo.push({file: file.logo_doc, documentType: 'LOGO', isVerified: file.logo_doc_is_verified});
|
||||||
}
|
}
|
||||||
// .............no review logo files set............
|
|
||||||
if (Array.isArray(files)) {
|
|
||||||
const filteredFiles = files.filter(
|
|
||||||
(file) =>
|
|
||||||
file.documentType === 'LOGO' &&
|
|
||||||
file.status === CLINIC_DOCUMENT_STATUS.NOT_REVIEWED
|
|
||||||
);
|
|
||||||
setNotReviewedLogoFiles(filteredFiles);
|
|
||||||
}
|
}
|
||||||
// ..............reviewed other file set............
|
|
||||||
if (Array.isArray(files)) {
|
// Handle ABN and contract documents (excluding logo docs which are handled separately)
|
||||||
const filteredFiles = files.filter(
|
if (file.abn_doc ) {
|
||||||
(file) =>
|
if (file.abn_doc_is_verified) {
|
||||||
(file.documentType === 'PAN' ||
|
reviewedOther.push({file: file.abn_doc, documentType: 'ABN', isVerified: file.abn_doc_is_verified});
|
||||||
file.documentType === 'TAN' ||
|
|
||||||
file.documentType === 'GST') &&
|
|
||||||
(file.status === CLINIC_DOCUMENT_STATUS.APPROVED ||
|
|
||||||
file.status === CLINIC_DOCUMENT_STATUS.REJECTED)
|
|
||||||
);
|
|
||||||
setReviewedOtherFiles(getAscendingArray(filteredFiles));
|
|
||||||
}
|
}
|
||||||
// .............. no reviewed other file set...........
|
else{
|
||||||
if (Array.isArray(files)) {
|
notReviewedOther.push({file: file.abn_doc, documentType: 'ABN', isVerified: file.abn_doc_is_verified});
|
||||||
const filteredFiles = files.filter(
|
|
||||||
(file) =>
|
|
||||||
(file.documentType === 'PAN' ||
|
|
||||||
file.documentType === 'TAN' ||
|
|
||||||
file.documentType === 'GST') &&
|
|
||||||
file.status === CLINIC_DOCUMENT_STATUS.NOT_REVIEWED
|
|
||||||
);
|
|
||||||
setNotReviewedOtherFile(getAscendingArray(filteredFiles));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.contract_doc) {
|
||||||
|
if (file.contract_doc_is_verified) {
|
||||||
|
reviewedOther.push({file: file.contract_doc, documentType: 'CONTRACT', isVerified: file.contract_doc_is_verified});
|
||||||
|
} else{
|
||||||
|
notReviewedOther.push({file: file.contract_doc, documentType: 'CONTRACT', isVerified: file.contract_doc_is_verified});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update state with filtered files
|
||||||
|
setReviewedLogoFiles(reviewedLogo);
|
||||||
|
setNotReviewedLogoFiles(notReviewedLogo);
|
||||||
|
setReviewedOtherFiles(reviewedOther);
|
||||||
|
setNotReviewedOtherFiles(notReviewedOther);
|
||||||
|
|
||||||
|
// Debug logs
|
||||||
|
console.log('Files processed:', files.length);
|
||||||
|
console.log('reviewedLogoFiles:', reviewedLogo);
|
||||||
|
console.log('notReviewedLogoFiles:', notReviewedLogo);
|
||||||
|
console.log('reviewedOtherFiles:', reviewedOther);
|
||||||
|
console.log('notReviewedOtherFiles:', notReviewedOther);
|
||||||
}, [files]);
|
}, [files]);
|
||||||
// .........................get file name and extention function.......................
|
// .........................get file name and extention function.......................
|
||||||
const getFileNameUsingFile = (file) => {
|
const getFileNameUsingFile = (file) => {
|
||||||
if (file) {
|
if (file) {
|
||||||
const url = new URL(file.fileURL);
|
// const url = new URL(file);
|
||||||
return url.pathname.split('/').pop();
|
// return url.pathname.split('/').pop();
|
||||||
|
return file
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFileExtentionUsingFile = (file) => {
|
const getFileExtentionUsingFile = (file) => {
|
||||||
if (file) {
|
if (file) {
|
||||||
const url = new URL(file.fileURL);
|
const url = new URL(file.file);
|
||||||
const fileName = url.pathname.split('/').pop();
|
const fileName = url.pathname.split('/').pop();
|
||||||
return fileName.split('.').pop();
|
return fileName.split('.').pop();
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +117,7 @@ const FileEvaluate = ({
|
||||||
: CLINIC_DOCUMENT_STATUS.REJECTED,
|
: CLINIC_DOCUMENT_STATUS.REJECTED,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (file.documentType === 'LOGO') {
|
if (file.logo_doc) {
|
||||||
const updatedFiles = [...notReviewedLogoFiles];
|
const updatedFiles = [...notReviewedLogoFiles];
|
||||||
updatedFiles.splice(index, 1, newFile);
|
updatedFiles.splice(index, 1, newFile);
|
||||||
setNotReviewedLogoFiles(updatedFiles);
|
setNotReviewedLogoFiles(updatedFiles);
|
||||||
|
|
@ -181,8 +169,12 @@ const FileEvaluate = ({
|
||||||
const handleDownload = (file) => {
|
const handleDownload = (file) => {
|
||||||
if (file) {
|
if (file) {
|
||||||
const anchor = document.createElement('a');
|
const anchor = document.createElement('a');
|
||||||
anchor.href = file.fileURL;
|
anchor.href = file.file; // file is now a direct URL
|
||||||
anchor.download = getFileNameUsingFile(file);
|
|
||||||
|
// Extract filename from URL for download attribute
|
||||||
|
const fileName = file.file.split('/').pop();
|
||||||
|
anchor.download = fileName;
|
||||||
|
|
||||||
anchor.click();
|
anchor.click();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -200,7 +192,7 @@ const FileEvaluate = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* ............CLINIC is Approved that time show only card............. */}
|
{/* ............CLINIC is Approved that time show only card............. */}
|
||||||
{companyStatus === CLINIC_STATUS.APPROVED ? (
|
{companyStatus === CLINIC_STATUS.ACTIVE ? (
|
||||||
<>
|
<>
|
||||||
<Grid container className={classes.mainGrid} gap={3.5}>
|
<Grid container className={classes.mainGrid} gap={3.5}>
|
||||||
{reviewedLogoFiles.map((file, index) => (
|
{reviewedLogoFiles.map((file, index) => (
|
||||||
|
|
@ -217,10 +209,10 @@ const FileEvaluate = ({
|
||||||
<Typography className={classes.titleOfBox}>
|
<Typography className={classes.titleOfBox}>
|
||||||
CLINIC LOGO INFO
|
CLINIC LOGO INFO
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.updatedDate}>
|
{/* <Typography className={classes.updatedDate}>
|
||||||
Uploaded:{' '}
|
Uploaded:{' '}
|
||||||
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
||||||
</Typography>
|
</Typography> */}
|
||||||
<Typography className={classes.documentNumberAndNameLabel}>
|
<Typography className={classes.documentNumberAndNameLabel}>
|
||||||
{companyName} LOGO
|
{companyName} LOGO
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
@ -228,7 +220,7 @@ const FileEvaluate = ({
|
||||||
<Box className={classes.imageBox}>
|
<Box className={classes.imageBox}>
|
||||||
<img
|
<img
|
||||||
className={classes.image}
|
className={classes.image}
|
||||||
src={file.fileURL}
|
src={file.file}
|
||||||
alt="Uploaded File"
|
alt="Uploaded File"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -251,10 +243,10 @@ const FileEvaluate = ({
|
||||||
<Typography className={classes.titleOfBox}>
|
<Typography className={classes.titleOfBox}>
|
||||||
CLINIC {file.documentType} INFO
|
CLINIC {file.documentType} INFO
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.updatedDate}>
|
{/* <Typography className={classes.updatedDate}>
|
||||||
Uploaded:{' '}
|
Uploaded:{' '}
|
||||||
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
||||||
</Typography>
|
</Typography> */}
|
||||||
<Typography className={classes.documentNumberAndNameLabel}>
|
<Typography className={classes.documentNumberAndNameLabel}>
|
||||||
{file.documentNumber}
|
{file.documentNumber}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
@ -287,10 +279,10 @@ const FileEvaluate = ({
|
||||||
<Typography className={classes.titleOfBox}>
|
<Typography className={classes.titleOfBox}>
|
||||||
CLINIC LOGO INFO
|
CLINIC LOGO INFO
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.updatedDate}>
|
{/* <Typography className={classes.updatedDate}>
|
||||||
Uploaded:{' '}
|
Uploaded:{' '}
|
||||||
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
||||||
</Typography>
|
</Typography> */}
|
||||||
<Typography className={classes.documentNumberAndNameLabel}>
|
<Typography className={classes.documentNumberAndNameLabel}>
|
||||||
{companyName} LOGO
|
{companyName} LOGO
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
@ -341,10 +333,10 @@ const FileEvaluate = ({
|
||||||
<Typography className={classes.titleOfBox}>
|
<Typography className={classes.titleOfBox}>
|
||||||
CLINIC {file.documentType} INFO
|
CLINIC {file.documentType} INFO
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.updatedDate}>
|
{/* <Typography className={classes.updatedDate}>
|
||||||
Uploaded:{' '}
|
Uploaded:{' '}
|
||||||
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
||||||
</Typography>
|
</Typography> */}
|
||||||
<Typography className={classes.documentNumberAndNameLabel}>
|
<Typography className={classes.documentNumberAndNameLabel}>
|
||||||
{companyName} LOGO
|
{companyName} LOGO
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
@ -494,17 +486,17 @@ const FileEvaluate = ({
|
||||||
<Typography className={classes.titleOfBox}>
|
<Typography className={classes.titleOfBox}>
|
||||||
CLINIC {file.documentType} INFO
|
CLINIC {file.documentType} INFO
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.updatetdDate}>
|
{/* <Typography className={classes.updatetdDate}>
|
||||||
Uploaded:{' '}
|
Uploaded:{' '}
|
||||||
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
{format(new Date(file?.updatedAt), 'dd MMM yyyy')}
|
||||||
</Typography>
|
</Typography> */}
|
||||||
<Box className={classes.documentNumberAndNameLabelBox}>
|
<Box className={classes.documentNumberAndNameLabelBox}>
|
||||||
<Typography
|
{/* <Typography
|
||||||
className={classes.documentNumberAndNameLabel}
|
className={classes.documentNumberAndNameLabel}
|
||||||
>
|
>
|
||||||
{file.documentNumber}
|
{file.documentNumber}
|
||||||
</Typography>
|
</Typography> */}
|
||||||
{file.documentNumber.length === GST_NUMBER_LENGTH &&
|
{/* {file.documentNumber.length === GST_NUMBER_LENGTH &&
|
||||||
file.documentType !== 'TAN' &&
|
file.documentType !== 'TAN' &&
|
||||||
file.documentType !== 'PAN' && (
|
file.documentType !== 'PAN' && (
|
||||||
<Typography
|
<Typography
|
||||||
|
|
@ -521,7 +513,7 @@ const FileEvaluate = ({
|
||||||
>
|
>
|
||||||
<VerifiedIcon className={classes.verifyIcon} />
|
<VerifiedIcon className={classes.verifyIcon} />
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)} */}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
@ -632,17 +624,15 @@ const FileEvaluate = ({
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item md={12} className={classes.previewFileTitle}>
|
<Grid item md={12} className={classes.previewFileTitle}>
|
||||||
<Typography color="white">
|
<Typography color="white">
|
||||||
{getFileNameUsingFile(previewFile)}
|
{previewFile.split('/').pop()}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid xs={12} className={classes.previewImageGrid}>
|
<Grid xs={12} className={classes.previewImageGrid}>
|
||||||
<ImagePreviewComponent
|
<ImagePreviewComponent
|
||||||
file={previewFile}
|
fileUrl={previewFile}
|
||||||
fileUrl={previewFile.fileURL}
|
|
||||||
fileExtension={getFileExtentionUsingFile(previewFile)}
|
fileExtension={getFileExtentionUsingFile(previewFile)}
|
||||||
handlePreview={handlePreview}
|
|
||||||
handleDownload={() => handleDownload(previewFile)}
|
handleDownload={() => handleDownload(previewFile)}
|
||||||
classes={classes}
|
classes={classes}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ import { profile } from '../../Login/loginAction';
|
||||||
import { setClinicId } from '../store/logInAsClinicAdminAction';
|
import { setClinicId } from '../store/logInAsClinicAdminAction';
|
||||||
import { useStyles } from './styles/generalInformationStyles';
|
import { useStyles } from './styles/generalInformationStyles';
|
||||||
|
|
||||||
const GeneralInformation = ({ companyData, companyAdminData }) => {
|
const GeneralInformation = ({ clinicData, clinicAdminData }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const handleViewCompanyDashboard = async () => {
|
const handleViewCompanyDashboard = async () => {
|
||||||
dispatch(setClinicId({ companyId: companyData?.id }));
|
dispatch(setClinicId({ companyId: clinicData?.id }));
|
||||||
await dispatch(profile());
|
await dispatch(profile());
|
||||||
navigate('/');
|
navigate('/');
|
||||||
};
|
};
|
||||||
|
|
@ -32,13 +32,13 @@ const GeneralInformation = ({ companyData, companyAdminData }) => {
|
||||||
<Grid item xs={3}>
|
<Grid item xs={3}>
|
||||||
<Typography className={classes.generalInfoUploaded}>
|
<Typography className={classes.generalInfoUploaded}>
|
||||||
Uploaded:{' '}
|
Uploaded:{' '}
|
||||||
{companyData?.updatedAt
|
{clinicData?.updatedAt
|
||||||
? format(new Date(companyData?.createdAt), 'dd MMM yyyy')
|
? format(new Date(clinicData?.createdAt), 'dd MMM yyyy')
|
||||||
: ''}
|
: ''}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={3}>
|
<Grid item xs={3}>
|
||||||
{companyData?.status === CLINIC_STATUS.APPROVED && (
|
{clinicData?.status === CLINIC_STATUS.APPROVED && (
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
variant="contained"
|
variant="contained"
|
||||||
display={false}
|
display={false}
|
||||||
|
|
@ -55,15 +55,15 @@ const GeneralInformation = ({ companyData, companyAdminData }) => {
|
||||||
<Grid className={classes.companyNameGrid}>
|
<Grid className={classes.companyNameGrid}>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Typography className={classes.companyNameLabel}>
|
<Typography className={classes.companyNameLabel}>
|
||||||
Para Hills
|
{clinicData?.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid xs={12} className={classes.companyNameSubTitleGrid}>
|
<Grid xs={12} className={classes.companyNameSubTitleGrid}>
|
||||||
<div>
|
<div>
|
||||||
<Typography className={classes.companyNameSubTitleLabel}>
|
<Typography className={classes.companyNameSubTitleLabel}>
|
||||||
Raised On:{' '}
|
Raised On:{' '}
|
||||||
{companyData?.requestRaisedOn
|
{clinicData?.update_time
|
||||||
? format(new Date(companyData?.requestRaisedOn), 'dd MMM yyyy')
|
? format(new Date(clinicData?.update_time), 'dd MMM yyyy')
|
||||||
: NOT_AVAILABLE_TEXT}
|
: NOT_AVAILABLE_TEXT}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -74,17 +74,7 @@ const GeneralInformation = ({ companyData, companyAdminData }) => {
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<Typography className={classes.companyNameSubTitleLabel}>
|
<Typography className={classes.companyNameSubTitleLabel}>
|
||||||
Website: {companyData?.website}
|
{clinicData?.email}
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
<Divider
|
|
||||||
className={classes.dividerClass}
|
|
||||||
orientation="vertical"
|
|
||||||
flexItem
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<Typography className={classes.companyNameSubTitleLabel}>
|
|
||||||
User ID: admin@gmail.com
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -93,7 +83,7 @@ const GeneralInformation = ({ companyData, companyAdminData }) => {
|
||||||
<Box className={classes.companyUserDetails}>
|
<Box className={classes.companyUserDetails}>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography className={classes.companyUserDetailsTitle}>
|
<Typography className={classes.companyUserDetailsTitle}>
|
||||||
{companyAdminData?.name}
|
{clinicAdminData?.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.companyUserDetailsSubTitle}>
|
<Typography className={classes.companyUserDetailsSubTitle}>
|
||||||
User Name
|
User Name
|
||||||
|
|
@ -101,8 +91,8 @@ const GeneralInformation = ({ companyData, companyAdminData }) => {
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography className={classes.companyUserDetailsTitle}>
|
<Typography className={classes.companyUserDetailsTitle}>
|
||||||
{companyAdminData?.designation
|
{clinicAdminData?.designation
|
||||||
? companyAdminData?.designation
|
? clinicAdminData?.designation
|
||||||
: NOT_AVAILABLE_TEXT}
|
: NOT_AVAILABLE_TEXT}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.companyUserDetailsSubTitle}>
|
<Typography className={classes.companyUserDetailsSubTitle}>
|
||||||
|
|
@ -111,8 +101,8 @@ const GeneralInformation = ({ companyData, companyAdminData }) => {
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography className={classes.companyUserDetailsTitle}>
|
<Typography className={classes.companyUserDetailsTitle}>
|
||||||
{companyAdminData?.mobile
|
{clinicAdminData?.phone
|
||||||
? `+91-${companyAdminData.mobile}`
|
? `${clinicAdminData.phone}`
|
||||||
: NOT_AVAILABLE_TEXT}
|
: NOT_AVAILABLE_TEXT}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.companyUserDetailsSubTitle}>
|
<Typography className={classes.companyUserDetailsSubTitle}>
|
||||||
|
|
@ -121,7 +111,7 @@ const GeneralInformation = ({ companyData, companyAdminData }) => {
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography className={classes.companyUserDetailsTitle}>
|
<Typography className={classes.companyUserDetailsTitle}>
|
||||||
{companyData?.pinCode ? companyData?.pinCode : NOT_AVAILABLE_TEXT}
|
{clinicData?.postal_code ? clinicData?.postal_code : NOT_AVAILABLE_TEXT}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.companyUserDetailsSubTitle}>
|
<Typography className={classes.companyUserDetailsSubTitle}>
|
||||||
Pincode
|
Pincode
|
||||||
|
|
@ -133,7 +123,7 @@ const GeneralInformation = ({ companyData, companyAdminData }) => {
|
||||||
<Grid container className={classes.companyDetailsAddressGrid}>
|
<Grid container className={classes.companyDetailsAddressGrid}>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Typography className={classes.companyUserDetailsTitle}>
|
<Typography className={classes.companyUserDetailsTitle}>
|
||||||
{companyData?.street ? companyData?.street : NOT_AVAILABLE_TEXT}
|
{clinicData?.address ? clinicData?.address : NOT_AVAILABLE_TEXT}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className={classes.companyUserDetailsSubTitle}>
|
<Typography className={classes.companyUserDetailsSubTitle}>
|
||||||
Full Address
|
Full Address
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import DoneIcon from '@mui/icons-material/Done';
|
import DoneIcon from "@mui/icons-material/Done";
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from "@mui/lab";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
|
|
@ -10,30 +10,31 @@ import {
|
||||||
Tab,
|
Tab,
|
||||||
TextField,
|
TextField,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from "@mui/material";
|
||||||
import { useFormik } from 'formik';
|
import { useFormik } from "formik";
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
|
import { Link, useLocation, useNavigate, useParams } from "react-router-dom";
|
||||||
import * as Yup from 'yup';
|
import * as Yup from "yup";
|
||||||
import onHoldDisableIcon from '../../assets/images/icon/onHoldDisable.svg';
|
import onHoldDisableIcon from "../../assets/images/icon/onHoldDisable.svg";
|
||||||
import onHoldEnableIcon from '../../assets/images/icon/onHoldEnable.svg';
|
import onHoldEnableIcon from "../../assets/images/icon/onHoldEnable.svg";
|
||||||
import CustomBreadcrumbs from '../../components/CustomBreadcrumbs';
|
import CustomBreadcrumbs from "../../components/CustomBreadcrumbs";
|
||||||
import Loader from '../../components/Loader';
|
import Loader from "../../components/Loader";
|
||||||
import PageHeader from '../../components/PageHeader';
|
import PageHeader from "../../components/PageHeader";
|
||||||
import {
|
import {
|
||||||
CLINIC_DOCUMENT_STATUS,
|
CLINIC_DOCUMENT_STATUS,
|
||||||
CLINIC_STATUS,
|
CLINIC_STATUS,
|
||||||
NOTIFICATION,
|
NOTIFICATION,
|
||||||
} from '../../constants';
|
} from "../../constants";
|
||||||
import {
|
import {
|
||||||
getClinicsById,
|
getClinicsById,
|
||||||
updateClinicStatus,
|
updateClinicStatus,
|
||||||
} from '../../services/clinics.service';
|
} from "../../services/clinics.service";
|
||||||
import { pushNotification } from '../../utils/notification';
|
import { pushNotification } from "../../utils/notification";
|
||||||
import CustomModal from '../Modal/Modal';
|
import CustomModal from "../Modal/Modal";
|
||||||
import { useStyles } from './clinicDetailsStyles';
|
import { useStyles } from "./clinicDetailsStyles";
|
||||||
|
import FileEvaluate from "./component/FileEvaluate";
|
||||||
|
|
||||||
import GeneralInformation from './component/GeneralInformation';
|
import GeneralInformation from "./component/GeneralInformation";
|
||||||
|
|
||||||
function ClinicDetails() {
|
function ClinicDetails() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
@ -42,11 +43,12 @@ function ClinicDetails() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [companyData, setCompanyData] = useState('');
|
const [clinicData, setClinicData] = useState("");
|
||||||
const [companyAdminData, setCompanyAdminData] = useState('');
|
const [clinicFiles, setClinicFiles] = useState("");
|
||||||
|
const [clinicAdminData, setClinicAdminData] = useState("");
|
||||||
const [isShowReasonModel, setIsShowReasonModel] = useState(false);
|
const [isShowReasonModel, setIsShowReasonModel] = useState(false);
|
||||||
const [updateFiles, setUpdateFiles] = useState([]);
|
const [updateFiles, setUpdateFiles] = useState([]);
|
||||||
const [buttonClickStatus, setButtonClickStatus] = useState('');
|
const [buttonClickStatus, setButtonClickStatus] = useState("");
|
||||||
const [isRejectButtonShow, setIsRejectedButtonShow] = useState(false);
|
const [isRejectButtonShow, setIsRejectedButtonShow] = useState(false);
|
||||||
const [isOnHoldButtonShow, setIsOnHoldButtonShow] = useState(false);
|
const [isOnHoldButtonShow, setIsOnHoldButtonShow] = useState(false);
|
||||||
const [isAcceptButtonShow, setIsAcceptedButtonShow] = useState(false);
|
const [isAcceptButtonShow, setIsAcceptedButtonShow] = useState(false);
|
||||||
|
|
@ -57,13 +59,12 @@ function ClinicDetails() {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const response = await getClinicsById(id);
|
const response = await getClinicsById(id);
|
||||||
setCompanyData(response?.data?.data);
|
setClinicData(response?.data?.data?.clinic);
|
||||||
setCompanyAdminData(
|
setClinicFiles(response?.data?.data?.clinic_files);
|
||||||
response?.data?.data?.companyUsers?.find((user) => user.isAdmin) || null
|
setClinicAdminData(response?.data?.data?.creator);
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error('Error fetching data:', error);
|
console.error("Error fetching data:", error);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
|
|
@ -75,17 +76,17 @@ function ClinicDetails() {
|
||||||
// ...................breadcrumbs array........................
|
// ...................breadcrumbs array........................
|
||||||
const breadcrumbs = [
|
const breadcrumbs = [
|
||||||
{
|
{
|
||||||
label: 'Dashboard',
|
label: "Dashboard",
|
||||||
path: '/',
|
path: "/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Clinic List',
|
label: "Clinic List",
|
||||||
path: '/clinics',
|
path: "/clinics",
|
||||||
query: { tab: queryParams.get('tab') || 'UNREGISTERED' },
|
query: { tab: queryParams.get("tab") || "UNREGISTERED" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Clinics Details',
|
label: "Clinics Details",
|
||||||
path: '',
|
path: "",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -93,7 +94,7 @@ function ClinicDetails() {
|
||||||
|
|
||||||
const updateCompany = async (body) => {
|
const updateCompany = async (body) => {
|
||||||
try {
|
try {
|
||||||
const response = await updateClinicStatus(companyData?.id, body);
|
const response = await updateClinicStatus(body);
|
||||||
if (response?.data?.error) {
|
if (response?.data?.error) {
|
||||||
pushNotification(response?.data?.message, NOTIFICATION.ERROR);
|
pushNotification(response?.data?.message, NOTIFICATION.ERROR);
|
||||||
setIsShowReasonModel(false);
|
setIsShowReasonModel(false);
|
||||||
|
|
@ -105,7 +106,7 @@ function ClinicDetails() {
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error('Error', error);
|
console.error("Error", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -116,7 +117,7 @@ function ClinicDetails() {
|
||||||
setIsOnHoldButtonShow(false);
|
setIsOnHoldButtonShow(false);
|
||||||
};
|
};
|
||||||
const defaultFormData = useRef({
|
const defaultFormData = useRef({
|
||||||
reason: '',
|
reason: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const fieldRefs = {
|
const fieldRefs = {
|
||||||
|
|
@ -124,7 +125,7 @@ function ClinicDetails() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const validationSchema = Yup.object({
|
const validationSchema = Yup.object({
|
||||||
reason: Yup.string().required('Reason is required.'),
|
reason: Yup.string().required("Reason is required."),
|
||||||
});
|
});
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
initialValues: defaultFormData.current,
|
initialValues: defaultFormData.current,
|
||||||
|
|
@ -148,9 +149,9 @@ function ClinicDetails() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNotReviewedFileCount = () => {
|
const getNotReviewedFileCount = () => {
|
||||||
if (companyData?.companyDocuments) {
|
if (clinicData?.companyDocuments) {
|
||||||
const notReviewedDocuments = companyData.companyDocuments.filter(
|
const notReviewedDocuments = clinicData.companyDocuments.filter(
|
||||||
(document) => document.status === 'NOT_REVIEWED'
|
(document) => document.status === "NOT_REVIEWED"
|
||||||
);
|
);
|
||||||
return notReviewedDocuments.length;
|
return notReviewedDocuments.length;
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +161,7 @@ function ClinicDetails() {
|
||||||
const handleCancelRejection = async () => {
|
const handleCancelRejection = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
// const resp = await companyCancelRejection(companyData?.id);
|
// const resp = await companyCancelRejection(clinicData?.id);
|
||||||
// if (resp?.data?.error) {
|
// if (resp?.data?.error) {
|
||||||
// pushNotification(resp?.data?.message, NOTIFICATION.ERROR);
|
// pushNotification(resp?.data?.message, NOTIFICATION.ERROR);
|
||||||
// fetchData();
|
// fetchData();
|
||||||
|
|
@ -172,7 +173,7 @@ function ClinicDetails() {
|
||||||
// setUpdateFiles(() => []);
|
// setUpdateFiles(() => []);
|
||||||
// setButtonClickStatus('');
|
// setButtonClickStatus('');
|
||||||
// }
|
// }
|
||||||
console.log("cancel rejection")
|
console.log("cancel rejection");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Handle error if needed
|
// Handle error if needed
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -192,17 +193,17 @@ function ClinicDetails() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
userId: companyAdminData?.id,
|
clinic_id: clinicData?.id,
|
||||||
reason: values ? values.reason : '',
|
rejection_reason: values ? values.reason : "",
|
||||||
status:
|
status:
|
||||||
buttonClickStatus === 'Rejected'
|
buttonClickStatus === "Rejected"
|
||||||
? CLINIC_STATUS.REJECTED
|
? CLINIC_STATUS.REJECTED.toLowerCase()
|
||||||
: buttonClickStatus === 'On Hold'
|
: buttonClickStatus === "On Hold"
|
||||||
? CLINIC_STATUS.ON_HOLD
|
? CLINIC_STATUS.UNDER_REVIEW.toLowerCase()
|
||||||
: CLINIC_STATUS.APPROVED,
|
: CLINIC_STATUS.ACTIVE.toLowerCase(),
|
||||||
documentStatus: {
|
// documentStatus: {
|
||||||
...documentStatusMap,
|
// ...documentStatusMap,
|
||||||
},
|
// },
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
@ -210,17 +211,17 @@ function ClinicDetails() {
|
||||||
// .................handle accept reject and on hold event.............
|
// .................handle accept reject and on hold event.............
|
||||||
const handleRejectClick = () => {
|
const handleRejectClick = () => {
|
||||||
setIsShowReasonModel(true);
|
setIsShowReasonModel(true);
|
||||||
setButtonClickStatus('Rejected');
|
setButtonClickStatus("Rejected");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnHoldClick = () => {
|
const handleOnHoldClick = () => {
|
||||||
setIsShowReasonModel(true);
|
setIsShowReasonModel(true);
|
||||||
setButtonClickStatus('On Hold');
|
setButtonClickStatus("On Hold");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAcceptClick = () => {
|
const handleAcceptClick = () => {
|
||||||
// setIsShowReasonModel(true);
|
// setIsShowReasonModel(true);
|
||||||
setButtonClickStatus('Accepted');
|
setButtonClickStatus("Accepted");
|
||||||
const body = formatedData();
|
const body = formatedData();
|
||||||
|
|
||||||
updateCompany(body);
|
updateCompany(body);
|
||||||
|
|
@ -229,31 +230,28 @@ function ClinicDetails() {
|
||||||
// ..................update file use effects................
|
// ..................update file use effects................
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsRejectedButtonShow(
|
setIsRejectedButtonShow(
|
||||||
updateFiles.some(
|
clinicFiles.abn_doc_is_verified != true &&
|
||||||
(file) => file.status === CLINIC_DOCUMENT_STATUS.REJECTED
|
clinicFiles.contract_doc_is_verified != true
|
||||||
)
|
|
||||||
);
|
);
|
||||||
setIsOnHoldButtonShow(
|
|
||||||
updateFiles.some(
|
|
||||||
(file) => file.status === CLINIC_DOCUMENT_STATUS.REJECTED
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const notReviewedFileCount = getNotReviewedFileCount();
|
|
||||||
|
|
||||||
const areAllFilesApproved = updateFiles.every(
|
setIsOnHoldButtonShow(
|
||||||
(file) => file.status === CLINIC_DOCUMENT_STATUS.APPROVED
|
clinicFiles.abn_doc_is_verified != true &&
|
||||||
|
clinicFiles.contract_doc_is_verified != true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const areAllFilesApproved =
|
||||||
|
clinicFiles.abn_doc_is_verified == true &&
|
||||||
|
clinicFiles.contract_doc_is_verified == true;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
notReviewedFileCount === updateFiles.length &&
|
|
||||||
areAllFilesApproved &&
|
areAllFilesApproved &&
|
||||||
companyData?.status !== CLINIC_STATUS.ON_HOLD &&
|
clinicData?.status === CLINIC_STATUS.UNDER_REVIEW.toLowerCase()
|
||||||
companyData?.status !== CLINIC_STATUS.REJECTED
|
|
||||||
) {
|
) {
|
||||||
setIsAcceptedButtonShow(true);
|
setIsAcceptedButtonShow(true);
|
||||||
} else {
|
} else {
|
||||||
setIsAcceptedButtonShow(false);
|
setIsAcceptedButtonShow(false);
|
||||||
}
|
}
|
||||||
}, [updateFiles]);
|
}, [clinicFiles]);
|
||||||
|
|
||||||
// ..............handle table change..........
|
// ..............handle table change..........
|
||||||
const handleTabChange = (event, newValue) => {
|
const handleTabChange = (event, newValue) => {
|
||||||
|
|
@ -261,7 +259,7 @@ function ClinicDetails() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditCompanyInfo = () => {
|
const handleEditCompanyInfo = () => {
|
||||||
navigate(`/clinics/${companyData?.id}/edit`);
|
navigate(`/clinics/${clinicData?.id}/edit`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmitClick = async () => {
|
const handleSubmitClick = async () => {
|
||||||
|
|
@ -275,10 +273,10 @@ function ClinicDetails() {
|
||||||
|
|
||||||
if (firstErrorRef) {
|
if (firstErrorRef) {
|
||||||
// Scroll to the first invalid field smoothly
|
// Scroll to the first invalid field smoothly
|
||||||
if (typeof firstErrorRef?.scrollIntoView === 'function') {
|
if (typeof firstErrorRef?.scrollIntoView === "function") {
|
||||||
firstErrorRef?.scrollIntoView({
|
firstErrorRef?.scrollIntoView({
|
||||||
behavior: 'smooth',
|
behavior: "smooth",
|
||||||
block: 'center',
|
block: "center",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -302,7 +300,7 @@ function ClinicDetails() {
|
||||||
pageTitle="Clinics Details"
|
pageTitle="Clinics Details"
|
||||||
hideAddButton
|
hideAddButton
|
||||||
extraComponent={
|
extraComponent={
|
||||||
companyData.status === CLINIC_STATUS.APPROVED ? (
|
clinicData.status === CLINIC_STATUS.ACTIVE.toLowerCase() ? (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
className={classes.editCompanyInfoButton}
|
className={classes.editCompanyInfoButton}
|
||||||
|
|
@ -332,7 +330,7 @@ function ClinicDetails() {
|
||||||
<CloseIcon className={classes.statusButtonIcon} /> Reject
|
<CloseIcon className={classes.statusButtonIcon} /> Reject
|
||||||
</Button>
|
</Button>
|
||||||
<Box display="flex" className={classes.cancelRejectionBox}>
|
<Box display="flex" className={classes.cancelRejectionBox}>
|
||||||
{companyData?.status === CLINIC_STATUS.REJECTED && (
|
{clinicData?.status === CLINIC_STATUS.REJECTED && (
|
||||||
<Link
|
<Link
|
||||||
className={classes.cancelRejectionLink}
|
className={classes.cancelRejectionLink}
|
||||||
onClick={handleCancelRejection}
|
onClick={handleCancelRejection}
|
||||||
|
|
@ -389,12 +387,12 @@ function ClinicDetails() {
|
||||||
<Box>
|
<Box>
|
||||||
<Paper className={classes.generalInfoPaper}>
|
<Paper className={classes.generalInfoPaper}>
|
||||||
<GeneralInformation
|
<GeneralInformation
|
||||||
companyData={companyData}
|
clinicData={clinicData}
|
||||||
companyAdminData={companyAdminData}
|
clinicAdminData={clinicAdminData}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
{/* {companyData.status === CLINIC_STATUS.APPROVED ? (
|
{clinicData.status === CLINIC_STATUS.ACTIVE ? (
|
||||||
<>
|
<>
|
||||||
<FormSectionHeading
|
<FormSectionHeading
|
||||||
title="More Details"
|
title="More Details"
|
||||||
|
|
@ -405,57 +403,53 @@ function ClinicDetails() {
|
||||||
<Box>
|
<Box>
|
||||||
<TabList onChange={handleTabChange}>
|
<TabList onChange={handleTabChange}>
|
||||||
<Tab label="Document Details" value={1} />
|
<Tab label="Document Details" value={1} />
|
||||||
{/* <Tab label="Plan Details" value={2} /> */}
|
<Tab label="Plan Details" value={2} />
|
||||||
{/* <Tab label="Recruitment Analytics" value={3} /> */}
|
</TabList>
|
||||||
{/* </TabList>
|
|
||||||
</Box>
|
</Box>
|
||||||
<TabPanel className={classes.tabsPanel} value={1}>
|
<TabPanel className={classes.tabsPanel} value={1}>
|
||||||
<Box>
|
<Box>
|
||||||
<FileEvaluate
|
<FileEvaluate
|
||||||
companyStatus={companyData && companyData?.status}
|
companyStatus={clinicData && clinicData?.status}
|
||||||
companyName={companyData && companyData?.name}
|
companyName={clinicData && clinicData?.name}
|
||||||
files={companyData && companyData?.companyDocuments}
|
files={clinicData && clinicData?.companyDocuments}
|
||||||
onFileButtonClick={handleFileButtonClick}
|
onFileButtonClick={handleFileButtonClick}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel className={classes.tabsPanel} value={2}>
|
<TabPanel className={classes.tabsPanel} value={2}>
|
||||||
<PlanDetails
|
<PlanDetails
|
||||||
companyData={companyData}
|
clinicData={clinicData}
|
||||||
reFetchData={fetchData}
|
reFetchData={fetchData}
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel className={classes.tabsPanel} value={3}>
|
|
||||||
<RecruitmentAnalytics
|
|
||||||
totalJobPublishedCount={
|
|
||||||
companyData?.recruitmentAnalytics?.totalJobs
|
|
||||||
}
|
|
||||||
activeJobsCount={
|
|
||||||
companyData?.recruitmentAnalytics?.activeJobs
|
|
||||||
}
|
|
||||||
expiredJobsCount={
|
|
||||||
companyData?.recruitmentAnalytics?.closedJobs
|
|
||||||
}
|
|
||||||
jobsInDraftCount={
|
|
||||||
companyData?.recruitmentAnalytics?.draftJobs
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
</TabContext>
|
</TabContext>
|
||||||
</Grid>
|
</Grid>
|
||||||
</> */}
|
</>
|
||||||
{/* ) : (
|
) : (
|
||||||
<Box>
|
<Box>
|
||||||
<FileEvaluate
|
<FileEvaluate
|
||||||
companyStatus={companyData && companyData?.status}
|
companyStatus={clinicData && clinicData?.status}
|
||||||
companyName={companyData && companyData?.name}
|
companyName={clinicData && clinicData?.name}
|
||||||
files={companyData && companyData?.companyDocuments}
|
files={
|
||||||
|
clinicData && [
|
||||||
|
{
|
||||||
|
abn_doc: clinicData?.abn_doc,
|
||||||
|
abn_doc_is_verified: clinicFiles?.abn_doc_is_verified,
|
||||||
|
contract_doc: clinicData?.contract_doc,
|
||||||
|
contract_doc_is_verified:
|
||||||
|
clinicFiles?.contract_doc_is_verified,
|
||||||
|
logo_doc: clinicData?.logo,
|
||||||
|
logo_doc_is_verified: clinicFiles?.logo_is_verified,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
onFileButtonClick={handleFileButtonClick}
|
onFileButtonClick={handleFileButtonClick}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)} */}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isShowReasonModel && (
|
{isShowReasonModel && (
|
||||||
<CustomModal
|
<CustomModal
|
||||||
title={`Mark ${buttonClickStatus}`}
|
title={`Mark ${buttonClickStatus}`}
|
||||||
|
|
@ -465,15 +459,15 @@ function ClinicDetails() {
|
||||||
modalBodyFunction={() => (
|
modalBodyFunction={() => (
|
||||||
<Box className={classes.reasonModelBox}>
|
<Box className={classes.reasonModelBox}>
|
||||||
<Typography>
|
<Typography>
|
||||||
{buttonClickStatus === 'Rejected'
|
{buttonClickStatus === "Rejected"
|
||||||
? 'Please define a reason for rejecting this company.'
|
? "Please define a reason for rejecting this company."
|
||||||
: 'Please define a reason for putting this company on hold.'}
|
: "Please define a reason for putting this company on hold."}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid item xs={12} className={classes.inputTextGrid}>
|
<Grid item xs={12} className={classes.inputTextGrid}>
|
||||||
<InputLabel className={classes.inputLabel}>
|
<InputLabel className={classes.inputLabel}>
|
||||||
{buttonClickStatus === 'Rejected'
|
{buttonClickStatus === "Rejected"
|
||||||
? 'Reason for Rejection'
|
? "Reason for Rejection"
|
||||||
: 'Reason for On Hold'}
|
: "Reason for On Hold"}
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
@ -492,7 +486,7 @@ function ClinicDetails() {
|
||||||
helperText={
|
helperText={
|
||||||
formik.errors.reason && formik.touched.reason
|
formik.errors.reason && formik.touched.reason
|
||||||
? formik.errors.reason
|
? formik.errors.reason
|
||||||
: ''
|
: ""
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import FileDownloadIcon from '@mui/icons-material/FileDownload';
|
||||||
|
|
||||||
|
|
||||||
import { useStyles } from "./clinicListStyles";
|
import { useStyles } from "./clinicListStyles";
|
||||||
import { CLINIC_STATUS, CLINIC_TYPE, PLAN_STATUS_TYPE } from "../../constants";
|
import { CLINIC_STATUS, CLINIC_TYPE, NOT_AVAILABLE_TEXT, PLAN_STATUS_TYPE } from "../../constants";
|
||||||
import { getClinics } from "../../services/clinics.service";
|
import { getClinics } from "../../services/clinics.service";
|
||||||
import CustomBreadcrumbs from "../../components/CustomBreadcrumbs";
|
import CustomBreadcrumbs from "../../components/CustomBreadcrumbs";
|
||||||
import Table from "../../components/Table";
|
import Table from "../../components/Table";
|
||||||
|
|
@ -115,14 +115,14 @@ const ClinicsList = () => {
|
||||||
enableColumnFilter: false,
|
enableColumnFilter: false,
|
||||||
enableSorting: true,
|
enableSorting: true,
|
||||||
size: 100,
|
size: 100,
|
||||||
accessorKey: "updatedAt",
|
accessorKey: "update_time",
|
||||||
header: "Req.Raised On",
|
header: "Req.Raised On",
|
||||||
Cell: ({ row }) => (
|
Cell: ({ row }) => (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
{row?.original?.requestRaisedOn
|
{row?.original?.update_time
|
||||||
? format(
|
? format(
|
||||||
new Date(row.original.requestRaisedOn),
|
new Date(row.original.update_time),
|
||||||
"dd MMM yyyy"
|
"dd MMM yyyy"
|
||||||
)
|
)
|
||||||
: NOT_AVAILABLE_TEXT}
|
: NOT_AVAILABLE_TEXT}
|
||||||
|
|
@ -196,8 +196,8 @@ const ClinicsList = () => {
|
||||||
<Chip
|
<Chip
|
||||||
className={classes.chipClass}
|
className={classes.chipClass}
|
||||||
label={
|
label={
|
||||||
status === CLINIC_STATUS.ON_HOLD ? (
|
status === CLINIC_STATUS.UNDER_REVIEW.toLowerCase() ? (
|
||||||
"On Hold"
|
"Under Review"
|
||||||
) : status === CLINIC_STATUS.NOT_REVIEWED ? (
|
) : status === CLINIC_STATUS.NOT_REVIEWED ? (
|
||||||
"Approval Pending"
|
"Approval Pending"
|
||||||
) : status ===
|
) : status ===
|
||||||
|
|
@ -208,7 +208,7 @@ const ClinicsList = () => {
|
||||||
Document Resubmitted
|
Document Resubmitted
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : status === CLINIC_STATUS.REJECTED ? (
|
) : status === CLINIC_STATUS.REJECTED.toLowerCase() ? (
|
||||||
"Rejected"
|
"Rejected"
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
|
|
@ -216,20 +216,20 @@ const ClinicsList = () => {
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
status === CLINIC_STATUS.ON_HOLD
|
status === CLINIC_STATUS.ON_HOLD.toLowerCase()
|
||||||
? theme.palette.orange.light
|
? theme.palette.orange.light
|
||||||
: status === CLINIC_STATUS.NOT_REVIEWED ||
|
: status === CLINIC_STATUS.NOT_REVIEWED.toLowerCase() ||
|
||||||
status === CLINIC_STATUS.REJECTED
|
status === CLINIC_STATUS.REJECTED.toLowerCase()
|
||||||
? theme.palette.primary.highlight
|
? theme.palette.primary.highlight
|
||||||
: status ===
|
: status ===
|
||||||
CLINIC_STATUS.APPROVAL_PENDING_DOCUMENT_RESUBMITTED
|
CLINIC_STATUS.APPROVAL_PENDING_DOCUMENT_RESUBMITTED
|
||||||
? theme.palette.primary.highlight
|
? theme.palette.primary.highlight
|
||||||
: theme.palette.blue.light,
|
: theme.palette.blue.light,
|
||||||
color:
|
color:
|
||||||
status === CLINIC_STATUS.ON_HOLD
|
status === CLINIC_STATUS.ON_HOLD.toLowerCase()
|
||||||
? theme.palette.orange.main
|
? theme.palette.orange.main
|
||||||
: status === CLINIC_STATUS.NOT_REVIEWED ||
|
: status === CLINIC_STATUS.NOT_REVIEWED.toLowerCase() ||
|
||||||
status === CLINIC_STATUS.REJECTED
|
status === CLINIC_STATUS.REJECTED.toLowerCase()
|
||||||
? theme.palette.primary.main
|
? theme.palette.primary.main
|
||||||
: status ===
|
: status ===
|
||||||
CLINIC_STATUS.APPROVAL_PENDING_DOCUMENT_RESUBMITTED
|
CLINIC_STATUS.APPROVAL_PENDING_DOCUMENT_RESUBMITTED
|
||||||
|
|
@ -406,9 +406,10 @@ const ClinicsList = () => {
|
||||||
type,
|
type,
|
||||||
};
|
};
|
||||||
const resp = await getClinics(params);
|
const resp = await getClinics(params);
|
||||||
|
console.log(resp)
|
||||||
return {
|
return {
|
||||||
data: resp?.data?.data?.records,
|
data: resp?.data?.data?.data?.clinics,
|
||||||
rowCount: resp?.data?.data?.totalCount,
|
rowCount: resp?.data?.data?.total,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -444,7 +445,8 @@ const ClinicsList = () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Clinic List",
|
label: "Clinic List",
|
||||||
path: "",
|
path: "/clinics",
|
||||||
|
query: { tab: queryParams.get('tab') || 'UNREGISTERED' }
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ const SuperAdminTotals = ({ isLoading, data }) => {
|
||||||
heading={`Approved`}
|
heading={`Approved`}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
viewAllClick={() => viewAllClick(false)}
|
viewAllClick={() => viewAllClick(false)}
|
||||||
value={rejected}
|
value={registered}
|
||||||
helperText={"Clinics"}
|
helperText={"Clinics"}
|
||||||
color={theme.palette.grey[52]}
|
color={theme.palette.grey[52]}
|
||||||
/>
|
/>
|
||||||
|
|
@ -52,7 +52,7 @@ const SuperAdminTotals = ({ isLoading, data }) => {
|
||||||
heading={`Rejected`}
|
heading={`Rejected`}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
viewAllClick={() => viewAllClick(false)}
|
viewAllClick={() => viewAllClick(false)}
|
||||||
value={registered}
|
value={rejected}
|
||||||
helperText={"Clinics"}
|
helperText={"Clinics"}
|
||||||
color={theme.palette.grey[57]}
|
color={theme.palette.grey[57]}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import ProtectedComponent from '../../../components/ProtectedComponent';
|
||||||
import { getClinicsDashboardStatsById } from '../../../services/clinics.service';
|
import { getClinicsDashboardStatsById } from '../../../services/clinics.service';
|
||||||
import TotalNumber from '../components/TotalNumber';
|
import TotalNumber from '../components/TotalNumber';
|
||||||
import { useStyles } from '../dashboardStyles';
|
import { useStyles } from '../dashboardStyles';
|
||||||
|
import { getDashboardStats } from '../../../services/dashboard.services';
|
||||||
|
|
||||||
const Totals = ({ data, setData }) => {
|
const Totals = ({ data, setData }) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
@ -19,12 +20,11 @@ const Totals = ({ data, setData }) => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const response = {};
|
const response = await getDashboardStats();
|
||||||
// const response = await getClinicsDashboardStatsById();
|
|
||||||
const apiData = response?.data?.data || {};
|
const apiData = response?.data?.data || {};
|
||||||
setData({
|
setData({
|
||||||
activeJobs: apiData.recruitmentAnalytics?.activeJobs,
|
activeJobs: apiData?.active,
|
||||||
totalMaxJobPostings: apiData.totalMaxJobPostings,
|
totalMaxJobPostings: apiData.inactive,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching data:', error);
|
console.error('Error fetching data:', error);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,205 @@
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
TextField,
|
||||||
|
Button,
|
||||||
|
Paper,
|
||||||
|
Grid,
|
||||||
|
Snackbar,
|
||||||
|
Alert,
|
||||||
|
InputAdornment
|
||||||
|
} from "@mui/material";
|
||||||
|
import { useStyles } from "../dashboardStyles";
|
||||||
|
import { getSignupMasterPricing, setSignupMasterPricing } from "../../../services/dashboard.services";
|
||||||
|
|
||||||
|
const PaymentConfig = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
// Initial payment configuration state
|
||||||
|
const [paymentConfig, setPaymentConfig] = useState({
|
||||||
|
setup_fees: "0.00",
|
||||||
|
subscription_fees: "0.00",
|
||||||
|
per_call_charges: "0.00"
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchPaymentConfig = async () => {
|
||||||
|
try {
|
||||||
|
const response = await getSignupMasterPricing();
|
||||||
|
const apiData = response?.data?.data || {};
|
||||||
|
setPaymentConfig({
|
||||||
|
setup_fees: apiData?.setup_fees,
|
||||||
|
subscription_fees: apiData?.subscription_fees,
|
||||||
|
per_call_charges: apiData?.per_call_charges
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching payment configuration:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchPaymentConfig();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// State for tracking if form has been edited
|
||||||
|
const [isEdited, setIsEdited] = useState(false);
|
||||||
|
|
||||||
|
// State for notification
|
||||||
|
const [notification, setNotification] = useState({
|
||||||
|
open: false,
|
||||||
|
message: "",
|
||||||
|
severity: "success"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle input change
|
||||||
|
const handleInputChange = (e) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
|
||||||
|
// Allow empty values, numbers, and decimal points with up to 2 decimal places
|
||||||
|
// This regex allows for more flexible input including empty string and partial numbers
|
||||||
|
if (value !== "" && !/^\d*(\.\d{0,2})?$/.test(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPaymentConfig({
|
||||||
|
...paymentConfig,
|
||||||
|
[name]: value
|
||||||
|
});
|
||||||
|
|
||||||
|
setIsEdited(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle save configuration
|
||||||
|
const handleSaveConfig = async () => {
|
||||||
|
try {
|
||||||
|
const response = await setSignupMasterPricing(paymentConfig);
|
||||||
|
const apiData = response?.data?.data || {};
|
||||||
|
setPaymentConfig({
|
||||||
|
setup_fees: apiData?.setup_fees,
|
||||||
|
subscription_fees: apiData?.subscription_fees,
|
||||||
|
per_call_charges: apiData?.per_call_charges
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching payment configuration:", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
setNotification({
|
||||||
|
open: true,
|
||||||
|
message: "Payment configuration saved successfully",
|
||||||
|
severity: "success"
|
||||||
|
});
|
||||||
|
|
||||||
|
setIsEdited(false);
|
||||||
|
|
||||||
|
// In a real implementation, you would save this data to your backend
|
||||||
|
console.log("Saving payment configuration:", paymentConfig);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle notification close
|
||||||
|
const handleCloseNotification = () => {
|
||||||
|
setNotification({
|
||||||
|
...notification,
|
||||||
|
open: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper elevation={3} sx={{ p: 3, mb: 4, borderRadius: 2 }}>
|
||||||
|
<Box mb={2}>
|
||||||
|
<Typography variant="h6" fontWeight="bold">
|
||||||
|
Payment Configuration
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
Configure payment details for new clinic registrations
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid item xs={12} md={4}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="Setup Fee"
|
||||||
|
name="setup_fees"
|
||||||
|
value={paymentConfig.setup_fees}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: <InputAdornment position="start">$</InputAdornment>,
|
||||||
|
}}
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={4}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="Subscription Fee (Monthly)"
|
||||||
|
name="subscription_fees"
|
||||||
|
value={paymentConfig.subscription_fees}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: <InputAdornment position="start">$</InputAdornment>,
|
||||||
|
}}
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={4}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="Per Call Charges"
|
||||||
|
name="per_call_charges"
|
||||||
|
value={paymentConfig.per_call_charges}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: <InputAdornment position="start">$</InputAdornment>,
|
||||||
|
endAdornment: <InputAdornment position="end">/call</InputAdornment>,
|
||||||
|
}}
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Box mt={3} display="flex" justifyContent="flex-end">
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleSaveConfig}
|
||||||
|
disabled={!isEdited}
|
||||||
|
sx={{
|
||||||
|
borderRadius: 50,
|
||||||
|
px: 3,
|
||||||
|
textTransform: "none",
|
||||||
|
backgroundColor: "#ff3366",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "#e61653",
|
||||||
|
},
|
||||||
|
"&:disabled": {
|
||||||
|
backgroundColor: "#ffb3c3",
|
||||||
|
color: "#ffffff"
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save Configuration
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Notification */}
|
||||||
|
<Snackbar
|
||||||
|
open={notification.open}
|
||||||
|
autoHideDuration={6000}
|
||||||
|
onClose={handleCloseNotification}
|
||||||
|
anchorOrigin={{ vertical: "top", horizontal: "right" }}
|
||||||
|
>
|
||||||
|
<Alert
|
||||||
|
onClose={handleCloseNotification}
|
||||||
|
severity={notification.severity}
|
||||||
|
sx={{ width: "100%" }}
|
||||||
|
>
|
||||||
|
{notification.message}
|
||||||
|
</Alert>
|
||||||
|
</Snackbar>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PaymentConfig;
|
||||||
|
|
@ -3,6 +3,8 @@ import { Box } from "@mui/system";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useStyles } from "../dashboardStyles";
|
import { useStyles } from "../dashboardStyles";
|
||||||
import SuperAdminTotals from "../Tiles/SuperAdminTotals";
|
import SuperAdminTotals from "../Tiles/SuperAdminTotals";
|
||||||
|
import PaymentConfig from "./PaymentConfig";
|
||||||
|
import { getDashboardStats } from "../../../services/dashboard.services";
|
||||||
|
|
||||||
const SuperAdmin = () => {
|
const SuperAdmin = () => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
@ -17,22 +19,14 @@ const SuperAdmin = () => {
|
||||||
const fetchDashboardStats = async () => {
|
const fetchDashboardStats = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
// const response = await getAdminDashboardStats();
|
const response = await getDashboardStats();
|
||||||
// const apiData = response?.data?.data || {};
|
const apiData = response?.data?.data || {};
|
||||||
// setData({
|
|
||||||
// totalAccounts: apiData?.dashboardStatistics?.totalAccounts,
|
|
||||||
// registrationRequest: apiData?.dashboardStatistics?.registrationRequest,
|
|
||||||
// rejected: apiData?.dashboardStatistics?.rejected,
|
|
||||||
// registered: apiData?.dashboardStatistics?.registered,
|
|
||||||
// });
|
|
||||||
setTimeout(() => {
|
|
||||||
setData({
|
setData({
|
||||||
totalAccounts: 10,
|
totalAccounts: apiData?.totalClinics,
|
||||||
registrationRequest: 5,
|
registrationRequest: apiData?.totalUnderReviewClinics,
|
||||||
rejected: 2,
|
rejected: apiData?.totalRejectedClinics,
|
||||||
registered: 8,
|
registered: apiData?.totalActiveClinics,
|
||||||
});
|
});
|
||||||
}, 1000);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching data:", error);
|
console.error("Error fetching data:", error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -53,6 +47,11 @@ const SuperAdmin = () => {
|
||||||
<SuperAdminTotals isLoading={isLoading} data={data} />
|
<SuperAdminTotals isLoading={isLoading} data={data} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Payment Configuration Section */}
|
||||||
|
<Box mt={4}>
|
||||||
|
<PaymentConfig />
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,12 @@ import React, { useEffect, useState } from "react";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import Loader from "../components/Loader";
|
import Loader from "../components/Loader";
|
||||||
import ThankYou from "../ThankYou/";
|
import ThankYou from "../ThankYou/";
|
||||||
import { Box, Typography } from '@mui/material';
|
import { Box, Typography } from "@mui/material";
|
||||||
import SuperAdmin from "./components/SuperAdmin";
|
import SuperAdmin from "./components/SuperAdmin";
|
||||||
import {
|
import { selectUserRole, setUserRole } from "../../redux/userRoleSlice";
|
||||||
selectUserRole,
|
|
||||||
setUserRole,
|
|
||||||
USER_ROLES,
|
|
||||||
} from "../../redux/userRoleSlice";
|
|
||||||
import Totals from "./Tiles/Totals";
|
import Totals from "./Tiles/Totals";
|
||||||
import { useStyles } from './dashboardStyles';
|
import { useStyles } from "./dashboardStyles";
|
||||||
|
import { USER_ROLES } from "../../constants";
|
||||||
|
|
||||||
function Dashboard() {
|
function Dashboard() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
@ -36,12 +33,10 @@ function Dashboard() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Determine user role based on user data from login reducer
|
// Determine user role based on user data from login reducer
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|
||||||
// Check if user is a super admin
|
// Check if user is a super admin
|
||||||
// This logic can be adjusted based on your specific role criteria
|
// This logic can be adjusted based on your specific role criteria
|
||||||
const isSuperAdmin = user.isBsAdmin ||
|
const isSuperAdmin =
|
||||||
(user.isAdmin && user.permissions?.includes("SUPER_ADMIN_PERMISSION"));
|
user.userType == USER_ROLES.SUPER_ADMIN.toLowerCase();
|
||||||
// Set the appropriate role in Redux
|
|
||||||
if (isSuperAdmin) {
|
if (isSuperAdmin) {
|
||||||
dispatch(setUserRole(USER_ROLES.SUPER_ADMIN));
|
dispatch(setUserRole(USER_ROLES.SUPER_ADMIN));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -69,32 +64,6 @@ function Dashboard() {
|
||||||
</Box>
|
</Box>
|
||||||
<Totals data={data} setData={setData} />
|
<Totals data={data} setData={setData} />
|
||||||
</Box>
|
</Box>
|
||||||
{/* <Grid
|
|
||||||
container
|
|
||||||
spacing={2.6}
|
|
||||||
className={classes.jobApplicationsAndManageSubscription}
|
|
||||||
>
|
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
style={{ width: '-webkit-fill-available' }}
|
|
||||||
lg={`${hasSubscriptionManagementPermission ? 6 : 12}`}
|
|
||||||
>
|
|
||||||
<JobApplications
|
|
||||||
onJobPostClick={() => setPostAJobModal(true)}
|
|
||||||
isJobPostAvailable={data?.remainingJobPosts > 0}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
{hasSubscriptionManagementPermission && (
|
|
||||||
<Grid style={{ width: '-webkit-fill-available' }} item lg={6}>
|
|
||||||
<ManageSubscription data={data} />
|
|
||||||
</Grid>
|
|
||||||
)}
|
|
||||||
{postAJobModal && (
|
|
||||||
<CreateJobPostModal
|
|
||||||
onClose={() => setPostAJobModal(false)}
|
|
||||||
></CreateJobPostModal>
|
|
||||||
)}
|
|
||||||
</Grid> */}
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import React, { useRef, useState } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { messaging } from '../../config/firebase';
|
import { initializeMessaging } from '../../config/firebase';
|
||||||
import { NOTIFICATION } from '../../constants';
|
import { NOTIFICATION } from '../../constants';
|
||||||
import { pushNotification } from '../../utils/notification';
|
import { pushNotification } from '../../utils/notification';
|
||||||
import {
|
import {
|
||||||
|
|
@ -64,9 +64,6 @@ function LoginForm() {
|
||||||
|
|
||||||
// Show success notification
|
// Show success notification
|
||||||
pushNotification('Login successful', NOTIFICATION.SUCCESS);
|
pushNotification('Login successful', NOTIFICATION.SUCCESS);
|
||||||
|
|
||||||
formik.setSubmitting(false);
|
|
||||||
|
|
||||||
// Navigate to dashboard immediately without waiting for profile
|
// Navigate to dashboard immediately without waiting for profile
|
||||||
navigate('/');
|
navigate('/');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -1,106 +1,106 @@
|
||||||
import { axiosInstance } from '../../config/api';
|
import { axiosInstance } from '../../config/api';
|
||||||
import { LOGIN, PROFILE } from './loginActionTypes';
|
import { LOGIN, PROFILE } from './loginActionTypes';
|
||||||
|
|
||||||
// export const login = (data) => ({
|
export const login = (data) => ({
|
||||||
// type: LOGIN,
|
|
||||||
// payload: axiosInstance.post('/auth/companies/login', data),
|
|
||||||
// });
|
|
||||||
|
|
||||||
// export const profile = () => ({
|
|
||||||
// type: PROFILE,
|
|
||||||
// payload: axiosInstance.get('/me'),
|
|
||||||
// });
|
|
||||||
|
|
||||||
export const login = (data) => {
|
|
||||||
// Determine user type based on email
|
|
||||||
const isSuperAdmin = data.email === 'admin@gmail.com';
|
|
||||||
const userRole = isSuperAdmin ? 'SUPER_ADMIN' : 'CLINIC_ADMIN';
|
|
||||||
const userId = isSuperAdmin ? 'super-admin-123' : 'clinic-admin-123';
|
|
||||||
|
|
||||||
// Store token and user type in localStorage to simulate a real login
|
|
||||||
localStorage.setItem('token', `mock-jwt-token-for-${isSuperAdmin ? 'super' : 'clinic'}-admin`);
|
|
||||||
localStorage.setItem('userType', userRole);
|
|
||||||
|
|
||||||
// Mock successful login response
|
|
||||||
const mockLoginResponse = {
|
|
||||||
data: {
|
|
||||||
message: 'Login successful',
|
|
||||||
token: `mock-jwt-token-for-${isSuperAdmin ? 'super' : 'clinic'}-admin`,
|
|
||||||
user: {
|
|
||||||
id: userId,
|
|
||||||
email: data.email,
|
|
||||||
role: userRole
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: LOGIN,
|
type: LOGIN,
|
||||||
// Use a real Promise with a slight delay to simulate network request
|
payload: axiosInstance.post('/auth/login', data),
|
||||||
payload: new Promise(resolve => setTimeout(() => resolve(mockLoginResponse), 300))
|
});
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const profile = () => {
|
export const profile = () => ({
|
||||||
// Get user type from localStorage to determine which profile to return
|
|
||||||
const userType = localStorage.getItem('userType') || 'CLINIC_ADMIN';
|
|
||||||
const isSuperAdmin = userType === 'SUPER_ADMIN';
|
|
||||||
|
|
||||||
// Create appropriate mock profile based on user type
|
|
||||||
let profileData;
|
|
||||||
|
|
||||||
if (isSuperAdmin) {
|
|
||||||
// Super Admin profile
|
|
||||||
profileData = {
|
|
||||||
id: 'super-admin-123',
|
|
||||||
name: 'Super Administrator',
|
|
||||||
email: 'admin@gmail.com',
|
|
||||||
role: 'SUPER_ADMIN',
|
|
||||||
isAdmin: true,
|
|
||||||
isBsAdmin: true, // This flag identifies super admin
|
|
||||||
permissions: [
|
|
||||||
'CREATE_REC_USERS',
|
|
||||||
'READ_REC_USERS',
|
|
||||||
'DELETE_REC_USERS',
|
|
||||||
'SUPER_ADMIN_PERMISSION'
|
|
||||||
]
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// Clinic Admin profile
|
|
||||||
profileData = {
|
|
||||||
id: 'clinic-admin-123',
|
|
||||||
name: 'Clinic Administrator',
|
|
||||||
email: 'admin@clinic.com',
|
|
||||||
role: 'CLINIC_ADMIN',
|
|
||||||
isAdmin: true,
|
|
||||||
isBsAdmin: false,
|
|
||||||
permissions: [
|
|
||||||
'CREATE_REC_USERS',
|
|
||||||
'READ_REC_USERS',
|
|
||||||
'DELETE_REC_USERS'
|
|
||||||
],
|
|
||||||
clinic: {
|
|
||||||
id: 'clinic-123',
|
|
||||||
name: 'Health Plus Clinic',
|
|
||||||
address: '123 Medical Center Blvd',
|
|
||||||
city: 'Healthcare City',
|
|
||||||
state: 'HC',
|
|
||||||
zipCode: '12345',
|
|
||||||
phone: '555-123-4567'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the response with the nested data structure the reducer expects
|
|
||||||
const mockProfileResponse = {
|
|
||||||
data: {
|
|
||||||
data: profileData
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: PROFILE,
|
type: PROFILE,
|
||||||
// Use a real Promise with a slight delay to simulate network request
|
payload: axiosInstance.get('/users/me'),
|
||||||
payload: new Promise(resolve => setTimeout(() => resolve(mockProfileResponse), 300))
|
});
|
||||||
};
|
|
||||||
};
|
// export const login = (data) => {
|
||||||
|
// // Determine user type based on email
|
||||||
|
// const isSuperAdmin = data.email === 'admin@gmail.com';
|
||||||
|
// const userRole = isSuperAdmin ? 'SUPER_ADMIN' : 'CLINIC_ADMIN';
|
||||||
|
// const userId = isSuperAdmin ? 'super-admin-123' : 'clinic-admin-123';
|
||||||
|
|
||||||
|
// // Store token and user type in localStorage to simulate a real login
|
||||||
|
// localStorage.setItem('token', `mock-jwt-token-for-${isSuperAdmin ? 'super' : 'clinic'}-admin`);
|
||||||
|
// localStorage.setItem('userType', userRole);
|
||||||
|
|
||||||
|
// // Mock successful login response
|
||||||
|
// const mockLoginResponse = {
|
||||||
|
// data: {
|
||||||
|
// message: 'Login successful',
|
||||||
|
// token: `mock-jwt-token-for-${isSuperAdmin ? 'super' : 'clinic'}-admin`,
|
||||||
|
// user: {
|
||||||
|
// id: userId,
|
||||||
|
// email: data.email,
|
||||||
|
// role: userRole
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// type: LOGIN,
|
||||||
|
// // Use a real Promise with a slight delay to simulate network request
|
||||||
|
// payload: new Promise(resolve => setTimeout(() => resolve(mockLoginResponse), 300))
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export const profile = () => {
|
||||||
|
// // Get user type from localStorage to determine which profile to return
|
||||||
|
// const userType = localStorage.getItem('userType') || 'CLINIC_ADMIN';
|
||||||
|
// const isSuperAdmin = userType === 'SUPER_ADMIN';
|
||||||
|
|
||||||
|
// // Create appropriate mock profile based on user type
|
||||||
|
// let profileData;
|
||||||
|
|
||||||
|
// if (isSuperAdmin) {
|
||||||
|
// // Super Admin profile
|
||||||
|
// profileData = {
|
||||||
|
// id: 'super-admin-123',
|
||||||
|
// name: 'Super Administrator',
|
||||||
|
// email: 'admin@gmail.com',
|
||||||
|
// role: 'SUPER_ADMIN',
|
||||||
|
// isAdmin: true,
|
||||||
|
// isSuperAdmin: true, // This flag identifies super admin
|
||||||
|
// permissions: [
|
||||||
|
// 'CREATE_REC_USERS',
|
||||||
|
// 'READ_REC_USERS',
|
||||||
|
// 'DELETE_REC_USERS',
|
||||||
|
// 'SUPER_ADMIN_PERMISSION'
|
||||||
|
// ]
|
||||||
|
// };
|
||||||
|
// } else {
|
||||||
|
// // Clinic Admin profile
|
||||||
|
// profileData = {
|
||||||
|
// id: 'clinic-admin-123',
|
||||||
|
// name: 'Clinic Administrator',
|
||||||
|
// email: 'admin@clinic.com',
|
||||||
|
// role: 'CLINIC_ADMIN',
|
||||||
|
// isAdmin: true,
|
||||||
|
// isSuperAdmin: false,
|
||||||
|
// permissions: [
|
||||||
|
// 'CREATE_REC_USERS',
|
||||||
|
// 'READ_REC_USERS',
|
||||||
|
// 'DELETE_REC_USERS'
|
||||||
|
// ],
|
||||||
|
// clinic: {
|
||||||
|
// id: 'clinic-123',
|
||||||
|
// name: 'Health Plus Clinic',
|
||||||
|
// address: '123 Medical Center Blvd',
|
||||||
|
// city: 'Healthcare City',
|
||||||
|
// state: 'HC',
|
||||||
|
// zipCode: '12345',
|
||||||
|
// phone: '555-123-4567'
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Create the response with the nested data structure the reducer expects
|
||||||
|
// const mockProfileResponse = {
|
||||||
|
// data: {
|
||||||
|
// data: profileData
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// type: PROFILE,
|
||||||
|
// // Use a real Promise with a slight delay to simulate network request
|
||||||
|
// payload: new Promise(resolve => setTimeout(() => resolve(mockProfileResponse), 300))
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,13 @@ import {
|
||||||
} from './loginActionTypes';
|
} from './loginActionTypes';
|
||||||
|
|
||||||
const initialState = {};
|
const initialState = {};
|
||||||
|
|
||||||
const loginPending = (state) => ({
|
const loginPending = (state) => ({
|
||||||
...state,
|
...state,
|
||||||
});
|
});
|
||||||
const loginFulfilled = (state) => ({
|
const loginFulfilled = (state, payload) => ({
|
||||||
...state,
|
...state,
|
||||||
|
token: payload?.payload?.data?.data,
|
||||||
});
|
});
|
||||||
const loginRejected = (state) => ({
|
const loginRejected = (state) => ({
|
||||||
...state,
|
...state,
|
||||||
|
|
@ -39,7 +41,7 @@ const profileFulfilled = (state, payload) => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
// Check if user is admin, add additional permissions
|
// Check if user is admin, add additional permissions
|
||||||
if (user.isAdmin && !user?.isBsAdmin) {
|
if (user.isAdmin && !user?.isSuperAdmin) {
|
||||||
userPermissions.push(
|
userPermissions.push(
|
||||||
'CREATE_REC_USERS',
|
'CREATE_REC_USERS',
|
||||||
'READ_REC_USERS',
|
'READ_REC_USERS',
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import AddIcon from '@mui/icons-material/Add';
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew';
|
import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew";
|
||||||
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
|
import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import PersonAddIcon from '@mui/icons-material/PersonAdd';
|
import PersonAddIcon from "@mui/icons-material/PersonAdd";
|
||||||
import SearchIcon from '@mui/icons-material/Search';
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Box,
|
Box,
|
||||||
|
|
@ -26,23 +26,23 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
TextField,
|
TextField,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from "@mui/material";
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from "react";
|
||||||
import CustomBreadcrumbs from '../../components/CustomBreadcrumbs';
|
import CustomBreadcrumbs from "../../components/CustomBreadcrumbs";
|
||||||
import PageHeader from '../../components/PageHeader';
|
import PageHeader from "../../components/PageHeader";
|
||||||
const MasterDataManagement = () => {
|
const MasterDataManagement = () => {
|
||||||
// State for form fields
|
// State for form fields
|
||||||
const [appointmentType, setAppointmentType] = useState('');
|
const [appointmentType, setAppointmentType] = useState("");
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
|
|
||||||
// State for staff list
|
// State for staff list
|
||||||
const [staffList, setStaffList] = useState([]);
|
const [staffList, setStaffList] = useState([]);
|
||||||
|
|
||||||
// State for dialog
|
// State for staff dialog
|
||||||
const [openDialog, setOpenDialog] = useState(false);
|
const [openDialog, setOpenDialog] = useState(false);
|
||||||
|
|
||||||
// State for search
|
// State for search
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
|
||||||
// State for pagination
|
// State for pagination
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
|
|
@ -51,11 +51,11 @@ const MasterDataManagement = () => {
|
||||||
// State for notification
|
// State for notification
|
||||||
const [notification, setNotification] = useState({
|
const [notification, setNotification] = useState({
|
||||||
open: false,
|
open: false,
|
||||||
message: '',
|
message: "",
|
||||||
severity: 'success',
|
severity: "success",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle dialog open/close
|
// Handle staff dialog open/close
|
||||||
const handleOpenDialog = () => {
|
const handleOpenDialog = () => {
|
||||||
setOpenDialog(true);
|
setOpenDialog(true);
|
||||||
};
|
};
|
||||||
|
|
@ -63,7 +63,7 @@ const MasterDataManagement = () => {
|
||||||
const handleCloseDialog = () => {
|
const handleCloseDialog = () => {
|
||||||
setOpenDialog(false);
|
setOpenDialog(false);
|
||||||
// Clear form
|
// Clear form
|
||||||
setAppointmentType('');
|
setAppointmentType("");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle form submission
|
// Handle form submission
|
||||||
|
|
@ -84,8 +84,8 @@ const MasterDataManagement = () => {
|
||||||
// Show success notification
|
// Show success notification
|
||||||
setNotification({
|
setNotification({
|
||||||
open: true,
|
open: true,
|
||||||
message: 'Staff member added successfully!',
|
message: "Staff member added successfully!",
|
||||||
severity: 'success',
|
severity: "success",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -100,36 +100,32 @@ const MasterDataManagement = () => {
|
||||||
// ...................breadcrumbs array........................
|
// ...................breadcrumbs array........................
|
||||||
const breadcrumbs = [
|
const breadcrumbs = [
|
||||||
{
|
{
|
||||||
label: 'Dashboard',
|
label: "Dashboard",
|
||||||
path: '/',
|
path: "/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Master Data Management',
|
label: "Master Data Management",
|
||||||
path: '/masterData',
|
path: "/masterData",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||||
|
<PageHeader pageTitle="Master Data Management" hideAddButton />
|
||||||
<PageHeader
|
|
||||||
pageTitle="Master Data Management"
|
|
||||||
hideAddButton
|
|
||||||
/>
|
|
||||||
|
|
||||||
<CustomBreadcrumbs breadcrumbs={breadcrumbs} />
|
<CustomBreadcrumbs breadcrumbs={breadcrumbs} />
|
||||||
|
|
||||||
<Paper elevation={3} sx={{ p: 0, mb: 4, overflow: 'hidden' }}>
|
<Paper elevation={3} sx={{ p: 0, mb: 4, overflow: "hidden" }}>
|
||||||
{/* Staff List Header with Add Button */}
|
{/* Staff List Header with Add Button */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
p: 3,
|
p: 3,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="h6" component="h2" sx={{ fontWeight: 'bold' }}>
|
<Typography variant="h6" component="h2" sx={{ fontWeight: "bold" }}>
|
||||||
Master Appointment Type List
|
Master Appointment Type List
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
|
|
@ -140,10 +136,10 @@ const MasterDataManagement = () => {
|
||||||
onClick={handleOpenDialog}
|
onClick={handleOpenDialog}
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: 50,
|
borderRadius: 50,
|
||||||
textTransform: 'none',
|
textTransform: "none",
|
||||||
backgroundColor: '#ff3366',
|
backgroundColor: "#ff3366",
|
||||||
'&:hover': {
|
"&:hover": {
|
||||||
backgroundColor: '#e61653',
|
backgroundColor: "#e61653",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -167,8 +163,8 @@ const MasterDataManagement = () => {
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: '#fff',
|
backgroundColor: "#fff",
|
||||||
'& .MuiOutlinedInput-root': {
|
"& .MuiOutlinedInput-root": {
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
@ -179,16 +175,17 @@ const MasterDataManagement = () => {
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow sx={{ backgroundColor: '#f5f5f5' }}>
|
<TableRow sx={{ backgroundColor: "#f5f5f5" }}>
|
||||||
<TableCell sx={{ fontWeight: 'bold' }}>Sr. No.</TableCell>
|
<TableCell sx={{ fontWeight: "bold" }}>Sr. No.</TableCell>
|
||||||
<TableCell sx={{ fontWeight: 'bold' }}>Appointment Type</TableCell>
|
<TableCell sx={{ fontWeight: "bold" }}>
|
||||||
|
Appointment Type
|
||||||
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{staffList.length > 0 ? (
|
{staffList.length > 0 ? (
|
||||||
staffList
|
staffList
|
||||||
.filter(
|
.filter((staff) =>
|
||||||
(staff) =>
|
|
||||||
`${staff.appointmentType}`
|
`${staff.appointmentType}`
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(searchQuery.toLowerCase())
|
.includes(searchQuery.toLowerCase())
|
||||||
|
|
@ -207,7 +204,7 @@ const MasterDataManagement = () => {
|
||||||
<TableCell
|
<TableCell
|
||||||
colSpan={2}
|
colSpan={2}
|
||||||
align="center"
|
align="center"
|
||||||
sx={{ py: 5, color: '#666' }}
|
sx={{ py: 5, color: "#666" }}
|
||||||
>
|
>
|
||||||
No Appointment Type added yet
|
No Appointment Type added yet
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
@ -221,17 +218,17 @@ const MasterDataManagement = () => {
|
||||||
{staffList.length > 0 && (
|
{staffList.length > 0 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
p: 2,
|
p: 2,
|
||||||
borderTop: '1px solid #eee',
|
borderTop: "1px solid #eee",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setPage((prev) => Math.max(prev - 1, 1))}
|
onClick={() => setPage((prev) => Math.max(prev - 1, 1))}
|
||||||
disabled={page === 1}
|
disabled={page === 1}
|
||||||
startIcon={<ArrowBackIosNewIcon fontSize="small" />}
|
startIcon={<ArrowBackIosNewIcon fontSize="small" />}
|
||||||
sx={{ mx: 1, color: '#666' }}
|
sx={{ mx: 1, color: "#666" }}
|
||||||
>
|
>
|
||||||
Previous
|
Previous
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -241,11 +238,11 @@ const MasterDataManagement = () => {
|
||||||
disableElevation
|
disableElevation
|
||||||
sx={{
|
sx={{
|
||||||
mx: 1,
|
mx: 1,
|
||||||
minWidth: '36px',
|
minWidth: "36px",
|
||||||
backgroundColor: '#f0f0f0',
|
backgroundColor: "#f0f0f0",
|
||||||
color: '#333',
|
color: "#333",
|
||||||
'&:hover': {
|
"&:hover": {
|
||||||
backgroundColor: '#e0e0e0',
|
backgroundColor: "#e0e0e0",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -256,7 +253,7 @@ const MasterDataManagement = () => {
|
||||||
onClick={() => setPage((prev) => prev + 1)}
|
onClick={() => setPage((prev) => prev + 1)}
|
||||||
disabled={page * rowsPerPage >= staffList.length}
|
disabled={page * rowsPerPage >= staffList.length}
|
||||||
endIcon={<ArrowForwardIosIcon fontSize="small" />}
|
endIcon={<ArrowForwardIosIcon fontSize="small" />}
|
||||||
sx={{ mx: 1, color: '#666' }}
|
sx={{ mx: 1, color: "#666" }}
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -264,6 +261,8 @@ const MasterDataManagement = () => {
|
||||||
)}
|
)}
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* Add Staff Dialog */}
|
{/* Add Staff Dialog */}
|
||||||
<Dialog
|
<Dialog
|
||||||
open={openDialog}
|
open={openDialog}
|
||||||
|
|
@ -273,18 +272,18 @@ const MasterDataManagement = () => {
|
||||||
>
|
>
|
||||||
<DialogTitle
|
<DialogTitle
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
pb: 1,
|
pb: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||||
<PersonAddIcon sx={{ mr: 1, color: '#0a2d6b' }} />
|
<PersonAddIcon sx={{ mr: 1, color: "#0a2d6b" }} />
|
||||||
<Typography
|
<Typography
|
||||||
variant="h6"
|
variant="h6"
|
||||||
component="span"
|
component="span"
|
||||||
sx={{ fontWeight: 'bold', color: '#0a2d6b' }}
|
sx={{ fontWeight: "bold", color: "#0a2d6b" }}
|
||||||
>
|
>
|
||||||
Add New Appointment Type
|
Add New Appointment Type
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
@ -321,9 +320,9 @@ const MasterDataManagement = () => {
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
sx={{
|
sx={{
|
||||||
py: 1.5,
|
py: 1.5,
|
||||||
backgroundColor: '#ff3366',
|
backgroundColor: "#ff3366",
|
||||||
'&:hover': {
|
"&:hover": {
|
||||||
backgroundColor: '#e61653',
|
backgroundColor: "#e61653",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -337,12 +336,12 @@ const MasterDataManagement = () => {
|
||||||
open={notification.open}
|
open={notification.open}
|
||||||
autoHideDuration={4000}
|
autoHideDuration={4000}
|
||||||
onClose={handleCloseNotification}
|
onClose={handleCloseNotification}
|
||||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
|
||||||
>
|
>
|
||||||
<Alert
|
<Alert
|
||||||
onClose={handleCloseNotification}
|
onClose={handleCloseNotification}
|
||||||
severity={notification.severity}
|
severity={notification.severity}
|
||||||
sx={{ width: '100%' }}
|
sx={{ width: "100%" }}
|
||||||
>
|
>
|
||||||
{notification.message}
|
{notification.message}
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
|
||||||
|
|
@ -228,58 +228,6 @@ const PaymentPage = () => {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{paymentMethod === 'card' && (
|
|
||||||
<Box mt={2}>
|
|
||||||
<TextField
|
|
||||||
label="Card Number"
|
|
||||||
fullWidth
|
|
||||||
margin="dense"
|
|
||||||
value={cardNumber}
|
|
||||||
onChange={(e) =>
|
|
||||||
setCardNumber(formatCardNumber(e.target.value))
|
|
||||||
}
|
|
||||||
placeholder="1234 5678 9012 3456"
|
|
||||||
inputProps={{ maxLength: 19 }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<TextField
|
|
||||||
label="Expiry Date"
|
|
||||||
fullWidth
|
|
||||||
margin="dense"
|
|
||||||
value={cardExpiry}
|
|
||||||
onChange={(e) =>
|
|
||||||
setCardExpiry(formatExpiry(e.target.value))
|
|
||||||
}
|
|
||||||
placeholder="MM/YY"
|
|
||||||
inputProps={{ maxLength: 5 }}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={6}>
|
|
||||||
<TextField
|
|
||||||
label="CVC"
|
|
||||||
fullWidth
|
|
||||||
margin="dense"
|
|
||||||
value={cardCVC}
|
|
||||||
onChange={(e) => setCardCVC(e.target.value)}
|
|
||||||
placeholder="123"
|
|
||||||
inputProps={{ maxLength: 3 }}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
label="Name on Card"
|
|
||||||
fullWidth
|
|
||||||
margin="dense"
|
|
||||||
value={name}
|
|
||||||
onChange={(e) => setName(e.target.value)}
|
|
||||||
placeholder="John Smith"
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{paymentMethod === 'net_banking' && (
|
{paymentMethod === 'net_banking' && (
|
||||||
<Box mt={2}>
|
<Box mt={2}>
|
||||||
<TextField
|
<TextField
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { getToken } from 'firebase/messaging';
|
import { getToken } from 'firebase/messaging';
|
||||||
import { RECRUITMENT_URL, FB_VAPID_KEY } from '../../common/envVariables';
|
import { RECRUITMENT_URL, FB_VAPID_KEY } from '../../common/envVariables';
|
||||||
import { messaging } from '../../config/firebase';
|
import { initializeMessaging, getMessagingInstance } from '../../config/firebase';
|
||||||
import { saveFcmToken } from '../../services/notification.service';
|
import { saveFcmToken } from '../../services/notification.service';
|
||||||
import { NOTIFICATION_TYPE } from './notificationConstant';
|
import { NOTIFICATION_TYPE } from './notificationConstant';
|
||||||
|
|
||||||
|
|
@ -10,12 +10,18 @@ export const requestNotificationPermission = async () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!messaging) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currentToken = await getToken(messaging, {
|
// Initialize messaging if not already initialized
|
||||||
|
const messagingInstance = await initializeMessaging();
|
||||||
|
if (!messagingInstance) {
|
||||||
|
console.log('Firebase messaging is not supported in this browser');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentToken = await getToken(messagingInstance, {
|
||||||
vapidKey: FB_VAPID_KEY,
|
vapidKey: FB_VAPID_KEY,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (currentToken) {
|
if (currentToken) {
|
||||||
await saveFcmToken({
|
await saveFcmToken({
|
||||||
token: currentToken,
|
token: currentToken,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,330 @@
|
||||||
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
Container,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
FormControlLabel,
|
||||||
|
IconButton,
|
||||||
|
MenuItem,
|
||||||
|
Paper,
|
||||||
|
Snackbar,
|
||||||
|
Alert,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
TextField,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import CustomBreadcrumbs from "../../components/CustomBreadcrumbs";
|
||||||
|
import PageHeader from "../../components/PageHeader";
|
||||||
|
|
||||||
|
const PaymentManagement = () => {
|
||||||
|
// State for payment dialog
|
||||||
|
const [paymentDialogOpen, setPaymentDialogOpen] = useState(false);
|
||||||
|
const [paymentData, setPaymentData] = useState({
|
||||||
|
clinicName: "",
|
||||||
|
setupFeeWaived: false,
|
||||||
|
specialOffer: false,
|
||||||
|
configurationMonth: 3
|
||||||
|
});
|
||||||
|
|
||||||
|
// State for payments list
|
||||||
|
const [paymentsList, setPaymentsList] = useState([]);
|
||||||
|
const [editPaymentIndex, setEditPaymentIndex] = useState(null);
|
||||||
|
|
||||||
|
// State for notification
|
||||||
|
const [notification, setNotification] = useState({
|
||||||
|
open: false,
|
||||||
|
message: "",
|
||||||
|
severity: "success",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle payment dialog submission
|
||||||
|
const handleAddPayment = () => {
|
||||||
|
// Validate input
|
||||||
|
if (!paymentData.clinicName.trim()) {
|
||||||
|
setNotification({
|
||||||
|
open: true,
|
||||||
|
message: "Please enter a clinic name",
|
||||||
|
severity: "error",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editPaymentIndex !== null) {
|
||||||
|
// Update existing payment
|
||||||
|
const updatedPayments = [...paymentsList];
|
||||||
|
updatedPayments[editPaymentIndex] = {...paymentData};
|
||||||
|
setPaymentsList(updatedPayments);
|
||||||
|
|
||||||
|
setNotification({
|
||||||
|
open: true,
|
||||||
|
message: "Payment configuration updated successfully",
|
||||||
|
severity: "success",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Add new payment
|
||||||
|
setPaymentsList([...paymentsList, {...paymentData}]);
|
||||||
|
|
||||||
|
setNotification({
|
||||||
|
open: true,
|
||||||
|
message: "Payment configuration added successfully",
|
||||||
|
severity: "success",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset form and close dialog
|
||||||
|
setPaymentData({
|
||||||
|
clinicName: "",
|
||||||
|
setupFeeWaived: false,
|
||||||
|
specialOffer: false,
|
||||||
|
configurationMonth: 3
|
||||||
|
});
|
||||||
|
setEditPaymentIndex(null);
|
||||||
|
setPaymentDialogOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle edit payment
|
||||||
|
const handleEditPayment = (index) => {
|
||||||
|
setEditPaymentIndex(index);
|
||||||
|
setPaymentData({...paymentsList[index]});
|
||||||
|
setPaymentDialogOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle delete payment
|
||||||
|
const handleDeletePayment = (index) => {
|
||||||
|
const updatedPayments = [...paymentsList];
|
||||||
|
updatedPayments.splice(index, 1);
|
||||||
|
setPaymentsList(updatedPayments);
|
||||||
|
|
||||||
|
setNotification({
|
||||||
|
open: true,
|
||||||
|
message: "Payment configuration deleted successfully",
|
||||||
|
severity: "success",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle notification close
|
||||||
|
const handleCloseNotification = () => {
|
||||||
|
setNotification({
|
||||||
|
...notification,
|
||||||
|
open: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Breadcrumbs
|
||||||
|
const breadcrumbs = [
|
||||||
|
{ label: "Dashboard", link: "/" },
|
||||||
|
{ label: "Payment Management", link: "/payment-management" },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||||
|
<PageHeader pageTitle="Payment Management" hideAddButton />
|
||||||
|
|
||||||
|
<CustomBreadcrumbs breadcrumbs={breadcrumbs} />
|
||||||
|
|
||||||
|
<Paper elevation={3} sx={{ p: 0, mb: 4, overflow: "hidden" }}>
|
||||||
|
{/* Payment Management Header with Add Button */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
p: 3,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h6" component="h2" sx={{ fontWeight: "bold" }}>
|
||||||
|
Payment Configurations
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="error"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
onClick={() => setPaymentDialogOpen(true)}
|
||||||
|
sx={{
|
||||||
|
borderRadius: 50,
|
||||||
|
textTransform: "none",
|
||||||
|
backgroundColor: "#ff3366",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "#e61653",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Payment
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Payment List Table */}
|
||||||
|
<TableContainer>
|
||||||
|
<Table sx={{ minWidth: 650 }} aria-label="payment table">
|
||||||
|
<TableHead sx={{ backgroundColor: "#f5f5f5" }}>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell sx={{ fontWeight: "bold" }}>Clinic Name</TableCell>
|
||||||
|
<TableCell sx={{ fontWeight: "bold" }}>Setup Fee Waived</TableCell>
|
||||||
|
<TableCell sx={{ fontWeight: "bold" }}>Special Offer</TableCell>
|
||||||
|
<TableCell sx={{ fontWeight: "bold" }}>Configuration Month</TableCell>
|
||||||
|
<TableCell sx={{ fontWeight: "bold" }}>Actions</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{paymentsList.length > 0 ? (
|
||||||
|
paymentsList.map((payment, index) => (
|
||||||
|
<TableRow key={index}>
|
||||||
|
<TableCell>{payment.clinicName}</TableCell>
|
||||||
|
<TableCell>{payment.setupFeeWaived ? "Yes" : "No"}</TableCell>
|
||||||
|
<TableCell>{payment.specialOffer ? "Yes" : "No"}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{payment.specialOffer ? payment.configurationMonth : "-"}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => handleEditPayment(index)}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
color="error"
|
||||||
|
onClick={() => handleDeletePayment(index)}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={5} align="center">
|
||||||
|
No payment configurations found
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
{/* Payment Dialog */}
|
||||||
|
<Dialog
|
||||||
|
open={paymentDialogOpen}
|
||||||
|
onClose={() => setPaymentDialogOpen(false)}
|
||||||
|
maxWidth="sm"
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
{editPaymentIndex !== null ? "Edit Payment" : "Add New Payment"}
|
||||||
|
<IconButton
|
||||||
|
aria-label="close"
|
||||||
|
onClick={() => setPaymentDialogOpen(false)}
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
right: 8,
|
||||||
|
top: 8,
|
||||||
|
color: (theme) => theme.palette.grey[500],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<Box sx={{ mt: 2 }}>
|
||||||
|
<TextField
|
||||||
|
autoFocus
|
||||||
|
margin="dense"
|
||||||
|
id="clinicName"
|
||||||
|
label="Clinic Name"
|
||||||
|
type="text"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={paymentData.clinicName}
|
||||||
|
onChange={(e) => setPaymentData({...paymentData, clinicName: e.target.value})}
|
||||||
|
sx={{ mb: 2 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={paymentData.setupFeeWaived}
|
||||||
|
onChange={(e) => setPaymentData({...paymentData, setupFeeWaived: e.target.checked})}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Setup fee waived"
|
||||||
|
sx={{ mb: 1 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={paymentData.specialOffer}
|
||||||
|
onChange={(e) => setPaymentData({...paymentData, specialOffer: e.target.checked})}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Special Offer: First 3 months free"
|
||||||
|
sx={{ mb: 1 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{paymentData.specialOffer && (
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
margin="dense"
|
||||||
|
id="configurationMonth"
|
||||||
|
label="Configuration Month"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={paymentData.configurationMonth}
|
||||||
|
onChange={(e) => setPaymentData({...paymentData, configurationMonth: e.target.value})}
|
||||||
|
sx={{ mt: 1 }}
|
||||||
|
>
|
||||||
|
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map((month) => (
|
||||||
|
<MenuItem key={month} value={month}>
|
||||||
|
{month}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => setPaymentDialogOpen(false)} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleAddPayment} variant="contained" color="primary">
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
{/* Notification Snackbar */}
|
||||||
|
<Snackbar
|
||||||
|
open={notification.open}
|
||||||
|
autoHideDuration={6000}
|
||||||
|
onClose={handleCloseNotification}
|
||||||
|
anchorOrigin={{ vertical: "top", horizontal: "right" }}
|
||||||
|
>
|
||||||
|
<Alert
|
||||||
|
onClose={handleCloseNotification}
|
||||||
|
severity={notification.severity}
|
||||||
|
sx={{ width: "100%" }}
|
||||||
|
>
|
||||||
|
{notification.message}
|
||||||
|
</Alert>
|
||||||
|
</Snackbar>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PaymentManagement;
|
||||||
|
|
@ -18,6 +18,7 @@ import {
|
||||||
Select,
|
Select,
|
||||||
TextField,
|
TextField,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useTheme } from "@mui/material/styles";
|
import { useTheme } from "@mui/material/styles";
|
||||||
|
|
@ -54,7 +55,11 @@ import {
|
||||||
ONLY_ALPHA_NUMERIC_ACCEPT_REGEX,
|
ONLY_ALPHA_NUMERIC_ACCEPT_REGEX,
|
||||||
WEBSITE_REGEX,
|
WEBSITE_REGEX,
|
||||||
} from "../../constants";
|
} from "../../constants";
|
||||||
import { fileUpload } from "../../services/file.upload.services";
|
import {
|
||||||
|
fileUpload,
|
||||||
|
getPresignedUrl,
|
||||||
|
uploadToS3,
|
||||||
|
} from "../../services/file.upload.services";
|
||||||
import { pushNotification } from "../../utils/notification";
|
import { pushNotification } from "../../utils/notification";
|
||||||
import {
|
import {
|
||||||
passwordLengthRegex,
|
passwordLengthRegex,
|
||||||
|
|
@ -64,30 +69,44 @@ import {
|
||||||
} from "../../utils/regex";
|
} from "../../utils/regex";
|
||||||
import { capitalizeAllLetters, capitalizeFirstLetter } from "../../utils/share";
|
import { capitalizeAllLetters, capitalizeFirstLetter } from "../../utils/share";
|
||||||
import PasswordValidation from "../Login/component/PasswordValidation";
|
import PasswordValidation from "../Login/component/PasswordValidation";
|
||||||
import { updateFormDetails } from "./signupAction";
|
import { resetFormData, updateFormDetails } from "./signupAction";
|
||||||
import { useStyles } from "./styles/signupStyles";
|
import { useStyles } from "./styles/signupStyles";
|
||||||
|
import { getLatestClinicId } from "../../services/clinics.service";
|
||||||
|
import { signup } from "../../services/auth.services";
|
||||||
|
import { decodeJWT } from "../../services/jwt.services";
|
||||||
|
|
||||||
function YourDetailsForm() {
|
function YourDetailsForm() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const [latestClinicID, setLatestClinicID] = useState(0);
|
||||||
const [otpField, setOtpField] = useState(false);
|
const [otpField, setOtpField] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||||
const [billingUsers, setBillingUsers] = useState([]);
|
|
||||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||||
const [localityOption, setLocalityOption] = useState([]);
|
const [localityOption, setLocalityOption] = useState([]);
|
||||||
const [countryOption, setCountryOption] = useState(["Australia", "India"]);
|
const [countryOption, setCountryOption] = useState(["Australia", "India"]);
|
||||||
const [pincodeData, setPincodeData] = useState();
|
const [pincodeData, setPincodeData] = useState();
|
||||||
const selectedLocalityRef = useRef();
|
const selectedLocalityRef = useRef();
|
||||||
|
const [testConnection, setTestConnDone] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsLoading(true);
|
||||||
|
getLatestClinicId().then((res) => {
|
||||||
|
setLatestClinicID(res?.data?.data);
|
||||||
|
});
|
||||||
|
setIsLoading(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Form data from Redux
|
// Form data from Redux
|
||||||
const yourDetailsFormData = useSelector((state) => state.signup);
|
const yourDetailsFormData = useSelector((state) => state.signup);
|
||||||
|
|
||||||
// Logo state variables
|
// Logo state variables
|
||||||
const logoRef = useRef(null);
|
const logoRef = useRef(null);
|
||||||
|
const testConnectionRef = useRef(null);
|
||||||
|
const otpButtonRef = useRef(null);
|
||||||
const fileInputRef = useRef(null);
|
const fileInputRef = useRef(null);
|
||||||
const [aspect, setAspect] = useState(1);
|
const [aspect, setAspect] = useState(1);
|
||||||
const [logoname, setLogoname] = useState();
|
const [logoname, setLogoname] = useState();
|
||||||
|
|
@ -109,7 +128,10 @@ function YourDetailsForm() {
|
||||||
{ id: "91", name: "+91" },
|
{ id: "91", name: "+91" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const integrationOptions = ["BP Software", "Medical Director"];
|
const integrationOptions = [
|
||||||
|
{ id: "bp", name: "BP Software" },
|
||||||
|
{ id: "medical_director", name: "Medical Director" },
|
||||||
|
];
|
||||||
|
|
||||||
// Default form data
|
// Default form data
|
||||||
const defaultFormData = useRef({
|
const defaultFormData = useRef({
|
||||||
|
|
@ -120,26 +142,25 @@ function YourDetailsForm() {
|
||||||
mobileNumber: "",
|
mobileNumber: "",
|
||||||
mobilePrefix: "",
|
mobilePrefix: "",
|
||||||
confirmPassword: "",
|
confirmPassword: "",
|
||||||
currentEmail: "",
|
|
||||||
otp: "",
|
otp: "",
|
||||||
|
|
||||||
// Clinic details
|
// Clinic details
|
||||||
companyName: "",
|
companyName: "",
|
||||||
designation: "",
|
designation: "",
|
||||||
|
businessPhonePrefix: "",
|
||||||
businessPhone: "",
|
businessPhone: "",
|
||||||
emergencyBusinessPhone: "",
|
emergencyBusinessPhone: "",
|
||||||
emergencyBusinessPhonePrefix: "",
|
emergencyBusinessPhonePrefix: "",
|
||||||
businessPhonePrefix: "",
|
|
||||||
businessFax: "",
|
businessFax: "",
|
||||||
companyLogo: "",
|
clinicLogo: "",
|
||||||
companyIndustry: "",
|
businessEmail: "",
|
||||||
pincode: "",
|
pincode: "",
|
||||||
state: "",
|
state: "",
|
||||||
locality: "",
|
locality: "",
|
||||||
country: "",
|
country: "",
|
||||||
fullAddress: "",
|
fullAddress: "",
|
||||||
companyPANImage: "",
|
companyABNImageNumber: "",
|
||||||
companyPANImage: "",
|
companyABNImage: "",
|
||||||
termsAccepted: "",
|
termsAccepted: "",
|
||||||
practiceManagementSystem: "",
|
practiceManagementSystem: "",
|
||||||
practiceId: "",
|
practiceId: "",
|
||||||
|
|
@ -167,18 +188,18 @@ function YourDetailsForm() {
|
||||||
emergencyBusinessPhone: useRef(null),
|
emergencyBusinessPhone: useRef(null),
|
||||||
emergencyBusinessPhonePrefix: useRef(null),
|
emergencyBusinessPhonePrefix: useRef(null),
|
||||||
businessFax: useRef(null),
|
businessFax: useRef(null),
|
||||||
|
businessEmail: useRef(null),
|
||||||
practiceManagementSystem: useRef(null),
|
practiceManagementSystem: useRef(null),
|
||||||
practiceId: useRef(null),
|
practiceId: useRef(null),
|
||||||
practiceName: useRef(null),
|
practiceName: useRef(null),
|
||||||
designation: useRef(null),
|
designation: useRef(null),
|
||||||
companyIndustry: useRef(null),
|
|
||||||
pincode: useRef(null),
|
pincode: useRef(null),
|
||||||
state: useRef(null),
|
state: useRef(null),
|
||||||
locality: useRef(null),
|
locality: useRef(null),
|
||||||
country: useRef(null),
|
country: useRef(null),
|
||||||
fullAddress: useRef(null),
|
fullAddress: useRef(null),
|
||||||
companyPANImage: useRef(null),
|
companyABNImageNumber: useRef(null),
|
||||||
companyTANNumber: useRef(null),
|
companyABNImage: useRef(null),
|
||||||
|
|
||||||
// contract management
|
// contract management
|
||||||
contract: useRef(null),
|
contract: useRef(null),
|
||||||
|
|
@ -186,14 +207,10 @@ function YourDetailsForm() {
|
||||||
|
|
||||||
if (yourDetailsFormData) {
|
if (yourDetailsFormData) {
|
||||||
defaultFormData.current = { ...yourDetailsFormData };
|
defaultFormData.current = { ...yourDetailsFormData };
|
||||||
|
// setLocalityOption([yourDetailsFormData?.locality])
|
||||||
|
selectedLocalityRef.current = yourDetailsFormData?.locality;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (yourDetailsFormData) {
|
|
||||||
setBillingUsers(yourDetailsFormData?.billingUsers);
|
|
||||||
}
|
|
||||||
}, [yourDetailsFormData]);
|
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
// Personal details validation
|
// Personal details validation
|
||||||
name: Yup.string().required("Name is required"),
|
name: Yup.string().required("Name is required"),
|
||||||
|
|
@ -206,6 +223,7 @@ function YourDetailsForm() {
|
||||||
.matches(/^[0-9]+$/, "Mobile Number must be a valid number")
|
.matches(/^[0-9]+$/, "Mobile Number must be a valid number")
|
||||||
.min(10, "Mobile number should have 10 digits only.")
|
.min(10, "Mobile number should have 10 digits only.")
|
||||||
.max(10, "Mobile number should have 10 digits only."),
|
.max(10, "Mobile number should have 10 digits only."),
|
||||||
|
mobilePrefix: Yup.string().required("Mobile Prefix is required"),
|
||||||
password: Yup.string()
|
password: Yup.string()
|
||||||
.matches(passwordLengthRegex, "Password must be at least 8 characters")
|
.matches(passwordLengthRegex, "Password must be at least 8 characters")
|
||||||
.matches(passwordLetterRegex, "Password must contain at least one letter")
|
.matches(passwordLetterRegex, "Password must contain at least one letter")
|
||||||
|
|
@ -218,7 +236,6 @@ function YourDetailsForm() {
|
||||||
confirmPassword: Yup.string()
|
confirmPassword: Yup.string()
|
||||||
.oneOf([Yup.ref("password"), null], "Passwords must match")
|
.oneOf([Yup.ref("password"), null], "Passwords must match")
|
||||||
.required("The password must match"),
|
.required("The password must match"),
|
||||||
currentEmail: Yup.string().email("Invalid email").notRequired(),
|
|
||||||
otp: Yup.string().required("OTP is required"),
|
otp: Yup.string().required("OTP is required"),
|
||||||
|
|
||||||
// Clinic details validation
|
// Clinic details validation
|
||||||
|
|
@ -228,6 +245,20 @@ function YourDetailsForm() {
|
||||||
.matches(/^[0-9]+$/, "Business Phone must be a valid number")
|
.matches(/^[0-9]+$/, "Business Phone must be a valid number")
|
||||||
.min(10, "Business Phone number should have 10 digits only.")
|
.min(10, "Business Phone number should have 10 digits only.")
|
||||||
.max(10, "Business Phone number should have 10 digits only."),
|
.max(10, "Business Phone number should have 10 digits only."),
|
||||||
|
businessPhonePrefix: Yup.string().required(
|
||||||
|
"Business Phone Prefix is required"
|
||||||
|
),
|
||||||
|
emergencyBusinessPhone: Yup.string()
|
||||||
|
.required("Emergency Business Phone is required")
|
||||||
|
.matches(/^[0-9]+$/, "Emergency Business Phone must be a valid number")
|
||||||
|
.min(10, "Emergency Business Phone number should have 10 digits only.")
|
||||||
|
.max(10, "Emergency Business Phone number should have 10 digits only."),
|
||||||
|
emergencyBusinessPhonePrefix: Yup.string().required(
|
||||||
|
"Emergency Business Phone Prefix is required"
|
||||||
|
),
|
||||||
|
businessEmail: Yup.string()
|
||||||
|
.required("Business Email is required")
|
||||||
|
.email("Please enter valid Email Address"),
|
||||||
businessFax: Yup.string()
|
businessFax: Yup.string()
|
||||||
.required("Business Fax is required")
|
.required("Business Fax is required")
|
||||||
.matches(/^[0-9]+$/, "Business Fax must be a valid number")
|
.matches(/^[0-9]+$/, "Business Fax must be a valid number")
|
||||||
|
|
@ -239,35 +270,21 @@ function YourDetailsForm() {
|
||||||
designation: Yup.string()
|
designation: Yup.string()
|
||||||
.required("Designation is required")
|
.required("Designation is required")
|
||||||
.typeError("Designation must be string"),
|
.typeError("Designation must be string"),
|
||||||
businessPhone: Yup.string()
|
pincode: Yup.string().required("Pincode is required"),
|
||||||
.required("Clinic website is required")
|
|
||||||
.matches(WEBSITE_REGEX, "Please enter a valid URL"),
|
|
||||||
companyIndustry: Yup.string().required("Clinic Industry is required"),
|
|
||||||
state: Yup.string().required(),
|
state: Yup.string().required(),
|
||||||
locality: Yup.string().required("City is required"),
|
locality: Yup.string().required("City is required"),
|
||||||
country: Yup.string().required("Country is required"),
|
country: Yup.string().required("Country is required"),
|
||||||
fullAddress: Yup.string()
|
fullAddress: Yup.string()
|
||||||
.required("Full Address is required")
|
.required("Full Address is required")
|
||||||
.typeError("Address must be string"),
|
.typeError("Address must be string"),
|
||||||
companyPANImage: Yup.string()
|
companyABNImageNumber: Yup.string()
|
||||||
.required("ABN number is required")
|
.required("ABN number is required")
|
||||||
.matches(
|
.matches(
|
||||||
ONLY_ALPHA_NUMERIC_ACCEPT_REGEX,
|
ONLY_ALPHA_NUMERIC_ACCEPT_REGEX,
|
||||||
"ABN Number must only contain numbers and letters"
|
"ABN Number must only contain numbers and letters"
|
||||||
)
|
)
|
||||||
.length(ABN_NUMBER_LENGTH, "Enter valid ABN Number"),
|
.length(ABN_NUMBER_LENGTH, "Enter valid ABN Number"),
|
||||||
companyTANNumber: Yup.string()
|
companyABNImage: Yup.string().required("Clinic ABN document is required"),
|
||||||
.required("Medicare number is required")
|
|
||||||
.matches(
|
|
||||||
ONLY_ALPHA_NUMERIC_ACCEPT_REGEX,
|
|
||||||
"Medicare Number must only contain numbers and letters"
|
|
||||||
)
|
|
||||||
.length(MEDIICARE_NUMBER_LENGTH, "Enter valid Medicare Number"),
|
|
||||||
companyGSTImage: Yup.string().required("Clinic GST document is required"),
|
|
||||||
companyPANImage: Yup.string().required("Clinic ABN document is required"),
|
|
||||||
companyTANImage: Yup.string().required(
|
|
||||||
"Clinic MEDICARE document is required"
|
|
||||||
),
|
|
||||||
contract: Yup.string().required("Contract is required"),
|
contract: Yup.string().required("Contract is required"),
|
||||||
termsAccepted: Yup.boolean()
|
termsAccepted: Yup.boolean()
|
||||||
.oneOf([true], "You must accept the terms and conditions")
|
.oneOf([true], "You must accept the terms and conditions")
|
||||||
|
|
@ -330,23 +347,22 @@ function YourDetailsForm() {
|
||||||
|
|
||||||
const handleFormSubmit = async () => {
|
const handleFormSubmit = async () => {
|
||||||
dispatch(updateFormDetails(formik.values));
|
dispatch(updateFormDetails(formik.values));
|
||||||
|
const body = formatedData(formik.values);
|
||||||
|
console.log(body);
|
||||||
|
|
||||||
// const body = formatedData(formik.values);
|
|
||||||
try {
|
try {
|
||||||
// const response = await signup(body);
|
// TODO: verify otp first
|
||||||
// if (response?.data?.error) {
|
|
||||||
// pushNotification(response?.data?.message, NOTIFICATION.ERROR);
|
const response = await signup(body);
|
||||||
// } else {
|
if (response?.data?.error) {
|
||||||
// pushNotification(response?.data?.message, NOTIFICATION.SUCCESS);
|
pushNotification(response?.data?.message, NOTIFICATION.ERROR);
|
||||||
// dispatch(resetFormData());
|
return;
|
||||||
// navigate('/');
|
}
|
||||||
// }
|
pushNotification(response?.data?.message, NOTIFICATION.SUCCESS);
|
||||||
// pushNotification('Your request is submitted', NOTIFICATION.SUCCESS);
|
dispatch(resetFormData());
|
||||||
// dispatch(resetFormData());
|
|
||||||
// navigate('/');
|
|
||||||
navigate("/auth/signup/payment");
|
navigate("/auth/signup/payment");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.error('Error signing up:', error);
|
console.error('Error signing up:', error);
|
||||||
} finally {
|
} finally {
|
||||||
formik.isSubmitting(false);
|
formik.isSubmitting(false);
|
||||||
}
|
}
|
||||||
|
|
@ -355,9 +371,7 @@ function YourDetailsForm() {
|
||||||
// Initialize formik with a submission handler defined inline to avoid circular references
|
// Initialize formik with a submission handler defined inline to avoid circular references
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
initialValues: defaultFormData.current,
|
initialValues: defaultFormData.current,
|
||||||
// validationSchema,
|
validationSchema,
|
||||||
validateOnBlur: true,
|
|
||||||
validateOnChange: false, // Only validate on blur, not on every keystroke
|
|
||||||
onSubmit: handleFormSubmit,
|
onSubmit: handleFormSubmit,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -366,7 +380,7 @@ function YourDetailsForm() {
|
||||||
if (formik?.values?.country !== defaultFormData.current.country) {
|
if (formik?.values?.country !== defaultFormData.current.country) {
|
||||||
formik.setFieldValue("pincode", "");
|
formik.setFieldValue("pincode", "");
|
||||||
formik.setFieldValue("state", "");
|
formik.setFieldValue("state", "");
|
||||||
formik.setFieldValue("locality", "");
|
// formik.setFieldValue("locality", "");
|
||||||
}
|
}
|
||||||
}, [formik?.values?.country]);
|
}, [formik?.values?.country]);
|
||||||
|
|
||||||
|
|
@ -383,11 +397,11 @@ function YourDetailsForm() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (Array.isArray(pincodeData) && pincodeData.length > 0) {
|
if (Array.isArray(pincodeData) && pincodeData.length > 0) {
|
||||||
formik.setFieldValue("state", pincodeData[0]?.state);
|
formik.setFieldValue("state", pincodeData[0]?.state);
|
||||||
formik.setFieldValue("locality", selectedLocalityRef.current);
|
// formik.setFieldValue("locality", selectedLocalityRef.current);
|
||||||
} else {
|
} else {
|
||||||
setCountryOption(["Australia", "India"]);
|
setCountryOption(["Australia", "India"]);
|
||||||
formik.setFieldValue("state", "");
|
// formik.setFieldValue("state", "");
|
||||||
formik.setFieldValue("locality", "");
|
// formik.setFieldValue("locality", "");
|
||||||
formik.setFieldError("pincode", "Invalid pincode");
|
formik.setFieldError("pincode", "Invalid pincode");
|
||||||
}
|
}
|
||||||
}, [pincodeData]);
|
}, [pincodeData]);
|
||||||
|
|
@ -402,20 +416,34 @@ function YourDetailsForm() {
|
||||||
aspect: 1 / 1,
|
aspect: 1 / 1,
|
||||||
});
|
});
|
||||||
setLogoname();
|
setLogoname();
|
||||||
formik.setFieldValue("companyLogo", "");
|
formik.setFieldValue("clinicLogo", "");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFileUpload = async (value) => {
|
const handleFileUpload = async (value) => {
|
||||||
let formData = new FormData();
|
|
||||||
formData.append("file", value);
|
|
||||||
formData.append("fileName", value?.name);
|
|
||||||
try {
|
try {
|
||||||
const data = await fileUpload(formData);
|
// Store the file object directly in the form values
|
||||||
const imageUrl = data?.data?.data?.Key;
|
// We'll use this later for the actual upload after form submission
|
||||||
formik.setFieldValue("companyLogo", imageUrl);
|
|
||||||
return imageUrl;
|
const filePayload = {
|
||||||
|
folder: "assests",
|
||||||
|
file_name: value.name,
|
||||||
|
};
|
||||||
|
|
||||||
|
const presignedUrlResponseClinicLogo = await getPresignedUrl(
|
||||||
|
filePayload,
|
||||||
|
);
|
||||||
|
|
||||||
|
await uploadToS3(
|
||||||
|
value,
|
||||||
|
presignedUrlResponseClinicLogo?.data?.data?.api_url
|
||||||
|
);
|
||||||
|
|
||||||
|
formik.setFieldValue("clinicLogo", presignedUrlResponseClinicLogo?.data?.data?.key);
|
||||||
|
|
||||||
|
// Return a temporary local URL for preview purposes
|
||||||
|
return URL.createObjectURL(value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
pushNotification("Error while uploading file", NOTIFICATION.ERROR);
|
pushNotification("Error processing file", NOTIFICATION.ERROR);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -508,7 +536,16 @@ function YourDetailsForm() {
|
||||||
|
|
||||||
// Set uploaded file URL
|
// Set uploaded file URL
|
||||||
const setUploadedFileUrl = (documentName, fileUrl) => {
|
const setUploadedFileUrl = (documentName, fileUrl) => {
|
||||||
|
console.log('Document Name:', documentName);
|
||||||
|
console.log('File URL:', fileUrl);
|
||||||
|
console.log('File URL Type:', typeof fileUrl);
|
||||||
|
|
||||||
|
if (documentName && fileUrl !== undefined) {
|
||||||
formik.setFieldValue(documentName, fileUrl);
|
formik.setFieldValue(documentName, fileUrl);
|
||||||
|
console.log('After setting value:', formik.values[documentName]);
|
||||||
|
} else {
|
||||||
|
console.error('Invalid parameters for setUploadedFileUrl:', { documentName, fileUrl });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// handleSaveAndNext will use formik's handleSubmit
|
// handleSaveAndNext will use formik's handleSubmit
|
||||||
|
|
@ -516,77 +553,66 @@ function YourDetailsForm() {
|
||||||
// Helper function for formatted data
|
// Helper function for formatted data
|
||||||
function formatedData(inputData) {
|
function formatedData(inputData) {
|
||||||
const data = {
|
const data = {
|
||||||
name: inputData.companyName || "",
|
user: {
|
||||||
businessPhone: inputData.businessPhone || "",
|
username: inputData.name,
|
||||||
emergencyBusinessPhone: inputData.emergencyBusinessPhone || "",
|
email: inputData.email,
|
||||||
emergencyBusinessPhonePrefix:
|
mobile: `${inputData.mobilePrefix ?? mobilePrefixOptions[0].name} ${
|
||||||
inputData.emergencyBusinessPhonePrefix || "",
|
inputData.mobileNumber
|
||||||
businessPhonePrefix: inputData.businessPhonePrefix || "",
|
}`,
|
||||||
businessFax: inputData.businessFax || "",
|
password: inputData.password,
|
||||||
city: inputData.locality || "",
|
clinicRole: inputData.designation,
|
||||||
state: inputData.state || "",
|
userType: "clinic_admin",
|
||||||
logo: inputData.companyLogo || null,
|
|
||||||
street: inputData.fullAddress || "",
|
|
||||||
pinCode: inputData.pincode || "",
|
|
||||||
country: inputData.country || "",
|
|
||||||
locality: inputData.locality || "",
|
|
||||||
industryId: inputData.companyIndustry || 0,
|
|
||||||
companyAdmin: {
|
|
||||||
name: inputData.name || "",
|
|
||||||
email: inputData.email || "",
|
|
||||||
mobile: inputData.mobileNumber || "",
|
|
||||||
password: inputData.password || "",
|
|
||||||
designation: inputData.designation || "",
|
|
||||||
},
|
},
|
||||||
practiceId: inputData.practiceId || "",
|
clinic: {
|
||||||
practiceManagementSystem: inputData.practiceManagementSystem || "",
|
name: inputData.companyName,
|
||||||
practiceName: inputData.practiceName || "",
|
address: inputData.fullAddress,
|
||||||
companyUsers: inputData.billingUsers || "",
|
state: inputData.state,
|
||||||
companyDocuments: [
|
phone: `${
|
||||||
...(inputData.companyLogo
|
inputData.businessPhonePrefix ?? mobilePrefixOptions[0].name
|
||||||
? [
|
} ${inputData.businessPhone}`,
|
||||||
{
|
emergencyPhone: `${
|
||||||
documentNumber: "LOGO",
|
inputData.emergencyBusinessPhonePrefix ?? mobilePrefixOptions[0].name
|
||||||
fileURL: inputData.companyLogo,
|
} ${inputData.emergencyBusinessPhone}`,
|
||||||
documentType: "LOGO",
|
fax: inputData.businessFax,
|
||||||
|
email: inputData.businessEmail,
|
||||||
|
integration: inputData.practiceManagementSystem,
|
||||||
|
pms_id: inputData.practiceId,
|
||||||
|
practice_name: inputData.practiceName,
|
||||||
|
logo: inputData.clinicLogo || null,
|
||||||
|
country: inputData.country,
|
||||||
|
postal_code: inputData.pincode,
|
||||||
|
city: inputData.locality,
|
||||||
|
abn_number: inputData.companyABNImageNumber,
|
||||||
|
abn_doc: inputData.companyABNImage,
|
||||||
|
contract_doc: inputData.contract,
|
||||||
},
|
},
|
||||||
]
|
|
||||||
: []),
|
|
||||||
{
|
|
||||||
documentNumber: inputData.companyPANImage || "",
|
|
||||||
fileURL: inputData.companyPANImage || "",
|
|
||||||
documentType: "PAN",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
contract: inputData.contract || "",
|
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAddUser = () => {
|
const handleSaveAndNext = async () => {
|
||||||
if (
|
if (!otpField) {
|
||||||
billingUsers?.includes(formik?.values?.currentEmail) ||
|
pushNotification("Please verify OTP first", NOTIFICATION.ERROR);
|
||||||
formik?.values?.email === formik.values?.currentEmail
|
otpButtonRef.current?.focus();
|
||||||
) {
|
|
||||||
pushNotification("Email Address must be unique", NOTIFICATION.ERROR);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (formik.values.currentEmail && billingUsers?.length < 5) {
|
|
||||||
setBillingUsers([...billingUsers, formik.values.currentEmail]);
|
if (!testConnection) {
|
||||||
formik.setFieldValue("currentEmail", "");
|
pushNotification("Please test the connection first", NOTIFICATION.ERROR);
|
||||||
|
// scroll to test connection button
|
||||||
|
// testConnectionRef.current?.scrollIntoView({
|
||||||
|
// behavior: "smooth",
|
||||||
|
// });
|
||||||
|
testConnectionRef.current?.focus();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserDelete = (index) => {
|
|
||||||
const updatedUsers = billingUsers.filter((_, i) => i !== index);
|
|
||||||
setBillingUsers(updatedUsers);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSaveAndNext = async () => {
|
|
||||||
const formikError = await formik.validateForm(formik.values);
|
const formikError = await formik.validateForm(formik.values);
|
||||||
|
|
||||||
const errors = Object.keys(formikError);
|
const errors = Object.keys(formikError);
|
||||||
|
|
||||||
|
console.log(errors)
|
||||||
|
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
// Find the first invalid field and focus it
|
// Find the first invalid field and focus it
|
||||||
const firstErrorField = errors[0];
|
const firstErrorField = errors[0];
|
||||||
|
|
@ -653,7 +679,7 @@ function YourDetailsForm() {
|
||||||
className={classes.formRoot}
|
className={classes.formRoot}
|
||||||
>
|
>
|
||||||
<Grid item md={4} sm={6} xs={12}>
|
<Grid item md={4} sm={6} xs={12}>
|
||||||
<TextField value={1} disabled />
|
<TextField value={latestClinicID + 1} disabled />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
@ -733,6 +759,7 @@ function YourDetailsForm() {
|
||||||
color="info"
|
color="info"
|
||||||
disabled={!formik.values.email}
|
disabled={!formik.values.email}
|
||||||
onClick={handleOTPButton}
|
onClick={handleOTPButton}
|
||||||
|
ref={otpButtonRef}
|
||||||
>
|
>
|
||||||
Request OTP
|
Request OTP
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -1146,7 +1173,16 @@ function YourDetailsForm() {
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
name="emergencyBusinessPhone"
|
name="emergencyBusinessPhone"
|
||||||
value={formik.values.emergencyBusinessPhone}
|
value={formik.values.emergencyBusinessPhone}
|
||||||
onChange={formik.handleChange}
|
onChange={(e) => {
|
||||||
|
if (e.target.value.length <= 10) {
|
||||||
|
const value =
|
||||||
|
e.target.value?.match(/\d+/g) || "";
|
||||||
|
formik.setFieldValue(
|
||||||
|
"emergencyBusinessPhone",
|
||||||
|
value?.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
type: "text",
|
type: "text",
|
||||||
|
|
@ -1253,16 +1289,7 @@ function YourDetailsForm() {
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
name="businessEmail"
|
name="businessEmail"
|
||||||
value={formik.values.businessEmail}
|
value={formik.values.businessEmail}
|
||||||
onChange={(e) => {
|
onChange={formik.handleChange}
|
||||||
if (e.target.value.length <= 10) {
|
|
||||||
const value =
|
|
||||||
e.target.value?.match(/\d+/g) || "";
|
|
||||||
formik.setFieldValue(
|
|
||||||
"businessEmail",
|
|
||||||
value?.toString()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
type: "email",
|
type: "email",
|
||||||
|
|
@ -1307,8 +1334,8 @@ function YourDetailsForm() {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{integrationOptions.map((option) => (
|
{integrationOptions.map((option) => (
|
||||||
<MenuItem key={option} value={option}>
|
<MenuItem key={option.id} value={option.id}>
|
||||||
{option}
|
{option.name}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
|
@ -1372,6 +1399,7 @@ function YourDetailsForm() {
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleTestConnection}
|
onClick={handleTestConnection}
|
||||||
|
ref={testConnectionRef}
|
||||||
>
|
>
|
||||||
Test Connection
|
Test Connection
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -1381,7 +1409,7 @@ function YourDetailsForm() {
|
||||||
<Grid item md={5} sm={12}>
|
<Grid item md={5} sm={12}>
|
||||||
<InputLabel className={classes.inputLabel}>
|
<InputLabel className={classes.inputLabel}>
|
||||||
Add Business Logo
|
Add Business Logo
|
||||||
{(logoImage || formik.values.companyLogo) && (
|
{(logoImage || formik.values.clinicLogo) && (
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
className={classes.imgButton}
|
className={classes.imgButton}
|
||||||
|
|
@ -1394,7 +1422,7 @@ function YourDetailsForm() {
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
<Box display="flex">
|
<Box display="flex">
|
||||||
<Box className={classes.dropZoneOuterBox}>
|
<Box className={classes.dropZoneOuterBox}>
|
||||||
<label htmlFor="companyLogo">
|
<label htmlFor="clinicLogo">
|
||||||
<Dropzone
|
<Dropzone
|
||||||
accept={{
|
accept={{
|
||||||
"image/": [...IMAGE_TYPE],
|
"image/": [...IMAGE_TYPE],
|
||||||
|
|
@ -1416,7 +1444,7 @@ function YourDetailsForm() {
|
||||||
onClick: (event) => {
|
onClick: (event) => {
|
||||||
if (
|
if (
|
||||||
logoImage ||
|
logoImage ||
|
||||||
formik.values.companyLogo
|
formik.values.clinicLogo
|
||||||
) {
|
) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
@ -1431,7 +1459,7 @@ function YourDetailsForm() {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{!logoImage &&
|
{!logoImage &&
|
||||||
!formik.values.companyLogo ? (
|
!formik.values.clinicLogo ? (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
className={classes.addIcon}
|
className={classes.addIcon}
|
||||||
|
|
@ -1478,13 +1506,13 @@ function YourDetailsForm() {
|
||||||
)}
|
)}
|
||||||
{!logoImage &&
|
{!logoImage &&
|
||||||
formik.values
|
formik.values
|
||||||
.companyLogo && (
|
.clinicLogo && (
|
||||||
<img
|
<img
|
||||||
alt="Edit me"
|
alt="Edit me"
|
||||||
src={
|
src={
|
||||||
IMAGE_LOCATION_BASE_URL +
|
IMAGE_LOCATION_BASE_URL +
|
||||||
formik.values
|
formik.values
|
||||||
.companyLogo
|
.clinicLogo
|
||||||
}
|
}
|
||||||
className={
|
className={
|
||||||
classes.editImage
|
classes.editImage
|
||||||
|
|
@ -1495,8 +1523,8 @@ function YourDetailsForm() {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
{formik.errors.companyLogo &&
|
{formik.errors.clinicLogo &&
|
||||||
formik.touched.companyLogo && (
|
formik.touched.clinicLogo && (
|
||||||
<Box
|
<Box
|
||||||
component="span"
|
component="span"
|
||||||
className={
|
className={
|
||||||
|
|
@ -1508,9 +1536,8 @@ function YourDetailsForm() {
|
||||||
classes.errorText
|
classes.errorText
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{formik.errors.companyLogo
|
{formik.errors.clinicLogo
|
||||||
? formik.errors
|
? formik.errors.clinicLogo
|
||||||
.companyLogo
|
|
||||||
: ""}
|
: ""}
|
||||||
</span>
|
</span>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -1557,6 +1584,7 @@ function YourDetailsForm() {
|
||||||
error={Boolean(
|
error={Boolean(
|
||||||
formik.errors.country && formik.touched.country
|
formik.errors.country && formik.touched.country
|
||||||
)}
|
)}
|
||||||
|
helperText={formik.errors.country}
|
||||||
>
|
>
|
||||||
<MenuItem value="" disabled>
|
<MenuItem value="" disabled>
|
||||||
<Typography className={classes.placeholderText}>
|
<Typography className={classes.placeholderText}>
|
||||||
|
|
@ -1650,6 +1678,7 @@ function YourDetailsForm() {
|
||||||
formik.errors.locality &&
|
formik.errors.locality &&
|
||||||
formik.touched.locality
|
formik.touched.locality
|
||||||
)}
|
)}
|
||||||
|
helperText={formik.errors.locality}
|
||||||
>
|
>
|
||||||
<MenuItem value="" disabled>
|
<MenuItem value="" disabled>
|
||||||
<Typography className={classes.placeholderText}>
|
<Typography className={classes.placeholderText}>
|
||||||
|
|
@ -1723,16 +1752,16 @@ function YourDetailsForm() {
|
||||||
{/* PAN NUMBER GRID */}
|
{/* PAN NUMBER GRID */}
|
||||||
<Grid item md={4} sm={6} xs={12}>
|
<Grid item md={4} sm={6} xs={12}>
|
||||||
<InputLabel className={classes.inputLabel}>
|
<InputLabel className={classes.inputLabel}>
|
||||||
Clinic ABN Number*
|
Clinic ABN/ACN Number*
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
placeholder="Enter Clinic ABN Number"
|
placeholder="Enter Clinic ABN/ACN Number"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
name="companyPANImage"
|
name="companyABNImageNumber"
|
||||||
value={formik.values.companyPANImage}
|
value={formik.values.companyABNImageNumber}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (
|
if (
|
||||||
e.target.value.length <= ABN_NUMBER_LENGTH
|
e.target.value.length <= ABN_NUMBER_LENGTH
|
||||||
|
|
@ -1745,26 +1774,26 @@ function YourDetailsForm() {
|
||||||
}}
|
}}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
formik.setFieldValue(
|
formik.setFieldValue(
|
||||||
"companyPANImage",
|
"companyABNImageNumber",
|
||||||
e.target.value.trim()
|
e.target.value.trim()
|
||||||
);
|
);
|
||||||
formik.handleBlur(e);
|
formik.handleBlur(e);
|
||||||
}}
|
}}
|
||||||
inputRef={fieldRefs.companyPANImage}
|
inputRef={fieldRefs.companyABNImageNumber}
|
||||||
error={Boolean(
|
error={Boolean(
|
||||||
formik.errors.companyPANImage &&
|
formik.errors.companyABNImageNumber &&
|
||||||
formik.touched.companyPANImage
|
formik.touched.companyABNImageNumber
|
||||||
)}
|
)}
|
||||||
helperText={
|
helperText={
|
||||||
formik.errors.companyPANImage &&
|
formik.errors.companyABNImageNumber &&
|
||||||
formik.touched.companyPANImage
|
formik.touched.companyABNImageNumber
|
||||||
? formik.errors.companyPANImage
|
? formik.errors.companyABNImageNumber
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{!formik.errors.companyPANImage ? (
|
{!formik.errors.companyABNImageNumber ? (
|
||||||
<VerifiedIcon
|
<VerifiedIcon
|
||||||
className={classes.verifyIcon}
|
className={classes.verifyIcon}
|
||||||
/>
|
/>
|
||||||
|
|
@ -1778,23 +1807,37 @@ function YourDetailsForm() {
|
||||||
{/* PAN image upload grid */}
|
{/* PAN image upload grid */}
|
||||||
<Grid item md={4} sm={12} xs={12}>
|
<Grid item md={4} sm={12} xs={12}>
|
||||||
<CustomFileUpload
|
<CustomFileUpload
|
||||||
label="Add ABN Image*"
|
label="Add ABN/ACN Image*"
|
||||||
documentName="companyPANImage"
|
documentName="companyABNImage"
|
||||||
onUploadDone={setUploadedFileUrl}
|
onUploadDone={setUploadedFileUrl}
|
||||||
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
|
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
|
||||||
maxFiles={MAX_FILES}
|
maxFiles={MAX_FILES}
|
||||||
uploadedFileUrl={formik.values.companyPANImage}
|
uploadedFileUrl={formik.values.companyABNImage}
|
||||||
errorMessage={
|
errorMessage={
|
||||||
formik.errors.companyPANImage &&
|
formik.errors.companyABNImage &&
|
||||||
formik.touched.companyPANImage
|
formik.touched.companyABNImage
|
||||||
? formik.errors.companyPANImage
|
? formik.errors.companyABNImage
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* contract grid */}
|
{/* contract grid */}
|
||||||
<Grid item md={4} sm={12} xs={12}>
|
<Grid
|
||||||
|
display="flex"
|
||||||
|
flexDirection="row"
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignItems="center"
|
||||||
|
item
|
||||||
|
md={4}
|
||||||
|
sm={12}
|
||||||
|
xs={12}
|
||||||
|
>
|
||||||
|
<Box mr={2}>
|
||||||
|
<Tooltip title="Download the contract template">
|
||||||
|
<Button>Download Template</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
<CustomFileUpload
|
<CustomFileUpload
|
||||||
label="Add Contract*"
|
label="Add Contract*"
|
||||||
documentName="contract"
|
documentName="contract"
|
||||||
|
|
|
||||||
|
|
@ -8,28 +8,31 @@ const initialState = {
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
mobileNumber: '',
|
mobileNumber: '',
|
||||||
|
mobilePrefix: '',
|
||||||
password: '',
|
password: '',
|
||||||
confirmPassword: '',
|
confirmPassword: '',
|
||||||
billingUsers: [],
|
|
||||||
currentEmail: '',
|
currentEmail: '',
|
||||||
|
|
||||||
companyName: '',
|
companyName: '',
|
||||||
designation: '',
|
designation: '',
|
||||||
businessPhone: '',
|
businessPhonePrefix: "",
|
||||||
companyAbout: '',
|
businessPhone: "",
|
||||||
companyLogo: '',
|
emergencyBusinessPhone: "",
|
||||||
companyIndustry: '',
|
emergencyBusinessPhonePrefix: "",
|
||||||
|
businessFax: "",
|
||||||
|
clinicLogo: '',
|
||||||
|
practiceManagementSystem: '',
|
||||||
|
practiceId: '',
|
||||||
|
practiceName: '',
|
||||||
pincode: '',
|
pincode: '',
|
||||||
state: '',
|
state: '',
|
||||||
locality: '',
|
locality: '',
|
||||||
fullAddress: '',
|
fullAddress: '',
|
||||||
companyGSTNumber: '',
|
companyABNImageNumber: "",
|
||||||
companyPANNumber: '',
|
companyABNImage: "",
|
||||||
companyTANNumber: '',
|
|
||||||
companyGSTImage: '',
|
|
||||||
companyPANImage: '',
|
|
||||||
companyTANImage: '',
|
|
||||||
termsAccepted: '',
|
termsAccepted: '',
|
||||||
hideAndShowFunctionality: false,
|
contract: '',
|
||||||
|
businessEmail: '',
|
||||||
};
|
};
|
||||||
const updateFormDetails = (state, payload) => ({
|
const updateFormDetails = (state, payload) => ({
|
||||||
...state,
|
...state,
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ function Users() {
|
||||||
const [roles, setRoles] = useState();
|
const [roles, setRoles] = useState();
|
||||||
const [isAdmin, setIsAdmin] = useState();
|
const [isAdmin, setIsAdmin] = useState();
|
||||||
|
|
||||||
const isBsAdmin = useSelector((state) => state?.login?.user?.isBsAdmin);
|
const isSuperAdmin = useSelector((state) => state?.login?.user?.isSuperAdmin);
|
||||||
|
|
||||||
/* ----------------- Get Users ----------------- */
|
/* ----------------- Get Users ----------------- */
|
||||||
const getData = async (filters) => {
|
const getData = async (filters) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue