/** * Client-side utility functions for member display. */ export function computeAge(dateOfBirth: string | null | undefined): number | null { if (!dateOfBirth) return null; const birth = new Date(dateOfBirth); const today = new Date(); let age = today.getFullYear() - birth.getFullYear(); const m = today.getMonth() - birth.getMonth(); if (m < 0 || (m === 0 && today.getDate() < birth.getDate())) age--; return age; } export function computeMembershipYears(entryDate: string | null | undefined): number { if (!entryDate) return 0; const entry = new Date(entryDate); const today = new Date(); let years = today.getFullYear() - entry.getFullYear(); const m = today.getMonth() - entry.getMonth(); if (m < 0 || (m === 0 && today.getDate() < entry.getDate())) years--; return Math.max(0, years); } export function formatSalutation(salutation: string | null | undefined, firstName: string, lastName: string): string { if (salutation) return `${salutation} ${firstName} ${lastName}`; return `${firstName} ${lastName}`; } export function formatAddress(member: Record): string { const parts: string[] = []; if (member.street) { let line = String(member.street); if (member.house_number) line += ` ${member.house_number}`; parts.push(line); } if (member.street2) parts.push(String(member.street2)); if (member.postal_code || member.city) { parts.push(`${member.postal_code ?? ''} ${member.city ?? ''}`.trim()); } return parts.join(', '); } export function formatIban(iban: string | null | undefined): string { if (!iban) return '—'; const cleaned = iban.replace(/\s/g, ''); return cleaned.replace(/(.{4})/g, '$1 ').trim(); } export function getMemberStatusColor(status: string): 'default' | 'secondary' | 'destructive' | 'outline' { switch (status) { case 'active': return 'default'; case 'inactive': return 'secondary'; case 'pending': return 'outline'; case 'resigned': case 'excluded': case 'deceased': return 'destructive'; default: return 'secondary'; } } export const STATUS_LABELS: Record = { active: 'Aktiv', inactive: 'Inaktiv', pending: 'Ausstehend', resigned: 'Ausgetreten', excluded: 'Ausgeschlossen', deceased: 'Verstorben', }; export const APPLICATION_STATUS_VARIANT: Record = { submitted: 'outline', review: 'secondary', approved: 'default', rejected: 'destructive', }; export const APPLICATION_STATUS_LABEL: Record = { submitted: 'Eingereicht', review: 'In Prüfung', approved: 'Genehmigt', rejected: 'Abgelehnt', };