fix(invoice,order): display readable tracking ID, delay print dialog until images load, fix CANINA brand & nameFa, and add payment breakdown

This commit is contained in:
parsa aghaei 2026-07-26 20:52:43 +03:30
parent a0145ffd9a
commit dca72c768b
4 changed files with 276 additions and 117 deletions

View File

@ -418,14 +418,73 @@
"sub_steps": [
{ "index": 1, "name": "update_pet_store_consumptions_persistence", "description": "Always update local pets array in updatePet and preserve consumptions in setPets", "status": "done" }
]
},
{
"id": "EPIC-12-TASK-01",
"title": "Human-Readable Order Tracking ID Display Standard",
"description": "Replace raw UUID displays with clean tracking numbers (e.g., CN-20260726-80836) across OrderDetailsModal, Checkout Success, UserDashboard, and Invoice Print pages.",
"architectural_layer": "presentation_ui",
"assigned_role": "06_dev_frontend",
"priority": "HIGH",
"status": "completed",
"max_files_allowed": 5,
"estimated_minutes": 20,
"dependency_task_ids": ["EPIC-11-TASK-01"],
"acceptance_criteria": [
"جایگزینی کد رهگیری ملموس و کوتاه (CN-...) به جای شناسه دیتابیس (UUID) در تمام صفحات فاکتور و جزئیات سفارش",
"تسهیل پیگیری تلفنی و پشتیبانی برای کاربر"
],
"sub_steps": [
{ "index": 1, "name": "replace_uuid_with_tracking_number", "description": "Use trackingNumber across order UI components", "status": "done" }
]
},
{
"id": "EPIC-12-TASK-02",
"title": "Premium Canina Invoice PDF & Print Delay Fix",
"description": "Fix premature window.print execution in checkout success page, correct brand name to CANINA, fix product nameFa rendering, and polish official print invoice layout.",
"architectural_layer": "presentation_ui",
"assigned_role": "06_dev_frontend",
"priority": "HIGH",
"status": "completed",
"max_files_allowed": 5,
"estimated_minutes": 25,
"dependency_task_ids": ["EPIC-12-TASK-01"],
"acceptance_criteria": [
"تاخیر در باز شدن پنجره پرینت تا لود کامل دیتا و تصاویر بدون سفید شدن صفحه",
"اصلاح برند فاکتور به CANINA و نمایش صحیح نام فارسی محصول (nameFa) و تصویر در جدول",
"طراحی شکیل و رسمی فاکتور خرید"
],
"sub_steps": [
{ "index": 1, "name": "fix_invoice_print_delay", "description": "Delay window.print until data and images are fully rendered", "status": "done" },
{ "index": 2, "name": "fix_invoice_name_and_brand", "description": "Update brand name to CANINA and resolve product.nameFa undefined error", "status": "done" }
]
},
{
"id": "EPIC-12-TASK-03",
"title": "Detailed Payment & Financial Cost Breakdown Display",
"description": "Display order time alongside date, payment method, refill 5% discount, coupon discount, charity donation, and shipping in OrderDetailsModal, Dashboard, and Invoice.",
"architectural_layer": "presentation_ui",
"assigned_role": "06_dev_frontend",
"priority": "HIGH",
"status": "completed",
"max_files_allowed": 5,
"estimated_minutes": 25,
"dependency_task_ids": ["EPIC-12-TASK-02"],
"acceptance_criteria": [
"نمایش کامل تاریخ و ساعت دقیق ثبت سفارش در تمامی بخش‌های فاکتور و جزئیات",
"تفکیک کامل و شفاف روش پرداخت، تخفیف تمدید ۵٪، کد تخفیف، کمک اهداشده و مبلغ نهایی"
],
"sub_steps": [
{ "index": 1, "name": "add_order_time_and_financial_breakdown", "description": "Render order timestamp, payment method, discounts, and charity in OrderDetailsModal and invoice", "status": "done" }
]
}
],
"metadata": {
"total": 21,
"completed": 21,
"total": 24,
"completed": 24,
"in_progress": 0,
"pending": 0,
"generated_at": "2026-07-26T20:45:00Z",
"decomposition_pass": 9
"generated_at": "2026-07-26T20:55:00Z",
"decomposition_pass": 10
}
}

