a982d9a669
- 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.
92 lines
2.3 KiB
TypeScript
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
|
|
}
|
|
},
|
|
};
|