feat: pr changes
This commit is contained in:
parent
d9db46abca
commit
4717c67cca
|
|
@ -7,11 +7,11 @@ import {
|
|||
Select,
|
||||
TextField,
|
||||
Tooltip,
|
||||
} from '@mui/material';
|
||||
import {MaterialReactTable} from 'material-react-table';
|
||||
import PreviousIcon from '@mui/icons-material/ArrowBack';
|
||||
import NextIcon from '@mui/icons-material/ArrowForward';
|
||||
import PropTypes from 'prop-types';
|
||||
} from "@mui/material";
|
||||
import { MaterialReactTable } from "material-react-table";
|
||||
import PreviousIcon from "@mui/icons-material/ArrowBack";
|
||||
import NextIcon from "@mui/icons-material/ArrowForward";
|
||||
import PropTypes from "prop-types";
|
||||
import React, {
|
||||
forwardRef,
|
||||
memo,
|
||||
|
|
@ -20,17 +20,17 @@ import React, {
|
|||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Pagination from '@mui/material/Pagination';
|
||||
import PaginationItem from '@mui/material/PaginationItem';
|
||||
import { debounce } from 'lodash';
|
||||
import { ExpandMore } from '@mui/icons-material';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
} from "react";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Pagination from "@mui/material/Pagination";
|
||||
import PaginationItem from "@mui/material/PaginationItem";
|
||||
import { debounce } from "lodash";
|
||||
import { ExpandMore } from "@mui/icons-material";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { useStyles } from './styles/tableStyles';
|
||||
import ProtectedComponent from '../components/ProtectedComponent';
|
||||
import { useStyles } from "./styles/tableStyles";
|
||||
import ProtectedComponent from "../components/ProtectedComponent";
|
||||
|
||||
const Table = memo(
|
||||
forwardRef((props, ref) => {
|
||||
|
|
@ -54,31 +54,13 @@ const Table = memo(
|
|||
navigateTo,
|
||||
} = props;
|
||||
const [data, setData] = useState([]);
|
||||
const [formattedColumns, setFormattedColumns] = useState(
|
||||
columns.map((column, i) => {
|
||||
if (i === 0) {
|
||||
return {
|
||||
...column,
|
||||
muiTableBodyCellProps: {
|
||||
sx: (theme) => ({
|
||||
opacity: 1,
|
||||
fontWeight: 600,
|
||||
fontSize: '16px',
|
||||
fontFamily: theme.fontFamily.semiBold,
|
||||
color: theme.palette.grey[10],
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
return column;
|
||||
})
|
||||
);
|
||||
const [formattedColumns, setFormattedColumns] = useState([]);
|
||||
const [isError, setIsError] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isRefetching, setIsRefetching] = useState(false);
|
||||
const [rowCount, setRowCount] = useState(0);
|
||||
const [columnFilters, setColumnFilters] = useState([]);
|
||||
const [globalFilter, setGlobalFilter] = useState('');
|
||||
const [globalFilter, setGlobalFilter] = useState("");
|
||||
const [sorting, setSorting] = useState([]);
|
||||
const tableRef = useRef();
|
||||
const [pagination, setPagination] = useState({
|
||||
|
|
@ -111,26 +93,46 @@ const Table = memo(
|
|||
},
|
||||
}));
|
||||
useEffect(() => {
|
||||
// Process columns and add any action columns that have a render function
|
||||
const processedColumns = [...columns];
|
||||
|
||||
// Add action columns with render functions
|
||||
if (actions && actions.length > 0) {
|
||||
actions.forEach((action) => {
|
||||
if (action.render && action.field) {
|
||||
processedColumns.push({
|
||||
accessorKey: action.field,
|
||||
header: action.title || "",
|
||||
Cell: ({ row }) => action.render(row.original),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setFormattedColumns(
|
||||
columns.map((column, i) => {
|
||||
processedColumns.map((column, i) => {
|
||||
if (column.isBold) {
|
||||
return {
|
||||
...column,
|
||||
muiTableBodyCellProps: {
|
||||
sx: (theme) => ({
|
||||
Cell: ({ cell }) => (
|
||||
<Typography
|
||||
sx={(theme) => ({
|
||||
opacity: 1,
|
||||
fontWeight: 600,
|
||||
fontSize: '16px',
|
||||
fontSize: "16px",
|
||||
fontFamily: theme.fontFamily.semiBold,
|
||||
color: theme.palette.grey[10],
|
||||
}),
|
||||
},
|
||||
})}
|
||||
>
|
||||
{cell.getValue()}
|
||||
</Typography>
|
||||
),
|
||||
};
|
||||
}
|
||||
return column;
|
||||
})
|
||||
);
|
||||
}, [columns]);
|
||||
}, [columns, actions]);
|
||||
|
||||
const fetchData = async () => {
|
||||
if (!data.length) {
|
||||
|
|
@ -138,15 +140,15 @@ const Table = memo(
|
|||
} else {
|
||||
setIsRefetching(true);
|
||||
}
|
||||
let filterString = '';
|
||||
let filterString = "";
|
||||
columnFilters.forEach((filter) => {
|
||||
filterString += `${filter.id}=${filter.value}&`;
|
||||
});
|
||||
let sortingString = sorting
|
||||
.map(
|
||||
(sort) => `orderBy=${sort.id}&order=${sort.desc ? 'DESC' : 'ASC'}&`
|
||||
(sort) => `orderBy=${sort.id}&order=${sort.desc ? "DESC" : "ASC"}&`
|
||||
)
|
||||
.join('');
|
||||
.join("");
|
||||
try {
|
||||
const response = await getData({
|
||||
pagination,
|
||||
|
|
@ -222,11 +224,6 @@ const Table = memo(
|
|||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{/* <img
|
||||
src={SearchFieldIcon}
|
||||
alt="search icon"
|
||||
className={classes.searchIconImg}
|
||||
/> */}
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
|
|
@ -256,29 +253,26 @@ const Table = memo(
|
|||
<CustomPagination table={props.table} />
|
||||
)}
|
||||
muiTableBodyCellProps={{
|
||||
// className: classes?.muiTableBodyCell,
|
||||
sx: (theme) => ({
|
||||
opacity: '1',
|
||||
// lineHeight: '2.5rem',
|
||||
opacity: "1",
|
||||
margin: theme.spacing(1),
|
||||
fontWeight: 500,
|
||||
fontSize: '16px',
|
||||
fontStretch: 'normal',
|
||||
fontStyle: 'normal',
|
||||
letterSpacing: 'normal',
|
||||
fontSize: "16px",
|
||||
fontStretch: "normal",
|
||||
fontStyle: "normal",
|
||||
letterSpacing: "normal",
|
||||
fontFamily: theme.fontFamily.medium,
|
||||
color: theme.palette.grey[22],
|
||||
// textAlign: 'center',
|
||||
textAlign: 'left',
|
||||
textAlign: "left",
|
||||
}),
|
||||
}}
|
||||
muiTopToolbarProps={{
|
||||
sx: (theme) => ({
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
'& div': {
|
||||
'& div': {
|
||||
'& .MuiIconButton-sizeMedium': {
|
||||
display: 'none',
|
||||
"& div": {
|
||||
"& div": {
|
||||
"& .MuiIconButton-sizeMedium": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -288,6 +282,16 @@ const Table = memo(
|
|||
renderTopToolbar={false}
|
||||
muiTableHeadCellProps={{
|
||||
className: classes?.muiTableHeadCell,
|
||||
sx: {
|
||||
// Fix for extra space in header cells
|
||||
padding: "16px 8px",
|
||||
whiteSpace: "nowrap",
|
||||
justifyContent: "flex-start",
|
||||
'& .MuiTableSortLabel-root': {
|
||||
width: '100%',
|
||||
justifyContent: 'flex-start',
|
||||
}
|
||||
}
|
||||
}}
|
||||
enableRowNumbers={enableRowNumbers}
|
||||
rowNumberMode={rowNumberMode}
|
||||
|
|
@ -296,15 +300,15 @@ const Table = memo(
|
|||
sx: (theme) => ({
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: theme.palette.common.white,
|
||||
boxShadow: 'none',
|
||||
'& .MuiTableContainer-root': {
|
||||
border: '0px solid',
|
||||
borderRadius: '16px',
|
||||
boxShadow: "none",
|
||||
"& .MuiTableContainer-root": {
|
||||
border: "0px solid",
|
||||
borderRadius: "16px",
|
||||
},
|
||||
}),
|
||||
}}
|
||||
muiTableHeadCellFilterTextFieldProps={{
|
||||
variant: 'outlined',
|
||||
variant: "outlined",
|
||||
}}
|
||||
muiTableBodyProps={{
|
||||
sx: (theme) => ({
|
||||
|
|
@ -328,12 +332,12 @@ const Table = memo(
|
|||
muiToolbarAlertBannerProps={
|
||||
isError
|
||||
? {
|
||||
color: 'error',
|
||||
children: 'Error loading data',
|
||||
color: "error",
|
||||
children: "Error loading data",
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
positionToolbarAlertBanner={'none'}
|
||||
positionToolbarAlertBanner={"none"}
|
||||
onColumnFiltersChange={setColumnFilters}
|
||||
onGlobalFilterChange={setGlobalFilter}
|
||||
onPaginationChange={setPagination}
|
||||
|
|
@ -351,16 +355,16 @@ const Table = memo(
|
|||
className: classes?.tableHeadRow,
|
||||
}}
|
||||
displayColumnDefOptions={{
|
||||
'mrt-row-actions': {
|
||||
header: '',
|
||||
"mrt-row-actions": {
|
||||
header: "",
|
||||
},
|
||||
}}
|
||||
muiTableBodyRowProps={({ row }) => ({
|
||||
onClick: (event) => {
|
||||
if (
|
||||
Object.values(event.target)?.[1]
|
||||
?.className?.split(' ')
|
||||
.includes('MuiBackdrop-root')
|
||||
?.className?.split(" ")
|
||||
.includes("MuiBackdrop-root")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -378,74 +382,67 @@ const Table = memo(
|
|||
muiSelectAllCheckboxProps={{
|
||||
className: classes?.tableCheckbox,
|
||||
}}
|
||||
renderRowActionMenuItems={({ row, closeMenu }) =>
|
||||
actions?.map((action, index) =>
|
||||
!(action?.renderAction?.(row) ?? true) ? null : (
|
||||
<ProtectedComponent
|
||||
key={index}
|
||||
permission={action.permissionName}
|
||||
>
|
||||
{(action?.icon ||
|
||||
action?.text ||
|
||||
(action?.textFn && action?.textFn(row))) && (
|
||||
<MenuItem
|
||||
className={classes.menuItem}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
action.onClick(row);
|
||||
closeMenu();
|
||||
}}
|
||||
disabled={
|
||||
action?.isDisabledValue
|
||||
? action?.isDisabledValue ===
|
||||
row?.original?.[action?.rowKey]
|
||||
: false
|
||||
}
|
||||
>
|
||||
{action?.icon} {action?.text}{' '}
|
||||
{action.textFn && action.textFn(row)}
|
||||
</MenuItem>
|
||||
)}
|
||||
</ProtectedComponent>
|
||||
)
|
||||
) ?? []
|
||||
}
|
||||
// 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
|
||||
.getSelectedRowModel()
|
||||
.flatRows.map((row) => row?.original);
|
||||
return handleBulkAction('ACTIVE', data);
|
||||
return handleBulkAction("ACTIVE", data);
|
||||
};
|
||||
const handleDelete = () => {
|
||||
const data = table
|
||||
.getSelectedRowModel()
|
||||
.flatRows.map((row) => row?.original);
|
||||
return handleBulkAction('DELETE', data, table);
|
||||
return handleBulkAction("DELETE", data, table);
|
||||
};
|
||||
const handleDownload = () => {
|
||||
const data = table
|
||||
.getSelectedRowModel()
|
||||
.flatRows.map((row) => row?.original);
|
||||
return handleBulkAction('DOWNLOAD', data);
|
||||
return handleBulkAction("DOWNLOAD", data);
|
||||
};
|
||||
return table.getIsSomeRowsSelected() ||
|
||||
table.getIsAllRowsSelected() ? (
|
||||
<Box
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Tooltip title="Change Status">
|
||||
<Box
|
||||
component="img"
|
||||
src={inactive}
|
||||
// Replace with actual image path or icon component
|
||||
// src={inactive}
|
||||
style={{
|
||||
marginLeft: '5px',
|
||||
cursor: 'pointer',
|
||||
marginTop: '8px',
|
||||
marginLeft: "5px",
|
||||
cursor: "pointer",
|
||||
marginTop: "8px",
|
||||
}}
|
||||
onClick={handleActive}
|
||||
/>
|
||||
|
|
@ -453,11 +450,11 @@ const Table = memo(
|
|||
<Tooltip title="Delete">
|
||||
<Box
|
||||
component="img"
|
||||
src={deleteIcon}
|
||||
// src={deleteIcon}
|
||||
style={{
|
||||
marginLeft: '24px',
|
||||
cursor: 'pointer',
|
||||
marginTop: '8px',
|
||||
marginLeft: "24px",
|
||||
cursor: "pointer",
|
||||
marginTop: "8px",
|
||||
}}
|
||||
onClick={handleDelete}
|
||||
/>
|
||||
|
|
@ -466,12 +463,12 @@ const Table = memo(
|
|||
<Tooltip title="Download Report">
|
||||
<Box
|
||||
component="img"
|
||||
src={downloadActivity}
|
||||
// src={downloadActivity}
|
||||
style={{
|
||||
marginLeft: '24px',
|
||||
cursor: 'pointer',
|
||||
marginTop: '9px',
|
||||
height: '20px',
|
||||
marginLeft: "24px",
|
||||
cursor: "pointer",
|
||||
marginTop: "9px",
|
||||
height: "20px",
|
||||
}}
|
||||
onClick={handleDownload}
|
||||
/>
|
||||
|
|
@ -483,7 +480,7 @@ const Table = memo(
|
|||
);
|
||||
}}
|
||||
muiTablePaginationProps={{
|
||||
labelRowsPerPage: 'Records Per Page',
|
||||
labelRowsPerPage: "Records Per Page",
|
||||
}}
|
||||
tableInstanceRef={tableRef}
|
||||
state={{
|
||||
|
|
@ -548,9 +545,9 @@ const CustomPagination = ({ table }) => {
|
|||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: { xs: 'column', md: 'row' },
|
||||
alignItems: 'center',
|
||||
display: "flex",
|
||||
flexDirection: { xs: "column", md: "row" },
|
||||
alignItems: "center",
|
||||
padding: 2,
|
||||
}}
|
||||
>
|
||||
|
|
@ -562,7 +559,7 @@ const CustomPagination = ({ table }) => {
|
|||
boundaryCount={3}
|
||||
onChange={(event, page) => setPageIndex(page - 1)}
|
||||
renderItem={(item) => {
|
||||
if (item.type === 'previous') {
|
||||
if (item.type === "previous") {
|
||||
return (
|
||||
<PaginationItem
|
||||
component={() => (
|
||||
|
|
@ -572,13 +569,13 @@ const CustomPagination = ({ table }) => {
|
|||
disabled={currentPage === 1}
|
||||
onClick={() => previousPage()}
|
||||
>
|
||||
<PreviousIcon style={{ marginRight: '6px' }} />
|
||||
<PreviousIcon style={{ marginRight: "6px" }} />
|
||||
Previous
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
} else if (item.type === 'next') {
|
||||
} else if (item.type === "next") {
|
||||
return (
|
||||
<PaginationItem
|
||||
component={() => (
|
||||
|
|
@ -589,7 +586,7 @@ const CustomPagination = ({ table }) => {
|
|||
onClick={() => nextPage()}
|
||||
>
|
||||
Next
|
||||
<NextIcon style={{ marginLeft: '6px' }} />
|
||||
<NextIcon style={{ marginLeft: "6px" }} />
|
||||
</Button>
|
||||
)}
|
||||
disabled={currentPage === totalPage}
|
||||
|
|
@ -600,19 +597,19 @@ const CustomPagination = ({ table }) => {
|
|||
}
|
||||
}}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
flex: '1',
|
||||
'& .MuiPagination-ul': {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
cursor: 'pointer',
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
flex: "1",
|
||||
"& .MuiPagination-ul": {
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
cursor: "pointer",
|
||||
},
|
||||
'& .MuiPagination-ul > :first-child': {
|
||||
marginRight: 'auto',
|
||||
"& .MuiPagination-ul > :first-child": {
|
||||
marginRight: "auto",
|
||||
},
|
||||
' & .MuiPagination-ul > :last-child': {
|
||||
marginLeft: 'auto',
|
||||
" & .MuiPagination-ul > :last-child": {
|
||||
marginLeft: "auto",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import PeopleOutlineIcon from '@mui/icons-material/PeopleOutline';
|
|||
import PeopleIcon from '@mui/icons-material/People';
|
||||
import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
import MedicationIcon from '@mui/icons-material/Medication';
|
||||
import MedicationOutlinedIcon from '@mui/icons-material/MedicationOutlined';
|
||||
import ArticleIcon from '@mui/icons-material/Article';
|
||||
import ArticleOutlinedIcon from '@mui/icons-material/ArticleOutlined';
|
||||
import TopicIcon from '@mui/icons-material/Topic';
|
||||
import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
|
||||
|
||||
import { USER_ROLES } from '../../../redux/userRoleSlice';
|
||||
|
||||
|
|
@ -40,6 +40,14 @@ export const SIDEBAR_CONFIG = [
|
|||
// Only super admin can access admin staff management
|
||||
roles: [USER_ROLES.SUPER_ADMIN]
|
||||
},
|
||||
{
|
||||
text: 'Master Data Management',
|
||||
path: 'masterData',
|
||||
icon: SettingsOutlinedIcon,
|
||||
activeIcon: SettingsIcon,
|
||||
// Only super admin can access admin staff management
|
||||
roles: [USER_ROLES.SUPER_ADMIN]
|
||||
},
|
||||
{
|
||||
text: 'Doctor/Nurse Management',
|
||||
path: 'doctor',
|
||||
|
|
@ -67,4 +75,13 @@ export const SIDEBAR_CONFIG = [
|
|||
// Clinic admin can access call transcripts
|
||||
roles: [USER_ROLES.CLINIC_ADMIN]
|
||||
},
|
||||
{
|
||||
text: 'Contract Management',
|
||||
path: 'contractManagement',
|
||||
requireSaprateApp: false,
|
||||
icon: TopicOutlinedIcon,
|
||||
activeIcon: TopicIcon,
|
||||
// Clinic admin can access contract management
|
||||
roles: [USER_ROLES.CLINIC_ADMIN]
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
export const userDataMock = {
|
||||
data: {
|
||||
records: [
|
||||
{
|
||||
id: 1,
|
||||
name: "test",
|
||||
email: "test@gmail.com",
|
||||
userType: "Manager",
|
||||
specialities: "Doctor",
|
||||
createdAt: "2025-01-01",
|
||||
status: "Active",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "John Doe",
|
||||
email: "johndoe@example.com",
|
||||
userType: "Employee",
|
||||
specialities: "Engineer",
|
||||
createdAt: "2024-11-15",
|
||||
status: "Inactive",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Jane Smith",
|
||||
email: "janesmith@example.com",
|
||||
userType: "Admin",
|
||||
specialities: "Manager",
|
||||
createdAt: "2024-12-01",
|
||||
status: "Active",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Alice Brown",
|
||||
email: "alicebrown@example.com",
|
||||
userType: "Manager",
|
||||
specialities: "HR",
|
||||
createdAt: "2023-06-22",
|
||||
status: "Active",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Bob Green",
|
||||
email: "bobgreen@example.com",
|
||||
userType: "Employee",
|
||||
specialities: "Software Developer",
|
||||
createdAt: "2024-09-10",
|
||||
status: "Active",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Charlie Black",
|
||||
email: "charlieblack@example.com",
|
||||
userType: "Admin",
|
||||
specialities: "IT Support",
|
||||
createdAt: "2023-07-05",
|
||||
status: "Inactive",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Eve White",
|
||||
email: "evewhite@example.com",
|
||||
userType: "Manager",
|
||||
specialities: "Finance",
|
||||
createdAt: "2025-03-30",
|
||||
status: "Active",
|
||||
},
|
||||
],
|
||||
totalCount: 7,
|
||||
},
|
||||
message: "Companies retrieved successfully",
|
||||
error: "",
|
||||
};
|
||||
|
|
@ -10,6 +10,8 @@ import MockPayment from "../views/MockPayment";
|
|||
import Users from "../views/User";
|
||||
import ClinicSetup from "../views/ClinicSetup";
|
||||
import ClinicTranscripts from "../views/ClinicTranscripts";
|
||||
import ContractManagement from "../views/ContractManagement";
|
||||
import MasterDataManagement from "../views/MasterData";
|
||||
|
||||
export const routesData = [
|
||||
{
|
||||
|
|
@ -23,6 +25,8 @@ export const routesData = [
|
|||
{ path: "/doctor", component: Users },
|
||||
{ path: "/clinicSetup", component: ClinicSetup },
|
||||
{ path: "/transcripts", component: ClinicTranscripts },
|
||||
{ path: "/contractManagement", component: ContractManagement },
|
||||
{ path: "/masterData", component: MasterDataManagement },
|
||||
],
|
||||
isProtected: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,24 +1,30 @@
|
|||
import { axiosInstance } from '../config/api';
|
||||
import { axiosInstance } from "../config/api";
|
||||
import { userDataMock } from "../mock/users";
|
||||
|
||||
// export const getUsers = (params) => {
|
||||
// let searchParams = new URLSearchParams();
|
||||
// searchParams.append('size', params?.pagination?.pageSize ?? 10);
|
||||
// searchParams.append('page', params?.pagination.pageIndex ?? 0);
|
||||
// if (params?.globalFilter) searchParams.append('search', params?.globalFilter);
|
||||
// if (params?.sortingString) {
|
||||
// const sortingParams = new URLSearchParams(params.sortingString);
|
||||
// sortingParams.forEach((value, key) => {
|
||||
// searchParams.append(key, value);
|
||||
// });
|
||||
// }
|
||||
|
||||
// let url = `/users?${searchParams.toString()}`;
|
||||
// return new Promise((resolve, reject) => {
|
||||
// axiosInstance
|
||||
// .get(url)
|
||||
// .then((response) => resolve(response?.data))
|
||||
// .catch((err) => reject(err));
|
||||
// });
|
||||
// };
|
||||
|
||||
export const getUsers = (params) => {
|
||||
let searchParams = new URLSearchParams();
|
||||
searchParams.append('size', params?.pagination?.pageSize ?? 10);
|
||||
searchParams.append('page', params?.pagination.pageIndex ?? 0);
|
||||
if (params?.globalFilter) searchParams.append('search', params?.globalFilter);
|
||||
if (params?.sortingString) {
|
||||
const sortingParams = new URLSearchParams(params.sortingString);
|
||||
sortingParams.forEach((value, key) => {
|
||||
searchParams.append(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
let url = `/users?${searchParams.toString()}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((response) => resolve(response?.data))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
const data = userDataMock;
|
||||
return data
|
||||
};
|
||||
|
||||
export const getUserById = (id) => {
|
||||
|
|
@ -37,43 +43,43 @@ export const getRoles = ({ page }) =>
|
|||
data: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Adult Immunisation',
|
||||
name: "Adult Immunisation",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Allied health',
|
||||
name: "Allied health",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Assist',
|
||||
name: "Assist",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Care plan',
|
||||
name: "Care plan",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Care plan reviews',
|
||||
name: "Care plan reviews",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Cervical Screening',
|
||||
name: "Cervical Screening",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Child Immunisation',
|
||||
name: "Child Immunisation",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Health assessments',
|
||||
name: "Health assessments",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: 'Mental Health Care Plans (MHCP)',
|
||||
name: "Mental Health Care Plans (MHCP)",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: 'Travel Immunisation',
|
||||
name: "Travel Immunisation",
|
||||
},
|
||||
],
|
||||
// },
|
||||
|
|
@ -88,7 +94,7 @@ export const getRoles = ({ page }) =>
|
|||
// });
|
||||
|
||||
export const addUser = (data) => {
|
||||
const url = '/users';
|
||||
const url = "/users";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
|
|
@ -149,7 +155,7 @@ export const logout = () => {
|
|||
};
|
||||
|
||||
export const changePassword = (data) => {
|
||||
const url = '/users/me/password';
|
||||
const url = "/users/me/password";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
|
|
@ -158,7 +164,7 @@ export const changePassword = (data) => {
|
|||
});
|
||||
};
|
||||
export const updateMailersSettings = (data) => {
|
||||
const url = '/users/me/mail-notification';
|
||||
const url = "/users/me/mail-notification";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
|
|
@ -168,7 +174,7 @@ export const updateMailersSettings = (data) => {
|
|||
};
|
||||
|
||||
export const updateUser = (imageUrl, isProfileDelete = false) => {
|
||||
let url = '/users/me';
|
||||
let url = "/users/me";
|
||||
const data = { profilePhoto: imageUrl, isProfileDelete };
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
@ -179,7 +185,7 @@ export const updateUser = (imageUrl, isProfileDelete = false) => {
|
|||
});
|
||||
};
|
||||
export const companyMe = () => {
|
||||
let url = '/companies/me';
|
||||
let url = "/companies/me";
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
|
|
@ -189,7 +195,7 @@ export const companyMe = () => {
|
|||
});
|
||||
};
|
||||
export const updateCompanyDetails = (data) => {
|
||||
let url = '/companies/me';
|
||||
let url = "/companies/me";
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
|
|
@ -200,7 +206,7 @@ export const updateCompanyDetails = (data) => {
|
|||
};
|
||||
|
||||
export const bsAdminLogin = (token) => {
|
||||
const url = '/auth/admin/login';
|
||||
const url = "/auth/admin/login";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, {
|
||||
|
|
@ -212,7 +218,7 @@ export const bsAdminLogin = (token) => {
|
|||
};
|
||||
|
||||
export const resendPasswordMailer = (data) => {
|
||||
const url = '/users/remind-password-setup';
|
||||
const url = "/users/remind-password-setup";
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.patch(url, {
|
||||
|
|
@ -224,7 +230,7 @@ export const resendPasswordMailer = (data) => {
|
|||
};
|
||||
|
||||
export const updateUserEmailAndContact = (data) => {
|
||||
let url = '/users/me';
|
||||
let url = "/users/me";
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
|
|
@ -235,7 +241,7 @@ export const updateUserEmailAndContact = (data) => {
|
|||
};
|
||||
|
||||
export const transferMasterAdminAccess = (id) => {
|
||||
if (!id) throw new Error('User id is required');
|
||||
if (!id) throw new Error("User id is required");
|
||||
const url = `/users/${id}/transfer-master-admin-access`;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
|
|||
|
|
@ -1,246 +0,0 @@
|
|||
import { axiosInstance } from '../config/api';
|
||||
|
||||
export const getUsers = (params) => {
|
||||
let searchParams = new URLSearchParams();
|
||||
searchParams.append('size', params?.pagination?.pageSize ?? 10);
|
||||
searchParams.append('page', params?.pagination.pageIndex ?? 0);
|
||||
if (params?.globalFilter) searchParams.append('search', params?.globalFilter);
|
||||
if (params?.sortingString) {
|
||||
const sortingParams = new URLSearchParams(params.sortingString);
|
||||
sortingParams.forEach((value, key) => {
|
||||
searchParams.append(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
let url = `/users?${searchParams.toString()}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((response) => resolve(response?.data))
|
||||
.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 }) =>
|
||||
page == 0
|
||||
? {
|
||||
// data: {
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Adult Immunisation',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Allied health',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Assist',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Care plan',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Care plan reviews',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Cervical Screening',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Child Immunisation',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Health assessments',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: 'Mental Health Care Plans (MHCP)',
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: 'Travel Immunisation',
|
||||
},
|
||||
],
|
||||
// },
|
||||
}
|
||||
: { data: [] };
|
||||
// const url = '/roles';
|
||||
// return new Promise((resolve, reject) => {
|
||||
// axiosInstance
|
||||
// .get(url)
|
||||
// .then((response) => resolve(response))
|
||||
// .catch((err) => reject(err));
|
||||
// });
|
||||
|
||||
export const addUser = (data) => {
|
||||
const url = '/users';
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const updateUserById = (id, data) => {
|
||||
const url = `/users/${id}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const revokeAdminTransferAccess = () => {
|
||||
const url = `/users/admin-access-transfer-revoke`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const approveAdminTransferAccess = (id, token) => {
|
||||
const url = `/users/admin-access-transfer-approve`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, { id, token })
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteUserById = (id) => {
|
||||
const url = `/users/${id}`;
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.delete(url)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const logout = () => {
|
||||
const url = '/auth/companies/logout';
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const changePassword = (data) => {
|
||||
const url = '/users/me/password';
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
export const updateMailersSettings = (data) => {
|
||||
const url = '/users/me/mail-notification';
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const updateUser = (imageUrl, isProfileDelete = false) => {
|
||||
let url = '/users/me';
|
||||
const data = { profilePhoto: imageUrl, isProfileDelete };
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
export const companyMe = () => {
|
||||
let url = '/companies/me';
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
export const updateCompanyDetails = (data) => {
|
||||
let url = '/companies/me';
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const bsAdminLogin = (token) => {
|
||||
const url = '/auth/admin/login';
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.post(url, {
|
||||
token,
|
||||
})
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const resendPasswordMailer = (data) => {
|
||||
const url = '/users/remind-password-setup';
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.patch(url, {
|
||||
email: data,
|
||||
})
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const updateUserEmailAndContact = (data) => {
|
||||
let url = '/users/me';
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url, data)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const transferMasterAdminAccess = (id) => {
|
||||
if (!id) throw new Error('User id is required');
|
||||
const url = `/users/${id}/transfer-master-admin-access`;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance
|
||||
.put(url)
|
||||
.then((response) => resolve(response))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
|
@ -465,8 +465,8 @@ const ClinicsList = () => {
|
|||
extraComponent={
|
||||
<Box className={classes.tabsBox}>
|
||||
<Tabs value={type} onChange={handleTabsChange}>
|
||||
<Tab value={CLINIC_TYPE.UNREGISTERED} label="Unregistered" />
|
||||
<Tab value={CLINIC_TYPE.REGISTERED} label="Registered" />
|
||||
<Tab value={CLINIC_TYPE.UNREGISTERED} label="Unregistered (2)" />
|
||||
<Tab value={CLINIC_TYPE.REGISTERED} label="Registered (2)" />
|
||||
{/* <Tab value={COMPANY_TYPE.SUBSCRIBED} label="Subscribers" /> */}
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
import React from 'react'
|
||||
|
||||
const ContractManagement = () => {
|
||||
return (
|
||||
<div>ContractManagement</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ContractManagement
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import React from 'react'
|
||||
|
||||
const MasterDataManagement = () => {
|
||||
return (
|
||||
<div>MasterDataManagement</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MasterDataManagement
|
||||
|
|
@ -19,6 +19,7 @@ import {
|
|||
import React, { useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import creditcard from '../../assets/images/logo/credit_card.png';
|
||||
import AccountBalanceIcon from '@mui/icons-material/AccountBalance';
|
||||
import { NOTIFICATION } from '../../constants';
|
||||
import { pushNotification } from '../../utils/notification';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
|
@ -27,6 +28,9 @@ import { setClinicId } from '../../views/ClinicDetails/store/logInAsClinicAdminA
|
|||
const PaymentPage = () => {
|
||||
const [paymentMethod, setPaymentMethod] = useState('card');
|
||||
const [cardNumber, setCardNumber] = useState('');
|
||||
const [accountNumber, setAccountNumber] = useState('');
|
||||
const [ifscCode, setIfscCode] = useState('');
|
||||
const [bankName, setBankName] = useState('');
|
||||
const [cardExpiry, setCardExpiry] = useState('');
|
||||
const [cardCVC, setCardCVC] = useState('');
|
||||
const [name, setName] = useState('');
|
||||
|
|
@ -203,6 +207,112 @@ const PaymentPage = () => {
|
|||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
<Paper
|
||||
variant="outlined"
|
||||
sx={{
|
||||
p: 2,
|
||||
mb: 2,
|
||||
mt: 2,
|
||||
borderColor:
|
||||
paymentMethod === 'net_banking' ? 'primary.main' : 'divider',
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="net_banking"
|
||||
control={<Radio />}
|
||||
label={
|
||||
<Box display="flex" alignItems="center">
|
||||
<AccountBalanceIcon sx={{ mr: 1, height: 24, width: 24 }} />
|
||||
<Typography>Net Banking</Typography>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
|
||||
{paymentMethod === 'card' && (
|
||||
<Box mt={2}>
|
||||
<TextField
|
||||
label="Card Number"
|
||||
fullWidth
|
||||
margin="dense"
|
||||
value={cardNumber}
|
||||
onChange={(e) =>
|
||||
setCardNumber(formatCardNumber(e.target.value))
|
||||
}
|
||||
placeholder="1234 5678 9012 3456"
|
||||
inputProps={{ maxLength: 19 }}
|
||||
/>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
label="Expiry Date"
|
||||
fullWidth
|
||||
margin="dense"
|
||||
value={cardExpiry}
|
||||
onChange={(e) =>
|
||||
setCardExpiry(formatExpiry(e.target.value))
|
||||
}
|
||||
placeholder="MM/YY"
|
||||
inputProps={{ maxLength: 5 }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
label="CVC"
|
||||
fullWidth
|
||||
margin="dense"
|
||||
value={cardCVC}
|
||||
onChange={(e) => setCardCVC(e.target.value)}
|
||||
placeholder="123"
|
||||
inputProps={{ maxLength: 3 }}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<TextField
|
||||
label="Name on Card"
|
||||
fullWidth
|
||||
margin="dense"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="John Smith"
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{paymentMethod === 'net_banking' && (
|
||||
<Box mt={2}>
|
||||
<TextField
|
||||
label="Bank Name"
|
||||
fullWidth
|
||||
margin="dense"
|
||||
value={bankName}
|
||||
onChange={(e) => setBankName(e.target.value)}
|
||||
placeholder="Enter Bank Name"
|
||||
required
|
||||
/>
|
||||
<TextField
|
||||
label="Account Number"
|
||||
fullWidth
|
||||
margin="dense"
|
||||
value={accountNumber}
|
||||
onChange={(e) => setAccountNumber(e.target.value)}
|
||||
placeholder="Enter Account Number"
|
||||
required
|
||||
/>
|
||||
<TextField
|
||||
label="IFSC Code"
|
||||
fullWidth
|
||||
margin="dense"
|
||||
value={ifscCode}
|
||||
onChange={(e) => setIfscCode(e.target.value)}
|
||||
placeholder="Enter IFSC Code"
|
||||
required
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
</Paper>
|
||||
</RadioGroup>
|
||||
|
||||
<Button
|
||||
|
|
@ -213,7 +323,9 @@ const PaymentPage = () => {
|
|||
disabled={
|
||||
loading ||
|
||||
(paymentMethod === 'card' &&
|
||||
(!cardNumber || !cardExpiry || !cardCVC || !name))
|
||||
(!cardNumber || !cardExpiry || !cardCVC || !name)) ||
|
||||
(paymentMethod === 'net_banking' &&
|
||||
(!accountNumber || !ifscCode || !bankName))
|
||||
}
|
||||
sx={{ mt: 3 }}
|
||||
>
|
||||
|
|
@ -267,6 +379,51 @@ const PaymentPage = () => {
|
|||
</Paper>
|
||||
</Box>
|
||||
|
||||
{/* Payment Information Section */}
|
||||
<Typography variant="h6" gutterBottom sx={{ mt: 3 }}>
|
||||
Payment Information
|
||||
</Typography>
|
||||
<Box mb={2}>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{ p: 2, backgroundColor: '#f9f9f9', borderRadius: 2 }}
|
||||
>
|
||||
<Typography variant="subtitle2" fontWeight="bold" gutterBottom>
|
||||
Subscription Details
|
||||
</Typography>
|
||||
|
||||
<Stack direction="row" justifyContent="space-between" mb={1}>
|
||||
<Typography variant="body2">Setup Fee</Typography>
|
||||
<Typography variant="body2">$500.00</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" justifyContent="space-between" mb={1}>
|
||||
<Typography variant="body2">Subscription Fee (Monthly)</Typography>
|
||||
<Typography variant="body2">$800.00</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" justifyContent="space-between" mb={1}>
|
||||
<Typography variant="body2">Per Call Charges</Typography>
|
||||
<Typography variant="body2">$5.00/call</Typography>
|
||||
</Stack>
|
||||
|
||||
<Box mt={2}>
|
||||
<Chip
|
||||
label="Special Offer: First 3 months free"
|
||||
size="small"
|
||||
color="secondary"
|
||||
sx={{ mt: 1, mr: 1 }}
|
||||
/>
|
||||
<Chip
|
||||
label="Setup fee waived"
|
||||
size="small"
|
||||
color="success"
|
||||
sx={{ mt: 1 }}
|
||||
/>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ my: 2 }} />
|
||||
|
||||
<Stack direction="row" justifyContent="space-between" mb={1}>
|
||||
|
|
@ -307,9 +464,17 @@ const PaymentPage = () => {
|
|||
elevation={0}
|
||||
sx={{ p: 2, mt: 2, border: '1px solid #e0e0e0', borderRadius: 2 }}
|
||||
>
|
||||
<Typography variant="subtitle2" fontWeight="bold" gutterBottom>
|
||||
Transaction Information
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" paragraph>
|
||||
<strong>Secure Payment:</strong> All transactions are encrypted
|
||||
and secure.
|
||||
<strong>Direct Debit:</strong> Payments will be automatically processed on the 1st of each month.
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" paragraph>
|
||||
<strong>Billing Cycle:</strong> Monthly/Annual based on your selected plan.
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" paragraph>
|
||||
<strong>Secure Payment:</strong> All transactions are encrypted and secure via Stripe Payment Gateway.
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
<strong>Customer Support:</strong> If you have any questions,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
Button,
|
||||
ButtonBase,
|
||||
Drawer,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
Grid,
|
||||
IconButton,
|
||||
|
|
@ -103,6 +104,11 @@ function YourDetailsForm() {
|
|||
{ id: "director", name: "Director" },
|
||||
];
|
||||
|
||||
const mobilePrefixOptions = [
|
||||
{ id: "61", name: "+61" },
|
||||
{ id: "91", name: "+91" },
|
||||
];
|
||||
|
||||
const integrationOptions = ["BP Software", "Medical Director"];
|
||||
|
||||
// Default form data
|
||||
|
|
@ -112,6 +118,7 @@ function YourDetailsForm() {
|
|||
email: "",
|
||||
password: "",
|
||||
mobileNumber: "",
|
||||
mobilePrefix: "",
|
||||
confirmPassword: "",
|
||||
currentEmail: "",
|
||||
otp: "",
|
||||
|
|
@ -119,7 +126,11 @@ function YourDetailsForm() {
|
|||
// Clinic details
|
||||
companyName: "",
|
||||
designation: "",
|
||||
companyWebsite: "",
|
||||
businessPhone: "",
|
||||
emergencyBusinessPhone: "",
|
||||
emergencyBusinessPhonePrefix: "",
|
||||
businessPhonePrefix: "",
|
||||
businessFax: "",
|
||||
companyLogo: "",
|
||||
companyIndustry: "",
|
||||
pincode: "",
|
||||
|
|
@ -130,6 +141,9 @@ function YourDetailsForm() {
|
|||
companyPANImage: "",
|
||||
companyPANImage: "",
|
||||
termsAccepted: "",
|
||||
practiceManagementSystem: "",
|
||||
practiceId: "",
|
||||
practiceName: "",
|
||||
});
|
||||
|
||||
// Field references for focus and validation
|
||||
|
|
@ -138,6 +152,7 @@ function YourDetailsForm() {
|
|||
name: useRef(null),
|
||||
email: useRef(null),
|
||||
mobileNumber: useRef(null),
|
||||
mobilePrefix: useRef(null),
|
||||
password: useRef(null),
|
||||
confirmPassword: useRef(null),
|
||||
otp: useRef(null),
|
||||
|
|
@ -145,10 +160,14 @@ function YourDetailsForm() {
|
|||
// Clinic details fields
|
||||
companyName: useRef(null),
|
||||
businessPhone: useRef(null),
|
||||
businessPhonePrefix: useRef(null),
|
||||
emergencyBusinessPhone: useRef(null),
|
||||
emergencyBusinessPhonePrefix: useRef(null),
|
||||
businessFax: useRef(null),
|
||||
practiceManagementSystem: useRef(null),
|
||||
practiceId: useRef(null),
|
||||
practiceName: useRef(null),
|
||||
designation: useRef(null),
|
||||
companyWebsite: useRef(null),
|
||||
companyIndustry: useRef(null),
|
||||
pincode: useRef(null),
|
||||
state: useRef(null),
|
||||
|
|
@ -214,7 +233,7 @@ function YourDetailsForm() {
|
|||
designation: Yup.string()
|
||||
.required("Designation is required")
|
||||
.typeError("Designation must be string"),
|
||||
companyWebsite: Yup.string()
|
||||
businessPhone: Yup.string()
|
||||
.required("Clinic website is required")
|
||||
.matches(WEBSITE_REGEX, "Please enter a valid URL"),
|
||||
companyIndustry: Yup.string().required("Clinic Industry is required"),
|
||||
|
|
@ -246,6 +265,8 @@ function YourDetailsForm() {
|
|||
termsAccepted: Yup.boolean()
|
||||
.oneOf([true], "You must accept the terms and conditions")
|
||||
.required("You must accept the terms and conditions"),
|
||||
practiceId: Yup.string().required("Practice ID is required"),
|
||||
practiceName: Yup.string().required("Practice Name is required"),
|
||||
});
|
||||
|
||||
// Debounced function for pincode lookup
|
||||
|
|
@ -287,6 +308,12 @@ function YourDetailsForm() {
|
|||
}
|
||||
};
|
||||
|
||||
const handleTestConnection = () => {
|
||||
// logic here
|
||||
setTestConnDone(true);
|
||||
pushNotification("Test connection successful", "success");
|
||||
};
|
||||
|
||||
const handleOTPButton = () => {
|
||||
console.log("btn");
|
||||
setOtpField(true);
|
||||
|
|
@ -483,7 +510,12 @@ function YourDetailsForm() {
|
|||
function formatedData(inputData) {
|
||||
const data = {
|
||||
name: inputData.companyName || "",
|
||||
website: inputData.companyWebsite || "",
|
||||
businessPhone: inputData.businessPhone || "",
|
||||
emergencyBusinessPhone: inputData.emergencyBusinessPhone || "",
|
||||
emergencyBusinessPhonePrefix:
|
||||
inputData.emergencyBusinessPhonePrefix || "",
|
||||
businessPhonePrefix: inputData.businessPhonePrefix || "",
|
||||
businessFax: inputData.businessFax || "",
|
||||
city: inputData.locality || "",
|
||||
state: inputData.state || "",
|
||||
logo: inputData.companyLogo || null,
|
||||
|
|
@ -499,6 +531,9 @@ function YourDetailsForm() {
|
|||
password: inputData.password || "",
|
||||
designation: inputData.designation || "",
|
||||
},
|
||||
practiceId: inputData.practiceId || "",
|
||||
practiceManagementSystem: inputData.practiceManagementSystem || "",
|
||||
practiceName: inputData.practiceName || "",
|
||||
companyUsers: inputData.billingUsers || "",
|
||||
companyDocuments: [
|
||||
...(inputData.companyLogo
|
||||
|
|
@ -601,6 +636,17 @@ function YourDetailsForm() {
|
|||
<Box className={classes.paperContainerBox}>
|
||||
<Box>
|
||||
<form>
|
||||
{/* Practice ID */}
|
||||
<FormSectionHeading title="practice id" />
|
||||
<Grid
|
||||
container
|
||||
spacing={theme.spacing(2.3)}
|
||||
padding={`0 ${theme.spacing(3.2)}`}
|
||||
className={classes.formRoot}
|
||||
>
|
||||
<TextField disabled />
|
||||
</Grid>
|
||||
|
||||
{/* Personal Details Section */}
|
||||
<FormSectionHeading title="PERSONAL DETAILS" />
|
||||
<Grid
|
||||
|
|
@ -718,12 +764,28 @@ function YourDetailsForm() {
|
|||
pattern: "[0-9]*",
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<Box className={classes.countryCodeBox}>
|
||||
<Typography
|
||||
className={classes.countryCodeLabel}
|
||||
<Box sx={{ padding: "1px" }}>
|
||||
<Select
|
||||
name="mobilePrefix"
|
||||
value={formik.values.mobilePrefix}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
inputRef={fieldRefs.mobilePrefix}
|
||||
defaultValue={"61"}
|
||||
>
|
||||
+61
|
||||
</Typography>
|
||||
{mobilePrefixOptions.map((option) => (
|
||||
<MenuItem
|
||||
sx={{
|
||||
outline: "none",
|
||||
border: "none",
|
||||
}}
|
||||
key={option.id}
|
||||
value={option.id}
|
||||
>
|
||||
{option.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Box>
|
||||
</InputAdornment>
|
||||
),
|
||||
|
|
@ -962,7 +1024,7 @@ function YourDetailsForm() {
|
|||
{/* Your designation grid */}
|
||||
<Grid item md={4} sm={6} xs={12}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
Your designation*
|
||||
User Role*
|
||||
</InputLabel>
|
||||
<Select
|
||||
fullWidth
|
||||
|
|
@ -983,7 +1045,59 @@ function YourDetailsForm() {
|
|||
}
|
||||
>
|
||||
{userRoles.map((option) => (
|
||||
<MenuItem key={option.id} value={option.id}>
|
||||
{option.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Grid>
|
||||
|
||||
{/* Business Phone grid */}
|
||||
<Grid item md={4} sm={6} xs={12}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
Business PhoneNumber*
|
||||
</InputLabel>
|
||||
<TextField
|
||||
className={classes.mobileNumberInput}
|
||||
fullWidth
|
||||
placeholder="Enter Mobile Number"
|
||||
color="secondary"
|
||||
variant="outlined"
|
||||
name="businessPhone"
|
||||
value={formik.values.businessPhone}
|
||||
onChange={(e) => {
|
||||
if (e.target.value.length <= 10) {
|
||||
const value =
|
||||
e.target.value?.match(/\d+/g) || "";
|
||||
formik.setFieldValue(
|
||||
"businessPhone",
|
||||
value?.toString()
|
||||
);
|
||||
}
|
||||
}}
|
||||
onBlur={formik.handleBlur}
|
||||
InputProps={{
|
||||
type: "text",
|
||||
pattern: "[0-9]*",
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<Box sx={{ padding: "1px" }}>
|
||||
<Select
|
||||
name="businessPhonePrefix"
|
||||
value={
|
||||
formik.values.businessPhonePrefix
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
inputRef={fieldRefs.businessPhonePrefix}
|
||||
defaultValue={"61"}
|
||||
>
|
||||
{mobilePrefixOptions.map((option) => (
|
||||
<MenuItem
|
||||
sx={{
|
||||
outline: "none",
|
||||
border: "none",
|
||||
}}
|
||||
key={option.id}
|
||||
value={option.id}
|
||||
>
|
||||
|
|
@ -991,38 +1105,270 @@ function YourDetailsForm() {
|
|||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Grid>
|
||||
|
||||
{/* Clinic Website grid */}
|
||||
<Grid item md={4} sm={6} xs={12}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
Clinic Website*
|
||||
</InputLabel>
|
||||
<TextField
|
||||
fullWidth
|
||||
placeholder="Enter Clinic Website"
|
||||
color="secondary"
|
||||
variant="outlined"
|
||||
name="companyWebsite"
|
||||
value={formik.values.companyWebsite}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
inputRef={fieldRefs.companyWebsite}
|
||||
</Box>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
inputRef={fieldRefs.businessPhone}
|
||||
error={Boolean(
|
||||
formik.errors.companyWebsite &&
|
||||
formik.touched.companyWebsite
|
||||
formik.errors.businessPhone &&
|
||||
formik.touched.businessPhone
|
||||
)}
|
||||
helperText={
|
||||
formik.errors.companyWebsite &&
|
||||
formik.touched.companyWebsite
|
||||
? formik.errors.companyWebsite
|
||||
formik.errors.businessPhone &&
|
||||
formik.touched.businessPhone
|
||||
? formik.errors.businessPhone
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* business emergency phone */}
|
||||
<Grid item md={4} sm={6} xs={12}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
Business Emergency Phone Number*
|
||||
</InputLabel>
|
||||
<TextField
|
||||
className={classes.mobileNumberInput}
|
||||
fullWidth
|
||||
placeholder="Enter Emergency Phone Number"
|
||||
color="secondary"
|
||||
variant="outlined"
|
||||
name="emergencyBusinessPhone"
|
||||
value={formik.values.emergencyBusinessPhone}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
InputProps={{
|
||||
type: "text",
|
||||
pattern: "[0-9]*",
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<Box sx={{ padding: "1px" }}>
|
||||
<Select
|
||||
name="emergencyBusinessPhonePrefix"
|
||||
value={
|
||||
formik.values
|
||||
.emergencyBusinessPhonePrefix
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
inputRef={
|
||||
fieldRefs.emergencyBusinessPhonePrefix
|
||||
}
|
||||
defaultValue={"61"}
|
||||
>
|
||||
{mobilePrefixOptions.map((option) => (
|
||||
<MenuItem
|
||||
sx={{
|
||||
outline: "none",
|
||||
border: "none",
|
||||
}}
|
||||
key={option.id}
|
||||
value={option.id}
|
||||
>
|
||||
{option.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Box>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
inputRef={fieldRefs.emergencyBusinessPhone}
|
||||
error={Boolean(
|
||||
formik.errors.emergencyBusinessPhone &&
|
||||
formik.touched.emergencyBusinessPhone
|
||||
)}
|
||||
helperText={
|
||||
formik.errors.emergencyBusinessPhone &&
|
||||
formik.touched.emergencyBusinessPhone
|
||||
? formik.errors.emergencyBusinessPhone
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* Business Fax grid */}
|
||||
<Grid item md={4} sm={6} xs={12}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
Business Fax Number*
|
||||
</InputLabel>
|
||||
<TextField
|
||||
// className={classes.mobileNumberInput}
|
||||
fullWidth
|
||||
placeholder="Enter Fax Number"
|
||||
color="secondary"
|
||||
variant="outlined"
|
||||
name="businessFax"
|
||||
value={formik.values.businessFax}
|
||||
onChange={(e) => {
|
||||
if (e.target.value.length <= 10) {
|
||||
const value =
|
||||
e.target.value?.match(/\d+/g) || "";
|
||||
formik.setFieldValue(
|
||||
"businessFax",
|
||||
value?.toString()
|
||||
);
|
||||
}
|
||||
}}
|
||||
onBlur={formik.handleBlur}
|
||||
InputProps={{
|
||||
type: "text",
|
||||
pattern: "[0-9]*",
|
||||
}}
|
||||
inputRef={fieldRefs.businessFax}
|
||||
error={Boolean(
|
||||
formik.errors.businessFax &&
|
||||
formik.touched.businessFax
|
||||
)}
|
||||
helperText={
|
||||
formik.errors.businessFax &&
|
||||
formik.touched.businessFax
|
||||
? formik.errors.businessFax
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* Business Email grid */}
|
||||
<Grid item md={4} sm={6} xs={12}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
Business Email*
|
||||
</InputLabel>
|
||||
<TextField
|
||||
// className={classes.mobileNumberInput}
|
||||
fullWidth
|
||||
placeholder="Enter Business Email"
|
||||
color="secondary"
|
||||
variant="outlined"
|
||||
name="businessEmail"
|
||||
value={formik.values.businessEmail}
|
||||
onChange={(e) => {
|
||||
if (e.target.value.length <= 10) {
|
||||
const value =
|
||||
e.target.value?.match(/\d+/g) || "";
|
||||
formik.setFieldValue(
|
||||
"businessEmail",
|
||||
value?.toString()
|
||||
);
|
||||
}
|
||||
}}
|
||||
onBlur={formik.handleBlur}
|
||||
InputProps={{
|
||||
type: "email",
|
||||
}}
|
||||
inputRef={fieldRefs.businessEmail}
|
||||
error={Boolean(
|
||||
formik.errors.businessEmail &&
|
||||
formik.touched.businessEmail
|
||||
)}
|
||||
helperText={
|
||||
formik.errors.businessEmail &&
|
||||
formik.touched.businessEmail
|
||||
? formik.errors.businessEmail
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* practice management system */}
|
||||
<Grid item xs={6} md={4}>
|
||||
<InputLabel
|
||||
className={classes.inputLabel}
|
||||
id="integration-software-label"
|
||||
>
|
||||
Integrate with
|
||||
</InputLabel>
|
||||
<Select
|
||||
fullWidth
|
||||
name="practiceManagementSystem"
|
||||
value={formik.values.practiceManagementSystem}
|
||||
onChange={formik.handleChange}
|
||||
inputRef={fieldRefs.practiceManagementSystem}
|
||||
error={Boolean(
|
||||
formik.errors.practiceManagementSystem &&
|
||||
formik.touched.practiceManagementSystem
|
||||
)}
|
||||
helperText={
|
||||
formik.errors.practiceManagementSystem &&
|
||||
formik.touched.practiceManagementSystem
|
||||
? formik.errors.practiceManagementSystem
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{integrationOptions.map((option) => (
|
||||
<MenuItem key={option} value={option}>
|
||||
{option}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Grid>
|
||||
|
||||
{/* PMS ID grid */}
|
||||
<Grid item xs={12} md={4}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
PMS ID
|
||||
</InputLabel>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="PMS ID"
|
||||
name="practiceId"
|
||||
value={formik.values.practiceId}
|
||||
onChange={formik.handleChange}
|
||||
variant="outlined"
|
||||
disabled={!formik.values.practiceManagementSystem}
|
||||
error={
|
||||
!!formik.values.practiceManagementSystem &&
|
||||
formik.errors.practiceId
|
||||
}
|
||||
helperText={
|
||||
!!formik.values.practiceManagementSystem &&
|
||||
formik.errors.practiceId
|
||||
? "Practice ID is required"
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* Practice Name grid */}
|
||||
<Grid item xs={12} md={4}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
Practice Name
|
||||
</InputLabel>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Practice Name"
|
||||
name="practiceName"
|
||||
value={formik.values.practiceName}
|
||||
onChange={formik.handleChange}
|
||||
variant="outlined"
|
||||
disabled={!formik.values.practiceManagementSystem}
|
||||
error={
|
||||
!!formik.values.practiceManagementSystem &&
|
||||
formik.errors.practiceName
|
||||
}
|
||||
helperText={
|
||||
!!formik.values.practiceManagementSystem &&
|
||||
formik.errors.practiceName
|
||||
? "Practice Name is required"
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* Test Connection Button */}
|
||||
<Grid item xs={12} md={8}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleTestConnection}
|
||||
>
|
||||
Test Connection
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
{/* Clinic logo grid */}
|
||||
<Grid item md={4} sm={12}>
|
||||
<Grid item md={5} sm={12}>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
Add Business Logo
|
||||
{(logoImage || formik.values.companyLogo) && (
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ const initialState = {
|
|||
currentEmail: '',
|
||||
companyName: '',
|
||||
designation: '',
|
||||
companyWebsite: '',
|
||||
businessPhone: '',
|
||||
companyAbout: '',
|
||||
companyLogo: '',
|
||||
companyIndustry: '',
|
||||
|
|
|
|||
|
|
@ -1,60 +1,61 @@
|
|||
import { LoadingButton } from '@mui/lab';
|
||||
import { Box, Grid, MenuItem, Select, 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 { LoadingButton } from "@mui/lab";
|
||||
import { Box, Button, 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";
|
||||
|
||||
/* ----------------- Custom Imports ----------------- */
|
||||
import PageHeader from '../../components/PageHeader';
|
||||
import Table from '../../components/Table';
|
||||
import ConfirmationModal from '../Modal/ConfirmationModal';
|
||||
import CustomModal from '../Modal/Modal';
|
||||
import { useStyles } from './userStyles';
|
||||
import PageHeader from "../../components/PageHeader";
|
||||
import Table from "../../components/Table";
|
||||
import ConfirmationModal from "../Modal/ConfirmationModal";
|
||||
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 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,
|
||||
getRoles,
|
||||
getUserById,
|
||||
resendPasswordMailer,
|
||||
revokeAdminTransferAccess,
|
||||
transferMasterAdminAccess,
|
||||
} from '../../services/users.services';
|
||||
} from "../../services/users.service";
|
||||
|
||||
/* ----------------- Utils ----------------- */
|
||||
import { format } from 'date-fns';
|
||||
import MultiSelect from '../../components/MultiSelect';
|
||||
import { NOTIFICATION, NOT_AVAILABLE_TEXT } from '../../constants';
|
||||
import { pushNotification } from '../../utils/notification';
|
||||
import { format } from "date-fns";
|
||||
import MultiSelect from "../../components/MultiSelect";
|
||||
import { NOTIFICATION, NOT_AVAILABLE_TEXT } from "../../constants";
|
||||
import { pushNotification } from "../../utils/notification";
|
||||
|
||||
/* ----------------- Validation Schema ----------------- */
|
||||
const validationSchema = Yup.object().shape({
|
||||
userName: Yup.string().required('User Name is required'),
|
||||
userName: Yup.string().required("User Name is required"),
|
||||
email: Yup.string()
|
||||
.email('Invalid Email Address')
|
||||
.required('Email is required'),
|
||||
.email("Invalid Email Address")
|
||||
.required("Email is required"),
|
||||
mobile: Yup.string()
|
||||
.matches(/^\d{10}$/, 'Mobile Number must be exactly 10 digits')
|
||||
.required('Mobile Number is required'),
|
||||
.matches(/^\d{10}$/, "Mobile Number must be exactly 10 digits")
|
||||
.required("Mobile Number is required"),
|
||||
});
|
||||
|
||||
function Users() {
|
||||
const ref = useRef(null);
|
||||
const defaultFormData = useRef({
|
||||
userName: '',
|
||||
email: 'q@gmail.com',
|
||||
mobile: '1234567890',
|
||||
userName: "",
|
||||
email: "q@gmail.com",
|
||||
mobile: "1234567890",
|
||||
isEditUser: false,
|
||||
lastName: '',
|
||||
userType: '',
|
||||
lastName: "",
|
||||
userType: "",
|
||||
appointmentType: [],
|
||||
appointmentTypeObject: '',
|
||||
appointmentTypeObject: "",
|
||||
});
|
||||
|
||||
const fieldRefs = {
|
||||
|
|
@ -74,9 +75,6 @@ function Users() {
|
|||
const [isEditUser, setIsEditUser] = useState(false);
|
||||
const [deleteModal, setDeleteModal] = useState(false);
|
||||
const [masterAdminModal, setMasterAdminModal] = useState(false);
|
||||
const [revokeAdminAccessRequestModal, setRevokeAdminAccessRequestModal] =
|
||||
useState(false);
|
||||
const [seletedUserData, setSelectedUserData] = useState();
|
||||
const [buttonLoading, setButtonLoading] = useState(false);
|
||||
const [userId, setUserId] = useState();
|
||||
const [userTotalCount, setUserTotalCount] = useState(0);
|
||||
|
|
@ -84,28 +82,41 @@ function Users() {
|
|||
const [checkboxError, setCheckboxError] = useState(false);
|
||||
const [roles, setRoles] = useState();
|
||||
const [isAdmin, setIsAdmin] = useState();
|
||||
const [hasProfileCompleted, setHasProfileCompleted] = useState(false);
|
||||
const [
|
||||
requestRaisedForTransferMasterAdminAccess,
|
||||
setRequestRaisedForTransferMasterAdminAccess,
|
||||
] = useState(false);
|
||||
|
||||
const isBsAdmin = useSelector((state) => state?.login?.user?.isBsAdmin);
|
||||
|
||||
/* ----------------- Get Users ----------------- */
|
||||
const getData = async (filters) => {
|
||||
const resp = await getUsers(filters);
|
||||
console.log(resp);
|
||||
console.log(resp?.data?.totalCount);
|
||||
setUserTotalCount(resp?.data?.totalCount);
|
||||
setRequestRaisedForTransferMasterAdminAccess(
|
||||
resp.data?.requestRaisedForTransferMasterAdminAccess
|
||||
);
|
||||
|
||||
const role = await getRoles();
|
||||
setRoles(role?.data?.data);
|
||||
const role = await getRoles({ page: 0 });
|
||||
setRoles(role?.data);
|
||||
|
||||
return { data: resp?.data?.records, rowCount: resp?.data?.totalCount };
|
||||
};
|
||||
|
||||
const handleToggleButton = async (row) => {
|
||||
try {
|
||||
// Replace this with your actual API call to update user status
|
||||
// Example: await updateUserStatus(row.id, !row.isActive);
|
||||
|
||||
// For now, just show a notification
|
||||
pushNotification(
|
||||
`${row.name}'s status has been ${row.isActive ? 'deactivated' : 'activated'}`,
|
||||
NOTIFICATION.SUCCESS
|
||||
);
|
||||
|
||||
// Refresh the table data
|
||||
ref.current.reFetchData();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
pushNotification('Failed to update status', NOTIFICATION.ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
/* ----------------- Handle Submit ----------------- */
|
||||
const handleSubmit = async (values, formik) => {
|
||||
try {
|
||||
|
|
@ -143,7 +154,7 @@ function Users() {
|
|||
|
||||
// if (response.status === 200) {
|
||||
// pushNotification(response?.data?.message, NOTIFICATION.SUCCESS);
|
||||
pushNotification('Doctor added successfully', NOTIFICATION.SUCCESS);
|
||||
pushNotification("Doctor added successfully", NOTIFICATION.SUCCESS);
|
||||
// ref.current.reFetchData();
|
||||
toggle();
|
||||
formik.resetForm();
|
||||
|
|
@ -162,60 +173,6 @@ function Users() {
|
|||
setShowModal(!showModal);
|
||||
};
|
||||
|
||||
/* ----------------- Edit User ----------------- */
|
||||
const editUser = async (row) => {
|
||||
try {
|
||||
const { data: { data: userData } = {} } = await getUserById(
|
||||
row?.original?.id
|
||||
);
|
||||
const formData = {
|
||||
userName: userData?.name,
|
||||
email: userData?.email,
|
||||
mobile: userData?.mobile,
|
||||
password: userData?.password,
|
||||
transferMasterAdminAccess: false,
|
||||
isEditUser: true,
|
||||
};
|
||||
setIsAdmin(userData?.isAdmin);
|
||||
setHasProfileCompleted(userData?.hasProfileCompleted);
|
||||
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 resendPasswordSetupMailer = (row) => {
|
||||
try {
|
||||
const response = resendPasswordMailer(row?.original?.email);
|
||||
if (response.status === 200) {
|
||||
pushNotification(response?.data?.message, NOTIFICATION.SUCCESS);
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
/* ----------------- Revoke Admin Access Request ----------------- */
|
||||
const revokeAdminAccessRequest = async () => {
|
||||
setRevokeAdminAccessRequestModal(true);
|
||||
};
|
||||
|
||||
/* ----------------- Handle Checkbox Change ----------------- */
|
||||
const handleCheckboxChange = (id, isChecked) => {
|
||||
setSelectedCheckboxes({ ...selectedCheckboxes, [id]: isChecked });
|
||||
|
|
@ -226,7 +183,7 @@ function Users() {
|
|||
() => [
|
||||
{
|
||||
size: 30,
|
||||
header: 'S.no.',
|
||||
header: "S.no.",
|
||||
Cell: (props) => {
|
||||
const tableState = props?.table?.getState();
|
||||
const serialNumber = (
|
||||
|
|
@ -235,59 +192,57 @@ function Users() {
|
|||
tableState?.pagination?.pageIndex * tableState?.pagination?.pageSize
|
||||
)
|
||||
?.toString()
|
||||
?.padStart(1, '0');
|
||||
?.padStart(1, "0");
|
||||
return <span>{serialNumber}.</span>;
|
||||
},
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
accessorFn: ({ name }) => name || NOT_AVAILABLE_TEXT,
|
||||
accessorKey: 'name',
|
||||
header: 'Doctor/Nurse Name',
|
||||
accessorKey: "name",
|
||||
header: "Doctor/Nurse Name",
|
||||
isBold: true,
|
||||
},
|
||||
// {
|
||||
// accessorKey: 'roles',
|
||||
// header: 'User Access',
|
||||
// enableSorting: false,
|
||||
// Cell: ({ row }) => (
|
||||
// <div>
|
||||
// {row.original.roles && row.original.roles.length > 0
|
||||
// ? row.original.roles.map((role, index) => (
|
||||
// <span key={index}>
|
||||
// {role.name}
|
||||
// {index !== row.original.roles.length - 1 ? ', ' : ''}
|
||||
// </span>
|
||||
// ))
|
||||
// : NOT_AVAILABLE_TEXT}
|
||||
// {row.original.isAdmin && ', Master Admin'}
|
||||
// </div>
|
||||
// ),
|
||||
// },
|
||||
{
|
||||
accessorFn: ({ mobile }) => mobile || NOT_AVAILABLE_TEXT,
|
||||
accessorKey: 'mobile',
|
||||
header: 'User Type',
|
||||
accessorKey: "userType",
|
||||
header: "User Type",
|
||||
},
|
||||
{
|
||||
accessorFn: ({ email }) => email || NOT_AVAILABLE_TEXT,
|
||||
accessorKey: 'email',
|
||||
header: 'Specialties',
|
||||
accessorKey: "specialities",
|
||||
header: "Specialties",
|
||||
},
|
||||
{
|
||||
accessorKey: 'createdAt',
|
||||
accessorKey: "createdAt",
|
||||
Cell: ({ row }) => (
|
||||
<div className={classes.dateStyle}>
|
||||
{format(new Date(row?.original?.createdAt), 'dd MMM, yyyy')}
|
||||
{format(new Date(row?.original?.createdAt), "dd MMM, yyyy")}
|
||||
</div>
|
||||
),
|
||||
header: 'Added On',
|
||||
header: "Added On",
|
||||
},
|
||||
{
|
||||
accessorFn: ({ email }) => email || NOT_AVAILABLE_TEXT,
|
||||
accessorKey: 'email',
|
||||
header: 'Status',
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
},
|
||||
{
|
||||
size: 30,
|
||||
accessorKey: "actions",
|
||||
header: "Actions",
|
||||
enableSorting: false,
|
||||
Cell: ({ row }) => (
|
||||
<div>
|
||||
<Switch
|
||||
checked={row?.original?.isActive}
|
||||
onChange={() => handleToggleButton(row?.original)}
|
||||
inputProps={{ "aria-label": "Status toggle" }}
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
}
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
|
@ -314,10 +269,6 @@ function Users() {
|
|||
setSelectedUserData(row?.original);
|
||||
};
|
||||
|
||||
const revokeAdminAccessToggle = () => {
|
||||
setRevokeAdminAccessRequestModal(!revokeAdminAccessRequestModal);
|
||||
};
|
||||
|
||||
/* ----------------- Transfer Master Admin Access to User ----------------- */
|
||||
const handleTransferMasterAdminAccess = async () => {
|
||||
setButtonLoading(true);
|
||||
|
|
@ -355,24 +306,6 @@ function Users() {
|
|||
setButtonLoading(false);
|
||||
}
|
||||
};
|
||||
/* ----------------- Revoke Admin Access ----------------- */
|
||||
const handleRevokeAdminAccessRequest = async () => {
|
||||
setButtonLoading(true);
|
||||
try {
|
||||
const response = await revokeAdminTransferAccess();
|
||||
if (response.status === 200) {
|
||||
pushNotification(response?.data?.message, NOTIFICATION.SUCCESS);
|
||||
ref.current.resetPage(true);
|
||||
setRevokeAdminAccessRequestModal(false);
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error?.response?.data?.message);
|
||||
} finally {
|
||||
ref.current.reFetchData();
|
||||
setButtonLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleuserAccessCancel = () => {
|
||||
setCheckboxError(false);
|
||||
|
|
@ -380,7 +313,7 @@ function Users() {
|
|||
};
|
||||
|
||||
const getRowStyle = (row) =>
|
||||
row?.original?.isAdmin ? { backgroundColor: '#E7F4EE !important' } : {};
|
||||
row?.original?.isAdmin ? { backgroundColor: "#E7F4EE !important" } : {};
|
||||
|
||||
const handleSubmitClick = async () => {
|
||||
const formikErrors = await formik.validateForm();
|
||||
|
|
@ -393,10 +326,10 @@ function Users() {
|
|||
|
||||
if (firstErrorRef) {
|
||||
// Scroll to the first invalid field smoothly
|
||||
if (typeof firstErrorRef?.scrollIntoView === 'function') {
|
||||
if (typeof firstErrorRef?.scrollIntoView === "function") {
|
||||
firstErrorRef?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -429,49 +362,26 @@ function Users() {
|
|||
columns={columns}
|
||||
getData={getData}
|
||||
options={{ enableRowSelection: false }}
|
||||
showAction={true}
|
||||
// showAction={true}
|
||||
hideShowPerPage={true}
|
||||
showSearchBox={true}
|
||||
ref={ref}
|
||||
searchText={'user'}
|
||||
searchText={"user"}
|
||||
getRowStyle={getRowStyle}
|
||||
actions={[
|
||||
{
|
||||
onClick: makeMasterAdminToggle,
|
||||
text: 'Make User Master Admin',
|
||||
icon: <RemoveIcon className={classes.tableActionIcons} />,
|
||||
renderAction: (row) => isBsAdmin && !row?.original?.isAdmin,
|
||||
},
|
||||
{
|
||||
onClick: revokeAdminAccessRequest,
|
||||
text: 'Revoke Admin Access Request',
|
||||
icon: <RemoveIcon className={classes.tableActionIcons} />,
|
||||
// permissionName: "CREATE_USERS",
|
||||
renderAction: (row) => row?.original?.transferMasterAdminAccess,
|
||||
},
|
||||
{
|
||||
onClick: editUser,
|
||||
text: 'Edit',
|
||||
icon: <EditIcon className={classes.tableActionIcons} />,
|
||||
// permissionName: "CREATE_USERS",
|
||||
},
|
||||
{
|
||||
onClick: (row) => resendPasswordSetupMailer(row),
|
||||
text: 'Resend password setup mailer',
|
||||
icon: <SendIcon className={classes.tableActionIcons} />,
|
||||
renderAction: (row) => !row?.original?.hasProfileCompleted,
|
||||
// permissionName: "CREATE_USERS",
|
||||
},
|
||||
{
|
||||
onClick: deleteUserToggle,
|
||||
text: 'Delete',
|
||||
icon: <DeleteIcon className={classes.tableActionIcons} />,
|
||||
renderAction: (row) => !row?.original?.isAdmin,
|
||||
// permissionName: 'DELETE_USERS',
|
||||
// isDisabledValue: user?.id,
|
||||
rowKey: 'id',
|
||||
},
|
||||
].filter(Boolean)}
|
||||
// actions={[
|
||||
// {
|
||||
// title: "Action",
|
||||
// field: "isActive",
|
||||
// render: (rowData) => (
|
||||
// <Switch
|
||||
// checked={rowData.isActive}
|
||||
// onChange={() => handleToggleButton(rowData)}
|
||||
// inputProps={{ "aria-label": "Status toggle" }}
|
||||
// color="primary"
|
||||
// />
|
||||
// ),
|
||||
// },
|
||||
// ]}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
|
@ -485,7 +395,7 @@ function Users() {
|
|||
footerRightButtonTitle="Submit"
|
||||
onFooterLeftButtonClick={() => handleCancel()}
|
||||
onFooterRightButtonClick={() => handleSubmit()}
|
||||
title={isEditUser ? 'Edit Doctor/Nurse' : 'Add New Doctor/Nurse'}
|
||||
title={isEditUser ? "Edit Doctor/Nurse" : "Add New Doctor/Nurse"}
|
||||
isTitleLeft={true}
|
||||
onClose={() => {
|
||||
formik.resetForm();
|
||||
|
|
@ -496,8 +406,8 @@ function Users() {
|
|||
modalBodyFunction={() => (
|
||||
<Box
|
||||
sx={{
|
||||
'& .MuiDialogContent-root': {
|
||||
padding: '0px',
|
||||
"& .MuiDialogContent-root": {
|
||||
padding: "0px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
|
@ -511,14 +421,14 @@ function Users() {
|
|||
fullWidth
|
||||
inputProps={{
|
||||
form: {
|
||||
autocomplete: 'off',
|
||||
autocomplete: "off",
|
||||
},
|
||||
}}
|
||||
name="userName"
|
||||
value={formik.values.userName}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={(e) => {
|
||||
formik.setFieldValue('userName', e.target.value.trim());
|
||||
formik.setFieldValue("userName", e.target.value.trim());
|
||||
formik.handleBlur(e);
|
||||
}}
|
||||
inputRef={fieldRefs.userName}
|
||||
|
|
@ -531,7 +441,7 @@ function Users() {
|
|||
<i>{formik.errors.userName}</i>
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
""
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
|
@ -544,14 +454,14 @@ function Users() {
|
|||
fullWidth
|
||||
inputProps={{
|
||||
form: {
|
||||
autocomplete: 'off',
|
||||
autocomplete: "off",
|
||||
},
|
||||
}}
|
||||
name="lastName"
|
||||
value={formik.values.lastName}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={(e) => {
|
||||
formik.setFieldValue('lastName', e.target.value.trim());
|
||||
formik.setFieldValue("lastName", e.target.value.trim());
|
||||
formik.handleBlur(e);
|
||||
}}
|
||||
inputRef={fieldRefs.lastName}
|
||||
|
|
@ -564,7 +474,7 @@ function Users() {
|
|||
<i>{formik.errors.lastName}</i>
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
""
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
|
@ -572,7 +482,7 @@ function Users() {
|
|||
select
|
||||
className={classes.perPageDropdown}
|
||||
fullWidth
|
||||
style={{ marginTop: '15px' }}
|
||||
style={{ marginTop: "15px" }}
|
||||
defaultValue={true}
|
||||
>
|
||||
<MenuItem value={true}>Doctor</MenuItem>
|
||||
|
|
@ -581,7 +491,7 @@ function Users() {
|
|||
|
||||
<MultiSelect
|
||||
apiCall={getRoles}
|
||||
searchParams={{ additionalParam: 'value' }}
|
||||
searchParams={{ additionalParam: "value" }}
|
||||
formik={formik}
|
||||
fieldValue="appointmentType"
|
||||
fieldObjectValue="appointmentTypeObject"
|
||||
|
|
@ -741,19 +651,6 @@ function Users() {
|
|||
/>
|
||||
)}
|
||||
|
||||
{/* ----------- Revoke Admin Access Request ----------- */}
|
||||
{revokeAdminAccessRequestModal && (
|
||||
<ConfirmationModal
|
||||
heading="Revoke Admin Access Request"
|
||||
bodyContent="The request for access privileges to Master Admin will be revoked for this user."
|
||||
confirmationLine="Are you sure you want to revoke access?"
|
||||
leftButtonText="Cancel"
|
||||
rightButtonText="Revoke Access"
|
||||
onCancel={revokeAdminAccessToggle}
|
||||
onConfirm={handleRevokeAdminAccessRequest}
|
||||
buttonLoading={buttonLoading}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue