Files
BarevClub/apps/landing/app/[locale]/pricing/page.tsx
T
2026-10-25 22:57:03 +04:00

118 lines
4.7 KiB
TypeScript

import { createT, formatAmd, isLocale, LOCALES, type Locale } from '@barev/i18n';
import { Icon } from '@barev/ui';
import { notFound } from 'next/navigation';
import { LegalShell, legalMetadata } from '../../../components/legal';
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 legalMetadata(params, 'pricing');
}
interface Row {
id: string;
price: string;
vars?: Record<string, string>;
href?: string;
}
/**
* Цены: подписки клуба и услуги, которые сейчас продаются. Все суммы — из настроек админки
* (как на главной и страницах услуг), поэтому страница не расходится с ботом.
*/
export default async function Pricing({ 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 { offer, barevPlus, categories } = await getCatalog();
const cleaning = categories.find((c) => c.code === 'HOME')?.services.find((s) => s.code === 'cleaning')?.fromPrice ?? 0;
const from = (n: number) => t('pricing.from', { price: amd(n) });
const plans = [
{ id: 'free', name: 'Barev', price: t('landing.club.free'), pct: 0 },
{ id: 'plus', name: 'Barev+', price: t('landing.club.perMonth', { price: amd(barevPlus.monthlyPrice) }), pct: offer.plusMaxPct },
{ id: 'elite', name: 'Barev Elite', price: t('landing.club.perMonth', { price: amd(offer.elitePrice) }), pct: offer.eliteMaxPct },
] as const;
const groups: { id: 'HOME' | 'DOCS'; rows: Row[] }[] = [
{
id: 'HOME',
rows: [
{ id: 'cleaning', price: from(cleaning), href: '/clean' },
{ id: 'transferStandard', price: amd(offer.transferStandard), href: '/airport' },
{ id: 'transferPremium', price: amd(offer.transferPremium), href: '/airport' },
{ id: 'hotel', price: t('pricing.perDay', { price: from(offer.hotelWithPlus) }), vars: { base: amd(offer.hotelBase) } },
],
},
{
id: 'DOCS',
rows: [
{ id: 'socialCard', price: amd(offer.socialCard), href: '/social-card' },
{ id: 'consultation', price: amd(offer.consultation), href: '/residence-permit' },
{ id: 'residence', price: from(offer.residenceEscortFrom), vars: { fee: amd(offer.residenceStateFee) }, href: '/residence-permit' },
],
},
];
return (
<LegalShell locale={locale} page="pricing">
<section className="policy__section" id="plans">
<h2>{t('pricing.plansTitle')}</h2>
<p>{t('pricing.plansNote')}</p>
<div className="pr-plans">
{plans.map((p) => (
<article key={p.id} className="pr-plan" data-plan={p.id}>
<h3>{p.name}</h3>
<span className="pr-plan__price">{p.price}</span>
<ul>
{[1, 2, 3].map((n) => (
<li key={n}>
<Icon name="check" size={16} strokeWidth={2.6} />
{t(`landing.club.${p.id}F${n}`, { pct: p.pct })}
</li>
))}
</ul>
<small>{t(`pricing.planNote.${p.id}`, { days: barevPlus.giftDays })}</small>
</article>
))}
</div>
</section>
<section className="policy__section" id="services">
<h2>{t('pricing.servicesTitle')}</h2>
<p>{t('pricing.servicesNote')}</p>
{groups.map((g) => (
<div key={g.id} className="pr-group">
<h3>{t(`categories.${g.id}.name`)}</h3>
<dl className="pr-list">
{g.rows.map((r) => (
<div key={r.id} className="pr-row">
<dt>
{r.href ? <a href={`/${locale}${r.href}`}>{t(`pricing.rows.${r.id}.name`)}</a> : t(`pricing.rows.${r.id}.name`)}
<small>{t(`pricing.rows.${r.id}.note`, r.vars)}</small>
</dt>
<dd>{r.price}</dd>
</div>
))}
</dl>
</div>
))}
</section>
<section className="policy__section" id="payment">
<h2>{t('pricing.payTitle')}</h2>
<p>{t('pricing.payBody')}</p>
<p>
<a href={`/${locale}/terms`}>{t('landing.footer.terms')}</a> · <a href={`/${locale}/refund`}>{t('landing.footer.refund')}</a>
</p>
</section>
</LegalShell>
);
}