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

@@ -9,6 +9,7 @@ import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { TagBadge } from '@/components/shared/tag-badge';
import { ArchiveConfirmDialog } from '@/components/shared/archive-confirm-dialog';
import { DetailHeaderStrip } from '@/components/shared/detail-header-strip';
import { PermissionGate } from '@/components/shared/permission-gate';
import { InterestForm } from '@/components/interests/interest-form';
import { InterestStagePicker } from '@/components/interests/interest-stage-picker';
@@ -70,8 +71,7 @@ export function InterestDetailHeader({ portSlug, interest }: InterestDetailHeade
const isArchived = !!interest.archivedAt;
const archiveMutation = useMutation({
mutationFn: () =>
apiFetch(`/api/v1/interests/${interest.id}`, { method: 'DELETE' }),
mutationFn: () => apiFetch(`/api/v1/interests/${interest.id}`, { method: 'DELETE' }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['interests', interest.id] });
queryClient.invalidateQueries({ queryKey: ['interests'] });
@@ -80,8 +80,7 @@ export function InterestDetailHeader({ portSlug, interest }: InterestDetailHeade
});
const restoreMutation = useMutation({
mutationFn: () =>
apiFetch(`/api/v1/interests/${interest.id}/restore`, { method: 'POST' }),
mutationFn: () => apiFetch(`/api/v1/interests/${interest.id}/restore`, { method: 'POST' }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['interests', interest.id] });
queryClient.invalidateQueries({ queryKey: ['interests'] });
@@ -91,7 +90,7 @@ export function InterestDetailHeader({ portSlug, interest }: InterestDetailHeade
return (
<>
<div className="space-y-3">
<DetailHeaderStrip>
<div className="flex items-start gap-3 flex-wrap">
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap">
@@ -99,7 +98,9 @@ export function InterestDetailHeader({ portSlug, interest }: InterestDetailHeade
{interest.clientName ?? 'Unknown Client'}
</h1>
{isArchived && (
<Badge variant="secondary" className="text-xs">Archived</Badge>
<Badge variant="secondary" className="text-xs">
Archived
</Badge>
)}
<span
className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-sm font-medium ${STAGE_COLORS[interest.pipelineStage] ?? 'bg-gray-100 text-gray-700'}`}
@@ -130,8 +131,7 @@ export function InterestDetailHeader({ portSlug, interest }: InterestDetailHeade
)}
{interest.source && (
<span>
Source:{' '}
<span className="text-foreground capitalize">{interest.source}</span>
Source: <span className="text-foreground capitalize">{interest.source}</span>
</span>
)}
</div>
@@ -176,7 +176,7 @@ export function InterestDetailHeader({ portSlug, interest }: InterestDetailHeade
</PermissionGate>
</div>
</div>
</div>
</DetailHeaderStrip>
<InterestForm
open={editOpen}