From 9e39a1f9a16defc41b531930ee3cd445b99b5803 Mon Sep 17 00:00:00 2001 From: deepvasoya Date: Fri, 30 May 2025 15:31:50 +0530 Subject: [PATCH] feat: clinic setup refactor: removed logo from signup and list fix: other changes --- src/components/Table.jsx | 53 ++- src/index.css | 4 +- src/services/clinics.service.js | 5 +- src/services/masterData.services.js | 2 + .../ClinicDetails/component/FileEvaluate.jsx | 245 ++----------- src/views/ClinicDetails/index.jsx | 47 ++- src/views/ClinicDocUpdate/index.jsx | 4 +- src/views/ClinicSetup/clinicSetupStyles.js | 325 ++++++++++++++++++ src/views/ClinicSetup/index.jsx | 278 ++++++++++++--- src/views/ClinicsList/index.jsx | 82 ++--- src/views/Dashboard/Tiles/Totals.jsx | 4 +- src/views/Login/loginReducer.js | 14 +- src/views/MasterData/index.jsx | 1 - src/views/PaymentManagement/index.jsx | 2 +- src/views/Signup/YourDetailsForm.jsx | 4 +- src/views/User/index.jsx | 6 +- 16 files changed, 684 insertions(+), 392 deletions(-) create mode 100644 src/views/ClinicSetup/clinicSetupStyles.js diff --git a/src/components/Table.jsx b/src/components/Table.jsx index 644b811..cb48d4c 100644 --- a/src/components/Table.jsx +++ b/src/components/Table.jsx @@ -34,6 +34,7 @@ import ProtectedComponent from "../components/ProtectedComponent"; import { DesktopDatePicker, LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; import { DateRangePicker } from "@mui/x-date-pickers-pro"; +import { enGB } from "date-fns/locale"; const Table = memo( forwardRef((props, ref) => { @@ -74,14 +75,6 @@ const Table = memo( }); const navigate = useNavigate(); - - useEffect(()=>{ - if(dateRange){ - console.log(dateRange); - - } - },[dateRange]) - useImperativeHandle(ref, () => ({ reFetchData() { setIsLoading(true); @@ -253,29 +246,27 @@ const Table = memo( /> {showDateFilters && ( - ( - - )} - slotProps={{ - field: { - clearable: true, - - } - }} - value={dateRange} - onChange={(newValue) => { - setDateRange(newValue); - // column.setFilterValue(newValue); - }} - inputFormat="MMM d, yyyy" - format="MMM d, yyyy" - /> - + className={classes.searchContainer} + dateAdapter={AdapterDateFns} + adapterLocale={enGB} // Import: import { enGB } from 'date-fns/locale' + > + { + setDateRange(newValue); + }} + format="dd/MM/yyyy" + /> + )} {!hideShowPerPage && ( diff --git a/src/index.css b/src/index.css index 5701b28..f76d994 100644 --- a/src/index.css +++ b/src/index.css @@ -109,6 +109,6 @@ div::-webkit-scrollbar-thumb:hover { background-color: transparent; } -div[style*="z-index: 100000"] { +/* div[style*="z-index: 100000"] { visibility: hidden; -} \ No newline at end of file +} */ \ No newline at end of file diff --git a/src/services/clinics.service.js b/src/services/clinics.service.js index fd4888f..de13094 100644 --- a/src/services/clinics.service.js +++ b/src/services/clinics.service.js @@ -5,7 +5,7 @@ import { clinicsData, registeredClinicsData } from "../mock/clinics"; export const getClinics = (params) => { let searchParams = new URLSearchParams(); searchParams.append("limit", params?.pagination?.pageSize ?? 10); - searchParams.append("page", params?.pagination.pageIndex + 1 ?? 1); + searchParams.append("page", params?.pagination?.pageIndex + 1 ?? 1); searchParams.append("filter_type", params?.type ?? CLINIC_TYPE.REGISTERED); searchParams.append("search", params?.globalFilter ?? ""); @@ -69,7 +69,7 @@ export const getClinicDocs = (id) => { }); }; -export const updateClinicDocs = (id, data) => { +export const updateClinic = (id, data) => { const url = `/clinics/${id}`; return new Promise((resolve, reject) => { axiosInstance @@ -180,7 +180,6 @@ export const deleteDoctor = (id) => { }; export const getCallTranscripts = (params) => { - console.log(params); let searchParams = new URLSearchParams(); searchParams.append("limit", params?.pagination?.pageSize ?? 10); searchParams.append("page", params?.pagination.pageIndex + 1 ?? 1); diff --git a/src/services/masterData.services.js b/src/services/masterData.services.js index e19425b..20e5eb6 100644 --- a/src/services/masterData.services.js +++ b/src/services/masterData.services.js @@ -2,6 +2,8 @@ import { axiosInstance } from "../config/api"; export const getMasterData = (params) => { let searchParams = new URLSearchParams(); + searchParams.append("limit", params?.pagination?.pageSize ?? 10); + searchParams.append("page", params?.pagination.pageIndex + 1 ?? 1); searchParams.append("search", params?.globalFilter ?? ""); const url = `/admin/master-data?${searchParams.toString()}`; diff --git a/src/views/ClinicDetails/component/FileEvaluate.jsx b/src/views/ClinicDetails/component/FileEvaluate.jsx index 827c2a0..db6dd07 100644 --- a/src/views/ClinicDetails/component/FileEvaluate.jsx +++ b/src/views/ClinicDetails/component/FileEvaluate.jsx @@ -26,8 +26,8 @@ const FileEvaluate = ({ const classes = useStyles(); const [isPreview, setIsPreview] = useState(false); const [previewFile, setPreviewFile] = useState(); - const [reviewedLogoFiles, setReviewedLogoFiles] = useState([]); - const [notReviewedLogoFiles, setNotReviewedLogoFiles] = useState([]); + // const [reviewedLogoFiles, setReviewedLogoFiles] = useState([]); + // const [notReviewedLogoFiles, setNotReviewedLogoFiles] = useState([]); const [reviewedOtherFiles, setReviewedOtherFiles] = useState([]); const [notReviewedOtherFiles, setNotReviewedOtherFiles] = useState([]); @@ -40,28 +40,28 @@ const FileEvaluate = ({ if (!Array.isArray(files)) return; // Process all files at once to avoid multiple iterations - const reviewedLogo = []; - const notReviewedLogo = []; + // const reviewedLogo = []; + // const notReviewedLogo = []; const reviewedOther = []; const notReviewedOther = []; files.forEach((file) => { // Handle logo documents - if (file.logo_doc) { - if (file.logo_is_verified) { - reviewedLogo.push({ - file: file.logo_doc, - documentType: "LOGO", - isVerified: file.logo_is_verified, - }); - } else { - notReviewedLogo.push({ - file: file.logo_doc, - documentType: "LOGO", - isVerified: file.logo_is_verified, - }); - } - } + // if (file.logo_doc) { + // if (file.logo_is_verified) { + // reviewedLogo.push({ + // file: file.logo_doc, + // documentType: "LOGO", + // isVerified: file.logo_is_verified, + // }); + // } else { + // notReviewedLogo.push({ + // file: file.logo_doc, + // documentType: "LOGO", + // isVerified: file.logo_is_verified, + // }); + // } + // } // Handle ABN and contract documents (excluding logo docs which are handled separately) if (file.abn_doc) { @@ -98,15 +98,15 @@ const FileEvaluate = ({ }); // Update state with filtered files - setReviewedLogoFiles(reviewedLogo); - setNotReviewedLogoFiles(notReviewedLogo); + // 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("reviewedLogoFiles:", reviewedLogo); + // console.log("notReviewedLogoFiles:", notReviewedLogo); console.log("reviewedOtherFiles:", reviewedOther); console.log("notReviewedOtherFiles:", notReviewedOther); }, [files]); @@ -133,21 +133,21 @@ const FileEvaluate = ({ const handleActionClick = (index, file, actionType) => { const newFile = { ...file, - isVerified: - actionType === "ACCEPT" - ? true - : false, + isVerified: actionType === "ACCEPT" ? true : false, }; - if (file.documentType == "LOGO") { - const updatedFiles = [...notReviewedLogoFiles]; - updatedFiles.splice(index, 1, newFile); - setNotReviewedLogoFiles(updatedFiles); - } else { - const updatedFiles = [...notReviewedOtherFiles]; - updatedFiles.splice(index, 1, newFile); - setNotReviewedOtherFiles(updatedFiles); - } + // if (file.documentType == "LOGO") { + // const updatedFiles = [...notReviewedLogoFiles]; + // updatedFiles.splice(index, 1, newFile); + // setNotReviewedLogoFiles(updatedFiles); + // } else { + // const updatedFiles = [...notReviewedOtherFiles]; + // updatedFiles.splice(index, 1, newFile); + // setNotReviewedOtherFiles(updatedFiles); + // } + const updatedFiles = [...notReviewedOtherFiles]; + updatedFiles.splice(index, 1, newFile); + setNotReviewedOtherFiles(updatedFiles); onFileButtonClick(newFile); }; @@ -216,40 +216,6 @@ const FileEvaluate = ({ {/* ............CLINIC is Approved that time show only card............. */} {companyStatus === CLINIC_STATUS.ACTIVE ? ( <> - - {reviewedLogoFiles.map((file, index) => ( - - - - - CLINIC LOGO INFO - - {/* - Uploaded:{' '} - {format(new Date(file?.updatedAt), 'dd MMM yyyy')} - */} - - {companyName} LOGO - - - - Uploaded File - - - - ))} - {reviewedOtherFiles.map((file, index) => ( {/* .................logo reviewed grid................ */} - - {reviewedLogoFiles.map((file, index) => ( - - - - - CLINIC LOGO INFO - - {/* - Uploaded:{' '} - {format(new Date(file?.updatedAt), 'dd MMM yyyy')} - */} - - {companyName} LOGO - - - - Uploaded File - - - - - - - {!file.isVerified && } - {file.isVerified && } - - - - ))} - - {notReviewedLogoFiles.map((file, index) => ( - - - - - CLINIC {file.documentType} INFO - - {/* - Uploaded:{' '} - {format(new Date(file?.updatedAt), 'dd MMM yyyy')} - */} - - {companyName} LOGO - - - - {file.documentType} - - - - - - - {file.isVerified == null ? ( - <> - - handleActionClick(index, file, "REJECT") - } - /> - - handleActionClick(index, file, "ACCEPT") - } - /> - - ) : file.isVerified ? ( - <> - - handleActionClick(index, file, "REJECT") - } - /> - - - ) : ( - <> - - handleActionClick(index, file, "ACCEPT") - } - /> - - - )} - - - - ))} - {/* .................another image grid............. */} diff --git a/src/views/ClinicDetails/index.jsx b/src/views/ClinicDetails/index.jsx index 18f6712..6fd136b 100644 --- a/src/views/ClinicDetails/index.jsx +++ b/src/views/ClinicDetails/index.jsx @@ -141,10 +141,10 @@ function ClinicDetails() { const newFile = { ...file, }; - if (file.documentType == "LOGO") { - newFile.logo_is_verified = file.isVerified; - clinicFiles.logo_is_verified = file.isVerified; - } + // if (file.documentType == "LOGO") { + // newFile.logo_is_verified = file.isVerified; + // clinicFiles.logo_is_verified = file.isVerified; + // } if (file.documentType == "ABN") { newFile.abn_doc_is_verified = file.isVerified; clinicFiles.abn_doc_is_verified = file.isVerified; @@ -159,10 +159,10 @@ function ClinicDetails() { const updatedFiles = [...prevFiles]; const fileToBeUpdate = updatedFiles[oldIndex]; - if (fileToBeUpdate.documentType == "LOGO") { - fileToBeUpdate.logo_is_verified = file.isVerified; - clinicFiles.logo_is_verified = file.isVerified; - } + // if (fileToBeUpdate.documentType == "LOGO") { + // fileToBeUpdate.logo_is_verified = file.isVerified; + // clinicFiles.logo_is_verified = file.isVerified; + // } if (fileToBeUpdate.documentType == "ABN") { fileToBeUpdate.abn_doc_is_verified = file.isVerified; @@ -180,16 +180,6 @@ function ClinicDetails() { } }; - const getNotReviewedFileCount = () => { - if (clinicData?.companyDocuments) { - const notReviewedDocuments = clinicData.companyDocuments.filter( - (document) => document.status === "NOT_REVIEWED" - ); - return notReviewedDocuments.length; - } - return; - }; - const handleCancelRejection = async () => { try { setIsLoading(true); @@ -246,7 +236,6 @@ function ClinicDetails() { setButtonClickStatus("Rejected"); }; - const handleAcceptClick = () => { // setIsShowReasonModel(true); setButtonClickStatus("Accepted"); @@ -258,19 +247,17 @@ function ClinicDetails() { // ..................update file use effects................ useEffect(() => { // Check if any document is not verified or is null/undefined - const hasUnverifiedDocuments = + const hasUnverifiedDocuments = clinicFiles?.abn_doc_is_verified !== true || - clinicFiles?.contract_doc_is_verified !== true || - clinicFiles?.logo_is_verified !== true; - + clinicFiles?.contract_doc_is_verified !== true; + // Set button visibility based on document verification status setIsRejectedButtonShow(hasUnverifiedDocuments); setIsOnHoldButtonShow(hasUnverifiedDocuments); const areAllFilesApproved = clinicFiles?.abn_doc_is_verified === true && - clinicFiles?.contract_doc_is_verified === true && - clinicFiles?.logo_is_verified === true; + clinicFiles?.contract_doc_is_verified === true; if ( areAllFilesApproved && @@ -279,6 +266,12 @@ function ClinicDetails() { ) { setIsAcceptedButtonShow(true); } else { + if(clinicData?.status === CLINIC_STATUS.PAYMENT_DUE){ + pushNotification( + "Accept button is disabled due to Payment Due status", + NOTIFICATION.WARNING + ); + } setIsAcceptedButtonShow(false); } }, [clinicFiles, updateFiles]); @@ -456,8 +449,8 @@ function ClinicDetails() { contract_doc: clinicData?.contract_doc, contract_doc_is_verified: clinicFiles?.contract_doc_is_verified, - logo_doc: clinicData?.logo, - logo_is_verified: clinicFiles?.logo_is_verified, + // logo_doc: clinicData?.logo, + // logo_is_verified: clinicFiles?.logo_is_verified, }, ] } diff --git a/src/views/ClinicDocUpdate/index.jsx b/src/views/ClinicDocUpdate/index.jsx index b5be296..c6428bc 100644 --- a/src/views/ClinicDocUpdate/index.jsx +++ b/src/views/ClinicDocUpdate/index.jsx @@ -7,7 +7,7 @@ import * as Yup from "yup"; import { MAX_FILE_SIZE_IN_MB, MAX_FILES } from "../../constants"; import { getClinicDocs, - updateClinicDocs, + updateClinic, } from "../../services/clinics.service"; import { useNavigate } from "react-router-dom"; import { useSelector } from "react-redux"; @@ -93,7 +93,7 @@ const ClinicDocUpdater = () => { // Only proceed if there are files to update if (Object.keys(payload).length > 0) { - const resp = await updateClinicDocs(formik.values.clinicId, payload); + const resp = await updateClinic(formik.values.clinicId, payload); console.log(resp); } diff --git a/src/views/ClinicSetup/clinicSetupStyles.js b/src/views/ClinicSetup/clinicSetupStyles.js new file mode 100644 index 0000000..af3349d --- /dev/null +++ b/src/views/ClinicSetup/clinicSetupStyles.js @@ -0,0 +1,325 @@ +import makeStyles from '@mui/styles/makeStyles'; +import { pxToRem } from '../../theme/typography'; + +export const useStyles = makeStyles((theme) => ({ + appBarStyle: { + backgroundColor: theme.palette.grey[28], + }, + contentBox: { + marginTop: '3%', + }, + mainContent: { + marginTop: theme.spacing(4), + marginBottom: theme.spacing(4), + marginLeft: theme.spacing(4), + marginRight: theme.spacing(4), + width: '100%', + overflowX: 'scroll', + '&::-webkit-scrollbar': { + height: '6px', + }, + }, + logoBox: { + display: 'flex', + width: '100%', + marginLeft: '1%', + [theme.breakpoints.down('md')]: { + width: 'auto', + }, + }, + logo: { + maxHeight: '61px', + objectFit: 'contain', + justifyContent: 'center', + }, + whitePaper: { + width: '100%', + marginBottom: theme.spacing(0.3), + paddingBottom: theme.spacing(0.7), + borderRadius: `${theme.spacing(2)} ${theme.spacing(2)} ${theme.spacing( + 1 + )} ${theme.spacing(1)}`, + }, + inputLabel: { + marginBottom: theme.spacing(0.5), + fontSize: pxToRem(12), + color: theme.palette.grey[10], + }, + textAreaLast: { + width: '-webkit-fill-available', + '&.MuiButtonBase-root': { + padding: theme.spacing(0.8), + }, + }, + helperText: { + color: theme.palette.error.main, + fontStyle: 'italic', + }, + formRoot: { + paddingTop: theme.spacing(3.2), + }, + formPassswordHeading: { + fontSize: pxToRem(14), + fontWeight: '600', + }, + passwordTextFiled: { + marginTop: theme.spacing(0), + }, + icon: { + cursor: 'pointer', + paddingLeft: theme.spacing(3), + display: 'flex', + alignItems: 'center', + width: '50px', + [theme.breakpoints.up('md')]: { + width: '50px', + }, + [theme.breakpoints.up('lg')]: { + width: '50px', + }, + [theme.breakpoints.up('xl')]: { + width: '50px', + }, + }, + formPasswordHeadingRoot: { + paddingTop: theme.spacing(2), + paddingLeft: theme.spacing(2), + width: '100%', + }, + subjectText: { + fontSize: pxToRem(12), + position: 'absolute', + right: pxToRem(8), + top: '90%', + transform: 'translateY(-90%)', + }, + // --- AddForm Style --- + screenViewGridItem: { + marginTop: theme.spacing(1), + }, + paperContainerBox: { + width: '100%', + }, + countryCodeBox: { + padding: pxToRem(12), + paddingRight: pxToRem(20), + paddingLeft: pxToRem(16), + borderRadius: pxToRem(10), + backgroundColor: theme.palette.grey[20], + }, + countryCodeLabel: { + marginBottom: theme.spacing(0), + opacity: 1, + fontFamily: 'Inter-Regular', + }, + mobileNumberInput: { + fontFamily: 'Inter-Regular', + '& .MuiInputBase-root': { + paddingLeft: theme.spacing(0), + border: 0, + }, + '& .MuiOutlinedInput-input': { + paddingLeft: theme.spacing(0), + }, + }, + passwordCheckListTitle: { + color: theme.palette.grey[20], + fontSize: pxToRem(12), + fontStyle: 'italic', + textAlign: 'left', + marginBottom: theme.spacing(0.4), + }, + emailNote: { + color: theme.palette.grey[20], + fontSize: pxToRem(14), + fontStyle: 'italic', + textAlign: 'left', + marginBottom: theme.spacing(0.4), + }, + passwordCheckList: { + fontSize: pxToRem(14), + paddingTop: theme.spacing(0.2), + fontStyle: 'italic', + color: theme.palette.grey[600], + }, + stateTextField: { + '& .Mui-disabled': { + WebkitTextFillColor: theme.palette.grey[10], // Change to the appropriate color value + opacity: 1, + }, + }, + termsAndConditionErrorMessage: { + color: theme.palette.error.main, + fontStyle: 'italic', + fontSize: pxToRem(12), + marginTop: theme.spacing(0.5), + }, + checkBox: { + marginTop: theme.spacing(3), + paddingRight: theme.spacing(1), + }, + checkBoxLabel: { + marginTop: theme.spacing(3.2), + marginLeft: theme.spacing(1.2), + fontSize: pxToRem(16), + color: theme.palette.common.black, + }, + linkText: { + color: theme.palette.grey[53], + }, + placeholderText: { + fontStyle: 'italic', + fontSize: pxToRem(14), + opacity: 0.5, + color: theme.palette.grey[10], + }, + // logo style + reactCrop: { + /* Set a minimum height and width */ + minHeight: '200px', + minWidth: '200px', + }, + dropZoneOuterBox: { + width: '100%', + }, + inputTitle: { + '&.MuiTypography-body1': { + fontSize: pxToRem(12), + color: theme.palette.grey[10], + }, + marginBottom: theme.spacing(0.6), + marginLeft: theme.spacing(0.6), + color: theme.palette.grey[10], + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + }, + imgButton: { + color: theme?.palette?.primary?.main, + fontSize: pxToRem(12), + fontWeight: 600, + fontFamily: theme?.fontFamily?.Regular, + backgroundColor: 'transparent', + border: 'none', + cursor: 'pointer', + margin: `${theme.spacing(0)} ${theme.spacing(0.8)}`, + padding: theme.spacing(0), + outline: 'none', + }, + logoUploadErrorBox: { + display: 'flex', + justifyContent: 'space-between', + }, + errorText: { + color: theme.palette.error.main, + fontSize: pxToRem(12), + fontStyle: 'italic', + }, + addButton: { + border: `1px dashed ${theme.palette.primary.main}`, + width: '100%', + height: '130px', + backgroundColor: theme.palette.common.white, + borderRadius: theme.spacing(1), + marginBottom: theme.spacing(1.48), + }, + addButtonContent: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + flexDirection: 'column', + height: '100%', + cursor: 'pointer', + width: '100%', + }, + addText: { + opacity: 1, + fontFamily: theme?.fontFamily?.medium, + fontSize: pxToRem(14), + height: '16px', + fontWeight: 500, + lineHeight: 'normal', + letterSpacing: 'normal', + marginTop: theme?.spacing(1), + }, + addIcon: { + width: '26px', + height: '24px', + }, + addSubtext: { + fontSize: pxToRem(12), + color: theme.palette.grey[10], + opacity: '0.6', + textAlign: 'center', + padding: `${theme.spacing(0.5)} ${theme.spacing(7)}`, + [theme.breakpoints.down('md')]: { + padding: theme.spacing(1), + }, + [theme.breakpoints.down('lg')]: { + padding: theme.spacing(1), + }, + }, + previewBox: { + display: 'flex', + justifyContent: 'end', + alignItems: 'start', + width: '153px', + height: '111px', + borderRadius: theme.spacing(0.4), + backgroundSize: 'cover', + }, + formSectionHeadingMargin: { + marginTop: theme.spacing(1.5), + }, + + termsAndConditionDrawer: { + '& .MuiDrawer-paper': { + maxWidth: pxToRem(550), + boxShadow: '-10px 0px 10px -2px rgba(0,0,0,0.1)', + }, + [theme.breakpoints.down('md')]: { + width: '100%', + }, + }, + verifyIcon: { + fontSize: pxToRem(20), + color: theme.palette.grey[54], + }, + chipOuter: { + display: 'flex', + flexWrap: 'wrap', + paddingLeft: theme.spacing(3.2), + }, + chip: { + minWidth: '170px', + height: '42px', + padding: theme.spacing(1.5), + margin: theme.spacing(1), + marginRight: theme.spacing(1.5), + justifyContent: 'space-between', + borderRadius: '24px', + fontSize: pxToRem(14), + }, + billingUserOuterSection: { + marginTop: theme.spacing(3.0), + }, + billingUserEmailSection: { + padding: `${theme.spacing(2.2)} ${theme.spacing(3.2)}`, + }, + saveUserButton: { + marginLeft: theme.spacing(1.0), + width: '150px', + display: 'flex', + justifyContent: 'space-evenly', + borderRadius: '8px', + height: '47px', + // opacity: 0.5, + }, + billingUserEmailWrapper: { + display: 'flex', + [theme.breakpoints.down('md')]: { + flexDirection: 'column', + gap: '15px', + }, + }, +})); diff --git a/src/views/ClinicSetup/index.jsx b/src/views/ClinicSetup/index.jsx index 57cd987..57becea 100644 --- a/src/views/ClinicSetup/index.jsx +++ b/src/views/ClinicSetup/index.jsx @@ -13,6 +13,7 @@ import { DialogContent, DialogContentText, DialogTitle, + InputAdornment, MenuItem, Paper, Select, @@ -26,10 +27,24 @@ import WarningAmberIcon from "@mui/icons-material/WarningAmber"; import { CLINIC_GREETINGS_LENGTH, CLINIC_SCENARIOS_LENGTH, + NOTIFICATION, } from "../../constants"; +import { useSelector } from "react-redux"; +import { getClinicsById, updateClinic } from "../../services/clinics.service"; +import { useStyles } from "./clinicSetupStyles"; +import { useNavigate } from "react-router-dom"; // Integration software options -const integrationOptions = ["BP Software", "Medical Director"]; +const integrationOptions = [ + { + id: "bp", + name: "BP Software", + }, + { + id: "medicaldirector", + name: "Medical Director", + }, +]; // Steps for the stepper const steps = [ @@ -55,12 +70,24 @@ const voiceModelGender = [ ]; export default function ClinicSetup() { + const classes = useStyles(); + // Active step state const [activeStep, setActiveStep] = React.useState(0); const [openDialog, setOpenDialog] = React.useState(false); const [audioContext, setAudioContext] = React.useState(null); - const [testConnDone, setTestConnDone] = React.useState(false); - const [confirmPhoneNumber, setConfirmPhoneNumber] = React.useState(false); + const [testConnDone, setTestConnDone] = React.useState(true); + const [confirmPhoneNumber, setConfirmPhoneNumber] = React.useState(true); + const [audioListenDone, setAudioListenDone] = React.useState(true); + const navigate = useNavigate(); + + const user = useSelector((state) => state.login.user); + const clinic = user?.created_clinics[0]; + + if (!clinic) { + pushNotification("Clinic not found!", NOTIFICATION.ERROR); + return; + } // Completed steps state const [completed, setCompleted] = React.useState({}); @@ -68,7 +95,9 @@ export default function ClinicSetup() { // Form state const [formData, setFormData] = React.useState({ // General Information - clinicPhone: "159875654", + clinicId: clinic?.id, + clinicPhone: "", + clinicPonePrefix: "+61", clinicAddress: "1 Wilkinson Road, Para Hills SA 5096", otherInfo: "", @@ -153,8 +182,73 @@ If No -Pt who do not have a Medicare card / Private patients with or without I // Voice Configuration voice: "", voiceGender: voiceModelGender[1].id, + voice_model_provider: "rime", }); + const [prevFormData, setPrevFormData] = React.useState({ + ...formData, + }); + + const mobilePrefixOptions = [ + { id: "61", name: "+61" }, + { id: "91", name: "+91" }, + ]; + + const parsePhoneNumber = (phoneString) => { + // Split by space + const parts = phoneString.split(" "); + + if (parts.length !== 2) { + return { + countryCode: null, + number: null, + error: "Phone number must contain exactly one space", + }; + } + + const countryCode = parts[0].replace("+", ""); // Everything before space (includes +) + const number = parts[1]; // Everything after space + + return { + countryCode, + number, + }; + }; + + const getClinic = async () => { + const resp = await getClinicsById(clinic.id); + + if (resp?.data?.error) { + pushNotification(resp?.data?.message, NOTIFICATION.ERROR); + return; + } + const clinicResp = resp?.data?.data?.clinic; + const { countryCode, number } = parsePhoneNumber(clinicResp?.phone); + setFormData({ + ...formData, + clinicPhone: number, + clinicPonePrefix: countryCode, + clinicAddress: clinicResp?.address, + clinicOthers: clinicResp?.general_info, + otherInfo: clinicResp?.other_info ?? formData.otherInfo, + clinicGreetings: clinicResp?.greeting_msg ?? formData.clinicGreetings, + clinicScenarios: clinicResp?.scenarios ?? formData.clinicScenarios, + integrationSoftware: clinicResp?.integration, + practiceId: clinicResp?.pms_id, + practiceName: clinicResp?.practice_name, + voice: clinicResp?.voice_model ?? formData.voice, + voiceGender: clinicResp?.voice_model_gender ?? formData.voiceGender, + voice_model_provider: clinicResp?.voice_model_provider, + }); + setPrevFormData({ + ...formData, + }); + }; + + React.useEffect(() => { + getClinic(); + }, []); + // Handle form reset const handleReset = () => { setActiveStep(0); @@ -172,12 +266,6 @@ If No -Pt who do not have a Medicare card / Private patients with or without I setConfirmPhoneNumber(true); }; - React.useEffect(() => { - if(formData.clinicPhone=="159875654"){ - setConfirmPhoneNumber(true); - } - }, []); - React.useEffect(() => { // Initialize audio context when component mounts function initAudioContext() { @@ -224,11 +312,31 @@ If No -Pt who do not have a Medicare card / Private patients with or without I // Handle next button click const handleNext = () => { + if ( + prevFormData.clinicPhone !== formData.clinicPhone && + !confirmPhoneNumber + ) { + pushNotification("Please confirm phone number", "error"); + return; + } + if (!confirmPhoneNumber) { pushNotification("Please confirm phone number", "error"); return; } + if (activeStep == 1) { + if ( + !audioListenDone + ) { + pushNotification( + "Please listen to the audio before proceeding", + "error" + ); + return; + } + } + const newActiveStep = isLastStep() && !allStepsCompleted() ? // It's the last step, but not all steps have been completed, @@ -293,6 +401,9 @@ If No -Pt who do not have a Medicare card / Private patients with or without I } ); }) + .then(() => { + setAudioListenDone(true); + }) .catch((err) => { pushNotification(`Error: ${err.message}`, "error"); }); @@ -330,6 +441,17 @@ If No -Pt who do not have a Medicare card / Private patients with or without I return; } + // if voice model or voice gender is changed then must listen first + if (activeStep == 1) { + if (!audioListenDone) { + pushNotification( + "Please listen to the audio before proceeding", + "error" + ); + return; + } + } + // Then check if the step is completed if (completed[step]) { setActiveStep(step); @@ -396,6 +518,12 @@ If No -Pt who do not have a Medicare card / Private patients with or without I // Handle complete step const handleComplete = () => { + + if( activeStep == 4 && !testConnDone){ + pushNotification("Please test connection before proceeding", NOTIFICATION.ERROR); + return; + } + if (true) { const newCompleted = { ...completed }; newCompleted[activeStep] = true; @@ -415,6 +543,14 @@ If No -Pt who do not have a Medicare card / Private patients with or without I setConfirmPhoneNumber(false); } + if (name === "voice" || name === "voiceGender") { + setAudioListenDone(false); + } + + if (name === "integrationSoftware" || name === "practiceId" || name === "practiceName") { + setTestConnDone(false); + } + setFormData((prev) => ({ ...prev, [name]: value, @@ -461,45 +597,40 @@ If No -Pt who do not have a Medicare card / Private patients with or without I }; // Handle form submission - const handleSubmit = (e) => { + const handleSubmit = async (e) => { e.preventDefault(); - + const payload = { + clinicId: formData.clinicId, + phone: `${formData.clinicPonePrefix} ${formData.clinicPhone}`, + address: formData.clinicAddress, + other_info: formData.otherInfo, + general_info: formData.clinicOthers, + greeting_msg: formData.clinicGreetings, + scenarios: formData.clinicScenarios, + integration: formData.integrationSoftware, + pms_id: formData.practiceId, + practice_name: formData.practiceName, + voice_model: formData.voice, + voice_model_gender: formData.voiceGender, + voice_model_provider:"rime" + }; if (validateForm()) { - console.log("Form submitted:", formData); + const resp = await updateClinic(formData.clinicId, payload); + if(resp?.data?.error){ + pushNotification(resp?.data?.message, NOTIFICATION.ERROR); + return; + } // Here you would typically send the data to your backend pushNotification("Clinic setup updated successfully", "success"); - // Reset the form after submission - handleReset(); - } else { - // Find the first step with errors and go to it - if ( - formData.clinicPhone.trim() === "" || - formData.clinicAddress.trim() === "" - ) { - setActiveStep(0); - setErrors({ - ...errors, - clinicPhone: formData.clinicPhone.trim() === "", - clinicAddress: formData.clinicAddress.trim() === "", - }); - } else if ( - formData.integrationSoftware && - (formData.practiceId.trim() === "" || - formData.practiceName.trim() === "") - ) { - setActiveStep(3); - setErrors({ - ...errors, - practiceId: formData.practiceId.trim() === "", - practiceName: formData.practiceName.trim() === "", - }); - } - - // Show an alert - pushNotification( - "Please fill in all required fields before submitting", - NOTIFICATION_TYPE.ERROR - ); + // Reset the form state manually + setActiveStep(0); + setCompleted({}); + setConfirmPhoneNumber(true); + setTestConnDone(true); + setAudioListenDone(true); + + // Refetch the clinic data to get the latest state + await getClinic(); } }; @@ -514,18 +645,22 @@ If No -Pt who do not have a Medicare card / Private patients with or without I xs={12} md={10} alignItems="baseline" - // justifyContent="center" - // alignContent="center" flexDirection="row" display="flex" > { + if (e.target.value.length <= 10) { + const value = e.target.value?.match(/\d+/g) || ""; + handleChange(e); + } + }} helperText={ errors.clinicPhone ? "Phone number is required" @@ -533,6 +668,37 @@ If No -Pt who do not have a Medicare card / Private patients with or without I } variant="outlined" error={errors.clinicPhone} + InputProps={{ + startAdornment: ( + + + + + + ), + }} /> */} - + @@ -923,7 +1089,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I )} {activeStep != 4 && (