makearmy-app/app/api/options/lens/route.ts

102 lines
3.6 KiB
TypeScript
Raw Normal View History

2025-09-22 14:18:08 -04:00
// app/api/options/lens/route.ts
2025-09-22 15:15:06 -04:00
import { NextRequest, NextResponse } from "next/server";
2025-09-22 10:37:53 -04:00
import { directusFetch } from "@/lib/directus";
2025-09-22 15:15:06 -04:00
/**
* Parse "110x110", "110×110", "110 X 110", etc. -> [110, 110]
* Returns null if we can't find two numbers.
*/
function parseFieldSize(s: unknown): [number, number] | null {
if (!s) return null;
const nums = String(s).match(/\d+(\.\d+)?/g)?.map((n) => Number(n)) ?? [];
if (nums.length >= 2 && Number.isFinite(nums[0]) && Number.isFinite(nums[1])) {
return [nums[0], nums[1]];
2025-09-22 14:18:08 -04:00
}
2025-09-22 15:15:06 -04:00
return null;
2025-09-22 10:37:53 -04:00
}
2025-09-22 15:15:06 -04:00
/** Pull a clean integer from a value like "F160", "160", "160mm" */
function parseFocalLength(v: unknown): number | null {
if (v == null) return null;
const m = String(v).match(/\d+(\.\d+)?/);
2025-09-22 15:09:05 -04:00
if (!m) return null;
2025-09-22 15:15:06 -04:00
const n = Number(m[0]);
return Number.isFinite(n) ? Math.round(n) : null;
2025-09-22 15:09:05 -04:00
}
2025-09-22 15:15:06 -04:00
/** Natural-ish compare for scan lens sizes: sort by width then height */
function sizeCompare(a: string, b: string): number {
const as = parseFieldSize(a);
const bs = parseFieldSize(b);
if (!as && !bs) return String(a).localeCompare(String(b));
if (!as) return 1;
if (!bs) return -1;
// width, then height
if (as[0] !== bs[0]) return as[0] - bs[0];
if (as[1] !== bs[1]) return as[1] - bs[1];
return 0;
}
2025-09-22 15:09:05 -04:00
2025-09-22 15:15:06 -04:00
export async function GET(req: NextRequest) {
try {
const { searchParams } = new URL(req.url);
2025-09-22 15:15:06 -04:00
const target = searchParams.get("target") || "";
const q = (searchParams.get("q") || "").trim().toLowerCase();
2025-09-22 14:18:08 -04:00
const limit = Number(searchParams.get("limit") || "500");
2025-09-22 15:15:06 -04:00
const isGantry = target === "settings_co2gan";
2025-09-22 15:09:05 -04:00
2025-09-22 15:15:06 -04:00
if (isGantry) {
// CO2 Gantry -> FOCUS lenses
const url = `/items/laser_focus_lens?fields=id,name&limit=${limit}`;
const { data } = await directusFetch<{ data: Array<{ id: string | number; name?: string }> }>(url);
let rows = (data ?? []).map((r) => ({
id: String(r.id),
label: r.name?.trim() || String(r.id),
_key: r.name?.toLowerCase() ?? "",
}));
2025-09-22 15:09:05 -04:00
2025-09-22 15:15:06 -04:00
if (q) rows = rows.filter((r) => r.label.toLowerCase().includes(q));
rows.sort((a, b) => a.label.localeCompare(b.label));
2025-09-22 15:09:05 -04:00
2025-09-22 15:15:06 -04:00
return NextResponse.json({ data: rows.map(({ id, label }) => ({ id, label })) });
2025-09-22 15:09:05 -04:00
}
2025-09-22 15:15:06 -04:00
// Galvo/UV/Fiber -> SCAN lenses with field_size + focal_length
const url = `/items/laser_scan_lens?fields=id,field_size,focal_length&limit=${limit}`;
const { data } = await directusFetch<{
data: Array<{ id: string | number; field_size?: string; focal_length?: string | number }>;
}>(url);
let rows = (data ?? []).map((r) => {
const sizeTxt = (r.field_size ?? "").toString().trim(); // e.g. "110x110"
const fmm = parseFocalLength(r.focal_length); // e.g. 160
// Build label: "110x110mm (F160)" or "110x110mm" if focal length missing
const label =
sizeTxt
? `${sizeTxt}mm${fmm != null ? ` (F${fmm})` : ""}`
: `${r.id}`;
return {
id: String(r.id),
label,
_size: sizeTxt,
};
});
2025-09-22 15:09:05 -04:00
2025-09-22 15:15:06 -04:00
if (q) {
const qq = q.toLowerCase();
rows = rows.filter((r) => r.label.toLowerCase().includes(qq));
}
2025-09-22 15:15:06 -04:00
rows.sort((a, b) => {
const c = sizeCompare(a._size, b._size);
return c !== 0 ? c : a.label.localeCompare(b.label);
2025-09-22 14:18:08 -04:00
});
2025-09-22 15:15:06 -04:00
return NextResponse.json({ data: rows.map(({ id, label }) => ({ id, label })) });
} catch (e: any) {
console.error("[options/lens] error:", e?.message || e);
return NextResponse.json({ error: e?.message || "Internal error" }, { status: 500 });
}
}