dana-medical-site/web/src/pages/CheckupPage.jsx

164 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useParams } from 'react-router-dom';
import ctaImage from '../assets/figma/checkup-cta-3d.webp';
import { api } from '../api.js';
import Breadcrumbs from '../components/Breadcrumbs.jsx';
import CtaBand from '../components/CtaBand.jsx';
import { useLeadModal } from '../context/LeadModalContext.jsx';
import { plural, priceLabel } from '../lib/format.js';
import { checkupMedia } from '../lib/media.js';
import { checklistItems, cleanText, introText } from '../lib/text.js';
import { useApi } from '../lib/useApi.js';
import { usePageTitle } from '../lib/usePageTitle.js';
import { pageMetadata } from '../lib/seo.js';
import { useInitialApiData } from '../context/ApiData.jsx';
import StubPage from './StubPage.jsx';
import './CheckupPage.css';
export default function CheckupPage() {
const { slug } = useParams();
const { open } = useLeadModal();
const checkup = useApi((signal) => api.checkup(slug, { signal }), [slug], `checkup:${slug}`);
const name = cleanText(checkup.data?.name);
const siteURL = useInitialApiData('siteURL') || (typeof window !== 'undefined' ? window.location.origin : '');
usePageTitle(name || undefined, checkup.data ? pageMetadata(`/checkup/${slug}/`, name, siteURL, checkup.data.seo, checkup.data.lead) : undefined);
if (checkup.error?.status === 404) return <StubPage notFound />;
if (checkup.error) return <p className="state">Не удалось загрузить программу. Обновите страницу.</p>;
if (!checkup.data || checkup.data.slug !== slug) return <p className="state checkup-loading">Загружаем…</p>;
const c = checkup.data;
const { hero, photo, cutout, heroBg, cutoutRatio } = checkupMedia(c);
const items = c.items?.length ? c.items.map(cleanText) : checklistItems(c.blocks);
const intro = introText(c.blocks);
const lead = cleanText(c.lead);
const book = () => open({ form: 'appointment', message: `Чек-ап: ${name}` });
const askPrice = () => open({ form: 'service_order', message: `Стоимость чек-апа: ${name}` });
// первый столбец списка заполняется сверху вниз, затем второй — как в макете
const rows = Math.ceil(items.length / 2);
return (
<div className="checkup-page">
<section
className={`checkup-hero${cutout ? ' checkup-hero--cutout' : ''}`}
style={heroBg ? { '--checkup-hero-bg': heroBg } : undefined}
>
<div className={`container checkup-hero__row${cutout ? ' checkup-hero__row--cutout' : ''}`}>
<div className="checkup-hero__copy">
<Breadcrumbs
items={[{ to: '/', label: 'Главная' }, { to: '/checkup/', label: 'Чек-апы' }, { label: name }]}
className="breadcrumbs--light checkup-hero__crumbs"
/>
<span className="checkup-hero__badge">Комплексная программа</span>
<h1 className="checkup-hero__title">{name}</h1>
{lead && <p className="checkup-hero__lead">{lead}</p>}
{intro && <p className="checkup-hero__text">{intro}</p>}
<div className="checkup-hero__actions">
<button type="button" className="btn checkup-hero__btn" onClick={book}>
Записаться на приём
</button>
<button type="button" className="btn checkup-hero__btn checkup-hero__btn--ghost" onClick={askPrice}>
Уточнить стоимость
</button>
</div>
</div>
{cutout ? (
<div
className="checkup-hero__image checkup-hero__image--cutout"
style={cutoutRatio ? { '--cutout-ratio': cutoutRatio } : undefined}
>
<img src={cutout} alt="" />
</div>
) : hero ? (
<div className="checkup-hero__image">
<img src={hero} alt="" />
</div>
) : (
photo && (
// крупного кадра нет — фото карточки в натуральном размере, без растягивания
<div className="checkup-hero__image checkup-hero__image--card">
<img src={photo} alt="" />
</div>
)
)}
</div>
</section>
<section className="checkup-facts">
<div className="container checkup-facts__row">
{items.length > 0 && (
<div className="checkup-fact">
<b>{items.length}</b>
<span>{plural(items.length, 'исследование и анализ', 'исследования и анализа', 'исследований и анализов')}</span>
</div>
)}
<div className="checkup-fact">
<b>{c.price ? priceLabel({ price: c.price }) : 'По запросу'}</b>
<span>
{c.price && c.old_price ? `вместо ${priceLabel({ price: c.old_price })}` : 'стоимость уточнит администратор'}
</span>
</div>
<div className="checkup-fact">
<b>Запись</b>
<span>в удобное для вас время</span>
</div>
</div>
</section>
<section className="checkup-content">
<div className="container checkup-content__inner">
{items.length > 0 && (
<>
<div className="checkup-content__head">
<h2 className="checkup-content__title">Что входит в программу</h2>
<p className="checkup-content__text">
Все ключевые этапы собраны в одном маршруте — от приёма специалиста до лабораторной диагностики.
</p>
</div>
<ol className="checkup-items" style={{ '--rows': rows }}>
{items.map((it, i) => (
<li key={i} className="checkup-item">
<span className="checkup-item__num">{i + 1}</span>
<span className="checkup-item__text">{it}</span>
</li>
))}
</ol>
</>
)}
<div className="checkup-info">
<div className="checkup-info__card">
<h3 className="checkup-info__title">Стоимость</h3>
<p className="checkup-info__text">
{c.price
? `Стоимость программы — ${priceLabel({ price: c.price })}. Администратор подтвердит её при записи.`
: 'Актуальную стоимость программы администратор назовёт при записи или по телефону.'}
</p>
</div>
<div className="checkup-info__card">
<h3 className="checkup-info__title">Как подготовиться</h3>
<p className="checkup-info__text">
Администратор расскажет о подготовке к анализам и исследованиям при подтверждении записи.
</p>
</div>
</div>
<p className="checkup-content__note">
Состав программы и актуальную стоимость уточняйте у администратора клиники.
</p>
</div>
</section>
<CtaBand
tone="lilac"
title="Позаботьтесь о здоровье вовремя"
text="Оставьте заявку — администратор поможет выбрать удобное время и уточнит детали программы."
action="Оставить заявку"
onAction={book}
image={ctaImage}
/>
</div>
);
}