From 90de3b4c4435c690c72a49ade4bfd3ab02eb3aa3 Mon Sep 17 00:00:00 2001 From: makearmy Date: Sat, 27 Sep 2025 23:34:35 -0400 Subject: [PATCH] standardized list pages with owner --- app/settings/co2-galvo/page.tsx | 329 +++++++++++++----------- app/settings/co2-gantry/page.tsx | 412 +++++++++++++++++-------------- app/settings/uv/page.tsx | 342 +++++++++++++------------ 3 files changed, 599 insertions(+), 484 deletions(-) diff --git a/app/settings/co2-galvo/page.tsx b/app/settings/co2-galvo/page.tsx index c17e8e2f..1cc344f8 100644 --- a/app/settings/co2-galvo/page.tsx +++ b/app/settings/co2-galvo/page.tsx @@ -14,26 +14,57 @@ export default function CO2GalvoSettingsPage() { const [settings, setSettings] = useState([]); const [loading, setLoading] = useState(true); - // canonical detail href builder const detailHref = (id: string | number) => `/settings/co2-galvo/${id}`; useEffect(() => { - const timer = setTimeout(() => setDebouncedQuery(query), 300); - return () => clearTimeout(timer); + const t = setTimeout(() => setDebouncedQuery(query), 300); + return () => clearTimeout(t); }, [query]); useEffect(() => { - fetch( - `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_co2gal?fields=submission_id,setting_title,uploader,photo.id,photo.title,mat.name,mat_coat.name,source.model,lens.field_size&limit=-1` - ) + const url = + `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_co2gal?fields=` + + [ + "submission_id", + "setting_title", + "uploader", + "owner.display_name", + "owner.first_name", + "owner.last_name", + "owner.username", + "owner.email", + "photo.id", + "photo.title", + "mat.name", + "mat_coat.name", + "source.model", + "lens.field_size", + "lens.name", + ].join(",") + + "&limit=-1"; + + fetch(url, { cache: "no-store" }) .then((res) => res.json()) .then((data) => { - setSettings(data.data || []); + setSettings(data?.data || []); setLoading(false); }) .catch(() => setLoading(false)); }, []); + const ownerName = (owner?: any) => { + if (!owner) return "—"; + return ( + owner.display_name || + [owner.first_name, owner.last_name].filter(Boolean).join(" ").trim() || + owner.username || + owner.email || + "—" + ); + }; + + const lensLabel = (row: any) => row?.lens?.field_size ?? row?.lens?.name ?? "—"; + const highlight = (text?: string) => { if (!debouncedQuery) return text || ""; const regex = new RegExp(`(${debouncedQuery})`, "gi"); @@ -45,11 +76,12 @@ export default function CO2GalvoSettingsPage() { return settings.filter((entry) => { const fieldsToSearch = [ entry.setting_title, - entry.uploader, - entry.mat?.name, - entry.mat_coat?.name, - entry.source?.model, - entry.lens?.field_size, + ownerName(entry.owner), + entry.uploader, + entry.mat?.name, + entry.mat_coat?.name, + entry.source?.model, + lensLabel(entry), ]; return fieldsToSearch .filter(Boolean) @@ -57,145 +89,151 @@ export default function CO2GalvoSettingsPage() { }); }, [settings, debouncedQuery]); + // Stats const totalSettings = settings.length; const uniqueMaterials = new Set(settings.map((s) => s.mat?.name).filter(Boolean)).size; const commonLens = settings.reduce((acc: Record, cur) => { - const lens = cur.lens?.field_size; - if (!lens) return acc; - acc[lens] = (acc[lens] || 0) + 1; + const l = lensLabel(cur); + if (!l || l === "—") return acc; + acc[l] = (acc[l] || 0) + 1; return acc; }, {}); const mostCommonLens = - Object.entries(commonLens).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || "—"; + Object.entries(commonLens).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || + "—"; - const sourceModels = settings.reduce((acc: Record, cur) => { - const model = cur.source?.model; - if (!model) return acc; - acc[model] = (acc[model] || 0) + 1; - return acc; - }, {}); - const mostCommonSource = - Object.entries(sourceModels).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || "—"; +const sourceModels = settings.reduce((acc: Record, cur) => { + const model = cur.source?.model; + if (!model) return acc; + acc[model] = (acc[model] || 0) + 1; + return acc; +}, {}); +const mostCommonSource = +Object.entries(sourceModels).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || +"—"; - const recentSettings = [...settings] - .sort((a, b) => b.submission_id - a.submission_id) - .slice(0, 5); +const recentSettings = [...settings] +.sort((a, b) => Number(b.submission_id) - Number(a.submission_id)) +.slice(0, 5); - return ( -
- +return ( +
+ -
-
-

CO₂ Galvo Settings

- setQuery(e.target.value)} - placeholder="Search settings by material, uploader, etc..." - className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" - /> -

- View and explore detailed CO₂ galvo settings with context. -

- - ← Back to Main Menu - -
+ {/* Header + Search */} +
+
+

CO₂ Galvo Settings

+ setQuery(e.target.value)} + placeholder="Search by material, owner, uploader, model, etc…" + className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" + /> +

