fix(orders): source attachments from order_attachements field
The orders review modal's source-of-truth panel now reads from the order_attachements multi-file field on the orders collection (pbc_3527180448) instead of the quote_attachments collection rows on the parent quote. Older orders were migrated on 2026-07-29; the order-level field is authoritative going forward. - Added orderAttachementsToQuotes() helper in src/app/(app)/orders/page.tsx that synthesises the QuoteAttachment[] shape from the order's file-field array, deriving kind (pdf/image/doc) and content_type from the filename extension. PB file fields don't carry a content-type from the wire, so we infer from extension (png/jpg/gif/webp/svg/bmp/pdf/docx/txt). - Replaced the quote_attachments collection query in OrdersReviewModalMount with the helper call. - Added orders + pbc_3527180448 to the ALLOWED_COLLECTIONS whitelist in the file proxy route so the review modal's PDF/image preview iframes can stream through /api/v1/files/... . Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
7801b602f5
commit
d6570dca71
2 changed files with 81 additions and 9 deletions
|
|
@ -72,6 +72,67 @@ const EMPTY_COUNTS: Record<TabGroup, number> = {
|
|||
|
||||
const SEARCH_DEBOUNCE_MS = 250;
|
||||
|
||||
/**
|
||||
* Convert the order's `order_attachements` file field into the
|
||||
* `QuoteAttachment[]` shape the review modal expects. The PB file field
|
||||
* stores bare filenames (no collection-id token), so we synthesise the
|
||||
* `kind` / `content_type` pairs from the filename extension. `size_bytes`
|
||||
* is not available from a PB file field, so we leave it at 0.
|
||||
*
|
||||
* Kept inline because it's tightly coupled to the modal's
|
||||
* `QuoteAttachment` interface — extracting it would just push the same
|
||||
* code into another file.
|
||||
*/
|
||||
function orderAttachementsToQuotes(
|
||||
order: import("@/lib/types").Order,
|
||||
): import("@/lib/types").QuoteAttachment[] {
|
||||
const files = order.order_attachements ?? [];
|
||||
return files.map((filename) => {
|
||||
const lower = filename.toLowerCase();
|
||||
let kind: "pdf" | "image" | "doc" = "doc";
|
||||
let content_type = "application/octet-stream";
|
||||
if (lower.endsWith(".pdf")) {
|
||||
kind = "pdf";
|
||||
content_type = "application/pdf";
|
||||
} else if (/\.(png|jpe?g|gif|webp|bmp|svg)$/.test(lower)) {
|
||||
const ext = lower.split(".").pop() ?? "";
|
||||
const imageMime =
|
||||
ext === "png"
|
||||
? "png"
|
||||
: ext === "gif"
|
||||
? "gif"
|
||||
: ext === "webp"
|
||||
? "webp"
|
||||
: ext === "svg"
|
||||
? "svg+xml"
|
||||
: ext === "bmp"
|
||||
? "bmp"
|
||||
: "jpeg";
|
||||
kind = "image";
|
||||
content_type = `image/${imageMime}`;
|
||||
} else if (lower.endsWith(".docx")) {
|
||||
content_type =
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||
} else if (lower.endsWith(".txt")) {
|
||||
content_type = "text/plain";
|
||||
}
|
||||
return {
|
||||
id: order.id,
|
||||
created: order.created,
|
||||
updated: order.updated,
|
||||
collectionId: order.collectionId,
|
||||
collectionName: "orders",
|
||||
quote: order.quote,
|
||||
filename,
|
||||
file: [filename],
|
||||
content_type,
|
||||
size_bytes: 0,
|
||||
email_message_id: "",
|
||||
kind,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* OrdersReviewModalMount — fetches the order's full details, line items,
|
||||
* the source quote's email + attachments, and the customer/company lists,
|
||||
|
|
@ -107,7 +168,8 @@ function OrdersReviewModalMount({
|
|||
// Use the BROWSER PB instance (not the admin one) — admin PB
|
||||
// requires server-only env vars and would break in the browser
|
||||
// bundle. The user's session PB already has read access to
|
||||
// customers + quote_attachments, so we don't need privileges.
|
||||
// customers, so we don't need privileges for the order-level
|
||||
// attachments (they live on the order record itself).
|
||||
const { getPocketBase } = await import("@/lib/pocketbase");
|
||||
const pb = getPocketBase();
|
||||
const [order, items, customersResult] = await Promise.all([
|
||||
|
|
@ -128,13 +190,17 @@ function OrdersReviewModalMount({
|
|||
})
|
||||
| undefined;
|
||||
|
||||
const attachments = quote
|
||||
? await pb
|
||||
.collection("quote_attachments")
|
||||
.getFullList({
|
||||
filter: `quote = "${quote.id}"`,
|
||||
})
|
||||
: [];
|
||||
// Source attachments from `order_attachements` — the multi-file
|
||||
// field ON the order record itself (orders collection
|
||||
// `pbc_3527180448`, `maxSelect: 10`, accepts any MIME). Older
|
||||
// orders may still have attachments stored under
|
||||
// `quote_attachments` on the parent quote, but those records
|
||||
// were migrated to the order-level field on 2026-07-29, so
|
||||
// reading from the order is authoritative going forward.
|
||||
// The PB file field stores bare filenames (no collection-id
|
||||
// token); we synthesise the QuoteAttachment shape the modal
|
||||
// expects (kind + content_type) from the filename extension.
|
||||
const attachments = orderAttachementsToQuotes(order);
|
||||
|
||||
if (cancelled) return;
|
||||
|
||||
|
|
@ -163,7 +229,7 @@ function OrdersReviewModalMount({
|
|||
subject: quote?.email_subject || "",
|
||||
body: quote?.email_body || "",
|
||||
},
|
||||
attachments: attachments as import("@/lib/types").QuoteAttachment[],
|
||||
attachments,
|
||||
});
|
||||
} catch (err) {
|
||||
if (!cancelled) {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@ const ALLOWED_COLLECTIONS = new Set<string>([
|
|||
// Order items — attachment chips and the Attach upload on the
|
||||
// Collection Confirm page proxy through here too.
|
||||
"order_items", "pbc_2456927940",
|
||||
// Orders — the `order_attachements` file field on the orders
|
||||
// collection. The orders review modal proxies PDF/image previews
|
||||
// through here (each file is keyed by the order's own record id).
|
||||
// Added 2026-07-29 when the review modal's attachment source moved
|
||||
// from `quote_attachments` to the order-level field.
|
||||
"orders", "pbc_3527180448",
|
||||
// Stock purchases — stock-PO PDFs (rendered into
|
||||
// `stock_purchases.documents`) and any other attachments the
|
||||
// operator uploads to a stock PO route through here. Added
|
||||
|
|
|
|||
Loading…
Reference in a new issue