Files
Makers3D/apps/web/app/works/[slug]/page.tsx
T

171 lines
7.4 KiB
TypeScript

import Link from "next/link";
import { headers } from "next/headers";
import { notFound } from "next/navigation";
import FavoriteToggle from "../../components/FavoriteToggle";
import WorkHeroGallery from "../../components/WorkHeroGallery";
import WorkShareActions from "../../components/WorkShareActions";
import { serverFetch } from "../../lib/api";
function toText(value: unknown, fallback = "") {
return typeof value === "string" && value ? value : fallback;
}
function asArray(value: unknown): string[] {
return Array.isArray(value) ? value.map((item) => String(item)) : [];
}
function asRecords(value: unknown): Array<Record<string, unknown>> {
return Array.isArray(value) ? value.filter((item): item is Record<string, unknown> => Boolean(item) && typeof item === "object" && !Array.isArray(item)) : [];
}
function galleryFor(work: Record<string, unknown>) {
const images = [toText(work.image_url), ...asArray(work.gallery_urls)].filter(Boolean);
return Array.from(new Set(images));
}
function draftDataFor(work: Record<string, unknown>) {
return work.draft_data && typeof work.draft_data === "object" && !Array.isArray(work.draft_data)
? work.draft_data as Record<string, unknown>
: {};
}
export default async function WorkPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
let work: Record<string, unknown>;
try {
const data = await serverFetch<{ work: Record<string, unknown> }>(`/works/${slug}`);
work = data.work;
} catch {
notFound();
}
const requestHeaders = await headers();
const gallery = galleryFor(work);
const draftData = draftDataFor(work);
const beforeImage = toText(draftData.beforeImageUrl);
const afterImage = toText(draftData.afterImageUrl);
const showBeforeAfter = Boolean(draftData.includeBeforeAfter && beforeImage && afterImage);
const relatedWorks = asRecords(work.related_works);
const title = toText(work.title, "Trabajo publicado");
const makerName = toText(work.maker_name, "Maker");
const host = requestHeaders.get("x-forwarded-host") || requestHeaders.get("host") || "dev.jazari.com.ar";
const protocol = requestHeaders.get("x-forwarded-proto") || (host.includes("localhost") ? "http" : "https");
const workUrl = `${protocol}://${host}/works/${slug}`;
const contactHref = `/consultas/nueva?makerId=${encodeURIComponent(String(work.maker_id))}&sourceType=work&sourceId=${encodeURIComponent(String(work.id))}&makerName=${encodeURIComponent(makerName)}&contextTitle=${encodeURIComponent(title)}&returnTo=${encodeURIComponent(`/works/${slug}`)}`;
return (
<main className="page-shell work-detail-page">
<section className="work-detail-phone">
<WorkHeroGallery gallery={gallery} title={title} workId={String(work.id)} shareUrl={workUrl} />
<section className="work-detail-title-card">
<h1>{title}</h1>
<div className="work-detail-tags">
<span>{toText(work.technology, "FDM")}</span>
<span>{toText(work.material, "PLA")}</span>
</div>
<Link href={`/makers/${toText(work.maker_slug)}`} className="work-detail-maker-card">
<span>{makerName.slice(0, 2).toUpperCase()}</span>
<div>
<strong>{makerName}</strong>
<small><span className="map-home-star">*</span> 4,9 | 128 opiniones | Aceptando trabajos</small>
</div>
<b>&gt;</b>
</Link>
</section>
<section className="work-detail-section">
<h2>Que se hizo?</h2>
<p>{toText(work.summary, "Se reprodujo una pieza a medida para resolver una necesidad real del cliente.")}</p>
<div className="work-detail-feature-grid">
<article><span>01</span><strong>Pieza funcional</strong></article>
<article><span>02</span><strong>Resiste calor</strong></article>
<article><span>03</span><strong>1 unidad</strong></article>
<article><span>04</span><strong>48 h fabricacion</strong></article>
</div>
</section>
{showBeforeAfter ? (
<section className="work-detail-section">
<div className="work-detail-section-head">
<h2>Antes / Resultado</h2>
<Link href="#galeria">Ver mas</Link>
</div>
<div className="work-detail-before-after">
<article>
<img src={beforeImage} alt="Antes" />
<span>Antes</span>
</article>
<b>&gt;</b>
<article>
<img src={afterImage} alt="Resultado" />
<span>Resultado</span>
</article>
</div>
</section>
) : null}
<section className="work-detail-section">
<h2>Historia del proyecto</h2>
<p>{toText(work.story, "El cliente necesitaba recuperar una pieza o validar una solucion. Se tomo una referencia, se ajusto el diseno y se fabrico una version funcional lista para probar.")}</p>
</section>
<section className="work-detail-section">
<details open>
<summary>Detalles tecnicos</summary>
<div className="work-detail-specs">
<span>Tecnologia</span><strong>{toText(work.technology, "FDM")}</strong>
<span>Material</span><strong>{toText(work.material, "PETG")}</strong>
<span>Acabado</span><strong>Lijado y ajuste manual</strong>
<span>Resolucion</span><strong>0,16 mm capa</strong>
<span>Relleno</span><strong>40%</strong>
<span>Tiempo</span><strong>48 horas</strong>
</div>
</details>
</section>
<section id="galeria" className="work-detail-section">
<div className="work-detail-section-head">
<h2>Galeria</h2>
<span>{gallery.length} fotos</span>
</div>
<div className="work-detail-gallery-grid">
{gallery.map((image, index) => (
<img key={`${image}-${index}`} src={image} alt={`${title} ${index + 1}`} />
))}
</div>
</section>
{relatedWorks.length ? (
<section className="work-detail-section">
<div className="work-detail-section-head">
<h2>Tambien puede interesarte</h2>
<Link href="/discover">Ver todos</Link>
</div>
<div className="work-detail-related-rail">
{relatedWorks.map((item) => (
<Link key={String(item.id)} href={`/works/${toText(item.slug)}`}>
<img src={toText(item.image_url, "/demo/work-custom.svg")} alt={toText(item.title, "Trabajo sugerido")} />
<strong>{toText(item.title, "Trabajo sugerido")}</strong>
<span>{toText(item.technology, "FDM")} | {toText(item.material, "PETG")}</span>
</Link>
))}
</div>
</section>
) : null}
<section className="work-detail-section work-detail-share">
<h2>Compartir este trabajo</h2>
<p>Comparte este enlace para mostrar la referencia o enviarla por WhatsApp.</p>
<WorkShareActions title={title} url={workUrl} />
</section>
</section>
<div className="work-detail-bottom-cta">
<FavoriteToggle targetType="work" targetId={String(work.id)} compact />
<a href={contactHref} className="button button-primary">Quiero algo similar</a>
</div>
</main>
);
}