From 06ce5266e23be3c85994a9738c88ac784adf124e Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 7 May 2024 02:43:23 +0300 Subject: [PATCH] refactoring: seen context provider --- src/components/App.tsx | 33 ++++++------ src/components/Feed/Sidebar/Sidebar.tsx | 5 +- src/context/seen.tsx | 67 +++++++++++++++++++++++++ src/stores/zine/seen.ts | 15 ------ 4 files changed, 87 insertions(+), 33 deletions(-) create mode 100644 src/context/seen.tsx delete mode 100644 src/stores/zine/seen.ts diff --git a/src/components/App.tsx b/src/components/App.tsx index 5a362864..f8f9a6c5 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -12,6 +12,7 @@ import { InboxProvider } from '../context/inbox' import { LocalizeProvider } from '../context/localize' import { MediaQueryProvider } from '../context/mediaQuery' import { NotificationsProvider } from '../context/notifications' +import { SeenProvider } from '../context/seen' import { SessionProvider } from '../context/session' import { SnackbarProvider } from '../context/snackbar' import { TopicsProvider } from '../context/topics' @@ -115,21 +116,23 @@ export const App = (props: Props) => { - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/src/components/Feed/Sidebar/Sidebar.tsx b/src/components/Feed/Sidebar/Sidebar.tsx index 213589ef..6fdbee40 100644 --- a/src/components/Feed/Sidebar/Sidebar.tsx +++ b/src/components/Feed/Sidebar/Sidebar.tsx @@ -4,18 +4,17 @@ import { For, Show, createSignal } from 'solid-js' import { useFollowing } from '../../../context/following' import { useLocalize } from '../../../context/localize' +import { useSeen } from '../../../context/seen' import { Author } from '../../../graphql/schema/core.gen' import { router, useRouter } from '../../../stores/router' import { useArticlesStore } from '../../../stores/zine/articles' -import { useSeenStore } from '../../../stores/zine/seen' import { Userpic } from '../../Author/Userpic' import { Icon } from '../../_shared/Icon' - import styles from './Sidebar.module.scss' export const Sidebar = () => { const { t } = useLocalize() - const { seen } = useSeenStore() + const { seen } = useSeen() const { subscriptions } = useFollowing() const { page } = useRouter() const { articlesByTopic } = useArticlesStore() diff --git a/src/context/seen.tsx b/src/context/seen.tsx new file mode 100644 index 00000000..f26ef3e2 --- /dev/null +++ b/src/context/seen.tsx @@ -0,0 +1,67 @@ +import { openDB } from 'idb' +import { Accessor, JSX, createContext, createSignal, onMount, useContext } from 'solid-js' + +type SeenContextType = { + seen: Accessor<{ [slug: string]: number }> + addSeen: (slug: string) => void +} + +const SeenContext = createContext() +export function useSeen() { + return useContext(SeenContext) +} + +const DB_NAME = 'discourseAppDB' +const DB_VERSION = 1 +const STORE_NAME = 'seen' +const setupIndexedDB = async () => { + return await openDB(DB_NAME, DB_VERSION, { + upgrade(db) { + if (!db.objectStoreNames.contains(STORE_NAME)) { + db.createObjectStore(STORE_NAME, { keyPath: 'slug' }) + } + }, + }) +} + +const getSeenFromIndexedDB = async (db) => { + const tx = db.transaction(STORE_NAME, 'readonly') + const store = tx.objectStore(STORE_NAME) + const seen = await store.getAll() + return seen.reduce((acc, { slug, date }) => { + acc[slug] = date + return acc + }, {}) +} + +const saveSeenToIndexedDB = async (db, seen) => { + const tx = db.transaction(STORE_NAME, 'readwrite') + const store = tx.objectStore(STORE_NAME) + for (const [slug, date] of Object.entries(seen)) { + await store.put({ slug, date }) + } + await tx.done +} + +export const SeenProvider = (props: { children: JSX.Element }) => { + const [seen, setSeen] = createSignal<{ [slug: string]: number }>({}) + const [db, setDb] = createSignal() + const addSeen = async (slug: string) => { + setSeen((prev) => { + const newSeen = { ...prev, [slug]: Date.now() } + saveSeenToIndexedDB(db(), newSeen) + return newSeen + }) + } + + onMount(async () => { + const ndb = await setupIndexedDB() + setDb(ndb) + const seenFromDB = await getSeenFromIndexedDB(ndb) + setSeen(seenFromDB) + }) + + const value: SeenContextType = { seen, addSeen } + + return {props.children} +} diff --git a/src/stores/zine/seen.ts b/src/stores/zine/seen.ts deleted file mode 100644 index bf01d92d..00000000 --- a/src/stores/zine/seen.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { createStorageSignal } from '@solid-primitives/storage' - -// TODO: use indexedDB here -export const [seen, setSeen] = createStorageSignal<{ [slug: string]: Date }>('seen', {}) -export const addSeen = (slug) => setSeen({ ...seen(), [slug]: Date.now() }) - -export const useSeenStore = (initialData: { [slug: string]: Date } = {}) => { - setSeen({ ...seen(), ...initialData }) - - return { - seen, - setSeen, - addSeen, - } -}