feat: add radar chart

This commit is contained in:
Nathan Lamy 2025-08-20 18:17:55 +02:00
parent e6ba7e0d9a
commit 3e01fa47cd
2 changed files with 178 additions and 811 deletions

View file

@ -1,729 +0,0 @@
import { useState } from "react";
import { Button } from "~/components/ui/button";
import { Badge } from "~/components/ui/badge";
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "~/components/ui/chart";
import {
LineChart,
Line,
BarChart,
Bar,
PieChart,
Pie,
Cell,
AreaChart,
Area,
RadarChart,
PolarGrid,
PolarAngleAxis,
PolarRadiusAxis,
Radar,
XAxis,
YAxis,
CartesianGrid,
ResponsiveContainer,
Legend,
Tooltip,
ReferenceLine,
} from "recharts";
import {
Maximize2,
X,
TrendingUp,
Award,
BookOpen,
Target,
} from "lucide-react";
export const gradesTrendData = {
"This Month": [
{
period: "Week 1",
math: 89,
science: 88,
english: 96,
history: 92,
average: 91.25,
},
{
period: "Week 2",
math: 91,
science: 89,
english: 97,
history: 93,
average: 92.5,
},
{
period: "Week 3",
math: 94,
science: 91,
english: 93,
history: 95,
average: 93.25,
},
{
period: "Week 4",
math: 92,
science: 90,
english: 98,
history: 94,
average: 93.5,
},
],
"3 Months": [
{
period: "Dec",
math: 89,
science: 88,
english: 96,
history: 92,
average: 91.25,
},
{
period: "Jan",
math: 94,
science: 91,
english: 93,
history: 95,
average: 93.25,
},
{
period: "Feb",
math: 91,
science: 89,
english: 97,
history: 93,
average: 92.5,
},
],
"Whole Year": [
{
period: "Sep",
math: 85,
science: 78,
english: 92,
history: 88,
average: 85.75,
},
{
period: "Oct",
math: 88,
science: 82,
english: 89,
history: 91,
average: 87.5,
},
{
period: "Nov",
math: 92,
science: 85,
english: 94,
history: 89,
average: 90,
},
{
period: "Dec",
math: 89,
science: 88,
english: 96,
history: 92,
average: 91.25,
},
{
period: "Jan",
math: 94,
science: 91,
english: 93,
history: 95,
average: 93.25,
},
{
period: "Feb",
math: 91,
science: 89,
english: 97,
history: 93,
average: 92.5,
},
],
};
const subjectPerformanceData = {
"This Month": [
{ subject: "Mathematics", grade: 94, target: 90, credits: 4 },
{ subject: "Science", grade: 91, target: 85, credits: 4 },
{ subject: "English", grade: 98, target: 92, credits: 3 },
{ subject: "History", grade: 95, target: 88, credits: 3 },
{ subject: "Art", grade: 96, target: 90, credits: 2 },
{ subject: "PE", grade: 90, target: 85, credits: 1 },
],
"3 Months": [
{ subject: "Mathematics", grade: 92, target: 90, credits: 4 },
{ subject: "Science", grade: 90, target: 85, credits: 4 },
{ subject: "English", grade: 96, target: 92, credits: 3 },
{ subject: "History", grade: 93, target: 88, credits: 3 },
{ subject: "Art", grade: 95, target: 90, credits: 2 },
{ subject: "PE", grade: 89, target: 85, credits: 1 },
],
"Whole Year": [
{ subject: "Mathematics", grade: 91, target: 90, credits: 4 },
{ subject: "Science", grade: 89, target: 85, credits: 4 },
{ subject: "English", grade: 97, target: 92, credits: 3 },
{ subject: "History", grade: 93, target: 88, credits: 3 },
{ subject: "Art", grade: 95, target: 90, credits: 2 },
{ subject: "PE", grade: 88, target: 85, credits: 1 },
],
};
const gradeDistributionData = {
"This Month": [
{ grade: "A+", count: 12, percentage: 35 },
{ grade: "A", count: 15, percentage: 44 },
{ grade: "A-", count: 5, percentage: 15 },
{ grade: "B+", count: 2, percentage: 6 },
{ grade: "B", count: 0, percentage: 0 },
],
"3 Months": [
{ grade: "A+", count: 10, percentage: 30 },
{ grade: "A", count: 14, percentage: 42 },
{ grade: "A-", count: 6, percentage: 18 },
{ grade: "B+", count: 3, percentage: 9 },
{ grade: "B", count: 1, percentage: 3 },
],
"Whole Year": [
{ grade: "A+", count: 8, percentage: 25 },
{ grade: "A", count: 12, percentage: 37.5 },
{ grade: "A-", count: 6, percentage: 18.75 },
{ grade: "B+", count: 4, percentage: 12.5 },
{ grade: "B", count: 2, percentage: 6.25 },
],
};
const skillsRadar = [
{ skill: "Problem Solving", score: 92 },
{ skill: "Critical Thinking", score: 88 },
{ skill: "Communication", score: 95 },
{ skill: "Creativity", score: 87 },
{ skill: "Collaboration", score: 91 },
{ skill: "Leadership", score: 85 },
];
const COLORS = [
"#8884d8",
"#82ca9d",
"#ffc658",
"#ff7300",
"#00ff00",
"#ff00ff",
];
export const chartConfig = {
math: { label: "Mathematics", color: "hsl(var(--chart-1))" },
science: { label: "Science", color: "hsl(var(--chart-2))" },
english: { label: "English", color: "hsl(var(--chart-3))" },
history: { label: "History", color: "hsl(var(--chart-4))" },
average: { label: "Average", color: "hsl(var(--chart-5))" },
};
export default function SchoolStatsPage() {
const [fullscreenChart, setFullscreenChart] = useState<string | null>(null);
const [selectedPeriod, setSelectedPeriod] = useState<
"This Month" | "3 Months" | "Whole Year"
>("3 Months");
const gradesTrend = gradesTrendData[selectedPeriod];
const subjectPerformance = subjectPerformanceData[selectedPeriod];
const gradeDistribution = gradeDistributionData[selectedPeriod];
const FullscreenModal = ({
chartId,
title,
children,
}: {
chartId: string;
title: string;
children: React.ReactNode;
}) => {
if (fullscreenChart !== chartId) return null;
return (
<div className="fixed inset-0 bg-black/90 z-50 flex items-center justify-center p-2">
<div
className="bg-background rounded-lg w-full h-full flex flex-col
w-[100vh] h-[100vw] rotate-90 origin-center"
>
<div className="flex items-center justify-between p-3 border-b shrink-0">
<h2 className="text-lg md:text-xl lg:text-2xl font-bold rotate-0">
{title}
</h2>
<Button
variant="ghost"
size="icon"
onClick={() => setFullscreenChart(null)}
className="rotate-0"
>
<X className="h-5 w-5 md:h-6 md:w-6" />
</Button>
</div>
<div className="p-3 md:p-4">
{children}
</div>
</div>
</div>
);
};
const currentGPA = 3.7;
const totalCredits = 17;
const completedAssignments = 156;
const upcomingTests = 3;
return (
<div className="min-h-screen bg-background">
<div className="w-full max-w-7xl mx-auto px-4 py-6 space-y-8">
{/* Header */}
<div className="text-center space-y-3">
<h1 className="text-2xl md:text-4xl font-bold">Academic Dashboard</h1>
<p className="text-sm md:text-base text-muted-foreground">
Track your grades and progress
</p>
</div>
<div className="flex justify-center">
<div className="bg-muted/50 rounded-lg p-1 flex gap-1">
{(["This Month", "3 Months", "Whole Year"] as const).map(
(period) => (
<Button
key={period}
variant={selectedPeriod === period ? "default" : "ghost"}
size="sm"
onClick={() => setSelectedPeriod(period)}
className="text-xs md:text-sm"
>
{period}
</Button>
)
)}
</div>
</div>
{/* Key Stats - Mobile First Grid */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="bg-muted/50 rounded-lg p-4 space-y-2">
<div className="flex items-center justify-between">
<span className="text-xs md:text-sm font-medium text-muted-foreground">
Current GPA
</span>
<Award className="h-4 w-4 text-muted-foreground" />
</div>
<div className="text-xl md:text-2xl font-bold">{currentGPA}</div>
</div>
<div className="bg-muted/50 rounded-lg p-4 space-y-2">
<div className="flex items-center justify-between">
<span className="text-xs md:text-sm font-medium text-muted-foreground">
Credits
</span>
<BookOpen className="h-4 w-4 text-muted-foreground" />
</div>
<div className="text-xl md:text-2xl font-bold">{totalCredits}</div>
<p className="text-xs text-muted-foreground">This semester</p>
</div>
<div className="bg-muted/50 rounded-lg p-4 space-y-2">
<div className="flex items-center justify-between">
<span className="text-xs md:text-sm font-medium text-muted-foreground">
Assignments
</span>
<Target className="h-4 w-4 text-muted-foreground" />
</div>
<div className="text-xl md:text-2xl font-bold">
{completedAssignments}
</div>
<p className="text-xs text-muted-foreground">Completed</p>
</div>
<div className="bg-muted/50 rounded-lg p-4 space-y-2">
<div className="flex items-center justify-between">
<span className="text-xs md:text-sm font-medium text-muted-foreground">
Tests
</span>
<TrendingUp className="h-4 w-4 text-muted-foreground" />
</div>
<div className="text-xl md:text-2xl font-bold">{upcomingTests}</div>
<p className="text-xs text-muted-foreground">Upcoming</p>
</div>
</div>
{/* Charts - Mobile First Layout */}
<div className="space-y-8">
{/* Grade Trends */}
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg md:text-xl font-semibold">
Grade Trends
</h2>
<p className="text-sm text-muted-foreground">
{selectedPeriod === "This Month"
? "Weekly"
: selectedPeriod === "3 Months"
? "Monthly"
: "Monthly"}{" "}
performance across subjects
</p>
</div>
<Button
variant="ghost"
size="icon"
onClick={() => setFullscreenChart("trends")}
>
<Maximize2 className="h-4 w-4" />
</Button>
</div>
<div className="bg-muted/30 rounded-lg">
<ChartContainer
config={chartConfig}
className="h-full w-full -ml-6"
>
<ResponsiveContainer width="100%" height="100%">
<LineChart data={gradesTrend}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="period" />
<YAxis domain={[70, 100]} />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
<Line type="monotone" dataKey="math" stroke="blue" />
<Area
type="monotone"
dataKey="science"
stackId="2"
stroke="var(--color-science)"
fill="var(--color-science)"
fillOpacity={0.3}
/>
<Area
type="monotone"
dataKey="english"
stackId="3"
stroke="var(--color-english)"
fill="var(--color-english)"
fillOpacity={0.3}
/>
<Area
type="monotone"
dataKey="history"
stackId="4"
stroke="var(--color-history)"
fill="var(--color-history)"
fillOpacity={0.3}
/>
<Line
type="monotone"
dataKey="average"
stroke="var(--color-average)"
strokeWidth={4}
/>
</LineChart>
</ResponsiveContainer>
</ChartContainer>
</div>
</div>
{/* Subject Performance */}
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg md:text-xl font-semibold">
Subject Performance
</h2>
<p className="text-sm text-muted-foreground">
Current grades vs targets
</p>
</div>
<Button
variant="ghost"
size="icon"
onClick={() => setFullscreenChart("performance")}
>
<Maximize2 className="h-4 w-4" />
</Button>
</div>
<div className="bg-muted/30 rounded-lg p-4">
<ChartContainer
config={chartConfig}
className="h-[250px] md:h-[300px] w-full"
>
<ResponsiveContainer width="100%" height="100%">
<BarChart
data={subjectPerformance}
layout="horizontal"
margin={{ top: 5, right: 10, left: 60, bottom: 5 }}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis type="number" domain={[0, 100]} />
<YAxis dataKey="subject" type="category" width={50} />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
<Bar
dataKey="grade"
fill="hsl(var(--chart-1))"
name="Current"
/>
<Bar
dataKey="target"
fill="hsl(var(--chart-2))"
name="Target"
/>
</BarChart>
</ResponsiveContainer>
</ChartContainer>
</div>
</div>
{/* Grade Distribution & Skills - Side by Side on Desktop */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* Grade Distribution */}
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg md:text-xl font-semibold">
Grade Distribution
</h2>
<p className="text-sm text-muted-foreground">
Breakdown of all grades
</p>
</div>
<Button
variant="ghost"
size="icon"
onClick={() => setFullscreenChart("distribution")}
>
<Maximize2 className="h-4 w-4" />
</Button>
</div>
<div className="bg-muted/30 rounded-lg p-4">
<ChartContainer
config={chartConfig}
className="h-[250px] md:h-[300px] w-full"
>
<ResponsiveContainer width="100%" height="100%">
<PieChart margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
<Pie
data={gradeDistribution}
cx="50%"
cy="50%"
labelLine={false}
label={({ grade, percentage }) =>
`${grade} (${percentage}%)`
}
outerRadius={80}
fill="#8884d8"
dataKey="count"
>
{gradeDistribution.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={COLORS[index % COLORS.length]}
/>
))}
</Pie>
<ChartTooltip content={<ChartTooltipContent />} />
</PieChart>
</ResponsiveContainer>
</ChartContainer>
</div>
</div>
{/* Skills Assessment */}
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg md:text-xl font-semibold">
Skills Assessment
</h2>
<p className="text-sm text-muted-foreground">
Competency across key areas
</p>
</div>
<Button
variant="ghost"
size="icon"
onClick={() => setFullscreenChart("skills")}
>
<Maximize2 className="h-4 w-4" />
</Button>
</div>
<div className="bg-muted/30 rounded-lg p-4">
<ChartContainer
config={chartConfig}
className="h-[250px] md:h-[300px] w-full"
>
<ResponsiveContainer width="100%" height="100%">
<RadarChart
data={skillsRadar}
margin={{ top: 20, right: 20, bottom: 20, left: 20 }}
>
<PolarGrid />
<PolarAngleAxis dataKey="skill" />
<PolarRadiusAxis angle={90} domain={[0, 100]} />
<Radar
name="Skills"
dataKey="score"
stroke="hsl(var(--chart-1))"
fill="hsl(var(--chart-1))"
fillOpacity={0.3}
/>
<ChartTooltip content={<ChartTooltipContent />} />
</RadarChart>
</ResponsiveContainer>
</ChartContainer>
</div>
</div>
</div>
</div>
{/* Fullscreen Modals */}
<FullscreenModal
chartId="trends"
title={`Grade Trends - ${selectedPeriod}`}
>
<ChartContainer config={chartConfig} className="h-full w-full z-100 ">
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={gradesTrend}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="period" />
<YAxis domain={[70, 100]} />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
<Area
type="monotone"
dataKey="math"
stackId="1"
stroke="blue"
fill="blue"
fillOpacity={0.3}
/>
<Area
type="monotone"
dataKey="science"
stackId="2"
stroke="var(--color-science)"
fill="var(--color-science)"
fillOpacity={0.3}
/>
<Area
type="monotone"
dataKey="english"
stackId="3"
stroke="var(--color-english)"
fill="var(--color-english)"
fillOpacity={0.3}
/>
<Area
type="monotone"
dataKey="history"
stackId="4"
stroke="var(--color-history)"
fill="var(--color-history)"
fillOpacity={0.3}
/>
<Line
type="monotone"
dataKey="average"
stroke="var(--color-average)"
strokeWidth={4}
/>
</AreaChart>
</ResponsiveContainer>
</ChartContainer>
</FullscreenModal>
<FullscreenModal
chartId="performance"
title={`Subject Performance - ${selectedPeriod}`}
>
<ChartContainer config={chartConfig} className="h-full">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={subjectPerformance}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="subject" />
<YAxis domain={[0, 100]} />
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
<Bar
dataKey="grade"
fill="hsl(var(--chart-1))"
name="Current Grade"
/>
<Bar
dataKey="target"
fill="hsl(var(--chart-2))"
name="Target Grade"
/>
</BarChart>
</ResponsiveContainer>
</ChartContainer>
</FullscreenModal>
<FullscreenModal
chartId="distribution"
title={`Grade Distribution - ${selectedPeriod}`}
>
<ChartContainer config={chartConfig} className="h-full">
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={gradeDistribution}
cx="50%"
cy="50%"
labelLine={false}
label={({ grade, percentage }) => `${grade} (${percentage}%)`}
outerRadius={200}
fill="#8884d8"
dataKey="count"
>
{gradeDistribution.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={COLORS[index % COLORS.length]}
/>
))}
</Pie>
<ChartTooltip content={<ChartTooltipContent />} />
<Legend />
</PieChart>
</ResponsiveContainer>
</ChartContainer>
</FullscreenModal>
<FullscreenModal
chartId="skills"
title="Skills Assessment - Fullscreen"
>
<ChartContainer config={chartConfig} className="h-full">
<ResponsiveContainer width="100%" height="100%">
<RadarChart data={skillsRadar}>
<PolarGrid />
<PolarAngleAxis dataKey="skill" />
<PolarRadiusAxis angle={90} domain={[0, 100]} />
<Radar
name="Skills"
dataKey="score"
stroke="hsl(var(--chart-1))"
fill="hsl(var(--chart-1))"
fillOpacity={0.3}
strokeWidth={3}
/>
<ChartTooltip content={<ChartTooltipContent />} />
</RadarChart>
</ResponsiveContainer>
</ChartContainer>
</FullscreenModal>
</div>
</div>
);
}

