236 lines
9.4 KiB
TypeScript
236 lines
9.4 KiB
TypeScript
import React from 'react';
|
||
import { Printer, X, CheckCircle2, ShieldCheck, Copy } from 'lucide-react';
|
||
import { toast } from 'react-hot-toast';
|
||
import Button from './ui/Button';
|
||
|
||
export interface TransactionReceiptData {
|
||
trackId?: string | number;
|
||
refNumber?: string | number;
|
||
amountRials?: number | string;
|
||
amountTomans?: number | string;
|
||
statusText?: string;
|
||
orderNumber?: string;
|
||
orderId?: string;
|
||
cardNumber?: string;
|
||
paidAt?: string;
|
||
createdAt?: string;
|
||
fee?: number | string;
|
||
mobile?: string;
|
||
description?: string;
|
||
psp?: string;
|
||
ip?: string;
|
||
}
|
||
|
||
interface TransactionReceiptModalProps {
|
||
isOpen: boolean;
|
||
onClose: () => void;
|
||
data: TransactionReceiptData | null;
|
||
}
|
||
|
||
export default function TransactionReceiptModal({
|
||
isOpen,
|
||
onClose,
|
||
data,
|
||
}: TransactionReceiptModalProps) {
|
||
if (!isOpen || !data) return null;
|
||
|
||
const handlePrint = () => {
|
||
window.print();
|
||
};
|
||
|
||
const handleCopy = (text: string, label: string) => {
|
||
if (!text) return;
|
||
navigator.clipboard.writeText(text);
|
||
toast.success(`${label} کپی شد`);
|
||
};
|
||
|
||
const rials =
|
||
data.amountRials !== undefined
|
||
? Number(data.amountRials)
|
||
: (Number(data.amountTomans || 0) * 10);
|
||
const tomans =
|
||
data.amountTomans !== undefined
|
||
? Number(data.amountTomans)
|
||
: Math.floor(Number(data.amountRials || 0) / 10);
|
||
|
||
return (
|
||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm print:p-0 print:bg-white">
|
||
<div className="bg-white rounded-3xl max-w-sm w-full shadow-2xl border border-gray-100 overflow-hidden print:border-none print:shadow-none font-vazir" dir="rtl">
|
||
{/* Modal Header */}
|
||
<div className="p-4 border-b border-gray-100 flex items-center justify-between print:hidden">
|
||
<h3 className="font-black text-sm text-gray-900 flex items-center gap-1.5">
|
||
<ShieldCheck className="w-4 h-4 text-emerald-600" />
|
||
<span>رسید تراکنش {data.trackId || ''}</span>
|
||
</h3>
|
||
<button
|
||
onClick={onClose}
|
||
className="text-gray-400 hover:text-gray-700 font-bold p-1 cursor-pointer"
|
||
>
|
||
<X className="w-5 h-5" />
|
||
</button>
|
||
</div>
|
||
|
||
{/* The Zigzag Receipt Slip (Matching Zibal screenshot exactly) */}
|
||
<div className="p-6 space-y-5 bg-white relative">
|
||
{/* Top Jagged Border (CSS Jagged effect) */}
|
||
<div className="w-full h-3 bg-indigo-50/50 -mt-6 mb-3 flex justify-between overflow-hidden opacity-60">
|
||
{Array.from({ length: 24 }).map((_, i) => (
|
||
<div
|
||
key={i}
|
||
className="w-0 h-0 border-l-[6px] border-l-transparent border-r-[6px] border-r-transparent border-t-[8px] border-t-white"
|
||
/>
|
||
))}
|
||
</div>
|
||
|
||
{/* Amount Display */}
|
||
<div className="text-center space-y-1">
|
||
<div className="text-2xl font-black text-emerald-600 font-mono">
|
||
{rials.toLocaleString('fa-IR')}{' '}
|
||
<span className="text-sm font-black text-emerald-700">ریال</span>
|
||
</div>
|
||
<p className="text-[11px] font-bold text-gray-400 font-mono">
|
||
({tomans.toLocaleString('fa-IR')} تومان)
|
||
</p>
|
||
</div>
|
||
|
||
{/* Data List (Aligned exactly like Zibal slip) */}
|
||
<div className="space-y-2.5 text-xs">
|
||
{/* Track ID */}
|
||
<div className="flex items-center justify-between py-1 border-b border-gray-50">
|
||
<button
|
||
type="button"
|
||
onClick={() => handleCopy(String(data.trackId || ''), 'شماره تراکنش')}
|
||
className="text-indigo-600 hover:text-indigo-800 flex items-center gap-1 font-mono font-bold cursor-pointer"
|
||
title="کپی"
|
||
>
|
||
<Copy className="w-3 h-3" />
|
||
<span>{data.trackId || '-'}</span>
|
||
</button>
|
||
<span className="text-gray-500 font-bold">شماره تراکنش</span>
|
||
</div>
|
||
|
||
{/* Reference Number */}
|
||
<div className="flex items-center justify-between py-1 border-b border-gray-50">
|
||
<button
|
||
type="button"
|
||
onClick={() => handleCopy(String(data.refNumber || ''), 'شناسه مرجع')}
|
||
className="text-indigo-600 hover:text-indigo-800 flex items-center gap-1 font-mono font-bold cursor-pointer"
|
||
title="کپی"
|
||
>
|
||
<Copy className="w-3 h-3" />
|
||
<span>{data.refNumber || '-'}</span>
|
||
</button>
|
||
<span className="text-gray-500 font-bold">شناسه مرجع</span>
|
||
</div>
|
||
|
||
{/* Paid At */}
|
||
<div className="flex items-center justify-between py-1 border-b border-gray-50">
|
||
<span className="font-mono text-gray-700 font-bold dir-ltr">
|
||
{data.paidAt || data.createdAt || '-'}
|
||
</span>
|
||
<span className="text-gray-500 font-bold">تاریخ پرداخت</span>
|
||
</div>
|
||
|
||
{/* Status */}
|
||
<div className="flex items-center justify-between py-1 border-b border-gray-50">
|
||
<span className="text-emerald-600 font-black flex items-center gap-1">
|
||
<span className="w-2 h-2 rounded-full bg-emerald-500 inline-block"></span>
|
||
<span>{data.statusText || 'پرداخت موفق'}</span>
|
||
</span>
|
||
<span className="text-gray-500 font-bold">وضعیت</span>
|
||
</div>
|
||
|
||
{/* Order ID */}
|
||
<div className="flex items-center justify-between py-1.5 px-2 bg-gray-50/80 rounded-lg">
|
||
<span className="font-mono font-bold text-gray-900">
|
||
{data.orderNumber || data.orderId || '-'}
|
||
</span>
|
||
<span className="text-gray-500 font-bold">شناسه سفارش</span>
|
||
</div>
|
||
|
||
{/* Card Number */}
|
||
<div className="flex items-center justify-between py-1 border-b border-gray-50">
|
||
<span className="font-mono text-gray-800 font-bold dir-ltr">
|
||
{data.cardNumber || '-'}
|
||
</span>
|
||
<span className="text-gray-500 font-bold">شماره کارت</span>
|
||
</div>
|
||
|
||
{/* Creation Date */}
|
||
<div className="flex items-center justify-between py-1.5 px-2 bg-gray-50/80 rounded-lg">
|
||
<span className="font-mono font-bold text-gray-700 dir-ltr">
|
||
{data.createdAt || data.paidAt || '-'}
|
||
</span>
|
||
<span className="text-gray-500 font-bold">تاریخ ایجاد</span>
|
||
</div>
|
||
|
||
{/* Mobile */}
|
||
<div className="flex items-center justify-between py-1.5 px-2 bg-gray-50/80 rounded-lg">
|
||
<span className="font-mono font-bold text-gray-800 dir-ltr">
|
||
{data.mobile || '-'}
|
||
</span>
|
||
<span className="text-gray-500 font-bold">شماره موبایل</span>
|
||
</div>
|
||
|
||
{/* Description */}
|
||
<div className="flex items-center justify-between py-1 border-b border-gray-50">
|
||
<span className="text-gray-800 font-bold max-w-[180px] truncate text-left">
|
||
{data.description || 'پرداخت آنلاین - پت شاپ کنینا'}
|
||
</span>
|
||
<span className="text-gray-500 font-bold">توضیحات</span>
|
||
</div>
|
||
|
||
{/* PSP */}
|
||
<div className="flex items-center justify-between py-1.5 px-2 bg-gray-50/80 rounded-lg">
|
||
<span className="font-bold text-indigo-700 text-[11px]">
|
||
{data.psp || 'زیبال / بهپرداخت ملت'}
|
||
</span>
|
||
<span className="text-gray-500 font-bold">PSP</span>
|
||
</div>
|
||
|
||
{/* Real IP */}
|
||
<div className="flex items-center justify-between py-1">
|
||
<button
|
||
type="button"
|
||
onClick={() => handleCopy(String(data.ip || ''), 'آیپی کاربر')}
|
||
className="text-indigo-600 hover:text-indigo-800 flex items-center gap-1 font-mono font-bold cursor-pointer dir-ltr"
|
||
title="کپی آیپی"
|
||
>
|
||
<Copy className="w-3 h-3" />
|
||
<span>{data.ip || '-'}</span>
|
||
</button>
|
||
<span className="text-gray-500 font-bold">IP</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Bottom Jagged Border */}
|
||
<div className="w-full h-3 bg-indigo-50/50 -mb-6 mt-4 flex justify-between overflow-hidden opacity-60">
|
||
{Array.from({ length: 24 }).map((_, i) => (
|
||
<div
|
||
key={i}
|
||
className="w-0 h-0 border-l-[6px] border-l-transparent border-r-[6px] border-r-transparent border-b-[8px] border-b-white"
|
||
/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Actions / Print Footer */}
|
||
<div className="p-4 bg-gray-50/80 border-t border-gray-100 flex items-center justify-between print:hidden">
|
||
<Button variant="outline" size="sm" onClick={onClose}>
|
||
بستن
|
||
</Button>
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
startIcon={Printer}
|
||
onClick={handlePrint}
|
||
className="border-gray-300 hover:border-indigo-600 text-indigo-600 hover:bg-indigo-50"
|
||
>
|
||
چاپ رسید
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|