UserTrustProvider.tsx raw
1 import client from '@/services/client.service'
2 import fayan from '@/services/fayan.service'
3 import { createContext, useCallback, useContext, useEffect } from 'react'
4 import { useNostr } from './NostrProvider'
5
6 type TUserTrustContext = {
7 hideUntrustedInteractions: boolean
8 hideUntrustedNotifications: boolean
9 hideUntrustedNotes: boolean
10 updateHideUntrustedInteractions: (hide: boolean) => void
11 updateHideUntrustedNotifications: (hide: boolean) => void
12 updateHideUntrustedNotes: (hide: boolean) => void
13 isUserTrusted: (pubkey: string) => boolean
14 isSpammer: (pubkey: string) => Promise<boolean>
15 }
16
17 const UserTrustContext = createContext<TUserTrustContext | undefined>(undefined)
18
19 export const useUserTrust = () => {
20 const context = useContext(UserTrustContext)
21 if (!context) {
22 throw new Error('useUserTrust must be used within a UserTrustProvider')
23 }
24 return context
25 }
26
27 const wotSet = new Set<string>()
28
29 export function UserTrustProvider({ children }: { children: React.ReactNode }) {
30 const { pubkey: currentPubkey } = useNostr()
31 // All three hideUntrusted flags are permanently disabled.
32 // Mute lists handle unwanted content. These flags break relay feeds
33 // by turning them into de-facto follow feeds.
34 const hideUntrustedInteractions = false
35 const hideUntrustedNotes = false
36 const hideUntrustedNotifications = false
37
38 useEffect(() => {
39 if (!currentPubkey) return
40
41 const initWoT = async () => {
42 const followings = await client.fetchFollowings(currentPubkey, false)
43 followings.forEach((pubkey) => wotSet.add(pubkey))
44
45 const batchSize = 20
46 for (let i = 0; i < followings.length; i += batchSize) {
47 const batch = followings.slice(i, i + batchSize)
48 await Promise.allSettled(
49 batch.map(async (pubkey) => {
50 const _followings = await client.fetchFollowings(pubkey, false)
51 _followings.forEach((following) => {
52 wotSet.add(following)
53 })
54 })
55 )
56 await new Promise((resolve) => setTimeout(resolve, 200))
57 }
58 }
59 initWoT()
60 }, [currentPubkey])
61
62 const isUserTrusted = useCallback(
63 (pubkey: string) => {
64 if (!currentPubkey || pubkey === currentPubkey) return true
65 return wotSet.has(pubkey)
66 },
67 [currentPubkey]
68 )
69
70 const isSpammer = useCallback(
71 async (pubkey: string) => {
72 if (isUserTrusted(pubkey)) return false
73 const percentile = await fayan.fetchUserPercentile(pubkey)
74 if (percentile === null) return false
75 return percentile < 60
76 },
77 [isUserTrusted]
78 )
79
80 // no-op updaters preserved for interface compatibility
81 const updateHideUntrustedInteractions = (_hide: boolean) => {}
82 const updateHideUntrustedNotifications = (_hide: boolean) => {}
83 const updateHideUntrustedNotes = (_hide: boolean) => {}
84
85 return (
86 <UserTrustContext.Provider
87 value={{
88 hideUntrustedInteractions,
89 hideUntrustedNotifications,
90 hideUntrustedNotes,
91 updateHideUntrustedInteractions,
92 updateHideUntrustedNotifications,
93 updateHideUntrustedNotes,
94 isUserTrusted,
95 isSpammer
96 }}
97 >
98 {children}
99 </UserTrustContext.Provider>
100 )
101 }
102