From b3b3bbb8b38310f087403606362a298878efd3e0 Mon Sep 17 00:00:00 2001
From: Matt
Date: Tue, 17 Feb 2026 13:48:12 +0100
Subject: [PATCH] Fix mobile overflow, logo nav, round activation, compare
projects setting
- Fix assignments page header overflow on mobile (flex-wrap)
- Hide 'Back to Dashboard' button on mobile (logo tap navigates home)
- Make logo/brand text clickable to navigate to role dashboard
- Snap windowOpenAt to now when manually activating a round early
- Gate Compare Projects cards behind jury_compare_enabled setting (defaults off)
- Expose jury_compare_enabled in getFeatureFlags tRPC procedure
Co-Authored-By: Claude Opus 4.6
---
src/app/(jury)/jury/competitions/page.tsx | 42 +++++++--------
src/app/(jury)/jury/page.tsx | 63 +++++++++++++----------
src/components/layouts/role-nav.tsx | 4 +-
src/server/routers/settings.ts | 6 ++-
src/server/services/round-engine.ts | 13 ++++-
5 files changed, 73 insertions(+), 55 deletions(-)
diff --git a/src/app/(jury)/jury/competitions/page.tsx b/src/app/(jury)/jury/competitions/page.tsx
index 0b4d2c3..33cbea7 100644
--- a/src/app/(jury)/jury/competitions/page.tsx
+++ b/src/app/(jury)/jury/competitions/page.tsx
@@ -58,7 +58,7 @@ export default function JuryAssignmentsPage() {
Projects assigned to you for evaluation
-
+
Back to Dashboard
@@ -89,29 +89,25 @@ export default function JuryAssignmentsPage() {
return (
-
-
-
{round.name}
-
- {formatEnumLabel(round.roundType)}
+
+ {round.name}
+
+ {formatEnumLabel(round.roundType)}
+
+ {round.status !== 'ROUND_ACTIVE' && (
+
+ {formatEnumLabel(round.status)}
- {round.status !== 'ROUND_ACTIVE' && (
-
- {formatEnumLabel(round.status)}
-
- )}
-
-
-
- {completed}/{total} completed
-
- {round.windowCloseAt && (
-
-
- Due {formatDateOnly(round.windowCloseAt)}
-
- )}
-
+ )}
+
+ {completed}/{total} completed
+
+ {round.windowCloseAt && (
+
+
+ Due {formatDateOnly(round.windowCloseAt)}
+
+ )}
diff --git a/src/app/(jury)/jury/page.tsx b/src/app/(jury)/jury/page.tsx
index 39967bb..ccd2da0 100644
--- a/src/app/(jury)/jury/page.tsx
+++ b/src/app/(jury)/jury/page.tsx
@@ -47,8 +47,8 @@ async function JuryDashboardContent() {
return null
}
- // Get assignments and grace periods in parallel
- const [assignments, gracePeriods] = await Promise.all([
+ // Get assignments, grace periods, and feature flags in parallel
+ const [assignments, gracePeriods, compareFlag] = await Promise.all([
prisma.assignment.findMany({
where: { userId },
include: {
@@ -106,8 +106,11 @@ async function JuryDashboardContent() {
extendedUntil: true,
},
}),
+ prisma.systemSettings.findUnique({ where: { key: 'jury_compare_enabled' } }),
])
+ const juryCompareEnabled = compareFlag?.value === 'true'
+
// Calculate stats
const totalAssignments = assignments.length
const completedAssignments = assignments.filter(
@@ -227,7 +230,7 @@ async function JuryDashboardContent() {
Your project assignments will appear here once an administrator assigns them to you.
-
+
View evaluations
-
-
-
-
-
-
Compare Projects
-
Side-by-side view
-
-
+ {juryCompareEnabled && (
+
+
+
+
+
+
Compare Projects
+
Side-by-side view
+
+
+ )}
@@ -450,7 +455,7 @@ async function JuryDashboardContent() {
-
+
View and manage evaluations
-
-
-
-
-
-
Compare Projects
-
Side-by-side comparison
-
-
+ {juryCompareEnabled && (
+
+
+
+
+
+
Compare Projects
+
Side-by-side comparison
+
+
+ )}
diff --git a/src/components/layouts/role-nav.tsx b/src/components/layouts/role-nav.tsx
index 714638e..19ba8fb 100644
--- a/src/components/layouts/role-nav.tsx
+++ b/src/components/layouts/role-nav.tsx
@@ -64,10 +64,10 @@ export function RoleNav({ navigation, roleName, user, basePath, statusBadge }: R
{/* Logo */}
-
+
{statusBadge}
-
+
{/* Desktop nav */}
diff --git a/src/server/routers/settings.ts b/src/server/routers/settings.ts
index 106a855..66c298a 100644
--- a/src/server/routers/settings.ts
+++ b/src/server/routers/settings.ts
@@ -26,7 +26,7 @@ export const settingsRouter = router({
* These are non-sensitive settings that can be exposed to any user
*/
getFeatureFlags: protectedProcedure.query(async ({ ctx }) => {
- const [whatsappEnabled, defaultLocale, availableLocales] = await Promise.all([
+ const [whatsappEnabled, defaultLocale, availableLocales, juryCompareEnabled] = await Promise.all([
ctx.prisma.systemSettings.findUnique({
where: { key: 'whatsapp_enabled' },
}),
@@ -36,12 +36,16 @@ export const settingsRouter = router({
ctx.prisma.systemSettings.findUnique({
where: { key: 'i18n_available_locales' },
}),
+ ctx.prisma.systemSettings.findUnique({
+ where: { key: 'jury_compare_enabled' },
+ }),
])
return {
whatsappEnabled: whatsappEnabled?.value === 'true',
defaultLocale: defaultLocale?.value || 'en',
availableLocales: availableLocales?.value ? JSON.parse(availableLocales.value) : ['en', 'fr'],
+ juryCompareEnabled: juryCompareEnabled?.value === 'true',
}
}),
diff --git a/src/server/services/round-engine.ts b/src/server/services/round-engine.ts
index acb2efd..9e063f6 100644
--- a/src/server/services/round-engine.ts
+++ b/src/server/services/round-engine.ts
@@ -106,10 +106,21 @@ export async function activateRound(
}
}
+ // If activating before the scheduled start, snap windowOpenAt to now
+ const now = new Date()
+ const windowData: Record = {}
+ if (round.windowOpenAt && new Date(round.windowOpenAt) > now) {
+ windowData.windowOpenAt = now
+ }
+ // If no windowOpenAt was set at all, also set it to now
+ if (!round.windowOpenAt) {
+ windowData.windowOpenAt = now
+ }
+
const updated = await prisma.$transaction(async (tx: any) => {
const result = await tx.round.update({
where: { id: roundId },
- data: { status: 'ROUND_ACTIVE' },
+ data: { status: 'ROUND_ACTIVE', ...windowData },
})
await tx.decisionAuditLog.create({