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