cleanup
This commit is contained in:
@@ -29,6 +29,8 @@ This file is the running release and change log for CODEXIUM. Keep it updated wh
|
|||||||
- Continued density standardization across CRM detail internals and inventory item editing so secondary cards, timeline/history panels, thumbnail panels, BOM/routing editors, and empty states use the tighter shared surface treatment with less filler copy
|
- Continued density standardization across CRM detail internals and inventory item editing so secondary cards, timeline/history panels, thumbnail panels, BOM/routing editors, and empty states use the tighter shared surface treatment with less filler copy
|
||||||
- Continued density standardization across inventory detail transaction/transfer/reservation surfaces, and fixed item-editor navigation controls so SKU master and cancel actions navigate reliably from the create-item form
|
- Continued density standardization across inventory detail transaction/transfer/reservation surfaces, and fixed item-editor navigation controls so SKU master and cancel actions navigate reliably from the create-item form
|
||||||
- Continued density standardization across sales, purchasing, shipping, and manufacturing editor internals, and standardized form-header cancel actions onto button-driven navigation to avoid in-form route-transition edge cases
|
- Continued density standardization across sales, purchasing, shipping, and manufacturing editor internals, and standardized form-header cancel actions onto button-driven navigation to avoid in-form route-transition edge cases
|
||||||
|
- Continued density standardization across sales, purchasing, shipping, and manufacturing detail internals, including denser KPI strips, tighter side panels, shorter empty states, and less redundant context copy on high-traffic record views
|
||||||
|
- Continued density standardization across shared attachment and revision-comparison surfaces, and changed inventory item-editor exit actions to hard navigation so SKU master and cancel transitions no longer depend on client-side router state
|
||||||
- Project-side milestone and work-order rollups surfaced on project list and detail pages
|
- Project-side milestone and work-order rollups surfaced on project list and detail pages
|
||||||
- Inventory SKU master builder with family-level sequence codes, branch-aware taxonomy management, and generated SKU previews on the item form
|
- Inventory SKU master builder with family-level sequence codes, branch-aware taxonomy management, and generated SKU previews on the item form
|
||||||
- Thumbnail image attachment staging on inventory item create/edit pages, with upload-on-save and replacement/removal support
|
- Thumbnail image attachment staging on inventory item create/edit pages, with upload-on-save and replacement/removal support
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ function buildFieldChanges(left: ComparisonField[], right: ComparisonField[]): A
|
|||||||
|
|
||||||
function ComparisonCard({ label, document }: { label: string; document: ComparisonDocument }) {
|
function ComparisonCard({ label, document }: { label: string; document: ComparisonDocument }) {
|
||||||
return (
|
return (
|
||||||
<article className="rounded-[18px] border border-line/70 bg-page/60 p-4">
|
<article className="rounded-[18px] border border-line/70 bg-page/60 px-3 py-3">
|
||||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">{label}</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">{label}</p>
|
||||||
@@ -111,7 +111,7 @@ function ComparisonCard({ label, document }: { label: string; document: Comparis
|
|||||||
{document.status}
|
{document.status}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<dl className="mt-4 grid gap-3 sm:grid-cols-2">
|
<dl className="mt-3 grid gap-2 sm:grid-cols-2">
|
||||||
{document.metaFields.map((field) => (
|
{document.metaFields.map((field) => (
|
||||||
<div key={`${label}-${field.label}`}>
|
<div key={`${label}-${field.label}`}>
|
||||||
<dt className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{field.label}</dt>
|
<dt className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{field.label}</dt>
|
||||||
@@ -119,15 +119,15 @@ function ComparisonCard({ label, document }: { label: string; document: Comparis
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</dl>
|
</dl>
|
||||||
<div className="mt-4 grid gap-3 sm:grid-cols-2">
|
<div className="mt-3 grid gap-2 sm:grid-cols-2">
|
||||||
{document.totalFields.map((field) => (
|
{document.totalFields.map((field) => (
|
||||||
<div key={`${label}-total-${field.label}`} className="rounded-[16px] border border-line/70 bg-surface/80 px-3 py-3">
|
<div key={`${label}-total-${field.label}`} className="rounded-[16px] border border-line/70 bg-surface/80 px-2 py-2">
|
||||||
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{field.label}</div>
|
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{field.label}</div>
|
||||||
<div className="mt-1 text-sm font-semibold text-text">{field.value}</div>
|
<div className="mt-1 text-sm font-semibold text-text">{field.value}</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4">
|
<div className="mt-3">
|
||||||
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">Notes</div>
|
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">Notes</div>
|
||||||
<p className="mt-2 whitespace-pre-line text-sm leading-6 text-text">{document.notes || "No notes recorded."}</p>
|
<p className="mt-2 whitespace-pre-line text-sm leading-6 text-text">{document.notes || "No notes recorded."}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -164,11 +164,11 @@ export function DocumentRevisionComparison({
|
|||||||
const totalChanges = buildFieldChanges(leftDocument.totalFields, rightDocument.totalFields);
|
const totalChanges = buildFieldChanges(leftDocument.totalFields, rightDocument.totalFields);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="surface-panel">
|
||||||
<div className="flex flex-col gap-3 xl:flex-row xl:items-start xl:justify-between">
|
<div className="flex flex-col gap-3 xl:flex-row xl:items-start xl:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">{title}</p>
|
<p className="section-kicker">{title}</p>
|
||||||
<p className="mt-2 text-sm text-muted">{description}</p>
|
<p className="mt-1 text-sm text-muted">{description}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-3 sm:grid-cols-2">
|
<div className="grid gap-3 sm:grid-cols-2">
|
||||||
<label className="block min-w-[220px]">
|
<label className="block min-w-[220px]">
|
||||||
@@ -202,19 +202,19 @@ export function DocumentRevisionComparison({
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 grid gap-3 xl:grid-cols-2">
|
<div className="mt-3 grid gap-3 xl:grid-cols-2">
|
||||||
<ComparisonCard label="Baseline" document={leftDocument} />
|
<ComparisonCard label="Baseline" document={leftDocument} />
|
||||||
<ComparisonCard label="Compare To" document={rightDocument} />
|
<ComparisonCard label="Compare To" document={rightDocument} />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 grid gap-3 xl:grid-cols-2">
|
<div className="mt-3 grid gap-3 xl:grid-cols-2">
|
||||||
<article className="rounded-[18px] border border-line/70 bg-page/60 p-4">
|
<article className="rounded-[18px] border border-line/70 bg-page/60 px-3 py-3">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Field Changes</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Field Changes</p>
|
||||||
{metaChanges.length === 0 && totalChanges.length === 0 ? (
|
{metaChanges.length === 0 && totalChanges.length === 0 ? (
|
||||||
<div className="mt-4 text-sm text-muted">No header or total changes between the selected revisions.</div>
|
<div className="mt-3 text-sm text-muted">No header or total changes.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-4 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{[...metaChanges, ...totalChanges].map((change) => (
|
{[...metaChanges, ...totalChanges].map((change) => (
|
||||||
<div key={change.label} className="rounded-[16px] border border-line/70 bg-surface/80 px-3 py-3">
|
<div key={change.label} className="rounded-[16px] border border-line/70 bg-surface/80 px-2 py-2">
|
||||||
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{change.label}</div>
|
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{change.label}</div>
|
||||||
<div className="mt-2 text-sm text-text">
|
<div className="mt-2 text-sm text-text">
|
||||||
{change.leftValue} {"->"} {change.rightValue}
|
{change.leftValue} {"->"} {change.rightValue}
|
||||||
@@ -224,28 +224,28 @@ export function DocumentRevisionComparison({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-page/60 p-4">
|
<article className="rounded-[18px] border border-line/70 bg-page/60 px-3 py-3">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Line Changes</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Line Changes</p>
|
||||||
<div className="mt-4 grid gap-3 sm:grid-cols-3">
|
<div className="mt-3 grid gap-2 sm:grid-cols-3">
|
||||||
<div className="rounded-[16px] border border-line/70 bg-surface/80 px-3 py-3">
|
<div className="rounded-[16px] border border-line/70 bg-surface/80 px-2 py-2">
|
||||||
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">Added</div>
|
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">Added</div>
|
||||||
<div className="mt-1 text-base font-bold text-text">{diffRows.filter((row) => row.status === "ADDED").length}</div>
|
<div className="mt-1 text-base font-bold text-text">{diffRows.filter((row) => row.status === "ADDED").length}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-[16px] border border-line/70 bg-surface/80 px-3 py-3">
|
<div className="rounded-[16px] border border-line/70 bg-surface/80 px-2 py-2">
|
||||||
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">Removed</div>
|
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">Removed</div>
|
||||||
<div className="mt-1 text-base font-bold text-text">{diffRows.filter((row) => row.status === "REMOVED").length}</div>
|
<div className="mt-1 text-base font-bold text-text">{diffRows.filter((row) => row.status === "REMOVED").length}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-[16px] border border-line/70 bg-surface/80 px-3 py-3">
|
<div className="rounded-[16px] border border-line/70 bg-surface/80 px-2 py-2">
|
||||||
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">Changed</div>
|
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">Changed</div>
|
||||||
<div className="mt-1 text-base font-bold text-text">{diffRows.filter((row) => row.status === "CHANGED").length}</div>
|
<div className="mt-1 text-base font-bold text-text">{diffRows.filter((row) => row.status === "CHANGED").length}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{diffRows.length === 0 ? (
|
{diffRows.length === 0 ? (
|
||||||
<div className="mt-4 text-sm text-muted">No line-level changes between the selected revisions.</div>
|
<div className="mt-3 text-sm text-muted">No line-level changes.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-4 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{diffRows.map((row) => (
|
{diffRows.map((row) => (
|
||||||
<div key={row.key} className="rounded-[16px] border border-line/70 bg-surface/80 px-3 py-3">
|
<div key={row.key} className="rounded-[16px] border border-line/70 bg-surface/80 px-2 py-2">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
<div className="text-sm font-semibold text-text">{row.right?.title ?? row.left?.title}</div>
|
<div className="text-sm font-semibold text-text">{row.right?.title ?? row.left?.title}</div>
|
||||||
<span className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{row.status}</span>
|
<span className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{row.status}</span>
|
||||||
|
|||||||
@@ -133,12 +133,12 @@ export function FileAttachmentsPanel({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article className="min-w-0 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="surface-panel min-w-0">
|
||||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">{eyebrow}</p>
|
<p className="section-kicker">{eyebrow}</p>
|
||||||
<h4 className="mt-2 text-lg font-bold text-text">{title}</h4>
|
<h4 className="text-lg font-bold text-text">{title}</h4>
|
||||||
<p className="mt-2 text-sm text-muted">{description}</p>
|
<p className="mt-1 text-sm text-muted">{description}</p>
|
||||||
</div>
|
</div>
|
||||||
{canWriteFiles ? (
|
{canWriteFiles ? (
|
||||||
<label className="inline-flex cursor-pointer items-center justify-center rounded-2xl bg-brand px-2 py-2 text-sm font-semibold text-white">
|
<label className="inline-flex cursor-pointer items-center justify-center rounded-2xl bg-brand px-2 py-2 text-sm font-semibold text-white">
|
||||||
@@ -147,17 +147,17 @@ export function FileAttachmentsPanel({
|
|||||||
</label>
|
</label>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 text-sm text-muted">{status}</div>
|
<div className="mt-3 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 text-sm text-muted">{status}</div>
|
||||||
{!canReadFiles ? (
|
{!canReadFiles ? (
|
||||||
<div className="mt-5 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">
|
||||||
You do not have permission to view file attachments.
|
You do not have permission to view file attachments.
|
||||||
</div>
|
</div>
|
||||||
) : attachments.length === 0 ? (
|
) : attachments.length === 0 ? (
|
||||||
<div className="mt-5 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">
|
||||||
{emptyMessage}
|
{emptyMessage}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{attachments.map((attachment) => (
|
{attachments.map((attachment) => (
|
||||||
<div
|
<div
|
||||||
key={attachment.id}
|
key={attachment.id}
|
||||||
@@ -166,7 +166,7 @@ export function FileAttachmentsPanel({
|
|||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="truncate text-sm font-semibold text-text">{attachment.originalName}</p>
|
<p className="truncate text-sm font-semibold text-text">{attachment.originalName}</p>
|
||||||
<p className="mt-1 text-xs text-muted">
|
<p className="mt-1 text-xs text-muted">
|
||||||
{attachment.mimeType} · {formatFileSize(attachment.sizeBytes)} · {new Date(attachment.createdAt).toLocaleString()}
|
{attachment.mimeType} - {formatFileSize(attachment.sizeBytes)} - {new Date(attachment.createdAt).toLocaleString()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex shrink-0 gap-3">
|
<div className="flex shrink-0 gap-3">
|
||||||
|
|||||||
@@ -444,12 +444,16 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function forceNavigate(path: string) {
|
||||||
|
window.location.assign(path);
|
||||||
|
}
|
||||||
|
|
||||||
function openSkuMaster() {
|
function openSkuMaster() {
|
||||||
navigate("/inventory/sku-master");
|
forceNavigate("/inventory/sku-master");
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeEditor() {
|
function closeEditor() {
|
||||||
navigate(mode === "create" ? "/inventory/items" : `/inventory/items/${itemId}`);
|
forceNavigate(mode === "create" ? "/inventory/items" : `/inventory/items/${itemId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -431,8 +431,8 @@ export function WorkOrderDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="grid gap-3 xl:grid-cols-6">
|
<section className="grid gap-2 xl:grid-cols-6">
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Planned</p><div className="mt-2 text-base font-bold text-text">{workOrder.quantity}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Planned</p><div className="mt-2 text-base font-bold text-text">{workOrder.quantity}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Completed</p><div className="mt-2 text-base font-bold text-text">{workOrder.completedQuantity}</div></article>
|
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Completed</p><div className="mt-2 text-base font-bold text-text">{workOrder.completedQuantity}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Remaining</p><div className="mt-2 text-base font-bold text-text">{workOrder.dueQuantity}</div></article>
|
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Remaining</p><div className="mt-2 text-base font-bold text-text">{workOrder.dueQuantity}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Project</p><div className="mt-2 text-base font-bold text-text">{workOrder.projectNumber || "Unlinked"}</div></article>
|
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Project</p><div className="mt-2 text-base font-bold text-text">{workOrder.projectNumber || "Unlinked"}</div></article>
|
||||||
|
|||||||
@@ -341,19 +341,19 @@ export function PurchaseDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-2 xl:grid-cols-4">
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Issue Date</p><div className="mt-2 text-base font-bold text-text">{new Date(activeDocument.issueDate).toLocaleDateString()}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Issue Date</p><div className="mt-2 text-base font-bold text-text">{new Date(activeDocument.issueDate).toLocaleDateString()}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Lines</p><div className="mt-2 text-base font-bold text-text">{activeDocument.lineCount}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Lines</p><div className="mt-2 text-base font-bold text-text">{activeDocument.lineCount}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Receipts</p><div className="mt-2 text-base font-bold text-text">{activeDocument.receipts.length}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Receipts</p><div className="mt-2 text-base font-bold text-text">{activeDocument.receipts.length}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Qty Remaining</p><div className="mt-2 text-base font-bold text-text">{activeDocument.lines.reduce((sum, line) => sum + line.remainingQuantity, 0)}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Qty Remaining</p><div className="mt-2 text-base font-bold text-text">{activeDocument.lines.reduce((sum, line) => sum + line.remainingQuantity, 0)}</div></article>
|
||||||
</section>
|
</section>
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-2 xl:grid-cols-4">
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Subtotal</p><div className="mt-2 text-base font-bold text-text">${activeDocument.subtotal.toFixed(2)}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Subtotal</p><div className="mt-2 text-base font-bold text-text">${activeDocument.subtotal.toFixed(2)}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Total</p><div className="mt-2 text-base font-bold text-text">${activeDocument.total.toFixed(2)}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Total</p><div className="mt-2 text-base font-bold text-text">${activeDocument.total.toFixed(2)}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Tax</p><div className="mt-2 text-base font-bold text-text">${activeDocument.taxAmount.toFixed(2)}</div><div className="mt-1 text-xs text-muted">{activeDocument.taxPercent.toFixed(2)}%</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Tax</p><div className="mt-2 text-base font-bold text-text">${activeDocument.taxAmount.toFixed(2)}</div><div className="mt-1 text-xs text-muted">{activeDocument.taxPercent.toFixed(2)}%</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Freight</p><div className="mt-2 text-base font-bold text-text">${activeDocument.freightAmount.toFixed(2)}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Freight</p><div className="mt-2 text-base font-bold text-text">${activeDocument.freightAmount.toFixed(2)}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Payment Terms</p><div className="mt-2 text-base font-bold text-text">{activeDocument.paymentTerms || "N/A"}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Payment Terms</p><div className="mt-2 text-base font-bold text-text">{activeDocument.paymentTerms || "N/A"}</div></article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Currency</p><div className="mt-2 text-base font-bold text-text">{activeDocument.currencyCode || "USD"}</div></article>
|
<article className="surface-panel-tight"><p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Currency</p><div className="mt-2 text-base font-bold text-text">{activeDocument.currencyCode || "USD"}</div></article>
|
||||||
</section>
|
</section>
|
||||||
<section className="surface-panel">
|
<section className="surface-panel">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
@@ -362,11 +362,11 @@ export function PurchaseDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{activeDocument.revisions.length === 0 ? (
|
{activeDocument.revisions.length === 0 ? (
|
||||||
<div className="mt-6 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">
|
||||||
No revisions have been recorded yet.
|
No revisions recorded yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{activeDocument.revisions.map((revision) => (
|
{activeDocument.revisions.map((revision) => (
|
||||||
<article key={revision.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
<article key={revision.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||||
@@ -417,37 +417,37 @@ export function PurchaseDetailPage() {
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.05fr)_minmax(320px,0.95fr)]">
|
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.05fr)_minmax(320px,0.95fr)]">
|
||||||
<article className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="surface-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Vendor</p>
|
<p className="section-kicker">VENDOR</p>
|
||||||
<dl className="mt-5 grid gap-3">
|
<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"><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">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>
|
<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>
|
</dl>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="surface-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Project Link</p>
|
<p className="section-kicker">PROJECT LINK</p>
|
||||||
{activeDocument.projectId ? (
|
{activeDocument.projectId ? (
|
||||||
<div className="mt-3 space-y-2">
|
<div className="mt-3 space-y-2">
|
||||||
<Link to={`/projects/${activeDocument.projectId}`} className="inline-flex items-center rounded-2xl border border-line/70 px-3 py-2 text-sm font-semibold text-text hover:bg-page/70">
|
<Link to={`/projects/${activeDocument.projectId}`} className="inline-flex items-center rounded-2xl border border-line/70 px-3 py-2 text-sm font-semibold text-text hover:bg-page/70">
|
||||||
{activeDocument.projectNumber} / {activeDocument.projectName}
|
{activeDocument.projectNumber} / {activeDocument.projectName}
|
||||||
</Link>
|
</Link>
|
||||||
<p className="text-sm text-muted">This purchase order is linked to the project context used by project cockpit and downstream rollups.</p>
|
<p className="text-sm text-muted">Project cockpit and rollups use this linkage.</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="mt-3 text-sm text-muted">No linked project is currently attached to this purchase order.</p>
|
<p className="mt-3 text-sm text-muted">No linked project.</p>
|
||||||
)}
|
)}
|
||||||
<p className="mt-5 text-xs font-semibold uppercase tracking-[0.24em] text-muted">Notes</p>
|
<p className="mt-4 text-xs font-semibold uppercase tracking-[0.24em] text-muted">Notes</p>
|
||||||
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{activeDocument.notes || "No notes recorded for this document."}</p>
|
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{activeDocument.notes || "No notes recorded for this document."}</p>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="surface-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Demand Context</p>
|
<p className="section-kicker">DEMAND CONTEXT</p>
|
||||||
{demandContextItems.length === 0 ? (
|
{demandContextItems.length === 0 ? (
|
||||||
<div className="mt-6 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">
|
||||||
No active shared shortage or buy-signal records currently point at items on this purchase order.
|
No active shortage or buy-signal context for these items.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{demandContextItems.map((item) => (
|
{demandContextItems.map((item) => (
|
||||||
<div key={item.itemId} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
<div key={item.itemId} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
@@ -464,12 +464,12 @@ export function PurchaseDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="surface-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Line Items</p>
|
<p className="section-kicker">LINE ITEMS</p>
|
||||||
{activeDocument.lines.length === 0 ? (
|
{activeDocument.lines.length === 0 ? (
|
||||||
<div className="mt-6 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No line items have been added yet.</div>
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">No line items added yet.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 overflow-hidden rounded-2xl border border-line/70">
|
<div className="mt-3 overflow-hidden rounded-2xl border border-line/70">
|
||||||
<table className="min-w-full divide-y divide-line/70 text-sm">
|
<table className="min-w-full divide-y divide-line/70 text-sm">
|
||||||
<thead className="bg-page/80 text-left text-muted">
|
<thead className="bg-page/80 text-left text-muted">
|
||||||
<tr><th className="px-2 py-2">Item</th><th className="px-2 py-2">Description</th><th className="px-2 py-2">Demand Source</th><th className="px-2 py-2">Ordered</th><th className="px-2 py-2">Received</th><th className="px-2 py-2">Remaining</th><th className="px-2 py-2">UOM</th><th className="px-2 py-2">Unit Cost</th><th className="px-2 py-2">Total</th></tr>
|
<tr><th className="px-2 py-2">Item</th><th className="px-2 py-2">Description</th><th className="px-2 py-2">Demand Source</th><th className="px-2 py-2">Ordered</th><th className="px-2 py-2">Received</th><th className="px-2 py-2">Remaining</th><th className="px-2 py-2">UOM</th><th className="px-2 py-2">Unit Cost</th><th className="px-2 py-2">Total</th></tr>
|
||||||
@@ -504,7 +504,7 @@ export function PurchaseDetailPage() {
|
|||||||
All ordered quantities have been received for this purchase order.
|
All ordered quantities have been received for this purchase order.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<form className="mt-5 space-y-4" onSubmit={handleReceiptSubmit}>
|
<form className="mt-3 space-y-3" onSubmit={handleReceiptSubmit}>
|
||||||
<div className="grid gap-3 xl:grid-cols-2">
|
<div className="grid gap-3 xl:grid-cols-2">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Receipt date</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Receipt date</span>
|
||||||
@@ -576,7 +576,7 @@ export function PurchaseDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-3 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 sm:flex-row sm:items-center sm:justify-between">
|
<div className="flex flex-col gap-2 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<span className="min-w-0 text-sm text-muted">{receiptStatus}</span>
|
<span className="min-w-0 text-sm text-muted">{receiptStatus}</span>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -593,11 +593,11 @@ export function PurchaseDetailPage() {
|
|||||||
<article className="surface-panel">
|
<article className="surface-panel">
|
||||||
<p className="section-kicker">RECEIPT HISTORY</p>
|
<p className="section-kicker">RECEIPT HISTORY</p>
|
||||||
{activeDocument.receipts.length === 0 ? (
|
{activeDocument.receipts.length === 0 ? (
|
||||||
<div className="mt-6 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">
|
||||||
No purchase receipts have been recorded for this order yet.
|
No purchase receipts recorded yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{activeDocument.receipts.map((receipt) => (
|
{activeDocument.receipts.map((receipt) => (
|
||||||
<article key={receipt.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
<article key={receipt.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="page-stack">
|
||||||
<div className="surface-panel">
|
<div className="surface-panel">
|
||||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
@@ -417,41 +417,41 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-2 xl:grid-cols-4">
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Issue Date</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Issue Date</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{new Date(activeDocument.issueDate).toLocaleDateString()}</div>
|
<div className="mt-2 text-base font-bold text-text">{new Date(activeDocument.issueDate).toLocaleDateString()}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Expires</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Expires</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{activeDocument.expiresAt ? new Date(activeDocument.expiresAt).toLocaleDateString() : "N/A"}</div>
|
<div className="mt-2 text-base font-bold text-text">{activeDocument.expiresAt ? new Date(activeDocument.expiresAt).toLocaleDateString() : "N/A"}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Lines</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Lines</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{activeDocument.lineCount}</div>
|
<div className="mt-2 text-base font-bold text-text">{activeDocument.lineCount}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Approval</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Approval</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{activeDocument.approvedAt ? new Date(activeDocument.approvedAt).toLocaleDateString() : "Pending"}</div>
|
<div className="mt-2 text-base font-bold text-text">{activeDocument.approvedAt ? new Date(activeDocument.approvedAt).toLocaleDateString() : "Pending"}</div>
|
||||||
<div className="mt-1 text-xs text-muted">{activeDocument.approvedByName ?? "No approver recorded"}</div>
|
<div className="mt-1 text-xs text-muted">{activeDocument.approvedByName ?? "No approver recorded"}</div>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-2 xl:grid-cols-4">
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Discount</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Discount</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">-${activeDocument.discountAmount.toFixed(2)}</div>
|
<div className="mt-2 text-base font-bold text-text">-${activeDocument.discountAmount.toFixed(2)}</div>
|
||||||
<div className="mt-1 text-xs text-muted">{activeDocument.discountPercent.toFixed(2)}%</div>
|
<div className="mt-1 text-xs text-muted">{activeDocument.discountPercent.toFixed(2)}%</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Tax</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Tax</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">${activeDocument.taxAmount.toFixed(2)}</div>
|
<div className="mt-2 text-base font-bold text-text">${activeDocument.taxAmount.toFixed(2)}</div>
|
||||||
<div className="mt-1 text-xs text-muted">{activeDocument.taxPercent.toFixed(2)}%</div>
|
<div className="mt-1 text-xs text-muted">{activeDocument.taxPercent.toFixed(2)}%</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Freight</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Freight</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">${activeDocument.freightAmount.toFixed(2)}</div>
|
<div className="mt-2 text-base font-bold text-text">${activeDocument.freightAmount.toFixed(2)}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Total</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Total</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">${activeDocument.total.toFixed(2)}</div>
|
<div className="mt-2 text-base font-bold text-text">${activeDocument.total.toFixed(2)}</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -463,11 +463,11 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{activeDocument.revisions.length === 0 ? (
|
{activeDocument.revisions.length === 0 ? (
|
||||||
<div className="mt-6 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">
|
||||||
No revisions have been recorded yet.
|
No revisions recorded yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{activeDocument.revisions.map((revision) => (
|
{activeDocument.revisions.map((revision) => (
|
||||||
<article key={revision.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
<article key={revision.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||||
@@ -517,8 +517,8 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.05fr)_minmax(320px,0.95fr)]">
|
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.05fr)_minmax(320px,0.95fr)]">
|
||||||
<article className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="surface-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Customer</p>
|
<p className="section-kicker">CUSTOMER</p>
|
||||||
<dl className="mt-5 grid gap-3">
|
<dl className="mt-5 grid gap-3">
|
||||||
<div>
|
<div>
|
||||||
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Account</dt>
|
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Account</dt>
|
||||||
@@ -530,30 +530,30 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="surface-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Project Link</p>
|
<p className="section-kicker">PROJECT LINK</p>
|
||||||
{activeDocument.linkedProjectId ? (
|
{activeDocument.linkedProjectId ? (
|
||||||
<div className="mt-3 space-y-2">
|
<div className="mt-3 space-y-2">
|
||||||
<Link to={`/projects/${activeDocument.linkedProjectId}`} className="inline-flex items-center rounded-2xl border border-line/70 px-3 py-2 text-sm font-semibold text-text hover:bg-page/70">
|
<Link to={`/projects/${activeDocument.linkedProjectId}`} className="inline-flex items-center rounded-2xl border border-line/70 px-3 py-2 text-sm font-semibold text-text hover:bg-page/70">
|
||||||
{activeDocument.linkedProjectNumber} / {activeDocument.linkedProjectName}
|
{activeDocument.linkedProjectNumber} / {activeDocument.linkedProjectName}
|
||||||
</Link>
|
</Link>
|
||||||
<p className="text-sm text-muted">This {entity === "quote" ? "quote" : "sales order"} is already linked to a project, and downstream WO/PO launches will carry that project context.</p>
|
<p className="text-sm text-muted">Downstream WO and PO launches carry this project context.</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="mt-3 text-sm text-muted">No linked project is currently attached to this {entity === "quote" ? "quote" : "sales order"}.</p>
|
<p className="mt-3 text-sm text-muted">No linked project.</p>
|
||||||
)}
|
)}
|
||||||
<p className="mt-5 text-xs font-semibold uppercase tracking-[0.24em] text-muted">Notes</p>
|
<p className="mt-4 text-xs font-semibold uppercase tracking-[0.24em] text-muted">Notes</p>
|
||||||
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{activeDocument.notes || "No notes recorded for this document."}</p>
|
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{activeDocument.notes || "No notes recorded for this document."}</p>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="surface-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Line Items</p>
|
<p className="section-kicker">LINE ITEMS</p>
|
||||||
{activeDocument.lines.length === 0 ? (
|
{activeDocument.lines.length === 0 ? (
|
||||||
<div className="mt-6 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">
|
||||||
No line items have been added yet.
|
No line items added yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 overflow-hidden rounded-2xl border border-line/70">
|
<div className="mt-3 overflow-hidden rounded-2xl border border-line/70">
|
||||||
<table className="min-w-full divide-y divide-line/70 text-sm">
|
<table className="min-w-full divide-y divide-line/70 text-sm">
|
||||||
<thead className="bg-page/80 text-left text-muted">
|
<thead className="bg-page/80 text-left text-muted">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -595,23 +595,23 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
<div>Status {planning.status}</div>
|
<div>Status {planning.status}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 grid gap-3 xl:grid-cols-4">
|
<div className="mt-4 grid gap-2 xl:grid-cols-4">
|
||||||
<article className="rounded-[18px] border border-line/70 bg-page/70 px-3 py-3">
|
<article className="surface-panel-tight bg-page/70 shadow-none">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Build Recommendations</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Build Recommendations</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{planning.summary.totalBuildQuantity}</div>
|
<div className="mt-2 text-base font-bold text-text">{planning.summary.totalBuildQuantity}</div>
|
||||||
<div className="mt-1 text-xs text-muted">{planning.summary.buildRecommendationCount} items</div>
|
<div className="mt-1 text-xs text-muted">{planning.summary.buildRecommendationCount} items</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-page/70 px-3 py-3">
|
<article className="surface-panel-tight bg-page/70 shadow-none">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Purchase Recommendations</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Purchase Recommendations</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{planning.summary.totalPurchaseQuantity}</div>
|
<div className="mt-2 text-base font-bold text-text">{planning.summary.totalPurchaseQuantity}</div>
|
||||||
<div className="mt-1 text-xs text-muted">{planning.summary.purchaseRecommendationCount} items</div>
|
<div className="mt-1 text-xs text-muted">{planning.summary.purchaseRecommendationCount} items</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-page/70 px-3 py-3">
|
<article className="surface-panel-tight bg-page/70 shadow-none">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Uncovered</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Uncovered</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{planning.summary.totalUncoveredQuantity}</div>
|
<div className="mt-2 text-base font-bold text-text">{planning.summary.totalUncoveredQuantity}</div>
|
||||||
<div className="mt-1 text-xs text-muted">{planning.summary.uncoveredItemCount} items</div>
|
<div className="mt-1 text-xs text-muted">{planning.summary.uncoveredItemCount} items</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-page/70 px-3 py-3">
|
<article className="surface-panel-tight bg-page/70 shadow-none">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Planned Items</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Planned Items</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{planning.summary.itemCount}</div>
|
<div className="mt-2 text-base font-bold text-text">{planning.summary.itemCount}</div>
|
||||||
<div className="mt-1 text-xs text-muted">{planning.summary.lineCount} sales lines</div>
|
<div className="mt-1 text-xs text-muted">{planning.summary.lineCount} sales lines</div>
|
||||||
@@ -682,7 +682,7 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-4 space-y-2">
|
||||||
{planning.lines.map((line) => (
|
{planning.lines.map((line) => (
|
||||||
<div key={line.lineId} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
<div key={line.lineId} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
@@ -712,11 +712,11 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{shipments.length === 0 ? (
|
{shipments.length === 0 ? (
|
||||||
<div className="mt-6 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">
|
||||||
No shipments have been created for this sales order yet.
|
No shipments created yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{shipments.map((shipment) => (
|
{shipments.map((shipment) => (
|
||||||
<Link key={shipment.id} to={`/shipping/shipments/${shipment.id}`} className="block rounded-[18px] border border-line/70 bg-page/60 p-3 transition hover:bg-page/80">
|
<Link key={shipment.id} to={`/shipping/shipments/${shipment.id}`} className="block rounded-[18px] border border-line/70 bg-page/60 p-3 transition hover:bg-page/80">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
|
|||||||
@@ -265,20 +265,20 @@ export function ShipmentDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-2 xl:grid-cols-4">
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Carrier</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Carrier</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{shipment.carrier || "Not set"}</div>
|
<div className="mt-2 text-base font-bold text-text">{shipment.carrier || "Not set"}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Ordered Units</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Ordered Units</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{totalOrderedQuantity}</div>
|
<div className="mt-2 text-base font-bold text-text">{totalOrderedQuantity}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Picked Units</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Picked Units</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{totalPickedQuantity}</div>
|
<div className="mt-2 text-base font-bold text-text">{totalPickedQuantity}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[18px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<article className="surface-panel-tight">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Packages</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Packages</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{shipment.packageCount}</div>
|
<div className="mt-2 text-base font-bold text-text">{shipment.packageCount}</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -324,8 +324,8 @@ export function ShipmentDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="surface-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Timing</p>
|
<p className="section-kicker">TIMING</p>
|
||||||
<dl className="mt-5 grid gap-3">
|
<dl className="mt-5 grid gap-3">
|
||||||
<div>
|
<div>
|
||||||
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Ship Date</dt>
|
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Ship Date</dt>
|
||||||
@@ -353,8 +353,8 @@ export function ShipmentDetailPage() {
|
|||||||
<div>
|
<div>
|
||||||
<p className="section-kicker">PICK AND ISSUE FROM STOCK</p>
|
<p className="section-kicker">PICK AND ISSUE FROM STOCK</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-[16px] border border-line/70 bg-page/60 px-3 py-2 text-xs text-muted">
|
<div className="rounded-[16px] border border-line/70 bg-page/60 px-2 py-2 text-xs text-muted">
|
||||||
Select the sales-order line, source location, and quantity you are physically picking.
|
Select line, location, and quantity.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 grid gap-3 md:grid-cols-2 xl:grid-cols-5">
|
<div className="mt-5 grid gap-3 md:grid-cols-2 xl:grid-cols-5">
|
||||||
@@ -470,11 +470,11 @@ export function ShipmentDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{shipment.picks.length === 0 ? (
|
{shipment.picks.length === 0 ? (
|
||||||
<div className="mt-6 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">
|
||||||
No shipment picks have been posted yet.
|
No shipment picks posted yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{shipment.picks.map((pick) => (
|
{shipment.picks.map((pick) => (
|
||||||
<div key={pick.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
<div key={pick.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||||
@@ -496,8 +496,8 @@ export function ShipmentDetailPage() {
|
|||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="surface-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Shipment Notes</p>
|
<p className="section-kicker">SHIPMENT NOTES</p>
|
||||||
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{shipment.notes || "No notes recorded for this shipment."}</p>
|
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{shipment.notes || "No notes recorded for this shipment."}</p>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
@@ -512,9 +512,9 @@ export function ShipmentDetailPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{relatedShipments.length === 0 ? (
|
{relatedShipments.length === 0 ? (
|
||||||
<div className="mt-6 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No additional shipments exist for this sales order.</div>
|
<div className="mt-3 rounded-[18px] border border-dashed border-line/70 bg-page/60 px-3 py-5 text-center text-sm text-muted">No additional shipments.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-3 space-y-2">
|
||||||
{relatedShipments.map((related) => (
|
{relatedShipments.map((related) => (
|
||||||
<Link key={related.id} to={`/shipping/shipments/${related.id}`} className="block rounded-[18px] border border-line/70 bg-page/60 p-3 transition hover:bg-page/80">
|
<Link key={related.id} to={`/shipping/shipments/${related.id}`} className="block rounded-[18px] border border-line/70 bg-page/60 p-3 transition hover:bg-page/80">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
|
|||||||
Reference in New Issue
Block a user