built user portal behind auth

This commit is contained in:
makearmy 2025-09-27 14:30:16 -04:00
parent 5c6962f4a5
commit 37d474d7c8
48 changed files with 822 additions and 496 deletions

View file

@ -1,65 +1,49 @@
// app/app/api/options/laser_source/route.ts
import { NextResponse } from "next/server";
import { directusFetch } from "@/lib/directus";
// app/api/options/laser_source/route.ts
export const dynamic = "force-dynamic";
// Parse "nm" that may be stored as a string (e.g., "1064", "1064nm", "1,064")
function parseNm(v: any): number | null {
const s = String(v ?? "").replace(/[^0-9.]/g, "");
if (!s) return null;
const n = Number(s);
return Number.isFinite(n) ? n : null;
import { NextRequest, NextResponse } from "next/server";
const BASE = (process.env.DIRECTUS_URL || "").replace(/\/$/, "");
function buildPath(target?: string | null) {
// If your schema supports target filtering, add it here. Otherwise we return all.
const url = new URL(`${BASE}/items/laser_source`);
url.searchParams.set("fields", "id,name");
url.searchParams.set("sort", "name");
// Example (uncomment/adjust if you actually have a `target` field or relation):
// if (target) url.searchParams.set("filter[target][_eq]", target);
return String(url);
}
// target → wavelength range (nm)
function nmRangeForTarget(t?: string): [number, number] | null {
switch (t) {
case "settings_fiber": return [1000, 1100];
case "settings_uv": return [300, 400];
case "settings_co2gan":
case "settings_co2gal": return [10000, 11000];
default: return null;
}
async function dFetch(bearer: string, target?: string | null) {
const res = await fetch(buildPath(target), {
headers: { Accept: "application/json", Authorization: `Bearer ${bearer}` },
cache: "no-store",
});
const text = await res.text().catch(() => "");
let json: any = null;
try { json = text ? JSON.parse(text) : null; } catch {}
return { res, json, text };
}
export async function GET(req: Request) {
export async function GET(req: NextRequest) {
try {
const { searchParams } = new URL(req.url);
const target = searchParams.get("target") || undefined;
const q = (searchParams.get("q") || "").trim().toLowerCase();
const limit = Number(searchParams.get("limit") || "500");
const userAt = req.cookies.get("ma_at")?.value;
if (!userAt) return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
const range = nmRangeForTarget(target);
if (!range) {
return NextResponse.json({ error: "missing/invalid target" }, { status: 400 });
const target = req.nextUrl.searchParams.get("target");
const r = await dFetch(userAt, target);
if (!r.res.ok) {
return NextResponse.json(
{ error: `Directus ${r.res.status}: ${r.text || r.res.statusText}` },
{ status: r.res.status }
);
}
const [lo, hi] = range;
// Only request fields we can read. laser_source uses submission_id as PK.
const url = `/items/laser_source?fields=submission_id,make,model,nm&limit=${limit}`;
const { data } = await directusFetch<{ data: any[] }>(url);
const list = Array.isArray(data) ? data : [];
// Filter by nm and optional text query
const filtered = list.filter((x) => {
const nm = parseNm(x.nm);
if (nm === null || nm < lo || nm > hi) return false;
if (!q) return true;
const label = [x.make, x.model].filter(Boolean).join(" ").toLowerCase();
return label.includes(q);
});
// Build labels and sort by make, then model
const out = filtered
.map((x) => ({
id: String(x.submission_id), // critical: use submission_id, not id
label: [x.make, x.model].filter(Boolean).join(" ") || String(x.submission_id),
sortKey: [x.make ?? "", x.model ?? ""].join(" ").toLowerCase(),
}))
.sort((a, b) => a.sortKey.localeCompare(b.sortKey))
.map(({ id, label }) => ({ id, label }));
return NextResponse.json({ data: out });
const rows: Array<{ id: number | string; name: string }> = r.json?.data ?? [];
const data = rows.map(({ id, name }) => ({ id, name }));
return NextResponse.json({ data });
} catch (e: any) {
return NextResponse.json({ error: e?.message || "Failed to load laser_source" }, { status: 500 });
return NextResponse.json({ error: e?.message || "Failed to load laser sources" }, { status: 500 });
}
}