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,144 @@
|
||||
import '../variants.css';
|
||||
import '../home.css';
|
||||
import { createT, formatAmd, isLocale, LOCALES, pickMessages, 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 { QuizButton, QuizProvider } from '../../components/quiz';
|
||||
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, '');
|
||||
}
|
||||
export const viewport: Viewport = { themeColor: '#4A1028' };
|
||||
|
||||
/** Шаги переезда: когда, что делаем и короткий факт (цена или срок) справа */
|
||||
const STEPS = ['airport', 'flat', 'docs', 'permit', 'perks', 'chat'] as const;
|
||||
const WHEN: Record<(typeof STEPS)[number], string> = {
|
||||
airport: 'whenArrive',
|
||||
flat: 'whenFirst',
|
||||
docs: 'whenSettled',
|
||||
permit: 'whenLater',
|
||||
perks: 'whenDaily',
|
||||
chat: 'whenAnytime',
|
||||
};
|
||||
|
||||
/** Шаги таймлайна со своей страницей услуги — заголовок шага ведёт на неё */
|
||||
const LINKS: Partial<Record<(typeof STEPS)[number], string>> = { airport: '/airport', docs: '/social-card', permit: '/residence-permit' };
|
||||
|
||||
/**
|
||||
* Главная «Переезжаю»: огромное «Barev», таймлайн от аэропорта до ВНЖ, тарифы клуба и квиз-подбор.
|
||||
* Версия для тех, кто уже живёт в Армении, — /live.
|
||||
*/
|
||||
export default async function Home({ params }: { params: Promise<{ locale: string }> }) {
|
||||
const { locale: raw } = await params;
|
||||
if (!isLocale(raw)) notFound();
|
||||
const locale: Locale = raw;
|
||||
const t = createT(locale);
|
||||
const amd = (n: number) => formatAmd(locale, n);
|
||||
const catalog = await getCatalog();
|
||||
const messages = pickMessages(locale, ['landing.quiz.', 'errors.']);
|
||||
|
||||
const meta = (key: (typeof STEPS)[number]) => {
|
||||
switch (key) {
|
||||
case 'airport':
|
||||
return null;
|
||||
case 'flat':
|
||||
return null;
|
||||
case 'docs':
|
||||
return null;
|
||||
case 'permit':
|
||||
return null;
|
||||
case 'perks':
|
||||
// скидки партнёров ещё не запущены — вместо ссылки плашка «Скоро» в стиле «Подробнее»
|
||||
return (
|
||||
<span className="bc-btn h-more h-more--soon" aria-disabled="true">
|
||||
{t('landing.home.perksSoon')}
|
||||
</span>
|
||||
);
|
||||
case 'chat':
|
||||
return <BotLink className="bc-btn v2-btn">{t('landing.home.chatCta')}</BotLink>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<BotLinkProvider locale={locale} bot={catalog.botUsername}>
|
||||
<QuizProvider locale={locale} messages={messages} consultPrice={amd(catalog.offer.consultation)}>
|
||||
<div className="v2">
|
||||
<ClubJsonLd locale={locale} path="" bot={catalog.botUsername} plusPrice={catalog.barevPlus.monthlyPrice} offer={catalog.offer} />
|
||||
<div className="v-wrap">
|
||||
<VariantHeader locale={locale} path="" className="vh--dark" logoColor="#F6C3D3" />
|
||||
<AudienceSwitch locale={locale} current="move" />
|
||||
|
||||
<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.home.title')}</h1>
|
||||
<div className="h-hero__side">
|
||||
<p className="v2-sub">{t('landing.home.sub')}</p>
|
||||
<div className="h-actions">
|
||||
<QuizButton className="bc-btn h-cta">{t('landing.home.cta')}</QuizButton>
|
||||
<BotLink className="bc-btn h-cta-ghost">{t('landing.home.ctaChat')}</BotLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<ol className="v2-line">
|
||||
{STEPS.map((key) => {
|
||||
// квартиры (/apartments) пока есть только на русском
|
||||
const link = key === 'flat' ? (locale === 'ru' ? '/apartments' : undefined) : LINKS[key];
|
||||
return (
|
||||
<li key={key} className="v2-step" data-live={key === 'airport' || key === 'chat' || Boolean(link && key === 'flat')}>
|
||||
<div className="v2-step__when">{t(`landing.home.${WHEN[key]}`)}</div>
|
||||
<div className="v2-step__body">
|
||||
<h2>{link ? <a href={`/${locale}${link}`}>{t(`landing.home.${key}Title`)}</a> : t(`landing.home.${key}Title`)}</h2>
|
||||
<p>{t(`landing.home.${key}Text`)}</p>
|
||||
</div>
|
||||
<div className="v2-step__meta">
|
||||
{meta(key)}
|
||||
{link && (
|
||||
<a href={`/${locale}${link}`} className="bc-btn h-more">
|
||||
{t('landing.home.more')} →
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ol>
|
||||
|
||||
<ClubPlans locale={locale} plusPrice={catalog.barevPlus.monthlyPrice} offer={catalog.offer} />
|
||||
|
||||
<section className="v2-final">
|
||||
<div>
|
||||
<h2>{t('landing.home.finalTitle')}</h2>
|
||||
<p>{t('landing.home.finalText')}</p>
|
||||
</div>
|
||||
<QuizButton className="bc-btn v2-final__cta">{t('landing.home.cta')}</QuizButton>
|
||||
</section>
|
||||
|
||||
<HomeFooter locale={locale} />
|
||||
</div>
|
||||
</div>
|
||||
</QuizProvider>
|
||||
</BotLinkProvider>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user