canina/frontend/application/components/OrderDetailsModal.tsx
parsa aghaei 2fca778930
All checks were successful
Deploy Canina / deploy (push) Successful in 1m48s
feat: complete payment retry, reviews system, catalog mode enforcement, and UI text defaults
2026-08-17 09:01:33 +03:30

690 lines
32 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.

/* eslint-disable @next/next/no-img-element */
"use client";
import React, { useState } from "react";
import { motion, AnimatePresence } from "motion/react";
import {
X,
Download,
Package,
ShoppingBag,
MapPin,
Clock,
CreditCard,
CheckCircle2,
Truck,
PackageCheck,
XCircle,
AlertCircle,
Wallet,
Building2,
Loader2,
ArrowRight,
Sparkles,
} from "lucide-react";
import { toPersian } from "../lib/utils";
import api from "../lib/services/api";
import { toast } from "sonner";
interface OrderDetailsModalProps {
isOpen: boolean;
onClose: () => void;
order: Record<string, unknown> | null;
onOrderUpdated?: (orderId: string, newStatus: string) => void;
}
export default function OrderDetailsModal({
isOpen,
onClose,
order,
onOrderUpdated,
}: OrderDetailsModalProps) {
const [retryModalOpen, setRetryModalOpen] = useState(false);
const [selectedMethod, setSelectedMethod] = useState<'online' | 'wallet' | 'card'>('online');
const [isProcessingPayment, setIsProcessingPayment] = useState(false);
if (!order) return null;
const orderId = String(order.id || '');
const orderStatus = String(order.status || '');
const isPendingPayment = orderStatus === 'pending_payment';
const getProductName = (p: Record<string, unknown> | undefined) =>
String(p?.nameFa || p?.name || p?.nameEn || 'محصول کنینا');
const getProductImage = (p: Record<string, unknown> | undefined) =>
String(p?.imageUrl || p?.image || '/products/product-placeholder.png');
const displayTrackingCode = String(
order.trackingNumber || (typeof order.id === 'string' ? order.id.substring(0, 8) : '') || 'CN-0000'
);
const rawDate = order.date || order.createdAt;
const orderDate = rawDate ? new Date(String(rawDate)) : new Date();
const formattedDate = orderDate.toLocaleDateString("fa-IR");
const formattedTime = orderDate.toLocaleTimeString("fa-IR", { hour: '2-digit', minute: '2-digit' });
const items = Array.isArray(order.items)
? (order.items as Record<string, unknown>[])
: Array.isArray(order.orderItems)
? (order.orderItems as Record<string, unknown>[])
: [];
const itemsSubtotal = items.reduce((sum: number, item: Record<string, unknown>) => {
const prod = item.product as Record<string, unknown> | undefined;
const price = Number(prod?.priceValue || item.priceValue || 0);
return sum + price * Number(item.quantity || 1);
}, 0);
const charityAmount = Number(order.charityDonation || 0);
const totalAmount = Number(order.total || order.totalAmount || itemsSubtotal + charityAmount);
const isRefill = Boolean(order.isRefill);
const getPaymentMethodTitle = (method?: unknown) => {
const m = String(method || '');
if (m === 'wallet') return 'کیف پول الکترونیک کنینا';
if (m === 'card' || m === 'card_to_card') return 'کارت به کارت مستقیم';
return 'درگاه پرداخت اینترنتی زیبال (شتاب)';
};
const handlePrint = () => {
const printWindow = window.open('', '_blank');
if (!printWindow) return;
const itemsHtml = items
.map((item: Record<string, unknown>) => {
const prod = item.product as Record<string, unknown> | undefined;
const pName = getProductName(prod);
const pImg = getProductImage(prod);
const pPrice = Number(prod?.priceValue || item.priceValue || 0);
const rowTotal = pPrice * Number(item.quantity || 1);
return `
<tr>
<td style="padding: 14px; border-bottom: 1px solid #e5e7eb; vertical-align: middle;">
<div style="display: flex; align-items: center; gap: 12px;">
<img src="${pImg}" alt="${pName}" style="width: 48px; height: 48px; object-fit: contain; border-radius: 8px; border: 1px solid #f3f4f6; background: #fff; padding: 4px;" />
<span style="font-weight: 700; color: #111827;">${pName}</span>
</div>
</td>
<td style="padding: 14px; border-bottom: 1px solid #e5e7eb; text-align: center; font-weight: 700;">${toPersian(
Number(item.quantity || 1)
)}</td>
<td style="padding: 14px; border-bottom: 1px solid #e5e7eb; text-align: left; font-weight: 700;">${toPersian(
pPrice.toLocaleString()
)} تومان</td>
<td style="padding: 14px; border-bottom: 1px solid #e5e7eb; text-align: left; font-weight: 900; color: #0055FF;">${toPersian(
rowTotal.toLocaleString()
)} تومان</td>
</tr>
`;
})
.join('');
printWindow.document.write(`
<!DOCTYPE html>
<html dir="rtl" lang="fa">
<head>
<meta charset="utf-8" />
<title>فاکتور رسمی کنینا - ${displayTrackingCode}</title>
<style>
@font-face {
font-family: 'Vazirmatn';
src: url('https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/fonts/webfonts/Vazirmatn-Regular.woff2') format('woff2');
}
body { font-family: 'Vazirmatn', sans-serif; padding: 40px; color: #1f2937; background: #fff; line-height: 1.6; }
.invoice-card { max-width: 850px; margin: 0 auto; border: 2px solid #e5e7eb; border-radius: 24px; padding: 40px; }
.header { display: flex; justify-content: space-between; align-items: center; border-bottom: 3px solid #0055FF; padding-bottom: 24px; margin-bottom: 32px; }
.logo-text { font-size: 28px; font-weight: 900; color: #0055FF; font-style: italic; }
.sub-logo { font-size: 13px; color: #6b7280; font-weight: 700; margin-top: 4px; }
.meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; background: #f9fafb; padding: 20px; border-radius: 16px; margin-bottom: 32px; font-size: 13px; }
table { width: 100%; border-collapse: collapse; margin-bottom: 32px; }
th { background: #f3f4f6; text-align: right; padding: 14px; font-size: 12px; font-weight: 900; color: #4b5563; border-radius: 8px; }
.summary-box { background: #0f172a; color: #fff; padding: 24px; border-radius: 20px; margin-top: 32px; }
.summary-row { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 10px; font-weight: 700; color: #94a3b8; }
.summary-row.total { font-size: 20px; font-weight: 900; color: #fbbf24; border-top: 1px solid #334155; padding-top: 14px; margin-top: 14px; margin-bottom: 0; }
.footer { margin-top: 40px; text-align: center; font-size: 11px; color: #9ca3af; font-weight: 700; }
@media print {
body { padding: 0; background: #fff; }
.invoice-card { border: none; padding: 0; max-width: 100%; }
}
</style>
</head>
<body>
<div class="invoice-card">
<div class="header">
<div>
<div class="logo-text">Canina Iran</div>
<div class="sub-logo">نماینده رسمی Canina pharma GmbH آلمان در ایران</div>
</div>
<div style="text-align: left;">
<h2 style="margin: 0; font-size: 22px; font-weight: 900; color: #111827;">صورتحساب فروش کالا و خدمات</h2>
<span style="font-size: 12px; font-weight: 700; color: #0055FF; margin-top: 4px; display: block;">شناسه فاکتور: ${toPersian(
displayTrackingCode
)}</span>
</div>
</div>
<div class="meta-grid">
<div>
<strong style="color: #4b5563;">اطلاعات سفارش:</strong>
<div style="margin-top: 6px;">تاریخ ثبت: ${toPersian(formattedDate)} - ساعت ${toPersian(
formattedTime
)}</div>
<div style="margin-top: 4px;">روش پرداخت: ${getPaymentMethodTitle(order.paymentMethod)}</div>
<div style="margin-top: 4px;">وضعیت: ${getStatusLabel(orderStatus)}</div>
</div>
<div>
<strong style="color: #4b5563;">نشانی تحویل گیرنده:</strong>
<div style="margin-top: 6px; line-height: 1.5;">${
String(order.shippingAddress || 'آدرس ثبتی کاربر در حساب کاربری')
}</div>
</div>
</div>
<table>
<thead>
<tr>
<th>شرح کالا / مکمل دارویی</th>
<th style="text-align: center;">تعداد</th>
<th style="text-align: left;">مبلغ واحد</th>
<th style="text-align: left;">مبلغ کل</th>
</tr>
</thead>
<tbody>
${itemsHtml}
</tbody>
</table>
<div class="summary-box">
<div class="summary-row">
<span>جمع اقلام:</span>
<span>${toPersian(itemsSubtotal.toLocaleString())} تومان</span>
</div>
${
charityAmount > 0
? `
<div class="summary-row" style="color: #f472b6;">
<span>کمک به حیوانات بی‌سرپرست (ردپای مهربانی):</span>
<span>${toPersian(charityAmount.toLocaleString())}+ تومان</span>
</div>
`
: ''
}
<div class="summary-row">
<span>هزینه بسته‌بندی و ارسال اکسپرس:</span>
<span style="color: #34d399;">رایگان (تحویل سراسری)</span>
</div>
<div class="summary-row total">
<span>مبلغ نهایی فاکتور:</span>
<span>${toPersian(totalAmount.toLocaleString())} تومان</span>
</div>
</div>
<div class="footer">
داروخانه تخصصی مکمل‌های کنینا ایران • تلفن پشتیبانی: ۰۲۱-۸۸۸۸۸۸۸۸ • وب‌سایت: www.canina.ir
</div>
</div>
<script>
window.onload = function() {
setTimeout(function() { window.print(); }, 300);
}
</script>
</body>
</html>
`);
printWindow.document.close();
};
const handleExecuteRetryPayment = async () => {
try {
setIsProcessingPayment(true);
const res = await api.post(`/orders/${orderId}/retry-payment`, {
paymentMethod: selectedMethod,
});
if (res.data?.success) {
if (selectedMethod === 'online') {
// Initiate Zibal Payment
const payRes = await api.post('/payment/zibal/initiate', {
orderId,
});
if (payRes.data?.paymentUrl) {
toast.success('در حال انتقال به درگاه پرداخت زیبال...');
window.location.href = payRes.data.paymentUrl;
return;
}
} else if (selectedMethod === 'wallet') {
toast.success('پرداخت سفارش با موفقیت از طریق کیف پول انجام شد.');
if (onOrderUpdated) {
onOrderUpdated(orderId, 'processing');
}
setRetryModalOpen(false);
onClose();
} else {
toast.success('روش پرداخت به کارت به کارت تغییر یافت.');
if (onOrderUpdated) {
onOrderUpdated(orderId, 'pending_payment');
}
setRetryModalOpen(false);
}
}
} catch (err: any) {
console.error('Retry payment error:', err);
} finally {
setIsProcessingPayment(false);
}
};
function getStatusIcon(st: string) {
switch (st) {
case 'processing':
return <Clock className="w-5 h-5 text-amber-500" />;
case 'packaged':
case 'ready_to_ship':
return <PackageCheck className="w-5 h-5 text-purple-500" />;
case 'shipped':
return <Truck className="w-5 h-5 text-blue-500" />;
case 'delivered':
return <CheckCircle2 className="w-5 h-5 text-green-500" />;
case 'pending_payment':
return <AlertCircle className="w-5 h-5 text-rose-500" />;
case 'cancelled':
return <XCircle className="w-5 h-5 text-red-500" />;
default:
return <Package className="w-5 h-5 text-medical-gray-400" />;
}
}
function getStatusLabel(st: string) {
switch (st) {
case 'processing':
return 'در حال پردازش در انبار';
case 'packaged':
case 'ready_to_ship':
return 'بسته‌بندی شده (آماده ارسال)';
case 'shipped':
return 'تحویل شرکت پست / پیک';
case 'delivered':
return 'تحویل موفق به مشتری';
case 'pending_payment':
return 'در انتظار پرداخت / ناموفق';
case 'cancelled':
return 'سفارش لغو شده';
default:
return 'ثبت اولیه';
}
}
return (
<AnimatePresence>
{isOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
className="absolute inset-0 bg-medical-gray-900/60 backdrop-blur-md"
/>
<motion.div
initial={{ opacity: 0, scale: 0.95, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 20 }}
className="bg-white w-full max-w-3xl rounded-[2.5rem] relative z-10 shadow-2xl overflow-hidden font-vazir text-right"
dir="rtl"
>
{/* Modal Header */}
<div className="p-6 sm:p-8 bg-medical-gray-50/80 border-b border-medical-gray-100 flex items-center justify-between">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-canina-blue/10 rounded-2xl flex items-center justify-center text-canina-blue">
<Package className="w-6 h-6" />
</div>
<div>
<h3 className="text-xl font-black text-medical-gray-900">
جزئیات کامل سفارش {toPersian(displayTrackingCode)}
</h3>
<p className="text-xs text-medical-gray-400 font-bold mt-0.5">
ثبت شده در تاریخ {toPersian(formattedDate)}
</p>
</div>
</div>
<button
onClick={onClose}
className="w-10 h-10 rounded-xl bg-white border border-medical-gray-200 text-medical-gray-400 hover:text-medical-gray-700 flex items-center justify-center transition-colors"
>
<X className="w-5 h-5" />
</button>
</div>
{/* Pending Payment Notice Banner */}
{isPendingPayment && (
<div className="bg-rose-50 border-b border-rose-200 px-6 py-4 flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div className="flex items-center gap-3">
<AlertCircle className="w-5 h-5 text-rose-600 shrink-0" />
<div>
<span className="text-xs font-black text-rose-900 block">
پرداخت این سفارش هنوز تکمیل نشده است.
</span>
<span className="text-[11px] text-rose-700 font-medium">
میتوانید همین حالا روش پرداخت را تغییر داده یا مجدداً پرداخت را انجام دهید.
</span>
</div>
</div>
<button
onClick={() => setRetryModalOpen(true)}
className="px-4 py-2 bg-rose-600 hover:bg-rose-700 text-white rounded-xl text-xs font-black transition-all shadow-md shadow-rose-600/20 whitespace-nowrap shrink-0 flex items-center justify-center gap-1.5"
>
<CreditCard className="w-4 h-4" />
<span>پرداخت و تکمیل سفارش</span>
</button>
</div>
)}
{/* Content Scrollable */}
<div className="max-h-[60vh] overflow-y-auto px-6 sm:px-10 py-6 space-y-6 custom-scrollbar">
{/* Summary Stats */}
<div className="grid grid-cols-3 gap-3 sm:gap-4">
<div className="bg-medical-gray-50 p-4 rounded-2xl">
<div className="text-[9px] font-black text-medical-gray-400 uppercase tracking-widest mb-1">
وضعیت سفارش
</div>
<div className="flex items-center gap-2">
{getStatusIcon(orderStatus)}
<span className="text-xs sm:text-sm font-black text-medical-gray-900">
{getStatusLabel(orderStatus)}
</span>
</div>
</div>
<div className="bg-medical-gray-50 p-4 rounded-2xl">
<div className="text-[9px] font-black text-medical-gray-400 uppercase tracking-widest mb-1">
کد پیگیری
</div>
<div className="text-xs sm:text-sm font-bold text-canina-blue font-vazir">
{toPersian(displayTrackingCode)}
</div>
</div>
<div className="bg-medical-gray-50 p-4 rounded-2xl">
<div className="text-[9px] font-black text-medical-gray-400 uppercase tracking-widest mb-1">
زمان دقیق
</div>
<div className="flex items-center gap-1.5">
<Clock className="w-4 h-4 text-medical-gray-400 flex-shrink-0" />
<span className="text-xs sm:text-sm font-black text-medical-gray-900">
{toPersian(formattedTime)}
</span>
</div>
</div>
</div>
{/* Items List */}
<div>
<h4 className="text-sm font-black text-medical-gray-900 mb-3 flex items-center gap-2">
<ShoppingBag className="w-4 h-4 text-canina-blue" />
سبد اقلام سفارش
</h4>
<div className="space-y-3">
{items.map((item: Record<string, unknown>, idx: number) => {
const prod = item.product as Record<string, unknown> | undefined;
const pName = getProductName(prod);
const pImg = getProductImage(prod);
const pPrice = Number(prod?.priceValue || item.priceValue || 0);
const itemQty = Number(item.quantity || 1);
return (
<div
key={String(prod?.id || idx)}
className="flex items-center justify-between p-4 border border-medical-gray-100 rounded-2xl hover:border-canina-blue transition-all"
>
<div className="flex items-center gap-4">
<div className="w-14 h-14 bg-medical-gray-50 rounded-xl p-1.5 flex items-center justify-center shrink-0 border border-medical-gray-200">
<img
src={pImg}
alt={pName}
className="max-w-full max-h-full object-contain"
/>
</div>
<div>
<h5 className="font-black text-medical-gray-900 text-xs sm:text-sm">
{pName}
</h5>
<p className="text-xs text-medical-gray-400 mt-0.5">
{toPersian(itemQty)} عدد × {toPersian(pPrice.toLocaleString())} تومان
</p>
</div>
</div>
<div className="text-left font-black text-canina-blue text-xs sm:text-sm">
{toPersian((pPrice * itemQty).toLocaleString())} تومان
</div>
</div>
);
})}
</div>
</div>
{/* Shipping & Payment */}
<div className="grid md:grid-cols-2 gap-6 pt-4 border-t border-medical-gray-100">
<div>
<h4 className="text-sm font-black text-medical-gray-900 mb-3 flex items-center gap-2">
<MapPin className="w-4 h-4 text-canina-blue" />
اطلاعات ارسال
</h4>
<p className="text-xs font-bold text-medical-gray-600 leading-relaxed bg-medical-gray-50 p-4 rounded-2xl border border-medical-gray-100">
{String(order.shippingAddress || 'آدرس ثبتی کاربر در حساب کاربری')}
</p>
</div>
<div>
<h4 className="text-sm font-black text-medical-gray-900 mb-3 flex items-center gap-2">
<CreditCard className="w-4 h-4 text-canina-blue" />
جزئیات مالی و روش پرداخت
</h4>
<div className="space-y-2 bg-medical-gray-50 p-4 rounded-2xl border border-medical-gray-100">
<div className="flex justify-between text-xs font-bold text-medical-gray-500">
<span>روش پرداخت:</span>
<span className="text-medical-gray-900 font-black">
{getPaymentMethodTitle(order.paymentMethod)}
</span>
</div>
<div className="flex justify-between text-xs font-bold text-medical-gray-500">
<span>مجموع اولیه اقلام:</span>
<span>{toPersian(itemsSubtotal.toLocaleString())} تومان</span>
</div>
{charityAmount > 0 && (
<div className="flex justify-between text-xs font-bold text-pink-500">
<span>کمک اهدایی (ردپای مهربانی):</span>
<span>{toPersian(charityAmount.toLocaleString())}+ تومان</span>
</div>
)}
<div className="flex justify-between text-xs font-bold text-medical-gray-500">
<span>هزینه ارسال:</span>
<span className="text-green-600 font-black">رایگان</span>
</div>
<div className="flex justify-between text-sm sm:text-base font-black text-medical-gray-900 pt-2 border-t border-medical-gray-200">
<span>مبلغ نهایی سفارش:</span>
<span className="text-canina-blue">
{toPersian(totalAmount.toLocaleString())} تومان
</span>
</div>
</div>
</div>
</div>
</div>
{/* Footer Actions */}
<div className="p-6 sm:p-8 bg-medical-gray-50 border-t border-medical-gray-100 flex flex-col sm:flex-row gap-3">
{isPendingPayment && (
<button
onClick={() => setRetryModalOpen(true)}
className="flex-1 py-3.5 bg-emerald-600 hover:bg-emerald-700 text-white rounded-2xl font-black text-xs sm:text-sm flex items-center justify-center gap-2 shadow-lg shadow-emerald-600/20 transition-all"
>
<CreditCard className="w-4 h-4" />
<span>پرداخت آنلاین و تکمیل سفارش</span>
</button>
)}
<button
onClick={handlePrint}
className="flex-1 py-3.5 bg-canina-blue hover:bg-medical-gray-900 text-white rounded-2xl font-black text-xs sm:text-sm flex items-center justify-center gap-2 transition-all shadow-md"
>
<Download className="w-4 h-4" />
<span>دانلود و چاپ فاکتور رسمی</span>
</button>
</div>
</motion.div>
{/* Retry Payment Method Selector Modal */}
{retryModalOpen && (
<div className="fixed inset-0 z-60 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm">
<div className="bg-white rounded-3xl p-6 sm:p-8 w-full max-w-md shadow-2xl space-y-6 font-vazir animate-in fade-in zoom-in-95 duration-150" dir="rtl">
<div className="flex items-center justify-between border-b border-medical-gray-100 pb-4">
<div className="flex items-center gap-2">
<CreditCard className="w-5 h-5 text-canina-blue" />
<h3 className="text-base font-black text-medical-gray-900">
انتخاب روش پرداخت سفارش
</h3>
</div>
<button
onClick={() => setRetryModalOpen(false)}
className="p-1 text-medical-gray-400 hover:text-medical-gray-600 rounded-lg hover:bg-medical-gray-100"
>
</button>
</div>
<div className="p-3.5 bg-canina-blue/5 border border-canina-blue/10 rounded-2xl flex justify-between items-center text-xs">
<span className="font-bold text-medical-gray-600">مبلغ قابل پرداخت:</span>
<span className="font-black text-canina-blue text-sm">
{toPersian(totalAmount.toLocaleString())} تومان
</span>
</div>
{/* Methods Options */}
<div className="space-y-3">
<label
onClick={() => setSelectedMethod('online')}
className={`flex items-center justify-between p-4 rounded-2xl border-2 cursor-pointer transition-all ${
selectedMethod === 'online'
? 'border-canina-blue bg-canina-blue/5'
: 'border-medical-gray-100 hover:border-medical-gray-200'
}`}
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-emerald-50 text-emerald-600 rounded-xl flex items-center justify-center font-bold">
<CreditCard className="w-5 h-5" />
</div>
<div>
<div className="text-xs font-black text-medical-gray-900">
درگاه پرداخت آنلاین زیبال
</div>
<div className="text-[10px] text-medical-gray-400 font-bold mt-0.5">
پرداخت آنی با تمامی کارتهای بانکی عضو شتاب
</div>
</div>
</div>
<div
className={`w-5 h-5 rounded-full border-2 flex items-center justify-center ${
selectedMethod === 'online'
? 'border-canina-blue bg-canina-blue'
: 'border-medical-gray-300'
}`}
>
{selectedMethod === 'online' && (
<span className="w-2 h-2 rounded-full bg-white" />
)}
</div>
</label>
<label
onClick={() => setSelectedMethod('wallet')}
className={`flex items-center justify-between p-4 rounded-2xl border-2 cursor-pointer transition-all ${
selectedMethod === 'wallet'
? 'border-canina-blue bg-canina-blue/5'
: 'border-medical-gray-100 hover:border-medical-gray-200'
}`}
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-purple-50 text-purple-600 rounded-xl flex items-center justify-center font-bold">
<Wallet className="w-5 h-5" />
</div>
<div>
<div className="text-xs font-black text-medical-gray-900">
کیف پول الکترونیک کنینا
</div>
<div className="text-[10px] text-medical-gray-400 font-bold mt-0.5">
کسر خودکار از موجودی کیف پول
</div>
</div>
</div>
<div
className={`w-5 h-5 rounded-full border-2 flex items-center justify-center ${
selectedMethod === 'wallet'
? 'border-canina-blue bg-canina-blue'
: 'border-medical-gray-300'
}`}
>
{selectedMethod === 'wallet' && (
<span className="w-2 h-2 rounded-full bg-white" />
)}
</div>
</label>
<label
onClick={() => setSelectedMethod('card')}
className={`flex items-center justify-between p-4 rounded-2xl border-2 cursor-pointer transition-all ${
selectedMethod === 'card'
? 'border-canina-blue bg-canina-blue/5'
: 'border-medical-gray-100 hover:border-medical-gray-200'
}`}
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-blue-50 text-blue-600 rounded-xl flex items-center justify-center font-bold">
<Building2 className="w-5 h-5" />
</div>
<div>
<div className="text-xs font-black text-medical-gray-900">
کارت به کارت مستقیم
</div>
<div className="text-[10px] text-medical-gray-400 font-bold mt-0.5">
واریز به شماره کارت / شبا شرکت
</div>
</div>
</div>
<div
className={`w-5 h-5 rounded-full border-2 flex items-center justify-center ${
selectedMethod === 'card'
? 'border-canina-blue bg-canina-blue'
: 'border-medical-gray-300'
}`}
>
{selectedMethod === 'card' && (
<span className="w-2 h-2 rounded-full bg-white" />
)}
</div>
</label>
</div>
<div className="flex items-center justify-end gap-3 pt-2">
<button
type="button"
onClick={() => setRetryModalOpen(false)}
className="px-4 py-2.5 text-xs font-bold text-medical-gray-600 hover:bg-medical-gray-100 rounded-xl transition-all"
>
انصراف
</button>
<button
type="button"
disabled={isProcessingPayment}
onClick={handleExecuteRetryPayment}
className="px-6 py-2.5 text-xs font-black bg-canina-blue hover:bg-canina-dark text-white rounded-xl shadow-lg shadow-canina-blue/20 transition-all flex items-center gap-2"
>
{isProcessingPayment ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
<CheckCircle2 className="w-4 h-4" />
)}
<span>تایید و ادامه پرداخت</span>
</button>
</div>
</div>
</div>
)}
</div>
)}
</AnimatePresence>
);
}