Rocky_Mountain_Vending/app/manuals/page.tsx

107 lines
4.5 KiB
TypeScript

export const dynamic = "force-dynamic"
import { existsSync } from "fs"
import { join } from "path"
import { Metadata } from "next"
import { businessConfig } from "@/lib/seo-config"
import { ManualsPageExperience } from "@/components/manuals-page-experience"
import { listConvexManuals } from "@/lib/convex-service"
import { scanManuals } from "@/lib/manuals"
import { selectManualsForSite } from "@/lib/manuals-site-selection"
import { generateSEOMetadata, generateStructuredData } from "@/lib/seo"
import { getManualsThumbnailsRoot } from "@/lib/manuals-paths"
export const metadata: Metadata = generateSEOMetadata({
title: "Vending Machine Manuals | Rocky Mountain Vending",
description:
"Browse vending machine manuals, service guides, and support documentation for snack, beverage, combo, coffee, and food machines.",
path: "/manuals",
keywords: [
"vending machine manuals",
"vending machine PDF",
"vending machine service manual",
"vending machine repair manual",
"vending machine troubleshooting guide",
"Royal Vendors manual",
"Dixie-Narco manual",
"Vendo manual",
"Crane vending manual",
"Seaga vending manual",
],
})
export default async function ManualsPage() {
// Prefer Convex-backed metadata, but keep filesystem fallback in place until the shared catalog is fully populated.
const convexManuals = await listConvexManuals()
const allManuals =
convexManuals.length > 0 ? convexManuals : await scanManuals()
let manuals =
convexManuals.length > 0
? convexManuals
: selectManualsForSite(allManuals).manuals
// Hide broken local thumbnails so the public manuals page doesn't spam 404s.
const thumbnailsRoot = getManualsThumbnailsRoot()
manuals = manuals.map((manual) => {
if (!manual.thumbnailUrl || /^https?:\/\//i.test(manual.thumbnailUrl)) {
return manual
}
const relativeThumbnailPath = manual.thumbnailUrl.includes("/thumbnails/")
? manual.thumbnailUrl.replace(/^.*\/thumbnails\//, "")
: manual.thumbnailUrl
return existsSync(join(thumbnailsRoot, relativeThumbnailPath))
? manual
: { ...manual, thumbnailUrl: undefined }
})
// Generate structured data for SEO
const structuredData = generateStructuredData({
title: "Vending Machine Manuals",
description:
"Download free PDF manuals, service guides, and parts documentation for hundreds of vending machine models from Royal Vendors, Dixie-Narco, Vendo, Crane, BevMax, Merchant Series, AP, GPL, Seaga, USI, and more. Find service manuals, parts catalogs, installation instructions, troubleshooting guides, and maintenance documentation for snack, beverage, combo, coffee, and food vending machines. Many manuals include available replacement parts with purchase links.",
url: `${businessConfig.website}/manuals`,
type: "WebPage",
})
// Add CollectionPage schema for better SEO
const collectionSchema = {
"@context": "https://schema.org",
"@type": "CollectionPage",
name: "Vending Machine Manuals",
description:
"A comprehensive collection of vending machine manuals, service guides, and parts documentation from leading manufacturers including Royal Vendors, Dixie-Narco, Vendo, Crane Merchandising, BevMax, Merchant Series, AP, GPL, Seaga, USI, and more. Includes service manuals, parts catalogs, installation instructions, troubleshooting guides, wiring diagrams, and maintenance documentation for snack machines, beverage machines, combo vending machines, coffee machines, food machines, and frozen food machines. Many manuals feature available replacement parts with direct purchase links.",
url: `${businessConfig.website}/manuals`,
mainEntity: {
"@type": "ItemList",
numberOfItems: manuals.length,
itemListElement: manuals.slice(0, 50).map((manual, index) => ({
"@type": "ListItem",
position: index + 1,
item: {
"@type": "DigitalDocument",
name: manual.filename.replace(/\.pdf$/i, ""),
description: `${manual.manufacturer} ${manual.category} Manual`,
encodingFormat: "application/pdf",
},
})),
},
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(collectionSchema) }}
/>
<div className="public-page">
<ManualsPageExperience initialManuals={manuals} />
</div>
</>
)
}