reservation-front/src/pages/MyReservations.tsx
2026-06-23 13:10:02 +03:30

115 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect, useState } from 'react'
import { createPortal } from 'react-dom'
import { useNavigate } from 'react-router-dom'
import InfoIcon from '../components/InfoIcon'
import SuccessIcon from '../components/SuccessIcon'
import { mockMyReservations, MyReservation } from '../data/mockMyReservations'
import { formatPersianNumber } from '../utils/formatNumber'
function ChevronIcon({ className = '' }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round">
<path d="M15.0898 4.07992L8.56984 10.5999C7.79984 11.3699 7.79984 12.6299 8.56984 13.3999L15.0898 19.9199" />
</svg>
)
}
function MyReservationCard({ reservation, onClick }: { reservation: MyReservation; onClick: () => void }) {
return (
<button
type="button"
onClick={onClick}
className="flex w-full flex-col items-start gap-3 rounded-2xl p-6 text-right shadow-[0px_4px_12px_0px_#0000001F]"
>
<h3 className="font-medium text-xl text-gray-900">{reservation.matchLabel}</h3>
<p className="text-lg text-gray-500">{reservation.dateTimeLabel}</p>
<div className="flex items-center gap-2">
<span className="font-normal rounded-full bg-[#ECF2F8] px-3 py-1 text-sm text-gray-700 h-9 flex items-center">
{formatPersianNumber(reservation.count)} نفر
</span>
<span className="font-medium rounded-full bg-[#ECF2F8] px-3 py-1 text-sm text-gray-700 h-9 flex items-center">
{reservation.code}
</span>
</div>
</button>
)
}
function DetailRow({ label, value }: { label: string; value: string }) {
return (
<div className="flex items-center justify-between py-3">
<span className="text-gray-500">{label}</span>
<span className="text-gray-900">{value}</span>
</div>
)
}
function ReservationDetailModal({ reservation, onClose }: { reservation: MyReservation; onClose: () => void }) {
useEffect(() => {
const previousOverflow = document.body.style.overflow
document.body.style.overflow = 'hidden'
return () => {
document.body.style.overflow = previousOverflow
}
}, [])
return createPortal(
<div className="fixed inset-0 z-1100 flex items-center justify-center bg-black/70 p-4" onClick={onClose}>
<div
className="max-h-[90vh] w-full overflow-y-auto rounded-3xl bg-white p-6"
onClick={(e) => e.stopPropagation()}
>
<SuccessIcon className="mx-auto h-24 w-24" />
<h2 className="mt-4 text-right font-semibold text-gray-900">جزئیات رزرو</h2>
<div className="mt-2">
<DetailRow label="تعداد" value={`${formatPersianNumber(reservation.count)} نفر`} />
<DetailRow label="به نام" value={reservation.name} />
<DetailRow label="شماره تماس" value={reservation.phone} />
<DetailRow label="کافه" value={reservation.cafeName} />
<DetailRow label="بازی" value={reservation.matchLabel} />
<DetailRow label="تاریخ و ساعت" value={reservation.dateTimeLabel} />
<DetailRow label="کد رزرو" value={reservation.code} />
</div>
<div className="mt-4 flex items-center justify-end gap-2 rounded-2xl bg-[#ECF2F8] px-4 py-3">
<InfoIcon />
<p className="text-right text-sm text-gray-500">
کد رزرو را برای ورود نزد خود نگه دارید. اطلاعات ورود و کد دیگری برای دقایقی شما پیامک می‌شود.
</p>
</div>
<button type="button" onClick={onClose} className="mt-4 w-full rounded-2xl bg-[#223D5D] py-4 text-lg font-semibold text-white">
بازگشت
</button>
</div>
</div>,
document.body,
)
}
export default function MyReservations() {
const navigate = useNavigate()
const [selectedReservation, setSelectedReservation] = useState<MyReservation | null>(null)
return (
<div className="min-h-screen bg-white pb-24">
<div className="h-16 w-full bg-gray-200" />
<button type="button" onClick={() => navigate(-1)} className="mt-4 flex w-full items-center justify-start gap-2 px-4">
<ChevronIcon className="h-5 w-5 -scale-x-100 text-gray-900" />
<span className="text-lg font-bold text-gray-900">رزروهای شما</span>
</button>
<div className="mt-4 flex flex-col gap-3 px-4">
{mockMyReservations.map((reservation) => (
<MyReservationCard key={reservation.id} reservation={reservation} onClick={() => setSelectedReservation(reservation)} />
))}
</div>
{selectedReservation && (
<ReservationDetailModal reservation={selectedReservation} onClose={() => setSelectedReservation(null)} />
)}
</div>
)
}