feat: clinic offers
This commit is contained in:
parent
f949253b77
commit
a17366037b
|
|
@ -24,7 +24,7 @@ function Header() {
|
|||
{user?.userType == USER_ROLES.SUPER_ADMIN.toLowerCase() ? null : `Welcome to ${user?.created_clinics?.[0]?.name}`}
|
||||
</Typography>
|
||||
<Box className={classes.profilDiv}>
|
||||
<NotificationSection />
|
||||
{/* <NotificationSection /> */}
|
||||
<Box
|
||||
sx={{
|
||||
zIndex:
|
||||
|
|
|
|||
|
|
@ -84,3 +84,49 @@ export const getClinicsDashboardStatsById = () => {
|
|||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const createClinicOffer = (data) => {
|
||||
const url = `/admin/clinic/offer`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const getClinicOffer = (params) => {
|
||||
|
||||
let searchParams = new URLSearchParams();
|
||||
searchParams.append("size", params?.pagination?.pageSize ?? 10);
|
||||
searchParams.append("page", params?.pagination.pageIndex ?? 0);
|
||||
searchParams.append("search", params?.globalFilter ?? "");
|
||||
|
||||
const url = `/admin/clinic/offers?${searchParams.toString()}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const updateClinicOffer = (data) => {
|
||||
const url = `/admin/clinic/offer`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteClinicOffer = (id) => {
|
||||
const url = `/admin/clinic/offer/${id}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.delete(url)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
import { axiosInstance } from "../config/api";
|
||||
|
||||
export const getMasterData = (params) => {
|
||||
let searchParams = new URLSearchParams();
|
||||
searchParams.append("search", params?.globalFilter ?? "");
|
||||
|
||||
const url = `/admin/master-data?${searchParams.toString()}`;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const setMasterData = (data) => {
|
||||
const url = "/admin/master-data";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const updateMasterData = (data) => {
|
||||
const url = "/admin/master-data";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
|
@ -9,3 +9,5 @@ export const passwordNumberRegex = /\d/;
|
|||
|
||||
// passwordSpacesRegex.js
|
||||
export const passwordSpacesRegex = /^\S.*\S$/;
|
||||
|
||||
export const emailRegex = /^\S+@\S+\.\S+$/;
|
||||
|
|
@ -249,7 +249,7 @@ const ClinicsList = () => {
|
|||
[
|
||||
// ..............sro number column......................
|
||||
{
|
||||
size: 60,
|
||||
size: 100,
|
||||
header: "Sr. No.",
|
||||
Cell: (props) => {
|
||||
const tableState = props?.table?.getState();
|
||||
|
|
@ -330,68 +330,6 @@ const ClinicsList = () => {
|
|||
);
|
||||
},
|
||||
},
|
||||
// ........................... sent email column.............................
|
||||
// {
|
||||
// enableSorting: true,
|
||||
// accessorKey: 'hasActiveCustomPlan',
|
||||
// minSize: 250,
|
||||
// header: 'Sent Mail',
|
||||
// Cell: ({ row }) => (
|
||||
// <>
|
||||
// {row?.original?.plans?.[0]?.status ===
|
||||
// PLAN_STATUS_TYPE.ACTIVATED && (
|
||||
// <div>
|
||||
// <Link
|
||||
// onClick={() => handleRegisterEmailSent(row)}
|
||||
// className={classes.sendEmailStatus}
|
||||
// >
|
||||
// <u>Resend Subscription Mail</u>
|
||||
// </Link>
|
||||
// <div className={classes.sendEmailLastSentMailDate}>
|
||||
// Last Sent On:{' '}
|
||||
// {format(
|
||||
// new Date(row?.original?.lastCustomPlanEmailSent),
|
||||
// 'dd MMM yyyy'
|
||||
// )}
|
||||
// </div>
|
||||
// </div>
|
||||
// )}
|
||||
// </>
|
||||
// ),
|
||||
// },
|
||||
|
||||
// ................add plan column..............................
|
||||
// {
|
||||
// enableSorting: true,
|
||||
// isBold: true,
|
||||
// size: 120,
|
||||
// accessorKey: 'hasActiveCustomPlan',
|
||||
// header: 'Custom Plan',
|
||||
// Cell: ({ row }) => (
|
||||
// <>
|
||||
// {row?.original?.plans?.[0]?.status ===
|
||||
// PLAN_STATUS_TYPE.ACTIVATED ? (
|
||||
// <Box>
|
||||
// <div className={classes.planAddedText}>
|
||||
// Plan Added <VerifiedIcon className={classes.verifyIcon} />
|
||||
// </div>
|
||||
// </Box>
|
||||
// ) : (
|
||||
// <Tooltip>
|
||||
// <Link
|
||||
// to={{
|
||||
// pathname: `/plans/${row.original.id}/custom-create`,
|
||||
// search: `?tab=${type}`,
|
||||
// }}
|
||||
// className={classes.addDiscountCodeLink}
|
||||
// >
|
||||
// <u>ADD PLAN</u>
|
||||
// </Link>
|
||||
// </Tooltip>
|
||||
// )}
|
||||
// </>
|
||||
// ),
|
||||
// },
|
||||
].filter(Boolean),
|
||||
[type]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,61 +1,38 @@
|
|||
import AddIcon from "@mui/icons-material/Add";
|
||||
import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew";
|
||||
import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
|
||||
import DescriptionIcon from '@mui/icons-material/Description';
|
||||
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 React, { useMemo, useRef, useState } from "react";
|
||||
import CustomBreadcrumbs from "../../components/CustomBreadcrumbs";
|
||||
import PageHeader from "../../components/PageHeader";
|
||||
import { pushNotification } from "../../utils/notification";
|
||||
import { NOTIFICATION } from "../../constants";
|
||||
import { useStyles } from "./masterDataStyles";
|
||||
import Table from "../../components/Table";
|
||||
import { getMasterData, setMasterData } from "../../services/masterData.services";
|
||||
|
||||
const MasterDataManagement = () => {
|
||||
const classes = useStyles();
|
||||
const ref = useRef(null);
|
||||
// State for form fields
|
||||
const [appointmentType, setAppointmentType] = useState("");
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
const [type, setType] = useState("");
|
||||
|
||||
// State for staff list
|
||||
const [staffList, setStaffList] = useState([]);
|
||||
|
||||
// State for staff dialog
|
||||
// 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 staff dialog open/close
|
||||
// Handle dialog open/close
|
||||
const handleOpenDialog = () => {
|
||||
setOpenDialog(true);
|
||||
};
|
||||
|
|
@ -63,38 +40,50 @@ const MasterDataManagement = () => {
|
|||
const handleCloseDialog = () => {
|
||||
setOpenDialog(false);
|
||||
// Clear form
|
||||
setAppointmentType("");
|
||||
setType("");
|
||||
};
|
||||
|
||||
// Handle form submission
|
||||
const handleSubmit = (e) => {
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Add new staff member
|
||||
const newStaff = {
|
||||
id: staffList.length + 1,
|
||||
appointmentType,
|
||||
const payload = {
|
||||
type,
|
||||
};
|
||||
|
||||
setStaffList([...staffList, newStaff]);
|
||||
const response = await setMasterData(payload);
|
||||
|
||||
if (response?.data?.data) {
|
||||
pushNotification("Master Data created successfully!", NOTIFICATION.SUCCESS);
|
||||
} else {
|
||||
pushNotification(response?.data?.message, NOTIFICATION.ERROR);
|
||||
}
|
||||
|
||||
// Close dialog
|
||||
handleCloseDialog();
|
||||
|
||||
// Show success notification
|
||||
setNotification({
|
||||
open: true,
|
||||
message: "Staff member added successfully!",
|
||||
severity: "success",
|
||||
});
|
||||
};
|
||||
|
||||
// Handle notification close
|
||||
const handleCloseNotification = () => {
|
||||
setNotification({
|
||||
...notification,
|
||||
open: false,
|
||||
});
|
||||
const getData = async (filters) => {
|
||||
try {
|
||||
// Remove the type parameter since it's not defined
|
||||
let params = {
|
||||
...filters
|
||||
};
|
||||
|
||||
const resp = await getMasterData(params);
|
||||
console.log('API Response:', resp);
|
||||
|
||||
return {
|
||||
data: resp?.data?.data?.data,
|
||||
rowCount: resp?.data?.data?.total || 0,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching admins:', error);
|
||||
return {
|
||||
data: [],
|
||||
rowCount: 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// ...................breadcrumbs array........................
|
||||
|
|
@ -109,244 +98,144 @@ const MasterDataManagement = () => {
|
|||
},
|
||||
];
|
||||
|
||||
const columns = useMemo(() => [
|
||||
{
|
||||
size: 100,
|
||||
header: "Sr. No.",
|
||||
Cell: (props) => {
|
||||
const tableState = props?.table?.getState();
|
||||
const serialNumber = (
|
||||
props?.row?.index +
|
||||
1 +
|
||||
tableState?.pagination?.pageIndex * tableState?.pagination?.pageSize
|
||||
)
|
||||
?.toString()
|
||||
?.padStart(2, "0");
|
||||
return <span>{serialNumber}</span>;
|
||||
},
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
id: "type", // Add an id to match the accessorKey
|
||||
size: 280,
|
||||
accessorKey: "type",
|
||||
header: "Type",
|
||||
enableColumnFilter: false,
|
||||
}
|
||||
// Removed the empty object that was causing the error
|
||||
]);
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||
<PageHeader pageTitle="Master Data Management" hideAddButton />
|
||||
|
||||
<Box>
|
||||
<PageHeader
|
||||
pageTitle="Master Data Management"
|
||||
// hideAddButton
|
||||
addButtonIcon={<AddIcon />}
|
||||
onAddButtonClick={handleOpenDialog}
|
||||
/>
|
||||
<CustomBreadcrumbs breadcrumbs={breadcrumbs} />
|
||||
|
||||
<Paper elevation={3} sx={{ p: 0, mb: 4, overflow: "hidden" }}>
|
||||
{/* Staff List Header with Add Button */}
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
p: 3,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" component="h2" sx={{ fontWeight: "bold" }}>
|
||||
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 className={classes.tableMainDiv}>
|
||||
<Box>
|
||||
<Table
|
||||
hideTopToolbar
|
||||
columns={columns}
|
||||
getData={getData}
|
||||
options={{
|
||||
enableRowSelection: true,
|
||||
showTopBar: false,
|
||||
showFilters: true,
|
||||
}}
|
||||
searchText="Master Data"
|
||||
showSearchBox={true}
|
||||
ref={ref}
|
||||
// actions={[
|
||||
// {
|
||||
// onClick: (row) => {
|
||||
|
||||
// },
|
||||
// text: "Remove",
|
||||
// icon: (
|
||||
// <DescriptionIcon />
|
||||
// // <img
|
||||
// // src={TransactionHistoryIcon}
|
||||
// // className={classes.tableActionIcons}
|
||||
// // alt="transaction history"
|
||||
// // />
|
||||
// ),
|
||||
// },
|
||||
// ]}
|
||||
/>
|
||||
</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
|
||||
</Box>
|
||||
<Box className={classes.tableMainDiv}>
|
||||
<Dialog
|
||||
open={openDialog}
|
||||
onClose={handleCloseDialog}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
p: 2,
|
||||
borderTop: "1px solid #eee",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
pb: 1,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={() => setPage((prev) => Math.max(prev - 1, 1))}
|
||||
disabled={page === 1}
|
||||
startIcon={<ArrowBackIosNewIcon fontSize="small" />}
|
||||
sx={{ mx: 1, color: "#666" }}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<PersonAddIcon sx={{ mr: 1, color: "#0a2d6b" }} />
|
||||
<Typography
|
||||
variant="h6"
|
||||
component="span"
|
||||
sx={{ fontWeight: "bold", color: "#0a2d6b" }}
|
||||
>
|
||||
Add 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={type}
|
||||
onChange={(e) => setType(e.target.value)}
|
||||
placeholder="Appointment Type"
|
||||
required
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions sx={{ px: 3, pb: 3 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
disableElevation
|
||||
color="error"
|
||||
fullWidth
|
||||
onClick={handleSubmit}
|
||||
sx={{
|
||||
mx: 1,
|
||||
minWidth: "36px",
|
||||
backgroundColor: "#f0f0f0",
|
||||
color: "#333",
|
||||
py: 1.5,
|
||||
backgroundColor: "#ff3366",
|
||||
"&:hover": {
|
||||
backgroundColor: "#e0e0e0",
|
||||
backgroundColor: "#e61653",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{page}
|
||||
Add Appointment Type
|
||||
</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>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
import makeStyles from '@mui/styles/makeStyles';
|
||||
import { pxToRem } from '../../theme/typography';
|
||||
|
||||
export const useStyles = makeStyles((theme) => ({
|
||||
chipClass: {
|
||||
height: 'fit-content',
|
||||
minHeight: '30px',
|
||||
padding: '2px',
|
||||
alignItems: 'center',
|
||||
},
|
||||
statusColor: {
|
||||
color: theme.palette.primary.main,
|
||||
fontSize: pxToRem(10),
|
||||
},
|
||||
tabsBox: {
|
||||
display: 'flex',
|
||||
justifyContent: ' space-around',
|
||||
// width: '55%',
|
||||
marginTop: theme.spacing(0.5),
|
||||
marginRight: theme.spacing(5.0),
|
||||
alignItems: 'center',
|
||||
},
|
||||
secondaryButton: {
|
||||
width: '200px',
|
||||
height: '46px',
|
||||
borderRadius: '8px',
|
||||
justifyContent: 'space-evenly',
|
||||
fontSize: pxToRem(16),
|
||||
},
|
||||
tableActionIcons: {
|
||||
marginRight: theme.spacing(1.4),
|
||||
width: '15px',
|
||||
},
|
||||
companyNameTableColumn: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
companyName: {
|
||||
marginLeft: theme.spacing(1),
|
||||
fontSize: pxToRem(14),
|
||||
objectFit: 'contain',
|
||||
width: '260px',
|
||||
},
|
||||
companyNameLink: {
|
||||
textDecoration: 'none',
|
||||
color: theme.palette.grey[10],
|
||||
'&:hover': {
|
||||
color: theme.palette.info.main,
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
},
|
||||
companyWebsiteLabel: {
|
||||
fontSize: pxToRem(12),
|
||||
},
|
||||
companyNameLogo: {
|
||||
height: '40px',
|
||||
width: '40px',
|
||||
borderRadius: theme.shape.borderRadiusComponent,
|
||||
objectFit: 'contain',
|
||||
},
|
||||
sendEmailStatus: {
|
||||
fontSize: pxToRem(14),
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
sendEmailLastSentMailDate: {
|
||||
fontSize: pxToRem(12),
|
||||
},
|
||||
addDiscountCodeLink: {
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
addDiscountCodeLabel: {
|
||||
fontSize: pxToRem(14),
|
||||
backgroundColor: theme.palette.common.white,
|
||||
color: theme.palette.common.black,
|
||||
},
|
||||
customModel: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
},
|
||||
customModelBox: {
|
||||
paddingLeft: theme.spacing(5),
|
||||
paddingRight: theme.spacing(5),
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
// height: '100%',
|
||||
border: 'none',
|
||||
},
|
||||
newPlanTitleText: {
|
||||
fontSize: pxToRem(28),
|
||||
fontFamily: theme.fontFamily.bold,
|
||||
},
|
||||
newPlanSubTitleText: {
|
||||
fontSize: pxToRem(18),
|
||||
padding: theme.spacing(1),
|
||||
},
|
||||
addPlanSuccessIcon: {
|
||||
padding: theme.spacing(2),
|
||||
paddingTop: theme.spacing(1),
|
||||
},
|
||||
planAddedText: {
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.grey[54],
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center',
|
||||
},
|
||||
verifyIcon: {
|
||||
marginLeft: theme.spacing(0.3),
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.grey[54],
|
||||
},
|
||||
}));
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import AddIcon from "@mui/icons-material/Add";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Container,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
|
|
@ -13,113 +13,173 @@ import {
|
|||
IconButton,
|
||||
MenuItem,
|
||||
Paper,
|
||||
Snackbar,
|
||||
Alert,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Divider,
|
||||
} from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useRef, useState } from "react";
|
||||
import CustomBreadcrumbs from "../../components/CustomBreadcrumbs";
|
||||
import PageHeader from "../../components/PageHeader";
|
||||
import { useStyles } from "./paymentStyles";
|
||||
import Table from "../../components/Table";
|
||||
import { getAdmins } from "../../services/auth.services";
|
||||
import { pushNotification } from "../../utils/notification";
|
||||
import { NOTIFICATION } from "../../constants";
|
||||
import { emailRegex } from "../../utils/regex";
|
||||
import {
|
||||
createClinicOffer,
|
||||
getClinicOffer,
|
||||
} from "../../services/clinics.service";
|
||||
|
||||
const PaymentManagement = () => {
|
||||
const classes = useStyles();
|
||||
const ref = useRef(null);
|
||||
const tableRef = useRef(null);
|
||||
|
||||
// State for payment dialog
|
||||
const [paymentDialogOpen, setPaymentDialogOpen] = useState(false);
|
||||
const [paymentData, setPaymentData] = useState({
|
||||
clinicName: "",
|
||||
clinicEmail: "",
|
||||
setupFeeWaived: false,
|
||||
specialOffer: false,
|
||||
configurationMonth: 3
|
||||
configurationMonth: 3,
|
||||
});
|
||||
|
||||
|
||||
// State for payments list
|
||||
const [paymentsList, setPaymentsList] = useState([]);
|
||||
const [editPaymentIndex, setEditPaymentIndex] = useState(null);
|
||||
|
||||
// State for notification
|
||||
const [notification, setNotification] = useState({
|
||||
open: false,
|
||||
message: "",
|
||||
severity: "success",
|
||||
});
|
||||
const handleSubmit = () => {};
|
||||
|
||||
const columns = useMemo(() => [
|
||||
{
|
||||
size: 100,
|
||||
header: "Sr. No.",
|
||||
Cell: (props) => {
|
||||
const tableState = props?.table?.getState();
|
||||
const serialNumber = (
|
||||
props?.row?.index +
|
||||
1 +
|
||||
tableState?.pagination?.pageIndex * tableState?.pagination?.pageSize
|
||||
)
|
||||
?.toString()
|
||||
?.padStart(2, "0");
|
||||
return <span>{serialNumber}</span>;
|
||||
},
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
size: 260,
|
||||
accessorKey: "clinic_email",
|
||||
header: "Clinic Email",
|
||||
enableColumnFilter: false,
|
||||
},
|
||||
{
|
||||
size: 200,
|
||||
accessorKey: "setup_fees_waived",
|
||||
header: "Setup Fees Waived",
|
||||
Cell: (props) => (props.renderedCellValue ? "Yes" : "No"),
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
size: 200,
|
||||
accessorKey: "special_offer_for_month",
|
||||
header: "Special Offer For Month",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
},
|
||||
]);
|
||||
|
||||
const getData = async (filters) => {
|
||||
try {
|
||||
let params = {
|
||||
...filters,
|
||||
};
|
||||
|
||||
const resp = await getClinicOffer(params);
|
||||
console.log("API Response:", resp);
|
||||
|
||||
return {
|
||||
data: resp?.data?.data?.data,
|
||||
rowCount: resp?.data?.total || 0,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching admins:", error);
|
||||
return {
|
||||
data: [],
|
||||
rowCount: 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Handle payment dialog submission
|
||||
const handleAddPayment = () => {
|
||||
const handleAddPayment = async () => {
|
||||
// Validate input
|
||||
if (!paymentData.clinicName.trim()) {
|
||||
setNotification({
|
||||
open: true,
|
||||
message: "Please enter a clinic name",
|
||||
severity: "error",
|
||||
});
|
||||
if (!paymentData.clinicEmail.trim()) {
|
||||
pushNotification("Please enter a clinic email", NOTIFICATION.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (editPaymentIndex !== null) {
|
||||
// Update existing payment
|
||||
const updatedPayments = [...paymentsList];
|
||||
updatedPayments[editPaymentIndex] = {...paymentData};
|
||||
setPaymentsList(updatedPayments);
|
||||
|
||||
setNotification({
|
||||
open: true,
|
||||
message: "Payment configuration updated successfully",
|
||||
severity: "success",
|
||||
});
|
||||
} else {
|
||||
// Add new payment
|
||||
setPaymentsList([...paymentsList, {...paymentData}]);
|
||||
|
||||
setNotification({
|
||||
open: true,
|
||||
message: "Payment configuration added successfully",
|
||||
severity: "success",
|
||||
});
|
||||
|
||||
if (!emailRegex.test(paymentData.clinicEmail)) {
|
||||
pushNotification("Please enter a valid clinic email", NOTIFICATION.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// either setup fees waived or special offer for month should be true
|
||||
if (!paymentData.setupFeeWaived && !paymentData.specialOffer) {
|
||||
pushNotification(
|
||||
"Please select either setup fees waived or special offer for month",
|
||||
NOTIFICATION.ERROR
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
clinic_email: paymentData.clinicEmail,
|
||||
setup_fees_waived: paymentData.setupFeeWaived,
|
||||
special_offer_for_month: paymentData.specialOffer
|
||||
? paymentData.configurationMonth.toString()
|
||||
: "0",
|
||||
};
|
||||
|
||||
const resp = await createClinicOffer(payload);
|
||||
console.log("API Response:", resp);
|
||||
|
||||
// Reset form and close dialog
|
||||
setPaymentData({
|
||||
clinicName: "",
|
||||
clinicEmail: "",
|
||||
setupFeeWaived: false,
|
||||
specialOffer: false,
|
||||
configurationMonth: 3
|
||||
configurationMonth: 3,
|
||||
});
|
||||
setEditPaymentIndex(null);
|
||||
setPaymentDialogOpen(false);
|
||||
|
||||
// Refresh the table data
|
||||
if (tableRef.current) {
|
||||
tableRef.current.reFetchData();
|
||||
pushNotification("Payment configuration added successfully", NOTIFICATION.SUCCESS);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Handle edit payment
|
||||
const handleEditPayment = (index) => {
|
||||
setEditPaymentIndex(index);
|
||||
setPaymentData({...paymentsList[index]});
|
||||
setPaymentData({ ...paymentsList[index] });
|
||||
setPaymentDialogOpen(true);
|
||||
};
|
||||
|
||||
|
||||
// Handle delete payment
|
||||
const handleDeletePayment = (index) => {
|
||||
const updatedPayments = [...paymentsList];
|
||||
updatedPayments.splice(index, 1);
|
||||
setPaymentsList(updatedPayments);
|
||||
|
||||
setNotification({
|
||||
open: true,
|
||||
message: "Payment configuration deleted successfully",
|
||||
severity: "success",
|
||||
});
|
||||
};
|
||||
|
||||
// Handle notification close
|
||||
const handleCloseNotification = () => {
|
||||
setNotification({
|
||||
...notification,
|
||||
open: false,
|
||||
});
|
||||
pushNotification(
|
||||
"Payment configuration deleted successfully",
|
||||
NOTIFICATION.SUCCESS
|
||||
);
|
||||
};
|
||||
|
||||
// Breadcrumbs
|
||||
|
|
@ -129,202 +189,229 @@ const PaymentManagement = () => {
|
|||
];
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||
<PageHeader pageTitle="Payment Management" hideAddButton />
|
||||
|
||||
<CustomBreadcrumbs breadcrumbs={breadcrumbs} />
|
||||
|
||||
<Paper elevation={3} sx={{ p: 0, mb: 4, overflow: "hidden" }}>
|
||||
{/* Payment Management Header with Add Button */}
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
p: 3,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" component="h2" sx={{ fontWeight: "bold" }}>
|
||||
Payment Configurations
|
||||
</Typography>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="error"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => setPaymentDialogOpen(true)}
|
||||
sx={{
|
||||
borderRadius: 50,
|
||||
textTransform: "none",
|
||||
backgroundColor: "#ff3366",
|
||||
"&:hover": {
|
||||
backgroundColor: "#e61653",
|
||||
},
|
||||
}}
|
||||
>
|
||||
Add Payment
|
||||
</Button>
|
||||
<>
|
||||
<Box>
|
||||
<PageHeader
|
||||
pageTitle="Payment Management"
|
||||
addButtonIcon={<AddIcon />}
|
||||
onAddButtonClick={() => setPaymentDialogOpen(true)}
|
||||
/>
|
||||
<CustomBreadcrumbs breadcrumbs={breadcrumbs} />
|
||||
<Box className={classes.tableMainDiv}>
|
||||
<Box>
|
||||
<Table
|
||||
ref={tableRef}
|
||||
hideTopToolbar
|
||||
columns={columns}
|
||||
getData={getData}
|
||||
options={{
|
||||
enableRowSelection: true,
|
||||
showTopBar: false,
|
||||
showFilters: true,
|
||||
}}
|
||||
searchText="Staff"
|
||||
showSearchBox={true}
|
||||
actions={[
|
||||
{
|
||||
onClick: (row) => handleEditPayment(row),
|
||||
text: "Edit",
|
||||
icon: <EditIcon />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Payment List Table */}
|
||||
<TableContainer>
|
||||
<Table sx={{ minWidth: 650 }} aria-label="payment table">
|
||||
<TableHead sx={{ backgroundColor: "#f5f5f5" }}>
|
||||
<TableRow>
|
||||
<TableCell sx={{ fontWeight: "bold" }}>Clinic Name</TableCell>
|
||||
<TableCell sx={{ fontWeight: "bold" }}>Setup Fee Waived</TableCell>
|
||||
<TableCell sx={{ fontWeight: "bold" }}>Special Offer</TableCell>
|
||||
<TableCell sx={{ fontWeight: "bold" }}>Configuration Month</TableCell>
|
||||
<TableCell sx={{ fontWeight: "bold" }}>Actions</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{paymentsList.length > 0 ? (
|
||||
paymentsList.map((payment, index) => (
|
||||
<TableRow key={index}>
|
||||
<TableCell>{payment.clinicName}</TableCell>
|
||||
<TableCell>{payment.setupFeeWaived ? "Yes" : "No"}</TableCell>
|
||||
<TableCell>{payment.specialOffer ? "Yes" : "No"}</TableCell>
|
||||
<TableCell>
|
||||
{payment.specialOffer ? payment.configurationMonth : "-"}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
size="small"
|
||||
color="primary"
|
||||
onClick={() => handleEditPayment(index)}
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
color="error"
|
||||
onClick={() => handleDeletePayment(index)}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={5} align="center">
|
||||
No payment configurations found
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Paper>
|
||||
|
||||
{/* Payment Dialog */}
|
||||
<Dialog
|
||||
open={paymentDialogOpen}
|
||||
onClose={() => setPaymentDialogOpen(false)}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle>
|
||||
{editPaymentIndex !== null ? "Edit Payment" : "Add New Payment"}
|
||||
<IconButton
|
||||
aria-label="close"
|
||||
onClick={() => setPaymentDialogOpen(false)}
|
||||
{/* Improved Dialog Box */}
|
||||
<Dialog
|
||||
open={paymentDialogOpen}
|
||||
onClose={() => setPaymentDialogOpen(false)}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
PaperProps={{
|
||||
sx: {
|
||||
borderRadius: "12px",
|
||||
overflow: "hidden",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DialogTitle
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
right: 8,
|
||||
top: 8,
|
||||
color: (theme) => theme.palette.grey[500],
|
||||
padding: "16px 24px",
|
||||
backgroundColor: (theme) => theme.palette.primary.main,
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin="dense"
|
||||
id="clinicName"
|
||||
label="Clinic Name"
|
||||
type="text"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={paymentData.clinicName}
|
||||
onChange={(e) => setPaymentData({...paymentData, clinicName: e.target.value})}
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={paymentData.setupFeeWaived}
|
||||
onChange={(e) => setPaymentData({...paymentData, setupFeeWaived: e.target.checked})}
|
||||
/>
|
||||
}
|
||||
label="Setup fee waived"
|
||||
sx={{ mb: 1 }}
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={paymentData.specialOffer}
|
||||
onChange={(e) => setPaymentData({...paymentData, specialOffer: e.target.checked})}
|
||||
/>
|
||||
}
|
||||
label="Special Offer: First 3 months free"
|
||||
sx={{ mb: 1 }}
|
||||
/>
|
||||
|
||||
{paymentData.specialOffer && (
|
||||
{editPaymentIndex !== null
|
||||
? "Edit Payment Configuration"
|
||||
: "Add New Payment"}
|
||||
<IconButton
|
||||
aria-label="close"
|
||||
onClick={() => setPaymentDialogOpen(false)}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
right: 8,
|
||||
top: 8,
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent sx={{ padding: "24px 24px 16px" }}>
|
||||
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 1 }}>
|
||||
<Typography variant="subtitle2" gutterBottom sx={{ mb: 1 }}>
|
||||
Clinic Information
|
||||
</Typography>
|
||||
|
||||
<TextField
|
||||
select
|
||||
autoFocus
|
||||
margin="dense"
|
||||
id="configurationMonth"
|
||||
label="Configuration Month"
|
||||
id="clinicEmail"
|
||||
label="Clinic Email"
|
||||
type="text"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={paymentData.configurationMonth}
|
||||
onChange={(e) => setPaymentData({...paymentData, configurationMonth: e.target.value})}
|
||||
sx={{ mt: 1 }}
|
||||
>
|
||||
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map((month) => (
|
||||
<MenuItem key={month} value={month}>
|
||||
{month}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
)}
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setPaymentDialogOpen(false)} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleAddPayment} variant="contained" color="primary">
|
||||
Save
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
value={paymentData.clinicEmail}
|
||||
onChange={(e) =>
|
||||
setPaymentData({
|
||||
...paymentData,
|
||||
clinicEmail: e.target.value,
|
||||
})
|
||||
}
|
||||
sx={{ mb: 3 }}
|
||||
/>
|
||||
|
||||
{/* Notification Snackbar */}
|
||||
<Snackbar
|
||||
open={notification.open}
|
||||
autoHideDuration={6000}
|
||||
onClose={handleCloseNotification}
|
||||
anchorOrigin={{ vertical: "top", horizontal: "right" }}
|
||||
>
|
||||
<Alert
|
||||
onClose={handleCloseNotification}
|
||||
severity={notification.severity}
|
||||
sx={{ width: "100%" }}
|
||||
>
|
||||
{notification.message}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
</Container>
|
||||
<Typography variant="subtitle2" gutterBottom sx={{ mb: 1 }}>
|
||||
Payment Options
|
||||
</Typography>
|
||||
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
backgroundColor: (theme) => theme.palette.grey[50],
|
||||
p: 2,
|
||||
mb: 2,
|
||||
border: "1px solid",
|
||||
borderColor: (theme) => theme.palette.grey[200],
|
||||
borderRadius: "8px",
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={paymentData.setupFeeWaived}
|
||||
onChange={(e) =>
|
||||
setPaymentData({
|
||||
...paymentData,
|
||||
setupFeeWaived: e.target.checked,
|
||||
})
|
||||
}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Box>
|
||||
<Typography variant="body1">Setup fee waived</Typography>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
No initial setup fee will be charged
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
sx={{ mb: 1, display: "flex", alignItems: "flex-start" }}
|
||||
/>
|
||||
|
||||
<Divider sx={{ my: 1.5 }} />
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={paymentData.specialOffer}
|
||||
onChange={(e) =>
|
||||
setPaymentData({
|
||||
...paymentData,
|
||||
specialOffer: e.target.checked,
|
||||
})
|
||||
}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Box>
|
||||
<Typography variant="body1">Special Offer</Typography>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
First 3 months free of charge
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
sx={{ display: "flex", alignItems: "flex-start" }}
|
||||
/>
|
||||
</Paper>
|
||||
|
||||
{paymentData.specialOffer && (
|
||||
<TextField
|
||||
select
|
||||
margin="dense"
|
||||
id="configurationMonth"
|
||||
label="Configuration Month"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={paymentData.configurationMonth}
|
||||
onChange={(e) =>
|
||||
setPaymentData({
|
||||
...paymentData,
|
||||
configurationMonth: parseInt(e.target.value),
|
||||
})
|
||||
}
|
||||
sx={{ mt: 1 }}
|
||||
helperText="Number of months for special configuration"
|
||||
>
|
||||
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map((month) => (
|
||||
<MenuItem key={month} value={month}>
|
||||
{month} {month === 1 ? "month" : "months"}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
)}
|
||||
</Box>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions
|
||||
sx={{
|
||||
padding: "16px 24px",
|
||||
borderTop: "1px solid",
|
||||
borderColor: (theme) => theme.palette.grey[200],
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={() => setPaymentDialogOpen(false)}
|
||||
sx={{
|
||||
color: (theme) => theme.palette.grey[700],
|
||||
fontWeight: "medium",
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleAddPayment}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
sx={{
|
||||
borderRadius: "8px",
|
||||
px: 3,
|
||||
}}
|
||||
>
|
||||
{editPaymentIndex !== null ? "Update" : "Save"}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PaymentManagement;
|
||||
export default PaymentManagement;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
import makeStyles from '@mui/styles/makeStyles';
|
||||
import { pxToRem } from '../../theme/typography';
|
||||
|
||||
export const useStyles = makeStyles((theme) => ({
|
||||
chipClass: {
|
||||
height: 'fit-content',
|
||||
minHeight: '30px',
|
||||
padding: '2px',
|
||||
alignItems: 'center',
|
||||
},
|
||||
statusColor: {
|
||||
color: theme.palette.primary.main,
|
||||
fontSize: pxToRem(10),
|
||||
},
|
||||
tabsBox: {
|
||||
display: 'flex',
|
||||
justifyContent: ' space-around',
|
||||
// width: '55%',
|
||||
marginTop: theme.spacing(0.5),
|
||||
marginRight: theme.spacing(5.0),
|
||||
alignItems: 'center',
|
||||
},
|
||||
secondaryButton: {
|
||||
width: '200px',
|
||||
height: '46px',
|
||||
borderRadius: '8px',
|
||||
justifyContent: 'space-evenly',
|
||||
fontSize: pxToRem(16),
|
||||
},
|
||||
tableActionIcons: {
|
||||
marginRight: theme.spacing(1.4),
|
||||
width: '15px',
|
||||
},
|
||||
companyNameTableColumn: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
companyName: {
|
||||
marginLeft: theme.spacing(1),
|
||||
fontSize: pxToRem(14),
|
||||
objectFit: 'contain',
|
||||
width: '260px',
|
||||
},
|
||||
companyNameLink: {
|
||||
textDecoration: 'none',
|
||||
color: theme.palette.grey[10],
|
||||
'&:hover': {
|
||||
color: theme.palette.info.main,
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
},
|
||||
companyWebsiteLabel: {
|
||||
fontSize: pxToRem(12),
|
||||
},
|
||||
companyNameLogo: {
|
||||
height: '40px',
|
||||
width: '40px',
|
||||
borderRadius: theme.shape.borderRadiusComponent,
|
||||
objectFit: 'contain',
|
||||
},
|
||||
sendEmailStatus: {
|
||||
fontSize: pxToRem(14),
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
sendEmailLastSentMailDate: {
|
||||
fontSize: pxToRem(12),
|
||||
},
|
||||
addDiscountCodeLink: {
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
addDiscountCodeLabel: {
|
||||
fontSize: pxToRem(14),
|
||||
backgroundColor: theme.palette.common.white,
|
||||
color: theme.palette.common.black,
|
||||
},
|
||||
customModel: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
},
|
||||
customModelBox: {
|
||||
paddingLeft: theme.spacing(5),
|
||||
paddingRight: theme.spacing(5),
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
// height: '100%',
|
||||
border: 'none',
|
||||
},
|
||||
newPlanTitleText: {
|
||||
fontSize: pxToRem(28),
|
||||
fontFamily: theme.fontFamily.bold,
|
||||
},
|
||||
newPlanSubTitleText: {
|
||||
fontSize: pxToRem(18),
|
||||
padding: theme.spacing(1),
|
||||
},
|
||||
addPlanSuccessIcon: {
|
||||
padding: theme.spacing(2),
|
||||
paddingTop: theme.spacing(1),
|
||||
},
|
||||
planAddedText: {
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.grey[54],
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center',
|
||||
},
|
||||
verifyIcon: {
|
||||
marginLeft: theme.spacing(0.3),
|
||||
fontSize: pxToRem(12),
|
||||
color: theme.palette.grey[54],
|
||||
},
|
||||
}));
|
||||
|
|
@ -1,28 +1,15 @@
|
|||
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,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
|
|
@ -32,12 +19,10 @@ import PageHeader from "../../components/PageHeader";
|
|||
import { createAdmin, getAdmins } from "../../services/auth.services";
|
||||
import { pushNotification } from "../../utils/notification";
|
||||
import { NOTIFICATION } from "../../constants";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useStyles } from "./staffStyles";
|
||||
import Table from "../../components/Table";
|
||||
|
||||
const StaffManagement = () => {
|
||||
const theme = useTheme();
|
||||
const classes = useStyles();
|
||||
const ref = useRef(null);
|
||||
// State for form fields
|
||||
|
|
@ -46,26 +31,9 @@ const StaffManagement = () => {
|
|||
const [email, setEmail] = useState("");
|
||||
const [emailError, setEmailError] = useState("");
|
||||
|
||||
// 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",
|
||||
});
|
||||
|
||||
// Email validation function
|
||||
const validateEmail = (email) => {
|
||||
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
|
|
@ -113,14 +81,6 @@ const StaffManagement = () => {
|
|||
handleCloseDialog();
|
||||
};
|
||||
|
||||
// Handle notification close
|
||||
const handleCloseNotification = () => {
|
||||
setNotification({
|
||||
...notification,
|
||||
open: false,
|
||||
});
|
||||
};
|
||||
|
||||
const getData = async (filters) => {
|
||||
try {
|
||||
// Remove the type parameter since it's not defined
|
||||
|
|
|
|||
Loading…
Reference in New Issue