Add file requirements per round and super admin promotion via UI
Part A: File Requirements per Round - New FileRequirement model with name, description, accepted MIME types, max size, required flag, sort order - Added requirementId FK to ProjectFile for linking uploads to requirements - Backend CRUD (create/update/delete/reorder) in file router with audit logging - Mime type validation and team member upload authorization in applicant router - Admin UI: FileRequirementsEditor component in round edit page - Applicant UI: RequirementUploadSlot/List components in submission detail and team pages - Viewer UI: RequirementChecklist with fulfillment status in file-viewer Part B: Super Admin Promotion - Added SUPER_ADMIN to role enums in user create/update/bulkCreate with guards - Member detail page: SUPER_ADMIN dropdown option with AlertDialog confirmation - Invite page: SUPER_ADMIN option visible only to super admins Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -69,7 +69,7 @@ import {
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
type Step = 'input' | 'preview' | 'sending' | 'complete'
|
||||
type Role = 'PROGRAM_ADMIN' | 'JURY_MEMBER' | 'MENTOR' | 'OBSERVER'
|
||||
type Role = 'SUPER_ADMIN' | 'PROGRAM_ADMIN' | 'JURY_MEMBER' | 'MENTOR' | 'OBSERVER'
|
||||
|
||||
interface Assignment {
|
||||
projectId: string
|
||||
@@ -99,6 +99,7 @@ interface ParsedUser {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||
|
||||
const ROLE_LABELS: Record<Role, string> = {
|
||||
SUPER_ADMIN: 'Super Admin',
|
||||
PROGRAM_ADMIN: 'Program Admin',
|
||||
JURY_MEMBER: 'Jury Member',
|
||||
MENTOR: 'Mentor',
|
||||
@@ -399,16 +400,18 @@ export default function MemberInvitePage() {
|
||||
const name = nameKey ? row[nameKey]?.trim() : undefined
|
||||
const rawRole = roleKey ? row[roleKey]?.trim().toUpperCase() : ''
|
||||
const role: Role =
|
||||
rawRole === 'PROGRAM_ADMIN'
|
||||
? 'PROGRAM_ADMIN'
|
||||
: rawRole === 'MENTOR'
|
||||
? 'MENTOR'
|
||||
: rawRole === 'OBSERVER'
|
||||
? 'OBSERVER'
|
||||
: 'JURY_MEMBER'
|
||||
rawRole === 'SUPER_ADMIN'
|
||||
? 'SUPER_ADMIN'
|
||||
: rawRole === 'PROGRAM_ADMIN'
|
||||
? 'PROGRAM_ADMIN'
|
||||
: rawRole === 'MENTOR'
|
||||
? 'MENTOR'
|
||||
: rawRole === 'OBSERVER'
|
||||
? 'OBSERVER'
|
||||
: 'JURY_MEMBER'
|
||||
const isValidFormat = emailRegex.test(email)
|
||||
const isDuplicate = email ? seenEmails.has(email) : false
|
||||
const isUnauthorizedAdmin = role === 'PROGRAM_ADMIN' && !isSuperAdmin
|
||||
const isUnauthorizedAdmin = (role === 'PROGRAM_ADMIN' || role === 'SUPER_ADMIN') && !isSuperAdmin
|
||||
if (isValidFormat && !isDuplicate && email) seenEmails.add(email)
|
||||
return {
|
||||
email,
|
||||
@@ -646,6 +649,11 @@ export default function MemberInvitePage() {
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{isSuperAdmin && (
|
||||
<SelectItem value="SUPER_ADMIN">
|
||||
Super Admin
|
||||
</SelectItem>
|
||||
)}
|
||||
{isSuperAdmin && (
|
||||
<SelectItem value="PROGRAM_ADMIN">
|
||||
Program Admin
|
||||
|
||||
Reference in New Issue
Block a user