115 lines
4.8 KiB
TypeScript
115 lines
4.8 KiB
TypeScript
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>
|
||
)
|
||
}
|