Files
vula-f7951bab/src/components/BusinessMap.tsx
T
Vula Builder c95c365716 Deploy
2026-10-11 14:20:23 +00:00

89 lines
3.0 KiB
TypeScript

'use client'
import { useEffect, useState } from 'react'
interface Address {
street: string | null
locality: string | null
region: string | null
postalCode: string | null
country: string | null
}
interface Profile {
businessName: string | null
address: Address | null
}
/** One line a map search understands, in South African order. */
export function placeFor(a: Address): string {
const country = !a.country || a.country === 'ZA' ? 'South Africa' : a.country
return [a.street, a.locality, [a.region, a.postalCode].filter(Boolean).join(' '), country]
.filter(Boolean)
.join(', ')
}
/**
* The business's own address on a map, with directions.
*
* Nothing at all until the owner has entered a full address. The map is
* loaded when a visitor asks for it, not before.
*/
export default function BusinessMap({ className = '' }: { className?: string }) {
const [p, setP] = useState<Profile | null>(null)
const [show, setShow] = useState(false)
useEffect(() => {
const base = process.env.NEXT_PUBLIC_VULA_COMMERCE_URL
const id = process.env.NEXT_PUBLIC_VULA_PROJECT_ID
if (!base || !id) return
let live = true
fetch(base + '/api/public/profile/' + id)
.then((r) => (r.ok ? r.json() : null))
.then((d) => { if (live && d?.profile) setP(d.profile) })
.catch(() => { /* no map is where we already were */ })
return () => { live = false }
}, [])
const a = p?.address
if (!a) return null
const q = encodeURIComponent(placeFor(a))
const name = p?.businessName || 'our location'
return (
<div className={'overflow-hidden rounded-2xl border border-border bg-card ' + className}>
{show ? (
<iframe
title={'Map showing ' + name}
src={'https://maps.google.com/maps?q=' + q + '&z=16&output=embed'}
className="block h-64 w-full border-0 sm:h-80"
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
allowFullScreen
/>
) : (
<button
type="button"
onClick={() => setShow(true)}
className="flex h-64 w-full flex-col items-center justify-center gap-2 bg-muted px-6 text-center transition-colors hover:bg-muted/70 sm:h-80"
>
<svg aria-hidden="true" viewBox="0 0 24 24" className="h-7 w-7 text-primary" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M20 10c0 6-8 12-8 12S4 16 4 10a8 8 0 0 1 16 0Z" />
<circle cx="12" cy="10" r="3" />
</svg>
<span className="font-semibold text-foreground">Show map</span>
<span className="text-xs text-muted-foreground">Loads Google Maps</span>
</button>
)}
<div className="flex justify-end p-4">
<a
href={'https://www.google.com/maps/dir/?api=1&destination=' + q}
target="_blank"
rel="noopener noreferrer"
className="text-sm font-medium text-primary hover:underline"
>
Get directions
</a>
</div>
</div>
)
}