feat: lunch banner on applicant dashboard
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import { CompetitionTimelineSidebar } from '@/components/applicant/competition-t
|
||||
import { MentoringRequestCard } from '@/components/applicant/mentoring-request-card'
|
||||
import { MentorConversationCard } from '@/components/applicant/mentor-conversation-card'
|
||||
import { AttendingMembersCard } from '@/components/applicant/attending-members-card'
|
||||
import { LunchBanner } from '@/components/applicant/lunch-banner'
|
||||
import { AnimatedCard } from '@/components/shared/animated-container'
|
||||
import { ProjectLogoUpload } from '@/components/shared/project-logo-upload'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
@@ -403,6 +404,9 @@ export default function ApplicantDashboardPage() {
|
||||
</AnimatedCard>
|
||||
))}
|
||||
|
||||
{/* Lunch banner (auto-hides when lunch event disabled or unconfigured) */}
|
||||
<LunchBanner programId={project.programId} />
|
||||
|
||||
{/* Grand finale attendee roster (auto-hides until confirmation status is CONFIRMED) */}
|
||||
<AttendingMembersCard />
|
||||
|
||||
|
||||
54
src/components/applicant/lunch-banner.tsx
Normal file
54
src/components/applicant/lunch-banner.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
'use client'
|
||||
|
||||
import { trpc } from '@/lib/trpc/client'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import { Calendar, MapPin, Salad, Clock } from 'lucide-react'
|
||||
|
||||
export function LunchBanner({ programId }: { programId: string }) {
|
||||
const { data: event } = trpc.lunch.getEventForMember.useQuery({ programId })
|
||||
if (!event) return null
|
||||
const fmt = new Intl.DateTimeFormat(undefined, {
|
||||
timeZone: 'Europe/Monaco',
|
||||
dateStyle: 'long',
|
||||
timeStyle: 'short',
|
||||
})
|
||||
const eventAt = event.eventAt ? new Date(event.eventAt) : null
|
||||
const deadline = event.changeDeadline ? new Date(event.changeDeadline) : null
|
||||
const deadlinePassed = deadline ? new Date() > deadline : false
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="flex flex-wrap items-center gap-4 py-3 text-sm">
|
||||
<Salad className="h-4 w-4 text-emerald-500" />
|
||||
<span className="font-medium">Lunch event</span>
|
||||
{eventAt && (
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Calendar className="h-4 w-4" /> {fmt.format(eventAt)}{' '}
|
||||
<span className="text-muted-foreground text-xs">(Monaco time)</span>
|
||||
</span>
|
||||
)}
|
||||
{event.venue && (
|
||||
<span className="flex items-center gap-1.5">
|
||||
<MapPin className="h-4 w-4" /> {event.venue}
|
||||
</span>
|
||||
)}
|
||||
{deadline && (
|
||||
<span
|
||||
className={`text-muted-foreground ml-auto flex items-center gap-1.5 ${deadlinePassed ? 'text-destructive' : ''}`}
|
||||
>
|
||||
<Clock className="h-4 w-4" />
|
||||
{deadlinePassed ? 'Picks closed' : 'Picks close'}: {fmt.format(deadline)}
|
||||
</span>
|
||||
)}
|
||||
{event.notes && (
|
||||
<details className="basis-full">
|
||||
<summary className="text-muted-foreground cursor-pointer text-xs">
|
||||
Notes from organizers
|
||||
</summary>
|
||||
<p className="mt-1 text-sm whitespace-pre-wrap">{event.notes}</p>
|
||||
</details>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user