Rocky_Mountain_Vending/artifacts/backups/formatting/app/vending-machines-[location]/page.tsx

411 lines
16 KiB
TypeScript

import { notFound } from "next/navigation";
import type { Metadata } from "next";
import { getLocationBySlug, getAllLocationSlugs } from "@/lib/location-data";
import { businessConfig, socialProfiles } from "@/lib/seo-config";
import { Phone, Mail, Globe, Clock, CreditCard, MapPin } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
import { ReviewsSection } from "@/components/reviews-section";
import { Button } from "@/components/ui/button";
import Link from "next/link";
interface LocationPageProps {
params: Promise<{ location: string }>;
}
// Known non-location routes that should be handled by the catch-all route
const NON_LOCATION_ROUTES = ['machines-we-use', 'machines-for-sale'];
// Generate static params for all locations
export async function generateStaticParams() {
const slugs = getAllLocationSlugs();
return slugs.map((slug) => ({
location: slug,
}));
}
// Generate metadata for each location page
export async function generateMetadata({ params }: LocationPageProps): Promise<Metadata> {
const { location } = await params;
// If this is a known non-location route, return notFound to let catch-all handle it
if (NON_LOCATION_ROUTES.includes(location)) {
return {
title: "Page Not Found | Rocky Mountain Vending",
};
}
const locationData = getLocationBySlug(location);
if (!locationData) {
return {
title: "Location Not Found | Rocky Mountain Vending",
};
}
const title = `Vending Machine Supplier in ${locationData.city}, ${locationData.stateAbbr} | Rocky Mountain Vending`;
const description = `Get FREE vending machines for your ${locationData.city} business! Rocky Mountain Vending provides quality vending machine sales, repairs, and service in ${locationData.city}, ${locationData.state}. Call (435) 233-9668.`;
return {
title,
description,
keywords: [
`vending machines ${locationData.city}`,
`vending machine supplier ${locationData.city}`,
`free vending machines ${locationData.city}`,
`vending machine repair ${locationData.city}`,
`${locationData.city} vending`,
...locationData.neighborhoods.map((n) => `vending machines ${n}`),
],
openGraph: {
title,
description,
url: `${businessConfig.website}/vending-machines-${location}`,
type: "website",
locale: "en_US",
siteName: businessConfig.name,
},
twitter: {
card: "summary_large_image",
title,
description,
},
alternates: {
canonical: `${businessConfig.website}/vending-machines-${location}`,
},
};
}
export default async function LocationPage({ params }: LocationPageProps) {
const { location } = await params;
// If this is a known non-location route, return notFound to let catch-all handle it
if (NON_LOCATION_ROUTES.includes(location)) {
notFound();
}
const locationData = getLocationBySlug(location);
if (!locationData) {
notFound();
}
// Generate structured data for the location
const structuredData = {
"@context": "https://schema.org",
"@type": "LocalBusiness",
name: businessConfig.name,
description: `Rocky Mountain Vending provides high-quality vending machines, vending machine sales, and vending machine repair services to businesses and schools across ${locationData.city}, ${locationData.state}.`,
url: `${businessConfig.website}/vending-machines-${location}`,
telephone: businessConfig.phoneFormatted,
priceRange: "$$",
foundingDate: businessConfig.openingDate,
areaServed: {
"@type": "City",
name: locationData.city,
address: {
"@type": "PostalAddress",
addressLocality: locationData.city,
addressRegion: locationData.stateAbbr,
postalCode: locationData.zipCode,
addressCountry: "US",
},
},
geo: {
"@type": "GeoCoordinates",
latitude: locationData.latitude,
longitude: locationData.longitude,
},
openingHoursSpecification: [
{
"@type": "OpeningHoursSpecification",
dayOfWeek: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
opens: "08:00",
closes: "17:00",
},
],
paymentAccepted: "Credit Card, Debit Card, American Express, Discover, MasterCard, Visa",
availableLanguage: ["English"],
sameAs: [
socialProfiles.linkedin,
socialProfiles.facebook,
socialProfiles.youtube,
socialProfiles.twitter,
locationData.chamberUrl,
locationData.cityWebsite,
...locationData.localLinks.map((link) => link.url),
],
};
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }} />
<article className="container mx-auto px-4 py-8 md:py-12">
{/* Hero Section */}
<header className="mb-12 text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">
Vending Machine Supplier in {locationData.city}, {locationData.state}
</h1>
<p className="text-lg md:text-xl text-muted-foreground max-w-3xl mx-auto leading-relaxed">
Need a vending machine supplier in {locationData.city}, {locationData.state}? Rocky Mountain Vending has
been helping local businesses and schools since 2019 with quality vending solutions. We bring healthy
snacks, cold drinks, and dependable service right to your doorno hassle, no fuss.
</p>
</header>
{/* Local Anecdote */}
<div className="mb-12 max-w-4xl mx-auto">
<Card className="border-secondary/20 bg-secondary/5">
<CardContent className="p-6 md:p-8">
<p className="text-base md:text-lg leading-relaxed">
A while back, we worked with a {locationData.anecdote.customer} near {locationData.anecdote.location}.
We set them up with a {locationData.anecdote.solution}. Now {locationData.anecdote.outcome}. That's
what we do best—make vending simple.
</p>
</CardContent>
</Card>
</div>
{/* Services Section */}
<section className="mb-16 max-w-4xl mx-auto">
<h2 className="text-3xl font-bold mb-8">{locationData.h2Variants.services}</h2>
<p className="text-muted-foreground mb-8">
We handle everything from picking the right machine to keeping it running smoothly. Here's what we offer:
</p>
<div className="grid gap-6 md:grid-cols-2">
<Card>
<CardContent className="p-6">
<h3 className="text-xl font-semibold mb-3">Vending Machine Sales</h3>
<p className="text-muted-foreground">
Need a new machine? We've got options that fit your space and budget. Whether you run a school,
office, or warehouse, we'll help you choose one that works.
</p>
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<h3 className="text-xl font-semibold mb-3">Vending Machine Repair</h3>
<p className="text-muted-foreground">
Machines break downit happens. When yours does, we fix it fast so you're not stuck with an empty
snack spot.
</p>
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<h3 className="text-xl font-semibold mb-3">Healthy Snack and Beverage Options</h3>
<p className="text-muted-foreground">
We stock machines with healthy choices like granola bars, fruit snacks, and sparkling water. Great
for schools and gyms that want better options.
</p>
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<h3 className="text-xl font-semibold mb-3">Maintenance Services</h3>
<p className="text-muted-foreground">
Regular checkups keep machines working right. We handle restocking, cleaning, and small fixes so you
don't have to think about it.
</p>
</CardContent>
</Card>
</div>
</section>
{/* Coverage Section */}
<section className="mb-16 max-w-4xl mx-auto">
<h2 className="text-3xl font-bold mb-6">{locationData.h2Variants.coverage}</h2>
<div className="prose prose-lg max-w-none">
<p className="text-muted-foreground mb-4">
We service all of {locationData.city}, including{" "}
{locationData.neighborhoods.map((n, i) => (
<span key={n}>
{i > 0 && i === locationData.neighborhoods.length - 1 && ", and "}
{i > 0 && i < locationData.neighborhoods.length - 1 && ", "}
{n}
</span>
))}
. We also deliver to nearby cities like{" "}
{locationData.nearbyCities.map((c, i) => (
<span key={c}>
{i > 0 && i === locationData.nearbyCities.length - 1 && ", and "}
{i > 0 && i < locationData.nearbyCities.length - 1 && ", "}
{c}
</span>
))}
free delivery within 50 miles of {locationData.city}.
</p>
<p className="text-muted-foreground mb-6">
The{" "}
<a
href={locationData.chamberUrl}
target="_blank"
rel="noopener noreferrer"
className="text-secondary hover:underline font-medium"
>
{locationData.chamberName}
</a>{" "}
connects us with local businesses, and we're proud to serve this community. Here are some helpful local
resources:
</p>
<ul className="space-y-2 mb-6">
{locationData.localLinks.map((link) => (
<li key={link.url}>
<a
href={link.url}
target="_blank"
rel="noopener noreferrer"
className="text-secondary hover:underline flex items-center gap-2"
>
<MapPin className="h-4 w-4" />
{link.name}
</a>
</li>
))}
</ul>
</div>
</section>
{/* Contact Section */}
<section className="mb-16 max-w-4xl mx-auto">
<h2 className="text-3xl font-bold mb-6">{locationData.h2Variants.contact}</h2>
<p className="text-muted-foreground mb-8">
We're open Monday through Friday, 8:00 AM to 5:00 PM. Closed on weekends, but you can always reach out by
phone or text.
</p>
<div className="grid gap-4 md:grid-cols-3 mb-8">
<Card>
<CardContent className="p-6 flex items-start gap-4">
<Phone className="h-6 w-6 text-secondary flex-shrink-0 mt-1" />
<div>
<div className="font-semibold mb-1">Phone</div>
<a href={businessConfig.phoneUrl} className="text-secondary hover:underline">
{businessConfig.phone}
</a>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-6 flex items-start gap-4">
<Mail className="h-6 w-6 text-secondary flex-shrink-0 mt-1" />
<div>
<div className="font-semibold mb-1">Text</div>
<a href={businessConfig.smsUrl} className="text-secondary hover:underline">
{businessConfig.phone}
</a>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-6 flex items-start gap-4">
<Globe className="h-6 w-6 text-secondary flex-shrink-0 mt-1" />
<div>
<div className="font-semibold mb-1">Website</div>
<a
href={businessConfig.website}
target="_blank"
rel="noopener noreferrer"
className="text-secondary hover:underline text-sm"
>
rockymountainvending.com
</a>
</div>
</CardContent>
</Card>
</div>
{/* CRM Form */}
<Card className="border-secondary/20">
<CardContent className="p-8">
<div className="text-center mb-6">
<h3 className="text-2xl font-bold mb-2">Get Your Free Vending Machine</h3>
<p className="text-muted-foreground">
Fill out the form below and we'll contact you within 24 hours to discuss your needs.
</p>
</div>
<iframe
src="https://link.sluice-box.io/widget/form/T76mIdPvC5iBwAI2wFPg"
style={{ width: "100%", height: "650px", border: "none", borderRadius: "4px" }}
id="inline-T76mIdPvC5iBwAI2wFPg"
data-layout="{'id':'INLINE'}"
data-trigger-type="alwaysShow"
data-trigger-value=""
data-activation-type="alwaysActivated"
data-activation-value=""
data-deactivation-type="neverDeactivate"
data-deactivation-value=""
data-form-name="Request Machine Short"
data-height="638"
data-layout-iframe-id="inline-T76mIdPvC5iBwAI2wFPg"
data-form-id="T76mIdPvC5iBwAI2wFPg"
title="Request Free Vending Machine Form"
/>
</CardContent>
</Card>
</section>
{/* Payment Options */}
<section className="mb-16 max-w-4xl mx-auto">
<h2 className="text-3xl font-bold mb-6">{locationData.h2Variants.payments}</h2>
<Card>
<CardContent className="p-6">
<div className="flex items-start gap-4 mb-4">
<CreditCard className="h-6 w-6 text-secondary flex-shrink-0 mt-1" />
<div>
<div className="font-semibold mb-2">Payment Methods</div>
<p className="text-muted-foreground">
We accept credit cards, debit cards, American Express, Discover, MasterCard, and Visa.
</p>
</div>
</div>
<div className="flex items-start gap-4">
<Clock className="h-6 w-6 text-secondary flex-shrink-0 mt-1" />
<div>
<div className="font-semibold mb-2">Language</div>
<p className="text-muted-foreground">
Our team speaks English, and we're happy to answer any questions you have.
</p>
</div>
</div>
</CardContent>
</Card>
</section>
{/* Why Choose Us */}
<section className="mb-16 max-w-4xl mx-auto">
<h2 className="text-3xl font-bold mb-6">{locationData.h2Variants.whyChoose}</h2>
<div className="prose prose-lg max-w-none">
<p className="text-muted-foreground mb-4">
Since 2019, we've been serving businesses and schools across Utah County, Salt Lake County, and Davis
County. We're local, we're fast, and we care about getting it right. About 95% of our {locationData.city}{" "}
clients stick with us because we show up when we say we will and fix problems quickly. That's based on our
own records, so we're confident in it.
</p>
<p className="text-muted-foreground mb-6">
We built our machines to handle Utah's weathercold winters, hot summers, all of it. You won't have to
worry about breakdowns when the temperature drops.
</p>
</div>
<div className="text-center">
<Button asChild size="lg" className="bg-secondary hover:bg-secondary/90">
<Link href="#contact">Get Your Free Machine Today</Link>
</Button>
</div>
</section>
</article>
{/* Google Reviews Section */}
<ReviewsSection />
</>
);
}