refactoring: seen context provider
This commit is contained in:
parent
a75401b802
commit
06ce5266e2
|
@ -12,6 +12,7 @@ import { InboxProvider } from '../context/inbox'
|
||||||
import { LocalizeProvider } from '../context/localize'
|
import { LocalizeProvider } from '../context/localize'
|
||||||
import { MediaQueryProvider } from '../context/mediaQuery'
|
import { MediaQueryProvider } from '../context/mediaQuery'
|
||||||
import { NotificationsProvider } from '../context/notifications'
|
import { NotificationsProvider } from '../context/notifications'
|
||||||
|
import { SeenProvider } from '../context/seen'
|
||||||
import { SessionProvider } from '../context/session'
|
import { SessionProvider } from '../context/session'
|
||||||
import { SnackbarProvider } from '../context/snackbar'
|
import { SnackbarProvider } from '../context/snackbar'
|
||||||
import { TopicsProvider } from '../context/topics'
|
import { TopicsProvider } from '../context/topics'
|
||||||
|
@ -115,6 +116,7 @@ export const App = (props: Props) => {
|
||||||
<MediaQueryProvider>
|
<MediaQueryProvider>
|
||||||
<SnackbarProvider>
|
<SnackbarProvider>
|
||||||
<TopicsProvider>
|
<TopicsProvider>
|
||||||
|
<SeenProvider>
|
||||||
<ConfirmProvider>
|
<ConfirmProvider>
|
||||||
<SessionProvider onStateChangeCallback={console.log}>
|
<SessionProvider onStateChangeCallback={console.log}>
|
||||||
<FollowingProvider>
|
<FollowingProvider>
|
||||||
|
@ -130,6 +132,7 @@ export const App = (props: Props) => {
|
||||||
</FollowingProvider>
|
</FollowingProvider>
|
||||||
</SessionProvider>
|
</SessionProvider>
|
||||||
</ConfirmProvider>
|
</ConfirmProvider>
|
||||||
|
</SeenProvider>
|
||||||
</TopicsProvider>
|
</TopicsProvider>
|
||||||
</SnackbarProvider>
|
</SnackbarProvider>
|
||||||
</MediaQueryProvider>
|
</MediaQueryProvider>
|
||||||
|
|
|
@ -4,18 +4,17 @@ import { For, Show, createSignal } from 'solid-js'
|
||||||
|
|
||||||
import { useFollowing } from '../../../context/following'
|
import { useFollowing } from '../../../context/following'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '../../../context/localize'
|
||||||
|
import { useSeen } from '../../../context/seen'
|
||||||
import { Author } from '../../../graphql/schema/core.gen'
|
import { Author } from '../../../graphql/schema/core.gen'
|
||||||
import { router, useRouter } from '../../../stores/router'
|
import { router, useRouter } from '../../../stores/router'
|
||||||
import { useArticlesStore } from '../../../stores/zine/articles'
|
import { useArticlesStore } from '../../../stores/zine/articles'
|
||||||
import { useSeenStore } from '../../../stores/zine/seen'
|
|
||||||
import { Userpic } from '../../Author/Userpic'
|
import { Userpic } from '../../Author/Userpic'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { Icon } from '../../_shared/Icon'
|
||||||
|
|
||||||
import styles from './Sidebar.module.scss'
|
import styles from './Sidebar.module.scss'
|
||||||
|
|
||||||
export const Sidebar = () => {
|
export const Sidebar = () => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const { seen } = useSeenStore()
|
const { seen } = useSeen()
|
||||||
const { subscriptions } = useFollowing()
|
const { subscriptions } = useFollowing()
|
||||||
const { page } = useRouter()
|
const { page } = useRouter()
|
||||||
const { articlesByTopic } = useArticlesStore()
|
const { articlesByTopic } = useArticlesStore()
|
||||||
|
|
67
src/context/seen.tsx
Normal file
67
src/context/seen.tsx
Normal 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>
|
||||||
|
}
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user