Platform-wide visual overhaul, team invites, analytics improvements, and deployment hardening
All checks were successful
Build and Push Docker Image / build (push) Successful in 11m14s
All checks were successful
Build and Push Docker Image / build (push) Successful in 11m14s
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:
@@ -28,6 +28,7 @@ import {
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from '@/components/ui/alert-dialog'
|
||||
import { AnimatedCard } from '@/components/shared/animated-container'
|
||||
import { FileViewer } from '@/components/shared/file-viewer'
|
||||
import { MentorChat } from '@/components/shared/mentor-chat'
|
||||
import { ProjectLogoWithUrl } from '@/components/shared/project-logo-with-url'
|
||||
@@ -194,21 +195,31 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
|
||||
|
||||
{/* Milestones Section */}
|
||||
{programId && mentorAssignmentId && (
|
||||
<AnimatedCard index={0}>
|
||||
<MilestonesSection
|
||||
programId={programId}
|
||||
mentorAssignmentId={mentorAssignmentId}
|
||||
/>
|
||||
</AnimatedCard>
|
||||
)}
|
||||
|
||||
{/* Private Notes Section */}
|
||||
{mentorAssignmentId && (
|
||||
<NotesSection mentorAssignmentId={mentorAssignmentId} />
|
||||
<AnimatedCard index={1}>
|
||||
<NotesSection mentorAssignmentId={mentorAssignmentId} />
|
||||
</AnimatedCard>
|
||||
)}
|
||||
|
||||
{/* Project Info */}
|
||||
<AnimatedCard index={2}>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Project Information</CardTitle>
|
||||
<CardTitle className="flex items-center gap-2.5 text-lg">
|
||||
<div className="rounded-lg bg-emerald-500/10 p-1.5">
|
||||
<FileText className="h-4 w-4 text-emerald-500" />
|
||||
</div>
|
||||
Project Information
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{/* Category & Ocean Issue badges */}
|
||||
@@ -299,12 +310,16 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
|
||||
{/* Team Members Section */}
|
||||
<AnimatedCard index={3}>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg flex items-center gap-2">
|
||||
<Users className="h-5 w-5" />
|
||||
<CardTitle className="flex items-center gap-2.5 text-lg">
|
||||
<div className="rounded-lg bg-violet-500/10 p-1.5">
|
||||
<Users className="h-4 w-4 text-violet-500" />
|
||||
</div>
|
||||
Team Members ({project.teamMembers?.length || 0})
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
@@ -392,12 +407,16 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
|
||||
{/* Files Section */}
|
||||
<AnimatedCard index={4}>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg flex items-center gap-2">
|
||||
<FileText className="h-5 w-5" />
|
||||
<CardTitle className="flex items-center gap-2.5 text-lg">
|
||||
<div className="rounded-lg bg-rose-500/10 p-1.5">
|
||||
<FileText className="h-4 w-4 text-rose-500" />
|
||||
</div>
|
||||
Project Files
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
@@ -426,12 +445,16 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
|
||||
{/* Messaging Section */}
|
||||
<AnimatedCard index={5}>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg flex items-center gap-2">
|
||||
<MessageSquare className="h-5 w-5" />
|
||||
<CardTitle className="flex items-center gap-2.5 text-lg">
|
||||
<div className="rounded-lg bg-blue-500/10 p-1.5">
|
||||
<MessageSquare className="h-4 w-4 text-blue-500" />
|
||||
</div>
|
||||
Messages
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
@@ -450,6 +473,7 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AnimatedCard>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -529,8 +553,10 @@ function MilestonesSection({
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-lg flex items-center gap-2">
|
||||
<Target className="h-5 w-5" />
|
||||
<CardTitle className="flex items-center gap-2.5 text-lg">
|
||||
<div className="rounded-lg bg-amber-500/10 p-1.5">
|
||||
<Target className="h-4 w-4 text-amber-500" />
|
||||
</div>
|
||||
Milestones
|
||||
</CardTitle>
|
||||
<Badge variant="secondary">
|
||||
@@ -552,7 +578,7 @@ function MilestonesSection({
|
||||
return (
|
||||
<div
|
||||
key={milestone.id}
|
||||
className={`flex items-start gap-3 p-3 rounded-lg border transition-colors ${
|
||||
className={`flex items-start gap-3 p-3 rounded-lg border transition-all duration-200 hover:-translate-y-0.5 hover:shadow-sm ${
|
||||
isCompleted ? 'bg-green-50/50 border-green-200 dark:bg-green-950/20 dark:border-green-900' : ''
|
||||
}`}
|
||||
>
|
||||
@@ -676,8 +702,10 @@ function NotesSection({ mentorAssignmentId }: { mentorAssignmentId: string }) {
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-lg flex items-center gap-2">
|
||||
<StickyNote className="h-5 w-5" />
|
||||
<CardTitle className="flex items-center gap-2.5 text-lg">
|
||||
<div className="rounded-lg bg-amber-500/10 p-1.5">
|
||||
<StickyNote className="h-4 w-4 text-amber-500" />
|
||||
</div>
|
||||
Private Notes
|
||||
</CardTitle>
|
||||
{!isAdding && !editingId && (
|
||||
|
||||
Reference in New Issue
Block a user