"use client" import { useEffect, useState, FormEvent } from "react" import { Gamepad2Icon, PlusIcon, PencilIcon, TrashIcon, Loader2, XIcon, } from "lucide-react" import { getDeviceColor } from "@/components/charts/EChartWrapper" interface DeviceItem { slug: string name: string deviceType: string image: string | null sortOrder: number totalBenchmarks?: number avgFps?: number | null gameCount?: number } interface DeviceFormData { slug: string name: string deviceType: "handheld" | "console" image: string sortOrder: number } export function HardwareClient() { const [devices, setDevices] = useState([]) const [loading, setLoading] = useState(true) const [showModal, setShowModal] = useState(false) const [editingDevice, setEditingDevice] = useState(null) const [form, setForm] = useState({ slug: "", name: "", deviceType: "handheld", image: "", sortOrder: 0, }) const [saving, setSaving] = useState(false) const [deleting, setDeleting] = useState(false) const fetchDevices = async () => { setLoading(true) try { const res = await fetch("/api/hardware/stats") if (res.ok) { const data = await res.json() setDevices( (data as DeviceItem[]).map((item) => ({ ...item, image: item.image ?? null, })) ) } } catch { // ignore } finally { setLoading(false) } } useEffect(() => { fetchDevices() }, []) const openCreate = () => { setEditingDevice(null) setForm({ slug: "", name: "", deviceType: "handheld", image: "", sortOrder: 0, }) setShowModal(true) } const openEdit = (device: DeviceItem) => { setEditingDevice(device) setForm({ slug: device.slug, name: device.name, deviceType: device.deviceType as "handheld" | "console", image: device.image ?? "", sortOrder: device.sortOrder, }) setShowModal(true) } const closeModal = () => { setShowModal(false) setEditingDevice(null) } const handleSubmit = async (e: FormEvent) => { e.preventDefault() setSaving(true) try { const body = editingDevice ? { name: form.name, deviceType: form.deviceType, image: form.image || null, sortOrder: form.sortOrder, } : { slug: form.slug, name: form.name, deviceType: form.deviceType, image: form.image || null, sortOrder: form.sortOrder, } const url = editingDevice ? `/api/hardware/${editingDevice.slug}` : "/api/hardware" const method = editingDevice ? "PATCH" : "POST" const res = await fetch(url, { method, headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }) if (res.ok) { closeModal() await fetchDevices() } } finally { setSaving(false) } } const handleDelete = async (slug: string) => { if (!confirm("Are you sure you want to delete this device?")) return setDeleting(true) try { const res = await fetch(`/api/hardware/${slug}`, { method: "DELETE" }) if (res.ok) { await fetchDevices() } } finally { setDeleting(false) } } return (

Hardware

{loading ? (
) : devices.length === 0 ? (

No devices found

) : (
{devices.map((device, index) => { const color = getDeviceColor(index) return (

{device.name}

/{device.slug}

{device.deviceType}
{device.totalBenchmarks ?? 0} benchmarks
) })}
)} {showModal && (

{editingDevice ? "Edit Device" : "Add Device"}

setForm((f) => ({ ...f, slug: e.target.value })) } disabled={!!editingDevice} required className="w-full px-3 py-2 rounded-md bg-text/5 border border-border text-sm text-text placeholder:text-text/40 focus:outline-none focus:border-primary/60 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" />
setForm((f) => ({ ...f, name: e.target.value })) } required className="w-full px-3 py-2 rounded-md bg-text/5 border border-border text-sm text-text placeholder:text-text/40 focus:outline-none focus:border-primary/60 transition-colors" />
setForm((f) => ({ ...f, sortOrder: Number(e.target.value), })) } className="w-full px-3 py-2 rounded-md bg-text/5 border border-border text-sm text-text placeholder:text-text/40 focus:outline-none focus:border-primary/60 transition-colors" />
setForm((f) => ({ ...f, image: e.target.value })) } placeholder="https://..." className="w-full px-3 py-2 rounded-md bg-text/5 border border-border text-sm text-text placeholder:text-text/40 focus:outline-none focus:border-primary/60 transition-colors" />
)}
) }