diff --git a/prisma/seed.ts b/prisma/seed.ts index e3c06ff..8496807 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -916,6 +916,27 @@ async function main() { } console.log(` ✓ ${visibilityLinks.length} submission visibility links created`) + // --- Applicant/Observer visibility settings --- + const visibilitySettings = [ + { key: 'observer_show_team_tab', value: 'true', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show Team tab on observer project detail page' }, + { key: 'applicant_show_evaluation_feedback', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show anonymous jury evaluation feedback to applicants' }, + { key: 'applicant_show_evaluation_scores', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show global scores in evaluation feedback' }, + { key: 'applicant_show_evaluation_criteria', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show per-criterion scores in evaluation feedback' }, + { key: 'applicant_show_evaluation_text', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show written feedback text in evaluation feedback' }, + { key: 'applicant_show_livefinal_feedback', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show live final scores to applicants' }, + { key: 'applicant_show_livefinal_scores', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show individual jury scores from live finals' }, + { key: 'applicant_show_deliberation_feedback', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show deliberation results to applicants' }, + { key: 'applicant_hide_feedback_from_rejected', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Hide feedback from rejected projects' }, + ] + for (const s of visibilitySettings) { + await prisma.systemSettings.upsert({ + where: { key: s.key }, + update: {}, + create: s, + }) + } + console.log(` ✓ Created ${visibilitySettings.length} applicant/observer visibility settings`) + // --- Feature flag: enable competition model --- await prisma.systemSettings.upsert({ where: { key: 'feature.useCompetitionModel' }, diff --git a/src/app/(applicant)/applicant/evaluations/page.tsx b/src/app/(applicant)/applicant/evaluations/page.tsx index f4f8acb..d749379 100644 --- a/src/app/(applicant)/applicant/evaluations/page.tsx +++ b/src/app/(applicant)/applicant/evaluations/page.tsx @@ -9,7 +9,7 @@ import { } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Skeleton } from '@/components/ui/skeleton' -import { Star, MessageSquare } from 'lucide-react' +import { Star, MessageSquare, Trophy, Vote } from 'lucide-react' export default function ApplicantEvaluationsPage() { const { data: rounds, isLoading } = trpc.applicant.getMyEvaluations.useQuery() @@ -58,84 +58,97 @@ export default function ApplicantEvaluationsPage() { ) : (
- {rounds.map((round) => ( - - -
- {round.roundName} - - {round.evaluationCount} evaluation{round.evaluationCount !== 1 ? 's' : ''} - -
-
- - {round.evaluations.map((ev, idx) => ( -
-
- - Evaluator #{idx + 1} - - {ev.submittedAt && ( - - {new Date(ev.submittedAt).toLocaleDateString()} + {rounds.map((round) => { + const roundIcon = round.roundType === 'LIVE_FINAL' + ? + : round.roundType === 'DELIBERATION' + ? + : + + return ( + + +
+ + {roundIcon} + {round.roundName} + + + {round.evaluationCount} {round.roundType === 'DELIBERATION' ? 'vote' : 'evaluation'}{round.evaluationCount !== 1 ? 's' : ''} + +
+
+ + {round.evaluations.map((ev, idx) => ( +
+
+ + {round.roundType === 'DELIBERATION' ? `Juror #${idx + 1}` : `Evaluator #${idx + 1}`} + {ev.submittedAt && ( + + {new Date(ev.submittedAt).toLocaleDateString()} + + )} +
+ + {ev.globalScore !== null && round.roundType !== 'DELIBERATION' && ( +
+ + {ev.globalScore} + + / {round.roundType === 'LIVE_FINAL' ? '10' : '100'} + +
+ )} + + {ev.criterionScores && ev.criteria && ( +
+

Criterion Scores

+
+ {(() => { + const criteria = ev.criteria as Array<{ id?: string; label?: string; name?: string; maxScore?: number }> + const scores = ev.criterionScores as Record + return criteria + .filter((c) => c.id || c.label || c.name) + .map((c, ci) => { + const key = c.id || String(ci) + const score = scores[key] + return ( +
+ {c.label || c.name || `Criterion ${ci + 1}`} + + {score !== undefined ? score : '—'} + {c.maxScore ? ` / ${c.maxScore}` : ''} + +
+ ) + }) + })()} +
+
+ )} + + {ev.feedbackText && ( +
+
+ + {round.roundType === 'DELIBERATION' ? 'Result' : 'Written Feedback'} +
+
+ {ev.feedbackText} +
+
)}
- - {ev.globalScore !== null && ( -
- - {ev.globalScore} - / 100 -
- )} - - {ev.criterionScores && ev.criteria && ( -
-

Criterion Scores

-
- {(() => { - const criteria = ev.criteria as Array<{ id?: string; label?: string; name?: string; maxScore?: number }> - const scores = ev.criterionScores as Record - return criteria - .filter((c) => c.id || c.label || c.name) - .map((c, ci) => { - const key = c.id || String(ci) - const score = scores[key] - return ( -
- {c.label || c.name || `Criterion ${ci + 1}`} - - {score !== undefined ? score : '—'} - {c.maxScore ? ` / ${c.maxScore}` : ''} - -
- ) - }) - })()} -
-
- )} - - {ev.feedbackText && ( -
-
- - Written Feedback -
-
- {ev.feedbackText} -
-
- )} -
- ))} - - - ))} + ))} + + + ) + })}

