diff --git a/txclient/src/app/landing/help/video/[videoId]/page.tsx b/txclient/src/app/landing/help/video/[videoId]/page.tsx new file mode 100644 index 0000000..cc0ae75 --- /dev/null +++ b/txclient/src/app/landing/help/video/[videoId]/page.tsx @@ -0,0 +1,272 @@ +import { Metadata } from "next"; +import Link from "next/link"; +import { notFound } from "next/navigation"; +import type { Video, VideoCategory } from "../../videoData"; +import { videoCategories, getAllVideos } from "../../videoData"; + +// Static generation: Next.js builds a page for every video at build time +export function generateStaticParams() { + return getAllVideos().map((video) => ({ videoId: video.id })); +} + +// SEO metadata per video +export async function generateMetadata({ + params, +}: { + params: Promise<{ videoId: string }>; +}): Promise { + const { videoId } = await params; + const video = getAllVideos().find((v) => v.id === videoId); + + if (!video) { + return {}; + } + + const category = videoCategories.find((c) => c.videos.some((v) => v.id === videoId)); + const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "https://turnosxpress.com.ar"; + const url = `${baseUrl}/landing/help/video/${videoId}`; + + return { + title: `${video.title} | TurnosXpress`, + description: video.description, + alternates: { + canonical: url, + }, + openGraph: { + type: "video.other", + title: video.title, + description: video.description, + images: [{ url: video.thumbnail, width: 480, height: 360, alt: video.title }], + siteName: "TurnosXpress", + locale: "es_AR", + }, + twitter: { + card: "summary_large_image", + title: video.title, + description: video.description, + images: [video.thumbnail], + }, + robots: { + index: true, + follow: true, + }, + }; +} + +const allVideos = getAllVideos(); + +// Build flat array with category context for each video +interface VideoWithContext { + video: Video; + category: VideoCategory; + index: number; +} + +function getVideoWithContext(videoId: string): VideoWithContext | null { + let flatIndex = 0; + for (const cat of videoCategories) { + const idx = cat.videos.findIndex((v) => v.id === videoId); + if (idx !== -1) { + return { + video: cat.videos[idx], + category: cat, + index: flatIndex, + }; + } + flatIndex += cat.videos.length; + } + return null; +} + +export default async function VideoPage({ + params, +}: { + params: Promise<{ videoId: string }>; +}) { + const { videoId } = await params; + const ctx = getVideoWithContext(videoId); + + if (!ctx) { + notFound(); + } + + const { video, category, index } = ctx; + const prevVideo = index > 0 ? allVideos[index - 1] : null; + const nextVideo = index < allVideos.length - 1 ? allVideos[index + 1] : null; + + // JSON-LD VideoObject schema for Google rich results + const jsonLd = { + "@context": "https://schema.org", + "@type": "VideoObject", + name: video.title, + description: video.description, + thumbnailUrl: video.thumbnail, + contentUrl: `https://www.youtube.com/watch?v=${video.id}`, + embedUrl: `https://www.youtube.com/embed/${video.id}`, + uploadDate: "2025-01-01", + publisher: { + "@type": "Organization", + name: "TurnosXpress", + logo: { + "@type": "ImageObject", + url: `${process.env.NEXT_PUBLIC_BASE_URL || "https://turnosxpress.com.ar"}/favicon.ico`, + }, + }, + category: category.name, + }; + + return ( + <> + {/* JSON-LD structured data */} +