Snapshot of uncommitted work: landing, bots, prod infra, partner cabinet, backoffice stage 1
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
45d7512d2b
commit
d452824c62
314 files changed
+44394
-121
No files matched your search
@@ -0,0 +1,14 @@
|
||||
import { createT, isLocale, LOCALES } from '@barev/i18n';
|
||||
import { OG_SIZE, ogImage } from '../../../lib/og';
|
||||
|
||||
export const size = OG_SIZE;
|
||||
export const contentType = 'image/png';
|
||||
export function generateStaticParams() {
|
||||
return LOCALES.map((locale) => ({ locale }));
|
||||
}
|
||||
|
||||
/** OG-картинка «Уже живу в Армении» */
|
||||
export default async function OgImage({ params }: { params: Promise<{ locale: string }> }) {
|
||||
const { locale } = await params;
|
||||
return ogImage(createT(isLocale(locale) ? locale : 'ru')('landing.live.title'));
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import '../../variants.css';
|
||||
import '../../home.css';
|
||||
import { createT, formatAmd, isLocale, LOCALES, type Locale } from '@barev/i18n';
|
||||
import type { Viewport } from 'next';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { BotLink, BotLinkProvider } from '../../../components/client';
|
||||
import { AudienceSwitch, ClubPlans, HomeFooter, homeMetadata } from '../../../components/home';
|
||||
import { ClubJsonLd } from '../../../components/seo';
|
||||
import { VariantHeader } from '../../../components/variant';
|
||||
import { getCatalog } from '../../../lib/data';
|
||||
|
||||
export const revalidate = 300;
|
||||
export const dynamicParams = false;
|
||||
export function generateStaticParams() {
|
||||
return LOCALES.map((locale) => ({ locale }));
|
||||
}
|
||||
export function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
|
||||
return homeMetadata(params, '/live');
|
||||
}
|
||||
export const viewport: Viewport = { themeColor: '#4A1028' };
|
||||
|
||||
/**
|
||||
* Прайс по подписке: клининг можно заказать сразу, трансфер — со скидкой Elite, документы — «от N ֏»,
|
||||
* остальное пока «скоро».
|
||||
*/
|
||||
const ITEMS = [
|
||||
{ key: 'cleaning', value: 'order' },
|
||||
{ key: 'repair', value: 'soon' },
|
||||
{ key: 'transfer', value: 'pct' },
|
||||
{ key: 'tours', value: 'soon' },
|
||||
{ key: 'docs', value: 'from' },
|
||||
{ key: 'lang', value: 'soon' },
|
||||
{ key: 'career', value: 'soon' },
|
||||
{ key: 'partners', value: 'soon' },
|
||||
] as const;
|
||||
|
||||
/** Версия главной «Уже живу в Армении»: что даёт подписка — скидки по направлениям и тарифы */
|
||||
export default async function Live({ params }: { params: Promise<{ locale: string }> }) {
|
||||
const { locale: raw } = await params;
|
||||
if (!isLocale(raw)) notFound();
|
||||
const locale: Locale = raw;
|
||||
const t = createT(locale);
|
||||
const catalog = await getCatalog();
|
||||
|
||||
return (
|
||||
<BotLinkProvider locale={locale} bot={catalog.botUsername}>
|
||||
<div className="v2">
|
||||
<ClubJsonLd locale={locale} path="/live" bot={catalog.botUsername} plusPrice={catalog.barevPlus.monthlyPrice} offer={catalog.offer} />
|
||||
<div className="v-wrap">
|
||||
<VariantHeader locale={locale} path="/live" className="vh--dark" logoColor="#F6C3D3" />
|
||||
<AudienceSwitch locale={locale} current="live" />
|
||||
|
||||
<section className="v2-hero">
|
||||
<div className="v2-word" aria-hidden="true">
|
||||
Barev
|
||||
</div>
|
||||
<ul className="v2-hello" aria-hidden="true">
|
||||
{t('landing.v2.hello')
|
||||
.split('\n')
|
||||
.map((h) => (
|
||||
<li key={h}>{h}</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="v2-hero__text">
|
||||
<h1 className="v2-title">{t('landing.live.title')}</h1>
|
||||
<div className="h-hero__side">
|
||||
<p className="v2-sub">{t('landing.live.sub')}</p>
|
||||
<div className="h-actions">
|
||||
<BotLink className="bc-btn h-cta">{t('landing.live.cta')}</BotLink>
|
||||
<a href="#plans" className="bc-btn h-cta-ghost">
|
||||
{t('landing.live.ctaPlans')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="discounts" className="h-price" aria-labelledby="discounts-title">
|
||||
<div className="h-section-head">
|
||||
<h2 id="discounts-title">{t('landing.live.listTitle')}</h2>
|
||||
<p>{t('landing.live.listNote', { pct: catalog.offer.plusMaxPct })}</p>
|
||||
</div>
|
||||
<ul className="h-price__list">
|
||||
{ITEMS.map((it) => (
|
||||
<li key={it.key} className="h-price__row" data-kind={it.value}>
|
||||
<b className="h-price__name">{t(`landing.live.${it.key}`)}</b>
|
||||
<span className="h-price__dots" aria-hidden="true" />
|
||||
{it.value === 'order' ? (
|
||||
<a href={`/${locale}/clean`} className="bc-btn h-price__order">
|
||||
{t('landing.live.orderNow')}
|
||||
</a>
|
||||
) : (
|
||||
<span className="h-price__value">
|
||||
{it.value === 'pct'
|
||||
? t('landing.live.upTo', { pct: catalog.offer.eliteMaxPct })
|
||||
: it.value === 'from'
|
||||
? t('landing.live.docsFrom', { price: formatAmd(locale, catalog.offer.docsFrom) })
|
||||
: t('common.soon')}
|
||||
</span>
|
||||
)}
|
||||
<small className="h-price__hint">{t(`landing.live.${it.key}Hint`)}</small>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<ClubPlans locale={locale} plusPrice={catalog.barevPlus.monthlyPrice} offer={catalog.offer} />
|
||||
|
||||
<section className="v2-final">
|
||||
<div>
|
||||
<h2>{t('landing.live.finalTitle')}</h2>
|
||||
<p>{t('landing.live.finalText')}</p>
|
||||
</div>
|
||||
<BotLink className="bc-btn v2-final__cta">{t('landing.live.cta')}</BotLink>
|
||||
</section>
|
||||
|
||||
<HomeFooter locale={locale} />
|
||||
</div>
|
||||
</div>
|
||||
</BotLinkProvider>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user