Skip to content

Commit

Permalink
feat: add JSON-parseability to stored values that use JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
trevor-anderson committed May 13, 2023
1 parent d098432 commit a809f07
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 20 deletions.
14 changes: 7 additions & 7 deletions src/utils/__mocks__/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ beforeEach(() => {
});

export const storage = _STORAGE_KEYS.reduce(
(acc, storageKey) => ({
(acc, key) => ({
...acc,
[storageKey]: {
[key]: {
get: jest.fn(() => {
return _mockLocalStorage?.[storageKey] ?? null;
return _mockLocalStorage?.[key] ?? null;
}),
set: jest.fn((str) => {
_mockLocalStorage[storageKey] = str;
_mockLocalStorage[key] = str;
}),
setDefaultIfEmpty: jest.fn((defaultValue) => {
const currentlyStoredValue = _mockLocalStorage?.[storageKey] ?? null;
if (currentlyStoredValue === null) _mockLocalStorage[storageKey] = defaultValue;
const currentlyStoredValue = _mockLocalStorage?.[key] ?? null;
if (currentlyStoredValue === null) _mockLocalStorage[key] = defaultValue;
}),
remove: jest.fn((str) => {
delete _mockLocalStorage[storageKey];
delete _mockLocalStorage[key];
}),
},
}),
Expand Down
47 changes: 34 additions & 13 deletions src/utils/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@ import { logger } from "./logger";
import { getTypeSafeErr } from "./typeSafety";
import type { Simplify } from "type-fest";

export const _STORAGE_KEYS = ["authToken", "checkoutValues", "preferredTheme"] as const;
export type LocalStorageWrapperKey = "authToken" | "preferredTheme" | "checkoutValues";
export type LocalStorageWrapperKeysArray = ReadonlyArray<LocalStorageWrapperKey>;
interface LocalStorageValueManagerConfig {
key: LocalStorageWrapperKey;
usesJSON?: boolean;
}

export const _STORAGE_KEY_CONFIGS: ReadonlyArray<LocalStorageValueManagerConfig> = [
{ key: "authToken" },
{ key: "preferredTheme" },
{ key: "checkoutValues", usesJSON: true },
] as const;

export const _STORAGE_KEYS = _STORAGE_KEY_CONFIGS.map(
({ key }) => key
) as LocalStorageWrapperKeysArray;

export type LocalStorageWrapperKeysArray = typeof _STORAGE_KEYS;
export type LocalStorageWrapperKey = LocalStorageWrapperKeysArray[number];
export type LocalStorageUtil = Simplify<
{ KEYS: LocalStorageWrapperKeysArray } & {
[K in LocalStorageWrapperKey as K]: LocalStorageValueManager;
Expand All @@ -14,22 +27,30 @@ export type LocalStorageUtil = Simplify<

export class LocalStorageValueManager {
protected storageKey: LocalStorageWrapperKey;
get: () => string | null;

constructor(storageKey: LocalStorageWrapperKey) {
this.storageKey = storageKey;
}

get(): string | null {
return localStorage.getItem(this.storageKey);
constructor({ key, usesJSON = false }: LocalStorageValueManagerConfig) {
this.storageKey = key;
this.get = usesJSON
? () => JSON.parse(localStorage.getItem(this.storageKey) ?? "null")
: () => localStorage.getItem(this.storageKey);
}

set(value: unknown): void {
try {
const valueToStore = typeof value === "string" ? value : JSON.stringify(value);
console.debug(
`[storage] value: `,
value,
`, typeof ${typeof value}`,
`\nvalueToStore: `,
valueToStore,
`, typeof ${typeof valueToStore}`
);
localStorage.setItem(this.storageKey, valueToStore);
} catch (err) {
// prettier-ignore
logger.error(getTypeSafeErr(err), `[LocalStorageWrapper] Failed to set value "${value}" for key ${this.storageKey}.`);
logger.error(getTypeSafeErr(err), `[LocalStorageWrapper] Failed to set value "${value}" for key "${this.storageKey}".`);
}
}

Expand All @@ -49,10 +70,10 @@ export class LocalStorageValueManager {
* For each localStorage key used in this app, the key is made available on the
* storage object along with localStorage wrapper methods.
*/
export const storage = _STORAGE_KEYS.reduce(
(acc, storageKey) => ({
export const storage = _STORAGE_KEY_CONFIGS.reduce(
(acc, { key, usesJSON = false }) => ({
...acc,
[storageKey]: new LocalStorageValueManager(storageKey),
[key]: new LocalStorageValueManager({ key, usesJSON }),
}),
{ KEYS: _STORAGE_KEYS } as LocalStorageUtil
);

0 comments on commit a809f07

Please sign in to comment.