// app/portal/my-settings/page.tsx "use client"; import { useEffect, useMemo, useState } from "react"; import Link from "next/link"; type Row = { id: string | number; submission_id?: string | number | null; setting_title?: string | null; status?: string | null; last_modified_date?: string | null; collection: "settings_co2gal" | "settings_co2gan" | "settings_fiber" | "settings_uv"; }; const COLLECTIONS: Array = [ "settings_co2gal", "settings_co2gan", "settings_fiber", "settings_uv", ]; const LABEL: Record = { settings_co2gal: "CO₂ Galvo", settings_co2gan: "CO₂ Gantry", settings_fiber: "Fiber", settings_uv: "UV", }; // Route to the existing detail page for view/edit (you can customize) function detailHref(row: Row) { const subId = row.submission_id ?? row.id; switch (row.collection) { case "settings_co2gal": return `/settings/co2-galvo/${subId}?edit=1`; case "settings_co2gan": return `/settings/co2-gantry/${subId}?edit=1`; case "settings_fiber": return `/settings/fiber/${subId}?edit=1`; case "settings_uv": return `/settings/uv/${subId}?edit=1`; } } export default function MySettingsPage() { const [loading, setLoading] = useState(true); const [me, setMe] = useState<{ id: string; username?: string | null } | null>(null); const [rows, setRows] = useState([]); const [q, setQ] = useState(""); // 1) get current user id useEffect(() => { let canceled = false; (async () => { try { const r = await fetch(`/api/dx/users/me?fields=id,username`, { credentials: "include", cache: "no-store", }); const j = await r.json(); const id = j?.data?.id ?? j?.id; if (!canceled) setMe(id ? { id: String(id), username: j?.data?.username ?? j?.username } : null); } catch { if (!canceled) setMe(null); } })(); return () => { canceled = true; }; }, []); // 2) fetch my settings from each collection useEffect(() => { if (!me?.id) return; let canceled = false; setLoading(true); (async () => { const all: Row[] = []; for (const coll of COLLECTIONS) { const url = new URL(`/api/dx/items/${coll}`, window.location.origin); url.searchParams.set("limit", "-1"); url.searchParams.set("sort", "-last_modified_date"); url.searchParams.set("fields", "id,submission_id,setting_title,status,last_modified_date"); url.searchParams.set("filter[owner][_eq]", me.id); try { const r = await fetch(url.toString(), { credentials: "include", cache: "no-store" }); const j = await r.json(); const data = Array.isArray(j?.data) ? j.data : []; for (const item of data) { all.push({ id: item.id, submission_id: item.submission_id ?? null, setting_title: item.setting_title ?? null, status: item.status ?? null, last_modified_date: item.last_modified_date ?? null, collection: coll, }); } } catch (e) { console.warn(`Failed to load ${coll}:`, e); } } if (!canceled) { setRows(all); setLoading(false); } })(); return () => { canceled = true; }; }, [me?.id]); const filtered = useMemo(() => { const needle = q.trim().toLowerCase(); if (!needle) return rows; return rows.filter((r) => [r.setting_title, LABEL[r.collection], r.status, r.last_modified_date] .filter(Boolean) .some((v) => String(v).toLowerCase().includes(needle)) ); }, [rows, q]); async function onDelete(row: Row) { if (!confirm(`Delete "${row.setting_title || "Untitled"}" from ${LABEL[row.collection]}?`)) return; try { const r = await fetch(`/api/dx/items/${row.collection}/${row.id}`, { method: "DELETE", credentials: "include", }); if (!r.ok) { const j = await r.json().catch(() => null); throw new Error(j?.errors?.[0]?.message || `HTTP ${r.status}`); } setRows((prev) => prev.filter((x) => !(x.collection === row.collection && String(x.id) === String(row.id)))); } catch (e: any) { alert(`Delete failed: ${e?.message || e}`); } } return (

My Settings

setQ(e.currentTarget.value)} /> {rows.length} total
{loading ? (

Loading…

) : filtered.length === 0 ? (

No settings yet.

) : (
{filtered.map((r) => ( ))}
Title Collection Status Updated Actions
{r.setting_title || "Untitled"} {LABEL[r.collection]} {r.status || "—"} {r.last_modified_date ? new Date(r.last_modified_date).toLocaleString() : "—"}
Edit
)}
); }