Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
81 lines
3.6 KiB
TypeScript
81 lines
3.6 KiB
TypeScript
import { createT, LOCALES, type Locale } from '@barev/i18n';
|
|
import type { LandingOffer } from '../lib/data';
|
|
import { CONTACTS, SITE } from '../lib/seo';
|
|
|
|
/** Телефон и почта для подвала: видны текстом, чтобы их могли прочитать люди, поисковики и ИИ */
|
|
export function FooterContacts() {
|
|
return (
|
|
<>
|
|
<a href={`tel:${CONTACTS.phone}`}>{CONTACTS.phoneDisplay}</a>
|
|
<a href={`mailto:${CONTACTS.email}`}>{CONTACTS.email}</a>
|
|
</>
|
|
);
|
|
}
|
|
|
|
/** Строка с реквизитами ИП — сигнал доверия для клиентов и E-E-A-T для Google */
|
|
export function LegalLine({ locale, className }: { locale: Locale; className?: string }) {
|
|
return <small className={className}>{createT(locale)('landing.footer.legal', { tin: CONTACTS.tin })}</small>;
|
|
}
|
|
|
|
/**
|
|
* Структурированные данные (JSON-LD) для Google и ИИ-поиска: кто мы, где работаем, на каких языках
|
|
* и сколько стоит подписка. Цены берутся из настроек админки, как и на самой странице.
|
|
*/
|
|
export function ClubJsonLd({ locale, path, bot, plusPrice, offer }: { locale: Locale; path: '' | '/live'; bot: string; plusPrice: number; offer: LandingOffer }) {
|
|
const t = createT(locale);
|
|
const org = `${SITE}/#org`;
|
|
const telegram = `https://t.me/${bot}`;
|
|
const { email, phone: telephone } = CONTACTS;
|
|
const plan = (name: string, price: number) => ({
|
|
'@type': 'Offer',
|
|
name,
|
|
price,
|
|
priceCurrency: 'AMD',
|
|
...(price > 0 && { priceSpecification: { '@type': 'UnitPriceSpecification', price, priceCurrency: 'AMD', unitCode: 'MON' } }),
|
|
url: `${SITE}/${locale}${path}#plans`,
|
|
});
|
|
const data = {
|
|
'@context': 'https://schema.org',
|
|
'@graph': [
|
|
{
|
|
'@type': 'Organization',
|
|
'@id': org,
|
|
name: 'Barev Club',
|
|
legalName: CONTACTS.legalName,
|
|
taxID: CONTACTS.tin,
|
|
url: SITE,
|
|
logo: `${SITE}/apple-icon`,
|
|
description: t('landing.seo.org'),
|
|
sameAs: [telegram],
|
|
email,
|
|
telephone,
|
|
address: { '@type': 'PostalAddress', addressLocality: 'Yerevan', addressCountry: 'AM' },
|
|
contactPoint: { '@type': 'ContactPoint', contactType: 'customer support', url: telegram, telephone, email, availableLanguage: [...LOCALES] },
|
|
},
|
|
{
|
|
'@type': 'ProfessionalService',
|
|
'@id': `${SITE}/#service`,
|
|
name: 'Barev Club',
|
|
url: `${SITE}/${locale}`,
|
|
image: `${SITE}/${locale}${path}/opengraph-image`,
|
|
description: t('landing.seo.org'),
|
|
parentOrganization: { '@id': org },
|
|
telephone,
|
|
email,
|
|
address: { '@type': 'PostalAddress', addressLocality: 'Yerevan', addressCountry: 'AM' },
|
|
areaServed: { '@type': 'City', name: 'Yerevan' },
|
|
availableLanguage: [...LOCALES],
|
|
currenciesAccepted: 'AMD',
|
|
hasOfferCatalog: {
|
|
'@type': 'OfferCatalog',
|
|
name: t('landing.club.title'),
|
|
itemListElement: [plan('Barev', 0), plan('Barev+', plusPrice), plan('Barev Elite', offer.elitePrice)],
|
|
},
|
|
},
|
|
{ '@type': 'WebSite', '@id': `${SITE}/#website`, url: SITE, name: 'Barev Club', inLanguage: locale, publisher: { '@id': org } },
|
|
],
|
|
};
|
|
// «<» экранируем, чтобы текст из настроек не мог закрыть тег script
|
|
return <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(data).replace(/</g, '\\u003c') }} />;
|
|
}
|