Apply full refactor updates plus pipeline/email UX confirmations
All checks were successful
Build and Push Docker Image / build (push) Successful in 10m33s

This commit is contained in:
Matt
2026-02-14 15:26:42 +01:00
parent e56e143a40
commit b5425e705e
374 changed files with 116737 additions and 111969 deletions

View File

@@ -18,6 +18,7 @@ import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
import { Badge } from '@/components/ui/badge'
import { Checkbox } from '@/components/ui/checkbox'
import { Skeleton } from '@/components/ui/skeleton'
import {
Select,
@@ -103,6 +104,7 @@ const fileTypeIcons: Record<string, React.ReactNode> = {
function EditProjectContent({ projectId }: { projectId: string }) {
const router = useRouter()
const [tagInput, setTagInput] = useState('')
const [statusNotificationConfirmed, setStatusNotificationConfirmed] = useState(false)
// Fetch project data
const { data: project, isLoading } = trpc.project.get.useQuery({
@@ -172,6 +174,24 @@ function EditProjectContent({ projectId }: { projectId: string }) {
}, [project, form])
const tags = form.watch('tags')
const selectedStatus = form.watch('status')
const previousStatus = (project?.status ?? 'SUBMITTED') as UpdateProjectForm['status']
const statusTriggersNotifications = ['SEMIFINALIST', 'FINALIST', 'REJECTED'].includes(selectedStatus)
const requiresStatusNotificationConfirmation = Boolean(
project && selectedStatus !== previousStatus && statusTriggersNotifications
)
const notificationRecipientEmails = Array.from(
new Set(
(project?.teamMembers ?? [])
.map((member) => member.user?.email?.toLowerCase().trim() ?? '')
.filter((email) => email.length > 0)
)
)
useEffect(() => {
setStatusNotificationConfirmed(false)
form.clearErrors('status')
}, [selectedStatus, form])
// Add tag
const addTag = useCallback(() => {
@@ -194,6 +214,14 @@ function EditProjectContent({ projectId }: { projectId: string }) {
)
const onSubmit = async (data: UpdateProjectForm) => {
if (requiresStatusNotificationConfirmation && !statusNotificationConfirmed) {
form.setError('status', {
type: 'manual',
message: 'Confirm participant notifications before saving this status change.',
})
return
}
await updateProject.mutateAsync({
id: projectId,
title: data.title,
@@ -370,6 +398,39 @@ function EditProjectContent({ projectId }: { projectId: string }) {
<SelectItem value="REJECTED">Rejected</SelectItem>
</SelectContent>
</Select>
{requiresStatusNotificationConfirmation && (
<div className="space-y-2 rounded-md border bg-muted/20 p-3">
<p className="text-xs font-medium">
Participant Notification Check
</p>
<p className="text-xs text-muted-foreground">
Saving this status will send automated notifications.
</p>
<p className="text-xs text-muted-foreground">
Recipients ({notificationRecipientEmails.length}):{' '}
{notificationRecipientEmails.length > 0
? notificationRecipientEmails.slice(0, 8).join(', ')
: 'No linked participant accounts found'}
{notificationRecipientEmails.length > 8 ? ', ...' : ''}
</p>
<div className="flex items-start gap-2">
<Checkbox
id="confirm-status-notifications"
checked={statusNotificationConfirmed}
onCheckedChange={(checked) => {
const confirmed = checked === true
setStatusNotificationConfirmed(confirmed)
if (confirmed) {
form.clearErrors('status')
}
}}
/>
<FormLabel htmlFor="confirm-status-notifications" className="text-sm font-normal leading-5">
I verified participant recipients and approve sending automated notifications.
</FormLabel>
</div>
</div>
)}
<FormMessage />
</FormItem>
)}
@@ -557,7 +618,10 @@ function EditProjectContent({ projectId }: { projectId: string }) {
<Button type="button" variant="outline" asChild>
<Link href={`/admin/projects/${projectId}`}>Cancel</Link>
</Button>
<Button type="submit" disabled={isPending}>
<Button
type="submit"
disabled={isPending || (requiresStatusNotificationConfirmation && !statusNotificationConfirmed)}
>
{updateProject.isPending && (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
)}