351 lines
13 KiB
TypeScript
351 lines
13 KiB
TypeScript
import type { Metadata } from "next"
|
|
import Link from "next/link"
|
|
import Image from "next/image"
|
|
import { getAllLocations } from "@/lib/location-data"
|
|
import { generateSEOMetadata } from "@/lib/seo"
|
|
import { businessConfig } from "@/lib/seo-config"
|
|
import { MapPin, Phone, ArrowRight, Wrench, Clock } from "lucide-react"
|
|
import {
|
|
PublicInset,
|
|
PublicPageHeader,
|
|
PublicSurface,
|
|
} from "@/components/public-surface"
|
|
import { GetFreeMachineCta } from "@/components/get-free-machine-cta"
|
|
|
|
export const metadata: Metadata = generateSEOMetadata({
|
|
title: "Utah Service Areas | Rocky Mountain Vending",
|
|
description:
|
|
"See the Utah cities and counties Rocky Mountain Vending serves for free placement, machine sales, repairs, moving, parts, and ongoing vending service.",
|
|
path: "/service-areas",
|
|
keywords: [
|
|
"Utah vending service areas",
|
|
"vending machine service areas Utah",
|
|
"Salt Lake City vending company",
|
|
],
|
|
})
|
|
|
|
function LocationCard({
|
|
city,
|
|
zipCode,
|
|
href,
|
|
neighborhoods,
|
|
}: {
|
|
city: string
|
|
zipCode: string
|
|
href: string
|
|
neighborhoods: string[]
|
|
}) {
|
|
return (
|
|
<Link href={href} className="group block h-full">
|
|
<PublicInset className="h-full p-4 transition-all hover:-translate-y-0.5 hover:border-primary/25 hover:shadow-[0_20px_48px_rgba(0,0,0,0.09)] md:p-5">
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div className="space-y-1">
|
|
<h3 className="text-lg font-semibold text-foreground transition-colors group-hover:text-primary">
|
|
{city}
|
|
</h3>
|
|
<p className="text-sm text-muted-foreground">{zipCode}</p>
|
|
</div>
|
|
<div className="rounded-full border border-border/60 bg-background/90 p-2 text-muted-foreground transition-all group-hover:border-primary/30 group-hover:text-primary group-hover:translate-x-0.5">
|
|
<ArrowRight className="h-4 w-4" />
|
|
</div>
|
|
</div>
|
|
<div className="mt-4 rounded-[1.1rem] border border-border/45 bg-background/60 p-3">
|
|
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-primary/75">
|
|
Popular Areas
|
|
</p>
|
|
<p className="mt-2 text-sm leading-relaxed text-muted-foreground">
|
|
{neighborhoods.slice(0, 2).join(", ")}
|
|
</p>
|
|
</div>
|
|
</PublicInset>
|
|
</Link>
|
|
)
|
|
}
|
|
|
|
export default function ServiceAreasPage() {
|
|
const locations = getAllLocations()
|
|
const state = "Utah"
|
|
|
|
const saltLakeCounty = locations.filter((loc) =>
|
|
[
|
|
"salt-lake-city-utah",
|
|
"sandy-utah",
|
|
"draper-utah",
|
|
"murray-utah",
|
|
"midvale-utah",
|
|
"south-salt-lake-utah",
|
|
"west-valley-city-utah",
|
|
"west-jordan-utah",
|
|
"south-jordan-utah",
|
|
"riverton-utah",
|
|
"herriman-utah",
|
|
"holladay-utah",
|
|
"millcreek-utah",
|
|
"cottonwood-heights-utah",
|
|
].includes(loc.slug)
|
|
)
|
|
|
|
const davisCounty = locations.filter((loc) =>
|
|
[
|
|
"ogden-utah",
|
|
"layton-utah",
|
|
"clearfield-utah",
|
|
"syracuse-utah",
|
|
"clinton-utah",
|
|
].includes(loc.slug)
|
|
)
|
|
|
|
const utahCounty = locations.filter((loc) =>
|
|
["provo-utah"].includes(loc.slug)
|
|
)
|
|
|
|
return (
|
|
<div className="public-page">
|
|
<PublicPageHeader
|
|
align="center"
|
|
eyebrow="Service Coverage"
|
|
title="Utah locations we serve with vending, repairs, parts, and machine service."
|
|
description="Rocky Mountain Vending currently runs service routes across Salt Lake, Davis, and Utah counties, with free placement for qualifying locations, machine sales, repairs, parts, and ongoing restocking and service."
|
|
/>
|
|
|
|
<div className="mt-10 grid gap-6 lg:grid-cols-[1.1fr_0.9fr]">
|
|
<PublicSurface>
|
|
<div className="relative aspect-[926/1024] overflow-hidden rounded-[1.5rem] bg-[radial-gradient(circle_at_top_left,rgba(196,154,52,0.16),transparent_55%),linear-gradient(180deg,rgba(247,244,236,0.7),rgba(255,255,255,0.96))]">
|
|
<Image
|
|
src="/images/rocky-mountain-vending-service-area-926x1024.webp"
|
|
alt="Rocky Mountain Vending service area map covering Salt Lake City, Ogden, Provo and surrounding Utah cities"
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
</PublicSurface>
|
|
|
|
<PublicSurface className="flex flex-col justify-between">
|
|
<div>
|
|
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-primary/80">
|
|
Need Coverage Confirmation?
|
|
</p>
|
|
<h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance text-foreground">
|
|
Don't see your city yet?
|
|
</h2>
|
|
<p className="mt-3 text-base leading-relaxed text-muted-foreground">
|
|
If you're close to one of our current routes, we may still be
|
|
able to help. Reach out and we'll confirm whether your
|
|
location fits our current coverage and service schedule.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="mt-6 space-y-4">
|
|
<PublicInset>
|
|
<a
|
|
href={businessConfig.phoneUrl}
|
|
className="flex items-center gap-3 text-base font-semibold text-foreground transition hover:text-primary"
|
|
>
|
|
<Phone className="h-5 w-5 text-primary" />
|
|
{businessConfig.phone}
|
|
</a>
|
|
<p className="mt-2 text-sm text-muted-foreground">
|
|
Tell us where you're located and what kind of vending help
|
|
you need, and we'll let you know what coverage looks like
|
|
for your area.
|
|
</p>
|
|
</PublicInset>
|
|
<GetFreeMachineCta
|
|
buttonLabel="See If My Location Qualifies"
|
|
className="h-11 px-5"
|
|
/>
|
|
</div>
|
|
</PublicSurface>
|
|
</div>
|
|
|
|
<section className="mt-12">
|
|
<PublicSurface>
|
|
<div className="text-center">
|
|
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-primary/80">
|
|
Core Services
|
|
</p>
|
|
<h2 className="mt-3 text-3xl font-semibold tracking-tight text-balance md:text-4xl">
|
|
Our vending machine services across {state}
|
|
</h2>
|
|
<p className="mx-auto mt-3 max-w-2xl text-base leading-relaxed text-muted-foreground">
|
|
From free placement and machine sales to repairs, moving, and
|
|
parts help, we help Utah businesses keep vending available without
|
|
having to manage the machines themselves.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="mt-8 grid gap-5 md:grid-cols-3">
|
|
{[
|
|
{
|
|
icon: Wrench,
|
|
title: "Repairs",
|
|
body: "Expert repair and maintenance for snack, beverage, food, and combo machines.",
|
|
href: "/services/repairs",
|
|
cta: "See repair service",
|
|
},
|
|
{
|
|
icon: MapPin,
|
|
title: "Parts",
|
|
body: "Replacement parts, manuals, and machine resources for major vending brands.",
|
|
href: "/services/parts",
|
|
cta: "Shop parts",
|
|
},
|
|
{
|
|
icon: Clock,
|
|
title: "Moving",
|
|
body: "Professional machine moving for vending machines and related equipment across Utah.",
|
|
href: "/services/moving",
|
|
cta: "Moving services",
|
|
},
|
|
].map((service) => (
|
|
<PublicInset
|
|
key={service.title}
|
|
className="h-full p-5 text-center"
|
|
>
|
|
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">
|
|
<service.icon className="h-6 w-6" />
|
|
</div>
|
|
<h3 className="mt-4 text-xl font-semibold">{service.title}</h3>
|
|
<p className="mt-2 text-sm leading-relaxed text-muted-foreground">
|
|
{service.body}
|
|
</p>
|
|
<Link
|
|
href={service.href}
|
|
className="mt-5 inline-flex items-center gap-2 text-sm font-medium text-primary hover:underline"
|
|
>
|
|
{service.cta}
|
|
<ArrowRight className="h-4 w-4" />
|
|
</Link>
|
|
</PublicInset>
|
|
))}
|
|
</div>
|
|
</PublicSurface>
|
|
</section>
|
|
|
|
<section className="mt-12 space-y-8">
|
|
{[
|
|
{
|
|
title: "Salt Lake County",
|
|
description:
|
|
"Serving a wide range of offices, schools, gyms, and workplaces across the Salt Lake County route.",
|
|
items: saltLakeCounty,
|
|
},
|
|
{
|
|
title: "Davis County",
|
|
description:
|
|
"Serving businesses from Ogden to Layton with reliable vending service and repairs.",
|
|
items: davisCounty,
|
|
},
|
|
{
|
|
title: "Utah County",
|
|
description:
|
|
"Serving Provo and nearby Utah County locations with vending placement, service, and repairs.",
|
|
items: utahCounty,
|
|
},
|
|
].map((section) => (
|
|
<PublicSurface key={section.title} className="p-5 md:p-6">
|
|
<div className="flex flex-col gap-4 border-b border-border/55 pb-5 lg:flex-row lg:items-end lg:justify-between">
|
|
<div>
|
|
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-primary/80">
|
|
Coverage Area
|
|
</p>
|
|
<h2 className="mt-2 text-3xl font-semibold tracking-tight text-balance">
|
|
{section.title}
|
|
</h2>
|
|
<p className="mt-2 max-w-3xl text-base leading-relaxed text-muted-foreground">
|
|
{section.description}
|
|
</p>
|
|
</div>
|
|
<div className="w-fit rounded-full border border-border/55 bg-background/70 px-3 py-1 text-sm text-muted-foreground">
|
|
{section.items.length} cities
|
|
</div>
|
|
</div>
|
|
<div className="mt-5 grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
|
{section.items.map((location) => (
|
|
<LocationCard
|
|
key={location.slug}
|
|
city={location.city}
|
|
zipCode={location.zipCode}
|
|
href={`/vending-machines-${location.slug}`}
|
|
neighborhoods={location.neighborhoods}
|
|
/>
|
|
))}
|
|
</div>
|
|
</PublicSurface>
|
|
))}
|
|
</section>
|
|
|
|
<section className="mt-12 grid gap-6 lg:grid-cols-2">
|
|
<PublicSurface>
|
|
<h2 className="text-3xl font-semibold tracking-tight text-balance">
|
|
Why businesses choose Rocky Mountain Vending
|
|
</h2>
|
|
<div className="mt-6 grid gap-5 md:grid-cols-2">
|
|
{[
|
|
[
|
|
"Free placement for qualifying locations",
|
|
"If the location qualifies, we can place and service machines without charging upfront machine or installation fees.",
|
|
],
|
|
[
|
|
"Delivery and installation",
|
|
"Within our current routes, we handle setup, stocking, and launch so the machines are ready to use.",
|
|
],
|
|
[
|
|
"Repairs and routine service",
|
|
"We keep machines running, stocked, and clean so your team deals with fewer interruptions.",
|
|
],
|
|
[
|
|
"Healthy and traditional options",
|
|
"We match the product mix to the people who will actually use the machines every day.",
|
|
],
|
|
].map(([title, body]) => (
|
|
<PublicInset key={title}>
|
|
<h3 className="text-lg font-semibold text-foreground">
|
|
{title}
|
|
</h3>
|
|
<p className="mt-2 text-sm leading-relaxed text-muted-foreground">
|
|
{body}
|
|
</p>
|
|
</PublicInset>
|
|
))}
|
|
</div>
|
|
<div className="mt-6">
|
|
<GetFreeMachineCta
|
|
buttonLabel="See If Your Location Qualifies"
|
|
className="h-11 px-5"
|
|
/>
|
|
</div>
|
|
</PublicSurface>
|
|
|
|
<PublicSurface>
|
|
<h2 className="text-3xl font-semibold tracking-tight text-balance">
|
|
The types of locations we commonly serve
|
|
</h2>
|
|
<div className="mt-6 space-y-4">
|
|
{[
|
|
[
|
|
"For businesses",
|
|
"Offices, warehouses, auto shops, and other workplaces that want reliable on-site vending.",
|
|
],
|
|
[
|
|
"For schools",
|
|
"Snacks and drinks for students and staff with service that does not add more work to school staff.",
|
|
],
|
|
[
|
|
"For gyms and fitness spaces",
|
|
"Protein bars, sports drinks, and post-workout options that match the traffic and audience at the location.",
|
|
],
|
|
].map(([title, body]) => (
|
|
<PublicInset key={title}>
|
|
<h3 className="text-lg font-semibold">{title}</h3>
|
|
<p className="mt-2 text-sm leading-relaxed text-muted-foreground">
|
|
{body}
|
|
</p>
|
|
</PublicInset>
|
|
))}
|
|
</div>
|
|
</PublicSurface>
|
|
</section>
|
|
</div>
|
|
)
|
|
}
|