BookmarksProvider.tsx raw
1 import { BookmarkList, tryToBookmarkList, Pubkey, eventDispatcher, EventBookmarked, EventUnbookmarked, BookmarkListPublished } from '@/domain'
2 import client from '@/services/client.service'
3 import { Event } from 'nostr-tools'
4 import { createContext, useContext } from 'react'
5 import { useNostr } from './NostrProvider'
6
7 type TBookmarksContext = {
8 addBookmark: (event: Event) => Promise<void>
9 removeBookmark: (event: Event) => Promise<void>
10 }
11
12 const BookmarksContext = createContext<TBookmarksContext | undefined>(undefined)
13
14 export const useBookmarks = () => {
15 const context = useContext(BookmarksContext)
16 if (!context) {
17 throw new Error('useBookmarks must be used within a BookmarksProvider')
18 }
19 return context
20 }
21
22 export function BookmarksProvider({ children }: { children: React.ReactNode }) {
23 const { pubkey: accountPubkey, publish, updateBookmarkListEvent } = useNostr()
24
25 const addBookmark = async (event: Event) => {
26 if (!accountPubkey) return
27
28 const bookmarkListEvent = await client.fetchBookmarkListEvent(accountPubkey)
29 const ownerPubkey = Pubkey.fromHex(accountPubkey)
30
31 // Use domain aggregate
32 const bookmarkList = tryToBookmarkList(bookmarkListEvent) ?? BookmarkList.empty(ownerPubkey)
33
34 // Add bookmark using domain method
35 const change = bookmarkList.addFromEvent(event)
36 if (change.type === 'no_change') return
37
38 // Publish the updated bookmark list
39 const draftEvent = bookmarkList.toDraftEvent()
40 const newBookmarkEvent = await publish(draftEvent)
41 await updateBookmarkListEvent(newBookmarkEvent)
42
43 // Dispatch domain events
44 if (change.type === 'added') {
45 await eventDispatcher.dispatch(
46 new EventBookmarked(ownerPubkey, change.entry.id, change.entry.type)
47 )
48 await eventDispatcher.dispatch(
49 new BookmarkListPublished(ownerPubkey, bookmarkList.count)
50 )
51 }
52 }
53
54 const removeBookmark = async (event: Event) => {
55 if (!accountPubkey) return
56
57 const bookmarkListEvent = await client.fetchBookmarkListEvent(accountPubkey)
58 if (!bookmarkListEvent) return
59
60 const bookmarkList = tryToBookmarkList(bookmarkListEvent)
61 if (!bookmarkList) return
62
63 const ownerPubkey = bookmarkList.owner
64
65 // Remove bookmark using domain method
66 const change = bookmarkList.removeFromEvent(event)
67 if (change.type === 'no_change') return
68
69 // Publish the updated bookmark list
70 const draftEvent = bookmarkList.toDraftEvent()
71 const newBookmarkEvent = await publish(draftEvent)
72 await updateBookmarkListEvent(newBookmarkEvent)
73
74 // Dispatch domain events
75 if (change.type === 'removed') {
76 await eventDispatcher.dispatch(
77 new EventUnbookmarked(ownerPubkey, change.id)
78 )
79 await eventDispatcher.dispatch(
80 new BookmarkListPublished(ownerPubkey, bookmarkList.count)
81 )
82 }
83 }
84
85 return (
86 <BookmarksContext.Provider
87 value={{
88 addBookmark,
89 removeBookmark
90 }}
91 >
92 {children}
93 </BookmarksContext.Provider>
94 )
95 }
96