RepositoryProvider.tsx raw

   1  import {
   2    FollowListRepository,
   3    MuteListRepository,
   4    PinnedUsersListRepository
   5  } from '@/domain'
   6  import {
   7    FollowListRepositoryImpl,
   8    MuteListRepositoryImpl,
   9    PinnedUsersListRepositoryImpl
  10  } from '@/infrastructure/persistence'
  11  import { createContext, useContext, useMemo } from 'react'
  12  import { useNostr } from './NostrProvider'
  13  
  14  /**
  15   * Repository context providing access to all domain repositories
  16   */
  17  type TRepositoryContext = {
  18    followListRepository: FollowListRepository
  19    muteListRepository: MuteListRepository
  20    pinnedUsersListRepository: PinnedUsersListRepository
  21  }
  22  
  23  const RepositoryContext = createContext<TRepositoryContext | undefined>(undefined)
  24  
  25  /**
  26   * Hook to access repositories
  27   * @throws Error if used outside RepositoryProvider
  28   */
  29  export const useRepositories = () => {
  30    const context = useContext(RepositoryContext)
  31    if (!context) {
  32      throw new Error('useRepositories must be used within a RepositoryProvider')
  33    }
  34    return context
  35  }
  36  
  37  /**
  38   * Provider that creates and provides repository instances with injected dependencies.
  39   * Must be nested within NostrProvider to access publish and encryption functions.
  40   */
  41  export function RepositoryProvider({ children }: { children: React.ReactNode }) {
  42    const { pubkey, publish, nip04Encrypt, nip04Decrypt } = useNostr()
  43  
  44    const repositories = useMemo<TRepositoryContext | null>(() => {
  45      if (!pubkey) return null
  46  
  47      const followListRepository = new FollowListRepositoryImpl({ publish })
  48  
  49      const muteListRepository = new MuteListRepositoryImpl({
  50        publish,
  51        currentUserPubkey: pubkey,
  52        decrypt: async (ciphertext, pk) => nip04Decrypt(pk, ciphertext),
  53        encrypt: async (plaintext, pk) => nip04Encrypt(pk, plaintext)
  54      })
  55  
  56      const pinnedUsersListRepository = new PinnedUsersListRepositoryImpl({
  57        publish,
  58        currentUserPubkey: pubkey,
  59        decrypt: async (ciphertext, pk) => nip04Decrypt(pk, ciphertext),
  60        encrypt: async (plaintext, pk) => nip04Encrypt(pk, plaintext)
  61      })
  62  
  63      return {
  64        followListRepository,
  65        muteListRepository,
  66        pinnedUsersListRepository
  67      }
  68    }, [pubkey, publish, nip04Encrypt, nip04Decrypt])
  69  
  70    // If not logged in, still render children but context will throw if accessed
  71    if (!repositories) {
  72      return <>{children}</>
  73    }
  74  
  75    return (
  76      <RepositoryContext.Provider value={repositories}>
  77        {children}
  78      </RepositoryContext.Provider>
  79    )
  80  }
  81