final settings pages fixes

This commit is contained in:
makearmy 2025-10-03 19:18:47 -04:00
parent fc380a49fb
commit 919894ee92

View file

@ -10,8 +10,8 @@ type Rec = {
setting_title?: string | null;
setting_notes?: string | null;
photo?: { id?: string } | string | null;
screen?: { id?: string } | string | null;
photo?: { id?: string } | string | number | null;
screen?: { id?: string } | string | number | null;
// ids & readable fields
mat?: { id?: string | number; name?: string | null } | null;
@ -54,9 +54,18 @@ function isMine(owner: Rec["owner"], meId: string | null) {
return owner.id != null && String(owner.id) === meId;
}
function fileUrl(id?: string) {
// --- Image helpers -----------------------------------------------------------
function resolveFileId(v: Rec["photo"]): string | null {
if (v == null) return null;
if (typeof v === "string" || typeof v === "number") return String(v);
if (typeof v === "object" && v.id) return String(v.id);
// some Directus shapes may nest deeper; add more cases if needed
return null;
}
function assetSrc(id?: string | null) {
return id ? `/api/dx/assets/${id}` : "";
}
// ----------------------------------------------------------------------------
export default function CO2GalvoDetail({
id,
@ -171,10 +180,11 @@ export default function CO2GalvoDetail({
const initialValues = useMemo(() => {
if (!rec) return null;
const toId = (v: any) => (v == null ? null : typeof v === "object" ? v.id ?? v.submission_id ?? null : v);
const photoId = typeof rec.photo === "string" || typeof rec.photo === "number" ? String(rec.photo) : rec.photo?.id ?? null;
const screenId = typeof rec.screen === "string" || typeof rec.screen === "number" ? String(rec.screen) : rec.screen?.id ?? null;
const photoId = resolveFileId(rec.photo);
const screenId = resolveFileId(rec.screen);
const matId = toId(rec.mat);
const coatId = toId(rec.mat_coat);
@ -229,14 +239,33 @@ export default function CO2GalvoDetail({
);
}
// VIEW (readable)
// VIEW
const ownerDisplay = ownerLabel(rec.owner);
const canEdit = showOwnerEdit && isMine(rec.owner, meId);
const photoId = typeof rec.photo === "object" ? rec.photo?.id : (rec.photo as any);
const screenId = typeof rec.screen === "object" ? rec.screen?.id : (rec.screen as any);
const photoSrc = photoId ? fileUrl(String(photoId)) : "";
const screenSrc = screenId ? fileUrl(String(screenId)) : "";
const photoSrc = assetSrc(resolveFileId(rec.photo));
const screenSrc = assetSrc(resolveFileId(rec.screen));
// simple lightbox state
const [lightbox, setLightbox] = useState<{ src: string; alt: string } | null>(null);
function Thumb({ src, alt }: { src: string; alt: string }) {
if (!src) return null;
return (
<figure className="border rounded overflow-hidden">
<button
type="button"
onClick={() => setLightbox({ src, alt })}
className="block w-full aspect-square overflow-hidden"
aria-label={`Open ${alt}`}
>
{/* 1:1 crop */}
<img src={src} alt={alt} className="w-full h-full object-cover" loading="lazy" />
</button>
<figcaption className="text-xs p-1 text-muted-foreground">{alt}</figcaption>
</figure>
);
}
return (
<div className="space-y-6">
@ -285,18 +314,8 @@ export default function CO2GalvoDetail({
</div>
<div className="grid grid-cols-2 gap-4">
{photoSrc ? (
<figure className="border rounded overflow-hidden">
<img src={photoSrc} alt="Result" className="w-full h-auto" />
<figcaption className="text-xs p-1 text-muted-foreground">Result</figcaption>
</figure>
) : null}
{screenSrc ? (
<figure className="border rounded overflow-hidden">
<img src={screenSrc} alt="Settings screenshot" className="w-full h-auto" />
<figcaption className="text-xs p-1 text-muted-foreground">Settings Screenshot</figcaption>
</figure>
) : null}
<Thumb src={photoSrc} alt="Result" />
<Thumb src={screenSrc} alt="Settings Screenshot" />
</div>
</section>
@ -406,6 +425,23 @@ export default function CO2GalvoDetail({
</div>
</section>
)}
{/* Lightbox overlay */}
{lightbox && (
<div
className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4"
onClick={() => setLightbox(null)}
role="dialog"
aria-modal="true"
>
<img
src={lightbox.src}
alt={lightbox.alt}
className="max-w-[90vw] max-h-[90vh] object-contain rounded"
onClick={(e) => e.stopPropagation()}
/>
</div>
)}
</div>
);
}