From 866d8238200b7276e228ecd579ca3770ce3849bf Mon Sep 17 00:00:00 2001 From: Bauke Date: Sun, 2 Jul 2023 12:25:48 +0200 Subject: [PATCH] Rework storage values to use a single function. --- source/content-scripts/setup.ts | 13 ++++++------ source/options/components/tours.tsx | 19 +++++++++++------ source/storage/common.ts | 32 +++++++++++++++++------------ source/tours/introduction.tsx | 6 ++++-- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/source/content-scripts/setup.ts b/source/content-scripts/setup.ts index a07e6fc..1bcf879 100644 --- a/source/content-scripts/setup.ts +++ b/source/content-scripts/setup.ts @@ -1,8 +1,5 @@ import Shepherd from "shepherd.js"; -import { - addCompletedTour, - createIntroductionUnderstood, -} from "../storage/common.js"; +import {fromStorage, StorageKey} from "../storage/common.js"; import { allTours, introductionTour, @@ -12,7 +9,9 @@ import { /** The main entry point for the content script. */ async function main(): Promise { - const introductionUnderstood = await createIntroductionUnderstood(); + const introductionUnderstood = await fromStorage( + StorageKey.IntroductionUnderstood, + ); // Get the anchor without the leading #. const anchor = window.location.hash.slice(1); @@ -121,7 +120,9 @@ function startTour(data: TourData, runMainAgainAfterComplete: boolean): void { } // Mark the tour as completed. - await addCompletedTour(data.id); + const completedTours = await fromStorage(StorageKey.ToursCompleted); + completedTours.value.add(data.id); + await completedTours.save(); if (runMainAgainAfterComplete) { await main(); diff --git a/source/options/components/tours.tsx b/source/options/components/tours.tsx index cc184e9..be787fa 100644 --- a/source/options/components/tours.tsx +++ b/source/options/components/tours.tsx @@ -1,12 +1,16 @@ import {Component, type JSX} from "preact"; -import {createToursCompleted} from "../../storage/common.js"; +import { + fromStorage, + StorageKey, + type StorageValues, +} from "../../storage/common.js"; import {allTours} from "../../tours/exports.js"; import {Tour} from "./tour.js"; type Props = Record; type State = { - toursCompleted: Awaited>["value"]; + toursCompleted: Awaited; }; export class Tours extends Component { @@ -14,20 +18,23 @@ export class Tours extends Component { super(props); this.state = { - toursCompleted: new Set(), + toursCompleted: undefined!, }; } async componentDidMount(): Promise { - const toursCompleted = await createToursCompleted(); - this.setState({toursCompleted: toursCompleted.value}); + const toursCompleted = await fromStorage(StorageKey.ToursCompleted); + this.setState({toursCompleted}); } render(): JSX.Element { const {toursCompleted} = this.state; + if (toursCompleted === undefined) { + return <>; + } const tours = allTours.map((tour) => ( - + )); return ( diff --git a/source/storage/common.ts b/source/storage/common.ts index a4bb145..8d8c724 100644 --- a/source/storage/common.ts +++ b/source/storage/common.ts @@ -2,33 +2,39 @@ import browser from "webextension-polyfill"; import {createValue} from "@holllo/webextension-storage"; import {type TourId} from "../tours/exports.js"; +/** All available storage keys. */ export enum StorageKey { IntroductionUnderstood = "introduction-understood", ToursCompleted = "tours-completed", } -export async function createIntroductionUnderstood() { - return createValue({ +/** All values we want to save in storage. */ +const storageValues = { + [StorageKey.IntroductionUnderstood]: createValue({ deserialize: (input) => input === "true", serialize: (input) => JSON.stringify(input), key: StorageKey.IntroductionUnderstood, storage: browser.storage.local, value: false, - }); -} - -export async function createToursCompleted() { - return createValue>({ + }), + [StorageKey.ToursCompleted]: createValue>({ deserialize: (input) => new Set(JSON.parse(input) as TourId[]), serialize: (input) => JSON.stringify(Array.from(input)), key: StorageKey.ToursCompleted, storage: browser.storage.local, value: new Set([]), - }); -} + }), +}; -export async function addCompletedTour(tourId: TourId): Promise { - const toursCompleted = await createToursCompleted(); - toursCompleted.value.add(tourId); - await toursCompleted.save(); +/** Alias to get the inferred type shape of {@link storageValues}. */ +export type StorageValues = typeof storageValues; + +/** + * Get the stored value for a given key. + * @param key The key to get from storage. + */ +export async function fromStorage( + key: K, +): Promise { + return storageValues[key]; } diff --git a/source/tours/introduction.tsx b/source/tours/introduction.tsx index 2c23d11..047f5d0 100644 --- a/source/tours/introduction.tsx +++ b/source/tours/introduction.tsx @@ -1,4 +1,4 @@ -import {createIntroductionUnderstood} from "../storage/common.js"; +import {fromStorage, StorageKey} from "../storage/common.js"; import {TourId, type TourData} from "./types.js"; import {openOptionsPageFromBackground, renderInContainer} from "./utilities.js"; @@ -103,7 +103,9 @@ const steps: TourData["steps"] = [ classes: "btn", text: "I understand", async action() { - const introductionUnderstood = await createIntroductionUnderstood(); + const introductionUnderstood = await fromStorage( + StorageKey.IntroductionUnderstood, + ); introductionUnderstood.value = true; await introductionUnderstood.save(); this.complete();