feat(frontend): add React UI — procurement office, wizard, suppliers, inventory panel (dash port), role-based login
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import { Paperclip } from "lucide-react";
|
||||
import { faNum } from "../../lib/formatters";
|
||||
import { groupCommas } from "../../lib/numutil";
|
||||
import { JalaliDatePicker } from "../../components/JalaliDatePicker";
|
||||
import { FileUpload } from "../../components/FileUpload";
|
||||
|
||||
export interface Step5Props {
|
||||
quoteDate: string | null;
|
||||
onQuoteDate: (iso: string | null) => void;
|
||||
expiryDate: string | null;
|
||||
onExpiryDate: (iso: string | null) => void;
|
||||
notes: string;
|
||||
onNotes: (v: string) => void;
|
||||
proforma: File | null;
|
||||
onProforma: (f: File | null) => void;
|
||||
// خلاصهی بازبینی
|
||||
summary: {
|
||||
supplierName: string;
|
||||
topicName: string;
|
||||
projects: string[];
|
||||
itemCount: number;
|
||||
tsCount: number;
|
||||
grandTotal: number;
|
||||
isOfficial: boolean;
|
||||
orphanCount: number;
|
||||
};
|
||||
}
|
||||
|
||||
// مرحله ۵ — تاریخ، یادداشت، پیشفاکتور و بازبینی نهایی
|
||||
export function Step5Review({
|
||||
quoteDate,
|
||||
onQuoteDate,
|
||||
expiryDate,
|
||||
onExpiryDate,
|
||||
notes,
|
||||
onNotes,
|
||||
proforma,
|
||||
onProforma,
|
||||
summary,
|
||||
}: Step5Props) {
|
||||
const rows: [string, string][] = [
|
||||
["تأمینکننده", summary.supplierName],
|
||||
["موضوع", summary.topicName],
|
||||
["پروژهها", summary.projects.join("، ") || "—"],
|
||||
["تعداد اقلام", groupCommas(summary.itemCount, true)],
|
||||
["تعداد termsheet", groupCommas(summary.tsCount, true)],
|
||||
["جمع کل تقریبی", groupCommas(summary.grandTotal, true) + " تومان"],
|
||||
["فاکتور رسمی", summary.isOfficial ? "بله" : "خیر"],
|
||||
["پیشفاکتور", proforma ? proforma.name : "—"],
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3 className="mb-3 text-[15px] font-bold">
|
||||
<span className="me-1 inline-flex h-6 w-6 items-center justify-center rounded-full bg-accent text-[12px] font-bold text-white">۵</span>
|
||||
تاریخ، یادداشت و بازبینی نهایی
|
||||
</h3>
|
||||
|
||||
<div className="grid max-w-2xl grid-cols-2 gap-3">
|
||||
<div className="field">
|
||||
<label>تاریخ پیشنهاد</label>
|
||||
<JalaliDatePicker value={quoteDate} onChange={onQuoteDate} placeholder="۱۴۰۳/۰۵/۱۲" withTime />
|
||||
<div className="hint">پیشفرض امروز</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label>تاریخ انقضای پیشنهاد</label>
|
||||
<JalaliDatePicker value={expiryDate} onChange={onExpiryDate} placeholder="۱۴۰۳/۰۶/۱۲" />
|
||||
<div className="hint">تا چه زمانی این قیمت معتبر است؟</div>
|
||||
</div>
|
||||
<div className="field col-span-2">
|
||||
<label>یادداشت (اختیاری)</label>
|
||||
<textarea
|
||||
rows={2}
|
||||
className="w-full rounded-lg border border-line bg-panel px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/40"
|
||||
placeholder="توضیحات اضافی درباره تماس یا توافق..."
|
||||
value={notes}
|
||||
onChange={(e) => onNotes(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="field col-span-2">
|
||||
<label>پیشفاکتور (اختیاری)</label>
|
||||
{proforma ? (
|
||||
<div className="inv-row">
|
||||
<span className="inv-name">
|
||||
<Paperclip className="me-1 inline h-3.5 w-3.5" />
|
||||
{proforma.name}
|
||||
</span>
|
||||
<button type="button" className="inv-x" title="حذف" onClick={() => onProforma(null)}>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<FileUpload onUpload={onProforma} label="انتخاب فایل پیشفاکتور" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 rounded-xl border border-line bg-panel p-4 shadow-sm">
|
||||
<h4 className="mb-2 text-[13.5px] font-bold">خلاصهی پیشنهاد پیش از ذخیره</h4>
|
||||
{rows.map(([label, val]) => (
|
||||
<div key={label} className="review-row">
|
||||
<span className="r-label">{label}</span>
|
||||
<span className="r-val">{val}</span>
|
||||
</div>
|
||||
))}
|
||||
{summary.orphanCount > 0 && (
|
||||
<div className="review-row">
|
||||
<span className="r-label">هشدار</span>
|
||||
<span className="r-val review-warn">
|
||||
{faNum(summary.orphanCount)} قلم به هیچ termsheet وصل نیست -- در ذخیرهسازی بهطور خودکار به اولین termsheet وصل میشود
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user