Merge latest prod_v2 (FileList preview modal, EditModal tabs) into integration
prod_v2's inline preview modal and EditModal redesign conflicted with the hardening branch's authenticated file API (urlOf/downloadUrl were removed because <a href>/<img> cannot send the Authorization header). - FileList: kept prod_v2's design (icons, preview modal, per-row actions) and adapted it — previews now fetch the bytes with a Bearer token and use a local objectURL (api.files.blobUrl), with revoke on close/unmount; the row download uses the authenticated onDownload. - EditModal: took prod_v2's tabbed redesign wholesale (it already carried our globalSpecs, clean material name and target_project work) and converted its FileList to onDownload + loadPreview. - AcceptModal: converted the remaining urlOf sites and removed duplicated file/date blocks the earlier merge had left outside the scroll body. - api.ts: restored the global handle401 (definition + all four fetch sites) alongside the new blobUrl helper.
This commit is contained in:
@@ -406,7 +406,8 @@ export function AcceptModal({ quoteId, onClose }: AcceptModalProps) {
|
||||
toast.error(err instanceof Error ? err.message : "حذف فاکتور ناموفق بود"),
|
||||
)
|
||||
}
|
||||
urlOf={(a) => (a.id ? api.files.downloadUrl(q.id, "invoice", a.id) : null)}
|
||||
onDownload={(a) => api.files.download(q.id, "invoice", a.id!, a.name)}
|
||||
loadPreview={(a) => api.files.blobUrl(q.id, "invoice", a.id!)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -424,7 +425,8 @@ export function AcceptModal({ quoteId, onClose }: AcceptModalProps) {
|
||||
toast.error(err instanceof Error ? err.message : "حذف پیشفاکتور ناموفق بود"),
|
||||
)
|
||||
}
|
||||
urlOf={(a) => (a.id ? api.files.downloadUrl(q.id, "proforma", a.id) : null)}
|
||||
onDownload={(a) => api.files.download(q.id, "proforma", a.id!, a.name)}
|
||||
loadPreview={(a) => api.files.blobUrl(q.id, "proforma", a.id!)}
|
||||
label="افزودن پیشفاکتور"
|
||||
/>
|
||||
</div>
|
||||
@@ -439,49 +441,6 @@ export function AcceptModal({ quoteId, onClose }: AcceptModalProps) {
|
||||
|
||||
</div>
|
||||
|
||||
{/* فاکتورهای اصلی */}
|
||||
<div className="border-t border-line pt-3">
|
||||
<div className="mb-1 text-[13px] font-bold">فاکتورهای اصلی (چند فایل):</div>
|
||||
<FileList
|
||||
files={invoices}
|
||||
onChange={setInvoices}
|
||||
upload={(f) => api.files.upload(q.id, "invoice", f)}
|
||||
onDelete={(a) =>
|
||||
a.id &&
|
||||
void api.files.remove(q.id, "invoice", a.id).catch((err) =>
|
||||
toast.error(err instanceof Error ? err.message : "حذف فاکتور ناموفق بود"),
|
||||
)
|
||||
}
|
||||
onDownload={(a) => api.files.download(q.id, "invoice", a.id!, a.name)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* پیشفاکتورها */}
|
||||
<div className="border-t border-line pt-3">
|
||||
<div className="mb-1 text-[13px] font-bold">پیشفاکتورها (چند فایل):</div>
|
||||
<FileList
|
||||
files={proformas}
|
||||
onChange={setProformas}
|
||||
upload={(f) => api.files.upload(q.id, "proforma", f)}
|
||||
onDelete={(a) =>
|
||||
a.id &&
|
||||
void api.files.remove(q.id, "proforma", a.id).catch((err) =>
|
||||
toast.error(err instanceof Error ? err.message : "حذف پیشفاکتور ناموفق بود"),
|
||||
)
|
||||
}
|
||||
onDownload={(a) => api.files.download(q.id, "proforma", a.id!, a.name)}
|
||||
label="افزودن پیشفاکتور"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* تاریخ و زمان پذیرش */}
|
||||
<div className="border-t border-line pt-3">
|
||||
<div className="field max-w-xs">
|
||||
<label>تاریخ و زمان پذیرش</label>
|
||||
<JalaliDatePicker value={acceptDate} onChange={setAcceptDate} placeholder="تاریخ و ساعت" withTime />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* فوتر ثابت */}
|
||||
<div className="px-6 py-4 bg-white border-t border-line shrink-0 z-10">
|
||||
<DialogFooter className="flex w-full gap-3 sm:justify-end">
|
||||
|
||||
Reference in New Issue
Block a user