Deploy
This commit is contained in:
@@ -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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user