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_title?: string | null;
setting_notes?: string | null; setting_notes?: string | null;
photo?: { id?: string } | string | null; photo?: { id?: string } | string | number | null;
screen?: { id?: string } | string | null; screen?: { id?: string } | string | number | null;
// ids & readable fields // ids & readable fields
mat?: { id?: string | number; name?: string | null } | null; 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; 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}` : ""; return id ? `/api/dx/assets/${id}` : "";
} }
// ----------------------------------------------------------------------------
export default function CO2GalvoDetail({ export default function CO2GalvoDetail({
id, id,
@ -171,10 +180,11 @@ export default function CO2GalvoDetail({
const initialValues = useMemo(() => { const initialValues = useMemo(() => {
if (!rec) return null; if (!rec) return null;
const toId = (v: any) => (v == null ? null : typeof v === "object" ? v.id ?? v.submission_id ?? null : v); 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 photoId = resolveFileId(rec.photo);
const screenId = typeof rec.screen === "string" || typeof rec.screen === "number" ? String(rec.screen) : rec.screen?.id ?? null; const screenId = resolveFileId(rec.screen);
const matId = toId(rec.mat); const matId = toId(rec.mat);
const coatId = toId(rec.mat_coat); const coatId = toId(rec.mat_coat);
@ -229,14 +239,33 @@ export default function CO2GalvoDetail({
); );
} }
// VIEW (readable) // VIEW
const ownerDisplay = ownerLabel(rec.owner); const ownerDisplay = ownerLabel(rec.owner);
const canEdit = showOwnerEdit && isMine(rec.owner, meId); const canEdit = showOwnerEdit && isMine(rec.owner, meId);
const photoId = typeof rec.photo === "object" ? rec.photo?.id : (rec.photo as any); const photoSrc = assetSrc(resolveFileId(rec.photo));
const screenId = typeof rec.screen === "object" ? rec.screen?.id : (rec.screen as any); const screenSrc = assetSrc(resolveFileId(rec.screen));
const photoSrc = photoId ? fileUrl(String(photoId)) : "";
const screenSrc = screenId ? fileUrl(String(screenId)) : ""; // 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 ( return (
<div className="space-y-6"> <div className="space-y-6">
@ -285,18 +314,8 @@ export default function CO2GalvoDetail({
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
{photoSrc ? ( <Thumb src={photoSrc} alt="Result" />
<figure className="border rounded overflow-hidden"> <Thumb src={screenSrc} alt="Settings Screenshot" />
<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}
</div> </div>
</section> </section>
@ -406,6 +425,23 @@ export default function CO2GalvoDetail({
</div> </div>
</section> </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> </div>
); );
} }