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,122 @@
|
||||
import '../../clean.css';
|
||||
import { createT, isLocale, LOCALES, pickMessages, type Locale } from '@barev/i18n';
|
||||
import { Logo } from '@barev/ui';
|
||||
import type { Metadata } from 'next';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { CleanForm } from '../../../components/clean';
|
||||
import { FooterContacts, LegalLine } from '../../../components/seo';
|
||||
import { BotLink, BotLinkProvider, LangMenu, LangSwitch } from '../../../components/client';
|
||||
import { getCleaning } from '../../../lib/data';
|
||||
|
||||
export const revalidate = 300;
|
||||
export const dynamicParams = false;
|
||||
export function generateStaticParams() {
|
||||
return LOCALES.map((locale) => ({ locale }));
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise<Metadata> {
|
||||
const { locale } = await params;
|
||||
if (!isLocale(locale)) return {};
|
||||
const t = createT(locale);
|
||||
return {
|
||||
title: t('landing.clean.meta.title'),
|
||||
description: t('landing.clean.meta.description'),
|
||||
alternates: {
|
||||
canonical: `/${locale}/clean`,
|
||||
languages: Object.fromEntries([...LOCALES.map((l) => [l, `/${l}/clean`]), ['x-default', '/ru/clean']]),
|
||||
},
|
||||
openGraph: { title: t('landing.clean.meta.title'), description: t('landing.clean.meta.description'), locale, type: 'website', siteName: 'Barev Club' },
|
||||
};
|
||||
}
|
||||
|
||||
const ZONES = ['kitchen', 'bathroom', 'rooms'] as const;
|
||||
|
||||
/** barevclub.com/clean — заказ уборки с сайта по модели qlean.ru */
|
||||
export default async function CleanPage({ params }: { params: Promise<{ locale: string }> }) {
|
||||
const { locale: raw } = await params;
|
||||
if (!isLocale(raw)) notFound();
|
||||
const locale: Locale = raw;
|
||||
const t = createT(locale);
|
||||
const config = await getCleaning();
|
||||
const messages = pickMessages(locale, ['landing.clean.', 'params.cleaning.', 'extras.', 'districts.', 'errors.', 'common.']);
|
||||
|
||||
return (
|
||||
<BotLinkProvider locale={locale} bot={config.botUsername}>
|
||||
<div className="wrap cl-wrap">
|
||||
<header className="header">
|
||||
<a href={`/${locale}`} aria-label={t('landing.clean.home')} style={{ display: 'inline-flex' }}>
|
||||
<Logo />
|
||||
</a>
|
||||
<nav className="nav" aria-label={t('landing.nav.label')}>
|
||||
<a href={`/${locale}`}>{t('landing.clean.home')}</a>
|
||||
<a href="#included">{t('landing.clean.includedTitle')}</a>
|
||||
<a href="#how">{t('landing.clean.howTitle')}</a>
|
||||
</nav>
|
||||
<div className="langs">
|
||||
<span className="langs__row">
|
||||
<LangSwitch current={locale} path="/clean" />
|
||||
</span>
|
||||
<LangMenu current={locale} path="/clean" />
|
||||
<BotLink className="bc-btn bc-btn--dark bc-btn--sm" style={{ marginLeft: 6 }}>
|
||||
<span className="tg-long">{t('landing.openTelegram')}</span>
|
||||
<span className="tg-short">Telegram</span>
|
||||
</BotLink>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<CleanForm locale={locale} config={config} messages={messages} />
|
||||
|
||||
<section id="included" className="cl-included">
|
||||
<h2 className="cl-section-title">{t('landing.clean.includedTitle')}</h2>
|
||||
<div className="cl-zones">
|
||||
{ZONES.map((z) => (
|
||||
<div key={z} className="cl-zone">
|
||||
<h3>{t(`landing.clean.zone.${z}`)}</h3>
|
||||
<ul>
|
||||
{t(`landing.clean.inc.${z}`)
|
||||
.split('\n')
|
||||
.map((line) => (
|
||||
<li key={line}>{line}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="cl-variants">
|
||||
<p>{t('landing.clean.general')}</p>
|
||||
<p>{t('landing.clean.renovation')}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="how" className="how cl-how">
|
||||
<h2 className="bc-h2" style={{ fontSize: 34 }}>
|
||||
{t('landing.clean.howTitle')}
|
||||
</h2>
|
||||
<ol className="cl-how__grid">
|
||||
{([1, 2, 3] as const).map((n) => (
|
||||
<li key={n} className="how__step">
|
||||
<div className="how__num" style={{ background: n === 1 ? 'var(--bc-home)' : n === 2 ? 'var(--bc-blue)' : 'var(--bc-pink)', color: 'var(--bc-ink)' }}>
|
||||
{n}
|
||||
</div>
|
||||
<div style={{ fontWeight: 600 }}>{t(`landing.clean.how${n}`)}</div>
|
||||
<div style={{ fontSize: 13, color: '#CFC8C2' }}>{t(`landing.clean.how${n}Sub`)}</div>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<footer className="footer">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
|
||||
<span style={{ fontFamily: 'var(--bc-font-head)', fontWeight: 700, color: 'var(--bc-plum)' }}>{t('landing.footer.brand')}</span>
|
||||
<LegalLine locale={locale} />
|
||||
</div>
|
||||
<div className="footer__links">
|
||||
<a href={`/${locale}`}>{t('landing.clean.home')}</a>
|
||||
<FooterContacts />
|
||||
<a href={`/${locale}/privacy`}>{t('landing.footer.privacy')}</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</BotLinkProvider>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user