From 17586e6ea1d20a0bc2569a70cea069d97cce9829 Mon Sep 17 00:00:00 2001 From: Hardik Date: Sat, 9 May 2026 17:51:54 +0530 Subject: [PATCH] =?UTF-8?q?fix:=20serialize=20Prisma=20Decimal=20fields=20?= =?UTF-8?q?before=20server=E2=86=92client=20boundary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert quantity, unitPrice, totalPrice, gstRate, and totalAmount to plain numbers in server pages before passing to client components, preventing Next.js serialization errors on Decimal objects. Co-Authored-By: Claude Sonnet 4.6 --- .../approvals/[id]/manager-edit-po-form.tsx | 27 ++++++++--- .../app/(portal)/approvals/[id]/page.tsx | 14 +++++- .../(portal)/po/[id]/edit/edit-po-form.tsx | 47 +++++++++++-------- .../app/(portal)/po/[id]/edit/page.tsx | 14 +++++- 4 files changed, 74 insertions(+), 28 deletions(-) diff --git a/App/pelagia-portal/app/(portal)/approvals/[id]/manager-edit-po-form.tsx b/App/pelagia-portal/app/(portal)/approvals/[id]/manager-edit-po-form.tsx index 4ac5de6..75a7c30 100644 --- a/App/pelagia-portal/app/(portal)/approvals/[id]/manager-edit-po-form.tsx +++ b/App/pelagia-portal/app/(portal)/approvals/[id]/manager-edit-po-form.tsx @@ -6,10 +6,25 @@ import { managerEditPo } from "./manager-po-edit-actions"; import { LineItemsEditor } from "@/components/po/po-line-items-editor"; import { TC_DEFAULTS, TC_FIXED_LINE } from "@/lib/validations/po"; import type { LineItemInput } from "@/lib/validations/po"; -import type { Vessel, Account, Vendor, PurchaseOrder, POLineItem } from "@prisma/client"; +import type { Vessel, Account, Vendor, PurchaseOrder } from "@prisma/client"; -type PoFull = PurchaseOrder & { - lineItems: POLineItem[]; +type SerializedLineItem = { + id: string; + poId: string; + description: string; + quantity: number; + unit: string; + size: string | null; + unitPrice: number; + totalPrice: number; + gstRate: number; + sortOrder: number; + productId: string | null; +}; + +type PoFull = Omit & { + totalAmount: number; + lineItems: SerializedLineItem[]; vessel: { id: string; name: string }; account: { id: string; name: string; code: string }; vendor: { id: string; name: string; vendorId: string | null } | null; @@ -45,11 +60,11 @@ export function ManagerEditPoForm({ po, vessels, accounts, vendors }: Props) { const [lineItems, setLineItems] = useState( po.lineItems.map((li) => ({ description: li.description, - quantity: Number(li.quantity), + quantity: li.quantity, unit: li.unit, size: li.size ?? undefined, - unitPrice: Number(li.unitPrice), - gstRate: Number((li as POLineItem & { gstRate?: unknown }).gstRate ?? 0.18), + unitPrice: li.unitPrice, + gstRate: li.gstRate, })) ); diff --git a/App/pelagia-portal/app/(portal)/approvals/[id]/page.tsx b/App/pelagia-portal/app/(portal)/approvals/[id]/page.tsx index 3ffd8ea..53dedcc 100644 --- a/App/pelagia-portal/app/(portal)/approvals/[id]/page.tsx +++ b/App/pelagia-portal/app/(portal)/approvals/[id]/page.tsx @@ -43,6 +43,18 @@ export default async function ApprovalDetailPage({ params }: Props) { if (!po) notFound(); if (po.status !== "MGR_REVIEW") redirect(`/po/${id}`); + const serializedPo = { + ...po, + totalAmount: po.totalAmount.toNumber(), + lineItems: po.lineItems.map((li) => ({ + ...li, + quantity: li.quantity.toNumber(), + unitPrice: li.unitPrice.toNumber(), + totalPrice: li.totalPrice.toNumber(), + gstRate: li.gstRate.toNumber(), + })), + }; + return (
@@ -55,7 +67,7 @@ export default async function ApprovalDetailPage({ params }: Props) { & { + totalAmount: number; + lineItems: SerializedLineItem[]; +}; interface Props { po: PoWithItems; @@ -25,11 +42,11 @@ export function EditPoForm({ po, vessels, accounts, vendors }: Props) { const [lineItems, setLineItems] = useState( po.lineItems.map((li) => ({ description: li.description, - quantity: Number(li.quantity), + quantity: li.quantity, unit: li.unit, size: li.size ?? undefined, - unitPrice: Number(li.unitPrice), - gstRate: Number((li as POLineItem & { gstRate: unknown }).gstRate ?? 0.18), + unitPrice: li.unitPrice, + gstRate: li.gstRate, })) ); const [submitting, setSubmitting] = useState<"save" | "resubmit" | null>(null); @@ -64,24 +81,14 @@ export function EditPoForm({ po, vessels, accounts, vendors }: Props) { const dateValue = po.dateRequired ? new Date(po.dateRequired).toISOString().split("T")[0] : ""; - const piDateValue = (po as PurchaseOrder & { piQuotationDate: Date | null }).piQuotationDate - ? new Date((po as PurchaseOrder & { piQuotationDate: Date | null }).piQuotationDate!).toISOString().split("T")[0] + const piDateValue = po.piQuotationDate + ? new Date(po.piQuotationDate).toISOString().split("T")[0] : ""; - const reqDateValue = (po as PurchaseOrder & { requisitionDate: Date | null }).requisitionDate - ? new Date((po as PurchaseOrder & { requisitionDate: Date | null }).requisitionDate!).toISOString().split("T")[0] + const reqDateValue = po.requisitionDate + ? new Date(po.requisitionDate).toISOString().split("T")[0] : ""; - const extPo = po as PurchaseOrder & { - piQuotationNo: string | null; - requisitionNo: string | null; - placeOfDelivery: string | null; - tcDelivery: string | null; - tcDispatch: string | null; - tcInspection: string | null; - tcTransitInsurance: string | null; - tcPaymentTerms: string | null; - tcOthers: string | null; - }; + const extPo = po; return (
e.preventDefault()}> diff --git a/App/pelagia-portal/app/(portal)/po/[id]/edit/page.tsx b/App/pelagia-portal/app/(portal)/po/[id]/edit/page.tsx index 8633e51..f9d7bb9 100644 --- a/App/pelagia-portal/app/(portal)/po/[id]/edit/page.tsx +++ b/App/pelagia-portal/app/(portal)/po/[id]/edit/page.tsx @@ -35,13 +35,25 @@ export default async function EditPoPage({ params }: Props) { db.vendor.findMany({ where: { isActive: true }, orderBy: { name: "asc" } }), ]); + const serializedPo = { + ...po, + totalAmount: po.totalAmount.toNumber(), + lineItems: po.lineItems.map((li) => ({ + ...li, + quantity: li.quantity.toNumber(), + unitPrice: li.unitPrice.toNumber(), + totalPrice: li.totalPrice.toNumber(), + gstRate: li.gstRate.toNumber(), + })), + }; + return (

Edit Purchase Order

{po.poNumber}

- +
); }