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:
@@ -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} />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user