+ View and explore detailed CO₂ galvo settings with context. +

+
-
-

How to Use

-

- Browse real-world CO₂ galvo settings from the community. Use the search to narrow results. Click any setting to view its full configuration, notes, and photos. Click any linked term to find related settings. -

-
+
+

How to Use

+

+ Browse community CO₂ galvo settings. Use the search to narrow results. Click any title + to view the full configuration, notes, and photos. +

+
-
-

Stats Summary

-
    -
  • Total Settings: {totalSettings}
  • -
  • Unique Materials: {uniqueMaterials}
  • -
  • Most Common Lens: {mostCommonLens}
  • -
  • Most Used Source: {mostCommonSource}
  • -
-
+
+

Stats Summary

+
    +
  • Total Settings: {totalSettings}
  • +
  • Unique Materials: {uniqueMaterials}
  • +
  • Most Common Lens: {mostCommonLens}
  • +
  • Most Used Source: {mostCommonSource}
  • +
+
-
-

Recently Added

-
    - {recentSettings.map((s) => ( -
  • - - {s.setting_title || "Untitled"} - {" "} - by {s.uploader || "—"} -
  • - ))} -
-
- -
-

Resources

- +
-
-
-

Submit a Setting

-

- Have a reliable galvo setting to share? Contribute to the community database. -

