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>
76 lines
2.2 KiB
TypeScript
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];
|
|
}
|