feat: protected routes for clinic docs update
fix: doc upload after rejection
This commit is contained in:
parent
3d91cee029
commit
35f21f2749
|
|
@ -117,9 +117,6 @@ const CustomFileUpload = forwardRef(function CustomFileUpload(
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const response = await getPresignedUrl(filePayload);
|
const response = await getPresignedUrl(filePayload);
|
||||||
|
|
||||||
// Debug the response structure
|
|
||||||
console.log('API Response:', response);
|
|
||||||
|
|
||||||
// Check if we have a valid response with the expected structure
|
// Check if we have a valid response with the expected structure
|
||||||
if (response?.data?.data?.Key) {
|
if (response?.data?.data?.Key) {
|
||||||
// Use the Key from the response
|
// Use the Key from the response
|
||||||
|
|
@ -128,7 +125,6 @@ const CustomFileUpload = forwardRef(function CustomFileUpload(
|
||||||
} else {
|
} else {
|
||||||
// If the expected structure is not found, try to find the key in a different location
|
// If the expected structure is not found, try to find the key in a different location
|
||||||
// or use a fallback value
|
// or use a fallback value
|
||||||
console.log('Response structure is different than expected');
|
|
||||||
|
|
||||||
// Try different possible paths to find the key
|
// Try different possible paths to find the key
|
||||||
const key = response?.data?.Key ||
|
const key = response?.data?.Key ||
|
||||||
|
|
@ -136,7 +132,6 @@ const CustomFileUpload = forwardRef(function CustomFileUpload(
|
||||||
response?.Key ||
|
response?.Key ||
|
||||||
value.name; // Fallback to the file name if key not found
|
value.name; // Fallback to the file name if key not found
|
||||||
|
|
||||||
console.log('Using key:', key);
|
|
||||||
onUploadDone(documentName, key);
|
onUploadDone(documentName, key);
|
||||||
|
|
||||||
// Try to find the API URL similarly
|
// Try to find the API URL similarly
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import axios from 'axios';
|
import axios from "axios";
|
||||||
import { API_BASE_URL } from '../common/envVariables';
|
import { API_BASE_URL } from "../common/envVariables";
|
||||||
import { ERRORS, NOTIFICATION } from '../constants';
|
import { ERRORS, NOTIFICATION } from "../constants";
|
||||||
import { pushNotification } from '../utils/notification';
|
import { pushNotification } from "../utils/notification";
|
||||||
import { commonLogoutFunc } from '../utils/share';
|
import { commonLogoutFunc } from "../utils/share";
|
||||||
import store from '../redux/store';
|
import store from "../redux/store";
|
||||||
|
|
||||||
export const axiosInstance = axios.create({
|
export const axiosInstance = axios.create({
|
||||||
baseURL: API_BASE_URL,
|
baseURL: API_BASE_URL,
|
||||||
|
|
@ -20,10 +20,15 @@ export const axiosInstance = axios.create({
|
||||||
axiosInstance.interceptors.request.use(
|
axiosInstance.interceptors.request.use(
|
||||||
async function (config) {
|
async function (config) {
|
||||||
try {
|
try {
|
||||||
const token = JSON.parse(localStorage.getItem('redux'));
|
const token = JSON.parse(localStorage.getItem("redux"));
|
||||||
if (token?.login?.token) {
|
if (token?.login?.token) {
|
||||||
config.headers.Authorization = `Bearer ${token?.login?.token}`;
|
config.headers.Authorization = `Bearer ${token?.login?.token}`;
|
||||||
}
|
}
|
||||||
|
// if url is dev-ai-appointment.s3.amazonaws.com
|
||||||
|
if (config.url?.includes("dev-ai-appointment.s3.amazonaws.com")) {
|
||||||
|
config.headers.Authorization = null;
|
||||||
|
}
|
||||||
|
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const companyId = state?.loginAsCompanyAdmin?.companyId; // Extract companyId
|
const companyId = state?.loginAsCompanyAdmin?.companyId; // Extract companyId
|
||||||
if (companyId) {
|
if (companyId) {
|
||||||
|
|
@ -58,7 +63,7 @@ axiosInstance.interceptors.response.use(
|
||||||
console.log(error);
|
console.log(error);
|
||||||
if (!error?.response?.data) {
|
if (!error?.response?.data) {
|
||||||
pushNotification(error.message, NOTIFICATION.ERROR);
|
pushNotification(error.message, NOTIFICATION.ERROR);
|
||||||
if (error.message !== 'Network Error') commonLogoutFunc();
|
if (error.message !== "Network Error") commonLogoutFunc();
|
||||||
} else if (
|
} else if (
|
||||||
error?.response?.data?.error &&
|
error?.response?.data?.error &&
|
||||||
error?.response?.data?.error[0]?.message
|
error?.response?.data?.error[0]?.message
|
||||||
|
|
@ -91,10 +96,10 @@ axiosInstance.interceptors.response.use(
|
||||||
|
|
||||||
export const fileDownloadAxios = axios.create({
|
export const fileDownloadAxios = axios.create({
|
||||||
baseURL: API_BASE_URL,
|
baseURL: API_BASE_URL,
|
||||||
responseType: 'blob',
|
responseType: "blob",
|
||||||
crossDomain: true,
|
crossDomain: true,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
timeout: 300000,
|
timeout: 300000,
|
||||||
|
|
@ -103,10 +108,16 @@ export const fileDownloadAxios = axios.create({
|
||||||
fileDownloadAxios.interceptors.request.use(
|
fileDownloadAxios.interceptors.request.use(
|
||||||
async function (config) {
|
async function (config) {
|
||||||
try {
|
try {
|
||||||
const token = JSON.parse(localStorage.getItem('redux'));
|
const token = JSON.parse(localStorage.getItem("redux"));
|
||||||
if (token?.data?.data) {
|
if (token?.data?.data) {
|
||||||
config.headers.Authorization = `${token?.data?.data}`;
|
config.headers.Authorization = `${token?.data?.data}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if url is dev-ai-appointment.s3.amazonaws.com
|
||||||
|
if (config.url?.includes("dev-ai-appointment.s3.amazonaws.com")) {
|
||||||
|
config.headers.Authorization = null;
|
||||||
|
}
|
||||||
|
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const companyId = state?.loginAsCompanyAdmin?.companyId; // Extract companyId
|
const companyId = state?.loginAsCompanyAdmin?.companyId; // Extract companyId
|
||||||
if (companyId) {
|
if (companyId) {
|
||||||
|
|
@ -131,7 +142,7 @@ fileDownloadAxios.interceptors.response.use(
|
||||||
async function (response) {
|
async function (response) {
|
||||||
// Handle error response (when server responds with JSON instead of a file)
|
// Handle error response (when server responds with JSON instead of a file)
|
||||||
if (
|
if (
|
||||||
response?.headers['content-type']?.includes('application/json') &&
|
response?.headers["content-type"]?.includes("application/json") &&
|
||||||
response?.data
|
response?.data
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -140,14 +151,14 @@ fileDownloadAxios.interceptors.response.use(
|
||||||
|
|
||||||
if (parsedError?.error) {
|
if (parsedError?.error) {
|
||||||
pushNotification(
|
pushNotification(
|
||||||
parsedError?.message || 'Download failed',
|
parsedError?.message || "Download failed",
|
||||||
NOTIFICATION.ERROR
|
NOTIFICATION.ERROR
|
||||||
);
|
);
|
||||||
return Promise.reject(parsedError);
|
return Promise.reject(parsedError);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error('Error parsing error response', err);
|
console.error("Error parsing error response", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,26 +170,26 @@ fileDownloadAxios.interceptors.response.use(
|
||||||
|
|
||||||
if (!error?.response?.data) {
|
if (!error?.response?.data) {
|
||||||
pushNotification(error.message, NOTIFICATION.ERROR);
|
pushNotification(error.message, NOTIFICATION.ERROR);
|
||||||
if (error.message !== 'Network Error') commonLogoutFunc();
|
if (error.message !== "Network Error") commonLogoutFunc();
|
||||||
} else {
|
} else {
|
||||||
// Handle error message from API
|
// Handle error message from API
|
||||||
const contentType = error?.response?.headers?.['content-type'];
|
const contentType = error?.response?.headers?.["content-type"];
|
||||||
|
|
||||||
if (contentType?.includes('application/json')) {
|
if (contentType?.includes("application/json")) {
|
||||||
error.response.data.text().then((text) => {
|
error.response.data.text().then((text) => {
|
||||||
try {
|
try {
|
||||||
const parsedError = JSON.parse(text);
|
const parsedError = JSON.parse(text);
|
||||||
pushNotification(
|
pushNotification(
|
||||||
parsedError.message || 'Something went wrong',
|
parsedError.message || "Something went wrong",
|
||||||
NOTIFICATION.ERROR
|
NOTIFICATION.ERROR
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
pushNotification('Unknown error occurred', NOTIFICATION.ERROR);
|
pushNotification("Unknown error occurred", NOTIFICATION.ERROR);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
pushNotification(
|
pushNotification(
|
||||||
error?.response?.data?.message || 'Download failed',
|
error?.response?.data?.message || "Download failed",
|
||||||
NOTIFICATION.ERROR
|
NOTIFICATION.ERROR
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,12 @@ import { CLINIC_STATUS, HIDE_MODULES } from "../../../constants";
|
||||||
import { isBSPortal } from "../../../utils/share";
|
import { isBSPortal } from "../../../utils/share";
|
||||||
import { hideAndShowFunctionality } from "../../../views/Signup/signupAction";
|
import { hideAndShowFunctionality } from "../../../views/Signup/signupAction";
|
||||||
import { useStyles } from "../mainLayoutStyles";
|
import { useStyles } from "../mainLayoutStyles";
|
||||||
|
|
||||||
// Import the configuration from the separate file
|
// Import the configuration from the separate file
|
||||||
import { SIDEBAR_CONFIG } from "./sideBarConfig"; // Adjust path if necessary
|
import { SIDEBAR_CONFIG } from "./sideBarConfig"; // Adjust path if necessary
|
||||||
|
import {
|
||||||
|
selectClinicStatus,
|
||||||
|
selectUserRole,
|
||||||
|
} from "../../../redux/userRoleSlice";
|
||||||
|
|
||||||
// NOTE: Removed the internal SIDEBAR_ITEMS definition.
|
// NOTE: Removed the internal SIDEBAR_ITEMS definition.
|
||||||
// We will now use the imported SIDEBAR_CONFIG.
|
// We will now use the imported SIDEBAR_CONFIG.
|
||||||
|
|
@ -41,6 +44,7 @@ const Sidebar = ({ onClose, showCloseIcon }) => {
|
||||||
const [childRoute, setchildRoute] = useState("");
|
const [childRoute, setchildRoute] = useState("");
|
||||||
const [combinedRoute, setcombinedRoute] = useState("");
|
const [combinedRoute, setcombinedRoute] = useState("");
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const clinicStatus = useSelector(selectClinicStatus);
|
||||||
|
|
||||||
// Assuming companyStatus is fetched or defined elsewhere correctly
|
// Assuming companyStatus is fetched or defined elsewhere correctly
|
||||||
const companyStatus = "APPROVED"; // Example status, replace with actual logic if needed
|
const companyStatus = "APPROVED"; // Example status, replace with actual logic if needed
|
||||||
|
|
@ -83,74 +87,70 @@ const Sidebar = ({ onClose, showCloseIcon }) => {
|
||||||
const userRole = useSelector((state) => state.userRole.role);
|
const userRole = useSelector((state) => state.userRole.role);
|
||||||
|
|
||||||
// Function to determine visibility and render a single sidebar item link
|
// Function to determine visibility and render a single sidebar item link
|
||||||
const checkVisibility = (item, i) => {
|
// The checkVisibility function with fixed logic
|
||||||
// Check if the user has the necessary role for this item
|
const checkVisibility = (item, i) => {
|
||||||
const hasRole = !item.roles || item.roles.includes(userRole);
|
// Check if the user has the necessary role for this item
|
||||||
|
const hasRole = !item.roles || item.roles.includes(userRole);
|
||||||
|
|
||||||
// Determine if the feature related to this item should be hidden
|
// Only render if user has the required role
|
||||||
let hideFeature =
|
if (hasRole) {
|
||||||
(companyStatus === CLINIC_STATUS.APPROVED &&
|
// Determine if the link should be disabled
|
||||||
HIDE_FUNCTIONALITY &&
|
// FIXED LOGIC: If clinic status is rejected, only allow "/" and "/docs" paths
|
||||||
HIDE_MODULES.includes(item?.path)) ||
|
const isDisabled = (clinicStatus === "rejected" || clinicStatus === "under_review" || clinicStatus === "payment_due") && !(item.path == "" || item.path == "docs");
|
||||||
(isSuperAdmin && HIDE_FUNCTIONALITY && HIDE_MODULES.includes(item?.path));
|
|
||||||
|
|
||||||
// Only render if user has the required role
|
// Set the correct target path
|
||||||
if (hasRole) {
|
const targetPath = isDisabled ? "#" : `/${item.path}`;
|
||||||
// Determine if the link should be disabled
|
const isActive = activeLink === item.path; // Check if this link is the active one
|
||||||
const isDisabled =
|
|
||||||
(!isSuperAdmin && companyStatus !== CLINIC_STATUS.APPROVED) || hideFeature;
|
|
||||||
const targetPath = isDisabled ? "#" : `/${item.path}`;
|
|
||||||
const isActive = activeLink === item.path; // Check if this link is the active one
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
className={classes.marginBottom}
|
className={classes.marginBottom}
|
||||||
onClick={() => handleHideFeatures(hideFeature)} // This seems odd, clicking the box hides features? Review this logic.
|
onClick={() => handleHideFeatures(isDisabled)} // Pass isDisabled to handleHideFeatures
|
||||||
key={item.path || i} // Use a stable key like item.path
|
key={item.path || i} // Use a stable key like item.path
|
||||||
|
>
|
||||||
|
<NavLink
|
||||||
|
className={`${isActive ? classes.activeLink : ""} ${
|
||||||
|
classes.textDecorationNone
|
||||||
|
} ${isDisabled ? classes.disabledLink : ""}`}
|
||||||
|
to={targetPath}
|
||||||
|
// Prevent navigation for disabled links
|
||||||
|
onClick={(e) => {
|
||||||
|
if (isDisabled) e.preventDefault();
|
||||||
|
handleLinkClick(item.path); // Set active link on click
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<NavLink
|
<ListItem
|
||||||
className={`${isActive ? classes.activeLink : ""} ${
|
button // Make it clear it's clickable
|
||||||
classes.textDecorationNone
|
className={`${classes.listItem} ${
|
||||||
} ${isDisabled ? classes.disabledLink : ""}`}
|
isActive && classes.activeLink
|
||||||
to={targetPath}
|
}`}
|
||||||
// Prevent navigation for disabled links, although `to="#"` handles this
|
disabled={isDisabled} // Visually disable the ListItem as well
|
||||||
onClick={(e) => {
|
|
||||||
if (isDisabled) e.preventDefault();
|
|
||||||
handleLinkClick(item.path); // Set active link on click
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<ListItem
|
<Box className={classes.sidebarListImg}>
|
||||||
button // Make it clear it's clickable
|
{isActive
|
||||||
className={`${classes.listItem} ${
|
? React.createElement(item.activeIcon, {
|
||||||
isActive && classes.activeLink
|
className: classes.sidebarLinkIcons,
|
||||||
}`}
|
})
|
||||||
disabled={isDisabled} // Visually disable the ListItem as well
|
: React.createElement(item.icon, {
|
||||||
>
|
className: classes.sidebarLinkIcons,
|
||||||
<Box className={classes.sidebarListImg}>
|
style: { color: "black" },
|
||||||
{isActive
|
})}
|
||||||
? React.createElement(item.activeIcon, {
|
</Box>
|
||||||
className: classes.sidebarLinkIcons,
|
<ListItemText
|
||||||
})
|
primary={item.text}
|
||||||
: React.createElement(item.icon, {
|
primaryTypographyProps={{
|
||||||
className: classes.sidebarLinkIcons,
|
className: isActive
|
||||||
style: { color: "black" },
|
? classes.activeLinkTextColor
|
||||||
})}
|
: classes.normalLinkTextColor,
|
||||||
</Box>
|
}}
|
||||||
<ListItemText
|
/>
|
||||||
primary={item.text}
|
</ListItem>
|
||||||
primaryTypographyProps={{
|
</NavLink>
|
||||||
className: isActive
|
</Box>
|
||||||
? classes.activeLinkTextColor
|
);
|
||||||
: classes.normalLinkTextColor,
|
}
|
||||||
}}
|
return null; // Return null if item shouldn't be rendered
|
||||||
/>
|
};
|
||||||
</ListItem>
|
|
||||||
</NavLink>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null; // Return null if item shouldn't be rendered
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to render a sidebar item that has children (accordion)
|
// Function to render a sidebar item that has children (accordion)
|
||||||
const rendersideMenu = (item, i) => {
|
const rendersideMenu = (item, i) => {
|
||||||
|
|
@ -164,7 +164,8 @@ const Sidebar = ({ onClose, showCloseIcon }) => {
|
||||||
const visibleChildren = item.children
|
const visibleChildren = item.children
|
||||||
?.filter((childItem) => {
|
?.filter((childItem) => {
|
||||||
// Check if child has the necessary role
|
// Check if child has the necessary role
|
||||||
const hasChildRole = !childItem.roles || childItem.roles.includes(userRole);
|
const hasChildRole =
|
||||||
|
!childItem.roles || childItem.roles.includes(userRole);
|
||||||
return hasChildRole;
|
return hasChildRole;
|
||||||
})
|
})
|
||||||
.filter(Boolean); // Filter out any null/undefined results
|
.filter(Boolean); // Filter out any null/undefined results
|
||||||
|
|
|
||||||
|
|
@ -82,4 +82,13 @@ export const SIDEBAR_CONFIG = [
|
||||||
// Clinic admin can access call transcripts
|
// Clinic admin can access call transcripts
|
||||||
roles: [USER_ROLES.CLINIC_ADMIN]
|
roles: [USER_ROLES.CLINIC_ADMIN]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: 'Clinic Documents',
|
||||||
|
path: 'docs',
|
||||||
|
requireSaprateApp: false,
|
||||||
|
icon: ArticleOutlinedIcon,
|
||||||
|
activeIcon: ArticleIcon,
|
||||||
|
// Clinic admin can access call transcripts
|
||||||
|
roles: [USER_ROLES.CLINIC_ADMIN]
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,22 @@
|
||||||
// Initial state
|
// Initial state
|
||||||
const initialState = {
|
const initialState = {
|
||||||
role: null,
|
role: null,
|
||||||
|
clinicStatus: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Action types
|
// Action types
|
||||||
const SET_USER_ROLE = 'userRole/SET_USER_ROLE';
|
const SET_USER_ROLE = 'userRole/SET_USER_ROLE';
|
||||||
|
|
||||||
// Action creators
|
// Action creators
|
||||||
export const setUserRole = (role) => ({
|
export const setUserRole = (role, clinicStatus) => ({
|
||||||
type: SET_USER_ROLE,
|
type: SET_USER_ROLE,
|
||||||
payload: role,
|
payload: role,
|
||||||
|
clinicStatus: clinicStatus,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Selector to get user role
|
// Selector to get user role
|
||||||
export const selectUserRole = (state) => state.userRole.role;
|
export const selectUserRole = (state) => state.userRole.role;
|
||||||
|
export const selectClinicStatus = (state) => state.userRole.clinicStatus;
|
||||||
|
|
||||||
// Reducer
|
// Reducer
|
||||||
export default function userRoleReducer(state = initialState, action) {
|
export default function userRoleReducer(state = initialState, action) {
|
||||||
|
|
@ -22,6 +25,7 @@ export default function userRoleReducer(state = initialState, action) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
role: action.payload,
|
role: action.payload,
|
||||||
|
clinicStatus: action.clinicStatus,
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import ClinicsList from "../views/ClinicsList";
|
||||||
import Dashboard from "../views/Dashboard";
|
import Dashboard from "../views/Dashboard";
|
||||||
import StaffManagement from "../views/StaffManagement";
|
import StaffManagement from "../views/StaffManagement";
|
||||||
import ClinicDetails from "../views/ClinicDetails";
|
import ClinicDetails from "../views/ClinicDetails";
|
||||||
import Login from '../views/Login';
|
import Login from "../views/Login";
|
||||||
import YourDetailsForm from "../views/Signup/YourDetailsForm";
|
import YourDetailsForm from "../views/Signup/YourDetailsForm";
|
||||||
import MockPayment from "../views/MockPayment";
|
import MockPayment from "../views/MockPayment";
|
||||||
import Users from "../views/User";
|
import Users from "../views/User";
|
||||||
|
|
@ -13,6 +13,7 @@ import ClinicTranscripts from "../views/ClinicTranscripts";
|
||||||
import ContractManagement from "../views/ContractManagement";
|
import ContractManagement from "../views/ContractManagement";
|
||||||
import MasterDataManagement from "../views/MasterData";
|
import MasterDataManagement from "../views/MasterData";
|
||||||
import PaymentManagement from "../views/PaymentManagement";
|
import PaymentManagement from "../views/PaymentManagement";
|
||||||
|
import ClinicDocUpdater from "../views/ClinicDocUpdate";
|
||||||
|
|
||||||
export const routesData = [
|
export const routesData = [
|
||||||
{
|
{
|
||||||
|
|
@ -28,6 +29,7 @@ export const routesData = [
|
||||||
{ path: "/transcripts", component: ClinicTranscripts },
|
{ path: "/transcripts", component: ClinicTranscripts },
|
||||||
{ path: "/masterData", component: MasterDataManagement },
|
{ path: "/masterData", component: MasterDataManagement },
|
||||||
{ path: "/payment-management", component: PaymentManagement },
|
{ path: "/payment-management", component: PaymentManagement },
|
||||||
|
{ path: "/docs", component: ClinicDocUpdater },
|
||||||
],
|
],
|
||||||
isProtected: true,
|
isProtected: true,
|
||||||
},
|
},
|
||||||
|
|
@ -38,7 +40,7 @@ export const routesData = [
|
||||||
{ path: "/auth/login", component: Login },
|
{ path: "/auth/login", component: Login },
|
||||||
{ path: "/auth/signup/payment", component: MockPayment },
|
{ path: "/auth/signup/payment", component: MockPayment },
|
||||||
{
|
{
|
||||||
path: 'signup/your-details',
|
path: "signup/your-details",
|
||||||
component: YourDetailsForm,
|
component: YourDetailsForm,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,197 @@
|
||||||
|
import { Button, Grid, Paper, Typography } from "@mui/material";
|
||||||
|
import { Box } from "@mui/system";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import CustomFileUpload from "../../components/CustomFileUpload";
|
||||||
|
import { useFormik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { MAX_FILE_SIZE_IN_MB, MAX_FILES } from "../../constants";
|
||||||
|
import { updateClinicDocs } from "../../services/clinics.service";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
const ClinicDocUpdater = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
// Use state instead of ref for initial form data
|
||||||
|
const [initialFormData, setInitialFormData] = useState({
|
||||||
|
companyABNImage: "",
|
||||||
|
contract: "",
|
||||||
|
logo: "",
|
||||||
|
clinicId: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Track if data is loaded
|
||||||
|
const [isDataLoaded, setIsDataLoaded] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Load user data from localStorage
|
||||||
|
try {
|
||||||
|
const user = JSON.parse(localStorage.getItem("user"));
|
||||||
|
|
||||||
|
if (user && user.created_clinics ) {
|
||||||
|
setInitialFormData({
|
||||||
|
companyABNImage: user.created_clinics.abn_doc || "",
|
||||||
|
contract: user.created_clinics.contract_doc || "",
|
||||||
|
logo: user.created_clinics.logo || "",
|
||||||
|
clinicId: user.created_clinics.id || "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading user data:", error);
|
||||||
|
} finally {
|
||||||
|
setIsDataLoaded(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
companyABNImage: Yup.string().required("Clinic ABN document is required"),
|
||||||
|
contract: Yup.string().required("Contract is required"),
|
||||||
|
logo: Yup.string().required("Logo is required"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleFormSubmit = async () => {
|
||||||
|
console.log("Form values:", formik.values);
|
||||||
|
const payload = {
|
||||||
|
abn_doc: formik.values.companyABNImage,
|
||||||
|
contract_doc: formik.values.contract,
|
||||||
|
logo: formik.values.logo,
|
||||||
|
}
|
||||||
|
|
||||||
|
const resp = await updateClinicDocs(formik.values.clinicId, payload);
|
||||||
|
console.log(resp);
|
||||||
|
|
||||||
|
// clear localStorage
|
||||||
|
localStorage.removeItem("user");
|
||||||
|
// redirect to login
|
||||||
|
navigate("/");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
formik.handleSubmit();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize formik only after data is loaded
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: initialFormData,
|
||||||
|
validationSchema,
|
||||||
|
onSubmit: handleFormSubmit,
|
||||||
|
enableReinitialize: true, // This is key - it will update form values when initialValues change
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set uploaded file URL
|
||||||
|
const setUploadedFileUrl = (documentName, fileUrl) => {
|
||||||
|
console.log("Document Name:", documentName);
|
||||||
|
console.log("File URL:", fileUrl);
|
||||||
|
console.log("File URL Type:", typeof fileUrl);
|
||||||
|
|
||||||
|
if (documentName && fileUrl !== undefined) {
|
||||||
|
formik.setFieldValue(documentName, fileUrl);
|
||||||
|
console.log("After setting value:", formik.values[documentName]);
|
||||||
|
} else {
|
||||||
|
console.error("Invalid parameters for setUploadedFileUrl:", {
|
||||||
|
documentName,
|
||||||
|
fileUrl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Box sx={{ width: "100%" }}>
|
||||||
|
<Paper sx={{ width: "100%", mb: 2 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h6" component="div">
|
||||||
|
Clinic Docs
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
{isDataLoaded ? (
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
display: "flex",
|
||||||
|
gap: 2,
|
||||||
|
flexWrap: "wrap",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={5}
|
||||||
|
// padding={`0 ${theme.spacing(3.2)}`}
|
||||||
|
// className={classes.formRoot}
|
||||||
|
// sx={{ display: "flex" }}
|
||||||
|
>
|
||||||
|
<Grid item md={4} sm={12} xs={12}>
|
||||||
|
<CustomFileUpload
|
||||||
|
label="Add ABN/ACN Image*"
|
||||||
|
documentName="companyABNImage"
|
||||||
|
onUploadDone={setUploadedFileUrl}
|
||||||
|
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
|
||||||
|
maxFiles={MAX_FILES}
|
||||||
|
uploadedFileUrl={formik.values.companyABNImage}
|
||||||
|
errorMessage={
|
||||||
|
formik.errors.companyABNImage &&
|
||||||
|
formik.touched.companyABNImage
|
||||||
|
? formik.errors.companyABNImage
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item md={4} sm={12} xs={12}>
|
||||||
|
<CustomFileUpload
|
||||||
|
label="Add Contract*"
|
||||||
|
documentName="contract"
|
||||||
|
onUploadDone={setUploadedFileUrl}
|
||||||
|
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
|
||||||
|
maxFiles={MAX_FILES}
|
||||||
|
uploadedFileUrl={formik.values.contract}
|
||||||
|
errorMessage={
|
||||||
|
formik.errors.contract && formik.touched.contract
|
||||||
|
? formik.errors.contract
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item md={4} sm={12} xs={12}>
|
||||||
|
<CustomFileUpload
|
||||||
|
label="Add Logo*"
|
||||||
|
documentName="logo"
|
||||||
|
onUploadDone={setUploadedFileUrl}
|
||||||
|
maxFileSizeInMb={MAX_FILE_SIZE_IN_MB}
|
||||||
|
maxFiles={MAX_FILES}
|
||||||
|
uploadedFileUrl={formik.values.logo}
|
||||||
|
errorMessage={
|
||||||
|
formik.errors.logo && formik.touched.logo
|
||||||
|
? formik.errors.logo
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<Box sx={{ p: 2 }}>
|
||||||
|
<Typography>Loading clinic documents...</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ClinicDocUpdater;
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
export const convertToSignupForm = (data) => {
|
||||||
|
return {
|
||||||
|
name: data.name,
|
||||||
|
email: data.email,
|
||||||
|
password: data.password,
|
||||||
|
mobileNumber: data.mobileNumber,
|
||||||
|
mobilePrefix: data.mobilePrefix,
|
||||||
|
companyName: data.companyName,
|
||||||
|
designation: data.designation,
|
||||||
|
businessPhonePrefix: data.businessPhonePrefix,
|
||||||
|
businessPhone: data.businessPhone,
|
||||||
|
emergencyBusinessPhone: data.emergencyBusinessPhone,
|
||||||
|
emergencyBusinessPhonePrefix: data.emergencyBusinessPhonePrefix,
|
||||||
|
businessFax: data.businessFax,
|
||||||
|
clinicLogo: data.clinicLogo,
|
||||||
|
businessEmail: data.businessEmail,
|
||||||
|
pincode: data.pincode,
|
||||||
|
state: data.state,
|
||||||
|
locality: data.locality,
|
||||||
|
country: data.country,
|
||||||
|
fullAddress: data.fullAddress,
|
||||||
|
companyABNImageNumber: data.companyABNImageNumber,
|
||||||
|
companyABNImage: data.companyABNImage,
|
||||||
|
termsAccepted: data.termsAccepted,
|
||||||
|
practiceManagementSystem: data.practiceManagementSystem,
|
||||||
|
practiceId: data.practiceId,
|
||||||
|
practiceName: data.practiceName,
|
||||||
|
contract: data.contract,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -7,7 +7,12 @@ import SuperAdmin from "./components/SuperAdmin";
|
||||||
import { selectUserRole, setUserRole } from "../../redux/userRoleSlice";
|
import { selectUserRole, setUserRole } from "../../redux/userRoleSlice";
|
||||||
import Totals from "./Tiles/Totals";
|
import Totals from "./Tiles/Totals";
|
||||||
import { useStyles } from "./dashboardStyles";
|
import { useStyles } from "./dashboardStyles";
|
||||||
import { USER_ROLES } from "../../constants";
|
import { NOTIFICATION, USER_ROLES } from "../../constants";
|
||||||
|
import { getClinicsById } from "../../services/clinics.service";
|
||||||
|
import { pushNotification } from "../../utils/notification";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { updateFormDetails } from "../Signup/signupAction";
|
||||||
|
import { convertToSignupForm } from "./helper";
|
||||||
|
|
||||||
function Dashboard() {
|
function Dashboard() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
@ -31,7 +36,51 @@ function Dashboard() {
|
||||||
const userRole = useSelector(selectUserRole);
|
const userRole = useSelector(selectUserRole);
|
||||||
const user = useSelector((state) => state.login.user);
|
const user = useSelector((state) => state.login.user);
|
||||||
|
|
||||||
|
const navigation = useNavigate();
|
||||||
|
|
||||||
|
const getClinic = async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
const resp = await getClinicsById(user.created_clinics[0].id);
|
||||||
|
|
||||||
|
|
||||||
|
// if(resp?.data?.data?.error){
|
||||||
|
// setIsActive(false);
|
||||||
|
// pushNotification("Error while fetching clinic data", NOTIFICATION.ERROR);
|
||||||
|
// navigation("/auth/signup/your-details?status=error");
|
||||||
|
// }
|
||||||
|
|
||||||
|
const status = resp?.data?.data?.clinic?.status;
|
||||||
|
|
||||||
|
if(status == "rejected"){
|
||||||
|
setIsActive(false);
|
||||||
|
|
||||||
|
// update user state with latest clinic
|
||||||
|
localStorage.setItem("user", JSON.stringify({
|
||||||
|
...user,
|
||||||
|
created_clinics: resp?.data?.data?.clinic
|
||||||
|
}))
|
||||||
|
|
||||||
|
dispatch(setUserRole(USER_ROLES.CLINIC_ADMIN, "rejected"));
|
||||||
|
|
||||||
|
pushNotification(resp?.data?.data?.fileStatus?.reason || "Your clinic registration has been rejected", NOTIFICATION.WARNING);
|
||||||
|
navigation("/docs");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(status=="payment_due"){
|
||||||
|
// setIsActive(false);
|
||||||
|
// pushNotification("Payment due", NOTIFICATION.WARNING);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if(status=="requested_doc"){
|
||||||
|
// setIsActive(false);
|
||||||
|
// pushNotification("Documents requested", NOTIFICATION.WARNING);
|
||||||
|
// }
|
||||||
|
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
getClinic();
|
||||||
// Determine user role based on user data from login reducer
|
// Determine user role based on user data from login reducer
|
||||||
if (user) {
|
if (user) {
|
||||||
// Check if user is a super admin
|
// Check if user is a super admin
|
||||||
|
|
@ -44,9 +93,9 @@ function Dashboard() {
|
||||||
setIsActive(clinicStatus == "active");
|
setIsActive(clinicStatus == "active");
|
||||||
|
|
||||||
if (isSuperAdmin) {
|
if (isSuperAdmin) {
|
||||||
dispatch(setUserRole(USER_ROLES.SUPER_ADMIN));
|
dispatch(setUserRole(USER_ROLES.SUPER_ADMIN, clinicStatus));
|
||||||
} else {
|
} else {
|
||||||
dispatch(setUserRole(USER_ROLES.CLINIC_ADMIN));
|
dispatch(setUserRole(USER_ROLES.CLINIC_ADMIN, clinicStatus));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,11 @@ function YourDetailsForm() {
|
||||||
const selectedLocalityRef = useRef();
|
const selectedLocalityRef = useRef();
|
||||||
const [testConnection, setTestConnDone] = useState(false);
|
const [testConnection, setTestConnDone] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
|
const errorStatus = new URLSearchParams(window.location.search).get("status");
|
||||||
|
|
||||||
|
console.log(errorStatus)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
getLatestClinicId().then((res) => {
|
getLatestClinicId().then((res) => {
|
||||||
|
|
@ -209,6 +214,7 @@ function YourDetailsForm() {
|
||||||
|
|
||||||
if (yourDetailsFormData) {
|
if (yourDetailsFormData) {
|
||||||
defaultFormData.current = { ...yourDetailsFormData };
|
defaultFormData.current = { ...yourDetailsFormData };
|
||||||
|
console.log(yourDetailsFormData)
|
||||||
// setLocalityOption([yourDetailsFormData?.locality])
|
// setLocalityOption([yourDetailsFormData?.locality])
|
||||||
selectedLocalityRef.current = yourDetailsFormData?.locality;
|
selectedLocalityRef.current = yourDetailsFormData?.locality;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue