feat(planner): implement C1 weekly planner home screen (#26)
Three-breakpoint layout (mobile/tablet/desktop) with VarietyScoreCard, WeekStrip, DayMealCard components. Server loads week plan and variety score via API; read-only role behavior derived from benutzer.rolle. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
88
frontend/src/lib/planner/week.ts
Normal file
88
frontend/src/lib/planner/week.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 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 (local time).
|
||||
*/
|
||||
export function isToday(dateStr: string): boolean {
|
||||
const today = new Date();
|
||||
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
|
||||
return dateStr === todayStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}`;
|
||||
}
|
||||
Reference in New Issue
Block a user