hellth-hub/apps/admin/lib/hellth/storage.ts

162 lines
5.2 KiB
TypeScript
Raw Permalink Normal View History

Refactor: God-Router + Frontend-Lib in Domain-Module aufgeteilt Router-Split (packages/api/src/trpc/routers/health/): - health.ts (2061 Zeilen Monolith) entfernt und in 6 Sub-Router aufgeteilt: - dashboard.ts (overview, profile, goals, point settings) - foods.ts (foods, nutrition, OpenFoodFacts, food preferences) - recipes.ts (recipes, submissions, reviews, activity feed) - stores.ts (stores, change-requests, shopping lists) - tracking.ts (meals, drinks, weight, mealPlans, activities, leaderboard) - community.ts (club, wearables, coach, stats) - index.ts mergt alle Sub-Router via mergeRouters, sodass Frontend-Aufrufe (trpc.health.listFoods etc.) unveraendert weiterfunktionieren. - t.mergeRouters in init.ts exportiert. Frontend-Lib-Split (apps/admin/lib/hellth/): - hellth-data.ts (1149 Zeilen Monolith) in 5 Domain-Module aufgeteilt: - types.ts (alle TypeScript-Types) - constants.ts (Seeds, Defaults, todayKey, uid) - nutrition.ts (calcRecipe, classifyRecipe, parseNutritionLabel, ...) - storage.ts (load/save HellthData, ClubData, hasCompletedHealthProfile) - stats.ts (Budget, Stats, Coach, Shopping, Weight-Projection) - hellth-data.ts wird zum reinen Re-Export-Index, damit bestehende Imports `from "@/lib/hellth-data"` unveraendert weiterfunktionieren. Funktional identisch zum Original - reine Code-Reorganisation. Verifiziert: 28 API-Tests + 10 Admin-Tests gruen, Typecheck (3 Packages) gruen, Admin-Build (26 Pages) gruen. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 01:09:53 +02:00
import {
HELLTH_CLUB_KEY,
HELLTH_DATA_KEY,
defaultClubProfile,
defaultGoals,
defaultReminderSettings,
seedActivityTemplates,
seedFoods,
seedPlannedMeals,
seedRecipes,
seedStores,
} from "./constants";
import type { ClubData, HellthData } from "./types";
export function defaultHellthData(): HellthData {
return {
stores: seedStores,
foods: seedFoods,
recipes: seedRecipes,
recipeRatings: [],
plannedMeals: seedPlannedMeals,
shoppingItems: [],
goals: defaultGoals,
coachRecommendations: [],
reminders: defaultReminderSettings,
activityTemplates: seedActivityTemplates,
activityLogs: [],
weeklyCaloriePlans: [],
};
}
function scopedStorageKey(baseKey: string, userKey?: string | null) {
const normalized = userKey?.trim().toLowerCase();
return normalized ? `${baseKey}:${normalized}` : baseKey;
}
export function hellthDataStorageKey(userKey?: string | null) {
return scopedStorageKey(HELLTH_DATA_KEY, userKey);
}
function migrateGlobalDataToUserKey(userKey: string) {
if (typeof window === "undefined") return;
const scopedKey = hellthDataStorageKey(userKey);
if (window.localStorage.getItem(scopedKey)) return;
const globalData = window.localStorage.getItem(HELLTH_DATA_KEY);
if (globalData) {
window.localStorage.setItem(scopedKey, globalData);
}
}
export function loadHellthData(userKey?: string | null): HellthData {
if (typeof window === "undefined") return defaultHellthData();
try {
if (userKey) migrateGlobalDataToUserKey(userKey);
const raw = window.localStorage.getItem(hellthDataStorageKey(userKey));
if (!raw) return defaultHellthData();
const parsed = JSON.parse(raw) as Partial<HellthData>;
return {
stores: parsed.stores?.length ? parsed.stores : seedStores,
foods: parsed.foods?.length ? parsed.foods : seedFoods,
recipes: parsed.recipes?.length ? parsed.recipes : seedRecipes,
recipeRatings: parsed.recipeRatings ?? [],
plannedMeals: parsed.plannedMeals ?? seedPlannedMeals,
shoppingItems: parsed.shoppingItems ?? [],
goals: { ...defaultGoals, ...parsed.goals },
healthProfile: parsed.healthProfile,
coachRecommendations: parsed.coachRecommendations ?? [],
reminders: {
...defaultReminderSettings,
...parsed.reminders,
rules: {
water: { ...defaultReminderSettings.rules.water, ...parsed.reminders?.rules?.water },
snack: { ...defaultReminderSettings.rules.snack, ...parsed.reminders?.rules?.snack },
movement: { ...defaultReminderSettings.rules.movement, ...parsed.reminders?.rules?.movement },
},
},
activityTemplates: parsed.activityTemplates?.length ? parsed.activityTemplates : seedActivityTemplates,
activityLogs: parsed.activityLogs ?? [],
weeklyCaloriePlans: parsed.weeklyCaloriePlans ?? [],
};
} catch {
return defaultHellthData();
}
}
export function saveHellthData(data: HellthData, userKey?: string | null) {
if (typeof window === "undefined") return;
window.localStorage.setItem(hellthDataStorageKey(userKey), JSON.stringify(data));
}
export function hasCompletedHealthProfile(userKey?: string | null) {
return Boolean(loadHellthData(userKey).healthProfile?.completedAt);
}
import { todayKey } from "./constants";
export function defaultClubData(): ClubData {
const today = todayKey();
return {
profile: defaultClubProfile,
activities: [
{
id: "club-sebastian-walk",
title: "Eine Stunde spazieren gehen",
hostUserKey: "seed-sebastian",
hostName: "Sebastian",
category: "walk",
scope: "state",
state: "Bayern",
city: "Augsburg",
locationLabel: "Bayern",
startsAt: `${today}T18:00:00`,
durationMinutes: 60,
points: 100,
note: "Lockerer Spaziergang nach Feierabend. Jeder geht für sich, aber wir starten gemeinsam.",
participants: [
{
userKey: "seed-sebastian",
displayName: "Sebastian",
joinedAt: `${today}T10:00:00`,
},
],
},
{
id: "club-mobility",
title: "5 Minuten Dehnübungen",
hostUserKey: "seed-hellth",
hostName: "Hellth Coach",
category: "mobility",
scope: "nationwide",
state: "Bayern",
locationLabel: "Deutschlandweit",
startsAt: `${today}T15:00:00`,
durationMinutes: 5,
points: 20,
note: "Kurze Schreibtischpause. Matte nicht nötig.",
participants: [],
},
],
};
}
export function loadClubData(): ClubData {
if (typeof window === "undefined") return defaultClubData();
try {
const raw = window.localStorage.getItem(HELLTH_CLUB_KEY);
if (!raw) return defaultClubData();
const parsed = JSON.parse(raw) as Partial<ClubData>;
return {
profile: { ...defaultClubProfile, ...parsed.profile },
activities: parsed.activities?.length ? parsed.activities : defaultClubData().activities,
};
} catch {
return defaultClubData();
}
}
export function saveClubData(data: ClubData) {
if (typeof window === "undefined") return;
window.localStorage.setItem(HELLTH_CLUB_KEY, JSON.stringify(data));
}