build error fix
This commit is contained in:
parent
f2c8590a99
commit
4b416b01e7
1 changed files with 24 additions and 138 deletions
|
|
@ -1,161 +1,47 @@
|
||||||
'use client';
|
// app/lasers/[id]/LaserDetailsClient.tsx
|
||||||
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import Link from "next/link";
|
||||||
import { useParams } from 'next/navigation';
|
|
||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
|
type Group = { title: string; fields: Record<string, string> };
|
||||||
type Laser = Record<string, any>;
|
type Laser = Record<string, any>;
|
||||||
|
|
||||||
const API = (process.env.NEXT_PUBLIC_API_BASE_URL || '').replace(/\/$/, '');
|
|
||||||
|
|
||||||
// Human labels for select-ish fields we render.
|
|
||||||
// Extend this as needed if you add more enums to the UI.
|
|
||||||
const CHOICE_LABELS: Record<string, Record<string, string>> = {
|
const CHOICE_LABELS: Record<string, Record<string, string>> = {
|
||||||
op: {
|
op: { pm: "MOPA", pq: "Q-Switch" },
|
||||||
pm: 'MOPA',
|
cooling: { aa: "Air, Active", ap: "Air, Passive", w: "Water" },
|
||||||
pq: 'Q-Switch',
|
|
||||||
},
|
|
||||||
cooling: {
|
|
||||||
aa: 'Air, Active',
|
|
||||||
ap: 'Air, Passive',
|
|
||||||
w: 'Water',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The exact fields this page uses; keeps payloads lean.
|
function resolveLabel(field: string, value: any) {
|
||||||
const FIELD_GROUPS = [
|
if (value == null || value === "") return "—";
|
||||||
{
|
const map = CHOICE_LABELS[field];
|
||||||
title: 'General Information',
|
if (map && typeof value === "string" && map[value]) return map[value];
|
||||||
fields: {
|
if (typeof value === "boolean") return value ? "Yes" : "No";
|
||||||
make: 'Make',
|
if (typeof value === "number") return Number.isFinite(value) ? String(value) : "—";
|
||||||
model: 'Model',
|
return String(value);
|
||||||
op: 'Pulse Operation Mode',
|
}
|
||||||
notes: 'Notes',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Optical Specifications',
|
|
||||||
fields: {
|
|
||||||
w: 'Laser Wattage (W)',
|
|
||||||
mj: 'milliJoule Max (mJ)',
|
|
||||||
nm: 'Wavelength (nm)',
|
|
||||||
k_hz: 'Pulse Repetition Rate (kHz)',
|
|
||||||
ns: 'Pulse Width (ns)',
|
|
||||||
d: 'Beam Diameter (mm)',
|
|
||||||
m2: 'M² - Quality',
|
|
||||||
instability: 'Instability',
|
|
||||||
polarization: 'Polarization',
|
|
||||||
band: 'Band (nm)',
|
|
||||||
anti: 'Anti-Reflection Coating',
|
|
||||||
mw: 'Red Dot Wattage (mW)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Electrical & Timing',
|
|
||||||
fields: {
|
|
||||||
v: 'Operating Voltage (V)',
|
|
||||||
temp_op: 'Operating Temperature (°C)',
|
|
||||||
temp_store: 'Storage Temperature (°C)',
|
|
||||||
l_on: 'l_on',
|
|
||||||
l_off: 'l_off',
|
|
||||||
mj_c: 'mj_c',
|
|
||||||
ns_c: 'ns_c',
|
|
||||||
d_c: 'd_c',
|
|
||||||
on_c: 'on_c',
|
|
||||||
off_c: 'off_c',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Integration & Physical',
|
|
||||||
fields: {
|
|
||||||
cable: 'Cable Length (m)',
|
|
||||||
cooling: 'Cooling Method',
|
|
||||||
weight: 'Weight (kg)',
|
|
||||||
dimensions: 'Dimensions (cm)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
const FIELD_KEYS = Array.from(
|
|
||||||
new Set([
|
|
||||||
'make',
|
|
||||||
'model',
|
|
||||||
...FIELD_GROUPS.flatMap((g) => Object.keys(g.fields)),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function LaserSourceDetailsPage() {
|
|
||||||
const params = useParams();
|
|
||||||
const id = Array.isArray(params?.id) ? params.id[0] : (params?.id as string | undefined);
|
|
||||||
|
|
||||||
const [laser, setLaser] = useState<Laser | null>(null);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
|
|
||||||
// Precompute the Directus fields query
|
|
||||||
const fieldsQuery = useMemo(
|
|
||||||
() => encodeURIComponent(FIELD_KEYS.join(',')),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!id) return;
|
|
||||||
let abort = false;
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
setError(null);
|
|
||||||
setLaser(null);
|
|
||||||
|
|
||||||
const res = await fetch(
|
|
||||||
`${API}/items/laser_source/${encodeURIComponent(String(id))}?fields=${fieldsQuery}`,
|
|
||||||
{ cache: 'no-store' },
|
|
||||||
);
|
|
||||||
if (!res.ok) throw new Error(`Fetch ${res.status}`);
|
|
||||||
const json = await res.json().catch(() => ({}));
|
|
||||||
if (!abort) setLaser(json?.data ?? null);
|
|
||||||
} catch (e: any) {
|
|
||||||
if (!abort) setError(e?.message || 'Failed to load');
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
abort = true;
|
|
||||||
};
|
|
||||||
}, [id, fieldsQuery]);
|
|
||||||
|
|
||||||
if (error) return <div className="p-6 text-red-600">Error: {error}</div>;
|
|
||||||
if (!laser) return <div className="p-6">Loading...</div>;
|
|
||||||
|
|
||||||
const resolveLabel = (field: string, value: any) => {
|
|
||||||
if (value == null || value === '') return '—';
|
|
||||||
// enum-ish fields
|
|
||||||
const map = CHOICE_LABELS[field];
|
|
||||||
if (map && typeof value === 'string' && map[value]) return map[value];
|
|
||||||
|
|
||||||
// smart-ish formatting for primitives
|
|
||||||
if (typeof value === 'boolean') return value ? 'Yes' : 'No';
|
|
||||||
if (typeof value === 'number') return Number.isFinite(value) ? String(value) : '—';
|
|
||||||
|
|
||||||
return String(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
export default function LaserDetailsClient({
|
||||||
|
laser,
|
||||||
|
fieldGroups,
|
||||||
|
}: {
|
||||||
|
laser: Laser;
|
||||||
|
fieldGroups: Group[];
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="p-6 max-w-4xl mx-auto">
|
<div className="p-6 max-w-4xl mx-auto">
|
||||||
<h1 className="text-3xl font-bold mb-4">
|
<h1 className="text-3xl font-bold mb-4">
|
||||||
{(laser.make as string) || '—'} {laser.model || ''}
|
{(laser.make as string) || "—"} {laser.model || ""}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{FIELD_GROUPS.map(({ title, fields }) => (
|
{fieldGroups.map(({ title, fields }) => (
|
||||||
<section key={title} className="bg-card border border-border rounded-xl p-4">
|
<section key={title} className="bg-card border border-border rounded-xl p-4">
|
||||||
<h2 className="text-xl font-semibold mb-2">{title}</h2>
|
<h2 className="text-xl font-semibold mb-2">{title}</h2>
|
||||||
<dl className="grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-4">
|
<dl className="grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-4">
|
||||||
{Object.entries(fields).map(([key, label]) => (
|
{Object.entries(fields).map(([key, label]) => (
|
||||||
<div key={key}>
|
<div key={key}>
|
||||||
<dt className="font-medium text-muted-foreground">{label}</dt>
|
<dt className="font-medium text-muted-foreground">{label}</dt>
|
||||||
<dd className="text-base break-words">
|
<dd className="text-base break-words">{resolveLabel(key, laser[key])}</dd>
|
||||||
{resolveLabel(key, (laser as any)[key])}
|
|
||||||
</dd>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</dl>
|
</dl>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue