Repository: tutur3u/platform
Pull request #2775: Show non-hidden testcases for users while doing the test
Author: login: khangronky
Created: 2025-05-12T06:46:04Z | Merged: 2025-05-12T07:18:45Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
  - Introduced a detailed submission card component that displays submission information, including test case and criteria evaluations, with visual indicators and collapsible sections for test case details.

- **Refactor**
  - Replaced inline submission rendering with a reusable submission card component for improved code organization and consistency.
  - Simplified and standardized type definitions related to problems and challenges for better maintainability.
  - Streamlined logic for identifying and passing the current problem in challenge pages.

- **Style**
  - Enhanced the submission card UI with color-coded badges, icons, and structured layouts for clearer feedback and improved readability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts b/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts
index 3ff6e83ffe..7e0c43f32d 100644
--- a/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts
+++ b/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts
@@ -3,12 +3,17 @@
 import { createAdminClient } from '@tuturuuu/supabase/next/server';
 import {
   NovaChallengeCriteria,
+  NovaProblemTestCase,
   NovaSubmission,
   NovaSubmissionCriteria,
+  NovaSubmissionTestCase,
 } from '@tuturuuu/types/db';
 import { getCurrentSupabaseUser } from '@tuturuuu/utils/user-helper';
 
 export type ExtendedNovaSubmission = NovaSubmission & {
+  test_cases: (NovaProblemTestCase & {
+    result: NovaSubmissionTestCase;
+  })[];
   total_tests: number;
   passed_tests: number;
   test_case_score: number;
@@ -35,6 +40,10 @@ export async function fetchSubmissions(
     .select(
       `
       *,
+      test_cases:nova_problem_test_cases(
+        *,
+        results:nova_submission_test_cases(*)
+      ),
       criteria:nova_challenge_criteria(
         *,
         results:nova_submission_criteria(*)
@@ -51,6 +60,15 @@ export async function fetchSubmissions(
 
   return submissions
     .map((submission) => {
+      // Map testcases to expected format
+      const testcases = submission.test_cases.map((testcase) => ({
+        ...testcase,
+        results: undefined,
+        result: testcase.results.find(
+          (result) => result.submission_id === submission.id
+        ),
+      }));
+
       // Map criteria to expected format
       const criteria = submission.criteria.map((criterion) => ({
         ...criterion,
@@ -64,6 +82,7 @@ export async function fetchSubmissions(
       return {
         ...submission,
         overall_assessment: '',
+        test_cases: testcases,
         total_tests: submission.total_tests || 0,
         passed_tests: submission.passed_tests || 0,
         test_case_score: submission.test_case_score || 0,
diff --git a/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx b/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx
index c97392c60e..eb89259690 100644
--- a/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx
+++ b/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx
@@ -1,7 +1,7 @@
 'use client';
 
 import { ExtendedNovaSubmission, fetchSubmissions } from './actions';
-import ScoreBadge from '@/components/common/ScoreBadge';
+import { SubmissionCard } from './submission-card';
 import { NovaProblem, NovaProblemTestCase } from '@tuturuuu/types/db';
 import { Badge } from '@tuturuuu/ui/badge';
 import { Button } from '@tuturuuu/ui/button';
@@ -14,7 +14,7 @@ import {
 } from '@tuturuuu/ui/card';
 import { LoadingIndicator } from '@tuturuuu/ui/custom/loading-indicator';
 import { toast } from '@tuturuuu/ui/hooks/use-toast';
-import { CheckCircle2, Clock, PlayCircle, XCircle } from '@tuturuuu/ui/icons';
+import { Clock, PlayCircle } from '@tuturuuu/ui/icons';
 import { Progress } from '@tuturuuu/ui/progress';
 import { Tabs, TabsContent, TabsList, TabsTrigger } from '@tuturuuu/ui/tabs';
 import { Textarea } from '@tuturuuu/ui/textarea';
@@ -387,154 +387,10 @@ export default function PromptForm({ problem }: Props) {
 
                     <div className="space-y-4">
                       {groupedSubmissions.map((submission) => (
-                        <Card key={submission.id} className="overflow-hidden">
-                          <CardHeader className="pb-2">
-                            <div className="flex items-center justify-between">
-                              <span className="text-muted-foreground text-xs">
-                                <Clock className="mr-1 inline h-3 w-3" />
-                                {new Date(
-                                  submission.created_at
-                                ).toLocaleString()}
-                              </span>
-
-                              <ScoreBadge
-                                score={submission.total_score}
-                                maxScore={10}
-                                className="px-2 py-0"
-                              >
-                                {submission.total_score.toFixed(2)}/10
-                              </ScoreBadge>
-                            </div>
-                          </CardHeader>
-                          <CardContent className="space-y-6">
-                            <div>
-                              <h3 className="text-foreground mb-1 text-sm font-medium">
-                                Prompt:
-                              </h3>
-                              <div className="bg-muted rounded-md p-2 text-sm">
-                                {submission.prompt}
-                              </div>
-                            </div>
-
-                            {/* Overall Assessment - moved to top for better visibility */}
-                            {submission.overall_assessment && (
-                              <div className="space-y-2">
-                                <h3 className="text-foreground mb-1 text-sm font-medium">
-                                  Overall Assessment:
-                                </h3>
-                                <div className="rounded-md border border-blue-200 bg-blue-50 p-4 dark:border-blue-900 dark:bg-blue-950/30">
-                                  <p className="text-sm">
-                                    {submission.overall_assessment}
-                                  </p>
-                                </div>
-                              </div>
-                            )}
-
-                            {/* Test Case Evaluation */}
-                            {submission.total_tests > 0 && (
-                              <div className="space-y-2">
-                                <div className="flex items-center justify-between">
-                                  <h3 className="text-muted-foreground text-xs font-medium">
-                                    Test Case Evaluation:
-                                  </h3>
-                                  <ScoreBadge
-                                    score={submission.test_case_score}
-                                    maxScore={10}
-                                    className="px-2 py-0"
-                                  >
-                                    {submission.test_case_score.toFixed(2)}/10
-                                  </ScoreBadge>
-                                </div>
-                                <div className="space-y-2 rounded-md border p-4">
-                                  <div>
-                                    <span className="text-sm">
-                                      Passed {submission.passed_tests} of{' '}
-                                      {submission.total_tests} test cases
-                                    </span>
-                                  </div>
-                                  <Progress
-                                    value={
-                                      (submission.passed_tests /
-                                        submission.total_tests) *
-                                      100
-                                    }
-                                    className="h-2 w-full"
-                                    indicatorClassName={
-                                      submission.test_case_score >= 8
-                                        ? 'bg-emerald-500'
-                                        : submission.test_case_score >= 5
-                                          ? 'bg-amber-500'
-                                          : 'bg-red-500'
-                                    }
-                                  />
-                                </div>
-                              </div>
-                            )}
-
-                            {/* Criteria Evaluation */}
-                            {submission.total_criteria > 0 && (
-                              <div className="space-y-2">
-                                <div className="flex items-center justify-between">
-                                  <h3 className="text-muted-foreground text-xs font-medium">
-                                    Criteria Evaluation:
-                                  </h3>
-                                  <ScoreBadge
-                                    score={submission.criteria_score}
-                                    maxScore={10}
-                                    className="px-2 py-0"
-                                  >
-                                    {submission.criteria_score.toFixed(2)}/10
-                                  </ScoreBadge>
-                                </div>
-                                <div className="grid gap-4">
-                                  {submission.criteria.map((cs) => {
-                                    if (!cs || !cs.result) return null;
-
-                                    return (
-                                      <div
-                                        key={cs.id}
-                                        className={`rounded-md border p-3 ${
-                                          cs.result.score >= 8
-                                            ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
-                                            : cs.result.score >= 5
-                                              ? 'border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950/30'
-                                              : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
-                                        }`}
-                                      >
-                                        <div className="mb-2 flex items-center justify-between">
-                                          <div className="flex items-center gap-2">
-                                            {cs.result.score >= 8 ? (
-                                              <CheckCircle2 className="h-4 w-4 text-emerald-500" />
-                                            ) : cs.result.score >= 5 ? (
-                                              <Clock className="h-4 w-4 text-amber-500" />
-                                            ) : (
-                                              <XCircle className="h-4 w-4 text-red-500" />
-                                            )}
-                                            <span className="text-sm font-medium">
-                                              {cs.name}
-                                            </span>
-                                          </div>
-                                          <ScoreBadge
-                                            score={cs.result.score}
-                                            maxScore={10}
-                                          >
-                                            {cs.result.score}/10
-                                          </ScoreBadge>
-                                        </div>
-
-                                        <div className="bg-background/50 mt-1 rounded border p-2">
-                                          <p className="text-muted-foreground text-sm">
-                                            {cs.result.feedback}
-                                          </p>
-                                        </div>
-                                      </div>
-                                    );
-                                  })}
-                                </div>
-                              </div>
-                            )}
-                          </CardContent>
-                        </Card>
+                        <SubmissionCard
+                          key={submission.id}
+                          submission={submission}
+                        />
                       ))}
                     </div>
                   </div>
diff --git a/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx b/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx
new file mode 100644
index 0000000000..b6c3f6977c
--- /dev/null
+++ b/apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx
@@ -0,0 +1,238 @@
+import { ExtendedNovaSubmission } from './actions';
+import ScoreBadge from '@/components/common/ScoreBadge';
+import {
+  Accordion,
+  AccordionContent,
+  AccordionItem,
+  AccordionTrigger,
+} from '@tuturuuu/ui/accordion';
+import { Card, CardContent, CardHeader } from '@tuturuuu/ui/card';
+import {
+  HoverCard,
+  HoverCardContent,
+  HoverCardTrigger,
+} from '@tuturuuu/ui/hover-card';
+import { CheckCircle2, Clock, XCircle } from '@tuturuuu/ui/icons';
+import { Progress } from '@tuturuuu/ui/progress';
+
+interface SubmissionCardProps {
+  submission: ExtendedNovaSubmission;
+}
+
+export function SubmissionCard({ submission }: SubmissionCardProps) {
+  return (
+    <Card className="overflow-hidden">
+      <CardHeader className="pb-2">
+        <div className="flex items-center justify-between">
+          <span className="text-muted-foreground text-xs">
+            <Clock className="mr-1 inline h-3 w-3" />
+            {new Date(submission.created_at).toLocaleString()}
+          </span>
+
+          <ScoreBadge
+            score={submission.total_score}
+            maxScore={10}
+            className="px-2 py-0"
+          >
+            {submission.total_score.toFixed(2)}/10
+          </ScoreBadge>
+        </div>
+      </CardHeader>
+      <CardContent className="space-y-6">
+        <div>
+          <h3 className="text-foreground mb-1 text-sm font-medium">Prompt:</h3>
+          <div className="bg-muted rounded-md p-2 text-sm">
+            {submission.prompt}
+          </div>
+        </div>
+
+        {/* Overall Assessment - moved to top for better visibility */}
+        {submission.overall_assessment && (
+          <div className="space-y-2">
+            <h3 className="text-foreground mb-1 text-sm font-medium">
+              Overall Assessment:
+            </h3>
+            <div className="rounded-md border border-blue-200 bg-blue-50 p-4 dark:border-blue-900 dark:bg-blue-950/30">
+              <p className="text-sm">{submission.overall_assessment}</p>
+            </div>
+          </div>
+        )}
+
+        {/* Test Case Evaluation */}
+        {submission.total_tests > 0 && (
+          <div className="space-y-2">
+            <div className="flex items-center justify-between">
+              <h3 className="text-muted-foreground text-xs font-medium">
+                Test Case Evaluation:
+              </h3>
+              <ScoreBadge
+                score={submission.test_case_score}
+                maxScore={10}
+                className="px-2 py-0"
+              >
+                {submission.test_case_score.toFixed(2)}/10
+              </ScoreBadge>
+            </div>
+            <div className="space-y-2 rounded-md border p-4">
+              <div>
+                <span className="text-sm">
+                  Passed {submission.passed_tests} of {submission.total_tests}{' '}
+                  test cases
+                </span>
+              </div>
+              <Progress
+                value={(submission.passed_tests / submission.total_tests) * 100}
+                className="h-2 w-full"
+                indicatorClassName={
+                  submission.test_case_score >= 8
+                    ? 'bg-emerald-500'
+                    : submission.test_case_score >= 5
+                      ? 'bg-amber-500'
+                      : 'bg-red-500'
+                }
+              />
+
+              {/* Detailed Test Cases */}
+              <div className="mt-4">
+                <Accordion type="single" collapsible className="w-full">
+                  <AccordionItem value="test-cases">
+                    <AccordionTrigger className="text-sm font-medium">
+                      View Test Case Details
+                    </AccordionTrigger>
+                    <AccordionContent>
+                      <div className="space-y-3">
+                        {submission.test_cases.map((testcase, index) => (
+                          <div
+                            key={testcase.id ?? index}
+                            className={`rounded-md border p-3 ${
+                              testcase.result?.matched
+                                ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
+                                : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
+                            }`}
+                          >
+                            <div className="mb-2 flex items-center justify-between">
+                              <span className="text-sm font-medium">
+                                Test Case {index + 1}
+                              </span>
+                              <div className="flex items-center">
+                                {testcase.result?.matched ? (
+                                  <CheckCircle2 className="mr-1 h-4 w-4 text-emerald-500" />
+                                ) : (
+                                  <XCircle className="mr-1 h-4 w-4 text-red-500" />
+                                )}
+                                <span
+                                  className={`text-xs font-medium ${
+                                    testcase.result?.matched
+                                      ? 'text-emerald-500'
+                                      : 'text-red-500'
+                                  }`}
+                                >
+                                  {testcase.result?.matched ? 'PASS' : 'FAIL'}
+                                </span>
+                              </div>
+                            </div>
+
+                            <div className="grid grid-cols-1 gap-2 text-xs md:grid-cols-2">
+                              <div className="space-y-1">
+                                <p className="font-medium">Input:</p>
+                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                  {testcase.input}
+                                </pre>
+                              </div>
+
+                              <div className="space-y-1">
+                                <p className="font-medium">Expected Output:</p>
+                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                  {testcase.output}
+                                </pre>
+                              </div>
+
+                              <div className="space-y-1 md:col-span-2">
+                                <p className="font-medium">Your Output:</p>
+                                <pre
+                                  className={`max-h-24 overflow-auto whitespace-pre-wrap rounded p-2 ${
+                                    testcase.result?.matched
+                                      ? 'bg-emerald-100 dark:bg-emerald-900/20'
+                                      : 'bg-red-100 dark:bg-red-900/20'
+                                  }`}
+                                >
+                                  {testcase.result?.output ||
+                                    'No output produced'}
+                                </pre>
+                              </div>
+                            </div>
+                          </div>
+                        ))}
+                      </div>
+                    </AccordionContent>
+                  </AccordionItem>
+                </Accordion>
+              </div>
+            </div>
+          </div>
+        )}
+
+        {/* Criteria Evaluation */}
+        {submission.total_criteria > 0 && (
+          <div className="space-y-2">
+            <div className="flex items-center justify-between">
+              <h3 className="text-muted-foreground text-xs font-medium">
+                Criteria Evaluation:
+              </h3>
+              <ScoreBadge
+                score={submission.criteria_score}
+                maxScore={10}
+                className="px-2 py-0"
+              >
+                {submission.criteria_score.toFixed(2)}/10
+              </ScoreBadge>
+            </div>
+            <div className="grid gap-2 sm:grid-cols-2">
+              {submission.criteria?.map((cs) => {
+                if (!cs) return null;
+
+                return (
+                  <HoverCard key={cs.result.criteria_id}>
+                    <HoverCardTrigger asChild>
+                      <div
+                        className={`flex cursor-pointer items-center justify-between rounded-md border p-2 ${
+                          cs.result.score >= 8
+                            ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
+                            : cs.result.score >= 5
+                              ? 'border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950/30'
+                              : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
+                        }`}
+                      >
+                        <div className="flex items-center gap-2">
+                          {cs.result.score >= 8 ? (
+                            <CheckCircle2 className="h-4 w-4 text-emerald-500" />
+                          ) : cs.result.score >= 5 ? (
+                            <Clock className="h-4 w-4 text-amber-500" />
+                          ) : (
+                            <XCircle className="h-4 w-4 text-red-500" />
+                          )}
+                          <span className="text-sm">{cs.name}</span>
+                        </div>
+                        <ScoreBadge score={cs.result.score} maxScore={10}>
+                          {cs.result.score}/10
+                        </ScoreBadge>
+                      </div>
+                    </HoverCardTrigger>
+                    <HoverCardContent className="w-80 p-4">
+                      <div className="space-y-2">
+                        <h4 className="font-medium">Feedback</h4>
+                        <p className="text-muted-foreground text-sm">
+                          {cs.result.feedback}
+                        </p>
+                      </div>
+                    </HoverCardContent>
+                  </HoverCard>
+                );
+              })}
+            </div>
+          </div>
+        )}
+      </CardContent>
+    </Card>
+  );
+}
diff --git a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts
index 7fb2a45dd9..3c02de5e6e 100644
--- a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts
+++ b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts
@@ -12,25 +12,30 @@ export const fetchFullSubmission = async (submissionId: string) => {
     .select('*, ...nova_challenge_criteria!inner(name, description)')
     .eq('submission_id', submissionId);
 
-  const { data: testCases, error: errorTestCases } = await sbAdmin
-    .from('nova_submission_test_cases')
-    .select(
-      '*, ...nova_problem_test_cases!inner(input, expected_output:output)'
-    )
-    .eq('submission_id', submissionId);
+  const { data: submissionTestCases, error: errorSubmissionTestCases } =
+    await sbAdmin
+      .from('nova_submission_test_cases')
+      .select(
+        '*, ...nova_problem_test_cases!inner(input, expected_output:output, hidden)'
+      )
+      .eq('nova_problem_test_cases.hidden', false)
+      .eq('submission_id', submissionId);
 
   if (errorCriteria || !submissionCriteria) {
     console.error('Error fetching submission criteria:', errorCriteria);
     return;
   }
 
-  if (errorTestCases || !testCases) {
-    console.error('Error fetching submission test cases:', errorTestCases);
+  if (errorSubmissionTestCases || !submissionTestCases) {
+    console.error(
+      'Error fetching submission test cases:',
+      errorSubmissionTestCases
+    );
     return;
   }
 
   return {
     criteria: submissionCriteria,
-    test_cases: testCases,
+    test_cases: submissionTestCases,
   };
 };
diff --git a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx
index b5345baba1..2122f8f4bf 100644
--- a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx
+++ b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx
@@ -2,7 +2,6 @@ import { ChallengeCriteriaDialog } from './challenge-criteria-dialog';
 import { NovaChallenge } from '@tuturuuu/types/db';
 import { NovaChallengeCriteria } from '@tuturuuu/types/db';
 import { NovaProblem } from '@tuturuuu/types/db';
-import { NovaProblemTestCase } from '@tuturuuu/types/db';
 import { Badge } from '@tuturuuu/ui/badge';
 import { Button } from '@tuturuuu/ui/button';
 import {
@@ -18,9 +17,7 @@ import { useEffect, useRef, useState } from 'react';
 
 type ExtendedNovaChallenge = NovaChallenge & {
   criteria: NovaChallengeCriteria[];
-  problems: (NovaProblem & {
-    test_cases: NovaProblemTestCase[];
-  })[];
+  problems: NovaProblem[];
 };
 
 interface Props {
diff --git a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx
index 66df755852..59e6ca2a74 100644
--- a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx
+++ b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx
@@ -31,9 +31,7 @@ import { useEffect, useState } from 'react';
 
 type ExtendedNovaChallenge = NovaChallenge & {
   criteria: NovaChallengeCriteria[];
-  problems: (NovaProblem & {
-    test_cases: NovaProblemTestCase[];
-  })[];
+  problems: NovaProblem[];
 };
 
 interface Props {
@@ -46,7 +44,7 @@ interface Props {
 
 export default function ChallengeClient({
   currentProblemIndex,
-  problem: currentProblem,
+  problem,
   challenge,
   session,
   submissions,
@@ -159,11 +157,7 @@ export default function ChallengeClient({
         href.startsWith('data:') ||
         href.startsWith('vbscript:')
       )
-        if (
-          href.includes(
-            `/challenges/${challenge.id}/problems/${currentProblem.id}`
-          )
-        )
+        if (href.includes(`/challenges/${challenge.id}/problems/${problem.id}`))
           return;
 
       if (!isNavigationConfirmed) {
@@ -233,12 +227,10 @@ export default function ChallengeClient({
                     </TabsTrigger>
                   </TabsList>
                   <TabsContent value="problem" className="m-0 p-4">
-                    <ProblemComponent problem={currentProblem} />
+                    <ProblemComponent problem={problem} />
                   </TabsContent>
                   <TabsContent value="test-cases" className="m-0 p-4">
-                    <TestCaseComponent
-                      testCases={currentProblem.test_cases || []}
-                    />
+                    <TestCaseComponent testCases={problem.test_cases || []} />
                   </TabsContent>
                 </Tabs>
               </CardContent>
@@ -248,7 +240,7 @@ export default function ChallengeClient({
           <div className="relative flex h-full w-full flex-col gap-4 overflow-hidden">
             <PromptComponent>
               <PromptForm
-                problem={currentProblem}
+                problem={problem}
                 session={session}
                 submissions={submissions}
               />
diff --git a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx
index 895d4a868d..510451f111 100644
--- a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx
+++ b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx
@@ -64,10 +64,10 @@ export default async function Page({ params }: Props) {
       test_cases: problem.test_cases.filter((t) => t.problem_id === problemId),
     }));
 
-    const currentProblem = problems.find((p) => p.id === problemId);
     const currentProblemIndex = problems.findIndex((p) => p.id === problemId);
+    const currentProblem = problems[currentProblemIndex];
 
-    if (!session) {
+    if (!currentProblem) {
       redirect('/challenges');
     }
 
@@ -79,9 +79,7 @@ export default async function Page({ params }: Props) {
         session={session}
         submissions={submissions}
         currentProblemIndex={currentProblemIndex}
-        problem={
-          currentProblem as NovaProblem & { test_cases: NovaProblemTestCase[] }
-        }
+        problem={currentProblem}
       />
     );
   } catch (error) {
diff --git a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx
index dcd3896e7a..ddbd87c20a 100644
--- a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx
+++ b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx
@@ -7,7 +7,7 @@ import {
   NovaProblemTestCase,
   NovaSession,
   NovaSubmissionData,
-  type NovaSubmissionWithScores,
+  NovaSubmissionWithScores,
 } from '@tuturuuu/types/db';
 import { Badge } from '@tuturuuu/ui/badge';
 import { Button } from '@tuturuuu/ui/button';
@@ -381,94 +381,92 @@ export default function PromptForm({ problem, session, submissions }: Props) {
                 </p>
               </div>
             ) : (
-              <>
-                <Tabs
-                  value={submissionsTab}
-                  onValueChange={setSubmissionsTab}
-                  className="w-full"
-                >
-                  <TabsList className="mb-4 grid w-full grid-cols-2">
-                    <TabsTrigger value="current" className="relative">
-                      Current Session
-                      {currentSubmissions && currentSubmissions.length > 0 && (
-                        <Badge variant="secondary" className="ml-2">
-                          {currentSubmissions.length}
-                        </Badge>
-                      )}
-                    </TabsTrigger>
-                    <TabsTrigger value="past" className="relative">
-                      Past Sessions
-                      {pastSubmissions && pastSubmissions.length > 0 && (
-                        <Badge variant="secondary" className="ml-2">
-                          {pastSubmissions.length}
-                        </Badge>
-                      )}
-                    </TabsTrigger>
-                  </TabsList>
-
-                  <TabsContent value="current" className="space-y-4">
-                    {currentSubmissions && currentSubmissions.length === 0 ? (
-                      <div className="flex flex-col items-center justify-center rounded-lg border border-dashed p-8 text-center">
-                        <Clock className="text-muted-foreground mb-2 h-10 w-10" />
-                        <h3 className="text-lg font-medium">
-                          No submissions in current session
-                        </h3>
-                        <p className="text-muted-foreground mt-1 text-sm">
-                          Submit your first prompt to see results here.
-                        </p>
-                      </div>
-                    ) : (
-                      currentSubmissions?.map((submission) => (
-                        <SubmissionCard
-                          key={
-                            submission.id || `current-${submission.created_at}`
-                          }
-                          submission={getSubmissionData(submission)}
-                          isCurrent={true}
-                          onRequestFetch={
-                            submission.id ? requestFetchSubmission : undefined
-                          }
-                          isLoading={
-                            submission.id
-                              ? loadingSubmissions.has(submission.id)
-                              : false
-                          }
-                        />
-                      ))
+              <Tabs
+                value={submissionsTab}
+                onValueChange={setSubmissionsTab}
+                className="w-full"
+              >
+                <TabsList className="mb-4 grid w-full grid-cols-2">
+                  <TabsTrigger value="current" className="relative">
+                    Current Session
+                    {currentSubmissions && currentSubmissions.length > 0 && (
+                      <Badge variant="secondary" className="ml-2">
+                        {currentSubmissions.length}
+                      </Badge>
                     )}
-                  </TabsContent>
-
-                  <TabsContent value="past" className="space-y-4">
-                    {pastSubmissions && pastSubmissions.length === 0 ? (
-                      <div className="flex flex-col items-center justify-center rounded-lg border border-dashed p-8 text-center">
-                        <Clock className="text-muted-foreground mb-2 h-10 w-10" />
-                        <h3 className="text-lg font-medium">
-                          No submissions from past sessions
-                        </h3>
-                        <p className="text-muted-foreground mt-1 text-sm">
-                          Past session submissions will appear here.
-                        </p>
-                      </div>
-                    ) : (
-                      pastSubmissions?.map((submission) => (
-                        <SubmissionCard
-                          key={submission.id || `past-${submission.created_at}`}
-                          submission={getSubmissionData(submission)}
-                          isCurrent={false}
-                          onRequestFetch={
-                            submission.id ? requestFetchSubmission : undefined
-                          }
-                          isLoading={
-                            submission.id
-                              ? loadingSubmissions.has(submission.id)
-                              : false
-                          }
-                        />
-                      ))
+                  </TabsTrigger>
+                  <TabsTrigger value="past" className="relative">
+                    Past Sessions
+                    {pastSubmissions && pastSubmissions.length > 0 && (
+                      <Badge variant="secondary" className="ml-2">
+                        {pastSubmissions.length}
+                      </Badge>
                     )}
-                  </TabsContent>
-                </Tabs>
-              </>
+                  </TabsTrigger>
+                </TabsList>
+
+                <TabsContent value="current" className="space-y-4">
+                  {currentSubmissions && currentSubmissions.length === 0 ? (
+                    <div className="flex flex-col items-center justify-center rounded-lg border border-dashed p-8 text-center">
+                      <Clock className="text-muted-foreground mb-2 h-10 w-10" />
+                      <h3 className="text-lg font-medium">
+                        No submissions in current session
+                      </h3>
+                      <p className="text-muted-foreground mt-1 text-sm">
+                        Submit your first prompt to see results here.
+                      </p>
+                    </div>
+                  ) : (
+                    currentSubmissions?.map((submission) => (
+                      <SubmissionCard
+                        key={
+                          submission.id || `current-${submission.created_at}`
+                        }
+                        submission={getSubmissionData(submission)}
+                        isCurrent={true}
+                        onRequestFetch={
+                          submission.id ? requestFetchSubmission : undefined
+                        }
+                        isLoading={
+                          submission.id
+                            ? loadingSubmissions.has(submission.id)
+                            : false
+                        }
+                      />
+                    ))
+                  )}
+                </TabsContent>
+
+                <TabsContent value="past" className="space-y-4">
+                  {pastSubmissions && pastSubmissions.length === 0 ? (
+                    <div className="flex flex-col items-center justify-center rounded-lg border border-dashed p-8 text-center">
+                      <Clock className="text-muted-foreground mb-2 h-10 w-10" />
+                      <h3 className="text-lg font-medium">
+                        No submissions from past sessions
+                      </h3>
+                      <p className="text-muted-foreground mt-1 text-sm">
+                        Past session submissions will appear here.
+                      </p>
+                    </div>
+                  ) : (
+                    pastSubmissions?.map((submission) => (
+                      <SubmissionCard
+                        key={submission.id || `past-${submission.created_at}`}
+                        submission={getSubmissionData(submission)}
+                        isCurrent={false}
+                        onRequestFetch={
+                          submission.id ? requestFetchSubmission : undefined
+                        }
+                        isLoading={
+                          submission.id
+                            ? loadingSubmissions.has(submission.id)
+                            : false
+                        }
+                      />
+                    ))
+                  )}
+                </TabsContent>
+              </Tabs>
             )}
           </TabsContent>
         </Tabs>
diff --git a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx
index 76f8ec4d8f..44bc346560 100644
--- a/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx
+++ b/apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx
@@ -1,5 +1,11 @@
 import ScoreBadge from '@/components/common/ScoreBadge';
 import { NovaSubmissionData } from '@tuturuuu/types/db';
+import {
+  Accordion,
+  AccordionContent,
+  AccordionItem,
+  AccordionTrigger,
+} from '@tuturuuu/ui/accordion';
 import { Badge } from '@tuturuuu/ui/badge';
 import { Card, CardContent, CardHeader } from '@tuturuuu/ui/card';
 import {
@@ -160,6 +166,82 @@ export function SubmissionCard({
                     }
                   />
                 )}
+
+              {/* Detailed Test Cases */}
+              <div className="mt-4">
+                <Accordion type="single" collapsible className="w-full">
+                  <AccordionItem value="test-cases">
+                    <AccordionTrigger className="text-sm font-medium">
+                      View Test Case Details
+                    </AccordionTrigger>
+                    <AccordionContent>
+                      <div className="space-y-3">
+                        {submission.test_cases?.map((testcase, index) => (
+                          <div
+                            key={testcase.test_case_id ?? index}
+                            className={`rounded-md border p-3 ${
+                              testcase.matched
+                                ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
+                                : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
+                            }`}
+                          >
+                            <div className="mb-2 flex items-center justify-between">
+                              <span className="text-sm font-medium">
+                                Test Case {index + 1}
+                              </span>
+                              <div className="flex items-center">
+                                {testcase.matched ? (
+                                  <CheckCircle2 className="mr-1 h-4 w-4 text-emerald-500" />
+                                ) : (
+                                  <XCircle className="mr-1 h-4 w-4 text-red-500" />
+                                )}
+                                <span
+                                  className={`text-xs font-medium ${
+                                    testcase.matched
+                                      ? 'text-emerald-500'
+                                      : 'text-red-500'
+                                  }`}
+                                >
+                                  {testcase.matched ? 'PASS' : 'FAIL'}
+                                </span>
+                              </div>
+                            </div>
+
+                            <div className="grid grid-cols-1 gap-2 text-xs md:grid-cols-2">
+                              <div className="space-y-1">
+                                <p className="font-medium">Input:</p>
+                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                  {testcase.input}
+                                </pre>
+                              </div>
+
+                              <div className="space-y-1">
+                                <p className="font-medium">Expected Output:</p>
+                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                  {testcase.output}
+                                </pre>
+                              </div>
+
+                              <div className="space-y-1 md:col-span-2">
+                                <p className="font-medium">Your Output:</p>
+                                <pre
+                                  className={`max-h-24 overflow-auto whitespace-pre-wrap rounded p-2 ${
+                                    testcase.matched
+                                      ? 'bg-emerald-100 dark:bg-emerald-900/20'
+                                      : 'bg-red-100 dark:bg-red-900/20'
+                                  }`}
+                                >
+                                  {testcase.output || 'No output produced'}
+                                </pre>
+                              </div>
+                            </div>
+                          </div>
+                        ))}
+                      </div>
+                    </AccordionContent>
+                  </AccordionItem>
+                </Accordion>
+              </div>
             </div>
           </div>
         ) : (


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 6**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx (1)</summary><blockquote>

`1-290`: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Add missing test coverage for the component.**

All the modified lines in this file are flagged as not covered by tests according to codecov/patch check. Consider adding unit/integration tests to ensure these component changes work as expected.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check for existing tests for this component
fd "client\.test" --full-path --exec echo "Found test file: {}"

# Check if there are any test frameworks set up in the project
grep -r "jest\|vitest\|@testing-library" package.json
```

Length of output: 252

---



</details>

**Add missing test coverage for `ChallengeClient` component**

It looks like there are no existing tests covering the new client.tsx under `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx` (the only “client.test.ts” found lives in `packages/supabase`). Since Vitest is already configured in `package.json`, please:

- Create a test file alongside the component, e.g.  
  `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.test.tsx`
- Use Vitest + Testing Library (`@testing-library/react`) to cover:
  - Rendering of tabs, header, and prompt form
  - Navigation guards (popstate, beforeunload, link clicks)
  - `handleEndChallenge` success/failure flows (mocking fetch)
  - Dialog open/close and confirm/cancel behaviors

This will ensure new lines are exercised and satisfy the codecov/patch requirements.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 34-34: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L34
Added line #L34 was not covered by tests

---

[warning] 47-47: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L47
Added line #L47 was not covered by tests

---

[warning] 160-160: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L160
Added line #L160 was not covered by tests

---

[warning] 230-230: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L230
Added line #L230 was not covered by tests

---

[warning] 233-233: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L233
Added line #L233 was not covered by tests

---

[warning] 243-243: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L243
Added line #L243 was not covered by tests

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx (2)</summary><blockquote>

`104-165`: **Consider adding accessibility attributes to the test case display.**

The test case display could benefit from additional accessibility attributes to improve screen reader support, such as `aria-label` for the test case status icons and possibly `aria-expanded` state for the accordion.

```diff
-                              <div className="flex items-center">
+                              <div className="flex items-center" aria-label={testcase.result?.matched ? "Test passed" : "Test failed"}>
                                 {testcase.result?.matched ? (
-                                  <CheckCircle2 className="mr-1 h-4 w-4 text-emerald-500" />
+                                  <CheckCircle2 className="mr-1 h-4 w-4 text-emerald-500" aria-hidden="true" />
                                 ) : (
-                                  <XCircle className="mr-1 h-4 w-4 text-red-500" />
+                                  <XCircle className="mr-1 h-4 w-4 text-red-500" aria-hidden="true" />
                                 )}
```

---

`136-163`: **Consider adding error handling for missing or malformed outputs.**

Currently, there's a fallback for missing output (`testcase.result?.output || 'No output produced'`), but you might want to consider additional error handling for malformed or extremely long outputs to prevent UI issues.

```diff
-                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                  {testcase.input ? testcase.input : 'No input provided'}
-                                  {testcase.input}
                                 </pre>

                                 <pre
                                   className={`max-h-24 overflow-auto whitespace-pre-wrap rounded p-2 ${
                                     testcase.result?.matched
                                       ? 'bg-emerald-100 dark:bg-emerald-900/20'
                                       : 'bg-red-100 dark:bg-red-900/20'
                                   }`}
                                 >
-                                  {testcase.result?.output ||
-                                    'No output produced'}
+                                  {testcase.result?.output 
+                                    ? testcase.result.output.length > 1000 
+                                      ? testcase.result.output.substring(0, 1000) + '... (output truncated)' 
+                                      : testcase.result.output
+                                    : 'No output produced'}
                                 </pre>
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 38a1f1e98e271ce2127f8a37ec65459fa3dd81e1 and 901cc59c589ea43625e13891d8782047124ce876.

</details>

<details>
<summary>📒 Files selected for processing (9)</summary>

* `apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts` (4 hunks)
* `apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx` (3 hunks)
* `apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx` (1 hunks)
* `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts` (1 hunks)
* `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx` (1 hunks)
* `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx` (5 hunks)
* `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx` (2 hunks)
* `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx` (2 hunks)
* `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx` (2 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (4)</summary>

<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx (1)</summary><blockquote>

<details>
<summary>packages/types/src/db.ts (1)</summary>

* `NovaProblem` (87-87)

</details>

</blockquote></details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts (1)</summary><blockquote>

<details>
<summary>packages/types/src/db.ts (2)</summary>

* `NovaSubmission` (90-90)
* `NovaProblemTestCase` (86-86)

</details>

</blockquote></details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx (3)</summary><blockquote>

<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts (1)</summary>

* `ExtendedNovaSubmission` (13-28)

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx (1)</summary>

* `SubmissionCard` (36-342)

</details>
<details>
<summary>apps/nova/src/components/common/ScoreBadge.tsx (1)</summary>

* `ScoreBadge` (4-33)

</details>

</blockquote></details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx (2)</summary><blockquote>

<details>
<summary>packages/types/src/db.ts (1)</summary>

* `NovaProblem` (87-87)

</details>
<details>
<summary>apps/upskii/src/app/[locale]/(dashboard)/[wsId]/shared/problem-component.tsx (1)</summary>

* `ProblemComponent` (12-90)

</details>

</blockquote></details>

</details><details>
<summary>🪛 GitHub Check: codecov/patch</summary>

<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx</summary>

[warning] 68-68: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx#L68
Added line #L68 was not covered by tests

---

[warning] 70-70: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx#L70
Added line #L70 was not covered by tests

---

[warning] 82-82: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx#L82
Added line #L82 was not covered by tests

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx</summary>

[warning] 20-20: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx#L20
Added line #L20 was not covered by tests

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts</summary>

[warning] 15-22: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts#L15-L22
Added lines #L15 - L22 were not covered by tests

---

[warning] 29-33: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts#L29-L33
Added lines #L29 - L33 were not covered by tests

---

[warning] 39-39: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts#L39
Added line #L39 was not covered by tests

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx</summary>

[warning] 3-8: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx#L3-L8
Added lines #L3 - L8 were not covered by tests

---

[warning] 169-244: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx#L169-L244
Added lines #L169 - L244 were not covered by tests

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx</summary>

[warning] 10-10: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx#L10
Added line #L10 was not covered by tests

---

[warning] 384-395: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx#L384-L395
Added lines #L384 - L395 were not covered by tests

---

[warning] 397-403: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx#L397-L403
Added lines #L397 - L403 were not covered by tests

---

[warning] 405-469: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx#L405-L469
Added lines #L405 - L469 were not covered by tests

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts</summary>

[warning] 6-6: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts#L6
Added line #L6 was not covered by tests

---

[warning] 9-9: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts#L9
Added line #L9 was not covered by tests

---

[warning] 14-16: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts#L14-L16
Added lines #L14 - L16 were not covered by tests

---

[warning] 43-46: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts#L43-L46
Added lines #L43 - L46 were not covered by tests

---

[warning] 63-71: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts#L63-L71
Added lines #L63 - L71 were not covered by tests

---

[warning] 85-85: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts#L85
Added line #L85 was not covered by tests

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx</summary>

[warning] 4-4: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx#L4
Added line #L4 was not covered by tests

---

[warning] 17-17: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx#L17
Added line #L17 was not covered by tests

---

[warning] 390-393: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx#L390-L393
Added lines #L390 - L393 were not covered by tests

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx</summary>

[warning] 2-238: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx#L2-L238
Added lines #L2 - L238 were not covered by tests

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx</summary>

[warning] 34-34: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L34
Added line #L34 was not covered by tests

---

[warning] 47-47: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L47
Added line #L47 was not covered by tests

---

[warning] 160-160: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L160
Added line #L160 was not covered by tests

---

[warning] 230-230: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L230
Added line #L230 was not covered by tests

---

[warning] 233-233: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L233
Added line #L233 was not covered by tests

---

[warning] 243-243: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L243
Added line #L243 was not covered by tests

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (6)</summary>

* GitHub Check: Analyze (javascript-typescript)
* GitHub Check: Deploy-Preview
* GitHub Check: Deploy-Preview
* GitHub Check: Deploy-Preview
* GitHub Check: Deploy-Preview
* GitHub Check: Deploy-Preview

</details>

<details>
<summary>🔇 Additional comments (19)</summary><blockquote>

<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx (2)</summary>

`10-10`: **Import changed from type-only to value import.**

The import for `NovaSubmissionWithScores` has been changed from a type-only import to a regular import. While this doesn't affect runtime behavior, it's good to be consistent with the module's export style.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 10-10: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx#L10
Added line #L10 was not covered by tests

</details>

</details>

---

`384-469`: **Excellent refactoring using SubmissionCard component.**

The code now uses the new `SubmissionCard` component to display submissions, which improves code organization and maintainability by encapsulating the submission display logic. The unnecessary React fragment wrapper has been removed, making the code cleaner.


However, this section lacks test coverage as flagged by static analysis. Consider adding tests for this functionality to ensure it behaves as expected.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 384-395: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx#L384-L395
Added lines #L384 - L395 were not covered by tests

---

[warning] 397-403: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx#L397-L403
Added lines #L397 - L403 were not covered by tests

---

[warning] 405-469: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx#L405-L469
Added lines #L405 - L469 were not covered by tests

</details>

</details>

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx (2)</summary>

`68-68`: **Improved problem retrieval logic.**

The code now finds the problem index first and then accesses the problem directly, which is more efficient than the previous approach. The null check now verifies the problem exists rather than the session, which makes the code more robust.



Also applies to: 70-70

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 68-68: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx#L68
Added line #L68 was not covered by tests

</details>

</details>

---

`82-82`: **Simplified prop passing.**

Removed unnecessary type assertion when passing the problem prop to the ChallengeClient component, making the code cleaner and more maintainable.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 82-82: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx#L82
Added line #L82 was not covered by tests

</details>

</details>

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts (3)</summary>

`15-22`: **Now filtering out hidden test cases.**

This change directly implements the PR objective by adding a filter to exclude hidden test cases (`eq('nova_problem_test_cases.hidden', false)`). Variable names have been improved for clarity (from `testCases` to `submissionTestCases`).


The additional inclusion of the `hidden` field in the selection also aligns with the overall goal of the PR.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 15-22: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts#L15-L22
Added lines #L15 - L22 were not covered by tests

</details>

</details>

---

`29-33`: **Improved error messaging.**

Error message and variable names have been updated for consistency, which improves code readability and maintainability.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 29-33: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts#L29-L33
Added lines #L29 - L33 were not covered by tests

</details>

</details>

---

`39-39`: **Consistent property naming.**

Changed the property name to `test_cases` in the returned object, which maintains consistency with the variable naming convention used earlier in the function.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 39-39: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts#L39
Added line #L39 was not covered by tests

</details>

</details>

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx (6)</summary>

`32-35`: **Type definition simplification looks good.**

The type definition for `ExtendedNovaChallenge` has been simplified by removing the nested `test_cases` array, which aligns with the broader refactor to handle test cases and submission results elsewhere in the application.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 34-34: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L34
Added line #L34 was not covered by tests

</details>

</details>

---

`45-51`: **Prop name change improves consistency.**

Renaming the prop from `currentProblem` to `problem` in the component parameters improves naming consistency throughout the codebase. This matches how the prop is used in related components like the `ProblemComponent`.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 47-47: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L47
Added line #L47 was not covered by tests

</details>

</details>

---

`159-161`: **Conditional navigation check correctly updated.**

The navigation check has been properly updated to use the new `problem` variable name, maintaining the same functionality to prevent unwanted navigation away from the current problem page.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 160-160: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L160
Added line #L160 was not covered by tests

</details>

</details>

---

`230-231`: **Updated prop name in child component usage.**

The prop name change is consistently applied when passing the problem to the `ProblemComponent`, making the code more maintainable and easier to follow.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 230-230: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L230
Added line #L230 was not covered by tests

</details>

</details>

---

`233-234`: **Updated test cases prop passing.**

The test cases are correctly passed to the `TestCaseComponent`, with a fallback to an empty array if `problem.test_cases` is undefined, which is a good defensive programming practice.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 233-233: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L233
Added line #L233 was not covered by tests

</details>

</details>

---

`242-246`: **Updated prop name in PromptForm usage.**

The prop renaming is consistently applied to the `PromptForm` component props, maintaining coherence across the component hierarchy.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 243-243: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx#L243
Added line #L243 was not covered by tests

</details>

</details>

</details>
<details>
<summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx (6)</summary>

`1-20`: **Well-structured component imports and props interface.**

The imports are well organized, and the `SubmissionCardProps` interface clearly defines the expected props. The component is using the `ExtendedNovaSubmission` type from the actions file which provides strong typing for the submission data.

---

`22-48`: **Card layout and prompt display looks good.**

The component renders a clean card layout with a header showing submission time and score, and a content section displaying the prompt text in a styled container. The score is properly formatted to two decimal places.

---

`49-59`: **Overall assessment section is well-positioned.**

Showing the overall assessment at the top of the card improves visibility for users, and the conditional rendering ensures it only appears when assessment data is available.

---

`61-93`: **Test case evaluation summary is clear and informative.**

The test case evaluation section effectively summarizes performance with:
1. A pass/total count
2. A progress bar with color-coded indicators based on score
3. A clear score badge

The conditional rendering ensures this section only appears when test cases exist.

---

`94-173`: **Detailed test case display implements the PR objective well.**

This section fulfills the PR objective to "Show non-hidden testcases for users while doing the test" by:
1. Using an accordion to keep the interface clean while allowing detailed inspection
2. Clearly indicating pass/fail status with icons and colors
3. Showing input, expected output, and actual output in readable, properly formatted containers
4. Using color-coding to highlight matching or non-matching outputs

The implementation is thorough and user-friendly.

---

`175-234`: **Criteria evaluation section is well-designed.**

The criteria evaluation section:
1. Shows an overall score summary
2. Uses a grid layout for efficient space usage
3. Implements hover cards for detailed feedback without cluttering the UI
4. Uses consistent color-coding and icons to indicate performance levels

The implementation is polished and user-friendly.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T06:51:11Z
user: login: vhpx
body: LGTM! Thanks @khangronky.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-12T07:18:39Z

Review comments:
diff_hunk: @@ -18,9 +17,7 @@
 
 type ExtendedNovaChallenge = NovaChallenge & {
   criteria: NovaChallengeCriteria[];
-  problems: (NovaProblem & {
-    test_cases: NovaProblemTestCase[];
-  })[];
+  problems: NovaProblem[];
path: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Type simplification improves modularity.**

The `ExtendedNovaChallenge` type has been simplified to use just `NovaProblem[]` instead of including nested test cases. This change follows a good design pattern of separating concerns and matches the broader refactoring where test case data is now handled separately.


The lack of test coverage for this change is flagged by static analysis:

---

🏁 Script executed:

```shell
#!/bin/bash
# Check how ExtendedNovaChallenge is used across the codebase
rg -A 3 -B 3 "ExtendedNovaChallenge" --type tsx --type ts
```

Length of output: 85

---

🏁 Script executed:

```shell
#!/bin/bash
# Search for all references to ExtendedNovaChallenge in .ts and .tsx files
rg -A 3 -B 3 "ExtendedNovaChallenge" -g "*.ts" -g "*.tsx"
```

Length of output: 15450

---



</details>

**Clarify type usage and add test coverage**

The `ExtendedNovaChallenge` interface is correctly simplified in your client‐side components (`client.tsx`, `challengeHeader.tsx`) to use `problems: NovaProblem[]`, while the server boundary (`page.tsx`) still defines it with nested `test_cases` so it can fetch raw data. To ensure consistency and robustness:

- Unify or explicitly distinguish your local challenge interfaces (e.g. rename the server’s version to `ChallengeWithTestCases` and the client’s to `ChallengeSummary`) to avoid confusion when they live side-by-side.  
- Add unit tests for `challengeHeader.tsx` (and any other component consuming the simplified shape) to cover the new `NovaProblem[]` structure.  
- Verify that all downstream components no longer rely on nested `test_cases` under `challenge.problems`.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 20-20: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx#L20
Added line #L20 was not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In
apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx
at line 20, the ExtendedNovaChallenge type was simplified to use problems:
NovaProblem[] without nested test cases. To fix the issue, rename the
server-side interface to something like ChallengeWithTestCases and the
client-side one to ChallengeSummary to clearly distinguish them. Then, add unit
tests for challengeHeader.tsx to cover the simplified NovaProblem[] structure
and ensure no downstream components rely on nested test_cases within
challenge.problems.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-12T06:51:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,7 +1,7 @@
 'use client';
 
 import { ExtendedNovaSubmission, fetchSubmissions } from './actions';
-import ScoreBadge from '@/components/common/ScoreBadge';
+import { SubmissionCard } from './submission-card';
path: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Incorrect import path – `SubmissionCard` is likely unresolved**

`prompt-form.tsx` lives under the *admin* folder, while the component was added under the *challenges* folder (`(dashboard)/challenges/.../submission-card.tsx`).  
Using a relative path `./submission-card` will fail to resolve and break the build.

```diff
-import { SubmissionCard } from './submission-card';
+// adjust the import to the actual relative path (example)
+import { SubmissionCard } from '../challenges/[challengeId]/problems/[problemId]/submission-card';
```

Please verify the real location (or move the file to a shared/component folder) so the import resolves.



> Committable suggestion skipped: line range outside the PR's diff.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 4-4: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx#L4
Added line #L4 was not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In
apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx
at line 4, the import path for SubmissionCard is incorrect because it uses a
relative path './submission-card' that does not resolve from the admin folder.
To fix this, update the import statement to use the correct relative path
pointing to the actual location of SubmissionCard under the
(dashboard)/challenges/... folder or move SubmissionCard to a shared or common
components directory and import it from there to ensure the path resolves
correctly and the build succeeds.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-12T06:51:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -387,154 +387,10 @@
 
                     <div className="space-y-4">
                       {groupedSubmissions.map((submission) => (
-                        <Card key={submission.id} className="overflow-hidden">
-                          <CardHeader className="pb-2">
-                            <div className="flex items-center justify-between">
-                              <span className="text-muted-foreground text-xs">
-                                <Clock className="mr-1 inline h-3 w-3" />
-                                {new Date(
-                                  submission.created_at
-                                ).toLocaleString()}
-                              </span>
-
-                              <ScoreBadge
-                                score={submission.total_score}
-                                maxScore={10}
-                                className="px-2 py-0"
-                              >
-                                {submission.total_score.toFixed(2)}/10
-                              </ScoreBadge>
-                            </div>
-                          </CardHeader>
-                          <CardContent className="space-y-6">
-                            <div>
-                              <h3 className="text-foreground mb-1 text-sm font-medium">
-                                Prompt:
-                              </h3>
-                              <div className="bg-muted rounded-md p-2 text-sm">
-                                {submission.prompt}
-                              </div>
-                            </div>
-
-                            {/* Overall Assessment - moved to top for better visibility */}
-                            {submission.overall_assessment && (
-                              <div className="space-y-2">
-                                <h3 className="text-foreground mb-1 text-sm font-medium">
-                                  Overall Assessment:
-                                </h3>
-                                <div className="rounded-md border border-blue-200 bg-blue-50 p-4 dark:border-blue-900 dark:bg-blue-950/30">
-                                  <p className="text-sm">
-                                    {submission.overall_assessment}
-                                  </p>
-                                </div>
-                              </div>
-                            )}
-
-                            {/* Test Case Evaluation */}
-                            {submission.total_tests > 0 && (
-                              <div className="space-y-2">
-                                <div className="flex items-center justify-between">
-                                  <h3 className="text-muted-foreground text-xs font-medium">
-                                    Test Case Evaluation:
-                                  </h3>
-                                  <ScoreBadge
-                                    score={submission.test_case_score}
-                                    maxScore={10}
-                                    className="px-2 py-0"
-                                  >
-                                    {submission.test_case_score.toFixed(2)}/10
-                                  </ScoreBadge>
-                                </div>
-                                <div className="space-y-2 rounded-md border p-4">
-                                  <div>
-                                    <span className="text-sm">
-                                      Passed {submission.passed_tests} of{' '}
-                                      {submission.total_tests} test cases
-                                    </span>
-                                  </div>
-                                  <Progress
-                                    value={
-                                      (submission.passed_tests /
-                                        submission.total_tests) *
-                                      100
-                                    }
-                                    className="h-2 w-full"
-                                    indicatorClassName={
-                                      submission.test_case_score >= 8
-                                        ? 'bg-emerald-500'
-                                        : submission.test_case_score >= 5
-                                          ? 'bg-amber-500'
-                                          : 'bg-red-500'
-                                    }
-                                  />
-                                </div>
-                              </div>
-                            )}
-
-                            {/* Criteria Evaluation */}
-                            {submission.total_criteria > 0 && (
-                              <div className="space-y-2">
-                                <div className="flex items-center justify-between">
-                                  <h3 className="text-muted-foreground text-xs font-medium">
-                                    Criteria Evaluation:
-                                  </h3>
-                                  <ScoreBadge
-                                    score={submission.criteria_score}
-                                    maxScore={10}
-                                    className="px-2 py-0"
-                                  >
-                                    {submission.criteria_score.toFixed(2)}/10
-                                  </ScoreBadge>
-                                </div>
-                                <div className="grid gap-4">
-                                  {submission.criteria.map((cs) => {
-                                    if (!cs || !cs.result) return null;
-
-                                    return (
-                                      <div
-                                        key={cs.id}
-                                        className={`rounded-md border p-3 ${
-                                          cs.result.score >= 8
-                                            ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
-                                            : cs.result.score >= 5
-                                              ? 'border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950/30'
-                                              : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
-                                        }`}
-                                      >
-                                        <div className="mb-2 flex items-center justify-between">
-                                          <div className="flex items-center gap-2">
-                                            {cs.result.score >= 8 ? (
-                                              <CheckCircle2 className="h-4 w-4 text-emerald-500" />
-                                            ) : cs.result.score >= 5 ? (
-                                              <Clock className="h-4 w-4 text-amber-500" />
-                                            ) : (
-                                              <XCircle className="h-4 w-4 text-red-500" />
-                                            )}
-                                            <span className="text-sm font-medium">
-                                              {cs.name}
-                                            </span>
-                                          </div>
-                                          <ScoreBadge
-                                            score={cs.result.score}
-                                            maxScore={10}
-                                          >
-                                            {cs.result.score}/10
-                                          </ScoreBadge>
-                                        </div>
-
-                                        <div className="bg-background/50 mt-1 rounded border p-2">
-                                          <p className="text-muted-foreground text-sm">
-                                            {cs.result.feedback}
-                                          </p>
-                                        </div>
-                                      </div>
-                                    );
-                                  })}
-                                </div>
-                              </div>
-                            )}
-                          </CardContent>
-                        </Card>
+                        <SubmissionCard
+                          key={submission.id}
+                          submission={submission}
+                        />
path: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**`SubmissionCard` is invoked without required props – TypeScript error & runtime break**

`SubmissionCardProps` requires `isCurrent` (and optionally `isLoading`, etc.), but the call site only passes `submission`.  
Compilation will fail (`Property 'isCurrent' is missing ...`) and at runtime the card cannot know whether it is the current session.

```diff
-<SubmissionCard
-  key={submission.id}
-  submission={submission}
-/>
+<SubmissionCard
+  key={submission.id}
+  submission={submission}
+  isCurrent={/* derive truthy value, e.g. */ sessionKey === 'standalone'}
+  /* isLoading / queuePosition if applicable */
+/>
```
Make sure to supply all mandatory props or mark them optional in the component’s interface.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
                        <SubmissionCard
                          key={submission.id}
                          submission={submission}
                          isCurrent={/* derive truthy value, e.g. */ sessionKey === 'standalone'}
                          /* isLoading / queuePosition if applicable */
                        />
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 390-393: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx#L390-L393
Added lines #L390 - L393 were not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In
apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx
around lines 390 to 393, the SubmissionCard component is called without the
required isCurrent prop, causing TypeScript errors and runtime issues. Update
the SubmissionCard invocation to include the isCurrent prop with the appropriate
boolean value indicating if the submission is the current one. Also, verify if
other optional props like isLoading need to be passed. Alternatively, if
isCurrent should not be mandatory, adjust the SubmissionCardProps interface to
make isCurrent optional.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-12T06:51:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -160,6 +166,82 @@
                     }
                   />
                 )}
+
+              {/* Detailed Test Cases */}
+              <div className="mt-4">
+                <Accordion type="single" collapsible className="w-full">
+                  <AccordionItem value="test-cases">
+                    <AccordionTrigger className="text-sm font-medium">
+                      View Test Case Details
+                    </AccordionTrigger>
+                    <AccordionContent>
+                      <div className="space-y-3">
+                        {submission.test_cases?.map((testcase, index) => (
+                          <div
+                            key={testcase.test_case_id ?? index}
+                            className={`rounded-md border p-3 ${
+                              testcase.matched
+                                ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
+                                : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
+                            }`}
+                          >
+                            <div className="mb-2 flex items-center justify-between">
+                              <span className="text-sm font-medium">
+                                Test Case {index + 1}
+                              </span>
+                              <div className="flex items-center">
+                                {testcase.matched ? (
+                                  <CheckCircle2 className="mr-1 h-4 w-4 text-emerald-500" />
+                                ) : (
+                                  <XCircle className="mr-1 h-4 w-4 text-red-500" />
+                                )}
+                                <span
+                                  className={`text-xs font-medium ${
+                                    testcase.matched
+                                      ? 'text-emerald-500'
+                                      : 'text-red-500'
+                                  }`}
+                                >
+                                  {testcase.matched ? 'PASS' : 'FAIL'}
+                                </span>
+                              </div>
+                            </div>
+
+                            <div className="grid grid-cols-1 gap-2 text-xs md:grid-cols-2">
+                              <div className="space-y-1">
+                                <p className="font-medium">Input:</p>
+                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                  {testcase.input}
+                                </pre>
+                              </div>
+
+                              <div className="space-y-1">
+                                <p className="font-medium">Expected Output:</p>
+                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                  {testcase.output}
+                                </pre>
+                              </div>
+
+                              <div className="space-y-1 md:col-span-2">
+                                <p className="font-medium">Your Output:</p>
+                                <pre
+                                  className={`max-h-24 overflow-auto whitespace-pre-wrap rounded p-2 ${
+                                    testcase.matched
+                                      ? 'bg-emerald-100 dark:bg-emerald-900/20'
+                                      : 'bg-red-100 dark:bg-red-900/20'
+                                  }`}
+                                >
+                                  {testcase.output || 'No output produced'}
+                                </pre>
+                              </div>
+                            </div>
+                          </div>
+                        ))}
+                      </div>
+                    </AccordionContent>
+                  </AccordionItem>
+                </Accordion>
+              </div>
path: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Wrong field used inside “Test Case Details” – always shows expected output and mis-labels pass/fail**

`matched` and the user’s output live under `testcase.result`, but the JSX references the parent object:

* `testcase.matched` → should be `testcase.result?.matched`
* The **“Your Output”** block prints `testcase.output` (expected output) instead of the user’s output.

```diff
-  className={`rounded-md border p-3 ${testcase.matched ? ...}`}
+  className={`rounded-md border p-3 ${testcase.result?.matched ? ...}`}

- {testcase.matched ? 'PASS' : 'FAIL'}
+ {testcase.result?.matched ? 'PASS' : 'FAIL'}

- {testcase.output || 'No output produced'}
+ {testcase.result?.output ?? 'No output produced'}
```

Without this fix every test case will look like **FAIL** and the user’s output is never displayed.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
{submission.test_cases?.map((testcase, index) => (
  <div
    key={testcase.test_case_id ?? index}
-   className={`rounded-md border p-3 ${
-     testcase.matched
-       ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
-       : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
-   }`}
+   className={`rounded-md border p-3 ${
+     testcase.result?.matched
+       ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
+       : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
+   }`}
  >
    {/* ... */}
    <span
      className={`text-xs font-medium ${
-       testcase.matched
+       testcase.result?.matched
          ? 'text-emerald-500'
          : 'text-red-500'
      }`}
    >
-     {testcase.matched ? 'PASS' : 'FAIL'}
+     {testcase.result?.matched ? 'PASS' : 'FAIL'}
    </span>
    {/* ... */}
    <div className="space-y-1 md:col-span-2">
      <p className="font-medium">Your Output:</p>
      <pre
        className={`max-h-24 overflow-auto whitespace-pre-wrap rounded p-2 ${
          testcase.matched
            ? 'bg-emerald-100 dark:bg-emerald-900/20'
            : 'bg-red-100 dark:bg-red-900/20'
        }`}
      >
-       {testcase.output || 'No output produced'}
+       {testcase.result?.output ?? 'No output produced'}
      </pre>
    </div>
    {/* ... */}
  </div>
))}
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 169-244: apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx#L169-L244
Added lines #L169 - L244 were not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In
apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx
between lines 169 and 244, the code incorrectly uses testcase.matched and
testcase.output for pass/fail status and user output display. Update all
references of testcase.matched to testcase.result?.matched and change the "Your
Output" block to display testcase.result?.output instead of testcase.output to
correctly reflect the user's output and pass/fail status.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-12T06:51:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,6 +60,15 @@
 
   return submissions
     .map((submission) => {
+      // Map testcases to expected format
+      const testcases = submission.test_cases.map((testcase) => ({
+        ...testcase,
+        results: undefined,
+        result: testcase.results.find(
+          (result) => result.submission_id === submission.id
+        ),
+      }));
+
path: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Unsafe access to `results` and loss of `matched`/`output` in mapped test cases**

1. `testcase.results` can be `null` when the LEFT JOIN returns no rows – calling `.find` will throw.
2. After the spread, `matched` & `output` stay nested in `result`, but the UI expects them (see card bug above).

```diff
-const testcases = submission.test_cases.map((testcase) => ({
-  ...testcase,
-  results: undefined,
-  result: testcase.results.find(
-    (result) => result.submission_id === submission.id
-  ),
-}));
+const testcases = submission.test_cases.map((testcase) => {
+  const result =
+    (testcase.results ?? []).find(
+      (r) => r.submission_id === submission.id
+    ) ?? null;
+
+  return {
+    ...testcase,
+    results: undefined, // strip the join helper array
+    result,            // holds matched/output/etc.
+  };
+});
```

This guards against runtime errors and delivers the data shape the React component expects.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
      // Map testcases to expected format
      const testcases = submission.test_cases.map((testcase) => {
        const result =
          (testcase.results ?? []).find(
            (r) => r.submission_id === submission.id
          ) ?? null;

        return {
          ...testcase,
          results: undefined, // strip the join helper array
          result,             // holds matched/output/etc.
        };
      });
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 63-71: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts#L63-L71
Added lines #L63 - L71 were not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In
apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts
around lines 63 to 71, the code unsafely accesses testcase.results which can be
null, causing a runtime error when calling .find. Also, matched and output
remain nested inside result, but the UI expects them at the top level. Fix this
by first checking if testcase.results exists before calling .find, and then
spread matched and output from the found result into the mapped testcase object
so they are directly accessible as expected by the UI.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-12T06:51:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,238 @@
+import { ExtendedNovaSubmission } from './actions';
+import ScoreBadge from '@/components/common/ScoreBadge';
+import {
+  Accordion,
+  AccordionContent,
+  AccordionItem,
+  AccordionTrigger,
+} from '@tuturuuu/ui/accordion';
+import { Card, CardContent, CardHeader } from '@tuturuuu/ui/card';
+import {
+  HoverCard,
+  HoverCardContent,
+  HoverCardTrigger,
+} from '@tuturuuu/ui/hover-card';
+import { CheckCircle2, Clock, XCircle } from '@tuturuuu/ui/icons';
+import { Progress } from '@tuturuuu/ui/progress';
+
+interface SubmissionCardProps {
+  submission: ExtendedNovaSubmission;
+}
+
+export function SubmissionCard({ submission }: SubmissionCardProps) {
+  return (
+    <Card className="overflow-hidden">
+      <CardHeader className="pb-2">
+        <div className="flex items-center justify-between">
+          <span className="text-muted-foreground text-xs">
+            <Clock className="mr-1 inline h-3 w-3" />
+            {new Date(submission.created_at).toLocaleString()}
+          </span>
+
+          <ScoreBadge
+            score={submission.total_score}
+            maxScore={10}
+            className="px-2 py-0"
+          >
+            {submission.total_score.toFixed(2)}/10
+          </ScoreBadge>
+        </div>
+      </CardHeader>
+      <CardContent className="space-y-6">
+        <div>
+          <h3 className="text-foreground mb-1 text-sm font-medium">Prompt:</h3>
+          <div className="bg-muted rounded-md p-2 text-sm">
+            {submission.prompt}
+          </div>
+        </div>
+
+        {/* Overall Assessment - moved to top for better visibility */}
+        {submission.overall_assessment && (
+          <div className="space-y-2">
+            <h3 className="text-foreground mb-1 text-sm font-medium">
+              Overall Assessment:
+            </h3>
+            <div className="rounded-md border border-blue-200 bg-blue-50 p-4 dark:border-blue-900 dark:bg-blue-950/30">
+              <p className="text-sm">{submission.overall_assessment}</p>
+            </div>
+          </div>
+        )}
+
+        {/* Test Case Evaluation */}
+        {submission.total_tests > 0 && (
+          <div className="space-y-2">
+            <div className="flex items-center justify-between">
+              <h3 className="text-muted-foreground text-xs font-medium">
+                Test Case Evaluation:
+              </h3>
+              <ScoreBadge
+                score={submission.test_case_score}
+                maxScore={10}
+                className="px-2 py-0"
+              >
+                {submission.test_case_score.toFixed(2)}/10
+              </ScoreBadge>
+            </div>
+            <div className="space-y-2 rounded-md border p-4">
+              <div>
+                <span className="text-sm">
+                  Passed {submission.passed_tests} of {submission.total_tests}{' '}
+                  test cases
+                </span>
+              </div>
+              <Progress
+                value={(submission.passed_tests / submission.total_tests) * 100}
+                className="h-2 w-full"
+                indicatorClassName={
+                  submission.test_case_score >= 8
+                    ? 'bg-emerald-500'
+                    : submission.test_case_score >= 5
+                      ? 'bg-amber-500'
+                      : 'bg-red-500'
+                }
+              />
+
+              {/* Detailed Test Cases */}
+              <div className="mt-4">
+                <Accordion type="single" collapsible className="w-full">
+                  <AccordionItem value="test-cases">
+                    <AccordionTrigger className="text-sm font-medium">
+                      View Test Case Details
+                    </AccordionTrigger>
+                    <AccordionContent>
+                      <div className="space-y-3">
+                        {submission.test_cases.map((testcase, index) => (
+                          <div
+                            key={testcase.id ?? index}
+                            className={`rounded-md border p-3 ${
+                              testcase.result?.matched
+                                ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
+                                : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
+                            }`}
+                          >
+                            <div className="mb-2 flex items-center justify-between">
+                              <span className="text-sm font-medium">
+                                Test Case {index + 1}
+                              </span>
+                              <div className="flex items-center">
+                                {testcase.result?.matched ? (
+                                  <CheckCircle2 className="mr-1 h-4 w-4 text-emerald-500" />
+                                ) : (
+                                  <XCircle className="mr-1 h-4 w-4 text-red-500" />
+                                )}
+                                <span
+                                  className={`text-xs font-medium ${
+                                    testcase.result?.matched
+                                      ? 'text-emerald-500'
+                                      : 'text-red-500'
+                                  }`}
+                                >
+                                  {testcase.result?.matched ? 'PASS' : 'FAIL'}
+                                </span>
+                              </div>
+                            </div>
+
+                            <div className="grid grid-cols-1 gap-2 text-xs md:grid-cols-2">
+                              <div className="space-y-1">
+                                <p className="font-medium">Input:</p>
+                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                  {testcase.input}
+                                </pre>
+                              </div>
+
+                              <div className="space-y-1">
+                                <p className="font-medium">Expected Output:</p>
+                                <pre className="bg-background max-h-24 overflow-auto whitespace-pre-wrap rounded p-2">
+                                  {testcase.output}
+                                </pre>
+                              </div>
+
+                              <div className="space-y-1 md:col-span-2">
+                                <p className="font-medium">Your Output:</p>
+                                <pre
+                                  className={`max-h-24 overflow-auto whitespace-pre-wrap rounded p-2 ${
+                                    testcase.result?.matched
+                                      ? 'bg-emerald-100 dark:bg-emerald-900/20'
+                                      : 'bg-red-100 dark:bg-red-900/20'
+                                  }`}
+                                >
+                                  {testcase.result?.output ||
+                                    'No output produced'}
+                                </pre>
+                              </div>
+                            </div>
+                          </div>
+                        ))}
+                      </div>
+                    </AccordionContent>
+                  </AccordionItem>
+                </Accordion>
+              </div>
+            </div>
+          </div>
+        )}
+
+        {/* Criteria Evaluation */}
+        {submission.total_criteria > 0 && (
+          <div className="space-y-2">
+            <div className="flex items-center justify-between">
+              <h3 className="text-muted-foreground text-xs font-medium">
+                Criteria Evaluation:
+              </h3>
+              <ScoreBadge
+                score={submission.criteria_score}
+                maxScore={10}
+                className="px-2 py-0"
+              >
+                {submission.criteria_score.toFixed(2)}/10
+              </ScoreBadge>
+            </div>
+            <div className="grid gap-2 sm:grid-cols-2">
+              {submission.criteria?.map((cs) => {
+                if (!cs) return null;
+
+                return (
+                  <HoverCard key={cs.result.criteria_id}>
+                    <HoverCardTrigger asChild>
+                      <div
+                        className={`flex cursor-pointer items-center justify-between rounded-md border p-2 ${
+                          cs.result.score >= 8
+                            ? 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/30'
+                            : cs.result.score >= 5
+                              ? 'border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950/30'
+                              : 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30'
+                        }`}
+                      >
+                        <div className="flex items-center gap-2">
+                          {cs.result.score >= 8 ? (
+                            <CheckCircle2 className="h-4 w-4 text-emerald-500" />
+                          ) : cs.result.score >= 5 ? (
+                            <Clock className="h-4 w-4 text-amber-500" />
+                          ) : (
+                            <XCircle className="h-4 w-4 text-red-500" />
+                          )}
+                          <span className="text-sm">{cs.name}</span>
+                        </div>
+                        <ScoreBadge score={cs.result.score} maxScore={10}>
+                          {cs.result.score}/10
+                        </ScoreBadge>
+                      </div>
+                    </HoverCardTrigger>
+                    <HoverCardContent className="w-80 p-4">
+                      <div className="space-y-2">
+                        <h4 className="font-medium">Feedback</h4>
+                        <p className="text-muted-foreground text-sm">
+                          {cs.result.feedback}
+                        </p>
+                      </div>
+                    </HoverCardContent>
+                  </HoverCard>
+                );
+              })}
+            </div>
+          </div>
+        )}
+      </CardContent>
+    </Card>
+  );
+}
path: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Add unit tests for this new component.**

The static analysis indicates this entire file lacks test coverage. Since this is a new component that plays an important role in displaying test results, it should be thoroughly tested to ensure it behaves as expected with various submission data scenarios.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check for existing component tests in the project
fd "submission-card\.test|submission-card\.spec" --full-path --exec echo "Found test file: {}"

# Look for testing examples to use as a template
fd "\.test\.(tsx|ts)$|\.spec\.(tsx|ts)$" --type f --max-depth 3 --exec head -n 20 {} \; | grep -A 10 "import.*test|describe|it"
```

Length of output: 229

---

Let's verify whether the repository already contains any test files or testing framework setup:

---

🏁 Script executed:

```shell
#!/bin/bash
# List any .test or .spec files across the repo
rg --files | grep -E "\.(test|spec)\.(js|jsx|ts|tsx)$" || echo "No test files found"

# Check for testing dependencies in package.json
grep -E '"(jest|vitest|@testing-library)"' package.json -n || echo "No testing framework dependencies found"
```

Length of output: 1458

---



</details>

**Add unit tests for SubmissionCard**  

The `SubmissionCard` component currently has no test coverage—please add a new test file at  
`apps/nova/src/__tests__/submission-card.test.tsx`, using Vitest and React Testing Library (see the existing `ScoreBadge.test.tsx` for examples).  

Suggested test scenarios:  
- Rendering of the prompt and correctly formatted date/time.  
- Conditional display of **Overall Assessment** when `submission.overall_assessment` is present or absent.  
- **Test Case Evaluation** section:  
  - Correct “Passed X of Y” text.  
  - Progress bar value and color variants for high (≥8), medium (5–7.99), and low (<5) scores.  
  - Accordion expands to show individual test cases with PASS/FAIL icons, input, expected output, and actual output.  
- **Criteria Evaluation** section:  
  - Renders one card per criterion.  
  - Correct icon (✔️, ⏰, ❌) based on the score thresholds.  
  - Badge shows the numeric score.  
  - HoverCard reveals feedback text.  
- Edge cases:  
  - No test cases (`total_tests === 0`) and no criteria (`total_criteria === 0`).  
  - Mixed result and score boundaries (e.g. exactly 5 or 8).  

This coverage will ensure the component behaves as expected across all data variations.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 2-238: apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx#L2-L238
Added lines #L2 - L238 were not covered by tests

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents (early access)</summary>

```
In
apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx
lines 1 to 238, the SubmissionCard component lacks unit tests. Create a new test
file at apps/nova/src/__tests__/submission-card.test.tsx using Vitest and React
Testing Library. Write tests covering rendering of prompt and formatted
date/time, conditional display of Overall Assessment, Test Case Evaluation
section with correct passed tests text, progress bar values and colors for
different score ranges, accordion expansion showing test case details with
PASS/FAIL icons and outputs, Criteria Evaluation section rendering cards with
correct icons, scores, and feedback in HoverCards, and edge cases with no test
cases or criteria and boundary score values like 5 and 8.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-12T06:51:11Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-05-12T06:46:11Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

The changes introduce a new `SubmissionCard` component to encapsulate the detailed rendering of coding challenge submissions, update the data model to include detailed test case results within submissions, and refactor related components and data-fetching logic for consistency. Type definitions and UI structures are updated to reflect these enhancements.

## Changes

| File(s) | Change Summary |
|---------|---------------|
| `apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts` | Extended `ExtendedNovaSubmission` type to include a `test_cases` array with result details; updated `fetchSubmissions` to join and map test case results per submission. |
| `apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx` | Introduced new `SubmissionCard` component for detailed submission display, including header, prompt, assessment, test case, and criteria evaluation sections with conditional rendering and dynamic styling. |
| `apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx` | Replaced inline submission rendering with the new `SubmissionCard` component; removed related imports and detailed JSX. |
| `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/actions.ts` | Modified test case fetching to exclude hidden test cases, expanded selected fields, and updated variable names for clarity. |
| `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/challengeHeader.tsx`,<br>`apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/client.tsx` | Simplified `ExtendedNovaChallenge` type by removing nested `test_cases` from `problems`; updated related references and prop names for consistency. |
| `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/page.tsx` | Refactored logic to identify and pass the current problem to the client component; removed unnecessary type assertion. |
| `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/prompt-form.tsx` | Removed unnecessary React fragment around tabs and adjusted import style for `NovaSubmissionWithScores`. |
| `apps/nova/src/app/[locale]/(dashboard)/challenges/[challengeId]/problems/[problemId]/submission-card.tsx` | Added an accordion section to display detailed test case results within the submission card, with color-coded pass/fail status and formatted output blocks. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Admin as Admin Dashboard
    participant Actions as actions.ts
    participant DB as Supabase DB

    Admin->>Actions: fetchSubmissions(problemId)
    Actions->>DB: Query submissions, join test_cases & results
    DB-->>Actions: Submissions with test_cases & results
    Actions->>Admin: Return ExtendedNovaSubmission[] (with test_cases & results)
    Admin->>SubmissionCard: Render each submission with test case and criteria details
```

## Possibly related PRs

- tutur3u/platform#2358: Introduced the initial implementation of testcase and criteria evaluation, including the creation of the `ExtendedNovaSubmission` type and the `fetchSubmissions` function, which are directly extended and modified in this PR.

## Suggested labels

`nova`

## Suggested reviewers

- vhpx

## Poem

> In the code garden, a card now blooms,  
> With test case tales and verdict rooms.  
> Submissions parade in detailed attire,  
> Each pass and fail, a badge to admire.  
> Rabbits hop by, their whiskers a-twitch—  
> "Well done!" they cheer, "This UI’s rich!"  
> 🐇✨

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> <details>
> <summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/prompt-form.tsx</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.26.0
> 
> Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@typescript-eslint/parser' imported from /eslint.config.mjs
>     at packageResolve (node:internal/modules/esm/resolve:839:9)
>     at moduleResolve (node:internal/modules/esm/resolve:908:18)
>     at defaultResolve (node:internal/modules/esm/resolve:1038:11)
>     at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
>     at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
>     at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
>     at ModuleJob._link (node:internal/modules/esm/module_job:126:49)
> 
> </details>
> 
> <details>
> <summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/actions.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.26.0
> 
> Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@typescript-eslint/parser' imported from /eslint.config.mjs
>     at packageResolve (node:internal/modules/esm/resolve:839:9)
>     at moduleResolve (node:internal/modules/esm/resolve:908:18)
>     at defaultResolve (node:internal/modules/esm/resolve:1038:11)
>     at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
>     at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
>     at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
>     at ModuleJob._link (node:internal/modules/esm/module_job:126:49)
> 
> </details>
> 
> <details>
> <summary>apps/nova/src/app/[locale]/(dashboard)/(admin)/(challenge-management)/problems/[problemId]/submission-card.tsx</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.26.0
> 
> Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@typescript-eslint/parser' imported from /eslint.config.mjs
>     at packageResolve (node:internal/modules/esm/resolve:839:9)
>     at moduleResolve (node:internal/modules/esm/resolve:908:18)
>     at defaultResolve (node:internal/modules/esm/resolve:1038:11)
>     at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
>     at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
>     at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
>     at ModuleJob._link (node:internal/modules/esm/module_job:126:49)
> 
> </details>
> 
> + 6 others
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡️ Faster reviews with caching</summary>
> 
> - CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure `Review - Disable Cache` at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the `Data Retention` setting under your Organization Settings.
> 
> Enjoy the performance boost—your workflow just got faster.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=tutur3u/platform&utm_content=2775):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: graphite-app[bot]
created_at: 2025-05-12T06:46:11Z
body: ## How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:
- <kbd>merge-queue</kbd> - adds this PR to the back of the merge queue
- <kbd>hotfix</kbd> - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using [this link](https://app.graphite.dev/invite/github/tutur3u?ref=merge-queue-instructions-comment&prId=6213390090).

<h2></h2>
<sub>

An organization admin has enabled the [Graphite Merge Queue](https://graphite.dev/docs/graphite-merge-queue) in this repository.

</sub>

<sub>

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

</sub>
author_association: NONE
user: login: codecov[bot]
created_at: 2025-05-12T06:46:22Z
body: ## [Codecov](https://app.codecov.io/gh/tutur3u/platform/pull/2775?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) Report
Attention: Patch coverage is `0%` with `454 lines` in your changes missing coverage. Please review.
> Project coverage is 0.76%. Comparing base [(`38a1f1e`)](https://app.codecov.io/gh/tutur3u/platform/commit/38a1f1e98e271ce2127f8a37ec65459fa3dd81e1?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) to head [(`901cc59`)](https://app.codecov.io/gh/tutur3u/platform/commit/901cc59c589ea43625e13891d8782047124ce876?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u).

| [Files with missing lines](https://app.codecov.io/gh/tutur3u/platform/pull/2775?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) | Patch % | Lines |
|---|---|---|
| [...nagement)/problems/[problemId]/submission-card.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&filepath=apps%2Fnova%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2F%28admin%29%2F%28challenge-management%29%2Fproblems%2F%5BproblemId%5D%2Fsubmission-card.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy9ub3ZhL3NyYy9hcHAvW2xvY2FsZV0vKGRhc2hib2FyZCkvKGFkbWluKS8oY2hhbGxlbmdlLW1hbmFnZW1lbnQpL3Byb2JsZW1zL1twcm9ibGVtSWRdL3N1Ym1pc3Npb24tY2FyZC50c3g=) | 0.00% | [237 Missing and 1 partial :warning: ](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) |
| [...[challengeId]/problems/[problemId]/prompt-form.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&filepath=apps%2Fnova%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2Fchallenges%2F%5BchallengeId%5D%2Fproblems%2F%5BproblemId%5D%2Fprompt-form.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy9ub3ZhL3NyYy9hcHAvW2xvY2FsZV0vKGRhc2hib2FyZCkvY2hhbGxlbmdlcy9bY2hhbGxlbmdlSWRdL3Byb2JsZW1zL1twcm9ibGVtSWRdL3Byb21wdC1mb3JtLnRzeA==) | 0.00% | [85 Missing :warning: ](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) |
| [...llengeId]/problems/[problemId]/submission-card.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&filepath=apps%2Fnova%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2Fchallenges%2F%5BchallengeId%5D%2Fproblems%2F%5BproblemId%5D%2Fsubmission-card.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy9ub3ZhL3NyYy9hcHAvW2xvY2FsZV0vKGRhc2hib2FyZCkvY2hhbGxlbmdlcy9bY2hhbGxlbmdlSWRdL3Byb2JsZW1zL1twcm9ibGVtSWRdL3N1Ym1pc3Npb24tY2FyZC50c3g=) | 0.00% | [82 Missing :warning: ](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) |
| [...llenge-management)/problems/[problemId]/actions.ts](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&filepath=apps%2Fnova%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2F%28admin%29%2F%28challenge-management%29%2Fproblems%2F%5BproblemId%5D%2Factions.ts&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy9ub3ZhL3NyYy9hcHAvW2xvY2FsZV0vKGRhc2hib2FyZCkvKGFkbWluKS8oY2hhbGxlbmdlLW1hbmFnZW1lbnQpL3Byb2JsZW1zL1twcm9ibGVtSWRdL2FjdGlvbnMudHM=) | 0.00% | [19 Missing :warning: ](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) |
| [...nges/[challengeId]/problems/[problemId]/actions.ts](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&filepath=apps%2Fnova%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2Fchallenges%2F%5BchallengeId%5D%2Fproblems%2F%5BproblemId%5D%2Factions.ts&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy9ub3ZhL3NyYy9hcHAvW2xvY2FsZV0vKGRhc2hib2FyZCkvY2hhbGxlbmdlcy9bY2hhbGxlbmdlSWRdL3Byb2JsZW1zL1twcm9ibGVtSWRdL2FjdGlvbnMudHM=) | 0.00% | [14 Missing :warning: ](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) |
| [...e-management)/problems/[problemId]/prompt-form.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&filepath=apps%2Fnova%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2F%28admin%29%2F%28challenge-management%29%2Fproblems%2F%5BproblemId%5D%2Fprompt-form.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy9ub3ZhL3NyYy9hcHAvW2xvY2FsZV0vKGRhc2hib2FyZCkvKGFkbWluKS8oY2hhbGxlbmdlLW1hbmFnZW1lbnQpL3Byb2JsZW1zL1twcm9ibGVtSWRdL3Byb21wdC1mb3JtLnRzeA==) | 0.00% | [6 Missing :warning: ](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) |
| [...nges/[challengeId]/problems/[problemId]/client.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&filepath=apps%2Fnova%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2Fchallenges%2F%5BchallengeId%5D%2Fproblems%2F%5BproblemId%5D%2Fclient.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy9ub3ZhL3NyYy9hcHAvW2xvY2FsZV0vKGRhc2hib2FyZCkvY2hhbGxlbmdlcy9bY2hhbGxlbmdlSWRdL3Byb2JsZW1zL1twcm9ibGVtSWRdL2NsaWVudC50c3g=) | 0.00% | [6 Missing :warning: ](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) |
| [...lenges/[challengeId]/problems/[problemId]/page.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&filepath=apps%2Fnova%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2Fchallenges%2F%5BchallengeId%5D%2Fproblems%2F%5BproblemId%5D%2Fpage.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy9ub3ZhL3NyYy9hcHAvW2xvY2FsZV0vKGRhc2hib2FyZCkvY2hhbGxlbmdlcy9bY2hhbGxlbmdlSWRdL3Byb2JsZW1zL1twcm9ibGVtSWRdL3BhZ2UudHN4) | 0.00% | [3 Missing :warning: ](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) |
| [...llengeId]/problems/[problemId]/challengeHeader.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&filepath=apps%2Fnova%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2Fchallenges%2F%5BchallengeId%5D%2Fproblems%2F%5BproblemId%5D%2FchallengeHeader.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy9ub3ZhL3NyYy9hcHAvW2xvY2FsZV0vKGRhc2hib2FyZCkvY2hhbGxlbmdlcy9bY2hhbGxlbmdlSWRdL3Byb2JsZW1zL1twcm9ibGVtSWRdL2NoYWxsZW5nZUhlYWRlci50c3g=) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/tutur3u/platform/pull/2775?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #2775      +/-   ##
==========================================
- Coverage    0.76%    0.76%   -0.01%     
==========================================
  Files        2371     2372       +1     
  Lines      276858   277043     +185     
  Branches     2811     2812       +1     
==========================================
  Hits         2119     2119              
- Misses     272695   272879     +184     
- Partials     2044     2045       +1     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/tutur3u/platform/pull/2775?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE