690 lines
32 KiB
TypeScript
690 lines
32 KiB
TypeScript
/* 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>
|
||
);
|
||
}
|