import { useState } from 'react'
import { createFileRoute, useNavigate } from '@tanstack/react-router'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import {
lessonPlanTemplateDetailOptions, lessonPlanTemplateMutations, lessonPlanTemplateKeys,
enrollmentListOptions,
} from '@/api/lessons'
import { globalMemberListOptions } from '@/api/members'
import { TemplateSectionBuilder, type TemplateSectionRow } from '@/components/lessons/template-section-builder'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Textarea } from '@/components/ui/textarea'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { ArrowLeft, Search, X, Zap } from 'lucide-react'
import { toast } from 'sonner'
import { useAuthStore } from '@/stores/auth.store'
import type { LessonPlanTemplate } from '@/types/lesson'
import type { MemberWithAccount } from '@/api/members'
export const Route = createFileRoute('/_authenticated/lessons/templates/$templateId')({
component: TemplateDetailPage,
})
function TemplateDetailPage() {
const { templateId } = Route.useParams()
const navigate = useNavigate()
const queryClient = useQueryClient()
const hasPermission = useAuthStore((s) => s.hasPermission)
const canAdmin = hasPermission('lessons.admin')
const { data: template, isLoading } = useQuery(lessonPlanTemplateDetailOptions(templateId))
const [instantiateOpen, setInstantiateOpen] = useState(false)
if (isLoading) return
Loading...
if (!template) return Template not found.
return (
{template.name}
{template.instrument &&
{template.instrument}
}
{template.isActive ? 'Active' : 'Inactive'}
{canAdmin && (
)}
{/* Read-only curriculum preview */}
{!canAdmin && (
Curriculum
{template.sections.map((section) => (
{section.title}
{section.items.map((item) => (
- {item.title}
))}
))}
)}
setInstantiateOpen(false)}
/>
)
}
// ─── Edit Form ────────────────────────────────────────────────────────────────
function EditTemplateForm({ template, templateId, queryClient }: { template: LessonPlanTemplate; templateId: string; queryClient: any }) {
const [name, setName] = useState(template.name)
const [description, setDescription] = useState(template.description ?? '')
const [instrument, setInstrument] = useState(template.instrument ?? '')
const [skillLevel, setSkillLevel] = useState<'beginner' | 'intermediate' | 'advanced' | 'all_levels'>(template.skillLevel)
const [sections, setSections] = useState(
template.sections.map((s) => ({
id: s.id,
title: s.title,
description: s.description ?? '',
items: s.items.map((i) => ({ id: i.id, title: i.title, description: i.description ?? '' })),
})),
)
const updateMutation = useMutation({
mutationFn: () =>
lessonPlanTemplateMutations.update(templateId, {
name,
description: description || undefined,
instrument: instrument || undefined,
skillLevel,
sections: sections.map((s, sIdx) => ({
title: s.title,
description: s.description || undefined,
sortOrder: sIdx,
items: s.items.map((item, iIdx) => ({
title: item.title,
description: item.description || undefined,
sortOrder: iIdx,
})),
})),
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: lessonPlanTemplateKeys.detail(templateId) })
toast.success('Template updated')
},
onError: (err: Error) => toast.error(err.message),
})
const allValid = name.trim() && sections.every((s) => s.title.trim() && s.items.every((i) => i.title.trim()))
return (
)
}
// ─── Instantiate Dialog ───────────────────────────────────────────────────────
function InstantiateDialog({ template, templateId, open, onClose }: {
template: LessonPlanTemplate
templateId: string
open: boolean
onClose: () => void
}) {
const navigate = useNavigate()
const [memberSearch, setMemberSearch] = useState('')
const [showDropdown, setShowDropdown] = useState(false)
const [selectedMember, setSelectedMember] = useState(null)
const [selectedEnrollmentId, setSelectedEnrollmentId] = useState('')
const [customTitle, setCustomTitle] = useState('')
const { data: membersData } = useQuery(
globalMemberListOptions({ page: 1, limit: 20, q: memberSearch || undefined, order: 'asc', sort: 'first_name' }),
)
const { data: enrollmentsData } = useQuery({
...enrollmentListOptions({ memberId: selectedMember?.id ?? '', status: 'active', page: 1, limit: 50 }),
enabled: !!selectedMember?.id,
})
const mutation = useMutation({
mutationFn: () =>
lessonPlanTemplateMutations.createPlan(templateId, {
memberId: selectedMember!.id,
enrollmentId: selectedEnrollmentId || undefined,
title: customTitle || undefined,
}),
onSuccess: (plan) => {
toast.success('Plan created from template')
navigate({ to: '/lessons/plans/$planId', params: { planId: plan.id }, search: {} as any })
},
onError: (err) => toast.error(err.message),
})
const members = membersData?.data ?? []
const enrollments = enrollmentsData?.data ?? []
function reset() {
setMemberSearch('')
setSelectedMember(null)
setSelectedEnrollmentId('')
setCustomTitle('')
}
return (
)
}