canina/frontend/application/components/OrderDetailsModal.tsx

752 lines
36 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.

"use client";
import React, { useState } from "react";
import Link from "next/link";
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";
import { useSettingsStore } from "../lib/store/settingsStore";
import SafeImage from "./SafeImage";
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 getText = useSettingsStore((state) => state.getText);
const isCardToCardEnabled = getText('PAY_GATEWAY_CARD_ENABLE', 'true') === 'true' && getText('cart_to_cart_enabled', 'true') === 'true';
const [retryModalOpen, setRetryModalOpen] = useState(false);
const [selectedMethod, setSelectedMethod] = useState<'online' | 'wallet' | 'card'>('online');
const [isProcessingPayment, setIsProcessingPayment] = useState(false);
const [zoomedImage, setZoomedImage] = useState<string | null>(null);
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 shippingAddress = (order.shippingAddress || order.address || {}) as Record<string, unknown>;
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('/fonts/vazirmatn-v33.003/fonts/webfonts/Vazirmatn-Regular.woff2') format('woff2');
}
body { font-family: 'Vazirmatn', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 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-[65vh] overflow-y-auto px-6 sm:px-10 py-6 space-y-6 custom-scrollbar">
{/* Summary Stats */}
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 sm:gap-4">
<div className="bg-medical-gray-50 p-4 rounded-2xl border border-medical-gray-100">
<div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-1.5">
وضعیت سفارش
</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 border border-medical-gray-100">
<div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-1.5">
کد رهگیری سفارش
</div>
<div className="text-xs sm:text-sm font-mono font-black text-canina-blue">
{toPersian(displayTrackingCode)}
</div>
</div>
<div className="bg-medical-gray-50 p-4 rounded-2xl border border-medical-gray-100">
<div className="text-[10px] font-black text-medical-gray-400 uppercase tracking-widest mb-1.5">
زمان ثبت سفارش
</div>
<div className="flex items-center gap-1.5 text-xs sm:text-sm font-black text-medical-gray-900">
<Clock className="w-4 h-4 text-medical-gray-400" />
<span>{toPersian(formattedTime)} - {toPersian(formattedDate)}</span>
</div>
</div>
</div>
{/* Items Section */}
<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);
const pSlug = String(prod?.slug || prod?.id || '');
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
onClick={() => setZoomedImage(pImg)}
className="w-14 h-14 bg-medical-gray-50 rounded-xl p-1 flex items-center justify-center shrink-0 border border-medical-gray-200 cursor-zoom-in hover:scale-105 transition-transform overflow-hidden"
title="مشاهده تصویر بزرگ"
>
<SafeImage
src={pImg}
alt={pName}
className="w-full h-full"
imgClassName="w-full h-full object-contain"
/>
</div>
<div>
{pSlug ? (
<Link
href={`/shop/${pSlug}`}
onClick={onClose}
className="font-black text-medical-gray-900 hover:text-canina-blue transition-colors text-xs sm:text-sm inline-block font-vazir"
>
{pName}
</Link>
) : (
<h5 className="font-black text-medical-gray-900 text-xs sm:text-sm font-vazir">
{pName}
</h5>
)}
<p className="text-xs text-medical-gray-400 mt-0.5 font-vazir">
{toPersian(itemQty)} عدد × {toPersian(pPrice.toLocaleString())} تومان
</p>
</div>
</div>
<div className="text-left font-black text-canina-blue text-xs sm:text-sm font-vazir">
{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>
<div className="bg-medical-gray-50 p-4 rounded-2xl space-y-2 text-xs font-bold text-medical-gray-700">
<div>
<span className="text-medical-gray-400">گیرنده: </span>
{String(shippingAddress.recipientName || shippingAddress.name || 'کاربر')}
</div>
<div>
<span className="text-medical-gray-400">شماره تماس: </span>
<span className="font-mono">{toPersian(String(shippingAddress.phone || shippingAddress.mobile || '-'))}</span>
</div>
<div>
<span className="text-medical-gray-400">نشانی کامل: </span>
{String(shippingAddress.fullAddress || shippingAddress.address || '-')}
</div>
{Boolean(shippingAddress.postalCode) && (
<div>
<span className="text-medical-gray-400">کد پستی: </span>
<span className="font-mono">{toPersian(String(shippingAddress.postalCode))}</span>
</div>
)}
</div>
</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="bg-medical-gray-50 p-4 rounded-2xl space-y-2.5 text-xs font-bold text-medical-gray-700">
<div className="flex justify-between items-center">
<span className="text-medical-gray-400">شیوه پرداخت:</span>
<span className="text-medical-gray-900">{getPaymentMethodTitle(order.paymentMethod)}</span>
</div>
<div className="flex justify-between items-center">
<span className="text-medical-gray-400">مجموع اقلام:</span>
<span>{toPersian(itemsSubtotal.toLocaleString())} تومان</span>
</div>
{charityAmount > 0 && (
<div className="flex justify-between items-center text-pink-500">
<span>ردپای مهربانی:</span>
<span>{toPersian(charityAmount.toLocaleString())}+ تومان</span>
</div>
)}
<div className="flex justify-between items-center">
<span className="text-medical-gray-400">هزینه ارسال:</span>
<span className="text-green-600">رایگان</span>
</div>
<div className="pt-2 border-t border-medical-gray-200/60 flex justify-between items-center text-sm font-black text-medical-gray-900">
<span>مبلغ نهایی فاکتور:</span>
<span className="text-canina-blue">{toPersian(totalAmount.toLocaleString())} تومان</span>
</div>
</div>
</div>
</div>
</div>
{/* Footer Actions */}
<div className="p-6 sm:px-10 bg-medical-gray-50 border-t border-medical-gray-100 flex flex-col sm:flex-row items-center justify-between gap-4">
<button
onClick={handlePrint}
className="w-full sm:w-auto px-5 py-2.5 bg-white border border-medical-gray-200 text-medical-gray-700 rounded-xl text-xs font-black hover:border-canina-blue hover:text-canina-blue transition-all flex items-center justify-center gap-2 shadow-xs cursor-pointer"
>
<Download className="w-4 h-4" />
<span>چاپ فاکتور رسمی</span>
</button>
<div className="flex items-center gap-3 w-full sm:w-auto">
{isPendingPayment && (
<button
onClick={() => setRetryModalOpen(true)}
className="w-full sm:w-auto px-6 py-2.5 bg-green-600 hover:bg-green-700 text-white rounded-xl text-xs font-black shadow-lg shadow-green-600/20 transition-all flex items-center justify-center gap-2 cursor-pointer"
>
<CreditCard className="w-4 h-4" />
<span>پرداخت سفارش</span>
</button>
)}
<button
onClick={onClose}
className="w-full sm:w-auto px-6 py-2.5 bg-medical-gray-900 hover:bg-canina-blue text-white rounded-xl text-xs font-black transition-all cursor-pointer flex items-center justify-center gap-1.5"
>
<span>بازگشت</span>
<X className="w-4 h-4" />
</button>
</div>
</div>
{/* Retry Payment Modal */}
{retryModalOpen && (
<div className="fixed inset-0 z-60 bg-black/60 backdrop-blur-xs flex items-center justify-center p-4">
<div className="bg-white rounded-3xl p-6 sm:p-8 max-w-md w-full shadow-2xl border border-medical-gray-200 space-y-6">
<div className="flex items-center justify-between pb-4 border-b border-medical-gray-100">
<h3 className="text-base font-black text-medical-gray-900">
انتخاب روش پرداخت سفارش
</h3>
<button
onClick={() => setRetryModalOpen(false)}
className="text-medical-gray-400 hover:text-medical-gray-600"
>
<X className="w-5 h-5" />
</button>
</div>
<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-green-50 text-green-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-amber-50 text-amber-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>
{isCardToCardEnabled && (
<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>
)}
{/* Image Zoom Modal */}
{zoomedImage && (
<div
className="fixed inset-0 z-70 bg-black/80 backdrop-blur-sm flex items-center justify-center p-4"
onClick={() => setZoomedImage(null)}
>
<div className="relative max-w-lg w-full bg-white p-6 rounded-3xl shadow-2xl flex flex-col items-center">
<button
onClick={() => setZoomedImage(null)}
className="absolute top-4 left-4 p-2 rounded-full bg-medical-gray-100 hover:bg-medical-gray-200 text-medical-gray-700 transition-colors cursor-pointer"
>
<X className="w-5 h-5" />
</button>
<SafeImage
src={zoomedImage}
alt="نمایش کامل تصویر محصول"
className="max-h-[70vh] w-full"
imgClassName="max-h-[70vh] w-auto object-contain rounded-2xl mx-auto"
/>
</div>
</div>
)}
</motion.div>
</div>
)}
</AnimatePresence>
);
}