diff --git a/app/rigs/RigsListClient.tsx b/app/rigs/RigsListClient.tsx new file mode 100644 index 00000000..b1fd4387 --- /dev/null +++ b/app/rigs/RigsListClient.tsx @@ -0,0 +1,139 @@ +// app/rigs/RigsListClient.tsx +"use client"; + +import { useEffect, useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { useToast } from "@/hooks/use-toast"; + +type RigRow = { + id: number | string; + name: string; + rig_type_name?: string | null; +}; + +async function apiJson(url: string, init?: RequestInit): Promise { + const res = await fetch(url, { + ...init, + headers: { + Accept: "application/json", + ...(init?.headers || {}), + }, + credentials: "include", + cache: "no-store", + }); + + const txt = await res.text().catch(() => ""); + if (res.ok) { + try { + return (txt ? JSON.parse(txt) : ({} as any)) as T; + } catch { + return {} as T; + } + } + + let body: any = null; + try { body = txt ? JSON.parse(txt) : null; } catch {} + const message = body?.error || body?.message || txt || `HTTP ${res.status} for ${url}`; + + // If unauthorized, send to sign-in (our flow always lands on /portal) + if (res.status === 401 && typeof window !== "undefined") { + window.location.assign("/auth/sign-in"); + } + + const err: any = new Error(message); + err.status = res.status; + err.body = body ?? txt; + throw err; +} + +export default function RigsListClient() { + const { toast } = useToast(); + const [rigs, setRigs] = useState(null); + const [loading, setLoading] = useState(true); + const [err, setErr] = useState(null); + const [deleting, setDeleting] = useState>({}); + + useEffect(() => { + (async () => { + try { + setLoading(true); + setErr(null); + const j = await apiJson<{ data: RigRow[] }>("/api/my/rigs"); + setRigs(j?.data ?? []); + } catch (e: any) { + setErr(e?.message || "Failed to load rigs"); + } finally { + setLoading(false); + } + })(); + }, []); + + async function onDelete(id: string | number) { + if (!confirm("Delete this rig?")) return; + try { + setDeleting((d) => ({ ...d, [id]: true })); + await apiJson(`/api/my/rigs/${id}`, { method: "DELETE" }); + setRigs((prev) => (prev ? prev.filter((r) => r.id !== id) : prev)); + toast({ title: "Rig deleted" }); + } catch (e: any) { + toast({ + title: "Delete failed", + description: e?.message || "Could not delete rig.", + variant: "destructive", + }); + } finally { + setDeleting((d) => { + const copy = { ...d }; + delete copy[id]; + return copy; + }); + } + } + + if (loading) { + return ( +
+ Loading your rigs… +
+ ); + } + + if (err) { + return ( +
+ {err} +
+ ); + } + + return ( +
+
+ {(!rigs || rigs.length === 0) && ( +
No rigs yet.
+ )} + + {rigs?.map((r) => ( +
+
+
{r.name}
+ {r.rig_type_name && ( + {r.rig_type_name} + )} +
+ + +
+ ))} +
+
+ ); +} diff --git a/app/rigs/page.tsx b/app/rigs/page.tsx index 59793f0c..0674cd58 100644 --- a/app/rigs/page.tsx +++ b/app/rigs/page.tsx @@ -4,7 +4,6 @@ import RigsListClient from "./RigsListClient"; export const metadata = { title: "Rigs" }; export default async function RigsPage() { - // Server shell only; the client component fetches via /api/my/rigs with user cookie return (

Your Rigs