View file

@ -3,6 +3,11 @@ import {
Legend, Legend,
Line, Line,
LineChart, LineChart,
PolarAngleAxis,
PolarGrid,
PolarRadiusAxis,
Radar,
RadarChart,
ResponsiveContainer, ResponsiveContainer,
XAxis, XAxis,
YAxis, YAxis,
@ -12,16 +17,33 @@ import { ChartContainer, ChartTooltip, ChartTooltipContent } from "../ui/chart";
import { Award } from "lucide-react"; import { Award } from "lucide-react";
import { getSubjectColor, getSubjectEmoji } from "~/lib/utils"; import { getSubjectColor, getSubjectEmoji } from "~/lib/utils";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Tabs, TabsList, tabsStyle, TabsTrigger } from "../ui/tabs";
const periods = [
{
id: "YEAR",
label: "Cette année",
},
{
id: "TRIMESTER",
label: "Ce trimestre",
},
{
id: "MONTH",
label: "Ce mois",
},
];
export default function GradesPage({ user }: { user: User }) { export default function GradesPage({ user }: { user: User }) {
// TODO: Error handling, loading state const [period, setPeriod] = useState(periods[0].id);
const { grades, subjects, isLoading, isError } = useGrades("YEAR");
const { grades, subjects, isLoading, isError } = useGrades(period);
const { const {
subjectAverages, subjectAverages,
globalAverage, globalAverage,
isLoading: loading, isLoading: loading,
isError: error, isError: error,
} = useAverages("YEAR"); } = useAverages(period);
const [hiddenSubjects, setHiddenSubjects] = useState<string[]>([]); const [hiddenSubjects, setHiddenSubjects] = useState<string[]>([]);
const toggleSubjectVisibility = (subject: string) => { const toggleSubjectVisibility = (subject: string) => {
@ -52,90 +74,164 @@ export default function GradesPage({ user }: { user: User }) {
return ( return (
<div className="space-y-6 pb-20 md:pb-0"> <div className="space-y-6 pb-20 md:pb-0">
{/* Tabs */} {/* Tabs */}
<Tabs
defaultValue={periods[0].id}
value={period}
onValueChange={setPeriod}
className="max-w-md w-full"
>
<TabsList className="w-full p-0 bg-background justify-start border-b rounded-none">
{periods.map((period) => (
<TabsTrigger
key={period.id}
value={period.id}
className={tabsStyle}
>
{period.label}
</TabsTrigger>
))}
</TabsList>
</Tabs>
{/* Global average */} {isNaN(globalAverage) ? (
<div className="bg-muted/80 dark:bg-muted/30 rounded-lg p-4 space-y-2"> <div className="text-center text-muted-foreground">
<div className="flex items-center justify-between"> Aucune note disponible pour cette période.
<span className="text-xs md:text-sm font-medium text-muted-foreground">
Moyenne générale
</span>
<Award className="h-4 w-4 text-muted-foreground" />
</div> </div>
<div className="text-xl md:text-2xl font-bold">{globalAverage} / 20</div> ) : isLoading || loading ? (
</div> <div className="flex items-center justify-center h-64">
<span className="text-muted-foreground">Chargement...</span>
{/* Charts - Mobile First Layout */} </div>
<div className="space-y-8"> ) : isError || error ? (
{/* Grade Trends */} <div className="text-center text-red-500">
<div className="space-y-4"> Une erreur est survenue lors de la récupération des données.
<div className="flex items-center justify-between"> </div>
<div> ) : (
<h2 className="text-lg md:text-xl font-semibold"> <>
Votre progression {/* Global average */}
</h2> <div className="bg-muted/50 rounded-lg p-4 space-y-2">
<p className="text-sm text-muted-foreground"> <div className="flex items-center justify-between">
Suivez vos notes au fil du temps <span className="text-xs md:text-sm font-medium text-muted-foreground">
</p> Moyenne générale
</span>
<Award className="h-4 w-4 text-muted-foreground" />
</div>
<div className="text-xl md:text-2xl font-bold">
{globalAverage} / 20
</div> </div>
</div> </div>
<div className="bg-muted/80 dark:bg-muted/30 rounded-lg py-4">
<ChartContainer {/* Charts - Mobile First Layout */}
config={{}} <div className="space-y-8">
className="h-full w-full -ml-6 max-w-2xl" {/* Grade Trends */}
> <div className="space-y-4">
<LineChart data={grades}> <div className="flex items-center justify-between">
<CartesianGrid strokeDasharray="3 3" /> <div>
<XAxis dataKey="period" /> <h2 className="text-lg md:text-xl font-semibold">
{/* TODO: Custom domain */} Votre progression
<YAxis domain={[min, max]} /> </h2>
<ChartTooltip content={<ChartTooltipContent />} /> <p className="text-sm text-muted-foreground">
<Legend Suivez vos notes au fil du temps
onClick={(e) => { </p>
if (e.dataKey) { </div>
toggleSubjectVisibility(e.dataKey as string); </div>
} <div className="bg-muted/50 rounded-lg py-4">
}} <ChartContainer
/> config={{}}
{subjects.map((subject, index) => ( className="h-full w-full -ml-6 max-w-2xl"
<Line >
key={index} <LineChart data={grades}>
type="monotone" <CartesianGrid strokeDasharray="3 3" />
dataKey={subject} <XAxis dataKey="period" />
name={ <YAxis domain={[min, max]} />
subject + " " + getSubjectEmoji(subject, user.preferences) <ChartTooltip content={<ChartTooltipContent />} />
} <Legend
hide={hiddenSubjects.includes(subject)} onClick={(e) => {
stroke={`var(--color-${getSubjectColor( if (e.dataKey) {
subject, toggleSubjectVisibility(e.dataKey as string);
user.preferences }
)}-800`} }}
dot={{ />
fill: `var(--color-${getSubjectColor( {subjects.map((subject, index) => (
subject, <Line
user.preferences key={index}
)}-800`, type="monotone"
stroke: `var(--color-${getSubjectColor( dataKey={subject}
subject, name={
user.preferences subject +
)}-800)`, " " +
}} getSubjectEmoji(subject, user.preferences)
/> }
))} hide={hiddenSubjects.includes(subject)}
<Line stroke={`var(--color-${getSubjectColor(
type="monotone" subject,
dataKey="average" user.preferences
name="Moyenne" )}-800`}
stroke="var(--primary)" dot={{
strokeWidth={2} fill: `var(--color-${getSubjectColor(
dot={false} subject,
strokeDasharray="5 5" user.preferences
hide={hiddenSubjects.includes("average")} )}-800`,
/> stroke: `var(--color-${getSubjectColor(
</LineChart> subject,
</ChartContainer> user.preferences
)}-800)`,
}}
/>
))}
<Line
type="monotone"
dataKey="average"
name="Moyenne"
stroke="var(--primary)"
strokeWidth={2}
dot={false}
strokeDasharray="5 5"
hide={hiddenSubjects.includes("average")}
/>
</LineChart>
</ChartContainer>
</div>
</div>
{/* Radar chart */}
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg md:text-xl font-semibold">
Vos points forts
</h2>
<p className="text-sm text-muted-foreground">
Visualisez vos performances par matière
</p>
</div>
</div>
<div className="bg-muted/50 rounded-lg py-4">
<ChartContainer
config={{}}
className="h-full w-full -ml-6 max-w-2xl"
>
<RadarChart
data={subjectAverages}
margin={{ top: 10, right: 10, bottom: 10, left: 10 }}
>
<PolarGrid />
<PolarAngleAxis dataKey="subject" />
<PolarRadiusAxis angle={90} domain={[0, 20]} />
<Radar
name="Moyenne"
dataKey="average"
stroke="var(--chart-2)"
fill="var(--chart-2)"
fillOpacity={0.3}
/>
<ChartTooltip content={<ChartTooltipContent />} />
</RadarChart>
</ChartContainer>
</div>
</div>
</div> </div>
</div> </>
</div> )}
</div> </div>
); );
} }