import { useState, useEffect, type FormEvent } from "react"; import { useNavigate, useParams, Link } from "react-router"; import { ProtectedRoute } from "~/components/ProtectedRoute"; import { Button } from "~/components/Button"; import { Input } from "~/components/Input"; import { GradingCategorySelector } from "~/components/GradingCategorySelector"; import { LoadingSpinner } from "~/components/LoadingSpinner"; import { api } from "~/api/client"; import type { Subject, GradingCategory } from "~/types/api"; import { GRADE_SYSTEMS, type GradeSystem } from "~/utils/gradeSystems"; const getMaxGradeForSystem = (system: GradeSystem): string => { switch (system) { case "german": return "6"; case "us-letter": case "percentage": default: return "100"; } }; export default function EditSubject() { const navigate = useNavigate(); const params = useParams(); const subjectId = params.subjectId; const [subject, setSubject] = useState(null); const [name, setName] = useState(""); const [teacher, setTeacher] = useState(""); const [color, setColor] = useState("#3b82f6"); const [gradeSystem, setGradeSystem] = useState("percentage"); const [targetGrade, setTargetGrade] = useState(""); const [targetMaxGrade, setTargetMaxGrade] = useState(""); const [categories, setCategories] = useState([]); const [error, setError] = useState(""); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); useEffect(() => { const fetchSubject = async () => { if (!subjectId) { setError("Invalid subject ID"); setLoading(false); return; } try { const subjects = await api.getSubjects(); const foundSubject = subjects.find((s) => s._id === subjectId); if (!foundSubject) { setError("Subject not found"); setLoading(false); return; } setSubject(foundSubject); setName(foundSubject.name); setTeacher(foundSubject.teacher || ""); setColor(foundSubject.color ?? "#3b82f6"); setGradeSystem((foundSubject.grade_system as GradeSystem) || "percentage"); setTargetGrade(foundSubject.target_grade?.toString() || ""); setTargetMaxGrade(foundSubject.target_grade_max?.toString() || ""); setCategories(foundSubject.grading_categories); setLoading(false); } catch (err) { setError(err instanceof Error ? err.message : "Failed to fetch subject"); setLoading(false); } }; fetchSubject(); }, [subjectId]); // Auto-update max grade when grade system changes useEffect(() => { setTargetMaxGrade(getMaxGradeForSystem(gradeSystem)); }, [gradeSystem]); const handleSubmit = async (e: FormEvent) => { e.preventDefault(); setError(""); if (!name.trim()) { setError("Subject name is required"); return; } if (categories.length === 0) { setError("Add at least one grading category"); return; } const totalWeight = categories.reduce((sum, cat) => sum + cat.weight, 0); if (Math.abs(totalWeight - 100) > 0.01) { setError("Category weights must sum to 100%"); return; } if (categories.some((cat) => !cat.name.trim())) { setError("All categories must have a name"); return; } if (!subjectId) { setError("Invalid subject ID"); return; } setSaving(true); try { await api.updateSubject(subjectId, { name: name.trim(), teacher: teacher.trim() || undefined, color, grade_system: gradeSystem, grading_categories: categories, target_grade: targetGrade ? parseFloat(targetGrade) : undefined, target_grade_max: targetMaxGrade ? parseFloat(targetMaxGrade) : undefined, }); navigate(`/subjects/${subjectId}`); } catch (err) { setError(err instanceof Error ? err.message : "Failed to update subject"); } finally { setSaving(false); } }; if (loading) { return (
); } if (error && !subject) { return (
{error}
); } return (
← Back to {subject?.name || "Subject"}

Edit Subject

setName(e.target.value)} placeholder="e.g., Mathematics, English, Biology" required /> setTeacher(e.target.value)} placeholder="e.g., Mrs. Smith" />
setColor(e.target.value)} className="w-20 h-10 rounded cursor-pointer border border-gray-300" />

Choose how grades will be displayed for this subject

Target Grade (Optional)

setTargetGrade(e.target.value)} placeholder={gradeSystem === "german" ? "e.g., 2.0" : "e.g., 85"} />
{targetMaxGrade}

Auto-set by grade system

Set a target grade to track your progress. Leave empty if not needed.

Choose how grades will be displayed for this subject

⚠️ Changing categories may affect how existing grades are calculated

{error && (
{error}
)}
); }