-
- - Submit a Setting - -
-
+ +
- {loading ? ( -

Loading settings...

- ) : filtered.length === 0 ? ( -

No CO₂ galvo settings found.

- ) : ( -
- - - - - - - - - - - - - - {filtered.map((setting) => ( + {/* Table */} + {loading ? ( +

Loading settings...

+ ) : filtered.length === 0 ? ( +

No CO₂ galvo settings found.

+ ) : ( +
+
PhotoTitleUploaderMaterialCoatingSourceLens
+ + + + + + + + + + + + + + {filtered.map((setting) => { + const ownerText = ownerName(setting.owner); + return ( - ))} - -
PhotoTitleOwnerUploaderMaterialCoatingSourceLens
{setting.photo?.id ? ( @@ -214,11 +252,17 @@ export default function CO2GalvoSettingsPage() { +
-
- )} + ); + })} + +
- ); + )} +
+); } diff --git a/app/settings/co2-gantry/page.tsx b/app/settings/co2-gantry/page.tsx index 0ef34a1f..49c61b12 100644 --- a/app/settings/co2-gantry/page.tsx +++ b/app/settings/co2-gantry/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useState, useMemo } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useSearchParams } from "next/navigation"; import Link from "next/link"; import Image from "next/image"; @@ -14,26 +14,57 @@ export default function CO2GantrySettingsPage() { const [settings, setSettings] = useState([]); const [loading, setLoading] = useState(true); - // canonical detail href builder const detailHref = (id: string | number) => `/settings/co2-gantry/${id}`; useEffect(() => { - const timer = setTimeout(() => setDebouncedQuery(query), 300); - return () => clearTimeout(timer); + const t = setTimeout(() => setDebouncedQuery(query), 300); + return () => clearTimeout(t); }, [query]); useEffect(() => { - fetch( - `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_co2gan?fields=submission_id,setting_title,uploader,photo.id,photo.title,mat.name,mat_coat.name,source.model,lens.name&limit=-1` - ) + const url = + `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_co2gan?fields=` + + [ + "submission_id", + "setting_title", + "uploader", + "owner.display_name", + "owner.first_name", + "owner.last_name", + "owner.username", + "owner.email", + "photo.id", + "photo.title", + "mat.name", + "mat_coat.name", + "source.model", + "lens.field_size", + "lens.name", + ].join(",") + + "&limit=-1"; + + fetch(url, { cache: "no-store" }) .then((res) => res.json()) .then((data) => { - setSettings(data.data || []); + setSettings(data?.data || []); setLoading(false); }) .catch(() => setLoading(false)); }, []); + const ownerName = (owner?: any) => { + if (!owner) return "—"; + return ( + owner.display_name || + [owner.first_name, owner.last_name].filter(Boolean).join(" ").trim() || + owner.username || + owner.email || + "—" + ); + }; + + const lensLabel = (row: any) => row?.lens?.field_size ?? row?.lens?.name ?? "—"; + const highlight = (text?: string) => { if (!debouncedQuery) return text || ""; const regex = new RegExp(`(${debouncedQuery})`, "gi"); @@ -45,11 +76,12 @@ export default function CO2GantrySettingsPage() { return settings.filter((entry) => { const fieldsToSearch = [ entry.setting_title, - entry.uploader, - entry.mat?.name, - entry.mat_coat?.name, - entry.source?.model, - entry.lens?.name, + ownerName(entry.owner), + entry.uploader, + entry.mat?.name, + entry.mat_coat?.name, + entry.source?.model, + lensLabel(entry), ]; return fieldsToSearch .filter(Boolean) @@ -57,198 +89,202 @@ export default function CO2GantrySettingsPage() { }); }, [settings, debouncedQuery]); + // Stats const totalSettings = settings.length; const uniqueMaterials = new Set(settings.map((s) => s.mat?.name).filter(Boolean)).size; const commonLens = settings.reduce((acc: Record, cur) => { - const lens = cur.lens?.name; - if (!lens) return acc; - acc[lens] = (acc[lens] || 0) + 1; + const l = lensLabel(cur); + if (!l || l === "—") return acc; + acc[l] = (acc[l] || 0) + 1; return acc; }, {}); const mostCommonLens = - Object.entries(commonLens).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || "—"; + Object.entries(commonLens).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || + "—"; - const sourceModels = settings.reduce((acc: Record, cur) => { - const model = cur.source?.model; - if (!model) return acc; - acc[model] = (acc[model] || 0) + 1; - return acc; - }, {}); - const mostCommonSource = - Object.entries(sourceModels).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || "—"; +const sourceModels = settings.reduce((acc: Record, cur) => { + const model = cur.source?.model; + if (!model) return acc; + acc[model] = (acc[model] || 0) + 1; + return acc; +}, {}); +const mostCommonSource = +Object.entries(sourceModels).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || +"—"; - const recentSettings = [...settings] - .sort((a, b) => b.submission_id - a.submission_id) - .slice(0, 5); +const recentSettings = [...settings] +.sort((a, b) => Number(b.submission_id) - Number(a.submission_id)) +.slice(0, 5); - return ( -
- +return ( +
+ -
-
-

CO₂ Gantry Settings

- setQuery(e.target.value)} - placeholder="Search settings by material, uploader, etc..." - className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" - /> -

- Explore curated CO₂ gantry settings. Search by material, uploader, or source. -

- - ← Back to Main Menu - -
+ {/* Header + Search */} +
+
+

CO₂ Gantry Settings

+ setQuery(e.target.value)} + placeholder="Search by material, owner, uploader, model, etc…" + className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" + /> +

+ Explore curated CO₂ gantry settings. Click any row to see full details. +

+
-
-

How to Use

-

- Browse real-world CO₂ gantry settings. Search or filter results, and click any setting for full configuration and notes. -

-
+
+

How to Use

+

+ Browse real-world CO₂ gantry settings. Use the search to narrow results. Click any title + to view the full configuration, notes, and photos. +

+
-
-

Stats Summary

-
    -
  • Total Settings: {totalSettings}
  • -
  • Unique Materials: {uniqueMaterials}
  • -
  • Most Common Lens: {mostCommonLens}
  • -
  • Most Used Source: {mostCommonSource}
  • -
