Files
berichtsheftgenerator/web/src/lib/storage.ts
T
2026-07-26 18:11:57 +02:00

117 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
firstOpenDay,
getFriday,
getMonday,
getWeekNumber,
getYearLabel,
weekNeedsSchool,
} from "./calendar";
import { START_WEEK_NUMBER, TRAINEE } from "../data/holidays-bw";
import { WEEK_THEMES } from "../data/suggestions";
export type WeekEntry = {
number: number;
yearLabel: string;
from: string;
to: string;
/** Flat weekly activity bullets (like original hefte) */
activities: string[];
frameworkRefs: string[];
weekTheme: string;
schoolTopics: string[];
done: boolean;
};
export type AppState = {
/** Monday of the current open week */
currentWeekMonday: string;
weeks: Record<string, WeekEntry>;
usedSuggestionIds: number[];
};
/** Stable localStorage key bump suffix only when AppState shape breaks compatibility. */
export const STORAGE_KEY = "berichtsheft-generator-v2";
/** Legacy key cleared on reset so old drafts do not linger. */
export const STORAGE_KEY_LEGACY = "berichtsheft-generator-v1";
const DEFAULT_FRAMEWORK = ["1.1", "1.2", "1.4", "2.1", "2.2", "2.3", "2.5", "4.4"];
export function pickTheme(exclude?: string): string {
const pool = WEEK_THEMES.filter((t) => t !== exclude);
const src = pool.length ? pool : WEEK_THEMES;
return src[Math.floor(Math.random() * src.length)] || "Büroabläufe";
}
export function createEmptyWeek(monday: string): WeekEntry {
return {
number: getWeekNumber(monday) || START_WEEK_NUMBER,
yearLabel: getYearLabel(monday),
from: monday,
to: getFriday(monday),
activities: [],
frameworkRefs: [...DEFAULT_FRAMEWORK],
weekTheme: pickTheme(),
schoolTopics: weekNeedsSchool(monday) ? [] : ["Ferien"],
done: false,
};
}
export function defaultState(): AppState {
const monday = getMonday(firstOpenDay());
return {
currentWeekMonday: monday,
weeks: { [monday]: createEmptyWeek(monday) },
usedSuggestionIds: [],
};
}
export function loadState(): AppState {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return defaultState();
const parsed = JSON.parse(raw) as AppState;
if (!parsed.currentWeekMonday) return defaultState();
return {
...defaultState(),
...parsed,
weeks: parsed.weeks ?? {},
usedSuggestionIds: parsed.usedSuggestionIds ?? [],
};
} catch {
return defaultState();
}
}
export function saveState(state: AppState): void {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
}
export function ensureWeek(state: AppState, monday: string): WeekEntry {
if (!state.weeks[monday]) {
state.weeks[monday] = createEmptyWeek(monday);
}
return state.weeks[monday];
}
export function getTrainee() {
return TRAINEE;
}
export function nextWeekMonday(monday: string): string {
const d = new Date(monday + "T12:00:00");
d.setDate(d.getDate() + 7);
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
}
export function prevWeekMonday(monday: string): string {
const d = new Date(monday + "T12:00:00");
d.setDate(d.getDate() - 7);
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
}