diff --git a/components/appointment/Container.js b/components/appointment/Container.js index b5f3358..987b368 100644 --- a/components/appointment/Container.js +++ b/components/appointment/Container.js @@ -82,6 +82,8 @@ function Container({ appointmentId={appointmentId} expiresAt={appointmentExpiresAt} doctor={doctor} + data={data} + isForAnother={isForAnother} selectedSlot={selectedSlot} selectedDate={selectedDate} />, diff --git a/components/appointment/paying/index.js b/components/appointment/paying/index.js index 33b0189..def7c4e 100644 --- a/components/appointment/paying/index.js +++ b/components/appointment/paying/index.js @@ -5,56 +5,59 @@ import { Button, MenuItem, Select, FormControl, InputLabel } from "@mui/material import ButtonFixed from "./ButtonFixed"; import { request } from "@/services/response"; -function Paying({ setStep, appointmentId, expiresAt, doctor, selectedSlot, selectedDate }) { - const [selectedBank, setSelectedBank] = useState(""); +const APPOINTMENT_AMOUNT_RIALS = 150000; +const PAYMENT_TTL = 900; + +const banks = [ + { id: "mellat", title: "بانک ملت" }, + { id: "sep", title: "سامان (سپ)" }, +]; + +function Paying({ setStep, appointmentId, expiresAt, doctor, data, isForAnother, selectedSlot }) { + const [selectedBank, setSelectedBank] = useState("mellat"); const [loading, setLoading] = useState(false); + const [testMode, setTestMode] = useState(null); const computeLeft = () => expiresAt ? Math.max(0, Math.floor((expiresAt * 1000 - Date.now()) / 1000)) - : 900; + : PAYMENT_TTL; const [timeLeft, setTimeLeft] = useState(computeLeft); - const banks = [ - { id: "mellat", title: "بانک ملت" }, - { id: "sep", title: "سامان (سپ)" } - ]; - useEffect(() => { - const timer = setInterval(() => { - setTimeLeft(computeLeft()); - }, 1000); - + const timer = setInterval(() => setTimeLeft(computeLeft()), 1000); return () => clearInterval(timer); }, [expiresAt]); + useEffect(() => { + request + .getPaymentConfig() + .then((res) => setTestMode(Boolean(res?.data?.test_mode))) + .catch(() => setTestMode(false)); + }, []); + const formatTime = (seconds) => { - const minutes = Math.floor(seconds / 60); - const secs = seconds % 60; - return `${minutes}:${secs.toString().padStart(2, '0')}`; + const m = Math.floor(seconds / 60); + const s = seconds % 60; + return `${m}:${s.toString().padStart(2, "0")}`; }; + const toman = (APPOINTMENT_AMOUNT_RIALS / 10).toLocaleString("fa-IR"); + const patientName = isForAnother + ? [data?.name?.value, data?.family?.value].filter(Boolean).join(" ").trim() + : data?.name?.value; + const expired = timeLeft === 0; + const progress = Math.max(0, Math.min(100, (timeLeft / PAYMENT_TTL) * 100)); + const handlePayment = async () => { - if (!selectedBank) { - alert("لطفا بانک خود را انتخاب کنید"); - return; - } - - if (!appointmentId) { - alert("شناسه نوبت یافت نشد"); - return; - } - + if (!appointmentId) return; setLoading(true); try { - const paymentPayload = { + const res = await request.postAppointmentPayment({ appointment_uuid: appointmentId, - gateway: selectedBank, + gateway: testMode ? "mellat" : selectedBank, frontend_address: `${window.location.origin}/payment/result`, - }; - - const res = await request.postAppointmentPayment(paymentPayload); - + }); const redirectUrl = res?.data?.redirect_url; if (redirectUrl) { window.location.href = redirectUrl; @@ -69,89 +72,135 @@ function Paying({ setStep, appointmentId, expiresAt, doctor, selectedSlot, selec return (
-
-

- اطلاعات پرداخت +

+

+ تأیید و پرداخت

- {selectedSlot?.start && ( -
- زمان نوبت: - - {moment.unix(selectedSlot.start).locale("fa").format("jD jMMMM jYYYY - HH:mm")} - {doctor?.name ? ` با ${doctor.name}` : ""} - + {/* ── خلاصه نوبت ── */} +
+ {doctor?.name && ( +
+ پزشک + {doctor.name} +
+ )} + {patientName && ( +
+ بیمار + {patientName} +
+ )} + {selectedSlot?.start && ( +
+ زمان نوبت + + {moment.unix(selectedSlot.start).locale("fa").format("dddd jD jMMMM jYYYY")} + {" — ساعت "} + {moment.unix(selectedSlot.start).format("HH:mm")} + +
+ )} +
+ + {/* ── مبلغ ── */} +
+ + مبلغ قابل پرداخت + + + {toman} تومان + +
+ + {/* ── شمارش معکوس ── */} + {!expired && ( +
+
+ + مهلت پرداخت و نگه‌داری نوبت + + + {formatTime(timeLeft)} + +
+
+
+
)} -
-
-

- زمان باقیمانده: -

-

- {formatTime(timeLeft)} + {/* ── درگاه / حالت آزمایشی ── */} + {!expired && ( +

+ {testMode ? ( +
+ 🧪 +
+

درگاه پرداخت آزمایشی

+

+ در این حالت پرداخت واقعی انجام نمی‌شود و نوبت به‌صورت آزمایشی تأیید می‌گردد. +

+
+
+ ) : ( + + انتخاب درگاه پرداخت + + + )} +
+ )} + + {expired && ( +
+

+ مهلت پرداخت تمام شد و نوبت آزاد شد. لطفاً دوباره زمان نوبت را انتخاب کنید.

- - - انتخاب بانک - - - - {/*
-

- مبلغ پیش پرداخت (بیعانه) : -

-

- 10،000 تومان -

-
*/} -
- - - - {timeLeft === 0 && ( -

- مهلت پرداخت تمام شد؛ لطفاً دوباره زمان نوبت را انتخاب کنید. -

)} -
- {timeLeft === 0 ? ( +
+ {expired ? ( ) : ( )}
diff --git a/services/response.js b/services/response.js index a2e7763..6eb2c61 100644 --- a/services/response.js +++ b/services/response.js @@ -73,6 +73,7 @@ export const request = { getMyAppointments: (userId, params) => api.get(`api/v1/appointment/my-appointments/${userId}`, { params, requireAuth: true }), postAppointmentPayment: (data) => api.post(`api/v1/payment/appointment`, data, { requireAuth: true }), + getPaymentConfig: () => api.get(`api/v1/payment/config`, { requireAuth: true }), getPayment: (uuid) => api.get(`api/v1/payment/${uuid}`, { requireAuth: true }), getMyPayments: (userId, params) => api.get(`api/v1/payment/my-payments/${userId}`, { params, requireAuth: true }), postDoctor: (data) => api.post("api/v1/doctor", data),