diff --git a/src/routes/index.js b/src/routes/index.js index 5fe51bf..f31d612 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -16,6 +16,7 @@ import ClinicDocUpdater from "../views/ClinicDocUpdate"; import ForgotPassword from "../views/ForgotPassword"; import ResetPassword from "../views/ResetPassword"; import SignupCharges from "../views/SignupCharges"; +import PaymentSuccessPage from "../views/WaitingPage"; export const routesData = [ { @@ -51,9 +52,10 @@ export const routesData = [ component: ForgotPassword, }, { - path: 'reset-password', + path: "reset-password", component: ResetPassword, }, + { path: "waiting", component: PaymentSuccessPage }, ], }, ]; diff --git a/src/services/clinics.service.js b/src/services/clinics.service.js index de13094..df26fdc 100644 --- a/src/services/clinics.service.js +++ b/src/services/clinics.service.js @@ -137,7 +137,7 @@ export const deleteClinicOffer = (id) => { export const getClinicDoctors = (params) => { let searchParams = new URLSearchParams(); searchParams.append("limit", params?.pagination?.pageSize ?? 10); - searchParams.append("page", params?.pagination.pageIndex + 1 ?? 1); + searchParams.append("page", params?.pagination?.pageIndex + 1 ?? 1); searchParams.append("search", params?.globalFilter ?? ""); const url = `/clinic-doctors?${searchParams.toString()}`; diff --git a/src/services/masterData.services.js b/src/services/masterData.services.js index 20e5eb6..83aee0f 100644 --- a/src/services/masterData.services.js +++ b/src/services/masterData.services.js @@ -2,8 +2,8 @@ import { axiosInstance } from "../config/api"; export const getMasterData = (params) => { let searchParams = new URLSearchParams(); - searchParams.append("limit", params?.pagination?.pageSize ?? 10); - searchParams.append("page", params?.pagination.pageIndex + 1 ?? 1); + searchParams.append("limit", 100); + searchParams.append("page", 1); searchParams.append("search", params?.globalFilter ?? ""); const url = `/admin/master-data?${searchParams.toString()}`; diff --git a/src/views/ClinicDocUpdate/index.jsx b/src/views/ClinicDocUpdate/index.jsx index c6428bc..f0fe112 100644 --- a/src/views/ClinicDocUpdate/index.jsx +++ b/src/views/ClinicDocUpdate/index.jsx @@ -191,7 +191,7 @@ const ClinicDocUpdater = () => { isDisabled={formik.values.isContractVerified} /> - + {/* { } isDisabled={formik.values.isLogoVerified} /> - + */} + */} diff --git a/src/views/ClinicsList/index.jsx b/src/views/ClinicsList/index.jsx index 90eb680..516cc12 100644 --- a/src/views/ClinicsList/index.jsx +++ b/src/views/ClinicsList/index.jsx @@ -84,18 +84,13 @@ const ClinicsList = () => { { enableColumnFilter: false, enableSorting: true, - size: "220px", + size: 100, accessorKey: "name", header: "Clinic Name", Cell: ({ row }) => ( <> -
- {/* logo */} -
+
+
{ > <>{row?.original.name} - -
- {row.original.website} -
@@ -118,7 +109,7 @@ const ClinicsList = () => { { enableColumnFilter: false, enableSorting: true, - size: 100, + size: 150, accessorKey: "update_time", header: "Req.Raised On", Cell: ({ row }) => ( @@ -132,43 +123,43 @@ const ClinicsList = () => { ), }, // .................send email column.................. - { - enableColumnFilter: false, - enableSorting: true, - accessorKey: "lastEmailSent", - size: 190, - header: "Send Mail", - Cell: ({ row }) => ( - <> - {(row.original.status === CLINIC_STATUS.REJECTED || - row.original.status === CLINIC_STATUS.ON_HOLD) && ( -
- handleEmailSent(row)} - className={classes.sendEmailStatus} - > - - {row.original.status === CLINIC_STATUS.ON_HOLD && - "Resend On Hold Mail"} - {row.original.status === CLINIC_STATUS.REJECTED && - "Resend Rejection Mail"} - - -
- Last Sent On: - {format( - new Date(row?.original?.lastEmailSent), - "dd MMM yyyy" - )} -
-
- )} - - ), - }, + // { + // enableColumnFilter: false, + // enableSorting: true, + // accessorKey: "lastEmailSent", + // size: 190, + // header: "Send Mail", + // Cell: ({ row }) => ( + // <> + // {(row.original.status === CLINIC_STATUS.REJECTED || + // row.original.status === CLINIC_STATUS.ON_HOLD) && ( + //
+ // handleEmailSent(row)} + // className={classes.sendEmailStatus} + // > + // + // {row.original.status === CLINIC_STATUS.ON_HOLD && + // "Resend On Hold Mail"} + // {row.original.status === CLINIC_STATUS.REJECTED && + // "Resend Rejection Mail"} + // + // + //
+ // Last Sent On: + // {format( + // new Date(row?.original?.lastEmailSent), + // "dd MMM yyyy" + // )} + //
+ //
+ // )} + // + // ), + // }, // .................location column.................. { - size: 100, + size: 150, enableColumnFilter: false, enableSorting: true, accessorKey: "city", @@ -196,7 +187,7 @@ const ClinicsList = () => { accessorFn: ({ status }) => ( <> { header: "Clinic Name", Cell: ({ row }) => ( <> -
- {/* logo */} - -
+
+
{ > <>{row?.original.name} -
- {row.original.website} -
diff --git a/src/views/Dashboard/components/PaymentConfig.jsx b/src/views/Dashboard/components/PaymentConfig.jsx index 6f73484..359f0d3 100644 --- a/src/views/Dashboard/components/PaymentConfig.jsx +++ b/src/views/Dashboard/components/PaymentConfig.jsx @@ -146,13 +146,13 @@ const PaymentConfig = () => { $, - endAdornment: /min, + endAdornment: /calls, }} variant="outlined" /> diff --git a/src/views/MasterData/index.jsx b/src/views/MasterData/index.jsx index bf3e629..8d1b3d8 100644 --- a/src/views/MasterData/index.jsx +++ b/src/views/MasterData/index.jsx @@ -143,7 +143,7 @@ const MasterDataManagement = () => { const handleEdit = async (row) => { setEditId(row.original.id); // Store the ID for update operation - setType(row.original.type); + setType(row.original.type.charAt(0).toUpperCase() + row.original.type.slice(1)); setOpenDialog(true); }; diff --git a/src/views/Signup/YourDetailsForm.jsx b/src/views/Signup/YourDetailsForm.jsx index 5cc1599..ee2f34b 100644 --- a/src/views/Signup/YourDetailsForm.jsx +++ b/src/views/Signup/YourDetailsForm.jsx @@ -346,7 +346,10 @@ function YourDetailsForm() { pushNotification(response?.data?.message, NOTIFICATION.ERROR); return; } - pushNotification("OTP sent successfully to your email", NOTIFICATION.SUCCESS); + pushNotification( + "OTP sent successfully to your email", + NOTIFICATION.SUCCESS + ); }; const verifyOTP = async (e) => { @@ -393,8 +396,9 @@ function YourDetailsForm() { return; } pushNotification(response?.data?.message, NOTIFICATION.SUCCESS); + localStorage.setItem("temp_signup_token", response?.data?.data?.token); // open new page for stripe payment from url - const newWindow = window.open(response?.data?.data, "_blank", "noopener,noreferrer"); + window.open(response?.data?.data?.url, "_blank", "noopener,noreferrer"); // if (!newWindow || newWindow.closed || typeof newWindow.closed === 'undefined') { // // Fallback in case popup is blocked // window.location.href = response?.data?.data; diff --git a/src/views/WaitingPage/index.jsx b/src/views/WaitingPage/index.jsx new file mode 100644 index 0000000..7e85f66 --- /dev/null +++ b/src/views/WaitingPage/index.jsx @@ -0,0 +1,436 @@ +import React, { useState, useEffect, useRef } from "react"; +import { + Box, + Card, + CardContent, + Typography, + Button, + CircularProgress, + Avatar, + LinearProgress, + Chip, + Stack, + Paper, + Divider, + Alert, +} from "@mui/material"; +import { + CheckCircle, + Schedule, + ArrowBack, + OpenInNew, + Error, + Refresh, +} from "@mui/icons-material"; +import { green, blue, red, grey } from "@mui/material/colors"; +import { API_BASE_URL } from "../../common/envVariables"; +import { useNavigate } from "react-router-dom"; + +const PaymentSuccessPage = () => { + const [status, setStatus] = useState("processing"); // 'processing', 'success', 'error' + const [invoiceUrl, setInvoiceUrl] = useState(""); + const [timeElapsed, setTimeElapsed] = useState(0); + const [token, setToken] = useState(""); + const navigate = useNavigate(); + + // Use refs to track active polling and timer + const pollingRef = useRef(null); + const timerRef = useRef(null); + const isPollingActiveRef = useRef(false); + + const checkPaymentStatus = async () => { + try { + if (!token || !isPollingActiveRef.current) { + return; + } + + const response = await fetch(`${API_BASE_URL}/stripe/get-invoice`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + const data = await response.json(); + + if (data.data && isPollingActiveRef.current) { + // Success - stop polling and timer + isPollingActiveRef.current = false; + if (pollingRef.current) { + clearTimeout(pollingRef.current); + pollingRef.current = null; + } + if (timerRef.current) { + clearInterval(timerRef.current); + timerRef.current = null; + } + + setStatus("success"); + setInvoiceUrl(data.data); + } else if (isPollingActiveRef.current) { + // Still processing, check again in 10 seconds + pollingRef.current = setTimeout(() => checkPaymentStatus(), 10000); + } + } catch (error) { + console.error("Error checking payment status:", error); + if (isPollingActiveRef.current) { + // Retry after 10 seconds on error + pollingRef.current = setTimeout(() => checkPaymentStatus(), 10000); + } + } + }; + + const startTimer = () => { + timerRef.current = setInterval(() => { + setTimeElapsed(prev => prev + 1); + }, 1000); + }; + + const stopPollingAndTimer = () => { + isPollingActiveRef.current = false; + + if (pollingRef.current) { + clearTimeout(pollingRef.current); + pollingRef.current = null; + } + + if (timerRef.current) { + clearInterval(timerRef.current); + timerRef.current = null; + } + }; + + const openInvoice = () => { + // Stop all polling and timer before navigation + stopPollingAndTimer(); + + if (invoiceUrl) { + window.open(invoiceUrl, "_blank"); + } + + // Clean up and navigate + localStorage.removeItem("temp_signup_token"); + setToken(""); + navigate("/auth/login"); + }; + + const goToLogin = () => { + stopPollingAndTimer(); + localStorage.removeItem("temp_signup_token"); + navigate("/auth/login"); + }; + + const goToDashboard = () => { + stopPollingAndTimer(); + navigate("/dashboard"); + }; + + const handleRetry = () => { + stopPollingAndTimer(); + setStatus("processing"); + setTimeElapsed(0); + isPollingActiveRef.current = true; + startTimer(); + checkPaymentStatus(); + }; + + const formatTime = (seconds) => { + const mins = Math.floor(seconds / 60); + const secs = seconds % 60; + return `${mins}:${secs.toString().padStart(2, "0")}`; + }; + + useEffect(() => { + const storedToken = localStorage.getItem("temp_signup_token"); + if (!storedToken) { + navigate("/auth/login"); + return; + } + + setToken(storedToken); + isPollingActiveRef.current = true; + startTimer(); + + // Start checking payment status once token is set + const initializeChecking = async () => { + if (storedToken) { + checkPaymentStatus(); + } + }; + + initializeChecking(); + + // Cleanup function + return () => { + stopPollingAndTimer(); + }; + }, []); // Remove token from dependency array to avoid infinite loop + + // Separate useEffect for when token changes + useEffect(() => { + if (token && status === "processing" && !isPollingActiveRef.current) { + isPollingActiveRef.current = true; + checkPaymentStatus(); + } + }, [token]); + + if (status === "processing") { + return ( + + + + {/* Header */} + + + + + + Processing Your Payment + + + + Please wait while we confirm your subscription and prepare your + invoice... + + + {/* Loading Animation */} + + + + Time elapsed: {formatTime(timeElapsed)} + + + + {/* Progress Steps */} + + + + + + Payment Submitted + + + + + + + Confirming Payment + + + + + + + Generating Invoice + + + + + + {/* Back Button */} + + + + + ); + } + + if (status === "success") { + return ( + + + + {/* Success Header */} + + + + + + Payment Successful! + + + + Your subscription has been activated and your invoice is ready. + + + {/* Processing Time */} + + + {/* Action Buttons */} + + + + + + + + + + + + + ); + } + + if (status === "error") { + return ( + + + + {/* Error Header */} + + + + + + Payment Processing Error + + + + We encountered an issue while processing your payment. Please try + again or contact support. + + + {/* Action Buttons */} + + + + + + + + + ); + } +}; + +export default PaymentSuccessPage; \ No newline at end of file