refactor: enhance appointment handling by adding appointmentId state and updating payment process
This commit is contained in:
@@ -34,6 +34,8 @@ function Container({
|
|||||||
setSelectedSlot,
|
setSelectedSlot,
|
||||||
selectedDate,
|
selectedDate,
|
||||||
setSelectedDate,
|
setSelectedDate,
|
||||||
|
appointmentId,
|
||||||
|
setAppointmentId,
|
||||||
}) {
|
}) {
|
||||||
const elements = [
|
const elements = [
|
||||||
<Date
|
<Date
|
||||||
@@ -70,8 +72,9 @@ function Container({
|
|||||||
doctor={doctor}
|
doctor={doctor}
|
||||||
selectedSlot={selectedSlot}
|
selectedSlot={selectedSlot}
|
||||||
selectedDate={selectedDate}
|
selectedDate={selectedDate}
|
||||||
|
setAppointmentId={setAppointmentId}
|
||||||
/>,
|
/>,
|
||||||
<Paying setStep={setStep} />,
|
<Paying setStep={setStep} appointmentId={appointmentId} />,
|
||||||
<SuccessPay setStep={setStep} />,
|
<SuccessPay setStep={setStep} />,
|
||||||
<FailedPay setStep={setStep} />,
|
<FailedPay setStep={setStep} />,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import ArrowLeftB from "@/components/icons/ArrowLeftB";
|
|||||||
import { request } from "@/services/response";
|
import { request } from "@/services/response";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
|
|
||||||
function SubmitData({ setStep, data, prevData, setErrors, doctor, selectedSlot, selectedDate }) {
|
function SubmitData({ setStep, data, prevData, setErrors, doctor, selectedSlot, selectedDate, setAppointmentId }) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const newStep = () => setStep((prev) => prev + 1);
|
const newStep = () => setStep((prev) => prev + 1);
|
||||||
|
|
||||||
@@ -113,7 +113,10 @@ function SubmitData({ setStep, data, prevData, setErrors, doctor, selectedSlot,
|
|||||||
info: ""
|
info: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
await request.postAppointment(appointmentPayload);
|
const appointmentResponse = await request.postAppointment(appointmentPayload);
|
||||||
|
if (appointmentResponse?.id) {
|
||||||
|
setAppointmentId(appointmentResponse.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ function Detail({
|
|||||||
doctor,
|
doctor,
|
||||||
selectedSlot,
|
selectedSlot,
|
||||||
selectedDate,
|
selectedDate,
|
||||||
|
setAppointmentId,
|
||||||
}) {
|
}) {
|
||||||
const [insurance, setInsurance] = useState();
|
const [insurance, setInsurance] = useState();
|
||||||
const [supplementaryInsurance, setSupplementaryInsurance] = useState();
|
const [supplementaryInsurance, setSupplementaryInsurance] = useState();
|
||||||
@@ -93,14 +94,15 @@ function Detail({
|
|||||||
</p>
|
</p>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<SubmitData
|
<SubmitData
|
||||||
setStep={setStep}
|
setStep={setStep}
|
||||||
data={data}
|
data={data}
|
||||||
prevData={prevData}
|
prevData={prevData}
|
||||||
setErrors={setErrors}
|
setErrors={setErrors}
|
||||||
doctor={doctor}
|
doctor={doctor}
|
||||||
selectedSlot={selectedSlot}
|
selectedSlot={selectedSlot}
|
||||||
selectedDate={selectedDate}
|
selectedDate={selectedDate}
|
||||||
|
setAppointmentId={setAppointmentId}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ function AppointmentPage({ doctor, disabledDates, matchedCity }) {
|
|||||||
// Appointment slot states
|
// Appointment slot states
|
||||||
const [selectedSlot, setSelectedSlot] = useState(null);
|
const [selectedSlot, setSelectedSlot] = useState(null);
|
||||||
const [selectedDate, setSelectedDate] = useState(null);
|
const [selectedDate, setSelectedDate] = useState(null);
|
||||||
|
const [appointmentId, setAppointmentId] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchUserData = async () => {
|
const fetchUserData = async () => {
|
||||||
@@ -201,6 +202,8 @@ function AppointmentPage({ doctor, disabledDates, matchedCity }) {
|
|||||||
setSelectedSlot={setSelectedSlot}
|
setSelectedSlot={setSelectedSlot}
|
||||||
selectedDate={selectedDate}
|
selectedDate={selectedDate}
|
||||||
setSelectedDate={setSelectedDate}
|
setSelectedDate={setSelectedDate}
|
||||||
|
appointmentId={appointmentId}
|
||||||
|
setAppointmentId={setAppointmentId}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,70 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
import ArrowLeftB from "@/components/icons/ArrowLeftB";
|
import ArrowLeftB from "@/components/icons/ArrowLeftB";
|
||||||
import { Button } from "@mui/material";
|
import { Button, MenuItem, Select, FormControl, InputLabel } from "@mui/material";
|
||||||
import ButtonFixed from "./ButtonFixed";
|
import ButtonFixed from "./ButtonFixed";
|
||||||
|
import { request } from "@/services/response";
|
||||||
|
|
||||||
|
function Paying({ setStep, appointmentId }) {
|
||||||
|
const [selectedBank, setSelectedBank] = useState("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [timeLeft, setTimeLeft] = useState(600); // 10 minutes in seconds
|
||||||
|
|
||||||
|
const banks = [
|
||||||
|
{ id: "mellat", title: "بانک ملت" },
|
||||||
|
{ id: "saman", title: "سامان کیش" }
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (timeLeft === 0) return;
|
||||||
|
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
setTimeLeft((prev) => prev - 1);
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => clearInterval(timer);
|
||||||
|
}, [timeLeft]);
|
||||||
|
|
||||||
|
const formatTime = (seconds) => {
|
||||||
|
const minutes = Math.floor(seconds / 60);
|
||||||
|
const secs = seconds % 60;
|
||||||
|
return `${minutes}:${secs.toString().padStart(2, '0')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePayment = async () => {
|
||||||
|
if (!selectedBank) {
|
||||||
|
alert("لطفا بانک خود را انتخاب کنید");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!appointmentId) {
|
||||||
|
alert("شناسه نوبت یافت نشد");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const paymentPayload = {
|
||||||
|
payment_method: selectedBank,
|
||||||
|
bundle: "appointment",
|
||||||
|
entity_reference_id: appointmentId
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await request.postPayment(paymentPayload);
|
||||||
|
|
||||||
|
// Redirect to payment gateway
|
||||||
|
if (response?.uuid) {
|
||||||
|
const paymentUrl = `${process.env.NEXT_PUBLIC_API_URL}/payment/${response.uuid}`;
|
||||||
|
window.location.href = paymentUrl;
|
||||||
|
} else {
|
||||||
|
setStep((prev) => prev + 1);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Payment error:", error);
|
||||||
|
alert("خطا در پرداخت");
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function Paying({ setTypePay, fadeElement, setStep }) {
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full lg:w-[59%]">
|
<div className="w-full lg:w-[59%]">
|
||||||
<div
|
<div
|
||||||
@@ -12,29 +74,60 @@ function Paying({ setTypePay, fadeElement, setStep }) {
|
|||||||
<p className="text-[#3B3B3B] text-[14px] sm:text-[16px] md:text-[18px] lg:text-[20px] font-bold">
|
<p className="text-[#3B3B3B] text-[14px] sm:text-[16px] md:text-[18px] lg:text-[20px] font-bold">
|
||||||
اطلاعات پرداخت
|
اطلاعات پرداخت
|
||||||
</p>
|
</p>
|
||||||
<div className="flex justify-between items-center mt-[12px] sm:mt-[18px] md:mt-[24px] lg:mt-[30px]">
|
|
||||||
<p className="text-[#616161] text-[14px] md:text-[16px] font-medium">
|
<div className="mt-[12px] sm:mt-[18px] md:mt-[24px] lg:mt-[30px]">
|
||||||
مبلغ پیش پرداخت (بیعانه) :{" "}
|
<div className="flex justify-between items-center mb-4">
|
||||||
</p>
|
<p className="text-[#616161] text-[14px] md:text-[16px] font-medium">
|
||||||
<p className="text-[#525252] text-[14px] md:text-[16px] font-bold">
|
زمان باقیمانده:
|
||||||
20،000 تومان
|
</p>
|
||||||
</p>
|
<p className={`text-[14px] md:text-[16px] font-bold ${timeLeft < 60 ? 'text-red-500' : 'text-[#525252]'}`}>
|
||||||
|
{formatTime(timeLeft)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormControl fullWidth className="!mb-4">
|
||||||
|
<InputLabel id="bank-select-label">انتخاب بانک</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="bank-select-label"
|
||||||
|
value={selectedBank}
|
||||||
|
label="انتخاب بانک"
|
||||||
|
onChange={(e) => setSelectedBank(e.target.value)}
|
||||||
|
>
|
||||||
|
{banks.map((bank) => (
|
||||||
|
<MenuItem key={bank.id} value={bank.id}>
|
||||||
|
{bank.title}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
{/* <div className="flex justify-between items-center">
|
||||||
|
<p className="text-[#616161] text-[14px] md:text-[16px] font-medium">
|
||||||
|
مبلغ پیش پرداخت (بیعانه) :
|
||||||
|
</p>
|
||||||
|
<p className="text-[#525252] text-[14px] md:text-[16px] font-bold">
|
||||||
|
10،000 تومان
|
||||||
|
</p>
|
||||||
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span className="bg-[#D7D7D7] hidden md:block h-px w-full mt-[32px] mb-[25px]"></span>
|
<span className="bg-[#D7D7D7] hidden md:block h-px w-full mt-[32px] mb-[25px]"></span>
|
||||||
|
|
||||||
<ButtonFixed>
|
<ButtonFixed>
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<p className="text-[#616161] md:text-[#3B3B3B] text-[14px] md:text-[16px] font-bold">
|
<p className="text-[#616161] md:text-[#3B3B3B] text-[14px] md:text-[16px] font-bold">
|
||||||
مبلغ قابل پرداخت : 20،000 تومان
|
مبلغ قابل پرداخت : 10،000 تومان
|
||||||
</p>
|
</p>
|
||||||
<Button
|
<Button
|
||||||
className="!gap-[4px] !mr-auto !flex !px-[12px] !p-[7px] md:!py-[9px] !min-w-[157px]"
|
className="!gap-[4px] !mr-auto !flex !px-[12px] !p-[7px] md:!py-[9px] !min-w-[157px]"
|
||||||
onClick={() => setStep((prev) => prev + 1)}
|
onClick={handlePayment}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
|
disabled={loading || !selectedBank || timeLeft === 0}
|
||||||
>
|
>
|
||||||
<p className="text-[#EFEFEF] text-[16px] font-medium">
|
<p className={`${loading && "opacity-0"} text-[#EFEFEF] text-[16px] font-medium`}>
|
||||||
پرداخت نهایی
|
{timeLeft === 0 ? "زمان پرداخت تمام شد" : "پرداخت نهایی"}
|
||||||
</p>
|
</p>
|
||||||
<ArrowLeftB />
|
{timeLeft > 0 && <ArrowLeftB />}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</ButtonFixed>
|
</ButtonFixed>
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ export const request = {
|
|||||||
removeTokenHead
|
removeTokenHead
|
||||||
),
|
),
|
||||||
postAppointment: (data) => api.post(`api/v1/appointment`, data, { requireAuth: true }),
|
postAppointment: (data) => api.post(`api/v1/appointment`, data, { requireAuth: true }),
|
||||||
|
postPayment: (data) => api.post(`api/v1/payment`, data, { requireAuth: true }),
|
||||||
postDoctor: (data) => api.post("api/v1/doctor", data),
|
postDoctor: (data) => api.post("api/v1/doctor", data),
|
||||||
postImageUpload: (data) =>
|
postImageUpload: (data) =>
|
||||||
api.post("file/upload/clinic_pro/doctor/field_image", data, {
|
api.post("file/upload/clinic_pro/doctor/field_image", data, {
|
||||||
|
|||||||
Reference in New Issue
Block a user