import React, { useState, useEffect } from 'react'; import { I } from '../icons.jsx'; import { CLINIC_DATA } from '../data.js'; import { Avatar, AppointmentCard, ScreenHeader } from '../components.jsx'; export function ApptsTabScreen({ nav }) { const { appointments, doctors, clinic } = CLINIC_DATA; const [tab, setTab] = useState('upcoming'); const items = appointments.filter(a => a.status === tab); return (

Мои приёмы

{items.map(a => { const d = doctors.find(x => x.id === a.doctor); const ad = clinic.addresses.find(x => x.id === a.address); return nav.push('appt:' + a.id)} />; })} {items.length === 0 && (
📋
Нет приёмов в этой категории
)}
); } export function ApptDetailScreen({ nav, apptId }) { const a = CLINIC_DATA.appointments.find(x => x.id === apptId); const d = CLINIC_DATA.doctors.find(x => x.id === a.doctor); const ad = CLINIC_DATA.clinic.addresses.find(x => x.id === a.address); const isUp = a.status === 'upcoming'; return (
nav.pop()} />
{a.weekday}, {a.date}
{a.time}
{a.type}
{ad.full}
{a.room} · 2 этаж
(342) 207-03-03
{isUp && (
)} {a.hasReport && (
Заключение врача
Диагноз: хронический риносинусит, обострение. Назначено: Аква Марис, Назонекс 14 дней. Контрольный осмотр через 2 недели.
)}
{isUp && (
)}
); } function EndoscopyTile({ label, time, seed = 0, big = false }) { const variants = [ 'radial-gradient(circle at 45% 40%, #FCE1DD 0%, #E9A29B 35%, #B36962 65%, #5A2624 100%)', 'radial-gradient(circle at 55% 50%, #FBD5D0 0%, #DC8981 40%, #9B4640 75%, #3F1B19 100%)', 'radial-gradient(circle at 40% 35%, #FFE4DE 0%, #E7988F 40%, #A55651 70%, #4A1E1B 100%)', 'radial-gradient(circle at 50% 55%, #FCDAD4 0%, #E5968C 35%, #A8544E 75%, #442220 100%)', ]; const insetPad = big ? 14 : 8; return (
{/* subtle highlight spot (specular) */}
{label} {time}
); } export function ResultEndoscopyScreen({ nav, resultId = 'r2' }) { const r = CLINIC_DATA.results.find(x => x.id === resultId) || CLINIC_DATA.results.find(x => x.kind === 'image'); const doctor = CLINIC_DATA.doctors.find(d => d.id === r.doctor); const [selected, setSelected] = useState(null); const images = [ { label: 'Носоглотка', time: '10:32' }, { label: 'Аденоиды', time: '10:33' }, { label: 'Хоана лев.', time: '10:34' }, { label: 'Хоана прав.', time: '10:35' }, ]; const diagnoses = ['Гипертрофия аденоидов III ст.']; const conclusion = 'Слизистая носоглотки умеренно гиперемирована, отёчна. Глоточная миндалина (аденоиды) III степени, заполняет просвет хоан на 2/3 с обеих сторон. Отделяемое слизистое. Устья слуховых труб обозримы, без особенностей.'; const recommendations = [ 'Консультация ЛОР-хирурга в течение 2 недель', 'Курс промываний «Кукушка» (5 процедур)', 'Контрольная эндоскопия через 1 месяц', 'Обсудить показания к аденотомии', ]; return (
nav.pop()} rightIcon={I.doc} />
Исследование провёл
{doctor.name.split(' ').slice(0,2).join(' ')}
Готово
{images.map((img, i) => ( ))}
Диагноз
{diagnoses.map(d => {d})}
Заключение

{conclusion}

Рекомендации
{recommendations.map((rec, i, a) => (
{i + 1}
{rec}
{i < a.length - 1 &&
}
))}
{selected !== null && (
setSelected(null)} style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.95)', zIndex: 200, display: 'flex', flexDirection: 'column', }} >
{images[selected].label}
e.stopPropagation()} style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 20px' }} >
{images.map((_, i) => (
)}
); } export function ResultsScreen({ nav }) { const { results, doctors } = CLINIC_DATA; return (
nav.pop()} />
{['Все','Готовы','В работе','Аудио','Эндоскопия'].map((p,i)=>( ))}
{results.map(r => { const d = doctors.find(x => x.id === r.doctor); const isReady = r.status === 'ready'; const kindIcons = { audio: I.hearing, image: I.video, lab: I.doc }; const Ic = kindIcons[r.kind]; return ( ); })}
); } export function ResultAudioScreen({ nav }) { const freqs = [250, 500, 1000, 2000, 4000, 8000]; const leftDB = [10, 15, 20, 25, 35, 50]; const rightDB = [5, 10, 15, 20, 30, 40]; const w = 320, h = 220, pl = 30, pt = 10, pr = 10, pb = 30; const iw = w - pl - pr, ih = h - pt - pb; const xFor = i => pl + (i / (freqs.length - 1)) * iw; const yFor = db => pt + (db / 120) * ih; return (
nav.pop()} rightIcon={I.doc} />
Правое ухо
Левое ухо
{[0, 20, 40, 60, 80, 100, 120].map(db => ( {db} ))} {freqs.map((f, i) => ( {f < 1000 ? f : (f/1000) + 'k'} ))} `${xFor(i)},${yFor(db)}`).join(' ')} fill="none" stroke="#E04E44" strokeWidth="2" /> {rightDB.map((db,i)=>())} `${xFor(i)},${yFor(db)}`).join(' ')} fill="none" stroke="#166B63" strokeWidth="2" strokeDasharray="4 3" /> {leftDB.map((db,i)=>( ))}
dB HL / частота (Гц) · зелёная зона — норма
Заключение
Правое ухо — норма. Левое ухо — лёгкая нейросенсорная тугоухость в области высоких частот (4–8 кГц).
Рекомендован контроль через 6 месяцев
); } export function RecoveryScreen({ nav }) { const { recovery } = CLINIC_DATA; const surgeon = CLINIC_DATA.doctors.find(d => d.id === recovery.surgeon); return (
nav.pop()} />
Операция
{recovery.op}
День {recovery.dayNow} {recovery.totalDays - recovery.dayNow} дней до выписки
Лекарства сегодня
{recovery.meds.map((m,i)=>(
{m.name}
{m.freq} · след. {m.nextTake}
{m.total > 0 && (
{m.taken}/{m.total}
)}
))}
План восстановления
{recovery.steps.map((s, i) => (
{i < recovery.steps.length - 1 && (
)}
{s.done && } {s.active &&
}
{s.title}
{s.note}
))}
Ваш хирург
{surgeon.name.split(' ').slice(0,2).join(' ')}
); } export function AudioTestScreen({ nav }) { const [stage, setStage] = useState('intro'); const [progress, setProgress] = useState(0); const [currFreq, setCurrFreq] = useState(500); useEffect(() => { if (stage !== 'test') return; const id = setInterval(() => { setProgress(p => { if (p >= 100) { clearInterval(id); setStage('done'); return 100; } return p + 2; }); setCurrFreq([250,500,1000,2000,4000,8000][Math.floor(Math.random()*6)]); }, 200); return () => clearInterval(id); }, [stage]); return (
nav.pop()} />
{stage === 'intro' && ( <>

Проверим Ваш слух

Тест займёт 3 минуты. Результат не заменяет консультацию сурдолога, но покажет, стоит ли записаться на приём.

Для точного теста
{[ { i: I.volume, t: 'Наденьте наушники', s: 'Без Bluetooth, проводные лучше' }, { i: I.shield, t: 'Выберите тихое место', s: 'Без фоновых звуков и разговоров' }, { i: I.clock, t: 'Не торопитесь', s: 'Отвечайте, когда уверены' }, ].map((x,i,a)=>{ const XI = x.i; return (
{x.t}
{x.s}
{i < a.length - 1 &&
}
); })}
Регулярные тесты помогают заметить изменения слуха вовремя
)} {stage === 'test' && ( <>
Правое ухо · {currFreq} Гц {Math.round(progress)}%
{[0,1,2].map(i => (
))}
Слышите звук?
Нажмите кнопку сразу, как услышите тон — даже если очень тихо
)} {stage === 'done' && ( <>

Тест завершён

Ваш слух в пределах нормы

Правое ухо
Норма
10 дБ, все частоты
Левое ухо
Почти норма
25 дБ на 4 кГц
Рекомендация
Небольшое снижение на левом ухе. Рекомендуем пройти аудиометрию у сурдолога.
)}
); } export function ChatTabScreen() { const msgs = [ { from: 'doc', t: 'Добрый день, Анна! Как самочувствие после операции?', tm: '14:02' }, { from: 'me', t: 'Здравствуйте! В целом хорошо, немного саднит в носу по утрам.', tm: '14:08' }, { from: 'doc', t: 'Это нормально на 6-й день. Продолжайте промывания Аква Марис 4 раза в день.', tm: '14:10' }, { from: 'doc', t: 'Выходите на осмотр сегодня? Я свободен после 15:00.', tm: '14:11' }, { from: 'me', t: 'Да, буду в 16:00 как запланировано.', tm: '14:14' }, { from: 'doc', t: 'Отлично, жду. Если что-то изменится — напишите.', tm: '14:15' }, ]; const doc = CLINIC_DATA.doctors.find(d => d.id === 'syndaev'); return (

Чат

{doc.name.split(' ').slice(0,2).join(' ')}
Онлайн · отвечает 5 мин
{msgs.map((m,i)=>(
{m.t}
{m.tm}
))}
Сообщение...
); } export function ProfileTabScreen({ nav }) { const sections = [ { title: 'Здоровье', items: [ { i: I.file, t: 'Медицинская карта', s: 'История, диагнозы', go: 'medcard' }, { i: I.doc, t: 'Анализы', s: '5 результатов', go: 'results' }, { i: I.pill, t: 'Лекарства', s: '3 активных курса', go: 'recovery' }, { i: I.hearing, t: 'История тестов слуха', s: '2 аудиограммы', go: 'results' }, ] }, { title: 'Оплата и бонусы', items: [ { i: I.card, t: 'Способы оплаты', s: 'Mir •••• 4821' }, { i: I.gift, t: 'Бонусы', s: '2 480 баллов · 5%', badge: 'Серебро' }, { i: I.file, t: 'История платежей', s: '12 операций' }, ] }, { title: 'Клиника', items: [ { i: I.pin, t: 'Адреса и часы работы', s: '3 клиники' }, { i: I.phone, t: '(342) 207-03-03', s: 'Ежедневно 9:00–21:00' }, ] }, { title: 'Настройки', items: [ { i: I.bell, t: 'Уведомления' }, { i: I.shield, t: 'Конфиденциальность' }, { i: I.user, t: 'Члены семьи', s: '+ 2 профиля' }, ] }, ]; return (

Профиль

Анна Сергеевна
+7 (912) 485-••-•• · 42 года
{sections.map((sec, si) => (
{sec.title}
{sec.items.map((it, i) => { const II = it.i; return ( {i < sec.items.length - 1 &&
} ); })}
))}
); } export function QRScreen({ nav }) { const cells = []; for (let i = 0; i < 441; i++) cells.push(Math.random() > 0.52 ? 1 : 0); const marker = (cx, cy) => { for (let y = 0; y < 7; y++) { for (let x = 0; x < 7; x++) { const isEdge = x === 0 || x === 6 || y === 0 || y === 6; const isInner = x >= 2 && x <= 4 && y >= 2 && y <= 4; cells[(cy + y) * 21 + (cx + x)] = (isEdge || isInner) ? 1 : 0; } } }; marker(0, 0); marker(14, 0); marker(0, 14); return (
Ваш QR-код
Покажите на ресепшен, чтобы быстро отметиться
{cells.map((c, i) => (
))}
Пациент №
УГН-2014-00482
Код обновляется каждые 60 секунд. Не передавайте третьим лицам.
); } export function TelemedScreen({ nav }) { return (
СА
05:42
Синдяев А.В.
ЛОР-хирург
АС
{[ { i: I.mic, bg: 'rgba(255,255,255,0.15)' }, { i: I.video, bg: 'rgba(255,255,255,0.15)' }, { i: I.chat, bg: 'rgba(255,255,255,0.15)' }, { i: I.phone, bg: '#E04E44' }, ].map((c,i)=>{ const CI = c.i; return ( ); })}
); } export function MedcardScreen({ nav }) { return (
nav.pop()} />
Основное
{[['Пол','Женский'],['Возраст','42 года'],['Рост / Вес','168 см · 62 кг'],['Группа крови','II (A), Rh+']].map(([k,v])=>(
{k} {v}
))}
Аллергии
Пенициллин Пыльца берёзы + добавить
История диагнозов
{[ { d: '12 апр 2026', t: 'Искривление носовой перегородки', doc: 'Синдяев А.В.', tag: 'Операция' }, { d: '8 апр 2026', t: 'Хронический риносинусит', doc: 'Макарова Л.Г.', tag: 'Приём' }, { d: '15 ноя 2025', t: 'ОРВИ', doc: 'Суворова С.В.', tag: 'Приём' }, ].map((r,i,a)=>(
{r.d} {r.tag}
{r.t}
{r.doc}
{i < a.length - 1 &&
}
))}
); } export function NotificationsScreen({ nav }) { const n = [ { tm: '2 ч назад', t: 'Напоминание', s: 'Приём Амоксиклава в 20:00', i: I.pill, tint: 'warning' }, { tm: 'Сегодня', t: 'Готово заключение', s: 'Макарова Л.Г. — эндоскопия носоглотки', i: I.doc, tint: 'primary' }, { tm: 'Вчера', t: 'Новое сообщение', s: 'Синдяев А.В.: «Как самочувствие?»', i: I.chat, tint: 'primary' }, { tm: '15 апр', t: 'Акция', s: 'Бесплатная консультация хирурга в апреле', i: I.gift, tint: 'warm' }, { tm: '12 апр', t: 'Приём завершён', s: 'Не забудьте оставить отзыв о враче', i: I.star, tint: 'warning' }, ]; const tints = { primary: { bg: 'var(--c-primary-100)', c: 'var(--c-primary-darker)' }, warning: { bg: 'var(--c-warning-50)', c: 'var(--c-warning)' }, warm: { bg: 'var(--c-warm-100)', c: 'var(--c-warm-text)' }, }; return (
nav.pop()} />
{n.map((x,i)=>{ const t = tints[x.tint]; const XI = x.i; return (
{x.t} {x.tm}
{x.s}
); })}
); }