109 lines
4.0 KiB
JavaScript
109 lines
4.0 KiB
JavaScript
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>
|
||
);
|
||
}
|