83 lines
2.8 KiB
TypeScript
83 lines
2.8 KiB
TypeScript
|
|
'use client'
|
||
|
|
|
||
|
|
import { trpc } from '@/lib/trpc/client'
|
||
|
|
import { toast } from 'sonner'
|
||
|
|
import { UserPlus, Loader2 } from 'lucide-react'
|
||
|
|
import {
|
||
|
|
AlertDialog,
|
||
|
|
AlertDialogAction,
|
||
|
|
AlertDialogCancel,
|
||
|
|
AlertDialogContent,
|
||
|
|
AlertDialogDescription,
|
||
|
|
AlertDialogFooter,
|
||
|
|
AlertDialogHeader,
|
||
|
|
AlertDialogTitle,
|
||
|
|
AlertDialogTrigger,
|
||
|
|
} from '@/components/ui/alert-dialog'
|
||
|
|
|
||
|
|
interface BulkInviteButtonProps {
|
||
|
|
roundId: string
|
||
|
|
}
|
||
|
|
|
||
|
|
export function BulkInviteButton({ roundId }: BulkInviteButtonProps) {
|
||
|
|
const preview = trpc.round.getBulkInvitePreview.useQuery({ roundId })
|
||
|
|
const inviteMutation = trpc.round.bulkInviteTeamMembers.useMutation({
|
||
|
|
onSuccess: (data) => {
|
||
|
|
toast.success(
|
||
|
|
`Invited ${data.invited} team member${data.invited !== 1 ? 's' : ''}${data.skipped ? ` (${data.skipped} already active/invited)` : ''}`
|
||
|
|
)
|
||
|
|
void preview.refetch()
|
||
|
|
},
|
||
|
|
onError: (err) => toast.error(err.message),
|
||
|
|
})
|
||
|
|
|
||
|
|
const uninvited = preview.data?.uninvitedCount ?? 0
|
||
|
|
if (uninvited === 0 && !preview.isLoading) return null
|
||
|
|
|
||
|
|
return (
|
||
|
|
<AlertDialog>
|
||
|
|
<AlertDialogTrigger asChild>
|
||
|
|
<button className="flex items-start gap-3 p-4 rounded-lg border border-l-4 border-l-blue-500 hover:-translate-y-0.5 hover:shadow-md transition-all text-left">
|
||
|
|
<UserPlus className="h-5 w-5 text-blue-600 mt-0.5 shrink-0" />
|
||
|
|
<div>
|
||
|
|
<p className="text-sm font-medium">Invite Team Members</p>
|
||
|
|
<p className="text-xs text-muted-foreground mt-0.5">
|
||
|
|
{preview.isLoading
|
||
|
|
? 'Checking...'
|
||
|
|
: `${uninvited} team member${uninvited !== 1 ? 's' : ''} need invitations`}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</button>
|
||
|
|
</AlertDialogTrigger>
|
||
|
|
<AlertDialogContent>
|
||
|
|
<AlertDialogHeader>
|
||
|
|
<AlertDialogTitle>Invite team members?</AlertDialogTitle>
|
||
|
|
<AlertDialogDescription>
|
||
|
|
This will send invitation emails to {uninvited} team member
|
||
|
|
{uninvited !== 1 ? 's' : ''} who haven't been invited yet.
|
||
|
|
{preview.data?.alreadyInvitedCount
|
||
|
|
? ` (${preview.data.alreadyInvitedCount} already invited)`
|
||
|
|
: ''}
|
||
|
|
</AlertDialogDescription>
|
||
|
|
</AlertDialogHeader>
|
||
|
|
<AlertDialogFooter>
|
||
|
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||
|
|
<AlertDialogAction
|
||
|
|
onClick={() => inviteMutation.mutate({ roundId })}
|
||
|
|
disabled={inviteMutation.isPending}
|
||
|
|
>
|
||
|
|
{inviteMutation.isPending ? (
|
||
|
|
<>
|
||
|
|
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||
|
|
Sending...
|
||
|
|
</>
|
||
|
|
) : (
|
||
|
|
`Send ${uninvited} Invitation${uninvited !== 1 ? 's' : ''}`
|
||
|
|
)}
|
||
|
|
</AlertDialogAction>
|
||
|
|
</AlertDialogFooter>
|
||
|
|
</AlertDialogContent>
|
||
|
|
</AlertDialog>
|
||
|
|
)
|
||
|
|
}
|