From 384ac121098d8b038b3ea2de0a585e10d0df4365 Mon Sep 17 00:00:00 2001 From: bagas Date: Sun, 22 Feb 2026 00:16:58 +0700 Subject: [PATCH] chore: remove unused UI components, dummy data, and theme provider --- app/context/auth-context.tsx | 55 +++++ app/routes/form.tsx | 138 ++++++++++++- app/routes/forms.tsx | 74 ++++++- app/routes/not-found.tsx | 13 ++ components/forms/form-card.tsx | 14 +- components/forms/question-editor.tsx | 285 ++++++++++++++++++++++++++ components/forms/question-preview.tsx | 16 +- components/shared/navbar.tsx | 57 ++++-- components/theme-provider.tsx | 11 + lib/api.ts | 68 ++++++ lib/auth.ts | 206 +++++++++++++++++++ lib/dummy-data.ts | 172 ---------------- lib/types.ts | 68 ++++++ 13 files changed, 948 insertions(+), 229 deletions(-) create mode 100644 app/context/auth-context.tsx create mode 100644 app/routes/not-found.tsx create mode 100644 components/forms/question-editor.tsx create mode 100644 components/theme-provider.tsx create mode 100644 lib/api.ts create mode 100644 lib/auth.ts delete mode 100644 lib/dummy-data.ts create mode 100644 lib/types.ts 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"} + +
+
+
+ )} +