import { useState } from 'react' import { createFileRoute, useNavigate } from '@tanstack/react-router' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { lessonPlanDetailOptions, lessonPlanMutations, lessonPlanKeys, lessonPlanItemMutations } from '@/api/lessons' import { GradeEntryDialog } from '@/components/lessons/grade-entry-dialog' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Input } from '@/components/ui/input' import { ArrowLeft, Star } from 'lucide-react' import { toast } from 'sonner' import { useAuthStore } from '@/stores/auth.store' import type { LessonPlanItem } from '@/types/lesson' export const Route = createFileRoute('/_authenticated/lessons/plans/$planId')({ component: LessonPlanDetailPage, }) const STATUSES = ['not_started', 'in_progress', 'mastered', 'skipped'] as const type ItemStatus = typeof STATUSES[number] const STATUS_LABELS: Record = { not_started: 'Not Started', in_progress: 'In Progress', mastered: 'Mastered', skipped: 'Skipped', } const STATUS_VARIANTS: Record = { not_started: 'outline', in_progress: 'secondary', mastered: 'default', skipped: 'outline', } function nextStatus(current: ItemStatus): ItemStatus { const idx = STATUSES.indexOf(current) return STATUSES[(idx + 1) % STATUSES.length] } function LessonPlanDetailPage() { const { planId } = Route.useParams() const navigate = useNavigate() const queryClient = useQueryClient() const hasPermission = useAuthStore((s) => s.hasPermission) const canEdit = hasPermission('lessons.edit') const { data: plan, isLoading } = useQuery(lessonPlanDetailOptions(planId)) const [gradeItem, setGradeItem] = useState(null) const [editingTitle, setEditingTitle] = useState(false) const [titleInput, setTitleInput] = useState('') const updatePlanMutation = useMutation({ mutationFn: (data: Record) => lessonPlanMutations.update(planId, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: lessonPlanKeys.detail(planId) }) setEditingTitle(false) }, onError: (err) => toast.error(err.message), }) const updateItemMutation = useMutation({ mutationFn: ({ id, data }: { id: string; data: Record }) => lessonPlanItemMutations.update(id, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: lessonPlanKeys.detail(planId) }) }, onError: (err) => toast.error(err.message), }) if (isLoading) return
Loading...
if (!plan) return
Plan not found.
const totalItems = plan.sections.flatMap((s) => s.items).filter((i) => i.status !== 'skipped').length const masteredItems = plan.sections.flatMap((s) => s.items).filter((i) => i.status === 'mastered').length function startEditTitle() { setTitleInput(plan!.title) setEditingTitle(true) } function saveTitle() { if (titleInput.trim() && titleInput !== plan!.title) { updatePlanMutation.mutate({ title: titleInput.trim() }) } else { setEditingTitle(false) } } function cycleStatus(item: LessonPlanItem) { updateItemMutation.mutate({ id: item.id, data: { status: nextStatus(item.status as ItemStatus) } }) } return (
{editingTitle ? (
setTitleInput(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') saveTitle(); if (e.key === 'Escape') setEditingTitle(false) }} className="text-xl font-bold h-9" autoFocus />
) : (

{plan.title}

)}
{plan.isActive ? 'Active' : 'Inactive'}
{/* Progress */}
{masteredItems} / {totalItems} mastered {Math.round(plan.progress)}%
{/* Sections */}
{plan.sections.map((section) => (
{section.title} ({section.items.filter((i) => i.status === 'mastered').length}/{section.items.length})
{section.items.map((item) => (
{canEdit ? ( ) : ( {STATUS_LABELS[item.status as ItemStatus]} )}

{item.title}

{item.description &&

{item.description}

}
{item.currentGradeValue && ( {item.currentGradeValue} )} {canEdit && ( )}
))}
))}
{gradeItem && ( setGradeItem(null)} /> )}
) }