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