refactor: route localStorage access through shared LocalStorageService

Sprint 2 high-priority cleanup: cart/language/location services called
localStorage directly, bypassing the try/catch safety and core/<domain>
pattern used elsewhere (e.g. ProjectEditorDraftStorageService). New
core/storage/LocalStorageService centralizes get/set/remove and JSON
helpers with private-mode/quota error handling, reused across all three.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-07-15 02:58:39 +04:00
parent 96a338ef6f
commit 3cf732797c
4 changed files with 73 additions and 21 deletions

View File

@@ -0,0 +1,53 @@
import { Injectable } from '@angular/core';
/**
* Safe wrapper around window.localStorage — swallows quota/private-mode
* errors instead of throwing, so callers don't each need their own try/catch.
*/
@Injectable({ providedIn: 'root' })
export class LocalStorageService {
getItem(key: string): string | null {
try {
return typeof localStorage !== 'undefined' ? localStorage.getItem(key) : null;
} catch {
return null;
}
}
setItem(key: string, value: string): void {
try {
if (typeof localStorage !== 'undefined') {
localStorage.setItem(key, value);
}
} catch {
// storage unavailable (private mode / quota) - value simply won't persist
}
}
removeItem(key: string): void {
try {
if (typeof localStorage !== 'undefined') {
localStorage.removeItem(key);
}
} catch {
// ignore
}
}
getJSON<T>(key: string): T | null {
const raw = this.getItem(key);
if (!raw) {
return null;
}
try {
return JSON.parse(raw) as T;
} catch {
this.removeItem(key);
return null;
}
}
setJSON<T>(key: string, value: T): void {
this.setItem(key, JSON.stringify(value));
}
}