Implement 10 platform features: evaluation UX, admin tools, AI summaries, applicant portal
Batch 1 - Quick Wins: - F1: Evaluation progress indicator with touch tracking in sticky status bar - F2: Export filtering results as CSV with dynamic AI column flattening - F3: Observer access to analytics dashboards (8 procedures changed to observerProcedure) Batch 2 - Jury Experience: - F4: Countdown timer component with urgency colors + email reminder service with cron endpoint - F5: Conflict of interest declaration system (dialog, admin management, review workflow) Batch 3 - Admin & AI Enhancements: - F6: Bulk status update UI with selection checkboxes, floating toolbar, status history recording - F7: AI-powered evaluation summary with anonymized data, OpenAI integration, scoring patterns - F8: Smart assignment improvements (geo diversity penalty, round familiarity bonus, COI blocking) Batch 4 - Form Flexibility & Applicant Portal: - F9: Evaluation form flexibility (text, boolean, section_header types, conditional visibility) - F10: Applicant portal (status timeline, per-round documents, mentor messaging) Schema: 5 new models (ReminderLog, ConflictOfInterest, EvaluationSummary, ProjectStatusHistory, MentorMessage), ProjectFile extended with roundId + isLate. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import { Badge } from '@/components/ui/badge'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { FileViewer } from '@/components/shared/file-viewer'
|
||||
import { MentorChat } from '@/components/shared/mentor-chat'
|
||||
import { ProjectLogoWithUrl } from '@/components/shared/project-logo-with-url'
|
||||
import {
|
||||
ArrowLeft,
|
||||
@@ -30,6 +31,7 @@ import {
|
||||
Calendar,
|
||||
FileText,
|
||||
ExternalLink,
|
||||
MessageSquare,
|
||||
} from 'lucide-react'
|
||||
import { formatDateOnly, getInitials } from '@/lib/utils'
|
||||
|
||||
@@ -52,6 +54,17 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
|
||||
projectId,
|
||||
})
|
||||
|
||||
const { data: mentorMessages, isLoading: messagesLoading } = trpc.mentor.getMessages.useQuery({
|
||||
projectId,
|
||||
})
|
||||
|
||||
const utils = trpc.useUtils()
|
||||
const sendMessage = trpc.mentor.sendMessage.useMutation({
|
||||
onSuccess: () => {
|
||||
utils.mentor.getMessages.invalidate({ projectId })
|
||||
},
|
||||
})
|
||||
|
||||
if (isLoading) {
|
||||
return <ProjectDetailSkeleton />
|
||||
}
|
||||
@@ -363,6 +376,30 @@ function ProjectDetailContent({ projectId }: { projectId: string }) {
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Messaging Section */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg flex items-center gap-2">
|
||||
<MessageSquare className="h-5 w-5" />
|
||||
Messages
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Communicate with the project team
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<MentorChat
|
||||
messages={mentorMessages || []}
|
||||
currentUserId={project.mentorAssignment?.mentor?.id || ''}
|
||||
onSendMessage={async (message) => {
|
||||
await sendMessage.mutateAsync({ projectId, message })
|
||||
}}
|
||||
isLoading={messagesLoading}
|
||||
isSending={sendMessage.isPending}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user