manufacturing stabilization

This commit is contained in:
2026-03-15 11:30:10 -05:00
parent 0596970b99
commit e2254d020e
15 changed files with 492 additions and 60 deletions

View File

@@ -6,6 +6,7 @@ import { useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { useAuth } from "../../auth/AuthProvider";
import { FileAttachmentsPanel } from "../../components/FileAttachmentsPanel";
import { api, ApiError } from "../../lib/api";
import { emptyPurchaseReceiptInput, purchaseStatusOptions } from "./config";
import { PurchaseStatusBadge } from "./PurchaseStatusBadge";
@@ -248,7 +249,7 @@ export function PurchaseDetailPage() {
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Vendor</p>
<dl className="mt-5 grid gap-3">
<div><dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Account</dt><dd className="mt-1 text-sm text-text">{activeDocument.vendorName}</dd></div>
<div><dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Account</dt><dd className="mt-1 text-sm text-text"><Link to={`/crm/vendors/${activeDocument.vendorId}`} className="hover:text-brand">{activeDocument.vendorName}</Link></dd></div>
<div><dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Email</dt><dd className="mt-1 text-sm text-text">{activeDocument.vendorEmail}</dd></div>
</dl>
</article>
@@ -422,6 +423,14 @@ export function PurchaseDetailPage() {
)}
</article>
</section>
<FileAttachmentsPanel
ownerType="PURCHASE_ORDER"
ownerId={activeDocument.id}
eyebrow="Supporting Documents"
title="Vendor invoices and backup"
description="Store vendor invoices, acknowledgements, certifications, and supporting procurement documents directly on the purchase order."
emptyMessage="No vendor supporting documents have been uploaded for this purchase order yet."
/>
<div className="rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
</section>
);

View File

@@ -1,6 +1,6 @@
import type { InventoryItemOptionDto, PurchaseLineInput, PurchaseOrderInput, PurchaseVendorOptionDto } from "@mrp/shared";
import { useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import { Link, useNavigate, useParams, useSearchParams } from "react-router-dom";
import { useAuth } from "../../auth/AuthProvider";
import { api, ApiError } from "../../lib/api";
@@ -11,6 +11,8 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
const { token } = useAuth();
const navigate = useNavigate();
const { orderId } = useParams();
const [searchParams] = useSearchParams();
const seededVendorId = searchParams.get("vendorId");
const [form, setForm] = useState<PurchaseOrderInput>(emptyPurchaseOrderInput);
const [status, setStatus] = useState(mode === "create" ? "Create a new purchase order." : "Loading purchase order...");
const [vendors, setVendors] = useState<PurchaseVendorOptionDto[]>([]);
@@ -30,9 +32,18 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
return;
}
api.getPurchaseVendors(token).then(setVendors).catch(() => setVendors([]));
api.getPurchaseVendors(token).then((nextVendors) => {
setVendors(nextVendors);
if (mode === "create" && seededVendorId) {
const seededVendor = nextVendors.find((vendor) => vendor.id === seededVendorId);
if (seededVendor) {
setForm((current: PurchaseOrderInput) => ({ ...current, vendorId: seededVendor.id }));
setVendorSearchTerm(seededVendor.name);
}
}
}).catch(() => setVendors([]));
api.getInventoryItemOptions(token).then((options) => setItemOptions(options.filter((option: InventoryItemOptionDto) => option.isPurchasable))).catch(() => setItemOptions([]));
}, [token]);
}, [mode, seededVendorId, token]);
useEffect(() => {
if (!token || mode !== "edit" || !orderId) {