feat(collection-confirm): rewrite row card as stacked vertical sections
This commit is contained in:
parent
9ab4be2666
commit
6d03be2ebc
1 changed files with 95 additions and 82 deletions
|
|
@ -566,7 +566,7 @@ function ConfirmCard({
|
|||
disabled={busy}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid min-w-0 flex-1 gap-3 md:grid-cols-[minmax(0,1.2fr)_minmax(0,0.9fr)_auto]">
|
||||
<div className="min-w-0 flex-1 space-y-1">
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-sm font-semibold">
|
||||
{row.expand?.purchase_order?.expand?.supplier?.suppliername ?? "Unknown supplier"}
|
||||
|
|
@ -599,90 +599,103 @@ function ConfirmCard({
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="min-w-0 space-y-1 text-sm">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xs text-muted-foreground">Ordered</span>
|
||||
<span className="font-mono">{row.order_qty ?? row.quantity ?? 0}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xs text-muted-foreground">Collected</span>
|
||||
<span className="font-mono">{row.qty_collected ?? 0}</span>
|
||||
</div>
|
||||
{row.problem_flag && (
|
||||
<div className="inline-flex items-center gap-1 rounded-md bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-800">
|
||||
<AlertTriangle className="h-3 w-3" />
|
||||
Problem: {row.problem_type ?? "flagged"}
|
||||
</div>
|
||||
)}
|
||||
{row.collection_photo && (
|
||||
<Button size="xs" variant="outline" onClick={() => setPhotoOpen(true)}>
|
||||
<ImageIcon className="mr-1 h-3 w-3" />
|
||||
View photo
|
||||
</Button>
|
||||
)}
|
||||
{attachments.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{attachments.map((name) => (
|
||||
<a
|
||||
key={name}
|
||||
href={attachmentUrl(row, name)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="inline-flex items-center gap-1 rounded-md border bg-background px-2 py-0.5 text-xs hover:bg-accent"
|
||||
>
|
||||
<Paperclip className="h-3 w-3" />
|
||||
{displayFilename(name)}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{invoice && (
|
||||
<div className="inline-flex items-center gap-1 rounded-md bg-emerald-50 px-2 py-0.5 text-xs font-medium text-emerald-700">
|
||||
Invoice {invoice.number} · {invoice.date}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-stretch gap-2 lg:min-w-[12rem]">
|
||||
<Button size="sm" variant="outline" onClick={() => setQuantityOpen(true)} disabled={busy}>
|
||||
<Pencil className="mr-1 h-3.5 w-3.5" />
|
||||
Adjust Quantity
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => setNoteOpen(true)} disabled={busy}>
|
||||
<MessageSquare className="mr-1 h-3.5 w-3.5" />
|
||||
Add Note
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => setAttachOpen(true)}
|
||||
disabled={busy}
|
||||
aria-label="Attach invoice"
|
||||
>
|
||||
<Paperclip className="mr-1 h-3.5 w-3.5" />
|
||||
Attach
|
||||
</Button>
|
||||
<Button size="sm" disabled={busy || !canConfirm} onClick={() => void onConfirm(row)} className="bg-emerald-600 text-white hover:bg-emerald-700">
|
||||
{busy ? <Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" /> : null}
|
||||
Confirm for invoicing
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => onRequestReturn(row)}
|
||||
disabled={busy}
|
||||
>
|
||||
<Undo2 className="mr-1 h-3.5 w-3.5" />
|
||||
Return to pool
|
||||
</Button>
|
||||
{!canConfirm && (
|
||||
<p className="text-[11px] text-muted-foreground">Add a confirming note before invoicing this row.</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Details: qty + problem + photo (left), attachments + invoice (right) ── */}
|
||||
<div className="grid grid-cols-1 gap-3 border-t bg-muted/20 px-4 py-3 md:grid-cols-2">
|
||||
<div className="space-y-1 text-sm">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xs text-muted-foreground">Ordered</span>
|
||||
<span className="font-mono">{row.order_qty ?? row.quantity ?? 0}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xs text-muted-foreground">Collected</span>
|
||||
<span className="font-mono">{row.qty_collected ?? 0}</span>
|
||||
</div>
|
||||
{row.problem_flag && (
|
||||
<div className="inline-flex items-center gap-1 rounded-md bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-800">
|
||||
<AlertTriangle className="h-3 w-3" />
|
||||
Problem: {row.problem_type ?? "flagged"}
|
||||
</div>
|
||||
)}
|
||||
{row.collection_photo && (
|
||||
<Button size="xs" variant="outline" onClick={() => setPhotoOpen(true)}>
|
||||
<ImageIcon className="mr-1 h-3 w-3" />
|
||||
View photo
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-1 text-sm">
|
||||
{attachments.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{attachments.map((name) => (
|
||||
<a
|
||||
key={name}
|
||||
href={attachmentUrl(row, name)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="inline-flex items-center gap-1 rounded-md border bg-background px-2 py-0.5 text-xs hover:bg-accent"
|
||||
>
|
||||
<Paperclip className="h-3 w-3" />
|
||||
{displayFilename(name)}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{invoice && (
|
||||
<div className="inline-flex items-center gap-1 rounded-md bg-emerald-50 px-2 py-0.5 text-xs font-medium text-emerald-700">
|
||||
Invoice {invoice.number} · {invoice.date}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Actions: 2-up grid on sm, 3-up on lg, primary spans 2 ── */}
|
||||
<div className="grid grid-cols-1 gap-2 border-t px-4 py-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<Button size="sm" variant="outline" onClick={() => setQuantityOpen(true)} disabled={busy}>
|
||||
<Pencil className="mr-1 h-3.5 w-3.5" />
|
||||
Adjust Quantity
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => setNoteOpen(true)} disabled={busy}>
|
||||
<MessageSquare className="mr-1 h-3.5 w-3.5" />
|
||||
Add Note
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => setAttachOpen(true)}
|
||||
disabled={busy}
|
||||
aria-label="Attach invoice"
|
||||
>
|
||||
<Paperclip className="mr-1 h-3.5 w-3.5" />
|
||||
Attach
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
disabled={busy || !canConfirm}
|
||||
onClick={() => void onConfirm(row)}
|
||||
className="bg-emerald-600 text-white hover:bg-emerald-700 lg:col-span-2"
|
||||
>
|
||||
{busy ? <Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" /> : <CheckCircle2 className="mr-1 h-3.5 w-3.5" />}
|
||||
Confirm for invoicing
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => onRequestReturn(row)}
|
||||
disabled={busy}
|
||||
>
|
||||
<Undo2 className="mr-1 h-3.5 w-3.5" />
|
||||
Return to pool
|
||||
</Button>
|
||||
{!canConfirm && (
|
||||
<p className="text-[11px] text-muted-foreground sm:col-span-2 lg:col-span-3">
|
||||
Add a confirming note before invoicing this row.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="border-t bg-muted/30 px-4 py-3">
|
||||
<p className="text-[11px] font-semibold uppercase tracking-widest text-muted-foreground">Notes</p>
|
||||
{entries.length === 0 ? (
|
||||
|
|
|
|||
Loading…
Reference in a new issue