This commit is contained in:
2026-07-26 18:11:57 +02:00
parent d408e01ab5
commit 21a3b34471
139 changed files with 32872 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
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}`;
}