feat: add app section visibility settings
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s

This commit is contained in:
zv
2026-06-14 17:38:54 +02:00
parent 9087e1215c
commit 8bbd9397a1
6 changed files with 114 additions and 7 deletions

46
lib/app-sections.ts Normal file
View File

@@ -0,0 +1,46 @@
import type { TranslationKey } from "@/lib/i18n";
export const APP_SECTION_SETTINGS = [
{
id: "warnings",
href: "/warnings",
titleKey: "settings.appSections.warnings.title",
descriptionKey: "settings.appSections.warnings.description",
defaultVisible: true,
},
{
id: "hydro",
href: "/hydro",
titleKey: "settings.appSections.hydro.title",
descriptionKey: "settings.appSections.hydro.description",
defaultVisible: false,
},
] as const satisfies ReadonlyArray<{
id: string;
href: string;
titleKey: TranslationKey;
descriptionKey: TranslationKey;
defaultVisible: boolean;
}>;
export type AppSectionId = typeof APP_SECTION_SETTINGS[number]["id"];
export type AppSectionVisibility = Record<AppSectionId, boolean>;
export const DEFAULT_APP_SECTION_VISIBILITY = APP_SECTION_SETTINGS.reduce((visibility, section) => ({
...visibility,
[section.id]: section.defaultVisible,
}), {} as AppSectionVisibility);
export function normalizeAppSectionVisibility(value: unknown): AppSectionVisibility {
const stored = value && typeof value === "object" ? value as Partial<Record<AppSectionId, unknown>> : {};
return APP_SECTION_SETTINGS.reduce((visibility, section) => ({
...visibility,
[section.id]: typeof stored[section.id] === "boolean" ? stored[section.id] : section.defaultVisible,
}), {} as AppSectionVisibility);
}
export function isAppNavItemVisible(href: string, visibility: AppSectionVisibility) {
const section = APP_SECTION_SETTINGS.find((candidate) => candidate.href === href);
return section ? visibility[section.id] : true;
}

View File

@@ -32,6 +32,12 @@ const translations = {
"settings.dashboardSections.weatherBrief.description": "Pokazuje deterministyczne podsumowanie dnia i krótką prognozę na jutro.",
"settings.dashboardSections.featuredStations.title": "Szybki wybór",
"settings.dashboardSections.featuredStations.description": "Pokazuje listę popularnych lokalizacji na dole strony głównej.",
"settings.appSections.title": "Sekcje aplikacji",
"settings.appSections.description": "Wybierz, które dodatkowe widoki mają być widoczne w nawigacji.",
"settings.appSections.warnings.title": "Ostrzeżenia",
"settings.appSections.warnings.description": "Pokazuje widok oficjalnych ostrzeżeń IMGW w głównej nawigacji.",
"settings.appSections.hydro.title": "Hydro",
"settings.appSections.hydro.description": "Pokazuje widok monitoringu hydrologicznego IMGW w głównej nawigacji.",
"settings.units.temperature.title": "Jednostka temperatury",
"settings.units.temperature.description": "Stosowana w prognozie, briefach, powiadomieniach i bieżących pomiarach na tym urządzeniu.",
"settings.units.temperature.label": "Wybierz jednostkę temperatury",
@@ -295,6 +301,12 @@ const translations = {
"settings.dashboardSections.weatherBrief.description": "Shows the deterministic daily summary and a short forecast for tomorrow.",
"settings.dashboardSections.featuredStations.title": "Quick select",
"settings.dashboardSections.featuredStations.description": "Shows the popular locations list at the bottom of the home screen.",
"settings.appSections.title": "App sections",
"settings.appSections.description": "Choose which additional views are visible in navigation.",
"settings.appSections.warnings.title": "Warnings",
"settings.appSections.warnings.description": "Shows the official IMGW warnings view in main navigation.",
"settings.appSections.hydro.title": "Hydro",
"settings.appSections.hydro.description": "Shows the IMGW hydrological monitoring view in main navigation.",
"settings.units.temperature.title": "Temperature unit",
"settings.units.temperature.description": "Used in forecasts, briefs, notifications and current readings on this device.",
"settings.units.temperature.label": "Choose temperature unit",

View File

@@ -5,6 +5,7 @@ import { persist } from "zustand/middleware";
import type { SelectedLocation } from "@/types/location";
import type { Province } from "@/types/province";
import type { TemperatureUnit, WindSpeedUnit } from "@/types/units";
import { DEFAULT_APP_SECTION_VISIBILITY, normalizeAppSectionVisibility, type AppSectionId, type AppSectionVisibility } from "@/lib/app-sections";
import { DEFAULT_DASHBOARD_SECTION_VISIBILITY, normalizeDashboardSectionVisibility, type DashboardSectionId, type DashboardSectionVisibility } from "@/lib/dashboard-sections";
import { DEFAULT_TEMPERATURE_UNIT, DEFAULT_WIND_SPEED_UNIT } from "@/lib/weather-utils";
import type { WeatherRegion } from "@/types/weather-region";
@@ -24,6 +25,7 @@ interface WeatherStore {
temperatureUnit: TemperatureUnit;
windSpeedUnit: WindSpeedUnit;
dashboardSections: DashboardSectionVisibility;
appSections: AppSectionVisibility;
toggleFavorite: (id: string) => void;
selectStation: (id: string) => void;
selectLocation: (location: SelectedLocation) => void;
@@ -35,6 +37,7 @@ interface WeatherStore {
setTemperatureUnit: (unit: TemperatureUnit) => void;
setWindSpeedUnit: (unit: WindSpeedUnit) => void;
setDashboardSectionVisible: (section: DashboardSectionId, visible: boolean) => void;
setAppSectionVisible: (section: AppSectionId, visible: boolean) => void;
}
export const useWeatherStore = create<WeatherStore>()(
@@ -51,6 +54,7 @@ export const useWeatherStore = create<WeatherStore>()(
temperatureUnit: DEFAULT_TEMPERATURE_UNIT,
windSpeedUnit: DEFAULT_WIND_SPEED_UNIT,
dashboardSections: DEFAULT_DASHBOARD_SECTION_VISIBILITY,
appSections: DEFAULT_APP_SECTION_VISIBILITY,
toggleFavorite: (id) =>
set((state) => ({
favorites: state.favorites.includes(id)
@@ -69,6 +73,9 @@ export const useWeatherStore = create<WeatherStore>()(
setDashboardSectionVisible: (section, visible) => set((state) => ({
dashboardSections: { ...state.dashboardSections, [section]: visible },
})),
setAppSectionVisible: (section, visible) => set((state) => ({
appSections: { ...state.appSections, [section]: visible },
})),
}),
{
name: "wtr:preferences",
@@ -77,12 +84,14 @@ export const useWeatherStore = create<WeatherStore>()(
const location = state?.selectedLocation as (Partial<SelectedLocation> & { region?: WeatherRegion }) | null | undefined;
if (!state) return persisted;
const dashboardSections = normalizeDashboardSectionVisibility(state.dashboardSections);
if (!location) return { ...state, dashboardSections };
const appSections = normalizeAppSectionVisibility(state.appSections);
if (!location) return { ...state, dashboardSections, appSections };
const countryCode = location.countryCode ?? (location.province ? "PL" : null);
const region = location.region ?? getWeatherRegionForCountryCode(countryCode);
return {
...state,
dashboardSections,
appSections,
selectedLocation: {
...location,
country: location.country ?? (countryCode === "PL" ? "Polska" : null),