All files / src/lib/seo city-service-schema.ts

100% Statements 4/4
87.5% Branches 7/8
100% Functions 1/1
100% Lines 4/4

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49                                              10x 10x 10x 10x                                            
/**
 * ProfessionalService JSON-LD for a city hub (#1118). One node per hub at
 * `{hub}#service`, linked to the homepage Organization through
 * `parentOrganization`. Address and phone are always the company's — never
 * a local office.
 */
import { BRAND, BRAND_POSTAL_ADDRESS } from "../content/brand";
import { wikidataSameAs } from "./live-city";
 
export type CityServiceSchemaInput = {
	siteUrl: string;
	slug: string;
	publicName: string;
	wikidataId: string | null | undefined;
	pricesApproved: boolean;
	description: string;
	aggregateRating?: Record<string, unknown> | null;
	dateModified?: string;
};
 
export function cityServiceSchema(
	input: CityServiceSchemaInput,
): Record<string, unknown> {
	const origin = input.siteUrl.replace(/\/$/, "");
	const hubUrl = `${origin}/interiors/${input.slug}`;
	const sameAs = wikidataSameAs(input.wikidataId);
	return {
		"@context": "https://schema.org",
		"@type": "ProfessionalService",
		"@id": `${hubUrl}#service`,
		name: `Interioring — Interior Designers in ${input.publicName}`,
		url: hubUrl,
		parentOrganization: { "@id": `${origin}#organization` },
		address: BRAND_POSTAL_ADDRESS,
		telephone: BRAND.phone,
		areaServed: {
			"@type": "City",
			name: input.publicName,
			...(sameAs ? { sameAs } : {}),
		},
		...(input.pricesApproved ? { priceRange: "₹₹₹" } : {}),
		description: input.description,
		dateModified: input.dateModified ?? new Date().toISOString(),
		...(input.aggregateRating
			? { aggregateRating: input.aggregateRating }
			: {}),
	};
}