mirror of
https://github.com/massbug/judge4c.git
synced 2025-07-04 07:40:51 +00:00
feat(analysis): add radar chart and integrate with detail view
This commit is contained in:
parent
573007398e
commit
579ad88d72
114
src/features/problems/analysis/components/content.tsx
Normal file
114
src/features/problems/analysis/components/content.tsx
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
CardFooter,
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
import prisma from "@/lib/prisma";
|
||||||
|
import {
|
||||||
|
ChartDataPoint,
|
||||||
|
CodeAnalysisRadarChart,
|
||||||
|
} from "@/features/problems/analysis/components/radar-chart";
|
||||||
|
|
||||||
|
interface AnalysisContentProps {
|
||||||
|
submissionId: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AnalysisContent = async ({ submissionId }: AnalysisContentProps) => {
|
||||||
|
if (!submissionId) {
|
||||||
|
return (
|
||||||
|
<div className="p-4 text-center text-muted-foreground">
|
||||||
|
No submission ID provided.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeAnalysisData = await prisma.codeAnalysis.findUnique({
|
||||||
|
where: {
|
||||||
|
submissionId: submissionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!codeAnalysisData) {
|
||||||
|
return (
|
||||||
|
<div className="p-4 text-center text-muted-foreground">
|
||||||
|
No analysis data found for this submission.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform the data into a format suitable for the RadarChart
|
||||||
|
const chartData: ChartDataPoint[] = [
|
||||||
|
{
|
||||||
|
kind: "overall",
|
||||||
|
score: codeAnalysisData.overallScore ?? 0,
|
||||||
|
fullMark: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "style",
|
||||||
|
score: codeAnalysisData.styleScore ?? 0,
|
||||||
|
fullMark: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "readability",
|
||||||
|
score: codeAnalysisData.readabilityScore ?? 0,
|
||||||
|
fullMark: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "efficiency",
|
||||||
|
score: codeAnalysisData.efficiencyScore ?? 0,
|
||||||
|
fullMark: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "correctness",
|
||||||
|
score: codeAnalysisData.correctnessScore ?? 0,
|
||||||
|
fullMark: 100,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className="w-full max-w-2xl mx-auto shadow-lg rounded-xl overflow-hidden border-0 bg-background/50 backdrop-blur-sm animate-fade-in">
|
||||||
|
<CardHeader className="items-center pb-2 space-y-1 px-6 pt-6">
|
||||||
|
<CardTitle className="text-2xl font-bold bg-gradient-to-r from-primary to-foreground bg-clip-text text-transparent">
|
||||||
|
Code Analysis
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription className="text-muted-foreground">
|
||||||
|
Detailed evaluation of your code submission
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="p-0">
|
||||||
|
<CodeAnalysisRadarChart chartData={chartData} />
|
||||||
|
</CardContent>
|
||||||
|
|
||||||
|
<CardFooter className="flex-col items-start gap-4 p-6 pt-0">
|
||||||
|
<div className="w-full space-y-3">
|
||||||
|
<div className="flex justify-between text-sm font-medium">
|
||||||
|
<span className="text-muted-foreground">Overall Score</span>
|
||||||
|
<span className="text-primary">
|
||||||
|
{codeAnalysisData.overallScore ?? "N/A"}
|
||||||
|
<span className="text-muted-foreground">/100</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="relative h-2.5 w-full overflow-hidden rounded-full bg-muted">
|
||||||
|
<div
|
||||||
|
className="h-full bg-gradient-to-r from-primary to-purple-500 rounded-full transition-all duration-700 ease-out"
|
||||||
|
style={{
|
||||||
|
width: `${codeAnalysisData.overallScore ?? 0}%`,
|
||||||
|
transitionProperty: "width",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-muted-foreground bg-muted/40 p-4 rounded-lg w-full border">
|
||||||
|
<h3 className="font-medium mb-2 text-foreground">Feedback</h3>
|
||||||
|
<p className="whitespace-pre-wrap leading-relaxed">
|
||||||
|
{codeAnalysisData.feedback}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||||
import { DetailTable } from "@/features/problems/detail/components/table";
|
import { DetailTable } from "@/features/problems/detail/components/table";
|
||||||
|
import { AnalysisContent } from "@/features/problems/analysis/components/content";
|
||||||
|
|
||||||
interface DetailContentProps {
|
interface DetailContentProps {
|
||||||
submissionId: string;
|
submissionId: string;
|
||||||
@ -10,6 +11,7 @@ export const DetailContent = ({ submissionId }: DetailContentProps) => {
|
|||||||
return (
|
return (
|
||||||
<ScrollArea className="h-full">
|
<ScrollArea className="h-full">
|
||||||
<DetailTable submissionId={submissionId} />
|
<DetailTable submissionId={submissionId} />
|
||||||
|
<AnalysisContent submissionId={submissionId} />
|
||||||
<ScrollBar orientation="horizontal" />
|
<ScrollBar orientation="horizontal" />
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user