From 5537946b5acfcad09159f1e222aa353979ffdaea Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 7 Apr 2026 20:15:55 -0400 Subject: [PATCH] feat: add bulk invite form to award juror tab, widen role filter to all users Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/(admin)/admin/awards/[id]/page.tsx | 30 +++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/app/(admin)/admin/awards/[id]/page.tsx b/src/app/(admin)/admin/awards/[id]/page.tsx index 00cf794..592b4d4 100644 --- a/src/app/(admin)/admin/awards/[id]/page.tsx +++ b/src/app/(admin)/admin/awards/[id]/page.tsx @@ -55,6 +55,8 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Input } from '@/components/ui/input' import { Progress } from '@/components/ui/progress' import { UserAvatar } from '@/components/shared/user-avatar' +import { BulkInviteForm } from '@/components/shared/bulk-invite-form' +import { Separator } from '@/components/ui/separator' import { AnimatedCard } from '@/components/shared/animated-container' import { Pagination } from '@/components/shared/pagination' import { EmailPreviewDialog } from '@/components/admin/round/email-preview-dialog' @@ -403,7 +405,7 @@ export default function AwardDetailPage({ // Deferred queries - only load when needed const { data: allUsers } = trpc.user.list.useQuery( - { role: 'JURY_MEMBER', page: 1, perPage: 100 }, + { page: 1, perPage: 200 }, { enabled: activeTab === 'jurors' } ) const { data: allProjects } = trpc.project.list.useQuery( @@ -484,6 +486,13 @@ export default function AwardDetailPage({ }, onError: () => toast.error('Failed to update chair status'), }) + const bulkInvite = trpc.specialAward.bulkInviteJurors.useMutation({ + onSuccess: (data) => { + utils.specialAward.listJurors.invalidate({ awardId }) + toast.success(`${data.created} invited, ${data.existing} already existed${data.errors > 0 ? `, ${data.errors} failed` : ''}`) + }, + onError: (err) => toast.error(err.message), + }) const setWinner = trpc.specialAward.setWinner.useMutation({ onSuccess: invalidateAward, }) @@ -1328,6 +1337,25 @@ export default function AwardDetailPage({ + +
+

Invite New Jurors by Email

+

+ Invite new users who don't have accounts yet. They'll receive an invitation email and be added as jurors for this award. +

+ { + await bulkInvite.mutateAsync({ + awardId, + role: 'AWARD_MASTER', + invitees: rows.map((r) => ({ name: r.name || undefined, email: r.email })), + }) + }} + isPending={bulkInvite.isPending} + submitLabel="Invite & Add as Jurors" + /> +
+ {jurors && jurors.length > 0 ? (