feat: add bulk invite form to award juror tab, widen role filter to all users
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m57s
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m57s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,8 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
|||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { Progress } from '@/components/ui/progress'
|
import { Progress } from '@/components/ui/progress'
|
||||||
import { UserAvatar } from '@/components/shared/user-avatar'
|
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 { AnimatedCard } from '@/components/shared/animated-container'
|
||||||
import { Pagination } from '@/components/shared/pagination'
|
import { Pagination } from '@/components/shared/pagination'
|
||||||
import { EmailPreviewDialog } from '@/components/admin/round/email-preview-dialog'
|
import { EmailPreviewDialog } from '@/components/admin/round/email-preview-dialog'
|
||||||
@@ -403,7 +405,7 @@ export default function AwardDetailPage({
|
|||||||
|
|
||||||
// Deferred queries - only load when needed
|
// Deferred queries - only load when needed
|
||||||
const { data: allUsers } = trpc.user.list.useQuery(
|
const { data: allUsers } = trpc.user.list.useQuery(
|
||||||
{ role: 'JURY_MEMBER', page: 1, perPage: 100 },
|
{ page: 1, perPage: 200 },
|
||||||
{ enabled: activeTab === 'jurors' }
|
{ enabled: activeTab === 'jurors' }
|
||||||
)
|
)
|
||||||
const { data: allProjects } = trpc.project.list.useQuery(
|
const { data: allProjects } = trpc.project.list.useQuery(
|
||||||
@@ -484,6 +486,13 @@ export default function AwardDetailPage({
|
|||||||
},
|
},
|
||||||
onError: () => toast.error('Failed to update chair status'),
|
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({
|
const setWinner = trpc.specialAward.setWinner.useMutation({
|
||||||
onSuccess: invalidateAward,
|
onSuccess: invalidateAward,
|
||||||
})
|
})
|
||||||
@@ -1328,6 +1337,25 @@ export default function AwardDetailPage({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Separator className="my-4" />
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Invite New Jurors by Email</h3>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Invite new users who don't have accounts yet. They'll receive an invitation email and be added as jurors for this award.
|
||||||
|
</p>
|
||||||
|
<BulkInviteForm
|
||||||
|
onSubmit={async (rows) => {
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{jurors && jurors.length > 0 ? (
|
{jurors && jurors.length > 0 ? (
|
||||||
<Card>
|
<Card>
|
||||||
<Table>
|
<Table>
|
||||||
|
|||||||
Reference in New Issue
Block a user