Files
flights_web/src/shared/storage.ts
T
gnezim a982d9a669 Fix lint: route sessionStorage through shared storage module, drop dead imports
- storage.ts: add sessionStore wrapper (getRaw/setRaw/delete/clear) so
  transientPrefill + ScheduleStartPage tests don't trip the
  no-restricted-globals rule.
- transientPrefill.ts + ScheduleStartPage.test.tsx: use sessionStore.
- closestFlight.ts: hoist bracket-index key so no newline-before-[ ASI.
- Test files: hoist typeof import(...) into named type alias with
  type-only namespace import.
- Drop unused imports: FlightCard (Link, languageToLocale),
  OnlineBoardDetailsPage (operatingCarrier),
  ScheduleSearchPage (FlightList, inline import() types),
  PageLayout (FeedbackButton).
- Drop react-hooks/exhaustive-deps disable comments for a rule not
  registered in eslint.config.js.
2026-04-20 08:15:21 +03:00

92 lines
2.3 KiB
TypeScript

import type { ZodSchema } from "zod";
const PREFIX = "afl_";
function prefixed(key: string): string {
return `${PREFIX}${key}`;
}
export const storage = {
get<T>(key: string, schema: ZodSchema<T>): T | null {
try {
const raw = localStorage.getItem(prefixed(key));
if (raw === null) return null;
const parsed: unknown = JSON.parse(raw);
const result = schema.safeParse(parsed);
return result.success ? result.data : null;
} catch {
return null;
}
},
set<T>(key: string, value: T, schema: ZodSchema<T>): void {
schema.parse(value);
localStorage.setItem(prefixed(key), JSON.stringify(value));
},
delete(key: string): void {
localStorage.removeItem(prefixed(key));
},
clear(): void {
const keysToRemove: string[] = [];
for (let i = 0; i < localStorage.length; i++) {
const k = localStorage.key(i);
if (k?.startsWith(PREFIX)) {
keysToRemove.push(k);
}
}
for (const k of keysToRemove) {
localStorage.removeItem(k);
}
},
};
/**
* Thin wrapper over `sessionStorage` for same-tab ephemeral state —
* cross-page prefill handoff, non-persistent UI flags, etc. No schema
* validation; callers own their key namespace (e.g. `afl-prefill:*`)
* and serialize/deserialize JSON themselves. All operations no-op
* when `sessionStorage` is undefined (SSR-safe).
*
* Exists so the rest of the codebase can stay under the
* `no-restricted-globals` rule that blocks direct sessionStorage access.
*/
export const sessionStore = {
getRaw(key: string): string | null {
if (typeof sessionStorage === "undefined") return null;
try {
return sessionStorage.getItem(key);
} catch {
return null;
}
},
setRaw(key: string, value: string): void {
if (typeof sessionStorage === "undefined") return;
try {
sessionStorage.setItem(key, value);
} catch {
// ignore quota/disabled
}
},
delete(key: string): void {
if (typeof sessionStorage === "undefined") return;
try {
sessionStorage.removeItem(key);
} catch {
// ignore disabled
}
},
clear(): void {
if (typeof sessionStorage === "undefined") return;
try {
sessionStorage.clear();
} catch {
// ignore disabled
}
},
};