type MediaLike = { url?: null | string } | null | undefined type Address = { city?: string country?: string // ISO code, e.g. 'PL' postalCode?: string region?: string street?: string } type LocalBusinessJsonLdArgs = { address?: Address /** Geo coordinates for maps/local search. */ geo?: { latitude: number; longitude: number } image?: MediaLike logo?: MediaLike name: string /** Opening hours, e.g. ['Mo-Fr 08:00-18:00', 'Sa 09:00-14:00']. */ openingHours?: string[] priceRange?: string // e.g. '$$' sameAs?: string[] /** Business phone, e.g. '+48 123 456 789'. */ telephone?: string url: string } /** * Builds LocalBusiness JSON-LD (schema.org) — the key structured data for LOCAL * SEO. Helps Google show the business in local results / map pack with address, * hours, phone. Strong signal for "usługa + miasto" queries. * * All data from the panel (company global) — nothing hardcoded. Emit once in the * root layout (business is site-wide): * * import { buildLocalBusinessJsonLd } from '@intecion/ipal-kit' * const jsonLd = buildLocalBusinessJsonLd({ * name: company.name, url: baseUrl, telephone: company.phone, * address: company.address, openingHours: company.hours, * }) * * For a more specific type (e.g. 'Dentist', 'Plumber'), override @type in the * returned object — schema.org has many LocalBusiness subtypes. */ export function buildLocalBusinessJsonLd({ name, address, geo, image, logo, openingHours, priceRange, sameAs, telephone, url, }: LocalBusinessJsonLdArgs) { const logoUrl = logo?.url const imageUrl = image?.url ?? logoUrl return { name, '@context': 'https://schema.org', '@type': 'LocalBusiness', url, ...(telephone ? { telephone } : {}), ...(imageUrl ? { image: imageUrl.startsWith('http') ? imageUrl : `${url}${imageUrl}` } : {}), ...(logoUrl ? { logo: logoUrl.startsWith('http') ? logoUrl : `${url}${logoUrl}` } : {}), ...(address ? { address: { '@type': 'PostalAddress', ...(address.street ? { streetAddress: address.street } : {}), ...(address.city ? { addressLocality: address.city } : {}), ...(address.postalCode ? { postalCode: address.postalCode } : {}), ...(address.region ? { addressRegion: address.region } : {}), ...(address.country ? { addressCountry: address.country } : {}), }, } : {}), ...(geo ? { geo: { '@type': 'GeoCoordinates', latitude: geo.latitude, longitude: geo.longitude } } : {}), ...(openingHours && openingHours.length > 0 ? { openingHours } : {}), ...(priceRange ? { priceRange } : {}), ...(sameAs && sameAs.length > 0 ? { sameAs } : {}), } }