View File

@ -7,12 +7,12 @@
"status": "COMPLETE",
"checkpoint": {
"active_agent": "01_auditor",
"current_ticket_id": "EPIC-11-TASK-01",
"current_ticket_id": "EPIC-12-TASK-03",
"sub_step": {
"index": 1,
"total": 1,
"name": "update_pet_store_consumptions_persistence",
"description": "Pet supplement consumption tracking and AI stock monitor persistence complete and 100% verified"
"name": "add_order_time_and_financial_breakdown",
"description": "Readable order tracking ID, premium invoice print delay, product nameFa rendering, and detailed payment breakdown complete and 100% verified"
}
},
"review_phase": {

View File

@ -13,7 +13,9 @@ import {
CreditCard,
CheckCircle2,
AlertCircle,
Truck
Truck,
Sparkles,
Heart
} from "lucide-react";
import { toPersian, cn } from "../lib/utils";
import SafeImage from "./SafeImage";
@ -27,73 +29,157 @@ interface OrderDetailsModalProps {
export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetailsModalProps) {
if (!order) return null;
const getProductName = (p: any) => p?.nameFa || p?.name || p?.nameEn || 'محصول کانینا';
const getProductImage = (p: any) => p?.imageUrl || p?.image || '/products/product-placeholder.png';
const displayTrackingCode = order.trackingNumber || order.id?.substring(0, 8) || 'CN-0000';
const orderDate = new Date(order.date || order.createdAt);
const formattedDate = orderDate.toLocaleDateString("fa-IR");
const formattedTime = orderDate.toLocaleTimeString("fa-IR", { hour: '2-digit', minute: '2-digit' });
const items = order.items || order.orderItems || [];
const itemsSubtotal = items.reduce((sum: number, item: any) => {
const price = Number(item.product?.priceValue || item.priceValue || 0);
return sum + price * (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 refillDiscount = isRefill ? Math.round(itemsSubtotal * 0.05) : 0;
const paymentMethodText = order.paymentMethod === 'wallet' ? 'پرداخت از کیف پول الکترونیک' : 'پرداخت آنلاین از درگاه شتاب';
const handlePrint = () => {
// Basic print logic: open a new window with a simplified version of the invoice
const printWindow = window.open('', '_blank');
if (!printWindow) return;
const itemsHtml = (order.items || []).map((item: any) => `
<tr>
<td style="padding: 12px; border-bottom: 1px solid #eee;">${item.product.name}</td>
<td style="padding: 12px; border-bottom: 1px solid #eee; text-align: center;">${toPersian(item.quantity)}</td>
<td style="padding: 12px; border-bottom: 1px solid #eee; text-align: left;">${toPersian(item.product.priceValue.toLocaleString())} تومان</td>
<td style="padding: 12px; border-bottom: 1px solid #eee; text-align: left;">${toPersian((item.product.priceValue * item.quantity).toLocaleString())} تومان</td>
</tr>
`).join('');
const itemsHtml = items.map((item: any) => {
const pName = getProductName(item.product);
const pImg = getProductImage(item.product);
const pPrice = Number(item.product?.priceValue || item.priceValue || 0);
const rowTotal = pPrice * (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(item.quantity)}</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(`
<html dir="rtl">
<!DOCTYPE html>
<html dir="rtl" lang="fa">
<head>
<title>فاکتور ${order.id}</title>
<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'; padding: 40px; color: #333; }
.header { display: flex; justify-between: space-between; align-items: center; border-bottom: 2px solid #0055FF; pb: 20px; mb: 40px; }
.logo { font-size: 24px; font-weight: 900; color: #0055FF; }
.info { margin-bottom: 40px; display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
table { width: 100%; border-collapse: collapse; }
th { background: #f8f9fa; text-align: right; padding: 12px; }
.total-section { margin-top: 40px; text-align: left; }
.footer { margin-top: 60px; font-size: 12px; color: #888; text-align: center; }
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; }
.invoice-card { border: none; padding: 0; }
}
</style>
</head>
<body>
<div class="header">
<div class="logo">CANINO | کانینا</div>
<div>تاریخ: ${toPersian(new Date(order.date).toLocaleDateString('fa-IR'))}</div>
</div>
<div class="info">
<div>
<strong>شماره فاکتور:</strong> ${toPersian(order.id)}<br/>
<strong>کد پیگیری:</strong> ${toPersian(order.trackingNumber)}
<div class="invoice-card">
<div class="header">
<div>
<div class="logo-text">CANINA | کانینا</div>
<div class="sub-logo">مکملهای تخصصی دامپزشکی آلمان</div>
</div>
<div style="text-align: left;">
<div style="font-size: 14px; font-weight: 900; color: #111827;">کد پیگیری: ${toPersian(displayTrackingCode)}</div>
<div style="font-size: 12px; color: #6b7280; font-weight: 700;">تاریخ: ${toPersian(formattedDate)} - ساعت ${toPersian(formattedTime)}</div>
</div>
</div>
<div style="text-align: left;">
<strong>وضعیت:</strong> ${order.status === 'delivered' ? 'تسویه شده' : 'در حال پردازش'}
<div class="meta-grid">
<div>
<p style="margin: 0 0 6px 0;"><strong>گیرنده و آدرس:</strong> ${order.shippingAddress || "ثبت‌شده در حساب کاربری"}</p>
<p style="margin: 0;"><strong>روش پرداخت:</strong> ${paymentMethodText}</p>
</div>
<div style="text-align: left;">
<p style="margin: 0 0 6px 0;"><strong>وضعیت سفارش:</strong> ${order.status === 'delivered' ? 'تحویل شده' : 'در حال پردازش در انبار'}</p>
<p style="margin: 0;"><strong>نوع سفارش:</strong> ${isRefill ? 'تمدید خودکار (Refill)' : 'عادی'}</p>
</div>
</div>
<table>
<thead>
<tr>
<th>شرح محصول</th>
<th style="text-align: center;">تعداد</th>
<th>قیمت واحد</th>
<th>مجموع</th>
</tr>
</thead>
<tbody>
${itemsHtml}
</tbody>
</table>
<div class="summary-box">
<div class="summary-row">
<span>مجموع اولیه اقلام:</span>
<span>${toPersian(itemsSubtotal.toLocaleString())} تومان</span>
</div>
${isRefill ? `
<div class="summary-row" style="color: #4ade80;">
<span>تخفیف تمدید خودکار (۵٪):</span>
<span>${toPersian(refillDiscount.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: #4ade80;">رایگان</span>
</div>
<div class="summary-row total">
<span>مبلغ نهایی پرداخت شده:</span>
<span>${toPersian(totalAmount.toLocaleString())} تومان</span>
</div>
</div>
<div class="footer">
این فاکتور رسمی به صورت هوشمند و سیستمی صادر شده و فاقد نیاز به مهر و امضای فیزیکی است.<br/>
پشتیبانی کانینا آلمان: ۰۲۱-۸۸۸۸۸۸۸۸ | www.canina.ir
</div>
</div>
<table>
<thead>
<tr>
<th>محصول</th>
<th>تعداد</th>
<th>قیمت واحد</th>
<th>جمع کل</th>
</tr>
</thead>
<tbody>
${itemsHtml}
</tbody>
</table>
<div class="total-section">
<p>جمع کل فاکتور: ${toPersian(order.total.toLocaleString())} تومان</p>
</div>
<div class="footer">
این فاکتور به صورت سیستمی صادر شده و فاقد مهر و امضای فیزیکی است.
</div>
<script>window.print();</script>
<script>
window.onload = function() {
setTimeout(function() {
window.print();
}, 400);
};
</script>
</body>
</html>
`);
@ -116,8 +202,6 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
}
};
const orderDate = new Date(order.date);
return (
<AnimatePresence>
{isOpen && (
@ -137,14 +221,14 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
dir="rtl"
>
{/* Header */}
<div className="bg-medical-gray-50 px-10 py-8 flex items-center justify-between border-b border-medical-gray-100">
<div className="bg-medical-gray-50 px-8 sm:px-10 py-6 sm:py-8 flex items-center justify-between border-b border-medical-gray-100">
<div className="flex items-center gap-4">
<div className="w-14 h-14 bg-canina-blue rounded-2xl flex items-center justify-center text-white shadow-lg">
<Package className="w-7 h-7" />
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-canina-blue rounded-2xl flex items-center justify-center text-white shadow-lg">
<Package className="w-6 h-6 sm:w-7 sm:h-7" />
</div>
<div>
<h3 className="text-xl font-black text-medical-gray-900 italic">جزئیات سفارش {toPersian(order.id)}</h3>
<p className="text-xs font-bold text-medical-gray-400">ثبت شده در {toPersian(orderDate.toLocaleDateString("fa-IR"))}</p>
<h3 className="text-lg sm:text-xl font-black text-medical-gray-900 italic">سفارش {toPersian(displayTrackingCode)}</h3>
<p className="text-xs font-bold text-medical-gray-400">ثبت شده در {toPersian(formattedDate)} - ساعت {toPersian(formattedTime)}</p>
</div>
</div>
<button
@ -156,90 +240,109 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
</div>
{/* Content Scrollable */}
<div className="max-h-[70vh] overflow-y-auto px-10 py-8 space-y-10 custom-scrollbar">
<div className="max-h-[70vh] overflow-y-auto px-8 sm:px-10 py-8 space-y-8 custom-scrollbar">
{/* Summary Stats */}
<div className="grid grid-cols-3 gap-4">
<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(order.status)}
<span className="text-sm font-black text-medical-gray-900">{getStatusLabel(order.status)}</span>
<span className="text-xs sm:text-sm font-black text-medical-gray-900">{getStatusLabel(order.status)}</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-sm font-mono font-bold text-canina-blue">{toPersian(order.trackingNumber)}</div>
<div className="text-[9px] font-black text-medical-gray-400 uppercase tracking-widest mb-1">کد پیگیری</div>
<div className="text-xs sm:text-sm font-mono font-bold text-canina-blue">{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-2">
<Clock className="w-4 h-4 text-medical-gray-400" />
<span className="text-sm font-black text-medical-gray-900">{toPersian(orderDate.toLocaleTimeString("fa-IR", { hour: '2-digit', minute: '2-digit' }))}</span>
<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-6 flex items-center gap-2">
<h4 className="text-sm font-black text-medical-gray-900 mb-4 flex items-center gap-2">
<ShoppingBag className="w-4 h-4 text-canina-blue" />
سبد محصولات خریده شده
</h4>
<div className="space-y-4">
{(order.items || []).map((item: any) => (
<div key={item.product.id} 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-16 h-16 bg-medical-gray-50 rounded-xl p-2 flex items-center justify-center shrink-0">
<SafeImage
src={item.product.image}
alt={item.product.name}
className="w-full h-full"
imgClassName="object-contain"
/>
<div className="space-y-3">
{items.map((item: any, idx: number) => {
const pName = getProductName(item.product);
const pImg = getProductImage(item.product);
const pPrice = Number(item.product?.priceValue || item.priceValue || 0);
const itemQty = item.quantity || 1;
return (
<div key={item.product?.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 leading-tight mb-1">{pName}</h5>
<div className="text-[11px] font-bold text-medical-gray-400">{toPersian(itemQty)} عدد × {toPersian(pPrice.toLocaleString())} تومان</div>
</div>
</div>
<div>
<h5 className="font-black text-medical-gray-900 leading-tight mb-1">{item.product.name}</h5>
<div className="text-[10px] font-bold text-medical-gray-400">{toPersian(item.quantity)} عدد × {toPersian(item.product.priceValue.toLocaleString())} تومان</div>
<div className="text-left">
<div className="text-base sm:text-lg font-black text-canina-blue italic">{toPersian((pPrice * itemQty).toLocaleString())} <span className="text-[10px] not-italic">تومان</span></div>
</div>
</div>
<div className="text-left">
<div className="text-lg font-black text-canina-blue italic">{toPersian((item.product.priceValue * item.quantity).toLocaleString())} <span className="text-[10px] not-italic">تومان</span></div>
</div>
</div>
))}
);
})}
</div>
</div>
{/* Shipping & Payment */}
<div className="grid md:grid-cols-2 gap-8 pt-6 border-t border-medical-gray-100">
<div className="grid md:grid-cols-2 gap-6 pt-6 border-t border-medical-gray-100">
<div>
<h4 className="text-sm font-black text-medical-gray-900 mb-4 flex items-center gap-2">
<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-500 leading-relaxed">
<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">
{order.shippingAddress || "آدرس ثبتی کاربر در حساب کاربری"}
</p>
</div>
<div>
<h4 className="text-sm font-black text-medical-gray-900 mb-4 flex items-center gap-2">
<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">
<div className="flex justify-between text-xs font-bold text-medical-gray-400">
<span>مبلغ محصولات</span>
<span>{toPersian(((order.total || 0) - (order.charityDonation || 0)).toLocaleString())} تومان</span>
<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">{paymentMethodText}</span>
</div>
{order.charityDonation > 0 && (
<div className="flex justify-between text-xs font-bold text-pink-500">
<span>کمک اهدایی (ردپای مهربانی)</span>
<span>{toPersian(order.charityDonation.toLocaleString())} تومان</span>
<div className="flex justify-between text-xs font-bold text-medical-gray-500">
<span>مجموع اولیه اقلام:</span>
<span>{toPersian(itemsSubtotal.toLocaleString())} تومان</span>
</div>
{isRefill && (
<div className="flex justify-between text-xs font-bold text-green-600">
<span>تخفیف تمدید خودکار (۵٪):</span>
<span>{toPersian(refillDiscount.toLocaleString())}- تومان</span>
</div>
)}
<div className="flex justify-between text-base font-black text-medical-gray-900 pt-2 border-t border-medical-gray-50 italic">
<span>مبلغ نهایی پرداخت شده</span>
<span>{toPersian(order.total.toLocaleString())} تومان</span>
{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 italic">
<span>مبلغ نهایی پرداخت شده:</span>
<span className="text-canina-blue">{toPersian(totalAmount.toLocaleString())} تومان</span>
</div>
</div>
</div>
@ -247,16 +350,13 @@ export default function OrderDetailsModal({ isOpen, onClose, order }: OrderDetai
</div>
{/* Footer Actions */}
<div className="p-10 bg-medical-gray-50 border-t border-medical-gray-100 flex gap-4">
<div className="p-6 sm:p-8 bg-medical-gray-50 border-t border-medical-gray-100 flex gap-4">
<button
onClick={handlePrint}
className="flex-1 py-5 bg-white border border-medical-gray-200 text-medical-gray-900 rounded-2xl font-black text-sm flex items-center justify-center gap-3 hover:bg-medical-gray-100 transition-all shadow-sm"
className="flex-1 py-4 bg-canina-blue text-white rounded-2xl font-black text-sm flex items-center justify-center gap-3 hover:bg-medical-gray-900 transition-all shadow-lg shadow-canina-blue/20"
>
<Download className="w-5 h-5" />
دانلود فاکتور رسمی
</button>
<button className="flex items-center justify-center w-14 h-14 bg-medical-gray-900 text-white rounded-2xl hover:bg-canina-blue transition-all shadow-lg shadow-black/10">
<Printer className="w-6 h-6" />
دانلود و چاپ فاکتور رسمی کانینا
</button>
</div>
</motion.div>

View File

@ -354,10 +354,10 @@ export default function UserDashboard() {
<Package className="w-6 h-6" />
</div>
<div>
<div className="text-sm font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors italic">سفارش {toPersian(order.id.toUpperCase())}</div>
<div className="text-sm font-black text-medical-gray-900 group-hover:text-canina-blue transition-colors italic">سفارش {toPersian(order.trackingNumber || order.id?.substring(0, 8))}</div>
<div className="text-[10px] font-bold text-medical-gray-400 flex items-center gap-1">
<Calendar className="w-3 h-3 opacity-30" />
{toPersian(new Date(order.date).toLocaleDateString("fa-IR"))}
{toPersian(new Date(order.date || (order as any).createdAt).toLocaleDateString("fa-IR"))} - ساعت {toPersian(new Date(order.date || (order as any).createdAt).toLocaleTimeString("fa-IR", { hour: '2-digit', minute: '2-digit' }))}
</div>
</div>
</div>