fix(buyer-tasks): make card layout mobile-friendly
At <=640px the buyer-tasks card content was crushed by the action
column sitting beside it: the PO number badge broke mid-string
('PO-2026-08-042' wrapping to 4 lines), supplier names wrapped to
6 lines, and the new 'Sent to ...' caption overlapped the PO
badge on the PO Sent tab.
Three responsive tweaks, all using Tailwind breakpoint utilities:
1. Outer card container switches from 'flex items-start' to
'flex flex-col sm:flex-row sm:items-start'. The action column
drops below the info column on mobile, giving the info all the
available width and the buttons full-width tap targets.
2. PO number badge gains 'whitespace-nowrap'. The badge stays
atomic; the parent's 'flex-wrap' carries the whole badge to a
new line when it doesn't fit.
3. PO Sent right column: buttons stack vertically on mobile
('flex-col sm:flex-row' + 'flex-1 sm:flex-none' on each
button) and the caption switches from 'text-right' to
'text-left sm:text-right' so it sits under the buttons.
Desktop layout is unchanged — verified at 1280px that the
side-by-side buttons, right-aligned caption, and inline single
button all still render exactly as before.
Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
d2ffbea6bc
commit
bf54511db1
1 changed files with 31 additions and 9 deletions
|
|
@ -67,17 +67,25 @@ export function BuyerTaskGroupCard({
|
|||
/>
|
||||
|
||||
<CardContent className="p-0 pl-3">
|
||||
<div className="flex items-start gap-3 p-3">
|
||||
{/* On mobile the action column drops below the info column so
|
||||
neither gets crushed — the PO number badge no longer wraps
|
||||
mid-number and the buttons get full-width tap targets. On
|
||||
`sm:` and up the original side-by-side layout returns. */}
|
||||
<div className="flex flex-col sm:flex-row sm:items-start gap-3 p-3">
|
||||
<div className="min-w-0 flex-1 space-y-1.5">
|
||||
{/* PO number + order number on the top row so they're
|
||||
both scannable. The PO number is the headline — the
|
||||
thing the operator needs to find quickly — so it goes
|
||||
first and gets its own visual weight. Only shown when
|
||||
a PO has been generated (po_draft / po_sent tabs). */}
|
||||
a PO has been generated (po_draft / po_sent tabs). The
|
||||
badge uses `whitespace-nowrap` so a long PO number
|
||||
(`PO-26071401`) never breaks mid-string when the info
|
||||
column gets narrow — the parent `flex-wrap` carries
|
||||
it onto the next line as a whole. */}
|
||||
<div className="flex items-baseline gap-2 flex-wrap">
|
||||
{group.poNumber && (
|
||||
<span
|
||||
className="inline-flex items-center gap-1 rounded-md border border-warn/40 bg-warn px-2 py-0.5 font-mono text-xs font-bold text-warn-foreground ring-1 ring-inset ring-warn/20 dark:bg-warn/20 dark:border-warn/30 dark:text-warn dark:ring-warn/20"
|
||||
className="inline-flex items-center gap-1 whitespace-nowrap rounded-md border border-warn/40 bg-warn px-2 py-0.5 font-mono text-xs font-bold text-warn-foreground ring-1 ring-inset ring-warn/20 dark:bg-warn/20 dark:border-warn/30 dark:text-warn dark:ring-warn/20"
|
||||
data-testid={`buyer-task-po-number-${group.groupId}`}
|
||||
>
|
||||
<FileText className="h-3 w-3" />
|
||||
|
|
@ -88,7 +96,7 @@ export function BuyerTaskGroupCard({
|
|||
{group.orderNumber}
|
||||
</span>
|
||||
<span
|
||||
className="text-sm font-semibold"
|
||||
className="min-w-0 text-sm font-semibold"
|
||||
// Tint the supplier name with the same colour as the
|
||||
// stripe so the supplier is recognisable even when the
|
||||
// card content overlaps with neighbours.
|
||||
|
|
@ -117,13 +125,20 @@ export function BuyerTaskGroupCard({
|
|||
// recorded `sentAt` (legacy rows predating email_payload,
|
||||
// or a fresh po_draft that got flipped straight to
|
||||
// po_sent without a successful send).
|
||||
<div className="flex flex-col items-end gap-1">
|
||||
<div className="flex items-center gap-2">
|
||||
//
|
||||
// Mobile (below `sm:`): the buttons stack vertically and
|
||||
// stretch to the full card width so the tap target is easy
|
||||
// to hit; the caption aligns left to sit under the buttons
|
||||
// naturally. On `sm:` and up the original side-by-side
|
||||
// button row + right-aligned caption returns.
|
||||
<div className="flex flex-col items-stretch sm:items-end gap-2">
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => onResend?.(group)}
|
||||
disabled={disabled || !onResend}
|
||||
className={cn(
|
||||
"flex-1 sm:flex-none",
|
||||
RESEND_DEFAULT_CLASS,
|
||||
group.poStatus === "mail_failed" && RESEND_FAILED_CLASS,
|
||||
)}
|
||||
|
|
@ -136,7 +151,10 @@ export function BuyerTaskGroupCard({
|
|||
type="button"
|
||||
onClick={() => onAction(group)}
|
||||
disabled={disabled}
|
||||
className={ACTION_CLASS[group.step]}
|
||||
className={cn(
|
||||
"flex-1 sm:flex-none",
|
||||
ACTION_CLASS[group.step],
|
||||
)}
|
||||
data-testid={`buyer-task-action-${group.groupId}-${group.step}`}
|
||||
>
|
||||
{ACTION_LABEL[group.step]}
|
||||
|
|
@ -144,7 +162,7 @@ export function BuyerTaskGroupCard({
|
|||
</div>
|
||||
{group.emailPayload?.sentAt ? (
|
||||
<div
|
||||
className="text-xs text-muted-foreground text-right leading-tight"
|
||||
className="text-xs text-muted-foreground text-left sm:text-right leading-tight"
|
||||
data-testid={`buyer-task-sent-info-${group.groupId}`}
|
||||
>
|
||||
{group.emailPayload.to ? (
|
||||
|
|
@ -169,12 +187,16 @@ export function BuyerTaskGroupCard({
|
|||
) : null}
|
||||
</div>
|
||||
) : (
|
||||
// needs_po / po_draft: single button (unchanged behaviour).
|
||||
// needs_po / po_draft: single button. On mobile the button
|
||||
// stretches full-width below the info column (better tap
|
||||
// target, gives the info column all the available width);
|
||||
// on `sm:` it sits inline to the right of the info.
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => onAction(group)}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
"sm:self-auto self-stretch",
|
||||
ACTION_CLASS[group.step],
|
||||
group.poStatus === "mail_failed" &&
|
||||
"bg-destructive hover:bg-destructive/90 text-destructive-foreground",
|
||||
|
|
|
|||
Loading…
Reference in a new issue