feat: clinic admin setup

This commit is contained in:
deepvasoya 2025-05-08 19:36:56 +05:30
parent 4717c67cca
commit 050cf206f5
11 changed files with 1088 additions and 195 deletions

View File

@ -77,13 +77,19 @@ const CustomFileUpload = forwardRef(function CustomFileUpload(
useEffect(() => {
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://');
if (!isHttp) {
setOldUploadedFileUrl(url ? `${IMAGE_LOCATION_BASE_URL}${url}` : '');
setFileExtension(
uploadedFileUrl ? uploadedFileUrl.split('.').pop() : ''
);
setImageName(uploadedFileUrl ? uploadedFileUrl.split('/').pop() : '');
setOldUploadedFileUrl(`${IMAGE_LOCATION_BASE_URL}${url}`);
setFileExtension(url.split('.').pop() || '');
setImageName(url.split('/').pop() || '');
return;
}
const urlObject = new URL(url);

View File

@ -382,30 +382,30 @@ const Table = memo(
muiSelectAllCheckboxProps={{
className: classes?.tableCheckbox,
}}
// renderRowActionMenuItems={({ row, closeMenu }) =>
// actions?.filter(action => !action.render)?.map((action, index) =>
// !(action?.renderAction?.(row) ?? true) ? null : (
// <MenuItem
// key={index}
// className={classes.menuItem}
// onClick={(event) => {
// event.stopPropagation();
// action.onClick && action.onClick(row);
// closeMenu();
// }}
// disabled={
// action?.isDisabledValue
// ? action?.isDisabledValue ===
// row?.original?.[action?.rowKey]
// : false
// }
// >
// {action?.icon} {action?.text}{" "}
// {action.textFn && action.textFn(row)}
// </MenuItem>
// )
// ) ?? []
// }
renderRowActionMenuItems={({ row, closeMenu }) =>
actions?.filter(action => !action.render)?.map((action, index) =>
!(action?.renderAction?.(row) ?? true) ? null : (
<MenuItem
key={index}
className={classes.menuItem}
onClick={(event) => {
event.stopPropagation();
action.onClick && action.onClick(row);
closeMenu();
}}
disabled={
action?.isDisabledValue
? action?.isDisabledValue ===
row?.original?.[action?.rowKey]
: false
}
>
{action?.icon} {action?.text}{" "}
{action.textFn && action.textFn(row)}
</MenuItem>
)
) ?? []
}
renderTopToolbarCustomActions={({ table }) => {
const handleActive = () => {
const data = table

View File

@ -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 CLINIC_GREETINGS_LENGTH = 1000;
export const CLINIC_SCENARIOS_LENGTH = 5000;
export const FILE_TYPE = [
'.jpeg',
'.jpg',

View File

@ -6,6 +6,7 @@ export const userDataMock = {
name: "test",
email: "test@gmail.com",
userType: "Manager",
appointmentTypes: ["Adult Immunisation", "Child Immunisation"],
specialities: "Doctor",
createdAt: "2025-01-01",
status: "Active",
@ -15,6 +16,7 @@ export const userDataMock = {
name: "John Doe",
email: "johndoe@example.com",
userType: "Employee",
appointmentTypes: ["Adult Immunisation"],
specialities: "Engineer",
createdAt: "2024-11-15",
status: "Inactive",
@ -24,6 +26,7 @@ export const userDataMock = {
name: "Jane Smith",
email: "janesmith@example.com",
userType: "Admin",
appointmentTypes: ["Adult Immunisation"],
specialities: "Manager",
createdAt: "2024-12-01",
status: "Active",
@ -32,6 +35,7 @@ export const userDataMock = {
id: 4,
name: "Alice Brown",
email: "alicebrown@example.com",
appointmentTypes: ["Adult Immunisation"],
userType: "Manager",
specialities: "HR",
createdAt: "2023-06-22",
@ -51,6 +55,7 @@ export const userDataMock = {
name: "Charlie Black",
email: "charlieblack@example.com",
userType: "Admin",
appointmentTypes: ["Adult Immunisation"],
specialities: "IT Support",
createdAt: "2023-07-05",
status: "Inactive",
@ -60,6 +65,7 @@ export const userDataMock = {
name: "Eve White",
email: "evewhite@example.com",
userType: "Manager",
appointmentTypes: ["Adult Immunisation"],
specialities: "Finance",
createdAt: "2025-03-30",
status: "Active",

View File

@ -28,14 +28,20 @@ export const getUsers = (params) => {
};
export const getUserById = (id) => {
const url = `/users/${id}`;
return new Promise((resolve, reject) => {
axiosInstance
.get(url)
.then((response) => resolve(response))
.catch((err) => reject(err));
});
const data = userDataMock;
return data.data.records.find((item) => item.id === id)
};
// 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 }) =>
page == 0
? {

View File

@ -1,12 +1,12 @@
import SendIcon from '@mui/icons-material/Send';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import FormControl from '@mui/material/FormControl';
import Grid from '@mui/material/Grid';
import InputLabel from '@mui/material/InputLabel';
import * as React from 'react';
import { pushNotification } from '../../utils/notification';
import { NOTIFICATION_TYPE } from '../Notifications/notificationConstant';
import SendIcon from "@mui/icons-material/Send";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import FormControl from "@mui/material/FormControl";
import Grid from "@mui/material/Grid";
import InputLabel from "@mui/material/InputLabel";
import * as React from "react";
import { pushNotification } from "../../utils/notification";
import { NOTIFICATION_TYPE } from "../Notifications/notificationConstant";
import {
Dialog,
DialogActions,
@ -21,33 +21,37 @@ import {
Stepper,
TextField,
Typography,
} from '@mui/material';
import WarningAmberIcon from '@mui/icons-material/WarningAmber';
} from "@mui/material";
import WarningAmberIcon from "@mui/icons-material/WarningAmber";
import {
CLINIC_GREETINGS_LENGTH,
CLINIC_SCENARIOS_LENGTH,
} from "../../constants";
// Integration software options
const integrationOptions = ['BP Software', 'Medical Director'];
const integrationOptions = ["BP Software", "Medical Director"];
// Steps for the stepper
const steps = [
'General Information',
'AI Receptionist Setup',
'Scenarios Setup',
'General Info Setup',
'Integration Settings',
"General Information",
"AI Receptionist Setup",
"Scenarios Setup",
"General Info Setup",
"Integration Settings",
];
const voiceModels = [
{ id: 'stream', name: 'Stream', gender: 'female' },
{ id: 'sandy', name: 'Sandy', gender: 'female' },
{ id: 'breeze', name: 'Breeze', gender: 'female' },
{ id: 'wolf', name: 'Wolf', gender: 'male' },
{ id: 'stan', name: 'Sten', gender: 'male' },
{ id: 'blaze', name: 'Blaze', gender: 'male' },
{ id: "stream", name: "Stream", gender: "female" },
{ id: "sandy", name: "Sandy", gender: "female" },
{ id: "breeze", name: "Breeze", gender: "female" },
{ id: "wolf", name: "Wolf", gender: "male" },
{ id: "stan", name: "Sten", gender: "male" },
{ id: "blaze", name: "Blaze", gender: "male" },
];
const voiceModelGender = [
{ id: 'male', name: 'Male' },
{ id: 'female', name: 'Female' },
{ id: "male", name: "Male" },
{ id: "female", name: "Female" },
];
export default function ClinicSetup() {
@ -56,6 +60,7 @@ export default function ClinicSetup() {
const [openDialog, setOpenDialog] = React.useState(false);
const [audioContext, setAudioContext] = React.useState(null);
const [testConnDone, setTestConnDone] = React.useState(false);
const [confirmPhoneNumber, setConfirmPhoneNumber] = React.useState(false);
// Completed steps state
const [completed, setCompleted] = React.useState({});
@ -63,13 +68,13 @@ export default function ClinicSetup() {
// Form state
const [formData, setFormData] = React.useState({
// General Information
clinicPhone: '159875654',
clinicAddress: '1 Wilkinson Road, Para Hills SA 5096',
otherInfo: '',
clinicPhone: "159875654",
clinicAddress: "1 Wilkinson Road, Para Hills SA 5096",
otherInfo: "",
// Greetings Setup
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
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 .
@ -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)`,
// Integration Settings
integrationSoftware: '',
practiceId: '',
practiceName: '',
integrationSoftware: "",
practiceId: "",
practiceName: "",
// Voice Configuration
voice: '',
voice: "",
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
setFormData(
Object.keys(formData).reduce((acc, key) => {
acc[key] = '';
acc[key] = "";
return acc;
}, {})
);
};
const handleConfirmPhoneNumber = () => {
setConfirmPhoneNumber(true);
};
React.useEffect(() => {
if(formData.clinicPhone=="159875654"){
setConfirmPhoneNumber(true);
}
}, []);
React.useEffect(() => {
// Initialize audio context when component mounts
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) {
pushNotification(
'Your browser does not support AudioContext and cannot play back audio.',
'error'
"Your browser does not support AudioContext and cannot play back audio.",
"error"
);
return null;
}
@ -189,7 +204,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
// Cleanup function
return () => {
if (context && context.state !== 'closed') {
if (context && context.state !== "closed") {
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
const handleNext = () => {
if (!confirmPhoneNumber) {
pushNotification("Please confirm phone number", "error");
return;
}
const newActiveStep =
isLastStep() && !allStepsCompleted()
? // 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
const listenVoice = () => {
if (!audioContext) {
pushNotification('Audio context not initialized', 'error');
pushNotification("Audio context not initialized", "error");
return;
}
if (!formData.clinicGreetings || formData.clinicGreetings.length === 0) {
pushNotification(
'Please enter clinic greetings to listen preview',
'error'
"Please enter clinic greetings to listen preview",
"error"
);
return;
}
const options = {
method: 'POST',
method: "POST",
headers: {
Accept: 'audio/mp3',
Authorization: 'Bearer ElD2r2Dn9Lsl5qB5TupaGcKlWSEf2llo9CkHi2OrOOU',
'Content-Type': 'application/json',
Accept: "audio/mp3",
Authorization: "Bearer ElD2r2Dn9Lsl5qB5TupaGcKlWSEf2llo9CkHi2OrOOU",
"Content-Type": "application/json",
},
body: JSON.stringify({
speaker: formData.voice || 'wolf',
speaker: formData.voice || "wolf",
text: formData.clinicGreetings,
modelId: 'mist',
lang: 'eng',
modelId: "mist",
lang: "eng",
samplingRate: 22050,
speedAlpha: 1.0,
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
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) => {
// Check if the response is successful
if (!response.ok) {
@ -269,12 +289,12 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
arrayBuffer,
(buffer) => playAudioBuffer(buffer, audioContext),
(error) => {
pushNotification('Failed to decode audio data', 'error');
pushNotification("Failed to decode audio data", "error");
}
);
})
.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);
// Notify user
pushNotification('Playing audio...', 'success');
pushNotification("Playing audio...", "success");
}
// 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
const handleStep = (step) => () => {
// If trying to skip ahead with errors in current step, validate first
if (step > activeStep) {
if (validateStep()) {
setActiveStep(step);
} else {
// Alert user about validation errors
pushNotification(
'Please complete the current step before proceeding',
NOTIFICATION_TYPE.ERROR
);
}
} else {
// Allow going backward anytime
// First check if phone number is confirmed for any step navigation
if (!confirmPhoneNumber) {
pushNotification(
"Please confirm phone number before navigating between steps",
"error"
);
return;
}
// Then check if the step is completed
if (completed[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 = () => {
// logic here
setTestConnDone(true);
pushNotification('Test connection successful', 'success');
pushNotification("Test connection successful", "success");
};
// 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
if (formData.integrationSoftware) {
const integrationErrors = {
practiceId: formData.practiceId.trim() === '',
practiceName: formData.practiceName.trim() === '',
practiceId: formData.practiceId.trim() === "",
practiceName: formData.practiceName.trim() === "",
};
setErrors(integrationErrors);
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 { name, value } = e.target;
if (name === "clinicPhone" && value != formData.clinicPhone) {
setConfirmPhoneNumber(false);
}
setFormData((prev) => ({
...prev,
[name]: value,
@ -419,14 +447,14 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
const validateForm = () => {
// Check all steps
const generalInfoValid =
formData.clinicPhone.trim() !== '' &&
formData.clinicAddress.trim() !== '';
formData.clinicPhone.trim() !== "" &&
formData.clinicAddress.trim() !== "";
let integrationValid = true;
if (formData.integrationSoftware) {
integrationValid =
formData.practiceId.trim() !== '' &&
formData.practiceName.trim() !== '';
formData.practiceId.trim() !== "" &&
formData.practiceName.trim() !== "";
}
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();
if (validateForm()) {
console.log('Form submitted:', formData);
console.log("Form submitted:", formData);
// 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
handleReset();
} else {
// Find the first step with errors and go to it
if (
formData.clinicPhone.trim() === '' ||
formData.clinicAddress.trim() === ''
formData.clinicPhone.trim() === "" ||
formData.clinicAddress.trim() === ""
) {
setActiveStep(0);
setErrors({
...errors,
clinicPhone: formData.clinicPhone.trim() === '',
clinicAddress: formData.clinicAddress.trim() === '',
clinicPhone: formData.clinicPhone.trim() === "",
clinicAddress: formData.clinicAddress.trim() === "",
});
} else if (
formData.integrationSoftware &&
(formData.practiceId.trim() === '' ||
formData.practiceName.trim() === '')
(formData.practiceId.trim() === "" ||
formData.practiceName.trim() === "")
) {
setActiveStep(3);
setErrors({
...errors,
practiceId: formData.practiceId.trim() === '',
practiceName: formData.practiceName.trim() === '',
practiceId: formData.practiceId.trim() === "",
practiceName: formData.practiceName.trim() === "",
});
}
// Show an alert
pushNotification(
'Please fill in all required fields before submitting',
"Please fill in all required fields before submitting",
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"
>
<TextField
style={{ width: '40%' }}
type="number"
style={{ width: "40%" }}
label="Clinic Phone Number"
name="clinicPhone"
value={formData.clinicPhone}
onChange={handleChange}
helperText={
errors.clinicPhone
? 'Phone number is required'
: 'Unique single number for your clinic'
? "Phone number is required"
: "Unique single number for your clinic"
}
variant="outlined"
error={errors.clinicPhone}
/>
<Button
style={{ marginLeft: '10px' }}
style={{ marginLeft: "10px" }}
variant="contained"
color="primary"
startIcon={<SendIcon />}
href="https://login.twilio.com/u/signup"
target="_blank"
onClick={handleConfirmPhoneNumber}
>
Configure Phone Number
Confirm
</Button>
<>
<Button
style={{ marginLeft: '10px' }}
style={{ marginLeft: "10px" }}
variant="outlined"
color="error"
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"
>
<DialogTitle id="alert-dialog-title">
{'Confirm Disable AI Receptionist'}
{"Confirm Disable AI Receptionist"}
</DialogTitle>
<DialogContent>
<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
onClick={() => {
pushNotification(
'AI Receptionist disabled successfully',
"AI Receptionist disabled successfully",
NOTIFICATION_TYPE.SUCCESS
);
setOpenDialog(false);
@ -579,7 +607,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
variant="outlined"
error={errors.clinicAddress}
helperText={
errors.clinicAddress ? 'Clinic address is required' : ''
errors.clinicAddress ? "Clinic address is required" : ""
}
/>
</Grid>
@ -610,15 +638,15 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
multiline
rows={3}
variant="outlined"
helperText={`${formData.clinicGreetings.length}/200 characters`}
inputProps={{ maxLength: 200 }}
helperText={`${formData.clinicGreetings.length}/${CLINIC_GREETINGS_LENGTH} characters`}
inputProps={{ maxLength: CLINIC_GREETINGS_LENGTH }}
/>
<div
style={{
display: 'flex',
maxWidth: '40%',
display: "flex",
maxWidth: "40%",
// marginTop: '10px',
justifyContent: 'space-between',
justifyContent: "space-between",
}}
>
<Button
@ -650,10 +678,10 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
onChange={handleChange}
value={
formData.voice ||
(formData.voiceGender === 'male'
? voiceModels.find((model) => model.gender === 'male')
(formData.voiceGender === "male"
? voiceModels.find((model) => model.gender === "male")
.id
: voiceModels.find((model) => model.gender === 'female')
: voiceModels.find((model) => model.gender === "female")
.id)
}
displayEmpty
@ -677,7 +705,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
return (
<>
<TextField
style={{ marginTop: '10px' }}
style={{ marginTop: "10px" }}
fullWidth
label="Scenarios"
name="clinicScenarios"
@ -685,9 +713,9 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
onChange={handleChange}
multiline
rows={8}
helperText={`${formData.clinicScenarios.length}/1500 characters`}
helperText={`${formData.clinicScenarios.length}/${CLINIC_SCENARIOS_LENGTH} characters`}
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 (
<>
<TextField
style={{ marginTop: '10px' }}
style={{ marginTop: "10px" }}
fullWidth
label="General Info"
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}
helperText={
!!formData.integrationSoftware && errors.practiceId
? 'Practice ID is required'
: ''
? "Practice ID is required"
: ""
}
/>
</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}
helperText={
!!formData.integrationSoftware && errors.practiceName
? 'Practice Name is required'
: ''
? "Practice Name is required"
: ""
}
/>
</Grid>
@ -808,17 +836,17 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
);
default:
return 'Unknown step';
return "Unknown step";
}
};
return (
<Box component="form" onSubmit={handleSubmit} sx={{ width: '100%' }}>
<Box component="form" onSubmit={handleSubmit} sx={{ width: "100%" }}>
<Paper elevation={0} sx={{ p: 2 }}>
<Typography
variant="h4"
component="h1"
sx={{ fontWeight: 'bold', mb: 3 }}
sx={{ fontWeight: "bold", mb: 3 }}
>
Clinic Setup
</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) => {
const stepProps = {};
const labelProps = {};
// Determine if this step is clickable
const isClickable = confirmPhoneNumber && completed[index];
return (
<Step key={label} {...stepProps} completed={completed[index]}>
<StepLabel
{...labelProps}
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}
</StepLabel>
@ -843,14 +880,14 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
</Stepper>
{/* Step Content */}
<Box sx={{ mt: 2, mb: 2, minHeight: '300px' }}>
<Box sx={{ mt: 2, mb: 2, minHeight: "300px" }}>
{allStepsCompleted() ? (
<React.Fragment>
<Typography sx={{ mt: 2, mb: 1 }}>
All steps completed - Setup is ready to be saved.
</Typography>
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2 }}>
<Box sx={{ flex: '1 1 auto' }} />
<Box sx={{ display: "flex", flexDirection: "row", pt: 2 }}>
<Box sx={{ flex: "1 1 auto" }} />
{/* <Button onClick={handleReset} sx={{ mr: 1 }}>
Reset
</Button> */}
@ -864,7 +901,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
{renderStepContent(activeStep)}
{/* Navigation Buttons */}
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2, mt: 4 }}>
<Box sx={{ display: "flex", flexDirection: "row", pt: 2, mt: 4 }}>
<Button
color="inherit"
disabled={activeStep === 0}
@ -874,7 +911,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
>
Back
</Button>
<Box sx={{ flex: '1 1 auto' }} />
<Box sx={{ flex: "1 1 auto" }} />
{activeStep == 4 && (
<Button
onClick={handleTestConnection}
@ -900,7 +937,7 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
color="primary"
onClick={handleComplete}
>
{isLastStep() ? 'Finish' : 'Complete Step'}
{isLastStep() ? "Finish" : "Complete Step"}
</Button>
)}
</Box>

View File

@ -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',
},
},
}));

View File

@ -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 = () => {
return (
<div>ContractManagement</div>
)
}
const classes = useStyles();
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;

View File

@ -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 = () => {
return (
<div>MasterDataManagement</div>
)
}
// State for form fields
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;

View File

@ -144,6 +144,9 @@ function YourDetailsForm() {
practiceManagementSystem: "",
practiceId: "",
practiceName: "",
// contract management
contract: "",
});
// Field references for focus and validation
@ -176,6 +179,9 @@ function YourDetailsForm() {
fullAddress: useRef(null),
companyPANImage: useRef(null),
companyTANNumber: useRef(null),
// contract management
contract: useRef(null),
};
if (yourDetailsFormData) {
@ -262,6 +268,7 @@ function YourDetailsForm() {
companyTANImage: Yup.string().required(
"Clinic MEDICARE document is required"
),
contract: Yup.string().required("Contract is required"),
termsAccepted: Yup.boolean()
.oneOf([true], "You must accept the terms and conditions")
.required("You must accept the terms and conditions"),
@ -551,6 +558,7 @@ function YourDetailsForm() {
documentType: "PAN",
},
],
contract: inputData.contract || "",
};
return data;
}
@ -644,7 +652,9 @@ function YourDetailsForm() {
padding={`0 ${theme.spacing(3.2)}`}
className={classes.formRoot}
>
<TextField disabled />
<Grid item md={4} sm={6} xs={12}>
<TextField value={1} disabled />
</Grid>
</Grid>
{/* Personal Details Section */}
@ -1769,7 +1779,7 @@ function YourDetailsForm() {
<Grid item md={4} sm={12} xs={12}>
<CustomFileUpload
label="Add ABN Image*"
documentName="sd"
documentName="companyPANImage"
onUploadDone={setUploadedFileUrl}
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
maxFiles={MAX_FILES}
@ -1783,6 +1793,24 @@ function YourDetailsForm() {
/>
</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 */}
<Grid item md={12}>
<Box display="flex">

View File

@ -1,9 +1,10 @@
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 React, { useMemo, useRef, useState } from "react";
import { useSelector } from "react-redux";
import * as Yup from "yup";
import EditIcon from '@mui/icons-material/Edit';
/* ----------------- Custom Imports ----------------- */
import PageHeader from "../../components/PageHeader";
@ -13,11 +14,7 @@ import CustomModal from "../Modal/Modal";
import { useStyles } from "./userStyles";
/* ----------------- Assets ----------------- */
import SendIcon from "@mui/icons-material/Send";
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 {
getUsers,
deleteUserById,
@ -98,6 +95,36 @@ function Users() {
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) => {
try {
// Replace this with your actual API call to update user status
@ -204,14 +231,63 @@ function Users() {
isBold: true,
},
{
accessorFn: ({ mobile }) => mobile || NOT_AVAILABLE_TEXT,
accessorFn: ({ userType }) => userType || NOT_AVAILABLE_TEXT,
accessorKey: "userType",
header: "User Type",
},
{
accessorFn: ({ email }) => email || NOT_AVAILABLE_TEXT,
accessorKey: "specialities",
header: "Specialties",
accessorKey: "appointmentTypes",
header: "Appointment Types",
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",
@ -362,26 +438,25 @@ function Users() {
columns={columns}
getData={getData}
options={{ enableRowSelection: false }}
// showAction={true}
showAction={true}
hideShowPerPage={true}
showSearchBox={true}
ref={ref}
searchText={"user"}
getRowStyle={getRowStyle}
// actions={[
// {
// title: "Action",
// field: "isActive",
// render: (rowData) => (
// <Switch
// checked={rowData.isActive}
// onChange={() => handleToggleButton(rowData)}
// inputProps={{ "aria-label": "Status toggle" }}
// color="primary"
// />
// ),
// },
// ]}
actions={[
{
onClick: editUser,
text: 'Edit',
icon: (
<EditIcon
// className={classes.tableActionIcons}
alt="Edit"
/>
),
// permissionName: "CREATE_USERS",
},
]}
/>
</Box>