import type { Component } from "solid-js"; import { createMemo, createResource, createSignal, onMount } from "solid-js"; import { createStore } from "solid-js/store"; import { useAuth } from "~/context/auth/context"; import styles from "./dashboard-teacher-assignments.module.scss"; import { createTeacherAssignment, generateTeacherQuestions, getTeacherAssignmentSetupData } from "./dashboard-teacher-assignments.data"; import { defaultGenerationForm, emptySetupForm } from "./dashboard-teacher-assignment-create.constants"; import { buildGenerationSuccessMessage, buildMixedGenerationInput, mergeSelectedQuestionIds, parseOptionalInteger } from "./dashboard-teacher-assignment-create.helpers"; import { AssignmentCreateHero, AssignmentDetailsSection, PersonalizedGenerationSection, QuestionBankSection, SetupSummarySection, SharedGenerationSection, SubmissionSection, } from "./dashboard-teacher-assignment-create.sections"; import type { AssignmentSetupForm, QuestionGenerationForm } from "./dashboard-teacher-assignment-create.types"; const DashboardTeacherAssignmentCreate: Component = () => { const auth = useAuth(); const [teacherId, setTeacherId] = createSignal(null); const [setupData, { mutate: mutateSetupData }] = createResource(teacherId, getTeacherAssignmentSetupData); const [form, setForm] = createStore(emptySetupForm); const [generationForm, setGenerationForm] = createStore(defaultGenerationForm); const [isSubmitting, setIsSubmitting] = createSignal(false); const [isGenerating, setIsGenerating] = createSignal(false); const [errorMessage, setErrorMessage] = createSignal(null); const [successMessage, setSuccessMessage] = createSignal(null); onMount(() => { if (auth.user()?.role === "teacher") { setTeacherId(auth.user()!.id); } }); const selectedClassroom = createMemo(() => setupData()?.classrooms.find((classroom) => `${classroom.id}` === form.classroomId)); const selectedQuestionCount = createMemo(() => form.selectedQuestionIds.length); const mixedGenerationEnabled = createMemo(() => form.useMixedGeneration); const mixedGenerationQuestionCount = createMemo(() => Number(form.totalQuestions) || 0); const mixedGenerationRatioLabel = createMemo(() => { const parsed = Number(form.personalizedRatio); if (!Number.isFinite(parsed) || parsed <= 0) return "30% personalized"; return `${parsed}% personalized`; }); const handleTextInput = ( field: | "classroomId" | "title" | "instructions" | "dueAt" | "primaryTopic" | "primaryDifficulty" | "totalQuestions" | "personalizedRatio" | "seed" | "personalizedDifficulty" | "subject", ) => (event: Event) => { const target = event.currentTarget as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement; setForm(field, target.value); setSuccessMessage(null); }; const handleMixedGenerationToggle = (event: Event) => { const target = event.currentTarget as HTMLInputElement; setForm("useMixedGeneration", target.checked); setSuccessMessage(null); }; const handleGenerationInput = (field: keyof QuestionGenerationForm) => (event: Event) => { const target = event.currentTarget as HTMLInputElement | HTMLSelectElement; setGenerationForm(field, target.value as QuestionGenerationForm[keyof QuestionGenerationForm]); setSuccessMessage(null); }; const handleQuestionToggle = (questionId: number) => (event: Event) => { const target = event.currentTarget as HTMLInputElement; setForm("selectedQuestionIds", target.checked ? [...form.selectedQuestionIds, questionId] : form.selectedQuestionIds.filter((id) => id !== questionId)); setSuccessMessage(null); }; const resetForm = () => { setForm({ ...emptySetupForm, classroomId: form.classroomId }); }; const mergeGeneratedQuestions = (generatedQuestionIds: number[], questions: Awaited>["questions"]) => { mutateSetupData((current) => { if (!current) return current; const existingQuestions = current.questions.filter((question) => !generatedQuestionIds.includes(question.id)); return { ...current, questions: [...questions, ...existingQuestions], }; }); setForm("selectedQuestionIds", mergeSelectedQuestionIds(form.selectedQuestionIds, generatedQuestionIds)); }; const handleGenerateQuestions = async (event: Event) => { event.preventDefault(); const currentTeacherId = teacherId(); if (!currentTeacherId) { setErrorMessage("Your teacher session is still loading."); return; } const parsedCount = Number(generationForm.count); const parsedSeed = parseOptionalInteger(generationForm.seed); if (!Number.isInteger(parsedCount) || parsedCount < 1 || parsedCount > 25) { setErrorMessage("Choose a question count between 1 and 25."); return; } if (generationForm.seed.trim() && (!Number.isInteger(parsedSeed) || Number.isNaN(parsedSeed))) { setErrorMessage("Seed must be a whole number when provided."); return; } setIsGenerating(true); setErrorMessage(null); setSuccessMessage(null); try { const result = await generateTeacherQuestions({ topic: generationForm.topic, difficulty: generationForm.difficulty, count: parsedCount, seed: parsedSeed, }); mergeGeneratedQuestions(result.generatedQuestionIds, result.questions); setSuccessMessage(buildGenerationSuccessMessage(generationForm, result.count, result.seed)); } catch (error) { setErrorMessage(error instanceof Error ? error.message : "Unable to generate questions right now."); } finally { setIsGenerating(false); } }; const handleSubmit = async (event: Event) => { event.preventDefault(); const currentTeacherId = teacherId(); if (!currentTeacherId) { setErrorMessage("Your teacher session is still loading."); return; } setIsSubmitting(true); setErrorMessage(null); setSuccessMessage(null); try { const mixedGeneration = buildMixedGenerationInput(form); await createTeacherAssignment({ teacherId: currentTeacherId, classroomId: Number(form.classroomId), title: form.title, instructions: form.instructions, dueAt: form.dueAt, selectedQuestionIds: form.selectedQuestionIds, mixedGeneration, }); setSuccessMessage( mixedGenerationEnabled() ? "Personalized homework created and assigned. Each student now has a mixed generated question set." : "Homework created and assigned to the selected class.", ); resetForm(); } catch (error) { setErrorMessage(error instanceof Error ? error.message : "Unable to create homework right now."); } finally { setIsSubmitting(false); } }; return (
void handleSubmit(event)}>
void handleGenerateQuestions(event)} />
); }; export default DashboardTeacherAssignmentCreate;