diff --git a/app/api/options/lens/route.ts b/app/api/options/lens/route.ts index 6dd2cf4e..60c8fc2c 100644 --- a/app/api/options/lens/route.ts +++ b/app/api/options/lens/route.ts @@ -1,57 +1,98 @@ -// app/app/api/options/lens/route.ts +// app/api/options/lens/route.ts import { NextResponse } from "next/server"; import { directusFetch } from "@/lib/directus"; -// Decide which collection to read based on target -function lensCollectionForTarget(target?: string) { - if (target === "settings_co2gan") return "laser_focus_lens"; // gantry - // fiber, uv, co2gal → scan lenses - return "laser_scan_lens"; +/** + * Lenses endpoint + * - Fiber/UV/CO2 Galvo -> laser_scan_lens (has field_size, focal_length) + * - CO2 Gantry -> laser_focus_lens (usually focal_length only) + * Returns [{ id, label }] using submission_id || id. + */ +function collectionForTarget( + target?: string +): "laser_scan_lens" | "laser_focus_lens" | null { + switch (target) { + case "settings_fiber": + case "settings_uv": + case "settings_co2gal": + return "laser_scan_lens"; + case "settings_co2gan": + return "laser_focus_lens"; + default: + return null; + } } export async function GET(req: Request) { 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 q = (searchParams.get("q") || "").toLowerCase().trim(); + const limit = Number(searchParams.get("limit") || "500"); - const coll = lensCollectionForTarget(target); + const coll = collectionForTarget(target); + if (!coll) return NextResponse.json({ data: [] }); - // Request both possible PK fields, plus name & focal_length for labels - const url = `/items/${coll}?fields=submission_id,id,name,focal_length&limit=${limit}`; - const { data } = await directusFetch<{ data: any[] }>(url); - const list = Array.isArray(data) ? data : []; + // Ask only for fields that exist on each collection + const fields = + coll === "laser_scan_lens" + ? "submission_id,id,name,field_size,focal_length" + : "submission_id,id,name,focal_length"; + + const url = `/items/${coll}?fields=${encodeURIComponent( + fields + )}&limit=${limit}`; + + const res = await directusFetch<{ data: any[] }>(url); + const list = Array.isArray(res?.data) ? res.data : []; const mapped = list.map((x) => { - const id = String(x.submission_id ?? x.id); - const label = - (x.name && String(x.name)) || - (x.focal_length != null ? `F${x.focal_length} mm` : id); - const key = - (x.focal_length != null ? String(x.focal_length).padStart(6, "0") : "") + - " " + - label.toLowerCase(); - return { id, label, key, focal: Number(x.focal_length ?? NaN) }; + const id = String(x?.submission_id ?? x?.id); + + const fieldSizeRaw = x?.field_size; + const fieldSize = + fieldSizeRaw !== null && fieldSizeRaw !== undefined + ? String(fieldSizeRaw).trim() + : ""; + + const fnum = Number(x?.focal_length); + const focalTxt = Number.isFinite(fnum) ? `F${fnum} mm` : ""; + + // Label: field_size THEN focal_length (requested order). + // Fall back to name, then id. + let label = [fieldSize, focalTxt].filter(Boolean).join(" — "); + if (!label) label = (x?.name ? String(x.name) : "").trim(); + if (!label) label = id; + + // Sort by focal length if available; else by label + const sortKey: number | string = Number.isFinite(fnum) + ? fnum + : label.toLowerCase(); + + return { + id, + label, + sortKey, + _search: `${id} ${label} ${fieldSize} ${x?.name ?? ""} ${ + x?.focal_length ?? "" + }`.toLowerCase(), + }; }); - // Optional text filter - const filtered = q - ? mapped.filter((m) => m.label.toLowerCase().includes(q)) - : mapped; + const filtered = q ? mapped.filter((m) => m._search.includes(q)) : mapped; - // Prefer numeric focal_length ordering, fallback to label filtered.sort((a, b) => { - const aNum = Number.isFinite(a.focal); - const bNum = Number.isFinite(b.focal); - if (aNum && bNum) return a.focal - b.focal; - if (aNum) return -1; - if (bNum) return 1; - return a.key.localeCompare(b.key); + if (typeof a.sortKey === "number" && typeof b.sortKey === "number") + return a.sortKey - b.sortKey; + return String(a.sortKey).localeCompare(String(b.sortKey)); }); - return NextResponse.json({ data: filtered.map(({ id, label }) => ({ id, label })) }); + return NextResponse.json({ + data: filtered.map(({ id, label }) => ({ id, label })), + }); } catch (e: any) { - return NextResponse.json({ error: e?.message || "Failed to load lens options" }, { status: 500 }); + console.error("[options/lens] error:", e?.message || e); + // Fail soft to keep UI responsive + return NextResponse.json({ data: [] }); } }