This commit is contained in:
Vula Builder
2026-09-15 18:02:57 +00:00
parent d631d6003f
commit 1319aad9b6
@@ -0,0 +1,143 @@
'use client'
import Image from "next/image"
import Link from "next/link"
import { Activity, ArrowRight } from 'lucide-react'
import { useProducts } from "@/hooks/useProducts"
import Button from "@/components/ui/Button"
import { Card } from "@/components/ui/Card"
const CURRENCY_SYMBOLS: Record<string, string> = {
zar: "R",
usd: "$",
eur: "€",
gbp: "£",
kes: "KSh",
ngn: "₦",
ghs: "₵",
}
const formatPrice = (amount: number, code?: string) => {
const symbol = CURRENCY_SYMBOLS[(code ?? "zar").toLowerCase()] ?? (code ? code.toUpperCase() : "R")
return symbol + (amount / 100).toFixed(0)
}
const conditions = [
"Neck, back and joint pain",
"Headaches and migraines",
"Nerve impingement",
"Sports and accident recovery",
"Spinal decompression",
"Fibromyalgia and infant colic",
]
const skeletonKeys = ["one", "two", "three", "four"]
export default function ChiropracticServicesSection() {
const { products, loading } = useProducts(8)
return (
<section data-vula-section="chiropracticservices" id="chiropractic-services" className="bg-background py-20 text-foreground lg:py-28">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl">
<p className="text-sm font-semibold uppercase tracking-[0.18em] text-primary">Services</p>
<h2 className="mt-4 text-3xl font-bold leading-tight sm:text-4xl">
A plan shaped by <span className="text-primary">your body</span>, not a queue
</h2>
<p className="mt-4 max-w-[44ch] text-lg text-muted-foreground">
Book the appointment that fits. Every session opens with a proper diagnosis and closes
with something you can do at home before the next visit.
</p>
</div>
<div className="mt-8 flex flex-wrap items-center gap-x-6 gap-y-2 text-sm text-muted-foreground">
{conditions.map((condition) => (
<span key={condition} className="flex items-center gap-2">
<span className="h-1.5 w-1.5 rounded-full bg-secondary" />
{condition}
</span>
))}
</div>
{loading ? (
<div className="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
{skeletonKeys.map((key) => (
<div key={key} className="overflow-hidden rounded-lg bg-card shadow-md">
<div className="aspect-video w-full animate-pulse bg-muted" />
<div className="space-y-3 p-6">
<div className="h-4 w-2/3 animate-pulse rounded bg-muted" />
<div className="h-3 w-full animate-pulse rounded bg-muted" />
<div className="h-3 w-4/5 animate-pulse rounded bg-muted" />
</div>
</div>
))}
</div>
) : (
<div className="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
{products.map((service) => {
const price = service.variants?.[0]?.prices?.[0]
return (
<Card
key={service.id}
className="group overflow-hidden rounded-lg shadow-md transition-all duration-200 ease-out hover:-translate-y-1 hover:shadow-xl"
>
<Link href={"/booking/" + service.id} className="block cursor-pointer">
<div className="relative aspect-video w-full overflow-hidden bg-muted">
{service.thumbnail ? (
<Image
src={service.thumbnail}
alt={service.title}
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 25vw"
className="object-cover transition-transform duration-500 ease-out group-hover:scale-105"
/>
) : (
<div className="flex h-full w-full items-center justify-center text-muted-foreground">
<Activity className="h-8 w-8" />
</div>
)}
</div>
<div className="p-6">
<h3 className="text-lg font-semibold leading-snug">{service.title}</h3>
{service.description ? (
<p className="mt-2 line-clamp-2 text-sm text-muted-foreground">
{service.description}
</p>
) : null}
<div className="mt-4 flex items-center justify-between gap-3">
{price ? (
<span className="text-base font-semibold text-primary">
{formatPrice(price.amount, price.currency_code)}
</span>
) : (
<span className="text-sm text-muted-foreground">Enquire at booking</span>
)}
<span className="inline-flex items-center gap-1 text-sm font-medium text-primary">
Book
<ArrowRight className="h-4 w-4" />
</span>
</div>
</div>
</Link>
</Card>
)
})}
</div>
)}
<div className="mt-12 flex flex-col items-start gap-4 border-t border-border pt-8 sm:flex-row sm:items-center sm:justify-between">
<p className="max-w-[44ch] text-sm text-muted-foreground">
Choose a time online — the practice confirms it with you. Babies from six weeks,
pregnant moms, athletes and desk workers are all welcome.
</p>
<Button asChild variant="secondary">
<Link href="/services">
See all services
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
</section>
)
}