index.tsx raw
1 import { cn } from '@/lib/utils'
2 import { useNostr } from '@/providers/NostrProvider'
3 import { useUserTrust } from '@/providers/UserTrustProvider'
4 import fayan from '@/services/fayan.service'
5 import { AlertTriangle, ShieldAlert } from 'lucide-react'
6 import { useEffect, useState } from 'react'
7 import { useTranslation } from 'react-i18next'
8
9 export default function TrustScoreBadge({
10 pubkey,
11 className
12 }: {
13 pubkey: string
14 className?: string
15 }) {
16 const { t } = useTranslation()
17 const { isUserTrusted } = useUserTrust()
18 const { pubkey: currentPubkey } = useNostr()
19 const [percentile, setPercentile] = useState<number | null>(null)
20 const [loading, setLoading] = useState(true)
21
22 useEffect(() => {
23 if (currentPubkey === pubkey) {
24 setLoading(false)
25 setPercentile(null)
26 return
27 }
28
29 if (isUserTrusted(pubkey)) {
30 setLoading(false)
31 setPercentile(null)
32 return
33 }
34
35 const fetchScore = async () => {
36 try {
37 const percentile = await fayan.fetchUserPercentile(pubkey)
38 if (percentile !== null) {
39 setPercentile(percentile)
40 }
41 } catch (error) {
42 console.error('Failed to fetch trust score:', error)
43 } finally {
44 setLoading(false)
45 }
46 }
47
48 fetchScore()
49 }, [pubkey, currentPubkey, isUserTrusted])
50
51 if (loading || percentile === null) return null
52
53 // percentile < 40: likely spam (red alert)
54 // percentile < 60: suspicious (yellow warning)
55 if (percentile < 40) {
56 return (
57 <div title={t('Likely spam account (Trust score: {{percentile}}%)', { percentile })}>
58 <ShieldAlert className={cn('!size-4 text-red-500', className)} />
59 </div>
60 )
61 }
62
63 if (percentile < 60) {
64 return (
65 <div title={t('Suspicious account (Trust score: {{percentile}}%)', { percentile })}>
66 <AlertTriangle className={cn('!size-4 text-yellow-600 dark:text-yellow-500', className)} />
67 </div>
68 )
69 }
70
71 return null
72 }
73