refactoring: seen context provider

This commit is contained in:
Untone 2024-05-07 02:43:23 +03:00
parent a75401b802
commit 06ce5266e2
4 changed files with 87 additions and 33 deletions

View File

@ -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) => {
<MediaQueryProvider>
<SnackbarProvider>
<TopicsProvider>
<ConfirmProvider>
<SessionProvider onStateChangeCallback={console.log}>
<FollowingProvider>
<ConnectProvider>
<NotificationsProvider>
<EditorProvider>
<InboxProvider>
<Dynamic component={pageComponent()} {...props} />
</InboxProvider>
</EditorProvider>
</NotificationsProvider>
</ConnectProvider>
</FollowingProvider>
</SessionProvider>
</ConfirmProvider>
<SeenProvider>
<ConfirmProvider>
<SessionProvider onStateChangeCallback={console.log}>
<FollowingProvider>
<ConnectProvider>
<NotificationsProvider>
<EditorProvider>
<InboxProvider>
<Dynamic component={pageComponent()} {...props} />
</InboxProvider>
</EditorProvider>
</NotificationsProvider>
</ConnectProvider>
</FollowingProvider>
</SessionProvider>
</ConfirmProvider>
</SeenProvider>
</TopicsProvider>
</SnackbarProvider>
</MediaQueryProvider>

View File

@ -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()

67
src/context/seen.tsx Normal file
View File

@ -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<SeenContextType>()
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 <SeenContext.Provider value={value}>{props.children}</SeenContext.Provider>
}

View File

@ -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,
}
}