parent
9e39a1f9a1
commit
344d5792ed
|
|
@ -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 },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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()}`;
|
||||
|
|
|
|||
|
|
@ -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()}`;
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ const ClinicDocUpdater = () => {
|
|||
isDisabled={formik.values.isContractVerified}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item md={4} sm={12} xs={12}>
|
||||
{/* <Grid item md={4} sm={12} xs={12}>
|
||||
<CustomFileUpload
|
||||
label="Add Logo*"
|
||||
documentName="logo"
|
||||
|
|
@ -206,7 +206,7 @@ const ClinicDocUpdater = () => {
|
|||
}
|
||||
isDisabled={formik.values.isLogoVerified}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid> */}
|
||||
</Grid>
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
|
|
|
|||
|
|
@ -229,10 +229,10 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
|||
clinicPhone: number,
|
||||
clinicPonePrefix: countryCode,
|
||||
clinicAddress: clinicResp?.address,
|
||||
clinicOthers: clinicResp?.general_info,
|
||||
otherInfo: clinicResp?.other_info ?? formData.otherInfo,
|
||||
clinicGreetings: clinicResp?.greeting_msg ?? formData.clinicGreetings,
|
||||
clinicScenarios: clinicResp?.scenarios ?? formData.clinicScenarios,
|
||||
clinicOthers: clinicResp?.general_info ?? "",
|
||||
otherInfo: clinicResp?.other_info ?? "",
|
||||
clinicGreetings: clinicResp?.greeting_msg ?? "",
|
||||
clinicScenarios: clinicResp?.scenarios ?? "",
|
||||
integrationSoftware: clinicResp?.integration,
|
||||
practiceId: clinicResp?.pms_id,
|
||||
practiceName: clinicResp?.practice_name,
|
||||
|
|
@ -652,7 +652,6 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
|||
className={classes.mobileNumberInput}
|
||||
type="string"
|
||||
style={{ width: "40%" }}
|
||||
label="Clinic Phone Number"
|
||||
name="clinicPhone"
|
||||
value={formData.clinicPhone}
|
||||
onChange={(e) => {
|
||||
|
|
@ -1018,7 +1017,27 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
|||
</Typography>
|
||||
|
||||
{/* Stepper */}
|
||||
<Stepper activeStep={activeStep} sx={{ mb: 4 }}>
|
||||
<Stepper
|
||||
activeStep={activeStep}
|
||||
sx={{
|
||||
mb: 4,
|
||||
'& .Mui-completed': {
|
||||
'& .MuiStepIcon-root': {
|
||||
color: 'success.main',
|
||||
},
|
||||
'& .MuiStepLabel-label.Mui-completed': {
|
||||
color: 'success.main',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
'& .MuiStepIcon-active': {
|
||||
color: 'primary.main',
|
||||
},
|
||||
'& .MuiStepIcon-completed': {
|
||||
color: 'success.main',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{steps.map((label, index) => {
|
||||
const stepProps = {};
|
||||
const labelProps = {};
|
||||
|
|
@ -1054,9 +1073,9 @@ If No -Pt who do not have a Medicare card / Private patients with or without I
|
|||
</Typography>
|
||||
<Box sx={{ display: "flex", flexDirection: "row", pt: 2 }}>
|
||||
<Box sx={{ flex: "1 1 auto" }} />
|
||||
<Button onClick={handleBack} sx={{ mr: 1 }} color="primary" variant="outlined">
|
||||
{/* <Button onClick={handleBack} sx={{ mr: 1 }} color="primary" variant="outlined">
|
||||
Back
|
||||
</Button>
|
||||
</Button> */}
|
||||
<Button onClick={handleSubmit} variant="contained" color="primary" type="submit" disabled={activeStep == 4 && !testConnDone}>
|
||||
Submit Setup
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -84,18 +84,13 @@ const ClinicsList = () => {
|
|||
{
|
||||
enableColumnFilter: false,
|
||||
enableSorting: true,
|
||||
size: "220px",
|
||||
size: 100,
|
||||
accessorKey: "name",
|
||||
header: "Clinic Name",
|
||||
Cell: ({ row }) => (
|
||||
<>
|
||||
<div className={classes.companyNameTableColumn}>
|
||||
{/* <img
|
||||
className={classes.companyNameLogo}
|
||||
src="https://dev-ai-appointment.s3.ap-southeast-2.amazonaws.com/common/clinic_logo.jpg"
|
||||
alt="logo"
|
||||
/> */}
|
||||
<div className={classes.companyName}>
|
||||
<div>
|
||||
<div>
|
||||
<Link
|
||||
to={{
|
||||
pathname: `/clinics/${row?.original?.id}`,
|
||||
|
|
@ -105,10 +100,6 @@ const ClinicsList = () => {
|
|||
>
|
||||
<>{row?.original.name}</>
|
||||
</Link>
|
||||
|
||||
<div className={classes.companyWebsiteLabel}>
|
||||
{row.original.website}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
@ -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) && (
|
||||
<div>
|
||||
<Link
|
||||
onClick={() => handleEmailSent(row)}
|
||||
className={classes.sendEmailStatus}
|
||||
>
|
||||
<u>
|
||||
{row.original.status === CLINIC_STATUS.ON_HOLD &&
|
||||
"Resend On Hold Mail"}
|
||||
{row.original.status === CLINIC_STATUS.REJECTED &&
|
||||
"Resend Rejection Mail"}
|
||||
</u>
|
||||
</Link>
|
||||
<div className={classes.sendEmailLastSentMailDate}>
|
||||
Last Sent On:
|
||||
{format(
|
||||
new Date(row?.original?.lastEmailSent),
|
||||
"dd MMM yyyy"
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
},
|
||||
// {
|
||||
// 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) && (
|
||||
// <div>
|
||||
// <Link
|
||||
// onClick={() => handleEmailSent(row)}
|
||||
// className={classes.sendEmailStatus}
|
||||
// >
|
||||
// <u>
|
||||
// {row.original.status === CLINIC_STATUS.ON_HOLD &&
|
||||
// "Resend On Hold Mail"}
|
||||
// {row.original.status === CLINIC_STATUS.REJECTED &&
|
||||
// "Resend Rejection Mail"}
|
||||
// </u>
|
||||
// </Link>
|
||||
// <div className={classes.sendEmailLastSentMailDate}>
|
||||
// Last Sent On:
|
||||
// {format(
|
||||
// new Date(row?.original?.lastEmailSent),
|
||||
// "dd MMM yyyy"
|
||||
// )}
|
||||
// </div>
|
||||
// </div>
|
||||
// )}
|
||||
// </>
|
||||
// ),
|
||||
// },
|
||||
// .................location column..................
|
||||
{
|
||||
size: 100,
|
||||
size: 150,
|
||||
enableColumnFilter: false,
|
||||
enableSorting: true,
|
||||
accessorKey: "city",
|
||||
|
|
@ -196,7 +187,7 @@ const ClinicsList = () => {
|
|||
accessorFn: ({ status }) => (
|
||||
<>
|
||||
<Chip
|
||||
className={classes.chipClass}
|
||||
// className={classes.chipClass}
|
||||
label={
|
||||
status === CLINIC_STATUS.UNDER_REVIEW.toLowerCase() ? (
|
||||
"Under Review"
|
||||
|
|
@ -275,14 +266,8 @@ const ClinicsList = () => {
|
|||
header: "Clinic Name",
|
||||
Cell: ({ row }) => (
|
||||
<>
|
||||
<div className={classes.companyNameTableColumn}>
|
||||
{/* <img
|
||||
className={classes.companyNameLogo}
|
||||
src="https://dev-ai-appointment.s3.ap-southeast-2.amazonaws.com/common/clinic_logo.jpg"
|
||||
alt="logo"
|
||||
/> */}
|
||||
|
||||
<div className={classes.companyName}>
|
||||
<div>
|
||||
<div>
|
||||
<Link
|
||||
to={{
|
||||
pathname: `/clinics/${row?.original?.id}`,
|
||||
|
|
@ -292,9 +277,6 @@ const ClinicsList = () => {
|
|||
>
|
||||
<>{row?.original.name}</>
|
||||
</Link>
|
||||
<div className={classes.companyWebsiteLabel}>
|
||||
{row.original.website}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -146,13 +146,13 @@ const PaymentConfig = () => {
|
|||
<Grid item xs={12} md={4}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Per Minute Charges"
|
||||
label="Per Call Charges"
|
||||
name="per_call_charges"
|
||||
value={paymentConfig.per_call_charges}
|
||||
onChange={handleInputChange}
|
||||
InputProps={{
|
||||
startAdornment: <InputAdornment position="start">$</InputAdornment>,
|
||||
endAdornment: <InputAdornment position="end">/min</InputAdornment>,
|
||||
endAdornment: <InputAdornment position="end">/calls</InputAdornment>,
|
||||
}}
|
||||
variant="outlined"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: "100vh",
|
||||
background: "linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
p: 2,
|
||||
}}
|
||||
>
|
||||
<Card sx={{ maxWidth: 400, width: "100%", textAlign: "center" }}>
|
||||
<CardContent sx={{ p: 4 }}>
|
||||
{/* Header */}
|
||||
<Avatar
|
||||
sx={{
|
||||
width: 64,
|
||||
height: 64,
|
||||
bgcolor: blue[100],
|
||||
color: blue[600],
|
||||
mx: "auto",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<Schedule />
|
||||
</Avatar>
|
||||
|
||||
<Typography variant="h5" fontWeight="bold" gutterBottom>
|
||||
Processing Your Payment
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||
Please wait while we confirm your subscription and prepare your
|
||||
invoice...
|
||||
</Typography>
|
||||
|
||||
{/* Loading Animation */}
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<CircularProgress size={40} sx={{ mb: 2 }} />
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Time elapsed: {formatTime(timeElapsed)}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Progress Steps */}
|
||||
<Box sx={{ mb: 4 }}>
|
||||
<Stack spacing={1}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
>
|
||||
<CheckCircle
|
||||
sx={{ color: green[500], mr: 1, fontSize: 18 }}
|
||||
/>
|
||||
<Typography variant="body2" sx={{ color: green[600] }}>
|
||||
Payment Submitted
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
>
|
||||
<CircularProgress
|
||||
size={16}
|
||||
sx={{ mr: 1, color: blue[500] }}
|
||||
/>
|
||||
<Typography variant="body2" sx={{ color: blue[600] }}>
|
||||
Confirming Payment
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
>
|
||||
<Schedule sx={{ color: grey[400], mr: 1, fontSize: 18 }} />
|
||||
<Typography variant="body2" color="text.disabled">
|
||||
Generating Invoice
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
{/* Back Button */}
|
||||
<Button
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
startIcon={<ArrowBack />}
|
||||
onClick={goToLogin}
|
||||
sx={{ mt: 2 }}
|
||||
>
|
||||
Back to Login
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
if (status === "success") {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: "100vh",
|
||||
background: "linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
p: 2,
|
||||
}}
|
||||
>
|
||||
<Card sx={{ maxWidth: 400, width: "100%", textAlign: "center" }}>
|
||||
<CardContent sx={{ p: 4 }}>
|
||||
{/* Success Header */}
|
||||
<Avatar
|
||||
sx={{
|
||||
width: 64,
|
||||
height: 64,
|
||||
bgcolor: green[100],
|
||||
color: green[600],
|
||||
mx: "auto",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<CheckCircle />
|
||||
</Avatar>
|
||||
|
||||
<Typography variant="h5" fontWeight="bold" gutterBottom>
|
||||
Payment Successful!
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||
Your subscription has been activated and your invoice is ready.
|
||||
</Typography>
|
||||
|
||||
{/* Processing Time */}
|
||||
<Chip
|
||||
label={`Processed in ${formatTime(timeElapsed)}`}
|
||||
color="success"
|
||||
variant="outlined"
|
||||
sx={{ mb: 3 }}
|
||||
/>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<Stack spacing={2}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
startIcon={<OpenInNew />}
|
||||
onClick={openInvoice}
|
||||
sx={{ py: 1.5 }}
|
||||
>
|
||||
View Invoice
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
onClick={goToDashboard}
|
||||
sx={{ py: 1.5 }}
|
||||
>
|
||||
Continue to Dashboard
|
||||
</Button>
|
||||
|
||||
<Divider sx={{ my: 1 }} />
|
||||
|
||||
<Button
|
||||
fullWidth
|
||||
color="inherit"
|
||||
startIcon={<ArrowBack />}
|
||||
onClick={goToLogin}
|
||||
>
|
||||
Back to Login
|
||||
</Button>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
if (status === "error") {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: "100vh",
|
||||
background: "linear-gradient(135deg, #ffebee 0%, #ffcdd2 100%)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
p: 2,
|
||||
}}
|
||||
>
|
||||
<Card sx={{ maxWidth: 400, width: "100%", textAlign: "center" }}>
|
||||
<CardContent sx={{ p: 4 }}>
|
||||
{/* Error Header */}
|
||||
<Avatar
|
||||
sx={{
|
||||
width: 64,
|
||||
height: 64,
|
||||
bgcolor: red[100],
|
||||
color: red[600],
|
||||
mx: "auto",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<Error />
|
||||
</Avatar>
|
||||
|
||||
<Typography variant="h5" fontWeight="bold" gutterBottom>
|
||||
Payment Processing Error
|
||||
</Typography>
|
||||
|
||||
<Alert severity="error" sx={{ mb: 3, textAlign: "left" }}>
|
||||
We encountered an issue while processing your payment. Please try
|
||||
again or contact support.
|
||||
</Alert>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<Stack spacing={2}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
startIcon={<Refresh />}
|
||||
onClick={handleRetry}
|
||||
sx={{ py: 1.5 }}
|
||||
>
|
||||
Try Again
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
startIcon={<ArrowBack />}
|
||||
onClick={goToLogin}
|
||||
sx={{ py: 1.5 }}
|
||||
>
|
||||
Back to Login
|
||||
</Button>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default PaymentSuccessPage;
|
||||
Loading…
Reference in New Issue