diff --git a/src/components/clients/client-detail-header.tsx b/src/components/clients/client-detail-header.tsx index becfbc4..efe9ab8 100644 --- a/src/components/clients/client-detail-header.tsx +++ b/src/components/clients/client-detail-header.tsx @@ -2,7 +2,8 @@ import { useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { Archive, RotateCcw, Mail, Phone } from 'lucide-react'; +import { Archive, Mail, MessageCircle, Phone, RotateCcw } from 'lucide-react'; +import { format } from 'date-fns'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; @@ -12,31 +13,28 @@ import { DetailHeaderStrip } from '@/components/shared/detail-header-strip'; import { PortalInviteButton } from '@/components/clients/portal-invite-button'; import { GdprExportButton } from '@/components/clients/gdpr-export-button'; import { apiFetch } from '@/lib/api/client'; +import { cn } from '@/lib/utils'; +import { getCountryName } from '@/lib/i18n/countries'; interface ClientDetailHeaderProps { client: { id: string; fullName: string; - nationality?: string | null; - preferredContactMethod?: string | null; - preferredLanguage?: string | null; - timezone?: string | null; - source?: string | null; - sourceDetails?: string | null; + nationalityIso?: string | null; archivedAt?: string | null; - contacts?: Array<{ channel: string; value: string; isPrimary: boolean; label?: string | null }>; + createdAt?: string; + contacts?: Array<{ + channel: string; + value: string; + valueE164?: string | null; + isPrimary: boolean; + label?: string | null; + }>; tags?: Array<{ id: string; name: string; color: string }>; clientPortalEnabled?: boolean; }; } -const SOURCE_LABELS: Record = { - website: 'Website', - manual: 'Manual', - referral: 'Referral', - broker: 'Broker', -}; - export function ClientDetailHeader({ client }: ClientDetailHeaderProps) { const queryClient = useQueryClient(); const [archiveOpen, setArchiveOpen] = useState(false); @@ -62,19 +60,34 @@ export function ClientDetailHeader({ client }: ClientDetailHeaderProps) { }); const primaryEmail = - client.contacts?.find((c) => c.channel === 'email' && c.isPrimary) ?? - client.contacts?.find((c) => c.channel === 'email'); - const primaryPhone = + client.contacts?.find((c) => c.channel === 'email' && c.isPrimary)?.value ?? + client.contacts?.find((c) => c.channel === 'email')?.value; + const primaryPhoneContact = client.contacts?.find((c) => c.channel === 'phone' && c.isPrimary) ?? client.contacts?.find((c) => c.channel === 'phone'); + const primaryPhone = primaryPhoneContact?.value; + // wa.me requires the E.164 number without the leading "+". Strip from the + // canonical E.164 form when available; otherwise strip non-digits from the + // display value as a best-effort fallback. + const whatsappNumber = primaryPhoneContact?.valueE164 + ? primaryPhoneContact.valueE164.replace(/^\+/, '') + : primaryPhoneContact?.value + ? primaryPhoneContact.value.replace(/[^\d]/g, '') + : null; + + const country = client.nationalityIso ? getCountryName(client.nationalityIso, 'en') : null; + const addedLabel = client.createdAt + ? `Added ${format(new Date(client.createdAt), 'MMM d, yyyy')}` + : null; + const meta = [country, addedLabel].filter(Boolean) as string[]; return ( <> -
-
+
+
-

+

{client.fullName}

{isArchived && ( @@ -84,31 +97,71 @@ export function ClientDetailHeader({ client }: ClientDetailHeaderProps) { )}
-
- {client.source && ( - - Source:{' '} - - {SOURCE_LABELS[client.source] ?? client.source} - - - )} - {primaryEmail && ( - - - {primaryEmail.value} - - )} - {primaryPhone && ( - - - {primaryPhone.value} - - )} + {meta.length > 0 ? ( +

{meta.join(' · ')}

+ ) : null} + +
+ {primaryEmail ? ( + + ) : null} + {primaryPhone ? ( + + ) : null} + {whatsappNumber ? ( + + ) : null} + {!isArchived && client.clientPortalEnabled !== false ? ( +
+ +
+ ) : null} +
+ +
{client.tags && client.tags.length > 0 && ( -
+
{client.tags.map((tag) => ( ))} @@ -116,34 +169,21 @@ export function ClientDetailHeader({ client }: ClientDetailHeaderProps) { )}
- {/* Actions */} -
- {!isArchived && client.clientPortalEnabled !== false && ( - + {/* Top-right: archive/restore as a small icon button — destructive + action sits out of the primary action flow. */} + -
+ > + {isArchived ? : } +