From 4fea42488a59c6d8d5e53ee62a44fe417a3a69b0 Mon Sep 17 00:00:00 2001 From: Quick <31828688+Quick104@users.noreply.github.com> Date: Fri, 29 May 2026 14:56:16 -0400 Subject: [PATCH] refactor(calendar): simplify preset handler and reuse storage util - Extract hardcoded trending snapshot source/window to named constants. - Collapse the three identical personal-preset nil-checks into one case. - Persist the selected preset through the shared storage util (try/catch wrapped) instead of raw localStorage with manual SSR guards. - Derive KNOWN_FILTERS from PRESET_OPTIONS so the lists can't drift. Co-Authored-By: Claude Opus 4.8 (1M context) --- internal/api/handlers/calendar.go | 30 ++++++++++++++++-------------- web/src/pages/Calendar.tsx | 14 +++++--------- web/src/utils/storage.ts | 1 + 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/internal/api/handlers/calendar.go b/internal/api/handlers/calendar.go index 9925adb8..6ead393d 100644 --- a/internal/api/handlers/calendar.go +++ b/internal/api/handlers/calendar.go @@ -45,6 +45,13 @@ const ( calendarFilterTrending = "trending" ) +// The Trending preset reads this canonical external-trending snapshot +// (see internal/sections trending snapshots). +const ( + calendarTrendingSnapshotSource = "tmdb" + calendarTrendingSnapshotWindow = "week" +) + // CalendarHandler handles the calendar endpoint. type CalendarHandler struct { repo calendarRepository @@ -179,23 +186,18 @@ func (h *CalendarHandler) resolveCalendarRestriction(ctx context.Context, filter switch filter { case calendarFilterAll, calendarFilterEverything: return false, nil, nil - case calendarFilterFollowing: + case calendarFilterFollowing, calendarFilterFavorites, calendarFilterWatchlist: if h.personal == nil { return true, nil, nil } - ids, err = h.personal.ListFollowedItemIDs(ctx, af.UserID, af.ProfileID) - return true, ids, err - case calendarFilterFavorites: - if h.personal == nil { - return true, nil, nil + switch filter { + case calendarFilterFavorites: + ids, err = h.personal.ListFavoriteItemIDs(ctx, af.UserID, af.ProfileID) + case calendarFilterWatchlist: + ids, err = h.personal.ListWatchlistItemIDs(ctx, af.UserID, af.ProfileID) + default: // following + ids, err = h.personal.ListFollowedItemIDs(ctx, af.UserID, af.ProfileID) } - ids, err = h.personal.ListFavoriteItemIDs(ctx, af.UserID, af.ProfileID) - return true, ids, err - case calendarFilterWatchlist: - if h.personal == nil { - return true, nil, nil - } - ids, err = h.personal.ListWatchlistItemIDs(ctx, af.UserID, af.ProfileID) return true, ids, err case calendarFilterPopular: if h.popular == nil { @@ -214,7 +216,7 @@ func (h *CalendarHandler) resolveCalendarRestriction(ctx context.Context, filter if h.trending == nil { return true, nil, nil } - snap, ok, err := h.trending.Get(ctx, "tmdb", "week") + snap, ok, err := h.trending.Get(ctx, calendarTrendingSnapshotSource, calendarTrendingSnapshotWindow) if err != nil { return true, nil, err } diff --git a/web/src/pages/Calendar.tsx b/web/src/pages/Calendar.tsx index 7eff7edf..a4635941 100644 --- a/web/src/pages/Calendar.tsx +++ b/web/src/pages/Calendar.tsx @@ -16,6 +16,7 @@ import { useUserLibraries } from "@/hooks/queries/libraries"; import WeekNavigator from "@/components/calendar/WeekNavigator"; import DayGroup from "@/components/calendar/DayGroup"; import { addWeeks, formatDayHeading, getWeekDays, getWeekStart } from "@/lib/calendarWeek"; +import { storage } from "@/utils/storage"; type CalendarFilter = "following" | "popular" | "trending" | "everything"; @@ -29,13 +30,10 @@ const PRESET_OPTIONS: { value: CalendarFilter; label: string }[] = [ ]; const DEFAULT_PRESET: CalendarFilter = "following"; -const PRESET_STORAGE_KEY = "calendar:preset"; -// Accept the four presets plus legacy server values so old shared links keep working. +// The selectable presets plus legacy server values so old shared links keep working. const KNOWN_FILTERS = new Set([ - "following", - "trending", - "everything", + ...PRESET_OPTIONS.map((o) => o.value), "all", "favorites", "watchlist", @@ -46,16 +44,14 @@ const CALENDAR_SKELETON_DAY_ROWS = 7; const CALENDAR_SKELETON_ITEMS_PER_ROW = 18; function readStoredPreset(): CalendarFilter { - if (typeof window === "undefined") return DEFAULT_PRESET; - const stored = window.localStorage.getItem(PRESET_STORAGE_KEY); + const stored = storage.get(storage.KEYS.CALENDAR_PRESET); return stored && PRESET_OPTIONS.some((o) => o.value === stored) ? (stored as CalendarFilter) : DEFAULT_PRESET; } function writeStoredPreset(value: string) { - if (typeof window === "undefined") return; - window.localStorage.setItem(PRESET_STORAGE_KEY, value); + storage.set(storage.KEYS.CALENDAR_PRESET, value); } function parseCalendarParams(searchParams: URLSearchParams) { diff --git a/web/src/utils/storage.ts b/web/src/utils/storage.ts index da1280a7..6241a32f 100644 --- a/web/src/utils/storage.ts +++ b/web/src/utils/storage.ts @@ -13,6 +13,7 @@ const STORAGE_KEYS = { UI_HIGH_CONTRAST: "silo-ui-high-contrast", UI_CUSTOM_THEME_VARS: "silo-custom-theme-vars", UI_CUSTOM_CSS: "silo-custom-css", + CALENDAR_PRESET: "calendar:preset", } as const; type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS];