diff --git a/app/routes/edit-form.tsx b/app/routes/edit-form.tsx new file mode 100644 index 0000000..4358ef0 --- /dev/null +++ b/app/routes/edit-form.tsx @@ -0,0 +1,181 @@ +import { useState, useEffect } from "react" +import { useNavigate, useParams, Link } from "react-router" +import { ArrowLeft } from "lucide-react" +import { Navbar } from "@/components/shared/navbar" +import { Footer } from "@/components/shared/footer" +import { FormInput } from "@/components/shared/form-input" +import { FormButton } from "@/components/shared/form-button" +import { QuestionEditor } from "@/components/forms/question-editor" +import { useAuth } from "@/app/context/auth-context" +import { getFormById, updateForm } from "@/lib/api" +import type { CreateQuestion } from "@/lib/types" + +const TYPES_WITH_OPTIONS = ["multiple_choice", "checkbox", "dropdown"] + +export default function EditFormPage() { + const { id } = useParams() + const { user, loading: authLoading } = useAuth() + const navigate = useNavigate() + + const [title, setTitle] = useState("") + const [description, setDescription] = useState("") + const [questions, setQuestions] = useState([]) + const [loadingForm, setLoadingForm] = useState(true) + const [submitting, setSubmitting] = useState(false) + const [error, setError] = useState(null) + + useEffect(() => { + if (!authLoading && !user) { + navigate("/login") + } + }, [user, authLoading, navigate]) + + useEffect(() => { + if (!id || authLoading || !user) return + + async function fetchForm() { + try { + const data = await getFormById(id!) + setTitle(data.title) + setDescription(data.description) + setQuestions( + data.questions.map((q) => ({ + type: q.type, + title: q.title, + required: q.required, + position: q.position, + options: q.options.map((o) => ({ + label: o.label, + position: o.position, + })), + })) + ) + } catch { + setError("Failed to load form.") + } finally { + setLoadingForm(false) + } + } + fetchForm() + }, [id, authLoading, user]) + + if (authLoading || !user) return null + + if (loadingForm) { + return ( +
+

Loading form...

+
+ ) + } + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault() + setError(null) + + if (!title.trim()) { + setError("Form title is required.") + return + } + + const hasEmptyQuestion = questions.some((q) => !q.title.trim()) + if (hasEmptyQuestion) { + setError("All questions must have a title.") + return + } + + const hasEmptyOption = questions.some( + (q) => + TYPES_WITH_OPTIONS.includes(q.type) && + (q.options.length === 0 || q.options.some((o) => !o.label.trim())) + ) + if (hasEmptyOption) { + setError("All options must have a label.") + return + } + + setSubmitting(true) + try { + await updateForm(id!, { + title: title.trim(), + description: description.trim(), + questions, + }) + navigate(`/form/${id}`) + } catch (err) { + setError(err instanceof Error ? err.message : "Failed to update form.") + } finally { + setSubmitting(false) + } + } + + return ( +
+ + +
+
+ + + Back to form + + +

+ Edit Form +

+ +
+ {error && ( +
+ {error} +
+ )} + +
+
+
+ setTitle(e.target.value)} + required + /> +
+ +