dana-medical-site/web/src/components/DoctorCard.jsx
2026-10-14 13:33:13 +00:00

109 lines
4.0 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 { Link } from 'react-router-dom';
import starIcon from '../assets/figma/icon-star.svg';
import { experienceLabel, ratingLabel } from '../lib/format.js';
import { doctorPath } from '../lib/links.js';
import { useLeadModal } from '../context/LeadModalContext.jsx';
import './DoctorCard.css';
// Короткая подпись роли: должность («Педиатр»), а если её нет — специальность.
export function roleLabel(doctor) {
return doctor.position || doctor.specialties?.[0]?.name || '';
}
// Запись к врачу: у кого настроен Medflex — ведём туда, у остальных открываем форму заявки.
export function BookButton({ doctor, className = '', children = 'Записаться' }) {
const { open } = useLeadModal();
if (doctor.booking?.provider === 'medflex' && doctor.booking.url) {
return (
<a className={className} href={doctor.booking.url} target="_blank" rel="noreferrer">
{children}
</a>
);
}
return (
<button type="button" className={className} onClick={() => open({ form: 'appointment', doctor })}>
{children}
</button>
);
}
function DoctorPhoto({ doctor, className }) {
return (
<div className={className}>
{doctor.photo ? (
<img src={doctor.photo} alt={doctor.full_name} loading="lazy" />
) : (
<span className="doctor-photo__initials" aria-hidden="true">
{`${doctor.last_name?.[0] || ''}${doctor.first_name?.[0] || ''}`}
</span>
)}
</div>
);
}
export function RatingBadge({ rating, className = '' }) {
if (typeof rating !== 'number') return null;
return (
<span className={`rating-badge ${className}`} aria-label={`Рейтинг ${ratingLabel(rating)}`}>
<img src={starIcon} alt="" width="13" height="13" />
{ratingLabel(rating)}
</span>
);
}
// Плитка для слайдера «Специалисты» на главной.
export function DoctorTile({ doctor }) {
const path = doctorPath(doctor);
return (
<article className="doctor-tile">
<Link to={path} className="doctor-tile__photo-link" tabIndex={-1} aria-hidden="true">
<DoctorPhoto doctor={doctor} className="doctor-tile__photo" />
<RatingBadge rating={doctor.rating} className="doctor-tile__rating" />
</Link>
<div className="doctor-tile__info">
<Link to={path} className="doctor-tile__name">
{doctor.full_name}
</Link>
<p className="doctor-tile__role">{roleLabel(doctor)}</p>
{doctor.experience_years != null && (
<span className="doctor-tile__exp">{experienceLabel(doctor.experience_years)}</span>
)}
</div>
</article>
);
}
// Карточка в списке врачей.
export function DoctorRow({ doctor }) {
const path = doctorPath(doctor);
return (
<article className="doctor-row">
<Link to={path} className="doctor-row__photo-link" tabIndex={-1} aria-hidden="true">
<DoctorPhoto doctor={doctor} className="doctor-row__photo" />
</Link>
<div className="doctor-row__info">
<p className="doctor-row__role">{roleLabel(doctor)}</p>
<Link to={path} className="doctor-row__name">
{doctor.full_name}
</Link>
<div className="doctor-row__meta">
{doctor.experience_years != null && (
<span className="doctor-row__exp">{experienceLabel(doctor.experience_years)}</span>
)}
<RatingBadge rating={doctor.rating} />
</div>
<div className="doctor-row__actions">
{doctor.absent ? (
<span className="doctor-row__absent">Временно не принимает</span>
) : (
<BookButton doctor={doctor} className="btn btn--coral doctor-row__btn" />
)}
<Link to={path} className="btn btn--outline doctor-row__btn doctor-row__btn--outline">
Подробнее
</Link>
</div>
</div>
</article>
);
}