89 lines
3.4 KiB
TypeScript
89 lines
3.4 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
type Rig = {
|
|
id: string | number;
|
|
name: string;
|
|
notes?: string;
|
|
rig_type?: { id: number; name: string };
|
|
laser_source?: { submission_id: number; make?: string; model?: string };
|
|
laser_scan_lens?: { id: number; field_size?: string; focal_length?: string };
|
|
laser_focus_lens?: { id: number; name?: string };
|
|
laser_scan_lens_apt?: { id: number; name?: string };
|
|
laser_scan_lens_exp?: { id: number; name?: string };
|
|
laser_software?: { id: number; name?: string };
|
|
};
|
|
|
|
function fmtX(v?: string) {
|
|
if (!v) return "";
|
|
const s = String(v).trim();
|
|
if (/x$/i.test(s)) return s;
|
|
if (/^\d+(\.\d+)?$/.test(s)) {
|
|
if (/^\d$/.test(s)) return `0${s}x`;
|
|
return `${s}x`;
|
|
}
|
|
const m = s.match(/(\d+(?:\.\d+)?)/);
|
|
if (m) {
|
|
const n = m[1];
|
|
if (/^\d$/.test(n)) return `0${n}x`;
|
|
return `${n}x`;
|
|
}
|
|
return `${s}x`;
|
|
}
|
|
|
|
export default function RigsListClient() {
|
|
const [rows, setRows] = useState<Rig[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
async function load() {
|
|
setLoading(true);
|
|
try {
|
|
const res = await fetch("/api/rigs", { credentials: "include", cache: "no-store" });
|
|
const data = await res.json();
|
|
setRows(Array.isArray(data) ? data : data?.data ?? []);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
useEffect(() => { load(); }, []);
|
|
|
|
async function remove(id: string | number) {
|
|
if (!confirm("Delete this rig?")) return;
|
|
const res = await fetch(`/api/rigs?id=${encodeURIComponent(String(id))}`, {
|
|
method: "DELETE",
|
|
credentials: "include",
|
|
});
|
|
if (res.ok) load();
|
|
else alert("Failed to delete");
|
|
}
|
|
|
|
if (loading) return <div className="text-sm opacity-70">Loading…</div>;
|
|
if (!rows.length) return <div className="text-sm opacity-70">No rigs yet.</div>;
|
|
|
|
return (
|
|
<div className="space-y-3">
|
|
{rows.map((r) => (
|
|
<div key={r.id} className="rounded border p-3">
|
|
<div className="flex items-center justify-between gap-3">
|
|
<div className="font-medium">{r.name}</div>
|
|
<button onClick={() => remove(r.id)} className="text-sm px-2 py-1 border rounded hover:bg-muted">
|
|
Delete
|
|
</button>
|
|
</div>
|
|
<div className="text-sm text-muted-foreground mt-1">
|
|
{r.rig_type?.name ? <>Type: {r.rig_type.name}. </> : null}
|
|
{r.laser_source ? <>Source: {[r.laser_source.make, r.laser_source.model].filter(Boolean).join(" ") || r.laser_source.submission_id}. </> : null}
|
|
{r.laser_focus_lens?.name ? <>Focus Lens: {r.laser_focus_lens.name}. </> : null}
|
|
{r.laser_scan_lens ? <>Scan Lens: {[r.laser_scan_lens.field_size && `${r.laser_scan_lens.field_size}mm`, r.laser_scan_lens.focal_length && `${r.laser_scan_lens.focal_length}mm`].filter(Boolean).join(" / ")}. </> : null}
|
|
{r.laser_scan_lens_apt?.name ? <>Scan Lens Apt: {r.laser_scan_lens_apt.name}. </> : null}
|
|
{r.laser_scan_lens_exp?.name ? <>Scan Lens Exp: {fmtX(r.laser_scan_lens_exp.name)}. </> : null}
|
|
{r.laser_software?.name ? <>Software: {r.laser_software.name}. </> : null}
|
|
</div>
|
|
{r.notes ? <div className="text-sm mt-2">{r.notes}</div> : null}
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|