chore: remove unused UI components, dummy data, and theme provider

This commit is contained in:
2026-02-22 00:16:58 +07:00
parent 58d74cb8c8
commit 384ac12109
13 changed files with 948 additions and 229 deletions
+55
View File
@@ -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<AuthContextType | null>(null)
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(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 (
<AuthContext.Provider value={{ user, loading, logout, refreshUser }}>
{children}
</AuthContext.Provider>
)
}
export function useAuth() {
const context = useContext(AuthContext)
if (!context) {
throw new Error("useAuth must be used within AuthProvider")
}
return context
}
+130 -8
View File
@@ -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<FormDetail | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(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 (
<div className="flex min-h-screen items-center justify-center bg-background">
<p className="text-muted-foreground">Loading...</p>
</div>
)
}
if (error || !form) {
return (
<div className="flex min-h-screen flex-col bg-background">
<Navbar />
<main className="flex flex-1 items-center justify-center">
<div className="text-center">
<p className="text-sm text-destructive">{error ?? "Form not found"}</p>
<Link
to="/forms"
className="mt-4 inline-flex items-center gap-1.5 text-sm font-medium text-primary hover:underline"
>
<ArrowLeft className="h-4 w-4" />
Back to forms
</Link>
</div>
</main>
<Footer />
</div>
)
}
return (
@@ -59,17 +128,38 @@ export default function FormPreviewPage() {
</span>
<span className="flex items-center gap-1.5">
<MessageSquare className="h-3.5 w-3.5" />
{form.responseCount} responses
{form.response_count} responses
</span>
<span className="flex items-center gap-1.5">
<Calendar className="h-3.5 w-3.5" />
Created {form.createdAt}
Created {new Date(form.created_at).toLocaleDateString()}
</span>
<span className="flex items-center gap-1.5">
<Calendar className="h-3.5 w-3.5" />
Updated {form.updatedAt}
Updated {new Date(form.updated_at).toLocaleDateString()}
</span>
</div>
{user && user.id === form.user_id && (
<div className="mt-5 flex items-center gap-3 border-t border-border pt-5">
<Link to={`/form/${id}/edit`}>
<FormButton type="button" variant="ghost" size="sm">
<Pencil className="h-4 w-4" />
Edit
</FormButton>
</Link>
<FormButton
type="button"
variant="ghost"
size="sm"
onClick={() => setShowDeleteConfirm(true)}
className="text-destructive hover:bg-destructive/10 hover:text-destructive"
>
<Trash2 className="h-4 w-4" />
Delete
</FormButton>
</div>
)}
</div>
</div>
@@ -103,6 +193,38 @@ export default function FormPreviewPage() {
</div>
</main>
{showDeleteConfirm && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
<div className="mx-4 w-full max-w-sm rounded-xl border border-border bg-card p-6 shadow-lg">
<h2 className="text-lg font-semibold text-foreground">Delete Form</h2>
<p className="mt-2 text-sm text-muted-foreground">
Are you sure you want to delete this form? This action cannot be
undone.
</p>
<div className="mt-6 flex items-center justify-end gap-3">
<FormButton
type="button"
variant="ghost"
size="sm"
onClick={() => setShowDeleteConfirm(false)}
disabled={deleting}
>
Cancel
</FormButton>
<FormButton
type="button"
size="sm"
onClick={handleDelete}
disabled={deleting}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
{deleting ? "Deleting..." : "Delete"}
</FormButton>
</div>
</div>
</div>
)}
<Footer />
</div>
)
+63 -11
View File
@@ -1,18 +1,56 @@
"use client"
import { useState } from "react"
import { useState, useEffect } from "react"
import { useNavigate, Link } from "react-router"
import { Plus, Search } from "lucide-react"
import { dummyForms } from "@/lib/dummy-data"
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 { FormCard } from "@/components/forms/form-card"
import { useAuth } from "@/app/context/auth-context"
import { getForms } from "@/lib/api"
import type { FormSummary } from "@/lib/types"
export default function FormsPage() {
const { user, loading } = useAuth()
const navigate = useNavigate()
const [search, setSearch] = useState("")
const [forms, setForms] = useState<FormSummary[]>([])
const [loadingForms, setLoadingForms] = useState(true)
const [error, setError] = useState<string | null>(null)
const filtered = dummyForms.filter((form) => {
useEffect(() => {
if (!loading && !user) {
navigate("/login")
}
}, [user, loading, navigate])
useEffect(() => {
if (!user) return
async function fetchForms() {
try {
const data = await getForms()
setForms(data)
} catch {
setError("Failed to load forms. Please try again.")
} finally {
setLoadingForms(false)
}
}
fetchForms()
}, [user])
if (loading || loadingForms) {
return (
<div className="flex min-h-screen items-center justify-center bg-background">
<p className="text-muted-foreground">Loading...</p>
</div>
)
}
if (!user) return null
const filtered = forms.filter((form) => {
return (
form.title.toLowerCase().includes(search.toLowerCase()) ||
form.description.toLowerCase().includes(search.toLowerCase())
@@ -32,10 +70,12 @@ export default function FormsPage() {
Manage and preview all your forms in one place
</p>
</div>
<FormButton size="md">
<Plus className="h-4 w-4" />
New Form
</FormButton>
<Link to="/forms/new">
<FormButton size="md">
<Plus className="h-4 w-4" />
New Form
</FormButton>
</Link>
</div>
<div className="mb-6">
@@ -51,10 +91,22 @@ export default function FormsPage() {
</div>
<p className="mb-4 text-sm text-muted-foreground">
Showing {filtered.length} of {dummyForms.length} forms
Showing {filtered.length} of {forms.length} forms
</p>
{filtered.length > 0 ? (
{error ? (
<div className="flex flex-col items-center justify-center rounded-xl border border-dashed border-border py-16">
<p className="text-sm text-destructive">{error}</p>
<FormButton
variant="ghost"
size="sm"
className="mt-3"
onClick={() => window.location.reload()}
>
Retry
</FormButton>
</div>
) : filtered.length > 0 ? (
<div className="grid gap-5 sm:grid-cols-2">
{filtered.map((form) => (
<FormCard key={form.id} form={form} />
+13
View File
@@ -0,0 +1,13 @@
export function meta() {
return [{ title: "404 - Page Not Found" }];
}
export default function NotFound() {
return (
<div style={{ textAlign: "center", padding: "4rem" }}>
<h1>404</h1>
<p>Page not found.</p>
<a href="/">Go home</a>
</div>
);
}