Evaluator identities are kept confidential. diff --git a/src/components/observer/observer-project-detail.tsx b/src/components/observer/observer-project-detail.tsx index c5f721d..e4eeeba 100644 --- a/src/components/observer/observer-project-detail.tsx +++ b/src/components/observer/observer-project-detail.tsx @@ -47,6 +47,7 @@ export function ObserverProjectDetail({ projectId }: { projectId: string }) { { id: projectId }, { refetchInterval: 30_000 }, ) + const { data: flags } = trpc.settings.getFeatureFlags.useQuery() const roundId = data?.assignments?.[0]?.roundId as string | undefined const { data: activeForm } = trpc.evaluation.getStageForm.useQuery( @@ -242,6 +243,14 @@ export function ObserverProjectDetail({ projectId }: { projectId: string }) { )} Files + {flags?.observerShowTeamTab && project.teamMembers.length > 0 && ( + + Team + + {project.teamMembers.length} + + + )} {/* ── Overview Tab ── */} @@ -854,6 +863,48 @@ export function ObserverProjectDetail({ projectId }: { projectId: string }) { )} + {/* ── Team Tab ── */} + {flags?.observerShowTeamTab && project.teamMembers.length > 0 && ( + + + + + +

+ +
+ Team Members + + + +
+ {project.teamMembers.map((member) => ( +
+ +
+

+ {member.user.name || 'Unnamed'} +

+

+ {member.user.email} +

+
+ + {member.role === 'LEAD' ? 'Lead' : member.role === 'ADVISOR' ? 'Advisor' : 'Member'} + +
+ ))} +
+
+ + + + )} + {/* ── Files Tab ── */} diff --git a/src/components/settings/settings-content.tsx b/src/components/settings/settings-content.tsx index f37a69d..e059bc2 100644 --- a/src/components/settings/settings-content.tsx +++ b/src/components/settings/settings-content.tsx @@ -145,6 +145,15 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin 'analytics_observer_comparison_tab', 'analytics_pdf_enabled', 'analytics_pdf_sections', + 'observer_show_team_tab', + 'applicant_show_evaluation_feedback', + 'applicant_show_evaluation_scores', + 'applicant_show_evaluation_criteria', + 'applicant_show_evaluation_text', + 'applicant_show_livefinal_feedback', + 'applicant_show_livefinal_scores', + 'applicant_show_deliberation_feedback', + 'applicant_hide_feedback_from_rejected', ]) const auditSecuritySettings = getSettingsByKeys([ @@ -785,6 +794,66 @@ function AnalyticsSettingsSection({ settings }: { settings: Record + +
+ +

+ Control what anonymous jury feedback applicants can see on their dashboard +

+ + + + + + + + +
{ if (ctx.user.role !== 'APPLICANT') { throw new TRPCError({ code: 'FORBIDDEN', message: 'Only applicants can access this' }) } + // Load admin visibility settings + const visKeys = [ + 'applicant_show_evaluation_feedback', 'applicant_show_evaluation_scores', + 'applicant_show_evaluation_criteria', 'applicant_show_evaluation_text', + 'applicant_show_livefinal_feedback', 'applicant_show_livefinal_scores', + 'applicant_show_deliberation_feedback', + 'applicant_hide_feedback_from_rejected', + ] + const settingsRows = await ctx.prisma.systemSettings.findMany({ + where: { key: { in: visKeys } }, + }) + const sMap = new Map(settingsRows.map((s) => [s.key, s.value])) + const adminSettingsExist = settingsRows.length > 0 + const flag = (k: string) => sMap.get(k) === 'true' + const project = await ctx.prisma.project.findFirst({ where: { OR: [ @@ -1804,34 +1821,18 @@ export const applicantRouter = router({ if (!project?.programId) return [] - // Get closed/archived EVALUATION rounds — only ones this project participated in const projectRoundIds = new Set( (await ctx.prisma.projectRoundState.findMany({ where: { projectId: project.id }, select: { roundId: true }, })).map((prs) => prs.roundId) ) - if (projectRoundIds.size === 0) return [] - const evalRounds = await ctx.prisma.round.findMany({ - where: { - competition: { programId: project.programId }, - roundType: 'EVALUATION', - status: { in: ['ROUND_CLOSED', 'ROUND_ARCHIVED'] }, - id: { in: [...projectRoundIds] }, - }, - select: { - id: true, - name: true, - configJson: true, - }, - orderBy: { sortOrder: 'asc' }, - }) - - const results: Array<{ + type ResultItem = { roundId: string roundName: string + roundType: string evaluationCount: number evaluations: Array<{ id: string @@ -1841,56 +1842,203 @@ export const applicantRouter = router({ feedbackText: string | null criteria: Prisma.JsonValue | null }> - }> = [] + } + const results: ResultItem[] = [] - const projectIsRejected = await isProjectRejected(ctx.prisma, project.id) - - for (let i = 0; i < evalRounds.length; i++) { - const round = evalRounds[i] - const parsed = EvaluationConfigSchema.safeParse(round.configJson) - if (!parsed.success || !parsed.data.applicantVisibility.enabled) continue - - // Skip this round if hideFromRejected is on and the project has been rejected - if (parsed.data.applicantVisibility.hideFromRejected && projectIsRejected) continue - - const vis = parsed.data.applicantVisibility - - // Get evaluations via assignments — NEVER select userId or user relation - const evaluations = await ctx.prisma.evaluation.findMany({ + // --- Backwards compatibility: if no admin settings exist yet, fall back to + // the old per-round applicantVisibility config for EVALUATION rounds --- + if (!adminSettingsExist) { + const evalRounds = await ctx.prisma.round.findMany({ where: { - assignment: { - projectId: project.id, - roundId: round.id, + competition: { programId: project.programId }, + roundType: 'EVALUATION', + status: { in: ['ROUND_CLOSED', 'ROUND_ARCHIVED'] }, + id: { in: [...projectRoundIds] }, + }, + select: { id: true, name: true, configJson: true }, + orderBy: { sortOrder: 'asc' }, + }) + + const projectIsRejected = await isProjectRejected(ctx.prisma, project.id) + + for (let i = 0; i < evalRounds.length; i++) { + const round = evalRounds[i] + const parsed = EvaluationConfigSchema.safeParse(round.configJson) + if (!parsed.success || !parsed.data.applicantVisibility.enabled) continue + if (parsed.data.applicantVisibility.hideFromRejected && projectIsRejected) continue + const vis = parsed.data.applicantVisibility + + const evaluations = await ctx.prisma.evaluation.findMany({ + where: { + assignment: { projectId: project.id, roundId: round.id }, + status: { in: ['SUBMITTED', 'LOCKED'] }, }, - status: { in: ['SUBMITTED', 'LOCKED'] }, - }, - select: { - id: true, - submittedAt: true, - globalScore: vis.showGlobalScore, - criterionScoresJson: vis.showCriterionScores, - feedbackText: vis.showFeedbackText, - form: vis.showCriterionScores ? { select: { criteriaJson: true } } : false, - }, - orderBy: { submittedAt: 'asc' }, - }) + select: { + id: true, submittedAt: true, + globalScore: vis.showGlobalScore, + criterionScoresJson: vis.showCriterionScores, + feedbackText: vis.showFeedbackText, + form: vis.showCriterionScores ? { select: { criteriaJson: true } } : false, + }, + orderBy: { submittedAt: 'asc' }, + }) + if (evaluations.length === 0) continue - // Mask round names: "Evaluation Round 1", "Evaluation Round 2", etc. - const maskedName = `Evaluation Round ${i + 1}` + results.push({ + roundId: round.id, + roundName: `Evaluation Round ${i + 1}`, + roundType: 'EVALUATION', + evaluationCount: evaluations.length, + evaluations: evaluations.map((ev) => ({ + id: ev.id, + submittedAt: ev.submittedAt, + globalScore: vis.showGlobalScore ? (ev as { globalScore?: number | null }).globalScore ?? null : null, + criterionScores: vis.showCriterionScores ? (ev as { criterionScoresJson?: Prisma.JsonValue }).criterionScoresJson ?? null : null, + feedbackText: vis.showFeedbackText ? (ev as { feedbackText?: string | null }).feedbackText ?? null : null, + criteria: vis.showCriterionScores ? ((ev as { form?: { criteriaJson: Prisma.JsonValue } | null }).form?.criteriaJson ?? null) : null, + })), + }) + } + return results + } - results.push({ - roundId: round.id, - roundName: maskedName, - evaluationCount: evaluations.length, - evaluations: evaluations.map((ev) => ({ - id: ev.id, - submittedAt: ev.submittedAt, - globalScore: vis.showGlobalScore ? (ev as { globalScore?: number | null }).globalScore ?? null : null, - criterionScores: vis.showCriterionScores ? (ev as { criterionScoresJson?: Prisma.JsonValue }).criterionScoresJson ?? null : null, - feedbackText: vis.showFeedbackText ? (ev as { feedbackText?: string | null }).feedbackText ?? null : null, - criteria: vis.showCriterionScores ? ((ev as { form?: { criteriaJson: Prisma.JsonValue } | null }).form?.criteriaJson ?? null) : null, - })), - }) + // --- New admin settings flow --- + const evalEnabled = flag('applicant_show_evaluation_feedback') + const evalShowScores = flag('applicant_show_evaluation_scores') + const evalShowCriteria = flag('applicant_show_evaluation_criteria') + const evalShowText = flag('applicant_show_evaluation_text') + const liveFinalEnabled = flag('applicant_show_livefinal_feedback') + const liveFinalShowScores = flag('applicant_show_livefinal_scores') + const deliberationEnabled = flag('applicant_show_deliberation_feedback') + const hideFromRejected = flag('applicant_hide_feedback_from_rejected') + + if (!evalEnabled && !liveFinalEnabled && !deliberationEnabled) return [] + + const projectIsRejected = hideFromRejected ? await isProjectRejected(ctx.prisma, project.id) : false + if (projectIsRejected) return [] + + // Build round type filter + const enabledTypes: RoundType[] = [] + if (evalEnabled) enabledTypes.push('EVALUATION') + if (liveFinalEnabled) enabledTypes.push('LIVE_FINAL') + if (deliberationEnabled) enabledTypes.push('DELIBERATION') + + const rounds = await ctx.prisma.round.findMany({ + where: { + competition: { programId: project.programId }, + roundType: { in: enabledTypes }, + status: { in: ['ROUND_CLOSED', 'ROUND_ARCHIVED'] }, + id: { in: [...projectRoundIds] }, + }, + select: { id: true, name: true, roundType: true }, + orderBy: { sortOrder: 'asc' }, + }) + + let evalCounter = 0 + let liveFinalCounter = 0 + let deliberationCounter = 0 + + for (const round of rounds) { + if (round.roundType === 'EVALUATION') { + evalCounter++ + const evaluations = await ctx.prisma.evaluation.findMany({ + where: { + assignment: { projectId: project.id, roundId: round.id }, + status: { in: ['SUBMITTED', 'LOCKED'] }, + }, + select: { + id: true, + submittedAt: true, + globalScore: evalShowScores, + criterionScoresJson: evalShowCriteria, + feedbackText: evalShowText, + form: evalShowCriteria ? { select: { criteriaJson: true } } : false, + }, + orderBy: { submittedAt: 'asc' }, + }) + if (evaluations.length === 0) continue + + results.push({ + roundId: round.id, + roundName: `Evaluation Round ${evalCounter}`, + roundType: 'EVALUATION', + evaluationCount: evaluations.length, + evaluations: evaluations.map((ev) => ({ + id: ev.id, + submittedAt: ev.submittedAt, + globalScore: evalShowScores ? (ev as { globalScore?: number | null }).globalScore ?? null : null, + criterionScores: evalShowCriteria ? (ev as { criterionScoresJson?: Prisma.JsonValue }).criterionScoresJson ?? null : null, + feedbackText: evalShowText ? (ev as { feedbackText?: string | null }).feedbackText ?? null : null, + criteria: evalShowCriteria ? ((ev as { form?: { criteriaJson: Prisma.JsonValue } | null }).form?.criteriaJson ?? null) : null, + })), + }) + } else if (round.roundType === 'LIVE_FINAL') { + liveFinalCounter++ + // LiveVote scores — anonymized + // Only show jury votes, not audience votes + const votes = await ctx.prisma.liveVote.findMany({ + where: { + projectId: project.id, + session: { roundId: round.id }, + isAudienceVote: false, + }, + select: { + id: true, + score: true, + votedAt: true, + }, + orderBy: { votedAt: 'asc' }, + }) + if (votes.length === 0) continue + + results.push({ + roundId: round.id, + roundName: `Live Final ${liveFinalCounter}`, + roundType: 'LIVE_FINAL', + evaluationCount: votes.length, + evaluations: votes.map((v) => ({ + id: v.id, + submittedAt: v.votedAt, + globalScore: liveFinalShowScores ? v.score : null, + criterionScores: null, + feedbackText: null, + criteria: null, + })), + }) + } else if (round.roundType === 'DELIBERATION') { + deliberationCounter++ + // DeliberationVote — per-juror votes for this project + const votes = await ctx.prisma.deliberationVote.findMany({ + where: { + session: { roundId: round.id }, + projectId: project.id, + runoffRound: 0, + }, + select: { + id: true, + createdAt: true, + rank: true, + isWinnerPick: true, + }, + orderBy: { createdAt: 'asc' }, + }) + if (votes.length === 0) continue + + results.push({ + roundId: round.id, + roundName: `Deliberation ${deliberationCounter}`, + roundType: 'DELIBERATION', + evaluationCount: votes.length, + evaluations: votes.map((v) => ({ + id: v.id, + submittedAt: v.createdAt, + globalScore: v.rank, + criterionScores: null, + feedbackText: v.isWinnerPick ? 'Selected as winner' : (v.rank ? `Ranked #${v.rank}` : null), + criteria: null, + })), + }) + } } return results diff --git a/src/server/routers/settings.ts b/src/server/routers/settings.ts index c9c0947..24d1d0c 100644 --- a/src/server/routers/settings.ts +++ b/src/server/routers/settings.ts @@ -25,7 +25,7 @@ function categorizeModel(modelId: string): string { return 'other' } -function inferSettingCategory(key: string): 'AI' | 'BRANDING' | 'EMAIL' | 'STORAGE' | 'SECURITY' | 'DEFAULTS' | 'WHATSAPP' | 'FEATURE_FLAGS' { +function inferSettingCategory(key: string): 'AI' | 'BRANDING' | 'EMAIL' | 'STORAGE' | 'SECURITY' | 'DEFAULTS' | 'WHATSAPP' | 'FEATURE_FLAGS' | 'ANALYTICS' { if (key.startsWith('openai') || key.startsWith('ai_') || key.startsWith('anthropic')) return 'AI' if (key.startsWith('smtp_') || key.startsWith('email_')) return 'EMAIL' if (key.startsWith('storage_') || key.startsWith('local_storage') || key.startsWith('max_file') || key.startsWith('avatar_') || key.startsWith('allowed_file')) return 'STORAGE' @@ -33,6 +33,7 @@ function inferSettingCategory(key: string): 'AI' | 'BRANDING' | 'EMAIL' | 'STORA if (key.startsWith('whatsapp_')) return 'WHATSAPP' if (key.startsWith('security_') || key.startsWith('session_')) return 'SECURITY' if (key.startsWith('learning_hub_') || key.startsWith('jury_compare_') || key.startsWith('support_')) return 'FEATURE_FLAGS' + if (key.startsWith('applicant_') || key.startsWith('observer_') || key.startsWith('analytics_')) return 'ANALYTICS' return 'DEFAULTS' } @@ -42,34 +43,40 @@ export const settingsRouter = router({ * These are non-sensitive settings that can be exposed to any user */ getFeatureFlags: protectedProcedure.query(async ({ ctx }) => { - const [whatsappEnabled, juryCompareEnabled, learningHubExternal, learningHubExternalUrl, supportEmail, accountReminderDays] = await Promise.all([ - ctx.prisma.systemSettings.findUnique({ - where: { key: 'whatsapp_enabled' }, - }), - ctx.prisma.systemSettings.findUnique({ - where: { key: 'jury_compare_enabled' }, - }), - ctx.prisma.systemSettings.findUnique({ - where: { key: 'learning_hub_external' }, - }), - ctx.prisma.systemSettings.findUnique({ - where: { key: 'learning_hub_external_url' }, - }), - ctx.prisma.systemSettings.findUnique({ - where: { key: 'support_email' }, - }), - ctx.prisma.systemSettings.findUnique({ - where: { key: 'account_reminder_days' }, - }), - ]) + const keys = [ + 'whatsapp_enabled', 'jury_compare_enabled', 'learning_hub_external', + 'learning_hub_external_url', 'support_email', 'account_reminder_days', + 'observer_show_team_tab', + 'applicant_show_evaluation_feedback', 'applicant_show_evaluation_scores', + 'applicant_show_evaluation_criteria', 'applicant_show_evaluation_text', + 'applicant_show_livefinal_feedback', 'applicant_show_livefinal_scores', + 'applicant_show_deliberation_feedback', + 'applicant_hide_feedback_from_rejected', + ] + const settings = await ctx.prisma.systemSettings.findMany({ + where: { key: { in: keys } }, + }) + const map = new Map(settings.map((s) => [s.key, s.value])) + const flag = (k: string, def = 'false') => (map.get(k) ?? def) === 'true' return { - whatsappEnabled: whatsappEnabled?.value === 'true', - juryCompareEnabled: juryCompareEnabled?.value === 'true', - learningHubExternal: learningHubExternal?.value === 'true', - learningHubExternalUrl: learningHubExternalUrl?.value || '', - supportEmail: supportEmail?.value || '', - accountReminderDays: parseInt(accountReminderDays?.value || '3', 10), + whatsappEnabled: flag('whatsapp_enabled'), + juryCompareEnabled: flag('jury_compare_enabled'), + learningHubExternal: flag('learning_hub_external'), + learningHubExternalUrl: map.get('learning_hub_external_url') || '', + supportEmail: map.get('support_email') || '', + accountReminderDays: parseInt(map.get('account_reminder_days') || '3', 10), + observerShowTeamTab: flag('observer_show_team_tab', 'true'), + applicantFeedback: { + evaluationEnabled: flag('applicant_show_evaluation_feedback'), + evaluationShowScores: flag('applicant_show_evaluation_scores'), + evaluationShowCriteria: flag('applicant_show_evaluation_criteria'), + evaluationShowText: flag('applicant_show_evaluation_text'), + liveFinalEnabled: flag('applicant_show_livefinal_feedback'), + liveFinalShowScores: flag('applicant_show_livefinal_scores'), + deliberationEnabled: flag('applicant_show_deliberation_feedback'), + hideFromRejected: flag('applicant_hide_feedback_from_rejected'), + }, } }),