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