93 lines
3.4 KiB
TypeScript
93 lines
3.4 KiB
TypeScript
import { Link } from "react-router-dom";
|
||
import { MapPin, Phone, User, Plus, Timer } from "lucide-react";
|
||
import type { Material, Supplier } from "../../lib/types";
|
||
import { normalize } from "../../lib/normalize";
|
||
import { fmtNum } from "../../lib/formatters";
|
||
|
||
export function topicCategories(topic: string, materials: Material[], suppliers: Supplier[]): string[] {
|
||
const out = new Set<string>();
|
||
materials
|
||
.filter((m) => topic && normalize(m.topic) === normalize(topic) && m.category)
|
||
.forEach((m) => out.add(m.category));
|
||
suppliers
|
||
.filter((s) => topic && normalize(s.topic) === normalize(topic))
|
||
.forEach((s) => (s.categories || []).forEach((c) => c && out.add(c)));
|
||
return [...out].sort((a, b) => a.localeCompare(b, "fa"));
|
||
}
|
||
|
||
export function suppliersOfCategory(topic: string, cat: string, suppliers: Supplier[]): Supplier[] {
|
||
return suppliers.filter(
|
||
(s) => normalize(s.topic) === normalize(topic) && (s.categories || []).some((c) => normalize(c) === normalize(cat)),
|
||
);
|
||
}
|
||
|
||
// کارت تأمینکننده همراه با برچسب میانگین زمان تحویل
|
||
export function SupplierCard({
|
||
s,
|
||
topic,
|
||
deletable,
|
||
onDelete,
|
||
materials = [],
|
||
avgLeadTime,
|
||
}: {
|
||
s: Supplier;
|
||
topic: string;
|
||
deletable?: boolean;
|
||
onDelete?: (id: string) => void;
|
||
materials?: string[];
|
||
avgLeadTime?: number | null;
|
||
}) {
|
||
return (
|
||
<div className="sup-card">
|
||
<div className="sc-head flex items-start justify-between gap-2">
|
||
<Link to={`/suppliers/${s.id}`} className="sc-name-link min-w-0 flex-1 leading-snug">
|
||
{s.name}
|
||
</Link>
|
||
<div className="flex items-center gap-1.5 shrink-0">
|
||
{avgLeadTime != null && (
|
||
<span
|
||
className="inline-flex items-center gap-1 whitespace-nowrap rounded-md bg-emerald-100 border border-emerald-300/80 px-2 py-0.5 text-xs font-bold text-emerald-900 shadow-2xs dark:bg-emerald-950 dark:border-emerald-800 dark:text-emerald-200 tabular-nums"
|
||
title="میانگین زمان تحویل سفارشها"
|
||
>
|
||
<Timer className="h-3.5 w-3.5 text-emerald-700 dark:text-emerald-400" />
|
||
<span>{fmtNum(avgLeadTime)} روز</span>
|
||
</span>
|
||
)}
|
||
{deletable && onDelete && (
|
||
<button type="button" className="sup-del" title="حذف تأمینکننده" onClick={() => onDelete(s.id)}>
|
||
×
|
||
</button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
<div className="sc-meta">
|
||
<span>
|
||
<MapPin className="me-1 inline h-3 w-3" /> {s.location || "—"}
|
||
</span>
|
||
<span>
|
||
<Phone className="me-1 inline h-3 w-3" /> {s.phone || "—"}
|
||
</span>
|
||
<span>
|
||
<User className="me-1 inline h-3 w-3" /> {s.contact || "—"}
|
||
</span>
|
||
</div>
|
||
{materials.length > 0 && (
|
||
<div className="mt-2 border-t border-line pt-1.5">
|
||
<div className="mb-1 flex flex-wrap gap-1">
|
||
{materials.map((m, i) => (
|
||
<span key={i} className="spec-chip">
|
||
{m}
|
||
</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
<div className="sc-actions">
|
||
<Link to={`/wizard?topic=${encodeURIComponent(topic)}&supplier=${encodeURIComponent(s.id)}`} className="btn-line-file no-underline">
|
||
<Plus className="h-3 w-3" />
|
||
پیشنهاد جدید
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
);
|
||
} |