// ISR: revalidate every 60s — see /[locale]/page.tsx for the full rationale. export const revalidate = 60; import type { Metadata } from "next"; import Link from "next/link"; import fs from "fs"; import path from "path"; import { prisma } from "@/lib/prisma"; import { notFound } from "next/navigation"; import ApplicationClient from "./ApplicationClient"; import { setRequestLocale } from "next-intl/server"; import { getLocalizedData } from "@/lib/i18nHelper"; import { buildPageMetadata, productSchema, breadcrumbSchema, baseUrl, } from "@/lib/seo"; import JsonLd from "@/components/seo/JsonLd"; // --- FUNCIÓN ORIGINAL PARA LEER IMÁGENES LOCALES --- function getApplicationImages(slug: string) { let blueprints: string[] = []; let machines: string[] = []; let heroImage = ""; try { const imagesDir = path.join(process.cwd(), "public", "applications", slug); if (fs.existsSync(imagesDir)) { const files = fs.readdirSync(imagesDir).filter((file) => /\.(png|jpe?g|webp)$/i.test(file)); heroImage = files[0] ? `/applications/${slug}/${files[0]}` : ""; blueprints = files .filter((f) => f.includes("Screenshot") || f.startsWith("P10") || f.includes("blueprint")) .slice(0, 3) .map((f) => `/applications/${slug}/${f}`); machines = files .filter((f) => !f.includes("Screenshot") && !f.startsWith("P10") && !f.includes("blueprint")) .slice(1, 4) .map((f) => `/applications/${slug}/${f}`); } } catch (error) { console.error(`[applications/${slug}] Image scan failed:`, error); } return { heroImage, blueprints, machines }; } // ── Per-page metadata (Open Graph, Twitter, hreflang, canonical) ─────────── export async function generateMetadata({ params, }: { params: Promise<{ slug: string; locale: string }>; }): Promise { try { const { slug, locale } = await params; const raw = await prisma.application.findUnique({ where: { slug } }); if (!raw) { return { title: "Application not found | FLUX", robots: { index: false, follow: false }, }; } const data: any = getLocalizedData(raw, locale); const heroImage = getApplicationImages(slug).heroImage; const title = data?.title || "Application"; const description = data?.shortDescription || data?.subtitle || "FLUX RF industrial solutions."; return buildPageMetadata({ locale, pathWithoutLocale: `applications/${slug}`, title: `${title} — RF Industrial Solutions | FLUX`, description, ogImageUrl: heroImage || undefined, type: "product", }); } catch (error) { console.error("[applications generateMetadata]", error); return { title: "FLUX | Energy, Directed." }; } } // Pre-render all known application slugs at build time. New slugs added // after deploy render on-demand and get cached by ISR (revalidate=60). // try/catch ensures the build never fails if the DB is unreachable // during docker build — pages just render on first request instead. export async function generateStaticParams() { try { const apps = await prisma.application.findMany({ select: { slug: true }, }); return apps.map((app) => ({ slug: app.slug })); } catch { return []; } } // 🔥 AHORA RECIBIMOS EL LOCALE DESDE LA URL export default async function ApplicationPage({ params }: { params: Promise<{ slug: string, locale: string }> }) { const resolvedParams = await params; const { slug, locale } = resolvedParams; setRequestLocale(locale); // 1. Buscamos la Teoría General de la Aplicación let rawData: any = null; try { rawData = await prisma.application.findUnique({ where: { slug } }); } catch (error) { console.error(`[applications/${slug}] DB error fetching application:`, error); } if (!rawData) { return (

Application not found in Database

Return Home
); } // 🔥 TRADUCIMOS LA APLICACIÓN PRINCIPAL let data: any; try { data = getLocalizedData(rawData, locale); } catch (error) { console.error(`[applications/${slug}] Locale merge failed:`, error); data = rawData; } // 2. Buscamos el "Muro de Soluciones" (Casos Reales específicos de esta app) let rawRealCases: any[] = []; try { rawRealCases = await prisma.globalNode.findMany({ where: { application: slug, isActive: true, projectOverview: { not: null }, }, orderBy: { createdAt: "desc" }, }); } catch (error) { console.error(`[applications/${slug}] DB error fetching cases:`, error); } // 🔥 TRADUCIMOS TODOS LOS CASOS DE ESTUDIO DEL MURO let realCases: any[] = []; try { realCases = rawRealCases.map((node: any) => getLocalizedData(node, locale)); } catch (error) { console.error(`[applications/${slug}] Cases locale merge failed:`, error); realCases = rawRealCases; } // 3. Leemos las imágenes de la carpeta original const images = getApplicationImages(slug); // 4. JSON-LD structured data — wrapped to never break the render. const appTitle = data?.title || "FLUX Application"; const appUrl = `${baseUrl()}/${locale}/applications/${slug}`; const crumbs = [ { name: "Home", url: `/${locale}` }, { name: "Applications", url: `/${locale}#applications-deep` }, { name: appTitle, url: `/${locale}/applications/${slug}` }, ]; let jsonLd: object[] = []; try { const description = data?.shortDescription || data?.subtitle || ""; jsonLd = [ productSchema({ name: appTitle, description, imageUrl: images.heroImage || undefined, category: data?.category || "RF Industrial", url: appUrl, }), breadcrumbSchema( crumbs.map((c) => ({ name: c.name, url: `${baseUrl()}${c.url}` })) ), ]; } catch (error) { console.error(`[applications/${slug}] JSON-LD build failed:`, error); } return ( <> {jsonLd.length > 0 && } ); }