Deploy
This commit is contained in:
@@ -0,0 +1,67 @@
|
|||||||
|
interface Profile {
|
||||||
|
businessName: string | null
|
||||||
|
schemaType: string
|
||||||
|
phone: string | null
|
||||||
|
email: string | null
|
||||||
|
socials?: { network: string; url: string }[]
|
||||||
|
address: {
|
||||||
|
street: string | null
|
||||||
|
locality: string | null
|
||||||
|
region: string | null
|
||||||
|
postalCode: string | null
|
||||||
|
country: string | null
|
||||||
|
} | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* schema.org LocalBusiness data for this business, rendered into the page.
|
||||||
|
*
|
||||||
|
* Server-side, and revalidated hourly rather than per request: this is the
|
||||||
|
* same answer for every visitor, and a crawler should not be waiting on our
|
||||||
|
* backend to see a page.
|
||||||
|
*/
|
||||||
|
export default async function BusinessSchema() {
|
||||||
|
const base = process.env.NEXT_PUBLIC_VULA_COMMERCE_URL
|
||||||
|
const id = process.env.NEXT_PUBLIC_VULA_PROJECT_ID
|
||||||
|
if (!base || !id) return null
|
||||||
|
|
||||||
|
let p: Profile | null = null
|
||||||
|
try {
|
||||||
|
const res = await fetch(base + '/api/public/profile/' + id, { next: { revalidate: 3600 } })
|
||||||
|
if (res.ok) p = (await res.json())?.profile ?? null
|
||||||
|
} catch {
|
||||||
|
// A page without structured data still renders. A page that fails to
|
||||||
|
// render because our backend is slow does not.
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (!p?.businessName) return null
|
||||||
|
|
||||||
|
const data: Record<string, unknown> = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': p.schemaType || 'LocalBusiness',
|
||||||
|
name: p.businessName,
|
||||||
|
}
|
||||||
|
if (p.phone) data.telephone = p.phone
|
||||||
|
if (p.email) data.email = p.email
|
||||||
|
// sameAs is how Google ties this site to her Facebook and Instagram pages —
|
||||||
|
// the same entity match that decides whether she appears in the map listing.
|
||||||
|
if (p.socials?.length) data.sameAs = p.socials.map((s) => s.url)
|
||||||
|
if (p.address) {
|
||||||
|
data.address = {
|
||||||
|
'@type': 'PostalAddress',
|
||||||
|
streetAddress: p.address.street,
|
||||||
|
addressLocality: p.address.locality,
|
||||||
|
...(p.address.region ? { addressRegion: p.address.region } : {}),
|
||||||
|
...(p.address.postalCode ? { postalCode: p.address.postalCode } : {}),
|
||||||
|
addressCountry: p.address.country || 'ZA',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
// The value is JSON we built ourselves from her own fields, never markup.
|
||||||
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(data).replace(/</g, '\\u003c') }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user