Platform-wide visual overhaul, team invites, analytics improvements, and deployment hardening
UI overhaul applying jury dashboard design patterns across all pages: - Stat cards with border-l-4 accent + icon pills on admin, observer, mentor, applicant dashboards and reports - Card section headers with color-coded icon pills throughout - Hover lift effects (translate-y + shadow) on cards and list items - Gradient progress bars (brand-teal to brand-blue) platform-wide - AnimatedCard stagger animations on all dashboard sections - Auth pages with gradient accent strip and polished icon containers - EmptyState component upgraded with rounded icon pill containers - Replaced AI-looking icons (Brain/Sparkles/Bot/Wand2/Cpu) with descriptive alternatives across 12 files - Removed gradient overlay from jury dashboard header - Quick actions restyled as card links with group hover effects Backend improvements: - Team member invite emails with account setup flow and notification logging - Analytics routers accept edition-wide queries (programId) in addition to roundId - Round detail endpoint returns inline progress data (eliminates extra getProgress call) - Award voting endpoints parallelized with Promise.all - Bulk invite supports optional sendInvitation flag - AwardVote composite index migration for query performance Infrastructure: - Docker entrypoint with migration retry loop (configurable retries/delay) - docker-compose pull_policy: always for automatic image refresh - Simplified deploy/update scripts using docker compose up -d --pull always - Updated deployment documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ import {
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import {
|
||||
Bot,
|
||||
Cog,
|
||||
Palette,
|
||||
Mail,
|
||||
HardDrive,
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
} from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { AnimatedCard } from '@/components/shared/animated-container'
|
||||
import { AISettingsForm } from './ai-settings-form'
|
||||
import { AIUsageCard } from './ai-usage-card'
|
||||
import { BrandingSettingsForm } from './branding-settings-form'
|
||||
@@ -195,7 +196,7 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
</TabsTrigger>
|
||||
{isSuperAdmin && (
|
||||
<TabsTrigger value="ai" className="gap-2 shrink-0">
|
||||
<Bot className="h-4 w-4" />
|
||||
<Cog className="h-4 w-4" />
|
||||
AI
|
||||
</TabsTrigger>
|
||||
)}
|
||||
@@ -275,7 +276,7 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<TabsList className="flex flex-col items-stretch h-auto w-full bg-transparent p-0 gap-0.5">
|
||||
{isSuperAdmin && (
|
||||
<TabsTrigger value="ai" className="justify-start gap-2 w-full px-3 py-2 h-auto data-[state=active]:bg-muted">
|
||||
<Bot className="h-4 w-4" />
|
||||
<Cog className="h-4 w-4" />
|
||||
AI
|
||||
</TabsTrigger>
|
||||
)}
|
||||
@@ -308,6 +309,7 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
|
||||
{isSuperAdmin && (
|
||||
<TabsContent value="ai" className="space-y-6">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>AI Configuration</CardTitle>
|
||||
@@ -319,11 +321,13 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<AISettingsForm settings={aiSettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
<AIUsageCard />
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="tags">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
@@ -353,9 +357,11 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="branding">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Platform Branding</CardTitle>
|
||||
@@ -367,10 +373,12 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<BrandingSettingsForm settings={brandingSettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
|
||||
{isSuperAdmin && (
|
||||
<TabsContent value="email">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Email Configuration</CardTitle>
|
||||
@@ -382,10 +390,12 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<EmailSettingsForm settings={emailSettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="notifications">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Notification Email Settings</CardTitle>
|
||||
@@ -397,10 +407,12 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<NotificationSettingsForm />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
|
||||
{isSuperAdmin && (
|
||||
<TabsContent value="storage">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>File Storage</CardTitle>
|
||||
@@ -412,11 +424,13 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<StorageSettingsForm settings={storageSettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
{isSuperAdmin && (
|
||||
<TabsContent value="security">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Security Settings</CardTitle>
|
||||
@@ -428,10 +442,12 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<SecuritySettingsForm settings={securitySettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="defaults">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Default Settings</CardTitle>
|
||||
@@ -443,9 +459,11 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<DefaultsSettingsForm settings={defaultsSettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="digest" className="space-y-6">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Digest Configuration</CardTitle>
|
||||
@@ -457,9 +475,11 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<DigestSettingsSection settings={digestSettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="analytics" className="space-y-6">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Analytics & Reports</CardTitle>
|
||||
@@ -471,9 +491,11 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<AnalyticsSettingsSection settings={analyticsSettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="audit" className="space-y-6">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Audit & Security</CardTitle>
|
||||
@@ -485,9 +507,11 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<AuditSettingsSection settings={auditSecuritySettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="localization" className="space-y-6">
|
||||
<AnimatedCard>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Localization</CardTitle>
|
||||
@@ -499,6 +523,7 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
<LocalizationSettingsSection settings={localizationSettings} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</TabsContent>
|
||||
</div>{/* end content area */}
|
||||
</div>{/* end lg:flex */}
|
||||
@@ -506,7 +531,7 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
|
||||
{/* Quick Links to sub-pages */}
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<Card>
|
||||
<Card className="transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base flex items-center gap-2">
|
||||
<LayoutTemplate className="h-4 w-4" />
|
||||
@@ -528,7 +553,7 @@ export function SettingsContent({ initialSettings, isSuperAdmin = true }: Settin
|
||||
</Card>
|
||||
|
||||
{isSuperAdmin && (
|
||||
<Card>
|
||||
<Card className="transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base flex items-center gap-2">
|
||||
<Webhook className="h-4 w-4" />
|
||||
|
||||
Reference in New Issue
Block a user