108 lines
3.5 KiB
TypeScript
108 lines
3.5 KiB
TypeScript
/**
|
||
* Returns the ISO Monday (YYYY-MM-DD) for the week containing `date`.
|
||
*/
|
||
export function getWeekStart(date: Date): string {
|
||
const d = new Date(date);
|
||
const day = d.getUTCDay(); // 0=Sun, 1=Mon, …
|
||
const diff = day === 0 ? -6 : 1 - day; // shift to Monday
|
||
d.setUTCDate(d.getUTCDate() + diff);
|
||
return d.toISOString().slice(0, 10);
|
||
}
|
||
|
||
/**
|
||
* Returns the Monday of the previous week relative to `weekStart`.
|
||
*/
|
||
export function prevWeek(weekStart: string): string {
|
||
const d = new Date(weekStart + 'T00:00:00Z');
|
||
d.setUTCDate(d.getUTCDate() - 7);
|
||
return d.toISOString().slice(0, 10);
|
||
}
|
||
|
||
/**
|
||
* Returns the Monday of the next week relative to `weekStart`.
|
||
*/
|
||
export function nextWeek(weekStart: string): string {
|
||
const d = new Date(weekStart + 'T00:00:00Z');
|
||
d.setUTCDate(d.getUTCDate() + 7);
|
||
return d.toISOString().slice(0, 10);
|
||
}
|
||
|
||
/**
|
||
* Formats a date string (YYYY-MM-DD) as a localized day abbreviation.
|
||
*/
|
||
export function formatDayAbbr(dateStr: string, length: 'narrow' | 'short' = 'narrow'): string {
|
||
const d = new Date(dateStr + 'T00:00:00Z');
|
||
return d.toLocaleDateString('de-DE', { weekday: length, timeZone: 'UTC' });
|
||
}
|
||
|
||
/**
|
||
* Returns an array of 7 date strings for the week starting on `weekStart`.
|
||
*/
|
||
export function weekDays(weekStart: string): string[] {
|
||
const days: string[] = [];
|
||
for (let i = 0; i < 7; i++) {
|
||
const d = new Date(weekStart + 'T00:00:00Z');
|
||
d.setUTCDate(d.getUTCDate() + i);
|
||
days.push(d.toISOString().slice(0, 10));
|
||
}
|
||
return days;
|
||
}
|
||
|
||
/**
|
||
* Formats a date string as "Mo, 30.03." style label.
|
||
*/
|
||
export function formatDayLabel(dateStr: string): string {
|
||
const d = new Date(dateStr + 'T00:00:00Z');
|
||
const day = d.toLocaleDateString('de-DE', { weekday: 'short', timeZone: 'UTC' });
|
||
const date = d.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', timeZone: 'UTC' });
|
||
return `${day}, ${date}`;
|
||
}
|
||
|
||
/**
|
||
* Formats a date string as "30. März" style label.
|
||
*/
|
||
export function formatDayFull(dateStr: string): string {
|
||
const d = new Date(dateStr + 'T00:00:00Z');
|
||
return d.toLocaleDateString('de-DE', { day: 'numeric', month: 'long', timeZone: 'UTC' });
|
||
}
|
||
|
||
/**
|
||
* Returns true if dateStr is today (UTC date).
|
||
* Uses UTC consistently with all other date functions in this module.
|
||
*/
|
||
export function isToday(dateStr: string): boolean {
|
||
const todayStr = new Date().toISOString().slice(0, 10);
|
||
return dateStr === todayStr;
|
||
}
|
||
|
||
const EFFORT_ORDER: Record<string, number> = { easy: 0, medium: 1, hard: 2 };
|
||
|
||
/**
|
||
* Returns a new array of recipes sorted easiest first (effort ASC, cookTimeMin ASC).
|
||
* Used for the J4 mid-week swap context — different from variety-first sorting in J2.
|
||
*/
|
||
export function sortEasiestFirst<T extends { effort?: string | null; cookTimeMin?: number | null }>(
|
||
recipes: T[]
|
||
): T[] {
|
||
return [...recipes].sort((a, b) => {
|
||
const ea = a.effort != null ? (EFFORT_ORDER[a.effort] ?? 99) : 99;
|
||
const eb = b.effort != null ? (EFFORT_ORDER[b.effort] ?? 99) : 99;
|
||
if (ea !== eb) return ea - eb;
|
||
const ta = a.cookTimeMin ?? Infinity;
|
||
const tb = b.cookTimeMin ?? Infinity;
|
||
return ta - tb;
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Formats a week range: "30. Mär – 5. Apr 2026".
|
||
*/
|
||
export function formatWeekRange(weekStart: string): string {
|
||
const start = new Date(weekStart + 'T00:00:00Z');
|
||
const end = new Date(weekStart + 'T00:00:00Z');
|
||
end.setUTCDate(end.getUTCDate() + 6);
|
||
const startStr = start.toLocaleDateString('de-DE', { day: 'numeric', month: 'short', timeZone: 'UTC' });
|
||
const endStr = end.toLocaleDateString('de-DE', { day: 'numeric', month: 'short', year: 'numeric', timeZone: 'UTC' });
|
||
return `${startStr} – ${endStr}`;
|
||
}
|