This commit is contained in:
Vula Builder
2026-08-03 11:42:10 +00:00
parent 44ba1177d5
commit 7c5e698bf8
@@ -0,0 +1,76 @@
'use client'
import { useVulaContent } from '@/hooks/useVulaContent'
import Badge from '@/components/ui/Badge'
const DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
function parseTime(value?: string): number | null {
if (!value) return null
const parts = value.split(':')
const hours = Number(parts[0])
const minutes = parts[1] ? Number(parts[1]) : 0
if (Number.isNaN(hours) || Number.isNaN(minutes)) return null
return hours * 60 + minutes
}
function isOpenNow(d: { day_of_week?: string; open_time?: string; close_time?: string; is_closed?: boolean }) {
if (String(d.is_closed).toLowerCase() === 'true') return false
const now = new Date()
if (String(d.day_of_week ?? '').toLowerCase() !== DAYS[now.getDay()].toLowerCase()) return false
const current = now.getHours() * 60 + now.getMinutes()
const open = parseTime(d.open_time)
const close = parseTime(d.close_time)
if (open === null || close === null) return false
return current >= open && current < close
}
export default function BusinessHoursSection() {
const { items = [], loading } = useVulaContent('business_hours')
if (loading) return <div className="flex justify-center py-16"><div className="w-8 h-8 rounded-full border-2 border-current border-t-transparent animate-spin" /></div>
if (items.length === 0) return null
const weekOrder = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
const sortedItems = [...items].sort((a, b) => {
const da = (a.data as { day_of_week?: string }).day_of_week ?? ''
const db = (b.data as { day_of_week?: string }).day_of_week ?? ''
return weekOrder.indexOf(da) - weekOrder.indexOf(db)
})
return (
<section id="business-hours" data-vula-section="business-hours" data-vula-cms="business_hours" className="bg-[#F0F8FF] py-20">
<div className="mx-auto max-w-4xl px-4">
<div className="mb-10 text-center">
<p className="mb-2 text-sm font-semibold uppercase tracking-[0.2em] text-[#00A8CC]">Fourways, Johannesburg</p>
<h2 className="font-sora text-3xl font-bold text-[#1A2B3C]">Our week at <span className="text-[#00A8CC]">Zama Salon</span></h2>
<p className="mx-auto mt-3 max-w-[44ch] text-[#1A2B3C]/70">Walk-ins welcome, but booking ahead saves your chair.</p>
</div>
<div className="overflow-hidden rounded-xl bg-white shadow-md">
{sortedItems.map((item) => {
const d = item.data as { day_of_week?: string; open_time?: string; close_time?: string; is_closed?: boolean; note?: string }
const closed = String(d.is_closed).toLowerCase() === 'true'
const open = isOpenNow(d)
const hours = closed ? 'Closed' : `${d.open_time} ${d.close_time}`
return (
<div
key={item.id}
className={`flex flex-col gap-1 border-b border-[#d4dadd] px-5 py-4 last:border-0 sm:flex-row sm:items-center sm:justify-between ${
open ? 'bg-[#0077BE] text-white' : ''
}`}
>
<div className="flex items-center gap-3">
<span className="w-28 font-semibold">{d.day_of_week}</span>
<span className={`text-sm ${open ? 'text-white/80' : 'text-[#1A2B3C]/60'}`}>{hours}</span>
</div>
{open && (
<Badge className="bg-[#00A8CC] text-white">Open now</Badge>
)}
</div>
)
})}
</div>
</div>
</section>
)
}