245 lines
7.5 KiB
TypeScript
245 lines
7.5 KiB
TypeScript
/**
|
||
* Structured Data (JSON-LD) Generators for Canina Iran
|
||
* Conforming to Schema.org and Google Search Rich Results guidelines
|
||
*/
|
||
|
||
export interface OrganizationSchemaOptions {
|
||
name?: string;
|
||
alternateName?: string;
|
||
url?: string;
|
||
logo?: string;
|
||
description?: string;
|
||
telephone?: string;
|
||
email?: string;
|
||
address?: {
|
||
streetAddress?: string;
|
||
addressLocality?: string;
|
||
addressRegion?: string;
|
||
postalCode?: string;
|
||
addressCountry?: string;
|
||
};
|
||
sameAs?: string[];
|
||
}
|
||
|
||
export function generateOrganizationSchema(options: OrganizationSchemaOptions = {}) {
|
||
const brandName = options.name || 'کنینا ایران';
|
||
const siteUrl = options.url || 'https://canina.ir';
|
||
const logoUrl = options.logo || `${siteUrl}/assets/images/logo.png`;
|
||
|
||
return {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'Organization',
|
||
'@id': `${siteUrl}#organization`,
|
||
name: brandName,
|
||
alternateName: options.alternateName || 'Canina pharma GmbH Iran Representative',
|
||
url: siteUrl,
|
||
logo: {
|
||
'@type': 'ImageObject',
|
||
url: logoUrl,
|
||
caption: brandName,
|
||
},
|
||
image: logoUrl,
|
||
description:
|
||
options.description ||
|
||
'نماینده رسمی و انحصاری مکملهای دارویی و درمانی Canina pharma GmbH آلمان در ایران.',
|
||
telephone: options.telephone || '+989211231517',
|
||
email: options.email || 'caninairan@gmail.com',
|
||
address: {
|
||
'@type': 'PostalAddress',
|
||
streetAddress: options.address?.streetAddress || 'جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵',
|
||
addressLocality: options.address?.addressLocality || 'تهران',
|
||
addressRegion: options.address?.addressRegion || 'تهران',
|
||
postalCode: options.address?.postalCode || '1967812345',
|
||
addressCountry: options.address?.addressCountry || 'IR',
|
||
},
|
||
sameAs: options.sameAs || [
|
||
'https://instagram.com/caninairan',
|
||
'https://t.me/caninairan',
|
||
'https://www.canina.de',
|
||
],
|
||
contactPoint: [
|
||
{
|
||
'@type': 'ContactPoint',
|
||
telephone: options.telephone || '+989211231517',
|
||
contactType: 'customer service',
|
||
availableLanguage: ['Persian', 'English', 'German'],
|
||
areaServed: 'IR',
|
||
},
|
||
],
|
||
};
|
||
}
|
||
|
||
export function generateLocalBusinessSchema(options: OrganizationSchemaOptions = {}) {
|
||
const siteUrl = options.url || 'https://canina.ir';
|
||
const brandName = options.name || 'کنینا ایران';
|
||
const logoUrl = options.logo || `${siteUrl}/assets/images/logo.png`;
|
||
|
||
return {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'VeterinaryCare',
|
||
'@id': `${siteUrl}#localbusiness`,
|
||
name: `${brandName} - دفتر مرکزی و پشتیبانی تخصصی`,
|
||
image: logoUrl,
|
||
url: siteUrl,
|
||
telephone: options.telephone || '+989211231517',
|
||
priceRange: '$$',
|
||
address: {
|
||
'@type': 'PostalAddress',
|
||
streetAddress: options.address?.streetAddress || 'تهران، جردن، خیابان سعیدی، ساختمان کنینا، طبقه ۵، واحد ۱۹',
|
||
addressLocality: options.address?.addressLocality || 'تهران',
|
||
addressRegion: options.address?.addressRegion || 'تهران',
|
||
postalCode: options.address?.postalCode || '1967812345',
|
||
addressCountry: 'IR',
|
||
},
|
||
geo: {
|
||
'@type': 'GeoCoordinates',
|
||
latitude: 35.7785,
|
||
longitude: 51.4172,
|
||
},
|
||
openingHoursSpecification: [
|
||
{
|
||
'@type': 'OpeningHoursSpecification',
|
||
dayOfWeek: ['Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday'],
|
||
opens: '09:00',
|
||
closes: '18:00',
|
||
},
|
||
],
|
||
sameAs: options.sameAs || [
|
||
'https://instagram.com/caninairan',
|
||
'https://t.me/caninairan',
|
||
],
|
||
};
|
||
}
|
||
|
||
export interface B2BServiceSchemaOptions {
|
||
serviceName?: string;
|
||
description?: string;
|
||
siteUrl?: string;
|
||
}
|
||
|
||
export function generateB2BServiceSchema(options: B2BServiceSchemaOptions = {}) {
|
||
const siteUrl = options.siteUrl || 'https://canina.ir';
|
||
return {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'Service',
|
||
'@id': `${siteUrl}/b2b#service`,
|
||
name: options.serviceName || 'تأمین عمده و همکاری تجاری مکملهای دارویی کنینا آلمان',
|
||
serviceType: 'B2B Veterinary Supply & Wholesale',
|
||
provider: {
|
||
'@type': 'Organization',
|
||
name: 'کنینا ایران',
|
||
url: siteUrl,
|
||
logo: `${siteUrl}/assets/images/logo.png`,
|
||
},
|
||
areaServed: {
|
||
'@type': 'Country',
|
||
name: 'Iran',
|
||
},
|
||
description:
|
||
options.description ||
|
||
'تأمین مستقیم، پخش عمده و اعطای نمایندگی مکملهای تخصصی دامپزشکی Canina آلمان به کلینیکها، بیمارستانهای دامپزشکی و پتشاپهای معتبر سراسر کشور.',
|
||
offers: {
|
||
'@type': 'Offer',
|
||
availability: 'https://schema.org/InStock',
|
||
businessFunction: 'http://purl.org/goodrelations/v1#ProvideService',
|
||
},
|
||
};
|
||
}
|
||
|
||
export interface MedicalWebPageSchemaOptions {
|
||
title: string;
|
||
description: string;
|
||
url: string;
|
||
datePublished?: string;
|
||
dateModified?: string;
|
||
medicalAudience?: string;
|
||
aspects?: string[];
|
||
}
|
||
|
||
export function generateMedicalWebPageSchema(options: MedicalWebPageSchemaOptions) {
|
||
return {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'MedicalWebPage',
|
||
name: options.title,
|
||
headline: options.title,
|
||
description: options.description,
|
||
url: options.url,
|
||
datePublished: options.datePublished || '2025-01-01',
|
||
dateModified: options.dateModified || new Date().toISOString(),
|
||
medicalAudience: {
|
||
'@type': 'MedicalAudience',
|
||
audienceType: options.medicalAudience || 'Veterinarians, Pet Care Professionals, and Pet Owners',
|
||
},
|
||
publisher: {
|
||
'@type': 'Organization',
|
||
name: 'کنینا ایران',
|
||
url: 'https://canina.ir',
|
||
},
|
||
about: options.aspects?.map((aspect) => ({
|
||
'@type': 'MedicalCondition',
|
||
name: aspect,
|
||
})) || [],
|
||
};
|
||
}
|
||
|
||
export interface VideoObjectSchemaOptions {
|
||
name: string;
|
||
description: string;
|
||
thumbnailUrl: string;
|
||
uploadDate: string;
|
||
contentUrl?: string;
|
||
embedUrl?: string;
|
||
duration?: string;
|
||
}
|
||
|
||
export function generateVideoObjectSchema(options: VideoObjectSchemaOptions) {
|
||
return {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'VideoObject',
|
||
name: options.name,
|
||
description: options.description,
|
||
thumbnailUrl: [options.thumbnailUrl],
|
||
uploadDate: options.uploadDate,
|
||
contentUrl: options.contentUrl,
|
||
embedUrl: options.embedUrl || options.contentUrl,
|
||
duration: options.duration || 'PT3M30S',
|
||
publisher: {
|
||
'@type': 'Organization',
|
||
name: 'کنینا ایران',
|
||
logo: {
|
||
'@type': 'ImageObject',
|
||
url: 'https://canina.ir/assets/images/logo.png',
|
||
},
|
||
},
|
||
};
|
||
}
|
||
|
||
export interface BreadcrumbItem {
|
||
name: string;
|
||
url: string;
|
||
}
|
||
|
||
export function generateBreadcrumbSchema(items: BreadcrumbItem[]) {
|
||
return {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'BreadcrumbList',
|
||
itemListElement: items.map((item, index) => ({
|
||
'@type': 'ListItem',
|
||
position: index + 1,
|
||
name: item.name,
|
||
item: item.url,
|
||
})),
|
||
};
|
||
}
|
||
|
||
/**
|
||
* SEC-017: Safely serialize schema data to JSON string for application/ld+json script tags,
|
||
* escaping any '</script>' or '<' characters that could break out of the script block.
|
||
*/
|
||
export function safeJsonLd(schema: unknown): string {
|
||
return JSON.stringify(schema)
|
||
.replace(/</g, '\\u003c')
|
||
.replace(/>/g, '\\u003e')
|
||
.replace(/&/g, '\\u0026');
|
||
}
|