feat: clinic admin setup
This commit is contained in:
parent
4717c67cca
commit
050cf206f5
|
|
@ -77,13 +77,19 @@ const CustomFileUpload = forwardRef(function CustomFileUpload(
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const makeFullUrlIfNeeded = (url) => {
|
const makeFullUrlIfNeeded = (url) => {
|
||||||
|
// Return early if url is undefined or empty
|
||||||
|
if (!url) {
|
||||||
|
setOldUploadedFileUrl('');
|
||||||
|
setFileExtension('');
|
||||||
|
setImageName('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isHttp = url.startsWith('http://') || url.startsWith('https://');
|
const isHttp = url.startsWith('http://') || url.startsWith('https://');
|
||||||
if (!isHttp) {
|
if (!isHttp) {
|
||||||
setOldUploadedFileUrl(url ? `${IMAGE_LOCATION_BASE_URL}${url}` : '');
|
setOldUploadedFileUrl(`${IMAGE_LOCATION_BASE_URL}${url}`);
|
||||||
setFileExtension(
|
setFileExtension(url.split('.').pop() || '');
|
||||||
uploadedFileUrl ? uploadedFileUrl.split('.').pop() : ''
|
setImageName(url.split('/').pop() || '');
|
||||||
);
|
|
||||||
setImageName(uploadedFileUrl ? uploadedFileUrl.split('/').pop() : '');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const urlObject = new URL(url);
|
const urlObject = new URL(url);
|
||||||
|
|
|
||||||
|
|
@ -382,30 +382,30 @@ const Table = memo(
|
||||||
muiSelectAllCheckboxProps={{
|
muiSelectAllCheckboxProps={{
|
||||||
className: classes?.tableCheckbox,
|
className: classes?.tableCheckbox,
|
||||||
}}
|
}}
|
||||||
// renderRowActionMenuItems={({ row, closeMenu }) =>
|
renderRowActionMenuItems={({ row, closeMenu }) =>
|
||||||
// actions?.filter(action => !action.render)?.map((action, index) =>
|
actions?.filter(action => !action.render)?.map((action, index) =>
|
||||||
// !(action?.renderAction?.(row) ?? true) ? null : (
|
!(action?.renderAction?.(row) ?? true) ? null : (
|
||||||
// <MenuItem
|
<MenuItem
|
||||||
// key={index}
|
key={index}
|
||||||
// className={classes.menuItem}
|
className={classes.menuItem}
|
||||||
// onClick={(event) => {
|
onClick={(event) => {
|
||||||
// event.stopPropagation();
|
event.stopPropagation();
|
||||||
// action.onClick && action.onClick(row);
|
action.onClick && action.onClick(row);
|
||||||
// closeMenu();
|
closeMenu();
|
||||||
// }}
|
}}
|
||||||
// disabled={
|
disabled={
|
||||||
// action?.isDisabledValue
|
action?.isDisabledValue
|
||||||
// ? action?.isDisabledValue ===
|
? action?.isDisabledValue ===
|
||||||
// row?.original?.[action?.rowKey]
|
row?.original?.[action?.rowKey]
|
||||||
// : false
|
: false
|
||||||
// }
|
}
|
||||||
// >
|
>
|
||||||
// {action?.icon} {action?.text}{" "}
|
{action?.icon} {action?.text}{" "}
|
||||||
// {action.textFn && action.textFn(row)}
|
{action.textFn && action.textFn(row)}
|
||||||
// </MenuItem>
|
</MenuItem>
|
||||||
// )
|
)
|
||||||
// ) ?? []
|
) ?? []
|
||||||
// }
|
}
|
||||||
renderTopToolbarCustomActions={({ table }) => {
|
renderTopToolbarCustomActions={({ table }) => {
|
||||||
const handleActive = () => {
|
const handleActive = () => {
|
||||||
const data = table
|
const data = table
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,10 @@ export const NOT_ALLOWED_BLANK_SPACE_REGEX = /^(?! +$)[\s\S]+$/;
|
||||||
|
|
||||||
export const HEX_COLOR_CODE_REGEX = /^#([A-Fa-f0-9]{6})$/;
|
export const HEX_COLOR_CODE_REGEX = /^#([A-Fa-f0-9]{6})$/;
|
||||||
|
|
||||||
|
export const CLINIC_GREETINGS_LENGTH = 1000;
|
||||||
|
|
||||||
|
export const CLINIC_SCENARIOS_LENGTH = 5000;
|
||||||
|
|
||||||
export const FILE_TYPE = [
|
export const FILE_TYPE = [
|
||||||
'.jpeg',
|
'.jpeg',
|
||||||
'.jpg',
|
'.jpg',
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ export const userDataMock = {
|
||||||
name: "test",
|
name: "test",
|
||||||
email: "test@gmail.com",
|
email: "test@gmail.com",
|
||||||
userType: "Manager",
|
userType: "Manager",
|
||||||
|
appointmentTypes: ["Adult Immunisation", "Child Immunisation"],
|
||||||
specialities: "Doctor",
|
specialities: "Doctor",
|
||||||
createdAt: "2025-01-01",
|
createdAt: "2025-01-01",
|
||||||
status: "Active",
|
status: "Active",
|
||||||
|
|
@ -15,6 +16,7 @@ export const userDataMock = {
|
||||||
name: "John Doe",
|
name: "John Doe",
|
||||||
email: "johndoe@example.com",
|
email: "johndoe@example.com",
|
||||||
userType: "Employee",
|
userType: "Employee",
|
||||||
|
appointmentTypes: ["Adult Immunisation"],
|
||||||
specialities: "Engineer",
|
specialities: "Engineer",
|
||||||
createdAt: "2024-11-15",
|
createdAt: "2024-11-15",
|
||||||
status: "Inactive",
|
status: "Inactive",
|
||||||
|
|
@ -24,6 +26,7 @@ export const userDataMock = {
|
||||||
name: "Jane Smith",
|
name: "Jane Smith",
|
||||||
email: "janesmith@example.com",
|
email: "janesmith@example.com",
|
||||||
userType: "Admin",
|
userType: "Admin",
|
||||||
|
appointmentTypes: ["Adult Immunisation"],
|
||||||
specialities: "Manager",
|
specialities: "Manager",
|
||||||
createdAt: "2024-12-01",
|
createdAt: "2024-12-01",
|
||||||
status: "Active",
|
status: "Active",
|
||||||
|
|
@ -32,6 +35,7 @@ export const userDataMock = {
|
||||||
id: 4,
|
id: 4,
|
||||||
name: "Alice Brown",
|
name: "Alice Brown",
|
||||||
email: "alicebrown@example.com",
|
email: "alicebrown@example.com",
|
||||||
|
appointmentTypes: ["Adult Immunisation"],
|
||||||
userType: "Manager",
|
userType: "Manager",
|
||||||
specialities: "HR",
|
specialities: "HR",
|
||||||
createdAt: "2023-06-22",
|
createdAt: "2023-06-22",
|
||||||
|
|
@ -51,6 +55,7 @@ export const userDataMock = {
|
||||||
name: "Charlie Black",
|
name: "Charlie Black",
|
||||||
email: "charlieblack@example.com",
|
email: "charlieblack@example.com",
|
||||||
userType: "Admin",
|
userType: "Admin",
|
||||||
|
appointmentTypes: ["Adult Immunisation"],
|
||||||
specialities: "IT Support",
|
specialities: "IT Support",
|
||||||
createdAt: "2023-07-05",
|
createdAt: "2023-07-05",
|
||||||
status: "Inactive",
|
status: "Inactive",
|
||||||
|
|
@ -60,6 +65,7 @@ export const userDataMock = {
|
||||||
name: "Eve White",
|
name: "Eve White",
|
||||||
email: "evewhite@example.com",
|
email: "evewhite@example.com",
|
||||||
userType: "Manager",
|
userType: "Manager",
|
||||||
|
appointmentTypes: ["Adult Immunisation"],
|
||||||
specialities: "Finance",
|
specialities: "Finance",
|
||||||
createdAt: "2025-03-30",
|
createdAt: "2025-03-30",
|
||||||
status: "Active",
|
status: "Active",
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,20 @@ export const getUsers = (params) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserById = (id) => {
|
export const getUserById = (id) => {
|
||||||
const url = `/users/${id}`;
|
const data = userDataMock;
|
||||||
return new Promise((resolve, reject) => {
|
return data.data.records.find((item) => item.id === id)
|
||||||
axiosInstance
|
|
||||||
.get(url)
|
|
||||||
.then((response) => resolve(response))
|
|
||||||
.catch((err) => reject(err));
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// export const getUserById = (id) => {
|
||||||
|
// const url = `/users/${id}`;
|
||||||
|
// return new Promise((resolve, reject) => {
|
||||||
|
// axiosInstance
|
||||||
|
// .get(url)
|
||||||
|
// .then((response) => resolve(response))
|
||||||
|
// .catch((err) => reject(err));
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
export const getRoles = ({ page }) =>
|
export const getRoles = ({ page }) =>
|
||||||
page == 0
|
page == 0
|
||||||
? {
|
? {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import SendIcon from '@mui/icons-material/Send';
|
import SendIcon from "@mui/icons-material/Send";
|
||||||
import Box from '@mui/material/Box';
|
import Box from "@mui/material/Box";
|
||||||
import Button from '@mui/material/Button';
|
import Button from "@mui/material/Button";
|
||||||
import FormControl from '@mui/material/FormControl';
|
import FormControl from "@mui/material/FormControl";
|
||||||
import Grid from '@mui/material/Grid';
|
import Grid from "@mui/material/Grid";
|
||||||
import InputLabel from '@mui/material/InputLabel';
|
import InputLabel from "@mui/material/InputLabel";
|
||||||
import * as React from 'react';
|
import * as React from "react";
|
||||||
import { pushNotification } from '../../utils/notification';
|
import { pushNotification } from "../../utils/notification";
|
||||||
import { NOTIFICATION_TYPE } from '../Notifications/notificationConstant';
|
import { NOTIFICATION_TYPE } from "../Notifications/notificationConstant";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogActions,
|
DialogActions,
|
||||||
|
|
@ -21,33 +21,37 @@ import {
|
||||||
Stepper,
|
Stepper,
|
||||||
TextField,
|
TextField,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from "@mui/material";
|
||||||
import WarningAmberIcon from '@mui/icons-material/WarningAmber';
|
import WarningAmberIcon from "@mui/icons-material/WarningAmber";
|
||||||
|
import {
|
||||||
|
CLINIC_GREETINGS_LENGTH,
|
||||||
|
CLINIC_SCENARIOS_LENGTH,
|
||||||
|
} from "../../constants";
|
||||||
|
|
||||||
// Integration software options
|
// Integration software options
|
||||||
const integrationOptions = ['BP Software', 'Medical Director'];
|
const integrationOptions = ["BP Software", "Medical Director"];
|
||||||
|
|
||||||
// Steps for the stepper
|
// Steps for the stepper
|
||||||
const steps = [
|
const steps = [
|
||||||
'General Information',
|
"General Information",
|
||||||
'AI Receptionist Setup',
|
"AI Receptionist Setup",
|
||||||
'Scenarios Setup',
|
"Scenarios Setup",
|
||||||
'General Info Setup',
|
"General Info Setup",
|
||||||
'Integration Settings',
|
"Integration Settings",
|
||||||
];
|
];
|
||||||
|
|
||||||
const voiceModels = [
|
const voiceModels = [
|
||||||
{ id: 'stream', name: 'Stream', gender: 'female' },
|
{ id: "stream", name: "Stream", gender: "female" },
|
||||||
{ id: 'sandy', name: 'Sandy', gender: 'female' },
|
{ id: "sandy", name: "Sandy", gender: "female" },
|
||||||
{ id: 'breeze', name: 'Breeze', gender: 'female' },
|
{ id: "breeze", name: "Breeze", gender: "female" },
|
||||||
{ id: 'wolf', name: 'Wolf', gender: 'male' },
|
{ id: "wolf", name: "Wolf", gender: "male" },
|
||||||
{ id: 'stan', name: 'Sten', gender: 'male' },
|
{ id: "stan", name: "Sten", gender: "male" },
|
||||||
{ id: 'blaze', name: 'Blaze', gender: 'male' },
|
{ id: "blaze", name: "Blaze", gender: "male" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const voiceModelGender = [
|
const voiceModelGender = [
|
||||||
{ id: 'male', name: 'Male' },
|
{ id: "male", name: "Male" },
|
||||||
{ id: 'female', name: 'Female' },
|
{ id: "female", name: "Female" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function ClinicSetup() {
|
export default function ClinicSetup() {
|
||||||
|
|
@ -56,6 +60,7 @@ export default function ClinicSetup() {
|
||||||
const [openDialog, setOpenDialog] = React.useState(false);
|
const [openDialog, setOpenDialog] = React.useState(false);
|
||||||
const [audioContext, setAudioContext] = React.useState(null);
|
const [audioContext, setAudioContext] = React.useState(null);
|
||||||
const [testConnDone, setTestConnDone] = React.useState(false);
|
const [testConnDone, setTestConnDone] = React.useState(false);
|
||||||
|
const [confirmPhoneNumber, setConfirmPhoneNumber] = React.useState(false);
|
||||||
|
|
||||||
// Completed steps state
|
// Completed steps state
|
||||||
const [completed, setCompleted] = React.useState({});
|
const [completed, setCompleted] = React.useState({});
|
||||||
|
|
@ -63,13 +68,13 @@ export default function ClinicSetup() {
|
||||||
// Form state
|
// Form state
|
||||||
const [formData, setFormData] = React.useState({
|
const [formData, setFormData] = React.useState({
|
||||||
// General Information
|
// General Information
|
||||||
clinicPhone: '159875654',
|
clinicPhone: "159875654",
|
||||||
clinicAddress: '1 Wilkinson Road, Para Hills SA 5096',
|
clinicAddress: "1 Wilkinson Road, Para Hills SA 5096",
|
||||||
otherInfo: '',
|
otherInfo: "",
|
||||||
|
|
||||||
// Greetings Setup
|
// Greetings Setup
|
||||||
clinicGreetings:
|
clinicGreetings:
|
||||||
'Welcome to 365 days medical center group, para hills clinic. We are here to help you.',
|
"Welcome to 365 days medical center group, para hills clinic. We are here to help you.",
|
||||||
clinicScenarios: `Booking for care plan /Care plan Review
|
clinicScenarios: `Booking for care plan /Care plan Review
|
||||||
Existing patients- Book with regular GP and Nurse on same day ( if not possible book different day, F2F with nurse for care plan and another days F2F consultation with Dr to sign of care plan )
|
Existing patients- Book with regular GP and Nurse on same day ( if not possible book different day, F2F with nurse for care plan and another days F2F consultation with Dr to sign of care plan )
|
||||||
New patients- At the moment we are not taking New patients on long term care but tell them they can see GP and can discuss with GP before booking for care plan .
|
New patients- At the moment we are not taking New patients on long term care but tell them they can see GP and can discuss with GP before booking for care plan .
|
||||||
|
|
@ -141,12 +146,12 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
- Other pets must remain outside the building except for veterinary consultations (available Tuesdays and Thursdays)`,
|
- Other pets must remain outside the building except for veterinary consultations (available Tuesdays and Thursdays)`,
|
||||||
|
|
||||||
// Integration Settings
|
// Integration Settings
|
||||||
integrationSoftware: '',
|
integrationSoftware: "",
|
||||||
practiceId: '',
|
practiceId: "",
|
||||||
practiceName: '',
|
practiceName: "",
|
||||||
|
|
||||||
// Voice Configuration
|
// Voice Configuration
|
||||||
voice: '',
|
voice: "",
|
||||||
voiceGender: voiceModelGender[1].id,
|
voiceGender: voiceModelGender[1].id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -157,12 +162,22 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
// reset form data to initial state
|
// reset form data to initial state
|
||||||
setFormData(
|
setFormData(
|
||||||
Object.keys(formData).reduce((acc, key) => {
|
Object.keys(formData).reduce((acc, key) => {
|
||||||
acc[key] = '';
|
acc[key] = "";
|
||||||
return acc;
|
return acc;
|
||||||
}, {})
|
}, {})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleConfirmPhoneNumber = () => {
|
||||||
|
setConfirmPhoneNumber(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if(formData.clinicPhone=="159875654"){
|
||||||
|
setConfirmPhoneNumber(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
// Initialize audio context when component mounts
|
// Initialize audio context when component mounts
|
||||||
function initAudioContext() {
|
function initAudioContext() {
|
||||||
|
|
@ -172,8 +187,8 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
|
|
||||||
if (!window.AudioContext) {
|
if (!window.AudioContext) {
|
||||||
pushNotification(
|
pushNotification(
|
||||||
'Your browser does not support AudioContext and cannot play back audio.',
|
"Your browser does not support AudioContext and cannot play back audio.",
|
||||||
'error'
|
"error"
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -189,7 +204,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
|
|
||||||
// Cleanup function
|
// Cleanup function
|
||||||
return () => {
|
return () => {
|
||||||
if (context && context.state !== 'closed') {
|
if (context && context.state !== "closed") {
|
||||||
context.close();
|
context.close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -209,6 +224,11 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
|
|
||||||
// Handle next button click
|
// Handle next button click
|
||||||
const handleNext = () => {
|
const handleNext = () => {
|
||||||
|
if (!confirmPhoneNumber) {
|
||||||
|
pushNotification("Please confirm phone number", "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newActiveStep =
|
const newActiveStep =
|
||||||
isLastStep() && !allStepsCompleted()
|
isLastStep() && !allStepsCompleted()
|
||||||
? // It's the last step, but not all steps have been completed,
|
? // It's the last step, but not all steps have been completed,
|
||||||
|
|
@ -221,30 +241,30 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
// Listen to voice using rime.ai API
|
// Listen to voice using rime.ai API
|
||||||
const listenVoice = () => {
|
const listenVoice = () => {
|
||||||
if (!audioContext) {
|
if (!audioContext) {
|
||||||
pushNotification('Audio context not initialized', 'error');
|
pushNotification("Audio context not initialized", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!formData.clinicGreetings || formData.clinicGreetings.length === 0) {
|
if (!formData.clinicGreetings || formData.clinicGreetings.length === 0) {
|
||||||
pushNotification(
|
pushNotification(
|
||||||
'Please enter clinic greetings to listen preview',
|
"Please enter clinic greetings to listen preview",
|
||||||
'error'
|
"error"
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'audio/mp3',
|
Accept: "audio/mp3",
|
||||||
Authorization: 'Bearer ElD2r2Dn9Lsl5qB5TupaGcKlWSEf2llo9CkHi2OrOOU',
|
Authorization: "Bearer ElD2r2Dn9Lsl5qB5TupaGcKlWSEf2llo9CkHi2OrOOU",
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
speaker: formData.voice || 'wolf',
|
speaker: formData.voice || "wolf",
|
||||||
text: formData.clinicGreetings,
|
text: formData.clinicGreetings,
|
||||||
modelId: 'mist',
|
modelId: "mist",
|
||||||
lang: 'eng',
|
lang: "eng",
|
||||||
samplingRate: 22050,
|
samplingRate: 22050,
|
||||||
speedAlpha: 1.0,
|
speedAlpha: 1.0,
|
||||||
reduceLatency: false,
|
reduceLatency: false,
|
||||||
|
|
@ -252,9 +272,9 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
};
|
};
|
||||||
|
|
||||||
// Show loading state
|
// Show loading state
|
||||||
pushNotification('Generating audio...', 'info');
|
pushNotification("Generating audio...", "info");
|
||||||
|
|
||||||
fetch('https://users.rime.ai/v1/rime-tts', options)
|
fetch("https://users.rime.ai/v1/rime-tts", options)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
// Check if the response is successful
|
// Check if the response is successful
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
@ -269,12 +289,12 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
arrayBuffer,
|
arrayBuffer,
|
||||||
(buffer) => playAudioBuffer(buffer, audioContext),
|
(buffer) => playAudioBuffer(buffer, audioContext),
|
||||||
(error) => {
|
(error) => {
|
||||||
pushNotification('Failed to decode audio data', 'error');
|
pushNotification("Failed to decode audio data", "error");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
pushNotification(`Error: ${err.message}`, 'error');
|
pushNotification(`Error: ${err.message}`, "error");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -291,7 +311,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
source.start(0);
|
source.start(0);
|
||||||
|
|
||||||
// Notify user
|
// Notify user
|
||||||
pushNotification('Playing audio...', 'success');
|
pushNotification("Playing audio...", "success");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle back button click
|
// Handle back button click
|
||||||
|
|
@ -301,20 +321,24 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
|
|
||||||
// Handle step click
|
// Handle step click
|
||||||
const handleStep = (step) => () => {
|
const handleStep = (step) => () => {
|
||||||
// If trying to skip ahead with errors in current step, validate first
|
// First check if phone number is confirmed for any step navigation
|
||||||
if (step > activeStep) {
|
if (!confirmPhoneNumber) {
|
||||||
if (validateStep()) {
|
pushNotification(
|
||||||
setActiveStep(step);
|
"Please confirm phone number before navigating between steps",
|
||||||
} else {
|
"error"
|
||||||
// Alert user about validation errors
|
);
|
||||||
pushNotification(
|
return;
|
||||||
'Please complete the current step before proceeding',
|
}
|
||||||
NOTIFICATION_TYPE.ERROR
|
|
||||||
);
|
// Then check if the step is completed
|
||||||
}
|
if (completed[step]) {
|
||||||
} else {
|
|
||||||
// Allow going backward anytime
|
|
||||||
setActiveStep(step);
|
setActiveStep(step);
|
||||||
|
} else {
|
||||||
|
// Alert user about validation errors
|
||||||
|
pushNotification(
|
||||||
|
"Please complete the current step before proceeding",
|
||||||
|
"error"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -322,7 +346,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
const handleTestConnection = () => {
|
const handleTestConnection = () => {
|
||||||
// logic here
|
// logic here
|
||||||
setTestConnDone(true);
|
setTestConnDone(true);
|
||||||
pushNotification('Test connection successful', 'success');
|
pushNotification("Test connection successful", "success");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Form validation state
|
// Form validation state
|
||||||
|
|
@ -357,8 +381,8 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
// Validate only if software is selected
|
// Validate only if software is selected
|
||||||
if (formData.integrationSoftware) {
|
if (formData.integrationSoftware) {
|
||||||
const integrationErrors = {
|
const integrationErrors = {
|
||||||
practiceId: formData.practiceId.trim() === '',
|
practiceId: formData.practiceId.trim() === "",
|
||||||
practiceName: formData.practiceName.trim() === '',
|
practiceName: formData.practiceName.trim() === "",
|
||||||
};
|
};
|
||||||
setErrors(integrationErrors);
|
setErrors(integrationErrors);
|
||||||
return !Object.values(integrationErrors).some((isError) => isError);
|
return !Object.values(integrationErrors).some((isError) => isError);
|
||||||
|
|
@ -387,6 +411,10 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
|
|
||||||
|
if (name === "clinicPhone" && value != formData.clinicPhone) {
|
||||||
|
setConfirmPhoneNumber(false);
|
||||||
|
}
|
||||||
|
|
||||||
setFormData((prev) => ({
|
setFormData((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[name]: value,
|
[name]: value,
|
||||||
|
|
@ -419,14 +447,14 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
const validateForm = () => {
|
const validateForm = () => {
|
||||||
// Check all steps
|
// Check all steps
|
||||||
const generalInfoValid =
|
const generalInfoValid =
|
||||||
formData.clinicPhone.trim() !== '' &&
|
formData.clinicPhone.trim() !== "" &&
|
||||||
formData.clinicAddress.trim() !== '';
|
formData.clinicAddress.trim() !== "";
|
||||||
|
|
||||||
let integrationValid = true;
|
let integrationValid = true;
|
||||||
if (formData.integrationSoftware) {
|
if (formData.integrationSoftware) {
|
||||||
integrationValid =
|
integrationValid =
|
||||||
formData.practiceId.trim() !== '' &&
|
formData.practiceId.trim() !== "" &&
|
||||||
formData.practiceName.trim() !== '';
|
formData.practiceName.trim() !== "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return generalInfoValid && integrationValid;
|
return generalInfoValid && integrationValid;
|
||||||
|
|
@ -437,39 +465,39 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (validateForm()) {
|
if (validateForm()) {
|
||||||
console.log('Form submitted:', formData);
|
console.log("Form submitted:", formData);
|
||||||
// Here you would typically send the data to your backend
|
// Here you would typically send the data to your backend
|
||||||
pushNotification('Clinic setup updated successfully', 'success');
|
pushNotification("Clinic setup updated successfully", "success");
|
||||||
// Reset the form after submission
|
// Reset the form after submission
|
||||||
handleReset();
|
handleReset();
|
||||||
} else {
|
} else {
|
||||||
// Find the first step with errors and go to it
|
// Find the first step with errors and go to it
|
||||||
if (
|
if (
|
||||||
formData.clinicPhone.trim() === '' ||
|
formData.clinicPhone.trim() === "" ||
|
||||||
formData.clinicAddress.trim() === ''
|
formData.clinicAddress.trim() === ""
|
||||||
) {
|
) {
|
||||||
setActiveStep(0);
|
setActiveStep(0);
|
||||||
setErrors({
|
setErrors({
|
||||||
...errors,
|
...errors,
|
||||||
clinicPhone: formData.clinicPhone.trim() === '',
|
clinicPhone: formData.clinicPhone.trim() === "",
|
||||||
clinicAddress: formData.clinicAddress.trim() === '',
|
clinicAddress: formData.clinicAddress.trim() === "",
|
||||||
});
|
});
|
||||||
} else if (
|
} else if (
|
||||||
formData.integrationSoftware &&
|
formData.integrationSoftware &&
|
||||||
(formData.practiceId.trim() === '' ||
|
(formData.practiceId.trim() === "" ||
|
||||||
formData.practiceName.trim() === '')
|
formData.practiceName.trim() === "")
|
||||||
) {
|
) {
|
||||||
setActiveStep(3);
|
setActiveStep(3);
|
||||||
setErrors({
|
setErrors({
|
||||||
...errors,
|
...errors,
|
||||||
practiceId: formData.practiceId.trim() === '',
|
practiceId: formData.practiceId.trim() === "",
|
||||||
practiceName: formData.practiceName.trim() === '',
|
practiceName: formData.practiceName.trim() === "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show an alert
|
// Show an alert
|
||||||
pushNotification(
|
pushNotification(
|
||||||
'Please fill in all required fields before submitting',
|
"Please fill in all required fields before submitting",
|
||||||
NOTIFICATION_TYPE.ERROR
|
NOTIFICATION_TYPE.ERROR
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -492,32 +520,32 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
display="flex"
|
display="flex"
|
||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
style={{ width: '40%' }}
|
type="number"
|
||||||
|
style={{ width: "40%" }}
|
||||||
label="Clinic Phone Number"
|
label="Clinic Phone Number"
|
||||||
name="clinicPhone"
|
name="clinicPhone"
|
||||||
value={formData.clinicPhone}
|
value={formData.clinicPhone}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
helperText={
|
helperText={
|
||||||
errors.clinicPhone
|
errors.clinicPhone
|
||||||
? 'Phone number is required'
|
? "Phone number is required"
|
||||||
: 'Unique single number for your clinic'
|
: "Unique single number for your clinic"
|
||||||
}
|
}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
error={errors.clinicPhone}
|
error={errors.clinicPhone}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
style={{ marginLeft: '10px' }}
|
style={{ marginLeft: "10px" }}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
startIcon={<SendIcon />}
|
startIcon={<SendIcon />}
|
||||||
href="https://login.twilio.com/u/signup"
|
onClick={handleConfirmPhoneNumber}
|
||||||
target="_blank"
|
|
||||||
>
|
>
|
||||||
Configure Phone Number
|
Confirm
|
||||||
</Button>
|
</Button>
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
style={{ marginLeft: '10px' }}
|
style={{ marginLeft: "10px" }}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="error"
|
color="error"
|
||||||
startIcon={<WarningAmberIcon />}
|
startIcon={<WarningAmberIcon />}
|
||||||
|
|
@ -532,7 +560,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
aria-describedby="alert-dialog-description"
|
aria-describedby="alert-dialog-description"
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">
|
<DialogTitle id="alert-dialog-title">
|
||||||
{'Confirm Disable AI Receptionist'}
|
{"Confirm Disable AI Receptionist"}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText id="alert-dialog-description">
|
<DialogContentText id="alert-dialog-description">
|
||||||
|
|
@ -553,7 +581,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
pushNotification(
|
pushNotification(
|
||||||
'AI Receptionist disabled successfully',
|
"AI Receptionist disabled successfully",
|
||||||
NOTIFICATION_TYPE.SUCCESS
|
NOTIFICATION_TYPE.SUCCESS
|
||||||
);
|
);
|
||||||
setOpenDialog(false);
|
setOpenDialog(false);
|
||||||
|
|
@ -579,7 +607,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
error={errors.clinicAddress}
|
error={errors.clinicAddress}
|
||||||
helperText={
|
helperText={
|
||||||
errors.clinicAddress ? 'Clinic address is required' : ''
|
errors.clinicAddress ? "Clinic address is required" : ""
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -610,15 +638,15 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
multiline
|
multiline
|
||||||
rows={3}
|
rows={3}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
helperText={`${formData.clinicGreetings.length}/200 characters`}
|
helperText={`${formData.clinicGreetings.length}/${CLINIC_GREETINGS_LENGTH} characters`}
|
||||||
inputProps={{ maxLength: 200 }}
|
inputProps={{ maxLength: CLINIC_GREETINGS_LENGTH }}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
maxWidth: '40%',
|
maxWidth: "40%",
|
||||||
// marginTop: '10px',
|
// marginTop: '10px',
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -650,10 +678,10 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
value={
|
value={
|
||||||
formData.voice ||
|
formData.voice ||
|
||||||
(formData.voiceGender === 'male'
|
(formData.voiceGender === "male"
|
||||||
? voiceModels.find((model) => model.gender === 'male')
|
? voiceModels.find((model) => model.gender === "male")
|
||||||
.id
|
.id
|
||||||
: voiceModels.find((model) => model.gender === 'female')
|
: voiceModels.find((model) => model.gender === "female")
|
||||||
.id)
|
.id)
|
||||||
}
|
}
|
||||||
displayEmpty
|
displayEmpty
|
||||||
|
|
@ -677,7 +705,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TextField
|
<TextField
|
||||||
style={{ marginTop: '10px' }}
|
style={{ marginTop: "10px" }}
|
||||||
fullWidth
|
fullWidth
|
||||||
label="Scenarios"
|
label="Scenarios"
|
||||||
name="clinicScenarios"
|
name="clinicScenarios"
|
||||||
|
|
@ -685,9 +713,9 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
multiline
|
multiline
|
||||||
rows={8}
|
rows={8}
|
||||||
helperText={`${formData.clinicScenarios.length}/1500 characters`}
|
helperText={`${formData.clinicScenarios.length}/${CLINIC_SCENARIOS_LENGTH} characters`}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
inputProps={{ maxLength: 3000 }}
|
inputProps={{ maxLength: CLINIC_SCENARIOS_LENGTH }}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
@ -696,7 +724,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TextField
|
<TextField
|
||||||
style={{ marginTop: '10px' }}
|
style={{ marginTop: "10px" }}
|
||||||
fullWidth
|
fullWidth
|
||||||
label="General Info"
|
label="General Info"
|
||||||
name="clinicOthers"
|
name="clinicOthers"
|
||||||
|
|
@ -782,8 +810,8 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
error={!!formData.integrationSoftware && errors.practiceId}
|
error={!!formData.integrationSoftware && errors.practiceId}
|
||||||
helperText={
|
helperText={
|
||||||
!!formData.integrationSoftware && errors.practiceId
|
!!formData.integrationSoftware && errors.practiceId
|
||||||
? 'Practice ID is required'
|
? "Practice ID is required"
|
||||||
: ''
|
: ""
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -799,8 +827,8 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
error={!!formData.integrationSoftware && errors.practiceName}
|
error={!!formData.integrationSoftware && errors.practiceName}
|
||||||
helperText={
|
helperText={
|
||||||
!!formData.integrationSoftware && errors.practiceName
|
!!formData.integrationSoftware && errors.practiceName
|
||||||
? 'Practice Name is required'
|
? "Practice Name is required"
|
||||||
: ''
|
: ""
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -808,17 +836,17 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
);
|
);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 'Unknown step';
|
return "Unknown step";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box component="form" onSubmit={handleSubmit} sx={{ width: '100%' }}>
|
<Box component="form" onSubmit={handleSubmit} sx={{ width: "100%" }}>
|
||||||
<Paper elevation={0} sx={{ p: 2 }}>
|
<Paper elevation={0} sx={{ p: 2 }}>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h4"
|
variant="h4"
|
||||||
component="h1"
|
component="h1"
|
||||||
sx={{ fontWeight: 'bold', mb: 3 }}
|
sx={{ fontWeight: "bold", mb: 3 }}
|
||||||
>
|
>
|
||||||
Clinic Setup
|
Clinic Setup
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
@ -828,12 +856,21 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
{steps.map((label, index) => {
|
{steps.map((label, index) => {
|
||||||
const stepProps = {};
|
const stepProps = {};
|
||||||
const labelProps = {};
|
const labelProps = {};
|
||||||
|
// Determine if this step is clickable
|
||||||
|
const isClickable = confirmPhoneNumber && completed[index];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Step key={label} {...stepProps} completed={completed[index]}>
|
<Step key={label} {...stepProps} completed={completed[index]}>
|
||||||
<StepLabel
|
<StepLabel
|
||||||
{...labelProps}
|
{...labelProps}
|
||||||
onClick={handleStep(index)}
|
onClick={handleStep(index)}
|
||||||
sx={{ cursor: 'pointer' }}
|
sx={{
|
||||||
|
cursor: isClickable ? "pointer" : "not-allowed",
|
||||||
|
opacity: isClickable ? 1 : 0.7,
|
||||||
|
"& .MuiStepLabel-label": {
|
||||||
|
color: isClickable ? "text.primary" : "text.disabled",
|
||||||
|
},
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</StepLabel>
|
</StepLabel>
|
||||||
|
|
@ -843,14 +880,14 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
</Stepper>
|
</Stepper>
|
||||||
|
|
||||||
{/* Step Content */}
|
{/* Step Content */}
|
||||||
<Box sx={{ mt: 2, mb: 2, minHeight: '300px' }}>
|
<Box sx={{ mt: 2, mb: 2, minHeight: "300px" }}>
|
||||||
{allStepsCompleted() ? (
|
{allStepsCompleted() ? (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Typography sx={{ mt: 2, mb: 1 }}>
|
<Typography sx={{ mt: 2, mb: 1 }}>
|
||||||
All steps completed - Setup is ready to be saved.
|
All steps completed - Setup is ready to be saved.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2 }}>
|
<Box sx={{ display: "flex", flexDirection: "row", pt: 2 }}>
|
||||||
<Box sx={{ flex: '1 1 auto' }} />
|
<Box sx={{ flex: "1 1 auto" }} />
|
||||||
{/* <Button onClick={handleReset} sx={{ mr: 1 }}>
|
{/* <Button onClick={handleReset} sx={{ mr: 1 }}>
|
||||||
Reset
|
Reset
|
||||||
</Button> */}
|
</Button> */}
|
||||||
|
|
@ -864,7 +901,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
{renderStepContent(activeStep)}
|
{renderStepContent(activeStep)}
|
||||||
|
|
||||||
{/* Navigation Buttons */}
|
{/* Navigation Buttons */}
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2, mt: 4 }}>
|
<Box sx={{ display: "flex", flexDirection: "row", pt: 2, mt: 4 }}>
|
||||||
<Button
|
<Button
|
||||||
color="inherit"
|
color="inherit"
|
||||||
disabled={activeStep === 0}
|
disabled={activeStep === 0}
|
||||||
|
|
@ -874,7 +911,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
<Box sx={{ flex: '1 1 auto' }} />
|
<Box sx={{ flex: "1 1 auto" }} />
|
||||||
{activeStep == 4 && (
|
{activeStep == 4 && (
|
||||||
<Button
|
<Button
|
||||||
onClick={handleTestConnection}
|
onClick={handleTestConnection}
|
||||||
|
|
@ -900,7 +937,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleComplete}
|
onClick={handleComplete}
|
||||||
>
|
>
|
||||||
{isLastStep() ? 'Finish' : 'Complete Step'}
|
{isLastStep() ? "Finish" : "Complete Step"}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
@ -1,9 +1,70 @@
|
||||||
import React from 'react'
|
import { Box } from "@mui/system";
|
||||||
|
import React from "react";
|
||||||
|
import { useFormik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { useTheme } from "@mui/material/styles";
|
||||||
|
|
||||||
|
import PageHeader from "../../components/PageHeader";
|
||||||
|
import CustomFileUpload from "../../components/CustomFileUpload";
|
||||||
|
import { MAX_FILE_SIZE_IN_MB, MAX_FILES } from "../../constants";
|
||||||
|
import { useStyles } from "./contractManagementStyles";
|
||||||
|
import { Grid, Paper } from "@mui/material";
|
||||||
|
|
||||||
const ContractManagement = () => {
|
const ContractManagement = () => {
|
||||||
return (
|
const classes = useStyles();
|
||||||
<div>ContractManagement</div>
|
const theme = useTheme();
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ContractManagement
|
const formik = useFormik({
|
||||||
|
initialValues: {
|
||||||
|
companyPANImage: "",
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object({
|
||||||
|
companyPANImage: Yup.string().required("Required"),
|
||||||
|
}),
|
||||||
|
onSubmit: (values) => {
|
||||||
|
console.log(values);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const setUploadedFileUrl = () => {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Paper
|
||||||
|
className={classes.formRoot}
|
||||||
|
sx={{ padding: theme.spacing(2), height: "70vh" }}
|
||||||
|
>
|
||||||
|
<PageHeader
|
||||||
|
pageTitle="Contract Management"
|
||||||
|
infiniteDropdown
|
||||||
|
hideAddButton={true}
|
||||||
|
/>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={theme.spacing(2.3)}
|
||||||
|
padding={`0 ${theme.spacing(3.2)}`}
|
||||||
|
className={classes.formRoot}
|
||||||
|
sx={{ display: "flex", flexDirection: "column" }}
|
||||||
|
>
|
||||||
|
<Grid item md={4} sm={12} xs={12}>
|
||||||
|
<CustomFileUpload
|
||||||
|
label="Contract*"
|
||||||
|
documentName="sd"
|
||||||
|
onUploadDone={setUploadedFileUrl}
|
||||||
|
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
|
||||||
|
maxFiles={MAX_FILES}
|
||||||
|
uploadedFileUrl={formik.values.companyPANImage}
|
||||||
|
errorMessage={
|
||||||
|
formik.errors.companyPANImage && formik.touched.companyPANImage
|
||||||
|
? formik.errors.companyPANImage
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ContractManagement;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,354 @@
|
||||||
import React from 'react'
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
|
import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew';
|
||||||
|
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
import PersonAddIcon from '@mui/icons-material/PersonAdd';
|
||||||
|
import SearchIcon from '@mui/icons-material/Search';
|
||||||
|
import {
|
||||||
|
Alert,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
Divider,
|
||||||
|
IconButton,
|
||||||
|
InputAdornment,
|
||||||
|
Paper,
|
||||||
|
Snackbar,
|
||||||
|
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 MasterDataManagement = () => {
|
const MasterDataManagement = () => {
|
||||||
return (
|
// State for form fields
|
||||||
<div>MasterDataManagement</div>
|
const [appointmentType, setAppointmentType] = useState('');
|
||||||
)
|
const queryParams = new URLSearchParams(location.search);
|
||||||
}
|
|
||||||
|
// State for staff list
|
||||||
|
const [staffList, setStaffList] = useState([]);
|
||||||
|
|
||||||
|
// State for dialog
|
||||||
|
const [openDialog, setOpenDialog] = useState(false);
|
||||||
|
|
||||||
|
// State for search
|
||||||
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
|
||||||
|
// State for pagination
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const rowsPerPage = 10;
|
||||||
|
|
||||||
|
// State for notification
|
||||||
|
const [notification, setNotification] = useState({
|
||||||
|
open: false,
|
||||||
|
message: '',
|
||||||
|
severity: 'success',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle dialog open/close
|
||||||
|
const handleOpenDialog = () => {
|
||||||
|
setOpenDialog(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseDialog = () => {
|
||||||
|
setOpenDialog(false);
|
||||||
|
// Clear form
|
||||||
|
setAppointmentType('');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle form submission
|
||||||
|
const handleSubmit = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Add new staff member
|
||||||
|
const newStaff = {
|
||||||
|
id: staffList.length + 1,
|
||||||
|
appointmentType,
|
||||||
|
};
|
||||||
|
|
||||||
|
setStaffList([...staffList, newStaff]);
|
||||||
|
|
||||||
|
// Close dialog
|
||||||
|
handleCloseDialog();
|
||||||
|
|
||||||
|
// Show success notification
|
||||||
|
setNotification({
|
||||||
|
open: true,
|
||||||
|
message: 'Staff member added successfully!',
|
||||||
|
severity: 'success',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle notification close
|
||||||
|
const handleCloseNotification = () => {
|
||||||
|
setNotification({
|
||||||
|
...notification,
|
||||||
|
open: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...................breadcrumbs array........................
|
||||||
|
const breadcrumbs = [
|
||||||
|
{
|
||||||
|
label: 'Dashboard',
|
||||||
|
path: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Master Data Management',
|
||||||
|
path: '/masterData',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||||
|
|
||||||
export default MasterDataManagement
|
<PageHeader
|
||||||
|
pageTitle="Master Data Management"
|
||||||
|
hideAddButton
|
||||||
|
/>
|
||||||
|
|
||||||
|
<CustomBreadcrumbs breadcrumbs={breadcrumbs} />
|
||||||
|
|
||||||
|
<Paper elevation={3} sx={{ p: 0, mb: 4, overflow: 'hidden' }}>
|
||||||
|
{/* Staff List Header with Add Button */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
p: 3,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h6" component="h2" sx={{ fontWeight: 'bold' }}>
|
||||||
|
Master Appointment Type List
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="error"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
onClick={handleOpenDialog}
|
||||||
|
sx={{
|
||||||
|
borderRadius: 50,
|
||||||
|
textTransform: 'none',
|
||||||
|
backgroundColor: '#ff3366',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#e61653',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Appointment Type
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Search Box */}
|
||||||
|
<Box sx={{ px: 3, pb: 2 }}>
|
||||||
|
<TextField
|
||||||
|
placeholder="Search Appointment Type here"
|
||||||
|
fullWidth
|
||||||
|
size="small"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<SearchIcon color="action" />
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: 2,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Staff List Table */}
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow sx={{ backgroundColor: '#f5f5f5' }}>
|
||||||
|
<TableCell sx={{ fontWeight: 'bold' }}>Sr. No.</TableCell>
|
||||||
|
<TableCell sx={{ fontWeight: 'bold' }}>Appointment Type</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{staffList.length > 0 ? (
|
||||||
|
staffList
|
||||||
|
.filter(
|
||||||
|
(staff) =>
|
||||||
|
`${staff.appointmentType}`
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(searchQuery.toLowerCase())
|
||||||
|
)
|
||||||
|
.slice((page - 1) * rowsPerPage, page * rowsPerPage)
|
||||||
|
.map((staff, index) => (
|
||||||
|
<TableRow key={staff.id}>
|
||||||
|
<TableCell>
|
||||||
|
{(page - 1) * rowsPerPage + index + 1}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{staff.appointmentType}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
colSpan={2}
|
||||||
|
align="center"
|
||||||
|
sx={{ py: 5, color: '#666' }}
|
||||||
|
>
|
||||||
|
No Appointment Type added yet
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
|
||||||
|
{/* Pagination */}
|
||||||
|
{staffList.length > 0 && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
p: 2,
|
||||||
|
borderTop: '1px solid #eee',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
onClick={() => setPage((prev) => Math.max(prev - 1, 1))}
|
||||||
|
disabled={page === 1}
|
||||||
|
startIcon={<ArrowBackIosNewIcon fontSize="small" />}
|
||||||
|
sx={{ mx: 1, color: '#666' }}
|
||||||
|
>
|
||||||
|
Previous
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
disableElevation
|
||||||
|
sx={{
|
||||||
|
mx: 1,
|
||||||
|
minWidth: '36px',
|
||||||
|
backgroundColor: '#f0f0f0',
|
||||||
|
color: '#333',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#e0e0e0',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{page}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={() => setPage((prev) => prev + 1)}
|
||||||
|
disabled={page * rowsPerPage >= staffList.length}
|
||||||
|
endIcon={<ArrowForwardIosIcon fontSize="small" />}
|
||||||
|
sx={{ mx: 1, color: '#666' }}
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
{/* Add Staff Dialog */}
|
||||||
|
<Dialog
|
||||||
|
open={openDialog}
|
||||||
|
onClose={handleCloseDialog}
|
||||||
|
maxWidth="sm"
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
<DialogTitle
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
pb: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<PersonAddIcon sx={{ mr: 1, color: '#0a2d6b' }} />
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
component="span"
|
||||||
|
sx={{ fontWeight: 'bold', color: '#0a2d6b' }}
|
||||||
|
>
|
||||||
|
Add New Appointment Type
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<IconButton onClick={handleCloseDialog} size="small">
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</DialogTitle>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<DialogContent>
|
||||||
|
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 1 }}>
|
||||||
|
<TextField
|
||||||
|
label="Appointment Type"
|
||||||
|
fullWidth
|
||||||
|
margin="normal"
|
||||||
|
value={appointmentType}
|
||||||
|
onChange={(e) => setAppointmentType(e.target.value)}
|
||||||
|
placeholder="Appointment Type"
|
||||||
|
required
|
||||||
|
InputLabelProps={{
|
||||||
|
shrink: true,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
|
||||||
|
<DialogActions sx={{ px: 3, pb: 3 }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="error"
|
||||||
|
fullWidth
|
||||||
|
onClick={handleSubmit}
|
||||||
|
sx={{
|
||||||
|
py: 1.5,
|
||||||
|
backgroundColor: '#ff3366',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#e61653',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Appointment Type
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
{/* Notification */}
|
||||||
|
<Snackbar
|
||||||
|
open={notification.open}
|
||||||
|
autoHideDuration={4000}
|
||||||
|
onClose={handleCloseNotification}
|
||||||
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||||
|
>
|
||||||
|
<Alert
|
||||||
|
onClose={handleCloseNotification}
|
||||||
|
severity={notification.severity}
|
||||||
|
sx={{ width: '100%' }}
|
||||||
|
>
|
||||||
|
{notification.message}
|
||||||
|
</Alert>
|
||||||
|
</Snackbar>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MasterDataManagement;
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,9 @@ function YourDetailsForm() {
|
||||||
practiceManagementSystem: "",
|
practiceManagementSystem: "",
|
||||||
practiceId: "",
|
practiceId: "",
|
||||||
practiceName: "",
|
practiceName: "",
|
||||||
|
|
||||||
|
// contract management
|
||||||
|
contract: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Field references for focus and validation
|
// Field references for focus and validation
|
||||||
|
|
@ -176,6 +179,9 @@ function YourDetailsForm() {
|
||||||
fullAddress: useRef(null),
|
fullAddress: useRef(null),
|
||||||
companyPANImage: useRef(null),
|
companyPANImage: useRef(null),
|
||||||
companyTANNumber: useRef(null),
|
companyTANNumber: useRef(null),
|
||||||
|
|
||||||
|
// contract management
|
||||||
|
contract: useRef(null),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (yourDetailsFormData) {
|
if (yourDetailsFormData) {
|
||||||
|
|
@ -262,6 +268,7 @@ function YourDetailsForm() {
|
||||||
companyTANImage: Yup.string().required(
|
companyTANImage: Yup.string().required(
|
||||||
"Clinic MEDICARE document is required"
|
"Clinic MEDICARE document 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")
|
||||||
.required("You must accept the terms and conditions"),
|
.required("You must accept the terms and conditions"),
|
||||||
|
|
@ -551,6 +558,7 @@ function YourDetailsForm() {
|
||||||
documentType: "PAN",
|
documentType: "PAN",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
contract: inputData.contract || "",
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
@ -644,7 +652,9 @@ function YourDetailsForm() {
|
||||||
padding={`0 ${theme.spacing(3.2)}`}
|
padding={`0 ${theme.spacing(3.2)}`}
|
||||||
className={classes.formRoot}
|
className={classes.formRoot}
|
||||||
>
|
>
|
||||||
<TextField disabled />
|
<Grid item md={4} sm={6} xs={12}>
|
||||||
|
<TextField value={1} disabled />
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/* Personal Details Section */}
|
{/* Personal Details Section */}
|
||||||
|
|
@ -1769,7 +1779,7 @@ function YourDetailsForm() {
|
||||||
<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 Image*"
|
||||||
documentName="sd"
|
documentName="companyPANImage"
|
||||||
onUploadDone={setUploadedFileUrl}
|
onUploadDone={setUploadedFileUrl}
|
||||||
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
|
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
|
||||||
maxFiles={MAX_FILES}
|
maxFiles={MAX_FILES}
|
||||||
|
|
@ -1783,6 +1793,24 @@ function YourDetailsForm() {
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
{/* contract grid */}
|
||||||
|
<Grid item md={4} sm={12} xs={12}>
|
||||||
|
<CustomFileUpload
|
||||||
|
label="Add Contract*"
|
||||||
|
documentName="contract"
|
||||||
|
onUploadDone={setUploadedFileUrl}
|
||||||
|
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
|
||||||
|
maxFiles={MAX_FILES}
|
||||||
|
uploadedFileUrl={formik.values.contract}
|
||||||
|
errorMessage={
|
||||||
|
formik.errors.contract &&
|
||||||
|
formik.touched.contract
|
||||||
|
? formik.errors.contract
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
{/* terms and condition grid */}
|
{/* terms and condition grid */}
|
||||||
<Grid item md={12}>
|
<Grid item md={12}>
|
||||||
<Box display="flex">
|
<Box display="flex">
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { LoadingButton } from "@mui/lab";
|
import { LoadingButton } from "@mui/lab";
|
||||||
import { Box, Button, Grid, MenuItem, Select, Switch, TextField } from "@mui/material";
|
import { Box, Button, Chip, Grid, MenuItem, Select, Switch, TextField } from "@mui/material";
|
||||||
import { useFormik } from "formik";
|
import { useFormik } from "formik";
|
||||||
import React, { useMemo, useRef, useState } from "react";
|
import React, { useMemo, useRef, useState } from "react";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
|
|
||||||
/* ----------------- Custom Imports ----------------- */
|
/* ----------------- Custom Imports ----------------- */
|
||||||
import PageHeader from "../../components/PageHeader";
|
import PageHeader from "../../components/PageHeader";
|
||||||
|
|
@ -13,11 +14,7 @@ import CustomModal from "../Modal/Modal";
|
||||||
import { useStyles } from "./userStyles";
|
import { useStyles } from "./userStyles";
|
||||||
|
|
||||||
/* ----------------- Assets ----------------- */
|
/* ----------------- Assets ----------------- */
|
||||||
import SendIcon from "@mui/icons-material/Send";
|
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
|
||||||
import EditIcon from "@mui/icons-material/Edit";
|
|
||||||
import RemoveIcon from "@mui/icons-material/Remove";
|
|
||||||
import {
|
import {
|
||||||
getUsers,
|
getUsers,
|
||||||
deleteUserById,
|
deleteUserById,
|
||||||
|
|
@ -98,6 +95,36 @@ function Users() {
|
||||||
return { data: resp?.data?.records, rowCount: resp?.data?.totalCount };
|
return { data: resp?.data?.records, rowCount: resp?.data?.totalCount };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const editUser = async (row) => {
|
||||||
|
try {
|
||||||
|
const userData = await getUserById(row?.original?.id);
|
||||||
|
const formData = {
|
||||||
|
userName: userData?.name,
|
||||||
|
email: userData?.email,
|
||||||
|
mobile: userData?.mobile,
|
||||||
|
isEditUser: true,
|
||||||
|
};
|
||||||
|
// const updatedCheckboxes = roles.reduce(
|
||||||
|
// (acc, role) => ({
|
||||||
|
// ...acc,
|
||||||
|
// [role?.id]: userData?.roles.some(
|
||||||
|
// (roleData) => roleData?.id === role?.id
|
||||||
|
// ),
|
||||||
|
// }),
|
||||||
|
// {}
|
||||||
|
// );
|
||||||
|
|
||||||
|
// setSelectedCheckboxes(updatedCheckboxes);
|
||||||
|
// formik.setValues(formData);
|
||||||
|
// toggle();
|
||||||
|
// setIsEditUser(true);
|
||||||
|
// setUserId(row?.original?.id);
|
||||||
|
} catch ({ resp }) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(resp?.data?.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleToggleButton = async (row) => {
|
const handleToggleButton = async (row) => {
|
||||||
try {
|
try {
|
||||||
// Replace this with your actual API call to update user status
|
// Replace this with your actual API call to update user status
|
||||||
|
|
@ -204,14 +231,63 @@ function Users() {
|
||||||
isBold: true,
|
isBold: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: ({ mobile }) => mobile || NOT_AVAILABLE_TEXT,
|
accessorFn: ({ userType }) => userType || NOT_AVAILABLE_TEXT,
|
||||||
accessorKey: "userType",
|
accessorKey: "userType",
|
||||||
header: "User Type",
|
header: "User Type",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: ({ email }) => email || NOT_AVAILABLE_TEXT,
|
accessorKey: "appointmentTypes",
|
||||||
accessorKey: "specialities",
|
header: "Appointment Types",
|
||||||
header: "Specialties",
|
Cell: ({ row }) => {
|
||||||
|
const appointmentTypes = row?.original?.appointmentTypes;
|
||||||
|
|
||||||
|
// Convert to array if it's a string (comma-separated values)
|
||||||
|
const typesArray = Array.isArray(appointmentTypes) && appointmentTypes.length > 0
|
||||||
|
? appointmentTypes
|
||||||
|
: typeof appointmentTypes === 'string' && appointmentTypes.trim() !== ''
|
||||||
|
? appointmentTypes.split(',').map(type => type.trim())
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
|
||||||
|
{typesArray.length > 0 ? (
|
||||||
|
typesArray.map((type, index) => {
|
||||||
|
const label = typeof type === 'string'
|
||||||
|
? type
|
||||||
|
: type?.name || type?.type || String(type);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
key={index}
|
||||||
|
label={label}
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
margin: '2px',
|
||||||
|
borderRadius: '16px',
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
'& .MuiChip-label': { fontSize: '0.75rem' }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<Chip
|
||||||
|
label={NOT_AVAILABLE_TEXT}
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
margin: '2px',
|
||||||
|
borderRadius: '16px',
|
||||||
|
backgroundColor: '#f0f0f0',
|
||||||
|
color: '#757575',
|
||||||
|
'& .MuiChip-label': { fontSize: '0.75rem' }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "createdAt",
|
accessorKey: "createdAt",
|
||||||
|
|
@ -362,26 +438,25 @@ function Users() {
|
||||||
columns={columns}
|
columns={columns}
|
||||||
getData={getData}
|
getData={getData}
|
||||||
options={{ enableRowSelection: false }}
|
options={{ enableRowSelection: false }}
|
||||||
// showAction={true}
|
showAction={true}
|
||||||
hideShowPerPage={true}
|
hideShowPerPage={true}
|
||||||
showSearchBox={true}
|
showSearchBox={true}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
searchText={"user"}
|
searchText={"user"}
|
||||||
getRowStyle={getRowStyle}
|
getRowStyle={getRowStyle}
|
||||||
// actions={[
|
actions={[
|
||||||
// {
|
{
|
||||||
// title: "Action",
|
onClick: editUser,
|
||||||
// field: "isActive",
|
text: 'Edit',
|
||||||
// render: (rowData) => (
|
icon: (
|
||||||
// <Switch
|
<EditIcon
|
||||||
// checked={rowData.isActive}
|
// className={classes.tableActionIcons}
|
||||||
// onChange={() => handleToggleButton(rowData)}
|
alt="Edit"
|
||||||
// inputProps={{ "aria-label": "Status toggle" }}
|
/>
|
||||||
// color="primary"
|
),
|
||||||
// />
|
// permissionName: "CREATE_USERS",
|
||||||
// ),
|
},
|
||||||
// },
|
]}
|
||||||
// ]}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue