import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { useNavigate } from "react-router-dom";
import { Cafe } from "../services/campaignApi";
import { chargePageUrl, createCharge } from "../services/ipgApi";
import { fetchWalletBalances } from "../services/walletApi";
import { formatPersianNumber } from "../utils/formatNumber";
import { toE164 } from "../utils/phone";
import { setPendingReservation } from "../utils/pendingReservation";
import { getUserPhone } from "../utils/userPhone";
import Icon from "./Icon";
interface ReservationModalProps {
isOpen: boolean;
onClose: () => void;
cafe: Cafe;
ticketPrice: number;
cafeMatchScheduleUuid: string;
}
// TODO: there's no "get the logged-in customer's own wallet uuid" endpoint yet —
// these are fixed test wallet ids given directly for now, replace once that exists
const WALLET_UUIDS = ["e7c9d4d1-4d1f-43b2-96f7-4d4a168f480d", "af7d967f-30c0-409b-9066-2549f2da5e5e"];
function PaymentRow({
label,
amount,
emphasize = false,
bottomBorder = false,
infoIconParam = false,
}: {
label: string;
amount: number;
emphasize?: boolean;
bottomBorder?: boolean;
infoIconParam?: boolean;
}) {
return (
{label}
{infoIconParam && (
)}
{formatPersianNumber(amount)} تومان
);
}
export default function ReservationModal({
isOpen,
onClose,
cafe,
ticketPrice,
cafeMatchScheduleUuid,
}: ReservationModalProps) {
const navigate = useNavigate();
const [fullName, setFullName] = useState("");
const [count, setCount] = useState(1);
const [walletBalance, setWalletBalance] = useState(0);
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState("");
useEffect(() => {
if (!isOpen) return;
const previousOverflow = document.body.style.overflow;
document.body.style.overflow = "hidden";
return () => {
document.body.style.overflow = previousOverflow;
};
}, [isOpen]);
useEffect(() => {
if (!isOpen) return;
fetchWalletBalances(WALLET_UUIDS)
.then((results) => setWalletBalance(results[0]?.balance ?? 0))
.catch(() => {});
}, [isOpen]);
if (!isOpen) return null;
const reservationAmount = ticketPrice * count;
const payableAmount = Math.max(0, reservationAmount - walletBalance);
const handlePay = async () => {
setError("");
if (!fullName.trim()) {
setError("لطفاً نام و نام خانوادگی را وارد کنید.");
return;
}
setIsSubmitting(true);
const payload = {
cafe_match_schedule_uuid: cafeMatchScheduleUuid,
people_count: count,
full_name: fullName,
phone_number: toE164(getUserPhone() ?? ""),
};
try {
if (payableAmount > 0) {
// reservation creation happens on /payment/success, only once the gateway confirms state=20
setPendingReservation(payload);
const appBaseUrl = (import.meta.env.VITE_APP_BASE_URL || window.location.origin).replace(/\/$/, "");
const { uuid } = await createCharge({
amount: payableAmount,
callback_url: `${appBaseUrl}/payment/success`,
});
window.location.href = chargePageUrl(uuid);
} else {
// wallet already covers the full amount — no gateway involved, land straight on the same success page
setPendingReservation(payload);
navigate("/payment/success?state=20");
}
} catch {
setError("اتصال به درگاه پرداخت با خطا مواجه شد. لطفاً دوباره تلاش کنید.");
setIsSubmitting(false);
}
};
return createPortal(
<>
{error &&
{error}
}
>,
document.body,
);
}