Files
familienarchiv/frontend/src/lib/person/personFormat.ts
Marcel 507fa088fd refactor(document): move statusDotClass and statusLabel to document domain
These functions describe DocumentStatus display logic (dot colours, readable
labels) and belong in the document domain. They were incorrectly placed in
personFormat.ts. Moving them to documentStatusLabel.ts removes the
person → document dependency and prepares the codebase for the
boundaries/dependencies ESLint rule.

Refs #410
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 18:09:01 +02:00

76 lines
2.2 KiB
TypeScript

import { formatDate } from '$lib/shared/utils/date';
type Person = { firstName?: string | null; lastName: string; displayName: string };
type DocForMeta = {
sender?: Person | null;
receivers?: Person[];
documentDate?: string | null;
};
const AVATAR_PALETTE = ['#012851', '#5A3080', '#007596', '#2A6040', '#803020'] as const;
function djb2(str: string): number {
let hash = 5381;
for (let i = 0; i < str.length; i++) {
hash = (hash * 33) ^ str.charCodeAt(i);
}
return Math.abs(hash);
}
export function getInitials(name: string): string {
const words = name.trim().split(/\s+/).filter(Boolean);
if (words.length === 0) return '';
if (words.length === 1) return words[0].charAt(0).toUpperCase();
return (words[0].charAt(0) + words[words.length - 1].charAt(0)).toUpperCase();
}
export function abbreviateName(person: Person): string {
if (!person.firstName) return person.lastName;
const first = person.firstName.trim();
const last = person.lastName.trim();
if (!last) return first;
return `${first.charAt(0)}. ${last}`;
}
function abbreviateCompact(person: Person): string {
if (!person.firstName) return person.lastName;
const first = person.firstName.trim();
const last = person.lastName.trim();
if (!last) return first;
return `${first.charAt(0)}.${last}`;
}
export function formatXsMeta(doc: DocForMeta): string {
const parts: string[] = [];
const receivers = doc.receivers ?? [];
if (doc.sender) {
const senderAbbr = abbreviateCompact(doc.sender);
if (receivers.length === 0) {
parts.push(senderAbbr);
} else {
const extra = receivers.length - 1;
const firstReceiver = abbreviateCompact(receivers[0]);
parts.push(
extra > 0
? `${senderAbbr}${firstReceiver} +${extra}`
: `${senderAbbr}${firstReceiver}`
);
}
} else if (receivers.length > 0) {
const extra = receivers.length - 1;
const firstReceiver = abbreviateCompact(receivers[0]);
parts.push(extra > 0 ? `${firstReceiver} +${extra}` : firstReceiver);
}
if (doc.documentDate) {
parts.push(formatDate(doc.documentDate, 'short'));
}
return parts.join(' · ');
}
export function personAvatarColor(personId: string): string {
return AVATAR_PALETTE[djb2(personId) % AVATAR_PALETTE.length];
}