-
+
+

Stats Summary

+
    +
  • Total Settings: {totalSettings}
  • +
  • Unique Materials: {uniqueMaterials}
  • +
  • Most Common Lens: {mostCommonLens}
  • +
  • Most Used Source: {mostCommonSource}
  • +
+
-
-

Recently Added

-
    - {recentSettings.map((s) => ( -
  • - - {s.setting_title || "Untitled"} - {" "} - by {s.uploader || "—"} -
  • - ))} -
-
- -
-

Resources

- +
-
-
-

Submit a Setting

-

- Got a dialed-in gantry setting? Contribute it to the database. -

-
- - Submit a Setting - -
-
+ +
- {loading ? ( -

Loading settings...

- ) : filtered.length === 0 ? ( -

No gantry settings found.

- ) : ( -
- - - - - - - - - - + {/* Table */} + {loading ? ( +

Loading settings...

+ ) : filtered.length === 0 ? ( +

No CO₂ gantry settings found.

+ ) : ( +
+
PhotoTitleUploaderMaterialCoatingSourceLens
+ + + + + + + + + + + + + + {filtered.map((setting) => ( + + + + - - - {filtered.map((setting) => ( - - - - - ))} - -
PhotoTitleOwnerUploaderMaterialCoatingSourceLens
+ {setting.photo?.id ? ( + {setting.photo.title + ) : ( + "—" + )} + + + + + + + +
- {setting.photo?.id ? ( - {setting.photo.title - ) : ( - "—" - )} - - - - - - - -
-
- )} + ))} + +
- ); + )} +
+); } diff --git a/app/settings/uv/page.tsx b/app/settings/uv/page.tsx index a3cb2d8c..c0a541ef 100644 --- a/app/settings/uv/page.tsx +++ b/app/settings/uv/page.tsx @@ -14,26 +14,57 @@ export default function UVSettingsPage() { const [settings, setSettings] = useState([]); const [loading, setLoading] = useState(true); - // canonical detail href builder const detailHref = (id: string | number) => `/settings/uv/${id}`; useEffect(() => { - const timer = setTimeout(() => setDebouncedQuery(query), 300); - return () => clearTimeout(timer); + const t = setTimeout(() => setDebouncedQuery(query), 300); + return () => clearTimeout(t); }, [query]); useEffect(() => { - fetch( - `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_uv?fields=submission_id,setting_title,uploader,photo.id,photo.title,mat.name,mat_coat.name,source.model,lens.field_size&limit=-1` - ) + const url = + `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_uv?fields=` + + [ + "submission_id", + "setting_title", + "uploader", + "owner.display_name", + "owner.first_name", + "owner.last_name", + "owner.username", + "owner.email", + "photo.id", + "photo.title", + "mat.name", + "mat_coat.name", + "source.model", + "lens.field_size", + "lens.name", + ].join(",") + + "&limit=-1"; + + fetch(url, { cache: "no-store" }) .then((res) => res.json()) .then((data) => { - setSettings(data.data || []); + setSettings(data?.data || []); setLoading(false); }) .catch(() => setLoading(false)); }, []); + const ownerName = (owner?: any) => { + if (!owner) return "—"; + return ( + owner.display_name || + [owner.first_name, owner.last_name].filter(Boolean).join(" ").trim() || + owner.username || + owner.email || + "—" + ); + }; + + const lensLabel = (row: any) => row?.lens?.field_size ?? row?.lens?.name ?? "—"; + const highlight = (text?: string) => { if (!debouncedQuery) return text || ""; const regex = new RegExp(`(${debouncedQuery})`, "gi"); @@ -45,11 +76,12 @@ export default function UVSettingsPage() { return settings.filter((entry) => { const fieldsToSearch = [ entry.setting_title, - entry.uploader, - entry.mat?.name, - entry.mat_coat?.name, - entry.source?.model, - entry.lens?.field_size, + ownerName(entry.owner), + entry.uploader, + entry.mat?.name, + entry.mat_coat?.name, + entry.source?.model, + lensLabel(entry), ]; return fieldsToSearch .filter(Boolean) @@ -57,156 +89,151 @@ export default function UVSettingsPage() { }); }, [settings, debouncedQuery]); + // Stats const totalSettings = settings.length; const uniqueMaterials = new Set(settings.map((s) => s.mat?.name).filter(Boolean)).size; const commonLens = settings.reduce((acc: Record, cur) => { - const lens = cur.lens?.field_size; - if (!lens) return acc; - acc[lens] = (acc[lens] || 0) + 1; + const l = lensLabel(cur); + if (!l || l === "—") return acc; + acc[l] = (acc[l] || 0) + 1; return acc; }, {}); const mostCommonLens = - Object.entries(commonLens).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || "—"; + Object.entries(commonLens).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || + "—"; - const sourceModels = settings.reduce((acc: Record, cur) => { - const model = cur.source?.model; - if (!model) return acc; - acc[model] = (acc[model] || 0) + 1; - return acc; - }, {}); - const mostCommonSource = - Object.entries(sourceModels).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || "—"; +const sourceModels = settings.reduce((acc: Record, cur) => { + const model = cur.source?.model; + if (!model) return acc; + acc[model] = (acc[model] || 0) + 1; + return acc; +}, {}); +const mostCommonSource = +Object.entries(sourceModels).sort((a, b) => (Number(b[1]) || 0) - (Number(a[1]) || 0))[0]?.[0] || +"—"; - const recentSettings = [...settings] - .sort((a, b) => b.submission_id - a.submission_id) - .slice(0, 5); +const recentSettings = [...settings] +.sort((a, b) => Number(b.submission_id) - Number(a.submission_id)) +.slice(0, 5); - return ( -
- +return ( +
+ -
-
-

UV Laser Settings

- setQuery(e.target.value)} - placeholder="Search settings by material, uploader, etc..." - className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" - /> -

- View and explore detailed UV laser settings with context. -

- - ← Back to Main Menu - -
+ {/* Header + Search */} +
+
+

UV Laser Settings

+ setQuery(e.target.value)} + placeholder="Search by material, owner, uploader, model, etc…" + className="w-full mb-4 dark:bg-background border border-border rounded-md p-2" + /> +

