JoinDialog.tsx raw

   1  import { Button } from '@/components/ui/button'
   2  import {
   3    Dialog,
   4    DialogContent,
   5    DialogDescription,
   6    DialogFooter,
   7    DialogHeader,
   8    DialogTitle
   9  } from '@/components/ui/dialog'
  10  import {
  11    Drawer,
  12    DrawerClose,
  13    DrawerContent,
  14    DrawerDescription,
  15    DrawerFooter,
  16    DrawerHeader,
  17    DrawerTitle
  18  } from '@/components/ui/drawer'
  19  import { Input } from '@/components/ui/input'
  20  import { Label } from '@/components/ui/label'
  21  import { createJoinDraftEvent } from '@/lib/draft-event'
  22  import { useNostr } from '@/providers/NostrProvider'
  23  import { useScreenSize } from '@/providers/ScreenSizeProvider'
  24  import relayMembershipService from '@/services/relay-membership.service'
  25  import { TRelayInfo } from '@/types'
  26  import { useState } from 'react'
  27  import { useTranslation } from 'react-i18next'
  28  import { toast } from 'sonner'
  29  
  30  export default function JoinDialog({
  31    relayInfo,
  32    showJoinDialog,
  33    setShowJoinDialog,
  34    onMembershipStatusChange
  35  }: {
  36    relayInfo: TRelayInfo
  37    showJoinDialog: boolean
  38    setShowJoinDialog: (open: boolean) => void
  39    onMembershipStatusChange: (status: boolean) => void
  40  }) {
  41    const { t } = useTranslation()
  42    const { isSmallScreen } = useScreenSize()
  43    const { publish } = useNostr()
  44    const [inviteCode, setInviteCode] = useState('')
  45    const [isLoading, setIsLoading] = useState(false)
  46  
  47    const handleJoinSubmit = async () => {
  48      setIsLoading(true)
  49      try {
  50        const draftEvent = createJoinDraftEvent(inviteCode)
  51        const joinRequestEvent = await publish(draftEvent, {
  52          specifiedRelayUrls: [relayInfo.url]
  53        })
  54        toast.success(t('Join request sent successfully'))
  55        await relayMembershipService.addNewMember(relayInfo.url, joinRequestEvent.pubkey)
  56        onMembershipStatusChange(true)
  57        setInviteCode('')
  58        setShowJoinDialog(false)
  59      } catch (error) {
  60        const errors = error instanceof AggregateError ? error.errors : [error]
  61        errors.forEach((err) => {
  62          toast.error(
  63            `${t('Failed to send join request')}: ${err instanceof Error ? err.message : String(err)}`,
  64            { duration: 10_000 }
  65          )
  66          console.error(err)
  67        })
  68        return
  69      } finally {
  70        setIsLoading(false)
  71      }
  72    }
  73  
  74    const content = (
  75      <div className="space-y-2">
  76        <Label htmlFor="invite-code">{t('Invite Code')}</Label>
  77        <Input
  78          id="invite-code"
  79          value={inviteCode}
  80          onChange={(e) => setInviteCode(e.target.value)}
  81          placeholder={t('Enter invite code')}
  82          required
  83        />
  84        <p className="text-sm text-muted-foreground">
  85          {t('You can get an invite code from a relay member.')}
  86        </p>
  87      </div>
  88    )
  89  
  90    if (isSmallScreen) {
  91      return (
  92        <Drawer open={showJoinDialog} onOpenChange={setShowJoinDialog}>
  93          <DrawerContent>
  94            <DrawerHeader>
  95              <DrawerTitle>{t('Request to Join Relay')}</DrawerTitle>
  96              <DrawerDescription>
  97                {t('Enter the invite code you received from a relay member.')}
  98              </DrawerDescription>
  99            </DrawerHeader>
 100            <div className="p-4">{content}</div>
 101            <DrawerFooter>
 102              <Button onClick={handleJoinSubmit} disabled={isLoading || !inviteCode.trim()}>
 103                {isLoading ? t('Sending...') : t('Send Request')}
 104              </Button>
 105              <DrawerClose asChild>
 106                <Button variant="outline">{t('Cancel')}</Button>
 107              </DrawerClose>
 108            </DrawerFooter>
 109          </DrawerContent>
 110        </Drawer>
 111      )
 112    }
 113  
 114    return (
 115      <Dialog open={showJoinDialog} onOpenChange={setShowJoinDialog}>
 116        <DialogContent>
 117          <DialogHeader>
 118            <DialogTitle>{t('Request to Join Relay')}</DialogTitle>
 119            <DialogDescription>
 120              {t('Enter the invite code you received from a relay member.')}
 121            </DialogDescription>
 122          </DialogHeader>
 123          {content}
 124          <DialogFooter>
 125            <Button
 126              variant="ghost"
 127              onClick={() => {
 128                setShowJoinDialog(false)
 129                setInviteCode('')
 130              }}
 131            >
 132              {t('Cancel')}
 133            </Button>
 134            <Button onClick={handleJoinSubmit} disabled={isLoading || !inviteCode.trim()}>
 135              {isLoading ? t('Sending...') : t('Send Request')}
 136            </Button>
 137          </DialogFooter>
 138        </DialogContent>
 139      </Dialog>
 140    )
 141  }
 142