refactor(date): consolidate formatDate in date.ts with optional format param

Add format?: 'short'|'long' (default 'long') to date.ts formatDate and
remove the duplicate from personFormat.ts. Update DocumentTopBar to
import from date.ts directly. Move the formatDate tests from
personFormat.spec to date.spec.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-15 13:10:44 +02:00
parent 76d6f234b4
commit 8be876492c
5 changed files with 35 additions and 21 deletions

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
import { slide } from 'svelte/transition';
import { formatDate } from '$lib/utils/personFormat';
import { formatDate } from '$lib/utils/date';
import { clickOutside } from '$lib/actions/clickOutside';
import PersonChipRow from './PersonChipRow.svelte';
import OverflowPillButton from './OverflowPillButton.svelte';

View File

@@ -1,5 +1,25 @@
import { describe, expect, it } from 'vitest';
import { formatGermanDateInput, isoToGerman, germanToIso } from './date';
import { formatDate, formatGermanDateInput, isoToGerman, germanToIso } from './date';
// ─── formatDate ──────────────────────────────────────────────────────────────
describe('formatDate', () => {
it('defaults to long format when no format arg is passed', () => {
expect(formatDate('1943-12-24')).toBe('24. Dezember 1943');
});
it('formats long date with German month name', () => {
expect(formatDate('1943-12-24', 'long')).toBe('24. Dezember 1943');
});
it('formats short date as dd.mm.yyyy', () => {
expect(formatDate('1943-12-24', 'short')).toBe('24.12.1943');
});
it('does not shift Dec 31 to Jan 1 (T12:00:00 UTC guard)', () => {
expect(formatDate('1943-12-31', 'short')).toBe('31.12.1943');
});
});
// ─── isoToGerman ─────────────────────────────────────────────────────────────

View File

@@ -1,13 +1,22 @@
/**
* Format an ISO date string (YYYY-MM-DD) for display.
* Uses T12:00:00 to avoid UTC timezone off-by-one when converting to local time.
* Defaults to 'long' (e.g. "24. Dezember 1943"); pass 'short' for DD.MM.YYYY.
*/
export function formatDate(isoDate: string): string {
export function formatDate(isoDate: string, format: 'short' | 'long' = 'long'): string {
const date = new Date(isoDate + 'T12:00:00');
if (format === 'short') {
return new Intl.DateTimeFormat('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
}).format(date);
}
return new Intl.DateTimeFormat('de-DE', {
day: 'numeric',
month: 'long',
year: 'numeric'
}).format(new Date(isoDate + 'T12:00:00'));
}).format(date);
}
/**

View File

@@ -4,10 +4,10 @@ import {
abbreviateName,
formatXsMeta,
personAvatarColor,
formatDate,
statusDotClass,
statusLabel
} from './personFormat';
import { formatDate } from './date';
// ─── getInitials ─────────────────────────────────────────────────────────────

View File

@@ -1,4 +1,5 @@
import { formatDocumentStatus } from './documentStatusLabel';
import { formatDate } from './date';
type Person = { firstName?: string | null; lastName: string; displayName: string };
type DocumentStatus = 'PLACEHOLDER' | 'UPLOADED' | 'TRANSCRIBED' | 'REVIEWED' | 'ARCHIVED';
@@ -75,22 +76,6 @@ export function personAvatarColor(personId: string): string {
return AVATAR_PALETTE[djb2(personId) % AVATAR_PALETTE.length];
}
export function formatDate(isoDate: string, format: 'short' | 'long'): string {
const date = new Date(isoDate + 'T12:00:00');
if (format === 'short') {
return new Intl.DateTimeFormat('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
}).format(date);
}
return new Intl.DateTimeFormat('de-DE', {
day: 'numeric',
month: 'long',
year: 'numeric'
}).format(date);
}
export function statusDotClass(status: DocumentStatus): string {
switch (status) {
case 'PLACEHOLDER':