import { Link } from "react-router-dom"; import { AlarmClock, ChevronDown, Pencil, TriangleAlert, Building2, Package, CreditCard, Check } from "lucide-react"; import type { Quote, Store } from "../../lib/types"; import { isExpired, itemsSummary, materialById, materialLabel, projectCell, quoteTotal, supplierById, termsheetSummary, unitWarning, } from "../../lib/quoteUtils"; import { STATUS_LABEL } from "../../lib/constants"; import { esc, fmtDate, fmtDateTime, fmtNum, priceCell } from "../../lib/formatters"; import { Badge } from "../../components/ui/badge"; import { cn } from "../../lib/utils"; import { QuoteDetail } from "./QuoteDetail"; export interface QuoteCardProps { store: Store; q: Quote; expanded: boolean; onToggleExpand: () => void; onAccept: () => void; onEdit: () => void; } function InfoCell({ label, children, className }: { label: string; children: React.ReactNode; className?: string }) { return (
{label}
{children}
); } // کارت پیشنهاد خرید — بهینه‌شده برای کاربری سرپا با موبایل export function QuoteCard({ store, q, expanded, onToggleExpand, onAccept, onEdit }: QuoteCardProps) { const sup = supplierById(store.suppliers, q.supplier_id); const expired = isExpired(q); const total = quoteTotal(q); const pc = priceCell(total); const ts = termsheetSummary(store, q); const unitWarns = unitWarning(store, q); const summary = itemsSummary(store, q); // ستون / دکمه پذیرش let acceptedCell: React.ReactNode; if (q.status === "offered") { acceptedCell = ( ); } else if (q.accepted_date) { acceptedCell = {fmtDateTime(q.accepted_date)}; } else { acceptedCell = —; } // وضعیت رسید کالا const activeItems = (q.line_items || []).filter((li) => !li.rejected); const receivedSum = activeItems.reduce((s, li) => s + (li.received_qty || 0), 0); const orderedSum = activeItems.reduce((s, li) => s + (li.quantity || 0), 0); const fulfilledItems = activeItems.filter( (li) => li.quantity != null && li.quantity > 0 && (li.received_qty || 0) >= li.quantity, ).length; const anyReceived = receivedSum > 0; const fullyDelivered = activeItems.length > 0 && fulfilledItems === activeItems.length && anyReceived; // نشان پیشرفت تکمیل let fulfillmentBadge: React.ReactNode = null; if (q.status === "accepted" || q.status === "arrived") { if (fullyDelivered || q.status === "arrived") { fulfillmentBadge = ( ✓ تکمیل ); } else if (anyReceived) { fulfillmentBadge = ( رسید: {fmtNum(fulfilledItems)}/{fmtNum(activeItems.length)} ); } else { fulfillmentBadge = ( ⏳ در راه ); } } let arrivedCell: React.ReactNode; const lastReceiptAt = activeItems.reduce((acc, li) => { if (!li.arrived_date) return acc; const t = new Date(li.arrived_date).getTime(); if (Number.isNaN(t)) return acc; return !acc || t > acc.getTime() ? new Date(li.arrived_date) : acc; }, null); if (q.status === "accepted") { if (q.arrived_date) { arrivedCell = {fmtDateTime(q.arrived_date)}; } else if (receivedSum > 0) { arrivedCell = ( {fmtNum(receivedSum)} از {fmtNum(orderedSum)} ); } else { arrivedCell = در انتظار انبار; } } else if (q.status === "arrived") { arrivedCell = ( {fmtDateTime(q.arrived_date || (lastReceiptAt ? lastReceiptAt.toISOString() : ""))} ); } else { arrivedCell = —; } return (
{/* سربرگ کارت */}
{sup.name.slice(0, 1)}
{sup.name} {sup.location &&
{sup.location}
}
{fulfillmentBadge ?? ( {STATUS_LABEL[q.status]} )}
{/* اطلاعات کلیدی — چیدمان بهینه‌شده موبایل */}
{/* ۱. پروژه — تمام‌عرض در موبایل */}
{q.projects && q.projects.length > 0 ? q.projects.join("، ") : projectCell(q)}
{/* ۲. اقلام — تمام‌عرض زیر پروژه با شکستن متن بدون سه‌نقطه */} {summary.count > 1 ? (
{fmtNum(summary.count)} قلم کالا
{store.quotes .find((x) => x.id === q.id) ?.line_items?.filter((li) => !li.rejected) .slice(0, 3) .map((li) => { const m = materialById(store.materials, li.material_id); return (
• {materialLabel(m)} {fmtNum(li.quantity)}{" "} {li.unit}
); })} {(q.line_items?.length || 0) > 3 && ( و {(q.line_items?.length || 0) - 3} قلم دیگر... )}
) : (
{summary.text}
)} {unitWarns.map((w) => ( واحد جدید: {w.unit} ))}
{(() => { const activeItems = (q.line_items || []).filter((li) => !li.rejected); if (q.status === "accepted" || q.status === "arrived") { // فقط پروژه‌ی هدف پذیرفته‌شده — همان منطق itemProjects در وضعیت accepted const targetProj = activeItems.find((li) => li.target_project)?.target_project; return targetProj?.name ?? projectCell(q); } // وضعیت offered: همه‌ی پروژه‌های کاندیدا از line_items (همان منطق itemProjects) const names = new Set(); activeItems.forEach((li) => (li.projects || []).forEach((p) => { const name = typeof p === "string" ? p : p.name; if (name) names.add(name); }) ); if (names.size > 0) return [...names].join("، "); return projectCell(q); })()} {pc ? (
{pc.num} تومان
({pc.words})
) : ( "—" )}
{/* ۴. شرایط معامله */} {ts.title !== "—" ? (
{ts.title}
{ts.sub &&
{ts.sub}
}
) : ( — )}
{/* تاریخ‌ها و اکشن‌ها */}
تاریخ: {fmtDate(q.quote_date)} اعتبار: {fmtDate(q.expiry_date)} {expired && } پذیرش: {acceptedCell} رسید: {arrivedCell}
{/* جزئیات تکمیلی بازشونده */} {expanded && }
); }