diff --git a/src/components/Table.jsx b/src/components/Table.jsx index 491c593..3d6aaac 100644 --- a/src/components/Table.jsx +++ b/src/components/Table.jsx @@ -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) => ({ - opacity: 1, - fontWeight: 600, - fontSize: '16px', - fontFamily: theme.fontFamily.semiBold, - color: theme.palette.grey[10], - }), - }, + Cell: ({ cell }) => ( + ({ + opacity: 1, + fontWeight: 600, + fontSize: "16px", + fontFamily: theme.fontFamily.semiBold, + color: theme.palette.grey[10], + })} + > + {cell.getValue()} + + ), }; } 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: ( - {/* search icon */} ), @@ -256,29 +253,26 @@ const Table = memo( )} 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 : ( - - {(action?.icon || - action?.text || - (action?.textFn && action?.textFn(row))) && ( - { - 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)} - - )} - - ) - ) ?? [] - } + // renderRowActionMenuItems={({ row, closeMenu }) => + // actions?.filter(action => !action.render)?.map((action, index) => + // !(action?.renderAction?.(row) ?? true) ? null : ( + // { + // 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)} + // + // ) + // ) ?? [] + // } 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() ? ( @@ -453,11 +450,11 @@ const Table = memo( @@ -466,12 +463,12 @@ const Table = memo( @@ -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 ( @@ -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 ( ( @@ -572,13 +569,13 @@ const CustomPagination = ({ table }) => { disabled={currentPage === 1} onClick={() => previousPage()} > - + Previous )} /> ); - } else if (item.type === 'next') { + } else if (item.type === "next") { return ( ( @@ -589,7 +586,7 @@ const CustomPagination = ({ table }) => { onClick={() => nextPage()} > Next - + )} 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", }, }} /> @@ -620,4 +617,4 @@ const CustomPagination = ({ table }) => { ); }; -export default Table; +export default Table; \ No newline at end of file diff --git a/src/layouts/mainLayout/components/sideBarConfig.js b/src/layouts/mainLayout/components/sideBarConfig.js index 6c0593b..23d0d4a 100644 --- a/src/layouts/mainLayout/components/sideBarConfig.js +++ b/src/layouts/mainLayout/components/sideBarConfig.js @@ -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] + }, ]; diff --git a/src/mock/users/index.js b/src/mock/users/index.js new file mode 100644 index 0000000..ad3e2bc --- /dev/null +++ b/src/mock/users/index.js @@ -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: "", +}; diff --git a/src/routes/index.js b/src/routes/index.js index b2ee5b5..9c65602 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -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, }, diff --git a/src/services/users.service.js b/src/services/users.service.js index ff2c3c4..e0ea9e0 100644 --- a/src/services/users.service.js +++ b/src/services/users.service.js @@ -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) => { diff --git a/src/services/users.services.js b/src/services/users.services.js deleted file mode 100644 index 9c67b27..0000000 --- a/src/services/users.services.js +++ /dev/null @@ -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)); - }); -}; diff --git a/src/views/ClinicsList/index.jsx b/src/views/ClinicsList/index.jsx index 6548c84..2f7dfe3 100644 --- a/src/views/ClinicsList/index.jsx +++ b/src/views/ClinicsList/index.jsx @@ -465,8 +465,8 @@ const ClinicsList = () => { extraComponent={ - - + + {/* */} diff --git a/src/views/ContractManagement/index.jsx b/src/views/ContractManagement/index.jsx new file mode 100644 index 0000000..8d01962 --- /dev/null +++ b/src/views/ContractManagement/index.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +const ContractManagement = () => { + return ( +
ContractManagement
+ ) +} + +export default ContractManagement \ No newline at end of file diff --git a/src/views/MasterData/index.jsx b/src/views/MasterData/index.jsx new file mode 100644 index 0000000..ed841cb --- /dev/null +++ b/src/views/MasterData/index.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +const MasterDataManagement = () => { + return ( +
MasterDataManagement
+ ) +} + +export default MasterDataManagement \ No newline at end of file diff --git a/src/views/MockPayment/index.jsx b/src/views/MockPayment/index.jsx index b65f100..46703ac 100644 --- a/src/views/MockPayment/index.jsx +++ b/src/views/MockPayment/index.jsx @@ -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 = () => {
)} + + } + label={ + + + Net Banking + + } + /> + + {paymentMethod === 'card' && ( + + + setCardNumber(formatCardNumber(e.target.value)) + } + placeholder="1234 5678 9012 3456" + inputProps={{ maxLength: 19 }} + /> + + + + + setCardExpiry(formatExpiry(e.target.value)) + } + placeholder="MM/YY" + inputProps={{ maxLength: 5 }} + /> + + + setCardCVC(e.target.value)} + placeholder="123" + inputProps={{ maxLength: 3 }} + /> + + + + setName(e.target.value)} + placeholder="John Smith" + /> + + )} + + {paymentMethod === 'net_banking' && ( + + setBankName(e.target.value)} + placeholder="Enter Bank Name" + required + /> + setAccountNumber(e.target.value)} + placeholder="Enter Account Number" + required + /> + setIfscCode(e.target.value)} + placeholder="Enter IFSC Code" + required + /> + + )} + + + + {/* Clinic logo grid */} - + Add Business Logo {(logoImage || formik.values.companyLogo) && ( diff --git a/src/views/Signup/signupReducer.js b/src/views/Signup/signupReducer.js index df8b818..26d073c 100644 --- a/src/views/Signup/signupReducer.js +++ b/src/views/Signup/signupReducer.js @@ -14,7 +14,7 @@ const initialState = { currentEmail: '', companyName: '', designation: '', - companyWebsite: '', + businessPhone: '', companyAbout: '', companyLogo: '', companyIndustry: '', diff --git a/src/views/User/index.jsx b/src/views/User/index.jsx index a68965e..6a2b06b 100644 --- a/src/views/User/index.jsx +++ b/src/views/User/index.jsx @@ -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 {serialNumber}.; }, 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 }) => ( - //
- // {row.original.roles && row.original.roles.length > 0 - // ? row.original.roles.map((role, index) => ( - // - // {role.name} - // {index !== row.original.roles.length - 1 ? ', ' : ''} - // - // )) - // : NOT_AVAILABLE_TEXT} - // {row.original.isAdmin && ', Master Admin'} - //
- // ), - // }, { 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 }) => (
- {format(new Date(row?.original?.createdAt), 'dd MMM, yyyy')} + {format(new Date(row?.original?.createdAt), "dd MMM, yyyy")}
), - 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 }) => ( +
+ handleToggleButton(row?.original)} + inputProps={{ "aria-label": "Status toggle" }} + color="primary" + /> +
+ ), + } ], [] ); @@ -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: , - renderAction: (row) => isBsAdmin && !row?.original?.isAdmin, - }, - { - onClick: revokeAdminAccessRequest, - text: 'Revoke Admin Access Request', - icon: , - // permissionName: "CREATE_USERS", - renderAction: (row) => row?.original?.transferMasterAdminAccess, - }, - { - onClick: editUser, - text: 'Edit', - icon: , - // permissionName: "CREATE_USERS", - }, - { - onClick: (row) => resendPasswordSetupMailer(row), - text: 'Resend password setup mailer', - icon: , - renderAction: (row) => !row?.original?.hasProfileCompleted, - // permissionName: "CREATE_USERS", - }, - { - onClick: deleteUserToggle, - text: 'Delete', - icon: , - renderAction: (row) => !row?.original?.isAdmin, - // permissionName: 'DELETE_USERS', - // isDisabledValue: user?.id, - rowKey: 'id', - }, - ].filter(Boolean)} + // actions={[ + // { + // title: "Action", + // field: "isActive", + // render: (rowData) => ( + // handleToggleButton(rowData)} + // inputProps={{ "aria-label": "Status toggle" }} + // color="primary" + // /> + // ), + // }, + // ]} />
@@ -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={() => ( @@ -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() { {formik.errors.userName} ) : ( - '' + "" ) } /> @@ -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() { {formik.errors.lastName} ) : ( - '' + "" ) } /> @@ -572,7 +482,7 @@ function Users() { select className={classes.perPageDropdown} fullWidth - style={{ marginTop: '15px' }} + style={{ marginTop: "15px" }} defaultValue={true} > Doctor @@ -581,7 +491,7 @@ function Users() { )} - {/* ----------- Revoke Admin Access Request ----------- */} - {revokeAdminAccessRequestModal && ( - - )} ); }