diff --git a/app/context/auth-context.tsx b/app/context/auth-context.tsx new file mode 100644 index 0000000..2e55407 --- /dev/null +++ b/app/context/auth-context.tsx @@ -0,0 +1,55 @@ +import { createContext, useContext, useState, useEffect, type ReactNode } from "react" +import { useNavigate } from "react-router" +import { type User, getUser, getUserAsync, logout as logoutUser } from "@/lib/auth" + +interface AuthContextType { + user: User | null + loading: boolean + logout: () => void + refreshUser: () => void +} + +const AuthContext = createContext(null) + +export function AuthProvider({ children }: { children: ReactNode }) { + const [user, setUser] = useState(null) + const [loading, setLoading] = useState(true) + const navigate = useNavigate() + + useEffect(() => { + async function init() { + let currentUser = getUser() + if (!currentUser) { + currentUser = await getUserAsync() + } + setUser(currentUser) + setLoading(false) + } + init() + }, []) + + async function logout() { + await logoutUser() + setUser(null) + navigate("/login") + } + + function refreshUser() { + const currentUser = getUser() + setUser(currentUser) + } + + return ( + + {children} + + ) +} + +export function useAuth() { + const context = useContext(AuthContext) + if (!context) { + throw new Error("useAuth must be used within AuthProvider") + } + return context +} diff --git a/app/routes/form.tsx b/app/routes/form.tsx index a95abb8..2cecbb0 100644 --- a/app/routes/form.tsx +++ b/app/routes/form.tsx @@ -1,23 +1,92 @@ -import { Link, useParams } from "react-router" +import { useState, useEffect } from "react" +import { Link, useParams, useNavigate } from "react-router" import { ArrowLeft, Calendar, FileText, Lock, MessageSquare, + Pencil, + Trash2, } from "lucide-react" -import { dummyForms } from "@/lib/dummy-data" import { Navbar } from "@/components/shared/navbar" import { Footer } from "@/components/shared/footer" import { FormButton } from "@/components/shared/form-button" import { QuestionPreview } from "@/components/forms/question-preview" +import { getFormById, deleteForm } from "@/lib/api" +import { useAuth } from "@/app/context/auth-context" +import type { FormDetail } from "@/lib/types" export default function FormPreviewPage() { const { id } = useParams() - const form = dummyForms.find((f) => f.id === id) + const navigate = useNavigate() + const { user } = useAuth() + const [form, setForm] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + const [showDeleteConfirm, setShowDeleteConfirm] = useState(false) + const [deleting, setDeleting] = useState(false) - if (!form) { - throw new Response("Form not found", { status: 404 }) + useEffect(() => { + if (!id) return + + async function fetchForm() { + try { + const data = await getFormById(id!) + setForm(data) + } catch (err) { + if (err instanceof Response && err.status === 404) { + throw err + } + setError("Failed to load form. Please try again.") + } finally { + setLoading(false) + } + } + fetchForm() + }, [id]) + + async function handleDelete() { + if (!id) return + setDeleting(true) + try { + await deleteForm(id) + navigate("/forms") + } catch { + setError("Failed to delete form.") + setShowDeleteConfirm(false) + } finally { + setDeleting(false) + } + } + + if (loading) { + return ( +
+

Loading...

+
+ ) + } + + if (error || !form) { + return ( +
+ +
+
+

{error ?? "Form not found"}

+ + + Back to forms + +
+
+
+
+ ) } return ( @@ -59,17 +128,38 @@ export default function FormPreviewPage() { - {form.responseCount} responses + {form.response_count} responses - Created {form.createdAt} + Created {new Date(form.created_at).toLocaleDateString()} - Updated {form.updatedAt} + Updated {new Date(form.updated_at).toLocaleDateString()} + + {user && user.id === form.user_id && ( +
+ + + + Edit + + + setShowDeleteConfirm(true)} + className="text-destructive hover:bg-destructive/10 hover:text-destructive" + > + + Delete + +
+ )} @@ -103,6 +193,38 @@ export default function FormPreviewPage() { + {showDeleteConfirm && ( +
+
+

Delete Form

+

+ Are you sure you want to delete this form? This action cannot be + undone. +

+
+ setShowDeleteConfirm(false)} + disabled={deleting} + > + Cancel + + + {deleting ? "Deleting..." : "Delete"} + +
+
+
+ )} +