no more pills
This commit is contained in:
@@ -52,7 +52,7 @@ export function ConfirmActionDialog({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/55 px-4 py-6">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/55 px-4 py-6">
|
||||||
<div className="w-full max-w-xl rounded-[28px] border border-line/70 bg-surface p-5 shadow-panel">
|
<div className="w-full max-w-xl rounded-[20px] border border-line/70 bg-surface p-5 shadow-panel">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Confirm Action</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Confirm Action</p>
|
||||||
<h3 className="mt-2 text-lg font-bold text-text">{title}</h3>
|
<h3 className="mt-2 text-lg font-bold text-text">{title}</h3>
|
||||||
<p className="mt-3 text-sm leading-6 text-text">{description}</p>
|
<p className="mt-3 text-sm leading-6 text-text">{description}</p>
|
||||||
@@ -105,3 +105,4 @@ export function ConfirmActionDialog({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ export function FileAttachmentsPanel({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article className="min-w-0 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="min-w-0 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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="text-xs font-semibold uppercase tracking-[0.24em] text-muted">{eyebrow}</p>
|
||||||
@@ -149,11 +149,11 @@ export function FileAttachmentsPanel({
|
|||||||
</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-5 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-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
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-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
{emptyMessage}
|
{emptyMessage}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -161,7 +161,7 @@ export function FileAttachmentsPanel({
|
|||||||
{attachments.map((attachment) => (
|
{attachments.map((attachment) => (
|
||||||
<div
|
<div
|
||||||
key={attachment.id}
|
key={attachment.id}
|
||||||
className="flex flex-col gap-2 rounded-3xl border border-line/70 bg-page/60 px-2 py-2 lg:flex-row lg:items-center lg:justify-between"
|
className="flex flex-col gap-2 rounded-[18px] border border-line/70 bg-page/60 px-2 py-2 lg:flex-row lg:items-center lg:justify-between"
|
||||||
>
|
>
|
||||||
<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>
|
||||||
@@ -218,3 +218,4 @@ export function FileAttachmentsPanel({
|
|||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ const GanttPage = React.lazy(() =>
|
|||||||
|
|
||||||
function RouteFallback() {
|
function RouteFallback() {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">
|
||||||
Loading module...
|
Loading module...
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -266,3 +266,4 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
|
|||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -58,17 +58,17 @@ export function CrmContactsPanel({ entity, ownerId, contacts, onContactsChange }
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article className="min-w-0 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="min-w-0 rounded-[20px] 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">Contacts</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Contacts</p>
|
||||||
<h4 className="mt-2 text-lg font-bold text-text">People on this account</h4>
|
<h4 className="mt-2 text-lg font-bold text-text">People on this account</h4>
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-5 space-y-3">
|
||||||
{contacts.length === 0 ? (
|
{contacts.length === 0 ? (
|
||||||
<div className="rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<div className="rounded-[18px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
||||||
No contacts have been added yet.
|
No contacts have been added yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
contacts.map((contact) => (
|
contacts.map((contact) => (
|
||||||
<div key={contact.id} className="rounded-3xl border border-line/70 bg-page/60 px-2 py-2">
|
<div key={contact.id} className="rounded-[18px] border border-line/70 bg-page/60 px-2 py-2">
|
||||||
<div className="flex flex-col gap-2 lg:flex-row lg:items-start lg:justify-between">
|
<div className="flex flex-col gap-2 lg:flex-row lg:items-start lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-semibold text-text">
|
<div className="text-sm font-semibold text-text">
|
||||||
@@ -151,3 +151,4 @@ export function CrmContactsPanel({ entity, ownerId, contacts, onContactsChange }
|
|||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
}, [config.singularLabel, entity, recordId, token]);
|
}, [config.singularLabel, entity, recordId, token]);
|
||||||
|
|
||||||
if (!record) {
|
if (!record) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateContactEntryField<Key extends keyof CrmContactEntryInput>(key: Key, value: CrmContactEntryInput[Key]) {
|
function updateContactEntryField<Key extends keyof CrmContactEntryInput>(key: Key, value: CrmContactEntryInput[Key]) {
|
||||||
@@ -112,7 +112,7 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">CRM Detail</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">CRM Detail</p>
|
||||||
@@ -146,7 +146,7 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-3 2xl:grid-cols-[minmax(0,1.2fr)_minmax(320px,0.8fr)]">
|
<div className="grid gap-3 2xl:grid-cols-[minmax(0,1.2fr)_minmax(320px,0.8fr)]">
|
||||||
<article className="min-w-0 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="min-w-0 rounded-[20px] 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">Contact</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Contact</p>
|
||||||
<dl className="mt-5 grid gap-3 xl:grid-cols-2">
|
<dl className="mt-5 grid gap-3 xl:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
@@ -176,7 +176,7 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</article>
|
</article>
|
||||||
<article className="min-w-0 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="min-w-0 rounded-[20px] 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">Internal Notes</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Internal Notes</p>
|
||||||
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">
|
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">
|
||||||
{record.notes || "No internal notes recorded for this account yet."}
|
{record.notes || "No internal notes recorded for this account yet."}
|
||||||
@@ -219,27 +219,27 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-3 xl:grid-cols-4">
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Last Contact</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Last Contact</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">
|
<div className="mt-2 text-base font-bold text-text">
|
||||||
{record.rollups?.lastContactAt ? new Date(record.rollups.lastContactAt).toLocaleDateString() : "None"}
|
{record.rollups?.lastContactAt ? new Date(record.rollups.lastContactAt).toLocaleDateString() : "None"}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Timeline Entries</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Timeline Entries</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{record.rollups?.contactHistoryCount ?? record.contactHistory.length}</div>
|
<div className="mt-2 text-base font-bold text-text">{record.rollups?.contactHistoryCount ?? record.contactHistory.length}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Account Contacts</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Account Contacts</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{record.rollups?.contactCount ?? record.contacts?.length ?? 0}</div>
|
<div className="mt-2 text-base font-bold text-text">{record.rollups?.contactCount ?? record.contacts?.length ?? 0}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Attachments</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Attachments</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{record.rollups?.attachmentCount ?? 0}</div>
|
<div className="mt-2 text-base font-bold text-text">{record.rollups?.attachmentCount ?? 0}</div>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
{entity === "customer" && (record.childCustomers?.length ?? 0) > 0 ? (
|
{entity === "customer" && (record.childCustomers?.length ?? 0) > 0 ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Hierarchy</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Hierarchy</p>
|
||||||
<h4 className="mt-2 text-lg font-bold text-text">End customers under this reseller</h4>
|
<h4 className="mt-2 text-lg font-bold text-text">End customers under this reseller</h4>
|
||||||
<div className="mt-5 grid gap-3 xl:grid-cols-2 2xl:grid-cols-3">
|
<div className="mt-5 grid gap-3 xl:grid-cols-2 2xl:grid-cols-3">
|
||||||
@@ -247,7 +247,7 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
<Link
|
<Link
|
||||||
key={child.id}
|
key={child.id}
|
||||||
to={`/crm/customers/${child.id}`}
|
to={`/crm/customers/${child.id}`}
|
||||||
className="rounded-3xl border border-line/70 bg-page/60 px-2 py-2 transition hover:border-brand/50 hover:bg-page/80"
|
className="rounded-[18px] border border-line/70 bg-page/60 px-2 py-2 transition hover:border-brand/50 hover:bg-page/80"
|
||||||
>
|
>
|
||||||
<div className="text-sm font-semibold text-text">{child.name}</div>
|
<div className="text-sm font-semibold text-text">{child.name}</div>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
@@ -259,7 +259,7 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
{entity === "vendor" ? (
|
{entity === "vendor" ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Purchasing Activity</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Purchasing Activity</p>
|
||||||
@@ -277,11 +277,11 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{relatedPurchaseOrders.length === 0 ? (
|
{relatedPurchaseOrders.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No purchase orders exist for this vendor yet.</div>
|
<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 purchase orders exist for this vendor yet.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-6 space-y-3">
|
||||||
{relatedPurchaseOrders.slice(0, 8).map((order) => (
|
{relatedPurchaseOrders.slice(0, 8).map((order) => (
|
||||||
<Link key={order.id} to={`/purchasing/orders/${order.id}`} className="block rounded-3xl border border-line/70 bg-page/60 p-3 transition hover:bg-page/80">
|
<Link key={order.id} to={`/purchasing/orders/${order.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">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{order.documentNumber}</div>
|
<div className="font-semibold text-text">{order.documentNumber}</div>
|
||||||
@@ -319,7 +319,7 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
/>
|
/>
|
||||||
<section className="grid gap-3 2xl:grid-cols-[minmax(360px,0.88fr)_minmax(0,1.12fr)]">
|
<section className="grid gap-3 2xl:grid-cols-[minmax(360px,0.88fr)_minmax(0,1.12fr)]">
|
||||||
{canManage ? (
|
{canManage ? (
|
||||||
<article className="min-w-0 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="min-w-0 rounded-[20px] 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">Contact History</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Contact History</p>
|
||||||
<h4 className="mt-2 text-lg font-bold text-text">Add timeline entry</h4>
|
<h4 className="mt-2 text-lg font-bold text-text">Add timeline entry</h4>
|
||||||
<p className="mt-2 text-sm text-muted">
|
<p className="mt-2 text-sm text-muted">
|
||||||
@@ -336,17 +336,17 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
) : null}
|
) : null}
|
||||||
<article className="min-w-0 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="min-w-0 rounded-[20px] 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">Timeline</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Timeline</p>
|
||||||
<h4 className="mt-2 text-lg font-bold text-text">Recent interactions</h4>
|
<h4 className="mt-2 text-lg font-bold text-text">Recent interactions</h4>
|
||||||
{record.contactHistory.length === 0 ? (
|
{record.contactHistory.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 contact history has been recorded for this account yet.
|
No contact history has been recorded for this account yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-6 space-y-3">
|
||||||
{record.contactHistory.map((entry) => (
|
{record.contactHistory.map((entry) => (
|
||||||
<article key={entry.id} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<article key={entry.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">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-wrap items-center gap-3">
|
<div className="flex flex-wrap items-center gap-3">
|
||||||
@@ -389,3 +389,4 @@ export function CrmDetailPage({ entity }: CrmDetailPageProps) {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export function CrmFormPage({ entity, mode }: CrmFormPageProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">CRM Editor</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">CRM Editor</p>
|
||||||
@@ -130,7 +130,7 @@ export function CrmFormPage({ entity, mode }: CrmFormPageProps) {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="space-y-4 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="space-y-4 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<CrmRecordForm entity={entity} form={form} hierarchyOptions={hierarchyOptions} onChange={updateField} />
|
<CrmRecordForm entity={entity} form={form} hierarchyOptions={hierarchyOptions} onChange={updateField} />
|
||||||
<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-3 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">{status}</span>
|
<span className="min-w-0 text-sm text-muted">{status}</span>
|
||||||
@@ -146,3 +146,4 @@ export function CrmFormPage({ entity, mode }: CrmFormPageProps) {
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export function CrmListPage({ entity }: CrmListPageProps) {
|
|||||||
}, [config.collectionLabel, entity, lifecycleFilter, operationalFilter, searchTerm, stateFilter, statusFilter, token]);
|
}, [config.collectionLabel, entity, lifecycleFilter, operationalFilter, searchTerm, stateFilter, statusFilter, token]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-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>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">CRM</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">CRM</p>
|
||||||
@@ -73,7 +73,7 @@ export function CrmListPage({ entity }: CrmListPageProps) {
|
|||||||
</Link>
|
</Link>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6 grid gap-3 rounded-3xl border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.35fr_0.8fr_0.8fr_0.9fr_0.9fr]">
|
<div className="mt-6 grid gap-3 rounded-[18px] border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.35fr_0.8fr_0.8fr_0.9fr_0.9fr]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
||||||
<input
|
<input
|
||||||
@@ -139,7 +139,7 @@ export function CrmListPage({ entity }: CrmListPageProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
||||||
{records.length === 0 ? (
|
{records.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
{config.emptyMessage}
|
{config.emptyMessage}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -209,3 +209,4 @@ export function CrmListPage({ entity }: CrmListPageProps) {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export function GanttPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Planning</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Planning</p>
|
||||||
@@ -60,42 +60,42 @@ export function GanttPage() {
|
|||||||
The planning surface now reads directly from active projects and open work orders so schedule pressure, due-date risk, and standalone manufacturing load are visible in one place.
|
The planning surface now reads directly from active projects and open work orders so schedule pressure, due-date risk, and standalone manufacturing load are visible in one place.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-3xl border border-line/70 bg-page/60 px-3 py-3 text-sm">
|
<div className="rounded-[18px] border border-line/70 bg-page/60 px-3 py-3 text-sm">
|
||||||
<div className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Timeline Status</div>
|
<div className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Timeline Status</div>
|
||||||
<div className="mt-2 font-semibold text-text">{status}</div>
|
<div className="mt-2 font-semibold text-text">{status}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<section className="grid gap-3 xl:grid-cols-6">
|
<section className="grid gap-3 xl:grid-cols-6">
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Active Projects</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Active Projects</p>
|
||||||
<div className="mt-2 text-xl font-extrabold text-text">{summary?.activeProjects ?? 0}</div>
|
<div className="mt-2 text-xl font-extrabold text-text">{summary?.activeProjects ?? 0}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">At Risk</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">At Risk</p>
|
||||||
<div className="mt-2 text-xl font-extrabold text-text">{summary?.atRiskProjects ?? 0}</div>
|
<div className="mt-2 text-xl font-extrabold text-text">{summary?.atRiskProjects ?? 0}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Overdue Projects</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Overdue Projects</p>
|
||||||
<div className="mt-2 text-xl font-extrabold text-text">{summary?.overdueProjects ?? 0}</div>
|
<div className="mt-2 text-xl font-extrabold text-text">{summary?.overdueProjects ?? 0}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Active Work Orders</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Active Work Orders</p>
|
||||||
<div className="mt-2 text-xl font-extrabold text-text">{summary?.activeWorkOrders ?? 0}</div>
|
<div className="mt-2 text-xl font-extrabold text-text">{summary?.activeWorkOrders ?? 0}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Overdue Work</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Overdue Work</p>
|
||||||
<div className="mt-2 text-xl font-extrabold text-text">{summary?.overdueWorkOrders ?? 0}</div>
|
<div className="mt-2 text-xl font-extrabold text-text">{summary?.overdueWorkOrders ?? 0}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Unscheduled Work</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Unscheduled Work</p>
|
||||||
<div className="mt-2 text-xl font-extrabold text-text">{summary?.unscheduledWorkOrders ?? 0}</div>
|
<div className="mt-2 text-xl font-extrabold text-text">{summary?.unscheduledWorkOrders ?? 0}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Shortage Items</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Shortage Items</p>
|
||||||
<div className="mt-2 text-xl font-extrabold text-text">{planningRollup?.summary.uncoveredItemCount ?? 0}</div>
|
<div className="mt-2 text-xl font-extrabold text-text">{planningRollup?.summary.uncoveredItemCount ?? 0}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Build / Buy</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Build / Buy</p>
|
||||||
<div className="mt-2 text-xl font-extrabold text-text">
|
<div className="mt-2 text-xl font-extrabold text-text">
|
||||||
{planningRollup ? `${planningRollup.summary.totalBuildQuantity} / ${planningRollup.summary.totalPurchaseQuantity}` : "0 / 0"}
|
{planningRollup ? `${planningRollup.summary.totalBuildQuantity} / ${planningRollup.summary.totalPurchaseQuantity}` : "0 / 0"}
|
||||||
@@ -104,7 +104,7 @@ export function GanttPage() {
|
|||||||
</section>
|
</section>
|
||||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.2fr)_360px]">
|
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.2fr)_360px]">
|
||||||
<div
|
<div
|
||||||
className={`gantt-theme overflow-hidden rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5 ${
|
className={`gantt-theme overflow-auto rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5 ${
|
||||||
mode === "dark" ? "wx-willow-dark-theme" : "wx-willow-theme"
|
mode === "dark" ? "wx-willow-dark-theme" : "wx-willow-theme"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -130,17 +130,17 @@ export function GanttPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<aside className="space-y-3">
|
<aside className="space-y-3">
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Planning Exceptions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Planning Exceptions</p>
|
||||||
<p className="mt-2 text-sm text-muted">Priority schedule issues from live project due dates and manufacturing commitments.</p>
|
<p className="mt-2 text-sm text-muted">Priority schedule issues from live project due dates and manufacturing commitments.</p>
|
||||||
{exceptions.length === 0 ? (
|
{exceptions.length === 0 ? (
|
||||||
<div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
No planning exceptions are active.
|
No planning exceptions are active.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-5 space-y-3">
|
||||||
{exceptions.map((exception: PlanningExceptionDto) => (
|
{exceptions.map((exception: PlanningExceptionDto) => (
|
||||||
<Link key={exception.id} to={exception.detailHref} className="block rounded-3xl border border-line/70 bg-page/60 p-3 transition hover:bg-page/80">
|
<Link key={exception.id} to={exception.detailHref} className="block rounded-[18px] border border-line/70 bg-page/60 p-3 transition hover:bg-page/80">
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{exception.kind === "PROJECT" ? "Project" : "Work Order"}</div>
|
<div className="text-xs font-semibold uppercase tracking-[0.16em] text-muted">{exception.kind === "PROJECT" ? "Project" : "Work Order"}</div>
|
||||||
@@ -157,9 +157,9 @@ export function GanttPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Planner Actions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Planner Actions</p>
|
||||||
<div className="mt-4 space-y-2 rounded-3xl border border-line/70 bg-page/60 p-3 text-sm">
|
<div className="mt-4 space-y-2 rounded-[18px] border border-line/70 bg-page/60 p-3 text-sm">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<span className="text-muted">Uncovered quantity</span>
|
<span className="text-muted">Uncovered quantity</span>
|
||||||
<span className="font-semibold text-text">{planningRollup?.summary.totalUncoveredQuantity ?? 0}</span>
|
<span className="font-semibold text-text">{planningRollup?.summary.totalUncoveredQuantity ?? 0}</span>
|
||||||
@@ -186,3 +186,4 @@ export function GanttPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -240,12 +240,12 @@ export function InventoryDetailPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Inventory Detail</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Inventory Detail</p>
|
||||||
@@ -271,38 +271,38 @@ export function InventoryDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section className="grid gap-3 xl:grid-cols-7">
|
<section className="grid gap-3 xl:grid-cols-7">
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">On Hand</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">On Hand</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{item.onHandQuantity}</div>
|
<div className="mt-2 text-base font-bold text-text">{item.onHandQuantity}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Reserved</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Reserved</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{item.reservedQuantity}</div>
|
<div className="mt-2 text-base font-bold text-text">{item.reservedQuantity}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Available</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Available</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{item.availableQuantity}</div>
|
<div className="mt-2 text-base font-bold text-text">{item.availableQuantity}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Stock Locations</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Stock Locations</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{item.stockBalances.length}</div>
|
<div className="mt-2 text-base font-bold text-text">{item.stockBalances.length}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Transactions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Transactions</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{item.recentTransactions.length}</div>
|
<div className="mt-2 text-base font-bold text-text">{item.recentTransactions.length}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Transfers</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Transfers</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{item.transfers.length}</div>
|
<div className="mt-2 text-base font-bold text-text">{item.transfers.length}</div>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">Reservations</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Reservations</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{item.reservations.length}</div>
|
<div className="mt-2 text-base font-bold text-text">{item.reservations.length}</div>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.05fr)_minmax(340px,0.95fr)]">
|
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.05fr)_minmax(340px,0.95fr)]">
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Item Definition</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Item Definition</p>
|
||||||
<dl className="mt-5 grid gap-3 xl:grid-cols-2">
|
<dl className="mt-5 grid gap-3 xl:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
@@ -333,7 +333,7 @@ export function InventoryDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Stock By Location</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Stock By Location</p>
|
||||||
{item.stockBalances.length === 0 ? (
|
{item.stockBalances.length === 0 ? (
|
||||||
<p className="mt-4 text-sm text-muted">No stock or reservation balances have been posted for this item yet.</p>
|
<p className="mt-4 text-sm text-muted">No stock or reservation balances have been posted for this item yet.</p>
|
||||||
@@ -362,7 +362,7 @@ export function InventoryDetailPage() {
|
|||||||
|
|
||||||
<section className="grid gap-3 xl:grid-cols-2">
|
<section className="grid gap-3 xl:grid-cols-2">
|
||||||
{canManage ? (
|
{canManage ? (
|
||||||
<form className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5" onSubmit={handleTransactionSubmit}>
|
<form className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5" onSubmit={handleTransactionSubmit}>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Stock Transactions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Stock Transactions</p>
|
||||||
<div className="mt-5 grid gap-3">
|
<div className="mt-5 grid gap-3">
|
||||||
<div className="grid gap-3 xl:grid-cols-2">
|
<div className="grid gap-3 xl:grid-cols-2">
|
||||||
@@ -403,7 +403,7 @@ export function InventoryDetailPage() {
|
|||||||
</label>
|
</label>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||||
<textarea value={transactionForm.notes} onChange={(event) => updateTransactionField("notes", event.target.value)} rows={3} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={transactionForm.notes} onChange={(event) => updateTransactionField("notes", event.target.value)} rows={3} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-col gap-3 rounded-2xl border border-line/70 bg-page/70 px-2 py-2">
|
<div className="flex flex-col gap-3 rounded-2xl border border-line/70 bg-page/70 px-2 py-2">
|
||||||
<span className="text-sm text-muted">{transactionStatus}</span>
|
<span className="text-sm text-muted">{transactionStatus}</span>
|
||||||
@@ -414,16 +414,16 @@ export function InventoryDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
) : null}
|
) : null}
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Recent Movements</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Recent Movements</p>
|
||||||
{item.recentTransactions.length === 0 ? (
|
{item.recentTransactions.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 stock transactions have been recorded for this item yet.
|
No stock transactions have been recorded for this item yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-6 space-y-3">
|
||||||
{item.recentTransactions.map((transaction) => (
|
{item.recentTransactions.map((transaction) => (
|
||||||
<article key={transaction.id} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<article key={transaction.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">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
@@ -453,7 +453,7 @@ export function InventoryDetailPage() {
|
|||||||
|
|
||||||
{canManage ? (
|
{canManage ? (
|
||||||
<section className="grid gap-3 xl:grid-cols-2">
|
<section className="grid gap-3 xl:grid-cols-2">
|
||||||
<form className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5" onSubmit={handleTransferSubmit}>
|
<form className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5" onSubmit={handleTransferSubmit}>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Inventory Transfer</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Inventory Transfer</p>
|
||||||
<div className="mt-5 grid gap-3">
|
<div className="mt-5 grid gap-3">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
@@ -496,7 +496,7 @@ export function InventoryDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||||
<textarea value={transferForm.notes} onChange={(event) => updateTransferField("notes", event.target.value)} rows={3} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={transferForm.notes} onChange={(event) => updateTransferField("notes", event.target.value)} rows={3} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-col gap-3 rounded-2xl border border-line/70 bg-page/70 px-2 py-2">
|
<div className="flex flex-col gap-3 rounded-2xl border border-line/70 bg-page/70 px-2 py-2">
|
||||||
<span className="text-sm text-muted">{transferStatus}</span>
|
<span className="text-sm text-muted">{transferStatus}</span>
|
||||||
@@ -506,7 +506,7 @@ export function InventoryDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<form className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5" onSubmit={handleReservationSubmit}>
|
<form className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5" onSubmit={handleReservationSubmit}>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Manual Reservation</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Manual Reservation</p>
|
||||||
<div className="mt-5 grid gap-3">
|
<div className="mt-5 grid gap-3">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
@@ -533,7 +533,7 @@ export function InventoryDetailPage() {
|
|||||||
</label>
|
</label>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||||
<textarea value={reservationForm.notes} onChange={(event) => setReservationForm((current) => ({ ...current, notes: event.target.value }))} rows={3} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={reservationForm.notes} onChange={(event) => setReservationForm((current) => ({ ...current, notes: event.target.value }))} rows={3} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-col gap-3 rounded-2xl border border-line/70 bg-page/70 px-2 py-2">
|
<div className="flex flex-col gap-3 rounded-2xl border border-line/70 bg-page/70 px-2 py-2">
|
||||||
<span className="text-sm text-muted">{reservationStatus}</span>
|
<span className="text-sm text-muted">{reservationStatus}</span>
|
||||||
@@ -547,16 +547,16 @@ export function InventoryDetailPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<section className="grid gap-3 xl:grid-cols-2">
|
<section className="grid gap-3 xl:grid-cols-2">
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Reservations</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Reservations</p>
|
||||||
{item.reservations.length === 0 ? (
|
{item.reservations.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 reservations have been recorded for this item.
|
No reservations have been recorded for this item.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-5 space-y-3">
|
||||||
{item.reservations.map((reservation) => (
|
{item.reservations.map((reservation) => (
|
||||||
<article key={reservation.id} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<article key={reservation.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{reservation.quantity} reserved</div>
|
<div className="font-semibold text-text">{reservation.quantity} reserved</div>
|
||||||
@@ -573,16 +573,16 @@ export function InventoryDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Transfers</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Transfers</p>
|
||||||
{item.transfers.length === 0 ? (
|
{item.transfers.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 transfers have been recorded for this item.
|
No transfers have been recorded for this item.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-5 space-y-3">
|
||||||
{item.transfers.map((transfer) => (
|
{item.transfers.map((transfer) => (
|
||||||
<article key={transfer.id} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<article key={transfer.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div className="font-semibold text-text">{transfer.quantity} moved</div>
|
<div className="font-semibold text-text">{transfer.quantity} moved</div>
|
||||||
<div className="text-xs text-muted">{new Date(transfer.createdAt).toLocaleString()}</div>
|
<div className="text-xs text-muted">{new Date(transfer.createdAt).toLocaleString()}</div>
|
||||||
@@ -637,3 +637,4 @@ export function InventoryDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Inventory Editor</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Inventory Editor</p>
|
||||||
@@ -239,7 +239,7 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="space-y-4 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="space-y-4 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="grid gap-3 xl:grid-cols-2 2xl:grid-cols-4">
|
<div className="grid gap-3 xl:grid-cols-2 2xl:grid-cols-4">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">SKU</span>
|
<span className="mb-2 block text-sm font-semibold text-text">SKU</span>
|
||||||
@@ -414,7 +414,7 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
value={form.description}
|
value={form.description}
|
||||||
onChange={(event) => updateField("description", event.target.value)}
|
onChange={(event) => updateField("description", event.target.value)}
|
||||||
rows={4}
|
rows={4}
|
||||||
className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
@@ -423,12 +423,12 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
value={form.notes}
|
value={form.notes}
|
||||||
onChange={(event) => updateField("notes", event.target.value)}
|
onChange={(event) => updateField("notes", event.target.value)}
|
||||||
rows={4}
|
rows={4}
|
||||||
className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
{form.type === "ASSEMBLY" || form.type === "MANUFACTURED" ? (
|
{form.type === "ASSEMBLY" || form.type === "MANUFACTURED" ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Manufacturing Routing</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Manufacturing Routing</p>
|
||||||
@@ -440,13 +440,13 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{form.operations.length === 0 ? (
|
{form.operations.length === 0 ? (
|
||||||
<div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
Add at least one station operation for this buildable item.
|
Add at least one station operation for this buildable item.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-4">
|
<div className="mt-5 space-y-4">
|
||||||
{form.operations.map((operation, index) => (
|
{form.operations.map((operation, index) => (
|
||||||
<div key={`${operation.stationId}-${operation.position}-${index}`} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<div key={`${operation.stationId}-${operation.position}-${index}`} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="grid gap-3 xl:grid-cols-[1.2fr_0.55fr_0.7fr_0.55fr_0.55fr_auto]">
|
<div className="grid gap-3 xl:grid-cols-[1.2fr_0.55fr_0.7fr_0.55fr_0.55fr_auto]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Station</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Station</span>
|
||||||
@@ -495,7 +495,7 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Bill Of Materials</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Bill Of Materials</p>
|
||||||
@@ -511,13 +511,13 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{form.bomLines.length === 0 ? (
|
{form.bomLines.length === 0 ? (
|
||||||
<div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
No BOM lines added yet.
|
No BOM lines added yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-4">
|
<div className="mt-5 space-y-4">
|
||||||
{form.bomLines.map((line, index) => (
|
{form.bomLines.map((line, index) => (
|
||||||
<div key={`${line.componentItemId}-${line.position}-${index}`} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<div key={`${line.componentItemId}-${line.position}-${index}`} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="grid gap-3 xl:grid-cols-[1.4fr_0.7fr_0.7fr_0.7fr_auto]">
|
<div className="grid gap-3 xl:grid-cols-[1.4fr_0.7fr_0.7fr_0.7fr_auto]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Component</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Component</span>
|
||||||
@@ -685,3 +685,4 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function InventoryListPage() {
|
|||||||
}, [searchTerm, statusFilter, token, typeFilter]);
|
}, [searchTerm, statusFilter, token, typeFilter]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Inventory</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Inventory</p>
|
||||||
@@ -56,7 +56,7 @@ export function InventoryListPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6 grid gap-3 rounded-3xl border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.3fr_0.8fr_0.8fr]">
|
<div className="mt-6 grid gap-3 rounded-[18px] border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.3fr_0.8fr_0.8fr]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
||||||
<input
|
<input
|
||||||
@@ -97,7 +97,7 @@ export function InventoryListPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
||||||
{items.length === 0 ? (
|
{items.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 inventory items have been added yet.
|
No inventory items have been added yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -145,3 +145,4 @@ export function InventoryListPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ export function WarehouseDetailPage() {
|
|||||||
}, [token, warehouseId]);
|
}, [token, warehouseId]);
|
||||||
|
|
||||||
if (!warehouse) {
|
if (!warehouse) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-8 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-8 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Warehouse Detail</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Warehouse Detail</p>
|
||||||
@@ -58,24 +58,24 @@ export function WarehouseDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,0.85fr)_minmax(0,1.15fr)]">
|
<div className="grid gap-3 xl:grid-cols-[minmax(0,0.85fr)_minmax(0,1.15fr)]">
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Notes</p>
|
<p className="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">{warehouse.notes || "No warehouse notes recorded."}</p>
|
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{warehouse.notes || "No warehouse notes recorded."}</p>
|
||||||
<div className="mt-8 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 text-sm text-muted">
|
<div className="mt-8 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 text-sm text-muted">
|
||||||
Created {new Date(warehouse.createdAt).toLocaleDateString()}
|
Created {new Date(warehouse.createdAt).toLocaleDateString()}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Locations</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Locations</p>
|
||||||
<h4 className="mt-2 text-lg font-bold text-text">Stock locations</h4>
|
<h4 className="mt-2 text-lg font-bold text-text">Stock locations</h4>
|
||||||
{warehouse.locations.length === 0 ? (
|
{warehouse.locations.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 stock locations have been defined for this warehouse yet.
|
No stock locations have been defined for this warehouse yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 grid gap-3 xl:grid-cols-2">
|
<div className="mt-6 grid gap-3 xl:grid-cols-2">
|
||||||
{warehouse.locations.map((location: WarehouseLocationDto) => (
|
{warehouse.locations.map((location: WarehouseLocationDto) => (
|
||||||
<article key={location.id} className="rounded-3xl border border-line/70 bg-page/60 px-2 py-2">
|
<article key={location.id} className="rounded-[18px] border border-line/70 bg-page/60 px-2 py-2">
|
||||||
<div className="text-sm font-semibold text-text">{location.code}</div>
|
<div className="text-sm font-semibold text-text">{location.code}</div>
|
||||||
<div className="mt-1 text-sm text-text">{location.name}</div>
|
<div className="mt-1 text-sm text-text">{location.name}</div>
|
||||||
<div className="mt-2 text-xs leading-6 text-muted">{location.notes || "No notes."}</div>
|
<div className="mt-2 text-xs leading-6 text-muted">{location.notes || "No notes."}</div>
|
||||||
@@ -88,3 +88,4 @@ export function WarehouseDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export function WarehouseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Warehouse Editor</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Warehouse Editor</p>
|
||||||
@@ -107,7 +107,7 @@ export function WarehouseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="space-y-4 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="space-y-4 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Warehouse code</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Warehouse code</span>
|
||||||
@@ -120,10 +120,10 @@ export function WarehouseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</div>
|
</div>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||||
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={4} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={4} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Locations</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Locations</p>
|
||||||
@@ -134,13 +134,13 @@ export function WarehouseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{form.locations.length === 0 ? (
|
{form.locations.length === 0 ? (
|
||||||
<div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
No locations added yet.
|
No locations added yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-4">
|
<div className="mt-5 space-y-4">
|
||||||
{form.locations.map((location: WarehouseLocationInput, index: number) => (
|
{form.locations.map((location: WarehouseLocationInput, index: number) => (
|
||||||
<div key={index} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<div key={index} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="grid gap-3 xl:grid-cols-[0.7fr_1fr_auto]">
|
<div className="grid gap-3 xl:grid-cols-[0.7fr_1fr_auto]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Code</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Code</span>
|
||||||
@@ -189,3 +189,4 @@ export function WarehouseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function WarehousesPage() {
|
|||||||
}, [token]);
|
}, [token]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Inventory</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Inventory</p>
|
||||||
@@ -46,7 +46,7 @@ export function WarehousesPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
||||||
{warehouses.length === 0 ? (
|
{warehouses.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 warehouses have been added yet.
|
No warehouses have been added yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -80,3 +80,4 @@ export function WarehousesPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,18 +53,18 @@ export function ManufacturingPage() {
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<section className="grid gap-3 xl:grid-cols-[minmax(0,1.05fr)_400px]">
|
<section className="grid gap-3 xl:grid-cols-[minmax(0,1.05fr)_400px]">
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Manufacturing Stations</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Manufacturing Stations</p>
|
||||||
<h3 className="mt-2 text-xl font-bold text-text">Scheduling anchors</h3>
|
<h3 className="mt-2 text-xl font-bold text-text">Scheduling anchors</h3>
|
||||||
<p className="mt-2 text-sm text-muted">Stations define where operation time belongs. Buildable items reference them in their routing template, and work orders inherit those steps automatically into planning.</p>
|
<p className="mt-2 text-sm text-muted">Stations define where operation time belongs. Buildable items reference them in their routing template, and work orders inherit those steps automatically into planning.</p>
|
||||||
{stations.length === 0 ? (
|
{stations.length === 0 ? (
|
||||||
<div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
No stations defined yet.
|
No stations defined yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-5 space-y-3">
|
||||||
{stations.map((station) => (
|
{stations.map((station) => (
|
||||||
<article key={station.id} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<article key={station.id} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{station.code} - {station.name}</div>
|
<div className="font-semibold text-text">{station.code} - {station.name}</div>
|
||||||
@@ -81,7 +81,7 @@ export function ManufacturingPage() {
|
|||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
{canManage ? (
|
{canManage ? (
|
||||||
<form onSubmit={handleSubmit} className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<form onSubmit={handleSubmit} className="rounded-[20px] 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">New Station</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">New Station</p>
|
||||||
<div className="mt-4 grid gap-3">
|
<div className="mt-4 grid gap-3">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
@@ -98,7 +98,7 @@ export function ManufacturingPage() {
|
|||||||
</label>
|
</label>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Description</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Description</span>
|
||||||
<textarea value={form.description} onChange={(event) => setForm((current) => ({ ...current, description: event.target.value }))} rows={3} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={form.description} onChange={(event) => setForm((current) => ({ ...current, description: event.target.value }))} rows={3} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center gap-3 rounded-2xl border border-line/70 bg-page px-2 py-2">
|
<label className="flex items-center gap-3 rounded-2xl border border-line/70 bg-page px-2 py-2">
|
||||||
<input type="checkbox" checked={form.isActive} onChange={(event) => setForm((current) => ({ ...current, isActive: event.target.checked }))} />
|
<input type="checkbox" checked={form.isActive} onChange={(event) => setForm((current) => ({ ...current, isActive: event.target.checked }))} />
|
||||||
@@ -118,3 +118,4 @@ export function ManufacturingPage() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -196,12 +196,12 @@ export function WorkOrderDetailPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!workOrder) {
|
if (!workOrder) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Work Order</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Work Order</p>
|
||||||
@@ -219,7 +219,7 @@ export function WorkOrderDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{canManage ? (
|
{canManage ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Quick Actions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Quick Actions</p>
|
||||||
@@ -236,16 +236,16 @@ export function WorkOrderDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="grid gap-3 xl:grid-cols-6">
|
<section className="grid gap-3 xl:grid-cols-6">
|
||||||
<article className="rounded-[24px] 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="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="rounded-[24px] 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-[24px] 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-[24px] 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>
|
||||||
<article className="rounded-[24px] 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">Operations</p><div className="mt-2 text-base font-bold text-text">{workOrder.operations.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">Operations</p><div className="mt-2 text-base font-bold text-text">{workOrder.operations.length}</div></article>
|
||||||
<article className="rounded-[24px] 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">Due Date</p><div className="mt-2 text-base font-bold text-text">{workOrder.dueDate ? new Date(workOrder.dueDate).toLocaleDateString() : "Not set"}</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">Due Date</p><div className="mt-2 text-base font-bold text-text">{workOrder.dueDate ? new Date(workOrder.dueDate).toLocaleDateString() : "Not set"}</div></article>
|
||||||
<article className="rounded-[24px] 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">Material Shortage</p><div className="mt-2 text-base font-bold text-text">{workOrder.materialRequirements.reduce((sum, requirement) => sum + requirement.shortageQuantity, 0)}</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">Material Shortage</p><div className="mt-2 text-base font-bold text-text">{workOrder.materialRequirements.reduce((sum, requirement) => sum + requirement.shortageQuantity, 0)}</div></article>
|
||||||
</section>
|
</section>
|
||||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,1fr)_minmax(360px,0.9fr)]">
|
<div className="grid gap-3 xl:grid-cols-[minmax(0,1fr)_minmax(360px,0.9fr)]">
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Execution Context</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Execution Context</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">Build item</dt><dd className="mt-1 text-sm text-text">{workOrder.itemSku} - {workOrder.itemName}</dd></div>
|
<div><dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Build item</dt><dd className="mt-1 text-sm text-text">{workOrder.itemSku} - {workOrder.itemName}</dd></div>
|
||||||
@@ -255,17 +255,17 @@ export function WorkOrderDetailPage() {
|
|||||||
<div><dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Demand source</dt><dd className="mt-1 text-sm text-text">{workOrder.salesOrderNumber ?? "Not linked"}</dd></div>
|
<div><dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Demand source</dt><dd className="mt-1 text-sm text-text">{workOrder.salesOrderNumber ?? "Not linked"}</dd></div>
|
||||||
</dl>
|
</dl>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Work Instructions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Work Instructions</p>
|
||||||
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{workOrder.notes || "No work-order notes recorded."}</p>
|
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{workOrder.notes || "No work-order notes recorded."}</p>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Operation Plan</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Operation Plan</p>
|
||||||
{workOrder.operations.length === 0 ? (
|
{workOrder.operations.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">This work order has no inherited station operations. Add routing steps on the item record to automate planning.</div>
|
<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">This work order has no inherited station operations. Add routing steps on the item record to automate planning.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 overflow-hidden rounded-3xl border border-line/70">
|
<div className="mt-5 overflow-hidden rounded-[18px] 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/70">
|
<thead className="bg-page/70">
|
||||||
<tr className="text-left text-xs font-semibold uppercase tracking-[0.18em] text-muted">
|
<tr className="text-left text-xs font-semibold uppercase tracking-[0.18em] text-muted">
|
||||||
@@ -296,7 +296,7 @@ export function WorkOrderDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
{canManage ? (
|
{canManage ? (
|
||||||
<section className="grid gap-3 xl:grid-cols-2">
|
<section className="grid gap-3 xl:grid-cols-2">
|
||||||
<form onSubmit={handleIssueSubmit} className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<form onSubmit={handleIssueSubmit} className="rounded-[20px] 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">Material Issue</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Material Issue</p>
|
||||||
<div className="mt-4 grid gap-3">
|
<div className="mt-4 grid gap-3">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
@@ -333,14 +333,14 @@ export function WorkOrderDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||||
<textarea value={issueForm.notes} onChange={(event) => setIssueForm((current) => ({ ...current, notes: event.target.value }))} rows={3} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={issueForm.notes} onChange={(event) => setIssueForm((current) => ({ ...current, notes: event.target.value }))} rows={3} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<button type="submit" disabled={isPostingIssue} className="rounded-2xl bg-brand px-2 py-2 text-sm font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60">
|
<button type="submit" disabled={isPostingIssue} className="rounded-2xl bg-brand px-2 py-2 text-sm font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60">
|
||||||
{isPostingIssue ? "Posting issue..." : "Post material issue"}
|
{isPostingIssue ? "Posting issue..." : "Post material issue"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<form onSubmit={handleCompletionSubmit} className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<form onSubmit={handleCompletionSubmit} className="rounded-[20px] 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">Production Completion</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Production Completion</p>
|
||||||
<div className="mt-4 grid gap-3">
|
<div className="mt-4 grid gap-3">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
@@ -349,7 +349,7 @@ export function WorkOrderDetailPage() {
|
|||||||
</label>
|
</label>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||||
<textarea value={completionForm.notes} onChange={(event) => setCompletionForm((current) => ({ ...current, notes: event.target.value }))} rows={3} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={completionForm.notes} onChange={(event) => setCompletionForm((current) => ({ ...current, notes: event.target.value }))} rows={3} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<div className="rounded-2xl border border-line/70 bg-page/70 px-2 py-2 text-sm text-muted">Finished goods receipt posts back to {workOrder.warehouseCode} / {workOrder.locationCode}.</div>
|
<div className="rounded-2xl border border-line/70 bg-page/70 px-2 py-2 text-sm text-muted">Finished goods receipt posts back to {workOrder.warehouseCode} / {workOrder.locationCode}.</div>
|
||||||
<button type="submit" disabled={isPostingCompletion} className="rounded-2xl bg-brand px-2 py-2 text-sm font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60">
|
<button type="submit" disabled={isPostingCompletion} className="rounded-2xl bg-brand px-2 py-2 text-sm font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60">
|
||||||
@@ -359,12 +359,12 @@ export function WorkOrderDetailPage() {
|
|||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Material Requirements</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Material Requirements</p>
|
||||||
{workOrder.materialRequirements.length === 0 ? (
|
{workOrder.materialRequirements.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">This build item does not currently have BOM material requirements.</div>
|
<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">This build item does not currently have BOM material requirements.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 overflow-hidden rounded-3xl border border-line/70">
|
<div className="mt-5 overflow-hidden rounded-[18px] 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/70">
|
<thead className="bg-page/70">
|
||||||
<tr className="text-left text-xs font-semibold uppercase tracking-[0.18em] text-muted">
|
<tr className="text-left text-xs font-semibold uppercase tracking-[0.18em] text-muted">
|
||||||
@@ -395,14 +395,14 @@ export function WorkOrderDetailPage() {
|
|||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
<section className="grid gap-3 xl:grid-cols-2">
|
<section className="grid gap-3 xl:grid-cols-2">
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Issue History</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Issue History</p>
|
||||||
{workOrder.materialIssues.length === 0 ? (
|
{workOrder.materialIssues.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No material issues have been posted yet.</div>
|
<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 material issues have been posted yet.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-5 space-y-3">
|
||||||
{workOrder.materialIssues.map((issue) => (
|
{workOrder.materialIssues.map((issue) => (
|
||||||
<div key={issue.id} className="rounded-3xl border border-line/70 bg-page/60 px-3 py-3">
|
<div key={issue.id} className="rounded-[18px] border border-line/70 bg-page/60 px-3 py-3">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{issue.componentSku} - {issue.componentName}</div>
|
<div className="font-semibold text-text">{issue.componentSku} - {issue.componentName}</div>
|
||||||
@@ -417,14 +417,14 @@ export function WorkOrderDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Completion History</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Completion History</p>
|
||||||
{workOrder.completions.length === 0 ? (
|
{workOrder.completions.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No production completions have been posted yet.</div>
|
<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 production completions have been posted yet.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-5 space-y-3">
|
||||||
{workOrder.completions.map((completion) => (
|
{workOrder.completions.map((completion) => (
|
||||||
<div key={completion.id} className="rounded-3xl border border-line/70 bg-page/60 px-3 py-3">
|
<div key={completion.id} className="rounded-[18px] border border-line/70 bg-page/60 px-3 py-3">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
<div className="font-semibold text-text">{completion.quantity} completed</div>
|
<div className="font-semibold text-text">{completion.quantity} completed</div>
|
||||||
<div className="text-xs text-muted">{completion.createdByName}</div>
|
<div className="text-xs text-muted">{completion.createdByName}</div>
|
||||||
@@ -484,3 +484,4 @@ export function WorkOrderDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ export function WorkOrderFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Manufacturing Editor</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Manufacturing Editor</p>
|
||||||
@@ -151,7 +151,7 @@ export function WorkOrderFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="space-y-4 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="space-y-4 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Build Item</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Build Item</span>
|
||||||
@@ -292,7 +292,7 @@ export function WorkOrderFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</label>
|
</label>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Work instructions / notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Work instructions / notes</span>
|
||||||
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={5} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={5} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<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-3 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">{status}</span>
|
<span className="min-w-0 text-sm text-muted">{status}</span>
|
||||||
@@ -304,3 +304,4 @@ export function WorkOrderFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export function WorkOrderListPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Manufacturing</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Manufacturing</p>
|
||||||
@@ -50,7 +50,7 @@ export function WorkOrderListPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,1fr)_240px]">
|
<div className="grid gap-3 xl:grid-cols-[minmax(0,1fr)_240px]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Search</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Search</span>
|
||||||
@@ -66,9 +66,9 @@ export function WorkOrderListPage() {
|
|||||||
<div className="mt-4 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 text-sm text-muted">{status}</div>
|
<div className="mt-4 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 text-sm text-muted">{status}</div>
|
||||||
</section>
|
</section>
|
||||||
{workOrders.length === 0 ? (
|
{workOrders.length === 0 ? (
|
||||||
<div className="rounded-[28px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No work orders are available yet.</div>
|
<div className="rounded-[20px] border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No work orders are available yet.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="overflow-hidden rounded-[28px] border border-line/70 bg-surface/90 shadow-panel">
|
<div className="overflow-hidden rounded-[20px] border border-line/70 bg-surface/90 shadow-panel">
|
||||||
<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/70">
|
<thead className="bg-page/70">
|
||||||
<tr className="text-left text-xs font-semibold uppercase tracking-[0.18em] text-muted">
|
<tr className="text-left text-xs font-semibold uppercase tracking-[0.18em] text-muted">
|
||||||
@@ -107,3 +107,4 @@ export function WorkOrderListPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ export function ProjectDetailPage() {
|
|||||||
}, [projectId, token]);
|
}, [projectId, token]);
|
||||||
|
|
||||||
if (!project) {
|
if (!project) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Project</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Project</p>
|
||||||
@@ -68,13 +68,13 @@ export function ProjectDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-3 xl:grid-cols-4">
|
||||||
<article className="rounded-[24px] 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">Customer</p><div className="mt-2 text-base font-bold text-text">{project.customerName}</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">Customer</p><div className="mt-2 text-base font-bold text-text">{project.customerName}</div></article>
|
||||||
<article className="rounded-[24px] 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">Owner</p><div className="mt-2 text-base font-bold text-text">{project.ownerName || "Unassigned"}</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">Owner</p><div className="mt-2 text-base font-bold text-text">{project.ownerName || "Unassigned"}</div></article>
|
||||||
<article className="rounded-[24px] 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">Due Date</p><div className="mt-2 text-base font-bold text-text">{project.dueDate ? new Date(project.dueDate).toLocaleDateString() : "Not set"}</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">Due Date</p><div className="mt-2 text-base font-bold text-text">{project.dueDate ? new Date(project.dueDate).toLocaleDateString() : "Not set"}</div></article>
|
||||||
<article className="rounded-[24px] 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">Created</p><div className="mt-2 text-base font-bold text-text">{new Date(project.createdAt).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">Created</p><div className="mt-2 text-base font-bold text-text">{new Date(project.createdAt).toLocaleDateString()}</div></article>
|
||||||
</section>
|
</section>
|
||||||
<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-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Customer Linkage</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Customer Linkage</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/customers/${project.customerId}`} className="hover:text-brand">{project.customerName}</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/customers/${project.customerId}`} className="hover:text-brand">{project.customerName}</Link></dd></div>
|
||||||
@@ -82,12 +82,12 @@ export function ProjectDetailPage() {
|
|||||||
<div><dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Phone</dt><dd className="mt-1 text-sm text-text">{project.customerPhone}</dd></div>
|
<div><dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Phone</dt><dd className="mt-1 text-sm text-text">{project.customerPhone}</dd></div>
|
||||||
</dl>
|
</dl>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Program Notes</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Program Notes</p>
|
||||||
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{project.notes || "No project notes recorded."}</p>
|
<p className="mt-3 whitespace-pre-line text-sm leading-6 text-text">{project.notes || "No project notes recorded."}</p>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Commercial + Delivery Links</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Commercial + Delivery Links</p>
|
||||||
<div className="mt-5 grid gap-3 xl:grid-cols-3">
|
<div className="mt-5 grid gap-3 xl:grid-cols-3">
|
||||||
<div className="rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm">
|
<div className="rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm">
|
||||||
@@ -105,22 +105,22 @@ export function ProjectDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{planning ? (
|
{planning ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Material Readiness</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Material Readiness</p>
|
||||||
<div className="mt-5 grid gap-3 xl:grid-cols-4">
|
<div className="mt-5 grid gap-3 xl:grid-cols-4">
|
||||||
<article className="rounded-[24px] border border-line/70 bg-page/60 px-3 py-3">
|
<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">Build Qty</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Build Qty</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>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-page/60 px-3 py-3">
|
<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">Buy Qty</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Buy Qty</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>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-page/60 px-3 py-3">
|
<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">Uncovered Qty</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Uncovered Qty</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>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[24px] border border-line/70 bg-page/60 px-3 py-3">
|
<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">Shortage Items</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Shortage Items</p>
|
||||||
<div className="mt-2 text-base font-bold text-text">{planning.summary.uncoveredItemCount}</div>
|
<div className="mt-2 text-base font-bold text-text">{planning.summary.uncoveredItemCount}</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -130,7 +130,7 @@ export function ProjectDetailPage() {
|
|||||||
.filter((item) => item.recommendedBuildQuantity > 0 || item.recommendedPurchaseQuantity > 0 || item.uncoveredQuantity > 0)
|
.filter((item) => item.recommendedBuildQuantity > 0 || item.recommendedPurchaseQuantity > 0 || item.uncoveredQuantity > 0)
|
||||||
.slice(0, 8)
|
.slice(0, 8)
|
||||||
.map((item) => (
|
.map((item) => (
|
||||||
<div key={item.itemId} className="rounded-3xl 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">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{item.itemSku}</div>
|
<div className="font-semibold text-text">{item.itemSku}</div>
|
||||||
@@ -145,7 +145,7 @@ export function ProjectDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Manufacturing Links</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Manufacturing Links</p>
|
||||||
@@ -158,11 +158,11 @@ export function ProjectDetailPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{workOrders.length === 0 ? (
|
{workOrders.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No work orders are linked to this project yet.</div>
|
<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 work orders are linked to this project yet.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-6 space-y-3">
|
||||||
{workOrders.map((workOrder) => (
|
{workOrders.map((workOrder) => (
|
||||||
<Link key={workOrder.id} to={`/manufacturing/work-orders/${workOrder.id}`} className="block rounded-3xl border border-line/70 bg-page/60 p-3 transition hover:bg-page/80">
|
<Link key={workOrder.id} to={`/manufacturing/work-orders/${workOrder.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">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{workOrder.workOrderNumber}</div>
|
<div className="font-semibold text-text">{workOrder.workOrderNumber}</div>
|
||||||
@@ -187,3 +187,4 @@ export function ProjectDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ export function ProjectFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Projects Editor</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Projects Editor</p>
|
||||||
@@ -194,7 +194,7 @@ export function ProjectFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="space-y-4 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="space-y-4 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Project name</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Project name</span>
|
||||||
@@ -475,7 +475,7 @@ export function ProjectFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</div>
|
</div>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||||
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={5} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={5} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<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-3 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">{status}</span>
|
<span className="min-w-0 text-sm text-muted">{status}</span>
|
||||||
@@ -541,3 +541,4 @@ export function ProjectFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export function ProjectListPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Projects</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Projects</p>
|
||||||
@@ -57,7 +57,7 @@ export function ProjectListPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.2fr)_0.45fr_0.45fr]">
|
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.2fr)_0.45fr_0.45fr]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Search</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Search</span>
|
||||||
@@ -78,7 +78,7 @@ export function ProjectListPage() {
|
|||||||
</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-5 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 text-sm text-muted">{status}</div>
|
||||||
{projects.length === 0 ? (
|
{projects.length === 0 ? (
|
||||||
<div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No projects are available for the current filters.</div>
|
<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">No projects are available for the current filters.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 overflow-hidden rounded-2xl border border-line/70">
|
<div className="mt-5 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">
|
||||||
@@ -114,3 +114,4 @@ export function ProjectListPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export function PurchaseDetailPage() {
|
|||||||
}, [document]);
|
}, [document]);
|
||||||
|
|
||||||
if (!document) {
|
if (!document) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeDocument = document;
|
const activeDocument = document;
|
||||||
@@ -236,7 +236,7 @@ export function PurchaseDetailPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Purchase Order</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Purchase Order</p>
|
||||||
@@ -267,7 +267,7 @@ export function PurchaseDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{canManage ? (
|
{canManage ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Quick Actions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Quick Actions</p>
|
||||||
@@ -284,42 +284,42 @@ export function PurchaseDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-3 xl:grid-cols-4">
|
||||||
<article className="rounded-[24px] 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="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="rounded-[24px] 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="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="rounded-[24px] 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="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="rounded-[24px] 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="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>
|
||||||
</section>
|
</section>
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-3 xl:grid-cols-4">
|
||||||
<article className="rounded-[24px] 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="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="rounded-[24px] 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="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="rounded-[24px] 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="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="rounded-[24px] 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="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="rounded-[24px] 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="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="rounded-[24px] 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="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>
|
||||||
</section>
|
</section>
|
||||||
<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-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">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-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Notes</p>
|
<p className="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-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Demand Context</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Demand Context</p>
|
||||||
{demandContextItems.length === 0 ? (
|
{demandContextItems.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 active shared shortage or buy-signal records currently point at items on this purchase order.
|
No active shared shortage or buy-signal records currently point at items on this purchase order.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-5 space-y-3">
|
||||||
{demandContextItems.map((item) => (
|
{demandContextItems.map((item) => (
|
||||||
<div key={item.itemId} className="rounded-3xl 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">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{item.itemSku}</div>
|
<div className="font-semibold text-text">{item.itemSku}</div>
|
||||||
@@ -334,10 +334,10 @@ export function PurchaseDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Line Items</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Line Items</p>
|
||||||
{activeDocument.lines.length === 0 ? (
|
{activeDocument.lines.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl 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-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-6 overflow-hidden rounded-2xl border border-line/70">
|
<div className="mt-6 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">
|
||||||
@@ -367,12 +367,12 @@ export function PurchaseDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
<section className="grid gap-3 2xl:grid-cols-[minmax(360px,0.82fr)_minmax(0,1.18fr)]">
|
<section className="grid gap-3 2xl:grid-cols-[minmax(360px,0.82fr)_minmax(0,1.18fr)]">
|
||||||
{canReceive ? (
|
{canReceive ? (
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Purchase Receiving</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Purchase Receiving</p>
|
||||||
<h4 className="mt-2 text-lg font-bold text-text">Receive material</h4>
|
<h4 className="mt-2 text-lg font-bold text-text">Receive material</h4>
|
||||||
<p className="mt-2 text-sm text-muted">Post received quantities to inventory and retain a receipt record against this order.</p>
|
<p className="mt-2 text-sm text-muted">Post received quantities to inventory and retain a receipt record against this order.</p>
|
||||||
{openLines.length === 0 ? (
|
{openLines.length === 0 ? (
|
||||||
<div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
All ordered quantities have been received for this purchase order.
|
All ordered quantities have been received for this purchase order.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -414,12 +414,12 @@ export function PurchaseDetailPage() {
|
|||||||
value={receiptForm.notes}
|
value={receiptForm.notes}
|
||||||
onChange={(event) => updateReceiptField("notes", event.target.value)}
|
onChange={(event) => updateReceiptField("notes", event.target.value)}
|
||||||
rows={3}
|
rows={3}
|
||||||
className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{openLines.map((line) => (
|
{openLines.map((line) => (
|
||||||
<div key={line.id} className="grid gap-3 rounded-3xl border border-line/70 bg-page/60 p-3 xl:grid-cols-[minmax(0,1.3fr)_0.6fr_0.7fr_0.7fr]">
|
<div key={line.id} className="grid gap-3 rounded-[18px] border border-line/70 bg-page/60 p-3 xl:grid-cols-[minmax(0,1.3fr)_0.6fr_0.7fr_0.7fr]">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{line.itemSku}</div>
|
<div className="font-semibold text-text">{line.itemSku}</div>
|
||||||
<div className="mt-1 text-xs text-muted">{line.itemName}</div>
|
<div className="mt-1 text-xs text-muted">{line.itemName}</div>
|
||||||
@@ -462,17 +462,17 @@ export function PurchaseDetailPage() {
|
|||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
) : null}
|
) : null}
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Receipt History</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Receipt History</p>
|
||||||
<h4 className="mt-2 text-lg font-bold text-text">Received material log</h4>
|
<h4 className="mt-2 text-lg font-bold text-text">Received material log</h4>
|
||||||
{activeDocument.receipts.length === 0 ? (
|
{activeDocument.receipts.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 purchase receipts have been recorded for this order yet.
|
No purchase receipts have been recorded for this order yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-6 space-y-3">
|
||||||
{activeDocument.receipts.map((receipt) => (
|
{activeDocument.receipts.map((receipt) => (
|
||||||
<article key={receipt.id} className="rounded-3xl 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">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-semibold text-text">{receipt.receiptNumber}</div>
|
<div className="text-sm font-semibold text-text">{receipt.receiptNumber}</div>
|
||||||
@@ -549,3 +549,4 @@ export function PurchaseDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Purchasing Editor</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Purchasing Editor</p>
|
||||||
@@ -264,7 +264,7 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="space-y-4 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="space-y-4 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="grid gap-3 xl:grid-cols-4">
|
<div className="grid gap-3 xl:grid-cols-4">
|
||||||
<label className="block xl:col-span-2">
|
<label className="block xl:col-span-2">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Vendor</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Vendor</span>
|
||||||
@@ -342,7 +342,7 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</div>
|
</div>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||||
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={3} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={3} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<div className="grid gap-3 xl:grid-cols-2">
|
<div className="grid gap-3 xl:grid-cols-2">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
@@ -355,7 +355,7 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Line Items</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Line Items</p>
|
||||||
@@ -364,11 +364,11 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
<button type="button" onClick={addLine} className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text">Add line</button>
|
<button type="button" onClick={addLine} className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text">Add line</button>
|
||||||
</div>
|
</div>
|
||||||
{form.lines.length === 0 ? (
|
{form.lines.length === 0 ? (
|
||||||
<div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No line items added yet.</div>
|
<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">No line items added yet.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-4">
|
<div className="mt-5 space-y-4">
|
||||||
{form.lines.map((line: PurchaseLineInput, index: number) => (
|
{form.lines.map((line: PurchaseLineInput, index: number) => (
|
||||||
<div key={index} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<div key={index} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="grid gap-3 xl:grid-cols-[1.15fr_1.25fr_0.5fr_0.55fr_0.7fr_0.75fr_auto]">
|
<div className="grid gap-3 xl:grid-cols-[1.15fr_1.25fr_0.5fr_0.55fr_0.7fr_0.75fr_auto]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">SKU</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">SKU</span>
|
||||||
@@ -477,3 +477,4 @@ export function PurchaseFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function PurchaseListPage() {
|
|||||||
}, [searchTerm, statusFilter, token]);
|
}, [searchTerm, statusFilter, token]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-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>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Purchasing</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Purchasing</p>
|
||||||
@@ -47,7 +47,7 @@ export function PurchaseListPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6 grid gap-3 rounded-3xl border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.35fr_0.8fr]">
|
<div className="mt-6 grid gap-3 rounded-[18px] border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.35fr_0.8fr]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
||||||
<input value={searchTerm} onChange={(event) => setSearchTerm(event.target.value)} placeholder="Search purchase orders by document number or vendor" className="w-full rounded-2xl border border-line/70 bg-surface px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<input value={searchTerm} onChange={(event) => setSearchTerm(event.target.value)} placeholder="Search purchase orders by document number or vendor" className="w-full rounded-2xl border border-line/70 bg-surface px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
@@ -65,7 +65,7 @@ export function PurchaseListPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
||||||
{documents.length === 0 ? (
|
{documents.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No purchase orders have been added yet.</div>
|
<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 purchase orders have been added yet.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 overflow-hidden rounded-2xl border border-line/70">
|
<div className="mt-6 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">
|
||||||
@@ -97,3 +97,4 @@ export function PurchaseListPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { ShipmentStatusBadge } from "../shipping/ShipmentStatusBadge";
|
|||||||
|
|
||||||
function PlanningNodeCard({ node }: { node: SalesOrderPlanningNodeDto }) {
|
function PlanningNodeCard({ node }: { node: SalesOrderPlanningNodeDto }) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-3xl border border-line/70 bg-page/60 p-3" style={{ marginLeft: node.level * 12 }}>
|
<div className="rounded-[18px] border border-line/70 bg-page/60 p-3" style={{ marginLeft: node.level * 12 }}>
|
||||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">
|
<div className="font-semibold text-text">
|
||||||
@@ -104,7 +104,7 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
}, [canReadShipping, config.singularLabel, documentId, entity, token]);
|
}, [canReadShipping, config.singularLabel, documentId, entity, token]);
|
||||||
|
|
||||||
if (!document) {
|
if (!document) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeDocument = document;
|
const activeDocument = document;
|
||||||
@@ -267,7 +267,7 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">{config.detailEyebrow}</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">{config.detailEyebrow}</p>
|
||||||
@@ -328,7 +328,7 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{canManage ? (
|
{canManage ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Quick Actions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Quick Actions</p>
|
||||||
@@ -351,45 +351,45 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-3 xl:grid-cols-4">
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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>
|
<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-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">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-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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>
|
<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-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">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-3 xl:grid-cols-4">
|
||||||
<article className="rounded-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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">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-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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>
|
<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-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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>
|
<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-[24px] border border-line/70 bg-surface/90 px-3 py-3 shadow-panel">
|
<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>
|
<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>
|
||||||
</section>
|
</section>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Revision History</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Revision History</p>
|
||||||
@@ -397,13 +397,13 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{activeDocument.revisions.length === 0 ? (
|
{activeDocument.revisions.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 revisions have been recorded yet.
|
No revisions have been recorded yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-6 space-y-3">
|
||||||
{activeDocument.revisions.map((revision) => (
|
{activeDocument.revisions.map((revision) => (
|
||||||
<article key={revision.id} className="rounded-3xl 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">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">Rev {revision.revisionNumber}</div>
|
<div className="font-semibold text-text">Rev {revision.revisionNumber}</div>
|
||||||
@@ -420,7 +420,7 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
<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-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Customer</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Customer</p>
|
||||||
<dl className="mt-5 grid gap-3">
|
<dl className="mt-5 grid gap-3">
|
||||||
<div>
|
<div>
|
||||||
@@ -433,15 +433,15 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</article>
|
</article>
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Notes</p>
|
<p className="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-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] 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">Line Items</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Line Items</p>
|
||||||
{activeDocument.lines.length === 0 ? (
|
{activeDocument.lines.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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.
|
No line items have been added yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -477,7 +477,7 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
{entity === "order" && planning ? (
|
{entity === "order" && planning ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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.24em] text-muted">Demand Planning</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Demand Planning</p>
|
||||||
@@ -492,22 +492,22 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 grid gap-3 xl:grid-cols-4">
|
<div className="mt-5 grid gap-3 xl:grid-cols-4">
|
||||||
<article className="rounded-[24px] border border-line/70 bg-page/70 px-3 py-3">
|
<article className="rounded-[18px] border border-line/70 bg-page/70 px-3 py-3">
|
||||||
<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-[24px] border border-line/70 bg-page/70 px-3 py-3">
|
<article className="rounded-[18px] border border-line/70 bg-page/70 px-3 py-3">
|
||||||
<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-[24px] border border-line/70 bg-page/70 px-3 py-3">
|
<article className="rounded-[18px] border border-line/70 bg-page/70 px-3 py-3">
|
||||||
<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-[24px] border border-line/70 bg-page/70 px-3 py-3">
|
<article className="rounded-[18px] border border-line/70 bg-page/70 px-3 py-3">
|
||||||
<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>
|
||||||
@@ -580,7 +580,7 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
) : null}
|
) : null}
|
||||||
<div className="mt-5 space-y-3">
|
<div className="mt-5 space-y-3">
|
||||||
{planning.lines.map((line) => (
|
{planning.lines.map((line) => (
|
||||||
<div key={line.lineId} className="rounded-3xl 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">
|
||||||
<div className="font-semibold text-text">
|
<div className="font-semibold text-text">
|
||||||
{line.itemSku} <span className="text-muted">{line.itemName}</span>
|
{line.itemSku} <span className="text-muted">{line.itemName}</span>
|
||||||
@@ -596,7 +596,7 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
{entity === "order" && canReadShipping ? (
|
{entity === "order" && canReadShipping ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Shipping</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Shipping</p>
|
||||||
@@ -609,13 +609,13 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{shipments.length === 0 ? (
|
{shipments.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 shipments have been created for this sales order yet.
|
No shipments have been created for this sales order yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 space-y-3">
|
<div className="mt-6 space-y-3">
|
||||||
{shipments.map((shipment) => (
|
{shipments.map((shipment) => (
|
||||||
<Link key={shipment.id} to={`/shipping/shipments/${shipment.id}`} className="block rounded-3xl 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">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{shipment.shipmentNumber}</div>
|
<div className="font-semibold text-text">{shipment.shipmentNumber}</div>
|
||||||
@@ -674,3 +674,4 @@ export function SalesDetailPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">{config.detailEyebrow} Editor</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">{config.detailEyebrow} Editor</p>
|
||||||
@@ -180,7 +180,7 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="space-y-4 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="space-y-4 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="grid gap-3 xl:grid-cols-4">
|
<div className="grid gap-3 xl:grid-cols-4">
|
||||||
<label className="block xl:col-span-2">
|
<label className="block xl:col-span-2">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Customer</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Customer</span>
|
||||||
@@ -299,7 +299,7 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
|
|||||||
value={form.notes}
|
value={form.notes}
|
||||||
onChange={(event) => updateField("notes", event.target.value)}
|
onChange={(event) => updateField("notes", event.target.value)}
|
||||||
rows={3}
|
rows={3}
|
||||||
className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{mode === "edit" ? (
|
{mode === "edit" ? (
|
||||||
@@ -351,7 +351,7 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Line Items</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Line Items</p>
|
||||||
@@ -362,13 +362,13 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{form.lines.length === 0 ? (
|
{form.lines.length === 0 ? (
|
||||||
<div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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">
|
||||||
No line items added yet.
|
No line items added yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-5 space-y-4">
|
<div className="mt-5 space-y-4">
|
||||||
{form.lines.map((line: SalesLineInput, index: number) => (
|
{form.lines.map((line: SalesLineInput, index: number) => (
|
||||||
<div key={index} className="rounded-3xl border border-line/70 bg-page/60 p-3">
|
<div key={index} className="rounded-[18px] border border-line/70 bg-page/60 p-3">
|
||||||
<div className="grid gap-3 xl:grid-cols-[1.15fr_1.25fr_0.5fr_0.55fr_0.7fr_0.75fr_auto]">
|
<div className="grid gap-3 xl:grid-cols-[1.15fr_1.25fr_0.5fr_0.55fr_0.7fr_0.75fr_auto]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">SKU</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">SKU</span>
|
||||||
@@ -499,3 +499,4 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export function SalesListPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
}, [config.collectionLabel, entity, searchTerm, statusFilter, token]);
|
}, [config.collectionLabel, entity, searchTerm, statusFilter, token]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-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>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">{config.listEyebrow}</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">{config.listEyebrow}</p>
|
||||||
@@ -55,7 +55,7 @@ export function SalesListPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</Link>
|
</Link>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6 grid gap-3 rounded-3xl border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.35fr_0.8fr]">
|
<div className="mt-6 grid gap-3 rounded-[18px] border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.35fr_0.8fr]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
||||||
<input
|
<input
|
||||||
@@ -82,7 +82,7 @@ export function SalesListPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
||||||
{documents.length === 0 ? (
|
{documents.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
|
<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 {config.collectionLabel.toLowerCase()} have been added yet.
|
No {config.collectionLabel.toLowerCase()} have been added yet.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -127,3 +127,4 @@ export function SalesListPage({ entity }: { entity: SalesDocumentEntity }) {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export function AdminDiagnosticsPage() {
|
|||||||
}, [token]);
|
}, [token]);
|
||||||
|
|
||||||
if (!diagnostics || !backupGuidance) {
|
if (!diagnostics || !backupGuidance) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleExportSupportSnapshot() {
|
async function handleExportSupportSnapshot() {
|
||||||
@@ -132,7 +132,7 @@ export function AdminDiagnosticsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Admin Diagnostics</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Admin Diagnostics</p>
|
||||||
@@ -166,7 +166,7 @@ export function AdminDiagnosticsPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-6 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
<div className="mt-6 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||||||
{summaryCards.map(([label, value]) => (
|
{summaryCards.map(([label, value]) => (
|
||||||
<div key={label} className="rounded-3xl border border-line/70 bg-page/70 p-4">
|
<div key={label} className="rounded-[18px] border border-line/70 bg-page/70 p-4">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-muted">{label}</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-muted">{label}</p>
|
||||||
<p className="mt-3 text-lg font-bold text-text">{value}</p>
|
<p className="mt-3 text-lg font-bold text-text">{value}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,7 +174,7 @@ export function AdminDiagnosticsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<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">Backup And Restore</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Backup And Restore</p>
|
||||||
@@ -241,7 +241,7 @@ export function AdminDiagnosticsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Startup Validation</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Startup Validation</p>
|
||||||
@@ -272,7 +272,7 @@ export function AdminDiagnosticsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">System Footprint</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">System Footprint</p>
|
||||||
<div className="mt-5 grid gap-3 xl:grid-cols-2">
|
<div className="mt-5 grid gap-3 xl:grid-cols-2">
|
||||||
{footprintCards.map(([label, value]) => (
|
{footprintCards.map(([label, value]) => (
|
||||||
@@ -284,7 +284,7 @@ export function AdminDiagnosticsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Support Logs</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Support Logs</p>
|
||||||
@@ -327,7 +327,7 @@ export function AdminDiagnosticsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Recent Audit Trail</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Recent Audit Trail</p>
|
||||||
@@ -377,3 +377,4 @@ export function AdminDiagnosticsPage() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export function CompanySettingsPage() {
|
|||||||
}, [logoUrl]);
|
}, [logoUrl]);
|
||||||
|
|
||||||
if (!form || !token) {
|
if (!form || !token) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSave(event: React.FormEvent<HTMLFormElement>) {
|
async function handleSave(event: React.FormEvent<HTMLFormElement>) {
|
||||||
@@ -147,7 +147,7 @@ export function CompanySettingsPage() {
|
|||||||
return (
|
return (
|
||||||
<form className="space-y-6" onSubmit={handleSave}>
|
<form className="space-y-6" onSubmit={handleSave}>
|
||||||
{user?.permissions.includes("admin.manage") ? (
|
{user?.permissions.includes("admin.manage") ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
<div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Admin</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Admin</p>
|
||||||
@@ -165,14 +165,14 @@ export function CompanySettingsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<div className="flex flex-col gap-6 lg:flex-row lg:items-start lg:justify-between">
|
<div className="flex flex-col gap-6 lg:flex-row lg:items-start lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Company Profile</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Company Profile</p>
|
||||||
<h3 className="mt-2 text-lg font-bold text-text">Branding and legal identity</h3>
|
<h3 className="mt-2 text-lg font-bold text-text">Branding and legal identity</h3>
|
||||||
<p className="mt-2 max-w-2xl text-sm text-muted">Every internal document and PDF template will inherit its company identity from this profile.</p>
|
<p className="mt-2 max-w-2xl text-sm text-muted">Every internal document and PDF template will inherit its company identity from this profile.</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-3xl border border-dashed border-line/70 bg-page/80 p-4">
|
<div className="rounded-[18px] border border-dashed border-line/70 bg-page/80 p-4">
|
||||||
{logoUrl ? <img alt="Company logo" className="h-20 w-20 rounded-2xl object-cover" src={logoUrl} /> : <div className="flex h-20 w-20 items-center justify-center rounded-2xl bg-brand text-sm font-bold text-white">LOGO</div>}
|
{logoUrl ? <img alt="Company logo" className="h-20 w-20 rounded-2xl object-cover" src={logoUrl} /> : <div className="flex h-20 w-20 items-center justify-center rounded-2xl bg-brand text-sm font-bold text-white">LOGO</div>}
|
||||||
<label className="mt-3 block cursor-pointer text-sm font-semibold text-brand">
|
<label className="mt-3 block cursor-pointer text-sm font-semibold text-brand">
|
||||||
Upload logo
|
Upload logo
|
||||||
@@ -206,7 +206,7 @@ export function CompanySettingsPage() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Theme</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Theme</p>
|
||||||
<div className="mt-5 grid gap-4 md:grid-cols-2 2xl:grid-cols-4">
|
<div className="mt-5 grid gap-4 md:grid-cols-2 2xl:grid-cols-4">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
@@ -245,3 +245,4 @@ export function CompanySettingsPage() {
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ export function UserManagementPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">User Management</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">User Management</p>
|
||||||
@@ -281,7 +281,7 @@ export function UserManagementPage() {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="grid gap-6 xl:grid-cols-2">
|
<section className="grid gap-6 xl:grid-cols-2">
|
||||||
<form className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5" onSubmit={handleUserSave}>
|
<form className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5" onSubmit={handleUserSave}>
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Users</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Users</p>
|
||||||
@@ -374,7 +374,7 @@ export function UserManagementPage() {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<form className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5" onSubmit={handleRoleSave}>
|
<form className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5" onSubmit={handleRoleSave}>
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Roles</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Roles</p>
|
||||||
@@ -452,7 +452,7 @@ export function UserManagementPage() {
|
|||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel backdrop-blur 2xl:p-5">
|
||||||
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Sessions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Sessions</p>
|
||||||
@@ -661,3 +661,4 @@ export function UserManagementPage() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,12 +140,12 @@ export function ShipmentDetailPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!shipment) {
|
if (!shipment) {
|
||||||
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
return <div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-4">
|
<section className="space-y-4">
|
||||||
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<div className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Shipment</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Shipment</p>
|
||||||
@@ -172,7 +172,7 @@ export function ShipmentDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{canManage ? (
|
{canManage ? (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Quick Actions</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Quick Actions</p>
|
||||||
@@ -189,17 +189,17 @@ export function ShipmentDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<section className="grid gap-3 xl:grid-cols-4">
|
<section className="grid gap-3 xl:grid-cols-4">
|
||||||
<article className="rounded-[24px] 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">Carrier</p><div className="mt-2 text-base font-bold text-text">{shipment.carrier || "Not set"}</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">Carrier</p><div className="mt-2 text-base font-bold text-text">{shipment.carrier || "Not set"}</div></article>
|
||||||
<article className="rounded-[24px] 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">Service</p><div className="mt-2 text-base font-bold text-text">{shipment.serviceLevel || "Not set"}</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">Service</p><div className="mt-2 text-base font-bold text-text">{shipment.serviceLevel || "Not set"}</div></article>
|
||||||
<article className="rounded-[24px] 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">Tracking</p><div className="mt-2 text-base font-bold text-text">{shipment.trackingNumber || "Not set"}</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">Tracking</p><div className="mt-2 text-base font-bold text-text">{shipment.trackingNumber || "Not set"}</div></article>
|
||||||
<article className="rounded-[24px] 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">Packages</p><div className="mt-2 text-base font-bold text-text">{shipment.packageCount}</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">Packages</p><div className="mt-2 text-base font-bold text-text">{shipment.packageCount}</div></article>
|
||||||
</section>
|
</section>
|
||||||
<div className="grid gap-3 xl:grid-cols-[minmax(0,1fr)_minmax(320px,0.9fr)]">
|
<div className="grid gap-3 xl:grid-cols-[minmax(0,1fr)_minmax(320px,0.9fr)]">
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Shipment Notes</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">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>
|
||||||
<article className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<article className="rounded-[20px] 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">Timing</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Timing</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">Ship Date</dt><dd className="mt-1 text-sm text-text">{shipment.shipDate ? new Date(shipment.shipDate).toLocaleDateString() : "Not set"}</dd></div>
|
<div><dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Ship Date</dt><dd className="mt-1 text-sm text-text">{shipment.shipDate ? new Date(shipment.shipDate).toLocaleDateString() : "Not set"}</dd></div>
|
||||||
@@ -208,7 +208,7 @@ export function ShipmentDetailPage() {
|
|||||||
</dl>
|
</dl>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Related Shipments</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Related Shipments</p>
|
||||||
@@ -219,11 +219,11 @@ export function ShipmentDetailPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{relatedShipments.length === 0 ? (
|
{relatedShipments.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl 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-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-6 space-y-3">
|
<div className="mt-6 space-y-3">
|
||||||
{relatedShipments.map((related) => (
|
{relatedShipments.map((related) => (
|
||||||
<Link key={related.id} to={`/shipping/shipments/${related.id}`} className="block rounded-3xl 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">
|
||||||
<div>
|
<div>
|
||||||
<div className="font-semibold text-text">{related.shipmentNumber}</div>
|
<div className="font-semibold text-text">{related.shipmentNumber}</div>
|
||||||
@@ -271,3 +271,4 @@ export function ShipmentDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export function ShipmentFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<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">Shipping Editor</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Shipping Editor</p>
|
||||||
@@ -98,7 +98,7 @@ export function ShipmentFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section className="space-y-4 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
<section className="space-y-4 rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Sales Order</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Sales Order</span>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -187,7 +187,7 @@ export function ShipmentFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</div>
|
</div>
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
<span className="mb-2 block text-sm font-semibold text-text">Notes</span>
|
||||||
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={4} className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
<textarea value={form.notes} onChange={(event) => updateField("notes", event.target.value)} rows={4} className="w-full rounded-[18px] border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand" />
|
||||||
</label>
|
</label>
|
||||||
<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-3 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">{status}</span>
|
<span className="min-w-0 text-sm text-muted">{status}</span>
|
||||||
@@ -199,3 +199,4 @@ export function ShipmentFormPage({ mode }: { mode: "create" | "edit" }) {
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function ShipmentListPage() {
|
|||||||
}, [searchTerm, statusFilter, token]);
|
}, [searchTerm, statusFilter, token]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel">
|
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-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>
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Shipping</p>
|
<p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Shipping</p>
|
||||||
@@ -51,7 +51,7 @@ export function ShipmentListPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6 grid gap-3 rounded-3xl border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.35fr_0.8fr]">
|
<div className="mt-6 grid gap-3 rounded-[18px] border border-line/70 bg-page/60 p-3 xl:grid-cols-[1.35fr_0.8fr]">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
<span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Search</span>
|
||||||
<input
|
<input
|
||||||
@@ -78,7 +78,7 @@ export function ShipmentListPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
<div className="mt-6 rounded-2xl border border-line/70 bg-page/60 px-2 py-2 text-sm text-muted">{status}</div>
|
||||||
{shipments.length === 0 ? (
|
{shipments.length === 0 ? (
|
||||||
<div className="mt-6 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">No shipments have been added yet.</div>
|
<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 shipments have been added yet.</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-6 overflow-hidden rounded-2xl border border-line/70">
|
<div className="mt-6 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">
|
||||||
@@ -114,3 +114,4 @@ export function ShipmentListPage() {
|
|||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user