fix: polish manuals staging rollout

This commit is contained in:
DMleadgen 2026-03-27 14:04:49 -06:00
parent d6403b6296
commit e3b97f361b
Signed by: matt
GPG key ID: C2720CF8CD701894
4 changed files with 49 additions and 8 deletions

View file

@ -7,6 +7,33 @@ import { getManualAssetFromStorage } from "@/lib/manuals-object-storage"
export const dynamic = "force-dynamic"
function buildPlaceholderSvg(label: string) {
const safeLabel = label
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;")
return `
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="480" viewBox="0 0 800 480" fill="none">
<rect width="800" height="480" rx="36" fill="#F5F1E6"/>
<rect x="28" y="28" width="744" height="424" rx="28" fill="#FCFBF7" stroke="#DCC9A3" stroke-width="2"/>
<circle cx="126" cy="124" r="54" fill="#E5D5B3"/>
<path d="M102 124h48M126 100v48" stroke="#8A6730" stroke-width="10" stroke-linecap="round"/>
<text x="400" y="184" text-anchor="middle" fill="#5C4320" font-size="40" font-family="Arial, sans-serif" font-weight="700">
Manual Preview
</text>
<text x="400" y="236" text-anchor="middle" fill="#8A6730" font-size="24" font-family="Arial, sans-serif">
Thumbnail unavailable
</text>
<text x="400" y="298" text-anchor="middle" fill="#7A6A4A" font-size="22" font-family="Arial, sans-serif">
${safeLabel}
</text>
</svg>
`.trim()
}
function decodeSegments(pathArray: string[]) {
return pathArray.map((segment) => {
try {
@ -72,7 +99,14 @@ export async function GET(
const normalizedThumbnailsDir = thumbnailsDir.replace(/\\/g, "/")
if (!existsSync(normalizedFullPath) && !existsSync(fullPath)) {
return new NextResponse("Thumbnail not found", { status: 404 })
const label = decodedPath.at(-1)?.replace(/\.(jpg|jpeg|png|webp)$/i, "") || "Rocky Mountain Vending"
return new NextResponse(buildPlaceholderSvg(label), {
headers: {
"Content-Type": "image/svg+xml; charset=utf-8",
"Cache-Control": "public, max-age=3600, stale-while-revalidate=86400",
"X-Content-Type-Options": "nosniff",
},
})
}
const fileToRead = existsSync(normalizedFullPath) ? normalizedFullPath : fullPath

View file

@ -150,27 +150,27 @@ export function Footer() {
<h3 className="font-semibold mb-5 text-base">Service Areas</h3>
<ul className="space-y-3 text-sm text-muted-foreground">
<li>
<Link href="/vending-machines/salt-lake-city-utah" className="transition-colors inline-block py-0.5">
<Link href="/vending-machines-salt-lake-city-utah" className="transition-colors inline-block py-0.5">
Salt Lake City, UT
</Link>
</li>
<li>
<Link href="/vending-machines/ogden-utah" className="transition-colors inline-block py-0.5">
<Link href="/vending-machines-ogden-utah" className="transition-colors inline-block py-0.5">
Ogden, UT
</Link>
</li>
<li>
<Link href="/vending-machines/provo-utah" className="transition-colors inline-block py-0.5">
<Link href="/vending-machines-provo-utah" className="transition-colors inline-block py-0.5">
Provo, UT
</Link>
</li>
<li>
<Link href="/vending-machines/sandy-utah" className="transition-colors inline-block py-0.5">
<Link href="/vending-machines-sandy-utah" className="transition-colors inline-block py-0.5">
Sandy, UT
</Link>
</li>
<li>
<Link href="/vending-machines/west-valley-city-utah" className="transition-colors inline-block py-0.5">
<Link href="/vending-machines-west-valley-city-utah" className="transition-colors inline-block py-0.5">
West Valley City, UT
</Link>
</li>

View file

@ -7,6 +7,7 @@ import {
Dialog,
DialogContent,
DialogHeader,
DialogDescription,
DialogTitle,
DialogClose,
} from '@/components/ui/dialog'
@ -168,6 +169,10 @@ export function ManualViewer({ manualUrl, filename, isOpen, onClose }: ManualVie
}}
>
<DialogHeader className="px-4 sm:px-6 pt-4 sm:pt-6 pb-3 sm:pb-4 border-b flex-shrink-0 bg-background">
<DialogDescription className="sr-only">
PDF viewer for {filename.replace(/\.pdf$/i, '')}. Use the actions to open the manual in a new tab,
download it, or browse available parts.
</DialogDescription>
<div className="flex items-center justify-between gap-4">
<DialogTitle className="text-base sm:text-lg font-semibold line-clamp-1 flex-1 min-w-0">
{filename.replace(/\.pdf$/i, '')}
@ -280,4 +285,3 @@ export function ManualViewer({ manualUrl, filename, isOpen, onClose }: ManualVie
</Dialog>
)
}

View file

@ -109,6 +109,10 @@ async function searchEBayForParts(partNumber: string, description?: string, manu
* Enhance parts data with real-time eBay listings
*/
async function enhancePartsData(parts: PartForPage[]): Promise<PartForPage[]> {
if (!ebayClient.isConfigured()) {
return parts
}
const enhancedParts = await Promise.all(parts.map(async (part) => {
// Only search for parts without existing eBay listings
if (part.ebayListings.length === 0) {
@ -261,4 +265,3 @@ export function clearPartsCache(): void {
manualPartsCache = null
manualPagesPartsCache = null
}