All checks were successful
Deploy to Netlify / Deploy to Netlify (push) Successful in 1m51s
110 lines
3 KiB
TypeScript
110 lines
3 KiB
TypeScript
import { CartesianGrid, Legend, Line, LineChart, XAxis, YAxis } from "recharts";
|
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from "../ui/chart";
|
|
import { getSubjectEmoji, getSubjectColor } from "~/lib/utils";
|
|
import type { PeriodResult, User } from "~/lib/api";
|
|
import { useEffect, useState } from "react";
|
|
|
|
export default function AverageChart({
|
|
averages,
|
|
subjects,
|
|
user,
|
|
}: {
|
|
averages: PeriodResult[];
|
|
subjects: string[];
|
|
user: User;
|
|
}) {
|
|
const [hiddenSubjects, setHiddenSubjects] = useState<string[]>([]);
|
|
const toggleSubjectVisibility = (subject: string) => {
|
|
setHiddenSubjects((prev) =>
|
|
prev.includes(subject)
|
|
? prev.filter((s) => s !== subject)
|
|
: [...prev, subject]
|
|
);
|
|
};
|
|
|
|
const [min, setMin] = useState(0);
|
|
const [max, setMax] = useState(20);
|
|
useEffect(() => {
|
|
if (averages.length > 0) {
|
|
const filteredGrades = averages.map((o) =>
|
|
Object.entries(o)
|
|
.filter(([key, value]) => {
|
|
return !hiddenSubjects.includes(key) && !isNaN(parseFloat(value));
|
|
})
|
|
.map(([_, v]) => parseFloat(v))
|
|
.filter(Boolean)
|
|
);
|
|
setMin(getMin(filteredGrades));
|
|
setMax(getMax(filteredGrades));
|
|
}
|
|
}, [averages, hiddenSubjects]);
|
|
|
|
return (
|
|
<ChartContainer config={{}} className="h-full w-full -ml-6 max-w-2xl">
|
|
<LineChart data={averages}>
|
|
<CartesianGrid strokeDasharray="3 3" />
|
|
<XAxis dataKey="period" />
|
|
<YAxis domain={[min, max]} />
|
|
<ChartTooltip content={<ChartTooltipContent />} />
|
|
<Legend
|
|
onClick={(e) => {
|
|
if (e.dataKey) {
|
|
toggleSubjectVisibility(e.dataKey as string);
|
|
}
|
|
}}
|
|
/>
|
|
{subjects.map((subject, index) => (
|
|
<Line
|
|
key={index}
|
|
type="monotone"
|
|
dataKey={subject}
|
|
name={subject + " " + getSubjectEmoji(subject, user.preferences)}
|
|
hide={hiddenSubjects.includes(subject)}
|
|
stroke={`var(--color-${getSubjectColor(
|
|
subject,
|
|
user.preferences
|
|
)}-800`}
|
|
dot={{
|
|
fill: `var(--color-${getSubjectColor(
|
|
subject,
|
|
user.preferences
|
|
)}-800`,
|
|
stroke: `var(--color-${getSubjectColor(
|
|
subject,
|
|
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>
|
|
);
|
|
}
|
|
|
|
function getMin(grades: number[][]) {
|
|
return Math.max(
|
|
Math.round(
|
|
Math.min(...grades.map((g) => Math.min(...g)).filter(Boolean)) - 1
|
|
),
|
|
0
|
|
);
|
|
}
|
|
|
|
function getMax(grades: number[][]) {
|
|
return Math.min(
|
|
Math.round(
|
|
Math.max(...grades.map((g) => Math.max(...g)).filter(Boolean)) + 1
|
|
),
|
|
20
|
|
);
|
|
}
|