+ View and explore detailed UV settings with context. +

+
-
-

How to Use

-

- Browse real-world UV laser settings from the community. Use the search to narrow results. Click any setting to view its full configuration, notes, and photos. Click any linked term to find related settings. -

-
+
+

How to Use

+

+ Browse community UV laser settings. Use search to narrow results. Click any + title to view full configuration, notes, and photos. +

+
-
-

Resources

-
    -
  • - - Material Safety Guide - +
    +

    Stats Summary

    +
      +
    • Total Settings: {totalSettings}
    • +
    • Unique Materials: {uniqueMaterials}
    • +
    • Most Common Lens: {mostCommonLens}
    • +
    • Most Used Source: {mostCommonSource}
    • +
    +
    + +
    +

    Recently Added

    + -
    + ))} +
+
-
-
-

Submit a Setting

-

- Have a reliable UV setting to share? Contribute to the community database. -

-
- - Submit a Setting - -
+ +
-
-

Stats Summary

-
    -
  • Total Settings: {totalSettings}
  • -
  • Unique Materials: {uniqueMaterials}
  • -
  • Most Common Lens: {mostCommonLens}
  • -
  • Most Used Source: {mostCommonSource}
  • -
-
- -
-

Recently Added

-
    - {recentSettings.map((s) => ( -
  • - - {s.setting_title || "Untitled"} - {" "} - by {s.uploader || "—"} -
  • - ))} -
-
-
- - {loading ? ( -

Loading settings...

- ) : filtered.length === 0 ? ( -

No UV settings found.

- ) : ( -
- - - - - - - - - - - - - - {filtered.map((setting) => ( + {/* Table */} + {loading ? ( +

Loading settings...

+ ) : filtered.length === 0 ? ( +

No UV settings found.

+ ) : ( +
+
PhotoTitleUploaderMaterialCoatingSourceLens
+ + + + + + + + + + + + + + {filtered.map((setting) => { + const ownerText = ownerName(setting.owner); + return ( - ))} - -
PhotoTitleOwnerUploaderMaterialCoatingSourceLens
{setting.photo?.id ? ( @@ -225,11 +252,17 @@ export default function UVSettingsPage() { +
-
- )} + ); + })} + +
- ); + )} +
+); }