From da0de6b7e51ce010c5af4b9963adda87501429b9 Mon Sep 17 00:00:00 2001 From: makearmy Date: Sun, 28 Sep 2025 14:58:54 -0400 Subject: [PATCH] migration to direct db calls --- app/api/options/_lib.ts | 48 -------------------- app/api/options/laser_focus_lens/route.ts | 11 ----- app/api/options/laser_scan_lens/route.ts | 16 ------- app/api/options/laser_scan_lens_apt/route.ts | 11 ----- app/api/options/laser_scan_lens_exp/route.ts | 11 ----- app/api/options/laser_software/route.ts | 11 ----- app/api/options/laser_source/route.ts | 43 ------------------ app/api/options/material/route.ts | 11 ----- app/api/options/material_coating/route.ts | 11 ----- app/api/options/material_color/route.ts | 11 ----- app/api/options/material_opacity/route.ts | 12 ----- app/api/options/repeater-choices/route.ts | 26 ----------- app/api/options/user_rig_type/route.ts | 39 ---------------- 13 files changed, 261 deletions(-) delete mode 100644 app/api/options/_lib.ts delete mode 100644 app/api/options/laser_focus_lens/route.ts delete mode 100644 app/api/options/laser_scan_lens/route.ts delete mode 100644 app/api/options/laser_scan_lens_apt/route.ts delete mode 100644 app/api/options/laser_scan_lens_exp/route.ts delete mode 100644 app/api/options/laser_software/route.ts delete mode 100644 app/api/options/laser_source/route.ts delete mode 100644 app/api/options/material/route.ts delete mode 100644 app/api/options/material_coating/route.ts delete mode 100644 app/api/options/material_color/route.ts delete mode 100644 app/api/options/material_opacity/route.ts delete mode 100644 app/api/options/repeater-choices/route.ts delete mode 100644 app/api/options/user_rig_type/route.ts diff --git a/app/api/options/_lib.ts b/app/api/options/_lib.ts deleted file mode 100644 index 75b4d31b..00000000 --- a/app/api/options/_lib.ts +++ /dev/null @@ -1,48 +0,0 @@ -// app/api/options/_lib.ts -import { NextRequest, NextResponse } from "next/server"; - -export type Option = { id: string | number; label: string }; - -export function readCookie(name: string, cookieHeader: string) { - const m = cookieHeader.match(new RegExp(`(?:^|;\\s*)${name}=([^;]+)`)); - return m?.[1] ?? null; -} - -export function getAuthHeaders(req: NextRequest) { - const cookieHeader = req.headers.get("cookie") ?? ""; - const ma_at = readCookie("ma_at", cookieHeader); - const headers: Record = { Accept: "application/json" }; - if (cookieHeader) headers.cookie = cookieHeader; - if (ma_at) headers.authorization = `Bearer ${ma_at}`; - return headers; -} - -export function apiBase() { - const base = (process.env.DIRECTUS_URL || process.env.NEXT_PUBLIC_API_BASE_URL || "").replace(/\/$/, ""); - if (!base) throw new Error("Missing DIRECTUS_URL or NEXT_PUBLIC_API_BASE_URL"); - return base; -} - -export async function dFetchJSON(req: NextRequest, path: string): Promise { - const res = await fetch(`${apiBase()}${path}`, { - headers: getAuthHeaders(req), - cache: "no-store", - }); - if (!res.ok) { - const text = await res.text().catch(() => ""); - throw new Error(`Directus ${res.status} fetching ${path}: ${text}`); - } - return res.json() as Promise; -} - -export function applyQFilter(rows: T[], q: string | null, pick: (row: T) => string): T[] { - if (!q) return rows; - const needle = q.trim().toLowerCase(); - if (!needle) return rows; - return rows.filter((r) => (pick(r) || "").toLowerCase().includes(needle)); -} - -export function json(data: Option[] | { data: Option[] }, status = 200) { - const body = Array.isArray(data) ? { data } : data; - return NextResponse.json(body, { status, headers: { "cache-control": "no-store" } }); -} diff --git a/app/api/options/laser_focus_lens/route.ts b/app/api/options/laser_focus_lens/route.ts deleted file mode 100644 index ecf669ac..00000000 --- a/app/api/options/laser_focus_lens/route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { id: number | string; name?: string | null }; - -export async function GET(req: NextRequest) { - const q = new URL(req.url).searchParams.get("q"); - const { data } = await dFetchJSON<{ data: Row[] }>(req, "/items/laser_focus_lens?fields=id,name&limit=1000&sort=name"); - const options: Option[] = data.map((r) => ({ id: r.id, label: r.name ?? String(r.id) })); - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/laser_scan_lens/route.ts b/app/api/options/laser_scan_lens/route.ts deleted file mode 100644 index 7b918630..00000000 --- a/app/api/options/laser_scan_lens/route.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { id: number | string; name?: string | null; focal_length?: number | string | null; field_size?: number | string | null }; - -export async function GET(req: NextRequest) { - const q = new URL(req.url).searchParams.get("q"); - const { data } = await dFetchJSON<{ data: Row[] }>(req, "/items/laser_scan_lens?fields=id,name,focal_length,field_size&limit=1000&sort=name"); - const options: Option[] = data.map((r) => { - const fl = r.focal_length != null ? `${r.focal_length}` : ""; - const fs = r.field_size != null ? `${r.field_size}` : ""; - const composed = r.name ?? [fl && `${fl} mm`, fs && `${fs} mm`].filter(Boolean).join(" — ") || String(r.id); - return { id: r.id, label: composed }; - }); - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/laser_scan_lens_apt/route.ts b/app/api/options/laser_scan_lens_apt/route.ts deleted file mode 100644 index ddfaf2c1..00000000 --- a/app/api/options/laser_scan_lens_apt/route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { id: number | string; name?: string | null }; - -export async function GET(req: NextRequest) { - const q = new URL(req.url).searchParams.get("q"); - const { data } = await dFetchJSON<{ data: Row[] }>(req, "/items/laser_scan_lens_apt?fields=id,name&limit=1000&sort=name"); - const options: Option[] = data.map((r) => ({ id: r.id, label: r.name ?? String(r.id) })); - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/laser_scan_lens_exp/route.ts b/app/api/options/laser_scan_lens_exp/route.ts deleted file mode 100644 index ddfaf2c1..00000000 --- a/app/api/options/laser_scan_lens_exp/route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { id: number | string; name?: string | null }; - -export async function GET(req: NextRequest) { - const q = new URL(req.url).searchParams.get("q"); - const { data } = await dFetchJSON<{ data: Row[] }>(req, "/items/laser_scan_lens_apt?fields=id,name&limit=1000&sort=name"); - const options: Option[] = data.map((r) => ({ id: r.id, label: r.name ?? String(r.id) })); - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/laser_software/route.ts b/app/api/options/laser_software/route.ts deleted file mode 100644 index 11d24cfe..00000000 --- a/app/api/options/laser_software/route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { id: number | string; name?: string | null }; - -export async function GET(req: NextRequest) { - const q = new URL(req.url).searchParams.get("q"); - const { data } = await dFetchJSON<{ data: Row[] }>(req, "/items/laser_software?fields=id,name&limit=1000&sort=name"); - const options: Option[] = data.map((r) => ({ id: r.id, label: r.name ?? String(r.id) })); - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/laser_source/route.ts b/app/api/options/laser_source/route.ts deleted file mode 100644 index e93a4f8f..00000000 --- a/app/api/options/laser_source/route.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { submission_id: string | number; make?: string | null; model?: string | null; nm?: string | null }; - -function rangeForTarget(target?: string | null): [number, number] | null { - if (!target) return null; - const t = target.toLowerCase(); - if (t === "fiber") return [1000, 9000]; - if (t === "uv") return [300, 400]; - if (t === "co2-gantry" || t === "co2-galvo") return [10000, 11000]; - return null; -} -function parseNm(s?: string | null): number | null { - if (!s) return null; - const m = String(s).match(/(\d+(\.\d+)?)/); - return m ? Number(m[1]) : null; -} - -export async function GET(req: NextRequest) { - const url = new URL(req.url); - const q = url.searchParams.get("q"); - const target = url.searchParams.get("target"); // fiber | uv | co2-gantry | co2-galvo - const { data } = await dFetchJSON<{ data: Row[] }>( - req, - "/items/laser_source?fields=submission_id,make,model,nm&limit=2000&sort=make,model" - ); - - const range = rangeForTarget(target); - const filteredByNm = range - ? data.filter((r) => { - const v = parseNm(r.nm); - return v != null && v >= range[0] && v <= range[1]; - }) - : data; - - const options: Option[] = filteredByNm.map((r) => ({ - id: r.submission_id, - label: [r.make, r.model].filter(Boolean).join(" ") || String(r.submission_id), - })); - - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/material/route.ts b/app/api/options/material/route.ts deleted file mode 100644 index 5e17e05d..00000000 --- a/app/api/options/material/route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { id: number | string; name?: string | null }; - -export async function GET(req: NextRequest) { - const q = new URL(req.url).searchParams.get("q"); - const { data } = await dFetchJSON<{ data: Row[] }>(req, "/items/material?fields=id,name&limit=1000&sort=name"); - const options: Option[] = data.map((r) => ({ id: r.id, label: r.name ?? String(r.id) })); - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/material_coating/route.ts b/app/api/options/material_coating/route.ts deleted file mode 100644 index 710f59ba..00000000 --- a/app/api/options/material_coating/route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { id: number | string; name?: string | null }; - -export async function GET(req: NextRequest) { - const q = new URL(req.url).searchParams.get("q"); - const { data } = await dFetchJSON<{ data: Row[] }>(req, "/items/material_coating?fields=id,name&limit=1000&sort=name"); - const options: Option[] = data.map((r) => ({ id: r.id, label: r.name ?? String(r.id) })); - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/material_color/route.ts b/app/api/options/material_color/route.ts deleted file mode 100644 index af3a3036..00000000 --- a/app/api/options/material_color/route.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { id: number | string; name?: string | null }; - -export async function GET(req: NextRequest) { - const q = new URL(req.url).searchParams.get("q"); - const { data } = await dFetchJSON<{ data: Row[] }>(req, "/items/material_color?fields=id,name&limit=1000&sort=name"); - const options: Option[] = data.map((r) => ({ id: r.id, label: r.name ?? String(r.id) })); - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/material_opacity/route.ts b/app/api/options/material_opacity/route.ts deleted file mode 100644 index fd89f46f..00000000 --- a/app/api/options/material_opacity/route.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { NextRequest } from "next/server"; -import { dFetchJSON, applyQFilter, json, Option } from "../_lib"; - -type Row = { id: number | string; opacity?: string | null }; - -export async function GET(req: NextRequest) { - const q = new URL(req.url).searchParams.get("q"); - // Ensure role can read id,opacity on this collection. - const { data } = await dFetchJSON<{ data: Row[] }>(req, "/items/material_opacity?fields=id,opacity&limit=1000&sort=opacity"); - const options: Option[] = data.map((r) => ({ id: r.id, label: r.opacity ?? String(r.id) })); - return json(applyQFilter(options, q, (o) => o.label)); -} diff --git a/app/api/options/repeater-choices/route.ts b/app/api/options/repeater-choices/route.ts deleted file mode 100644 index 472f70fd..00000000 --- a/app/api/options/repeater-choices/route.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { directusFetch } from "@/lib/directus"; - -export async function GET(req: NextRequest) { - const { searchParams } = new URL(req.url); - const target = searchParams.get("target") || ""; - const group = searchParams.get("group") || ""; - const field = searchParams.get("field") || "type"; - if (!target || !group) return NextResponse.json({ error: "missing target/group" }, { status: 400 }); - - const meta = await directusFetch(`/fields/${target}/${group}?fields=meta`); - const fields = meta?.data?.meta?.options?.fields ?? []; - const nested = fields.find((f: any) => (f?.field ?? f?.key) === field); - const choices = nested?.options?.choices ?? nested?.meta?.options?.choices ?? []; - - const out = (choices as any[]) - .map((c) => ({ - id: String(c.value ?? c.text ?? c.label ?? ""), - label: String(c.text ?? c.label ?? c.value ?? ""), - })) - .filter((o) => o.id) - .sort((a, b) => a.label.localeCompare(b.label)); - - return NextResponse.json({ data: out }); -} - diff --git a/app/api/options/user_rig_type/route.ts b/app/api/options/user_rig_type/route.ts deleted file mode 100644 index 1bca7221..00000000 --- a/app/api/options/user_rig_type/route.ts +++ /dev/null @@ -1,39 +0,0 @@ -// app/api/options/user_rig_type/route.ts -export const dynamic = "force-dynamic"; - -import { NextRequest, NextResponse } from "next/server"; - -const BASE = (process.env.DIRECTUS_URL || "").replace(/\/$/, ""); -const PATH = `/items/user_rig_type?fields=id,name&sort=sort`; - -async function dFetch(bearer: string) { - const res = await fetch(`${BASE}${PATH}`, { - 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: NextRequest) { - try { - const userAt = req.cookies.get("ma_at")?.value; - if (!userAt) return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); - - const r = await dFetch(userAt); - if (!r.res.ok) { - return NextResponse.json( - { error: `Directus ${r.res.status}: ${r.text || r.res.statusText}` }, - { status: r.res.status === 401 || r.res.status === 403 ? r.res.status : 500 } - ); - } - - const rows: Array<{ id: number | string; name: string }> = r.json?.data ?? []; - const data = rows.map(({ id, name }) => ({ id, name })); - return NextResponse.json({ data }, { status: 200 }); - } catch (e: any) { - return NextResponse.json({ error: e?.message || "Failed to load rig types" }, { status: 500 }); - } -}