style(detail): apply gradient header strip to client/interest/yacht/company/berth/residential/invoice details

Adds shared <DetailHeaderStrip> wrapper (rounded-xl + gradient-brand-soft + shadow-xs)
and applies it to every legacy domain detail header. Residential client/interest and
invoice detail get an inline gradient strip with eyebrow ('Residential Client',
'Residential Interest', 'Invoice'). Residential bodies normalized to lg:grid-cols-[2fr_1fr]
per spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt Ciaccio
2026-04-28 12:09:47 +02:00
parent cda44e721b
commit 22f944fde2
9 changed files with 81 additions and 59 deletions

View File

@@ -24,6 +24,7 @@ import {
SelectValue,
} from '@/components/ui/select';
import { Textarea } from '@/components/ui/textarea';
import { DetailHeaderStrip } from '@/components/shared/detail-header-strip';
import { PermissionGate } from '@/components/shared/permission-gate';
import { BerthForm } from './berth-form';
import { apiFetch } from '@/lib/api/client';
@@ -94,7 +95,7 @@ function StatusChangeDialog({
formState: { isSubmitting },
} = useForm<UpdateBerthStatusInput>({
resolver: zodResolver(updateBerthStatusSchema),
defaultValues: { status: currentStatus as typeof BERTH_STATUSES[number], reason: '' },
defaultValues: { status: currentStatus as (typeof BERTH_STATUSES)[number], reason: '' },
});
const status = watch('status');
@@ -127,7 +128,7 @@ function StatusChangeDialog({
<Label>New Status</Label>
<Select
value={status}
onValueChange={(v) => setValue('status', v as typeof BERTH_STATUSES[number])}
onValueChange={(v) => setValue('status', v as (typeof BERTH_STATUSES)[number])}
>
<SelectTrigger>
<SelectValue />
@@ -143,11 +144,7 @@ function StatusChangeDialog({
</div>
<div className="space-y-2">
<Label>Reason *</Label>
<Textarea
{...register('reason')}
placeholder="Reason for status change..."
rows={3}
/>
<Textarea {...register('reason')} placeholder="Reason for status change..." rows={3} />
</div>
<DialogFooter>
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
@@ -169,22 +166,18 @@ export function BerthDetailHeader({ berth }: BerthDetailHeaderProps) {
return (
<>
<div className="space-y-3">
<DetailHeaderStrip>
<div className="flex items-start gap-4">
<div className="flex-1 min-w-0">
<div className="flex items-center gap-3 flex-wrap">
<h1 className="text-2xl font-bold text-foreground">
Berth {berth.mooringNumber}
</h1>
<h1 className="text-2xl font-bold text-foreground">Berth {berth.mooringNumber}</h1>
<span
className={`inline-flex items-center rounded-full border px-3 py-1 text-sm font-medium ${STATUS_COLORS[berth.status] ?? 'bg-muted text-muted-foreground border-muted'}`}
>
{STATUS_LABELS[berth.status] ?? berth.status}
</span>
</div>
{berth.area && (
<p className="text-muted-foreground mt-1">{berth.area}</p>
)}
{berth.area && <p className="text-muted-foreground mt-1">{berth.area}</p>}
</div>
<div className="flex items-center gap-2 shrink-0">
@@ -200,7 +193,7 @@ export function BerthDetailHeader({ berth }: BerthDetailHeaderProps) {
</PermissionGate>
</div>
</div>
</div>
</DetailHeaderStrip>
<BerthForm berth={berth} open={editOpen} onOpenChange={setEditOpen} />