index.tsx raw

   1  import { Button } from '@/components/ui/button'
   2  import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer'
   3  import {
   4    DropdownMenu,
   5    DropdownMenuContent,
   6    DropdownMenuItem,
   7    DropdownMenuTrigger
   8  } from '@/components/ui/dropdown-menu'
   9  import { useMuteList } from '@/providers/MuteListProvider'
  10  import { useNostr } from '@/providers/NostrProvider'
  11  import { useScreenSize } from '@/providers/ScreenSizeProvider'
  12  import { BellOff, Loader } from 'lucide-react'
  13  import { useMemo, useState } from 'react'
  14  import { useTranslation } from 'react-i18next'
  15  import { toast } from 'sonner'
  16  
  17  export default function MuteButton({ pubkey }: { pubkey: string }) {
  18    const { t } = useTranslation()
  19    const { isSmallScreen } = useScreenSize()
  20    const { pubkey: accountPubkey, checkLogin } = useNostr()
  21    const { mutePubkeySet, changing, mutePubkeyPrivately, mutePubkeyPublicly, unmutePubkey } =
  22      useMuteList()
  23    const [updating, setUpdating] = useState(false)
  24    const isMuted = useMemo(() => mutePubkeySet.has(pubkey), [mutePubkeySet, pubkey])
  25  
  26    if (!accountPubkey || (pubkey && pubkey === accountPubkey)) return null
  27  
  28    const handleMute = async (e: React.MouseEvent, isPrivate = true) => {
  29      e.stopPropagation()
  30      checkLogin(async () => {
  31        if (isMuted) return
  32  
  33        setUpdating(true)
  34        try {
  35          if (isPrivate) {
  36            await mutePubkeyPrivately(pubkey)
  37          } else {
  38            await mutePubkeyPublicly(pubkey)
  39          }
  40        } catch (error) {
  41          toast.error(`${t('Mute failed')}: ${(error as Error).message}`)
  42        } finally {
  43          setUpdating(false)
  44        }
  45      })
  46    }
  47  
  48    const handleUnmute = async (e: React.MouseEvent) => {
  49      e.stopPropagation()
  50      checkLogin(async () => {
  51        if (!isMuted) return
  52  
  53        setUpdating(true)
  54        try {
  55          await unmutePubkey(pubkey)
  56        } catch (error) {
  57          toast.error(`${t('Unmute failed')}: ${(error as Error).message}`)
  58        } finally {
  59          setUpdating(false)
  60        }
  61      })
  62    }
  63  
  64    if (isMuted) {
  65      return (
  66        <Button
  67          className="w-20 min-w-20 rounded-full"
  68          variant="secondary"
  69          onClick={handleUnmute}
  70          disabled={updating || changing}
  71        >
  72          {updating ? <Loader className="animate-spin" /> : t('Unmute')}
  73        </Button>
  74      )
  75    }
  76  
  77    const trigger = (
  78      <Button
  79        variant="destructive"
  80        className="w-20 min-w-20 rounded-full"
  81        disabled={updating || changing}
  82      >
  83        {updating ? <Loader className="animate-spin" /> : t('Mute')}
  84      </Button>
  85    )
  86  
  87    if (isSmallScreen) {
  88      return (
  89        <Drawer>
  90          <DrawerTrigger asChild>{trigger}</DrawerTrigger>
  91          <DrawerContent>
  92            <div className="py-2">
  93              <Button
  94                className="w-full p-6 justify-start text-destructive text-lg gap-4 [&_svg]:size-5 focus:text-destructive"
  95                variant="ghost"
  96                onClick={(e) => handleMute(e, true)}
  97                disabled={updating || changing}
  98              >
  99                {updating ? <Loader className="animate-spin" /> : t('Mute user privately')}
 100              </Button>
 101              <Button
 102                className="w-full p-6 justify-start text-destructive text-lg gap-4 [&_svg]:size-5 focus:text-destructive"
 103                variant="ghost"
 104                onClick={(e) => handleMute(e, false)}
 105                disabled={updating || changing}
 106              >
 107                {updating ? <Loader className="animate-spin" /> : t('Mute user publicly')}
 108              </Button>
 109            </div>
 110          </DrawerContent>
 111        </Drawer>
 112      )
 113    }
 114  
 115    return (
 116      <DropdownMenu>
 117        <DropdownMenuTrigger asChild>{trigger}</DropdownMenuTrigger>
 118        <DropdownMenuContent>
 119          <DropdownMenuItem
 120            onClick={(e) => handleMute(e, true)}
 121            className="text-destructive focus:text-destructive"
 122          >
 123            <BellOff />
 124            {t('Mute user privately')}
 125          </DropdownMenuItem>
 126          <DropdownMenuItem
 127            onClick={(e) => handleMute(e, false)}
 128            className="text-destructive focus:text-destructive"
 129          >
 130            <BellOff />
 131            {t('Mute user publicly')}
 132          </DropdownMenuItem>
 133        </DropdownMenuContent>
 134      </DropdownMenu>
 135    )
 136  }
 137