Files
mobile-app-prototip/src/screens/screens-misc.jsx
T
arazor72 31b861e452 Add endoscopy result viewer screen
New screen for viewing endoscopy results: 2×2 snapshot grid with
simulated endoscopic view (radial gradient + specular highlight),
diagnosis chips, conclusion, numbered recommendations, PDF/share
actions, and full-screen image viewer with pagination.

Wired via nav route `result:<id>` from ResultsScreen and exposed in
Tweaks screen selector.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 18:32:03 +05:00

934 lines
52 KiB
React
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 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 (
<div style={{ paddingBottom: 100 }}>
<div style={{ padding: '12px 20px 12px' }}>
<h1 className="h-screen" style={{ marginBottom: 14 }}>Мои приёмы</h1>
<div className="seg" style={{ width: '100%', display: 'flex' }}>
<button onClick={() => setTab('upcoming')} className={tab==='upcoming'?'on':''} style={{ flex: 1 }}>Предстоящие · {appointments.filter(a=>a.status==='upcoming').length}</button>
<button onClick={() => setTab('past')} className={tab==='past'?'on':''} style={{ flex: 1 }}>Прошедшие</button>
</div>
</div>
<div style={{ padding: '0 16px', display: 'flex', flexDirection: 'column', gap: 10 }}>
{items.map(a => {
const d = doctors.find(x => x.id === a.doctor);
const ad = clinic.addresses.find(x => x.id === a.address);
return <AppointmentCard key={a.id} appt={a} doctor={d} addr={ad} onClick={() => nav.push('appt:' + a.id)} />;
})}
{items.length === 0 && (
<div style={{ textAlign: 'center', padding: '40px 20px' }}>
<div style={{ fontSize: 48, opacity: .3, marginBottom: 8 }}>📋</div>
<div className="sub">Нет приёмов в этой категории</div>
</div>
)}
</div>
<div style={{ padding: 16, marginTop: 12 }}>
<button onClick={() => nav.push('booking-specs')} className="btn-p block">
<I.plus size={18} /> Записаться на приём
</button>
</div>
</div>
);
}
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 (
<div style={{ paddingBottom: 120 }}>
<ScreenHeader title="Приём" onBack={() => nav.pop()} />
<div style={{ padding: '0 20px' }}>
<div className="card" style={{ padding: 20, textAlign: 'center', marginBottom: 14, background: isUp ? 'linear-gradient(135deg,#E3F4F2,#F2FAF9)' : '#fff' }}>
<div style={{ fontSize: 14, color: 'var(--c-primary-darker)', fontWeight: 700, marginBottom: 6 }}>{a.weekday}, {a.date}</div>
<div style={{ fontSize: 42, fontFamily: 'var(--font-narrow)', fontWeight: 700, color: 'var(--c-fg-1)', lineHeight: 1, marginBottom: 8 }}>{a.time}</div>
<div className="sub">{a.type}</div>
</div>
<div className="card" style={{ padding: 0, marginBottom: 14 }}>
<button onClick={() => nav.push('doctor:' + d.id)} style={{ width: '100%', textAlign: 'left', padding: 14, display: 'flex', gap: 12, alignItems: 'center' }}>
<Avatar init={d.init} size={48} />
<div style={{ flex: 1 }}>
<div style={{ fontWeight: 700, fontSize: 15 }}>{d.name.split(' ').slice(0,2).join(' ')}</div>
<div className="sub" style={{ fontSize: 12 }}>{d.spec}</div>
</div>
<I.chev size={16} style={{ color: 'var(--c-fg-4)' }} />
</button>
</div>
<div className="card" style={{ padding: 0 }}>
<div style={{ padding: '14px 16px', display: 'flex', alignItems: 'center', gap: 12 }}>
<I.pin size={20} style={{ color: 'var(--c-primary-darker)' }} />
<div style={{ flex: 1 }}>
<div style={{ fontSize: 14, fontWeight: 700 }}>{ad.full}</div>
<div className="sub" style={{ fontSize: 12 }}>{a.room} · 2 этаж</div>
</div>
<button className="btn-s" style={{ padding: '8px 12px', fontSize: 12 }}>Карта</button>
</div>
<div className="divider" />
<div style={{ padding: '14px 16px', display: 'flex', alignItems: 'center', gap: 12 }}>
<I.phone size={20} style={{ color: 'var(--c-primary-darker)' }} />
<div style={{ flex: 1, fontSize: 14 }}>(342) 207-03-03</div>
<I.chev size={16} style={{ color: 'var(--c-fg-4)' }} />
</div>
</div>
{isUp && (
<div style={{ marginTop: 16, display: 'flex', flexDirection: 'column', gap: 8 }}>
<button className="btn-g" style={{ width: '100%', padding: 14 }}>
<I.calendar size={18} /> Добавить в календарь
</button>
<button className="btn-g" style={{ width: '100%', padding: 14 }}>
<I.bell size={18} /> Напомнить позже
</button>
</div>
)}
{a.hasReport && (
<div style={{ marginTop: 16 }}>
<div className="h-sec" style={{ marginBottom: 10 }}>Заключение врача</div>
<div className="card">
<div style={{ fontSize: 14, lineHeight: 1.55, color: 'var(--c-fg-2)' }}>
Диагноз: хронический риносинусит, обострение. Назначено: Аква Марис, Назонекс 14 дней. Контрольный осмотр через 2 недели.
</div>
<button className="btn-s" style={{ marginTop: 12, padding: '8px 14px', fontSize: 13 }}>
<I.doc size={15} /> Открыть PDF
</button>
</div>
</div>
)}
</div>
{isUp && (
<div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, padding: '14px 20px 34px', background: '#fff', borderTop: '1px solid var(--c-border)', display: 'flex', gap: 10 }}>
<button className="btn-g" style={{ flex: 1, padding: 14, color: 'var(--c-danger)', borderColor: 'var(--c-accent-50)' }}>Отменить</button>
<button className="btn-p" style={{ flex: 2 }}>Перенести</button>
</div>
)}
</div>
);
}
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 (
<div style={{ position: 'relative', background: '#0B0606', borderRadius: big ? 22 : 14, overflow: 'hidden', aspectRatio: '1', width: '100%' }}>
<div style={{
position: 'absolute', inset: insetPad, borderRadius: '50%',
background: variants[seed % 4],
}} />
<div style={{
position: 'absolute', inset: insetPad, borderRadius: '50%',
boxShadow: 'inset 0 0 30px rgba(0,0,0,0.65), inset 0 0 6px rgba(255,255,255,0.15)',
pointerEvents: 'none',
}} />
{/* subtle highlight spot (specular) */}
<div style={{
position: 'absolute', top: `${22 + (seed % 3) * 6}%`, left: `${30 + (seed % 4) * 5}%`,
width: big ? 26 : 14, height: big ? 26 : 14, borderRadius: '50%',
background: 'radial-gradient(circle, rgba(255,255,255,0.55) 0%, transparent 70%)',
pointerEvents: 'none',
}} />
<div style={{
position: 'absolute', left: insetPad + 4, right: insetPad + 4, bottom: insetPad + 4,
padding: big ? '8px 12px' : '5px 8px',
background: 'rgba(0,0,0,0.55)', borderRadius: 8,
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
color: '#fff', fontSize: big ? 13 : 11,
}}>
<span style={{ fontWeight: 700 }}>{label}</span>
<span style={{ opacity: .7, fontFamily: 'var(--font-narrow)' }}>{time}</span>
</div>
</div>
);
}
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 (
<div style={{ paddingBottom: 40 }}>
<ScreenHeader title={r.name} subtitle={`${r.date} · ${images.length} снимков`} onBack={() => nav.pop()} rightIcon={I.doc} />
<div style={{ padding: '0 20px' }}>
<div className="card" style={{ padding: 14, display: 'flex', gap: 12, alignItems: 'center', marginBottom: 14 }}>
<Avatar init={doctor.init} size={44} />
<div style={{ flex: 1 }}>
<div className="sub" style={{ fontSize: 11, marginBottom: 2 }}>Исследование провёл</div>
<div style={{ fontSize: 14, fontWeight: 700 }}>{doctor.name.split(' ').slice(0,2).join(' ')}</div>
</div>
<span className="chip chip-success">Готово</span>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 16 }}>
{images.map((img, i) => (
<button key={i} onClick={() => setSelected(i)} className="press" style={{ padding: 0, background: 'transparent', borderRadius: 14 }}>
<EndoscopyTile label={img.label} time={img.time} seed={i} />
</button>
))}
</div>
<div className="card" style={{ marginBottom: 12 }}>
<div className="h-row" style={{ marginBottom: 10 }}>Диагноз</div>
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
{diagnoses.map(d => <span key={d} className="chip chip-warm" style={{ fontSize: 13, padding: '7px 12px' }}>{d}</span>)}
</div>
</div>
<div className="card" style={{ marginBottom: 12 }}>
<div className="h-row" style={{ marginBottom: 8 }}>Заключение</div>
<p style={{ margin: 0, fontSize: 14, color: 'var(--c-fg-2)', lineHeight: 1.55 }}>{conclusion}</p>
</div>
<div className="card" style={{ marginBottom: 16 }}>
<div className="h-row" style={{ marginBottom: 6 }}>Рекомендации</div>
{recommendations.map((rec, i, a) => (
<div key={i}>
<div style={{ display: 'flex', gap: 12, padding: '10px 0', alignItems: 'flex-start' }}>
<div style={{
width: 22, height: 22, borderRadius: 999, background: 'var(--c-primary-100)',
color: 'var(--c-primary-darker)', fontSize: 12, fontWeight: 700,
display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, marginTop: 1,
}}>{i + 1}</div>
<div style={{ fontSize: 14, color: 'var(--c-fg-2)', lineHeight: 1.5 }}>{rec}</div>
</div>
{i < a.length - 1 && <div className="divider" />}
</div>
))}
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
<button className="btn-p block">
<I.doc size={18} /> Скачать PDF
</button>
<div style={{ display: 'flex', gap: 10 }}>
<button onClick={() => nav.push('chat')} className="btn-g" style={{ flex: 1, padding: 14 }}>
<I.chat size={16} /> Обсудить
</button>
<button className="btn-g" style={{ flex: 1, padding: 14 }}>
<I.arrow size={16} /> Поделиться
</button>
</div>
</div>
</div>
{selected !== null && (
<div
onClick={() => setSelected(null)}
style={{
position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.95)', zIndex: 200,
display: 'flex', flexDirection: 'column',
}}
>
<div style={{ padding: '50px 20px 16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', color: '#fff' }}>
<button onClick={(e) => { e.stopPropagation(); setSelected(null); }} className="press" style={{
width: 38, height: 38, borderRadius: 999, background: 'rgba(255,255,255,0.15)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
}}>
<I.close size={18} style={{ color: '#fff' }} />
</button>
<div style={{ fontSize: 15, fontWeight: 700 }}>{images[selected].label}</div>
<button onClick={(e) => e.stopPropagation()} className="press" style={{
width: 38, height: 38, borderRadius: 999, background: 'rgba(255,255,255,0.15)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
}}>
<I.doc size={18} style={{ color: '#fff' }} />
</button>
</div>
<div
onClick={(e) => e.stopPropagation()}
style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 20px' }}
>
<div style={{ width: '100%', maxWidth: 340 }}>
<EndoscopyTile label={images[selected].label} time={images[selected].time} seed={selected} big />
</div>
</div>
<div style={{ padding: '16px 20px 36px', display: 'flex', justifyContent: 'center', gap: 8 }}>
{images.map((_, i) => (
<button
key={i}
onClick={(e) => { e.stopPropagation(); setSelected(i); }}
style={{
width: i === selected ? 24 : 8, height: 8, borderRadius: 999,
background: i === selected ? '#fff' : 'rgba(255,255,255,0.35)',
border: 0, padding: 0, cursor: 'pointer', transition: 'width .2s',
}}
/>
))}
</div>
</div>
)}
</div>
);
}
export function ResultsScreen({ nav }) {
const { results, doctors } = CLINIC_DATA;
return (
<div style={{ paddingBottom: 100 }}>
<ScreenHeader title="Анализы и обследования" onBack={() => nav.pop()} />
<div className="pills" style={{ marginBottom: 12 }}>
{['Все','Готовы','В работе','Аудио','Эндоскопия'].map((p,i)=>(
<button key={i} className={'pill' + (i===0?' on':'')}>{p}</button>
))}
</div>
<div style={{ padding: '0 16px', display: 'flex', flexDirection: 'column', gap: 10 }}>
{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 (
<button key={r.id} onClick={() => isReady && nav.push(r.kind === 'audio' ? 'result-audio' : 'result:' + r.id)} className="press card" style={{
display: 'flex', gap: 12, alignItems: 'center', textAlign: 'left', opacity: isReady ? 1 : .7,
}}>
<div style={{ width: 44, height: 44, borderRadius: 12, background: isReady ? 'var(--c-primary-100)' : 'var(--c-warning-50)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Ic size={22} style={{ color: isReady ? 'var(--c-primary-darker)' : 'var(--c-warning)' }} />
</div>
<div style={{ flex: 1 }}>
<div style={{ fontWeight: 700, fontSize: 15, marginBottom: 2 }}>{r.name}</div>
<div className="sub" style={{ fontSize: 12 }}>{r.date} · {d.name.split(' ')[0]}</div>
</div>
{isReady ? <I.chev size={16} style={{ color: 'var(--c-fg-4)' }} /> : <span className="chip" style={{ background: 'var(--c-warning-50)', color: 'var(--c-warning)' }}>В работе</span>}
</button>
);
})}
</div>
</div>
);
}
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 (
<div style={{ paddingBottom: 40 }}>
<ScreenHeader title="Аудиограмма" subtitle="8 апр 2026" onBack={() => nav.pop()} rightIcon={I.doc} />
<div style={{ padding: '0 20px' }}>
<div className="card" style={{ marginBottom: 14 }}>
<div style={{ display: 'flex', gap: 16, marginBottom: 12 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
<div style={{ width: 10, height: 10, borderRadius: 999, background: 'var(--c-accent)' }} />
<span style={{ fontSize: 12, fontWeight: 700 }}>Правое ухо</span>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
<div style={{ width: 10, height: 10, background: 'var(--c-primary-darker)' }} />
<span style={{ fontSize: 12, fontWeight: 700 }}>Левое ухо</span>
</div>
</div>
<svg width="100%" viewBox={`0 0 ${w} ${h}`} style={{ display: 'block' }}>
{[0, 20, 40, 60, 80, 100, 120].map(db => (
<g key={db}>
<line x1={pl} y1={yFor(db)} x2={w - pr} y2={yFor(db)} stroke="#E4EAF2" strokeWidth="1" />
<text x={pl - 6} y={yFor(db) + 4} fontSize="10" fill="#9AA7B4" textAnchor="end">{db}</text>
</g>
))}
{freqs.map((f, i) => (
<g key={f}>
<line x1={xFor(i)} y1={pt} x2={xFor(i)} y2={h - pb} stroke="#E4EAF2" strokeWidth="1" />
<text x={xFor(i)} y={h - pb + 14} fontSize="10" fill="#9AA7B4" textAnchor="middle">{f < 1000 ? f : (f/1000) + 'k'}</text>
</g>
))}
<rect x={pl} y={pt} width={iw} height={yFor(25)-pt} fill="#E8F5EE" opacity=".5" />
<polyline points={rightDB.map((db,i)=>`${xFor(i)},${yFor(db)}`).join(' ')} fill="none" stroke="#E04E44" strokeWidth="2" />
{rightDB.map((db,i)=>(<circle key={i} cx={xFor(i)} cy={yFor(db)} r="4" fill="#fff" stroke="#E04E44" strokeWidth="2" />))}
<polyline points={leftDB.map((db,i)=>`${xFor(i)},${yFor(db)}`).join(' ')} fill="none" stroke="#166B63" strokeWidth="2" strokeDasharray="4 3" />
{leftDB.map((db,i)=>(
<g key={i} stroke="#166B63" strokeWidth="2">
<line x1={xFor(i)-4} y1={yFor(db)-4} x2={xFor(i)+4} y2={yFor(db)+4} />
<line x1={xFor(i)+4} y1={yFor(db)-4} x2={xFor(i)-4} y2={yFor(db)+4} />
</g>
))}
</svg>
<div className="sub" style={{ fontSize: 11, textAlign: 'center', marginTop: 8 }}>dB HL / частота (Гц) · зелёная зона норма</div>
</div>
<div className="card" style={{ marginBottom: 14 }}>
<div className="h-row" style={{ marginBottom: 8 }}>Заключение</div>
<div style={{ fontSize: 14, color: 'var(--c-fg-2)', lineHeight: 1.55, marginBottom: 12 }}>
Правое ухо норма. Левое ухо лёгкая нейросенсорная тугоухость в области высоких частот (48 кГц).
</div>
<div style={{ display: 'flex', gap: 8, alignItems: 'center', padding: 12, background: 'var(--c-primary-50)', borderRadius: 10 }}>
<I.stetho size={18} style={{ color: 'var(--c-primary-darker)' }} />
<div style={{ fontSize: 13, color: 'var(--c-fg-2)' }}>Рекомендован контроль через 6 месяцев</div>
</div>
</div>
<button className="btn-g" style={{ width: '100%', padding: 14 }}>
<I.doc size={18} /> Скачать заключение
</button>
</div>
</div>
);
}
export function RecoveryScreen({ nav }) {
const { recovery } = CLINIC_DATA;
const surgeon = CLINIC_DATA.doctors.find(d => d.id === recovery.surgeon);
return (
<div style={{ paddingBottom: 40 }}>
<ScreenHeader title="Восстановление" onBack={() => nav.pop()} />
<div style={{ padding: '0 20px 16px' }}>
<div className="card" style={{ padding: 18, marginBottom: 14, background: 'linear-gradient(135deg, var(--c-primary-darker), #0F4A44)', color: '#fff', border: 0 }}>
<div style={{ fontSize: 12, textTransform: 'uppercase', letterSpacing: .8, opacity: .7, marginBottom: 4 }}>Операция</div>
<div style={{ fontSize: 20, fontWeight: 700, marginBottom: 14 }}>{recovery.op}</div>
<div style={{ height: 8, background: 'rgba(255,255,255,0.2)', borderRadius: 999, overflow: 'hidden', marginBottom: 12 }}>
<div style={{ width: `${recovery.dayNow/recovery.totalDays*100}%`, height: '100%', background: '#fff', borderRadius: 999 }} />
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12 }}>
<span style={{ opacity: .8 }}>День {recovery.dayNow}</span>
<span style={{ opacity: .8 }}>{recovery.totalDays - recovery.dayNow} дней до выписки</span>
</div>
</div>
<div className="h-sec" style={{ marginBottom: 10 }}>Лекарства сегодня</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 18 }}>
{recovery.meds.map((m,i)=>(
<div key={i} className="card" style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14 }}>
<div style={{ width: 40, height: 40, borderRadius: 10, background: 'var(--c-warning-50)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.pill size={20} style={{ color: 'var(--c-warning)' }} />
</div>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 14, fontWeight: 700 }}>{m.name}</div>
<div className="sub" style={{ fontSize: 12 }}>{m.freq} · след. {m.nextTake}</div>
</div>
{m.total > 0 && (
<div style={{ fontSize: 12, color: 'var(--c-fg-3)', fontWeight: 700 }}>{m.taken}/{m.total}</div>
)}
</div>
))}
</div>
<div className="h-sec" style={{ marginBottom: 10 }}>План восстановления</div>
<div className="card" style={{ padding: 0 }}>
{recovery.steps.map((s, i) => (
<div key={i} style={{ display: 'flex', gap: 14, padding: '14px 16px', alignItems: 'flex-start', position: 'relative' }}>
{i < recovery.steps.length - 1 && (
<div style={{ position: 'absolute', left: 27, top: 36, bottom: -10, width: 2, background: s.done ? 'var(--c-primary-darker)' : 'var(--c-divider)' }} />
)}
<div style={{
width: 28, height: 28, borderRadius: 999, flexShrink: 0,
background: s.done ? 'var(--c-primary-darker)' : '#fff',
border: s.active ? '3px solid var(--c-primary-darker)' : s.done ? 0 : '2px solid var(--c-border-strong)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
position: 'relative', zIndex: 1,
}}>
{s.done && <I.check size={16} style={{ color: '#fff' }} sw={3} />}
{s.active && <div style={{ width: 10, height: 10, borderRadius: 999, background: 'var(--c-primary-darker)' }} />}
</div>
<div style={{ flex: 1, paddingBottom: 4 }}>
<div style={{ fontSize: 14, fontWeight: 700, color: s.done ? 'var(--c-fg-3)' : 'var(--c-fg-1)', marginBottom: 2 }}>{s.title}</div>
<div className="sub" style={{ fontSize: 12 }}>{s.note}</div>
</div>
</div>
))}
</div>
<div className="card" style={{ marginTop: 14, display: 'flex', gap: 12, alignItems: 'center', padding: 14 }}>
<Avatar init={surgeon.init} size={44} />
<div style={{ flex: 1 }}>
<div className="sub" style={{ fontSize: 11 }}>Ваш хирург</div>
<div style={{ fontSize: 14, fontWeight: 700 }}>{surgeon.name.split(' ').slice(0,2).join(' ')}</div>
</div>
<button onClick={() => nav.push('chat')} className="btn-s" style={{ padding: '8px 12px' }}>
<I.chat size={15} /> Чат
</button>
</div>
</div>
</div>
);
}
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 (
<div style={{ paddingBottom: 40, height: '100%', display: 'flex', flexDirection: 'column' }}>
<ScreenHeader title="Тест слуха" onBack={() => nav.pop()} />
<div style={{ flex: 1, padding: '0 20px', display: 'flex', flexDirection: 'column' }}>
{stage === 'intro' && (
<>
<div style={{ textAlign: 'center', padding: '24px 0' }}>
<div style={{ width: 120, height: 120, margin: '0 auto 20px', borderRadius: 999, background: 'var(--c-primary-100)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.hearing size={60} style={{ color: 'var(--c-primary-darker)' }} />
</div>
<h1 className="h-screen" style={{ marginBottom: 10 }}>Проверим Ваш слух</h1>
<p className="sub" style={{ fontSize: 14, maxWidth: 300, margin: '0 auto' }}>Тест займёт 3 минуты. Результат не заменяет консультацию сурдолога, но покажет, стоит ли записаться на приём.</p>
</div>
<div className="card" style={{ marginBottom: 14 }}>
<div className="h-row" style={{ marginBottom: 10 }}>Для точного теста</div>
{[
{ 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 (
<div key={i}>
<div style={{ display: 'flex', gap: 12, padding: '10px 0', alignItems: 'flex-start' }}>
<XI size={20} style={{ color: 'var(--c-primary-darker)', flexShrink: 0, marginTop: 1 }} />
<div>
<div style={{ fontSize: 14, fontWeight: 700, marginBottom: 2 }}>{x.t}</div>
<div className="sub" style={{ fontSize: 12 }}>{x.s}</div>
</div>
</div>
{i < a.length - 1 && <div className="divider" />}
</div>
);
})}
</div>
<div style={{ flex: 1 }} />
<button onClick={() => setStage('test')} className="btn-p block" style={{ marginBottom: 10 }}>Начать тест</button>
<div className="sub" style={{ fontSize: 12, textAlign: 'center' }}>Регулярные тесты помогают заметить изменения слуха вовремя</div>
</>
)}
{stage === 'test' && (
<>
<div style={{ padding: '16px 0 8px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6 }}>
<span className="sub" style={{ fontSize: 12 }}>Правое ухо · {currFreq} Гц</span>
<span className="sub" style={{ fontSize: 12 }}>{Math.round(progress)}%</span>
</div>
<div style={{ height: 6, background: 'var(--c-divider)', borderRadius: 999, overflow: 'hidden' }}>
<div style={{ width: `${progress}%`, height: '100%', background: 'var(--c-primary-darker)', borderRadius: 999, transition: 'width .2s' }} />
</div>
</div>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}>
<div style={{ position: 'relative', width: 220, height: 220, marginBottom: 24 }}>
{[0,1,2].map(i => (
<div key={i} style={{
position: 'absolute', inset: -20 * i, borderRadius: 999,
border: '2px solid var(--c-primary-200)',
opacity: 0.5 - i * 0.15,
animation: `pulse 1.4s ${i * 0.3}s ease-out infinite`,
}} />
))}
<div style={{ position: 'absolute', inset: 0, borderRadius: 999, background: 'var(--c-primary-darker)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.volume size={70} style={{ color: '#fff' }} />
</div>
</div>
<div style={{ fontSize: 18, fontWeight: 700, textAlign: 'center', marginBottom: 8 }}>Слышите звук?</div>
<div className="sub" style={{ fontSize: 14, textAlign: 'center', maxWidth: 260 }}>Нажмите кнопку сразу, как услышите тон даже если очень тихо</div>
</div>
<button className="btn-p block" style={{ padding: 22, fontSize: 17, marginBottom: 8 }}>Слышу!</button>
<button className="btn-g" style={{ width: '100%', padding: 14 }}>Не слышу</button>
</>
)}
{stage === 'done' && (
<>
<div style={{ textAlign: 'center', padding: '24px 0' }}>
<div style={{ width: 96, height: 96, margin: '0 auto 20px', borderRadius: 999, background: 'var(--c-success-50)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.check size={48} style={{ color: 'var(--c-success)' }} sw={3} />
</div>
<h1 className="h-screen" style={{ marginBottom: 8 }}>Тест завершён</h1>
<p className="sub" style={{ fontSize: 14 }}>Ваш слух в пределах нормы</p>
</div>
<div className="card" style={{ marginBottom: 14 }}>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
<div>
<div className="sub" style={{ fontSize: 11, marginBottom: 4 }}>Правое ухо</div>
<div style={{ fontSize: 18, fontWeight: 700, color: 'var(--c-success)' }}>Норма</div>
<div className="sub" style={{ fontSize: 12, marginTop: 2 }}>10 дБ, все частоты</div>
</div>
<div>
<div className="sub" style={{ fontSize: 11, marginBottom: 4 }}>Левое ухо</div>
<div style={{ fontSize: 18, fontWeight: 700, color: 'var(--c-warning)' }}>Почти норма</div>
<div className="sub" style={{ fontSize: 12, marginTop: 2 }}>25 дБ на 4 кГц</div>
</div>
</div>
</div>
<div className="card" style={{ marginBottom: 14, background: 'var(--c-primary-50)' }}>
<div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
<I.stetho size={20} style={{ color: 'var(--c-primary-darker)', flexShrink: 0, marginTop: 2 }} />
<div>
<div style={{ fontSize: 14, fontWeight: 700, marginBottom: 4 }}>Рекомендация</div>
<div style={{ fontSize: 13, color: 'var(--c-fg-2)', lineHeight: 1.5 }}>Небольшое снижение на левом ухе. Рекомендуем пройти аудиометрию у сурдолога.</div>
</div>
</div>
</div>
<div style={{ flex: 1 }} />
<button onClick={() => nav.push('booking-specs')} className="btn-p block" style={{ marginBottom: 10 }}>Записаться к сурдологу</button>
<button onClick={() => nav.pop()} className="btn-g" style={{ width: '100%', padding: 14 }}>Сохранить и закрыть</button>
</>
)}
</div>
</div>
);
}
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 (
<div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
<div style={{ padding: '12px 20px 12px' }}>
<h1 className="h-screen">Чат</h1>
</div>
<div style={{ padding: '0 16px 12px' }}>
<div className="card" style={{ display: 'flex', gap: 12, alignItems: 'center', padding: 12, background: 'var(--c-primary-50)' }}>
<Avatar init={doc.init} size={44} />
<div style={{ flex: 1 }}>
<div style={{ fontSize: 14, fontWeight: 700 }}>{doc.name.split(' ').slice(0,2).join(' ')}</div>
<div className="sub" style={{ fontSize: 12, display: 'flex', alignItems: 'center', gap: 4 }}>
<span style={{ width: 6, height: 6, borderRadius: 999, background: 'var(--c-success)' }} />
Онлайн · отвечает 5 мин
</div>
</div>
<button className="btn-s" style={{ padding: 10, borderRadius: 999 }}>
<I.video size={16} />
</button>
</div>
</div>
<div style={{ flex: 1, overflowY: 'auto', padding: '8px 16px', display: 'flex', flexDirection: 'column', gap: 8 }}>
{msgs.map((m,i)=>(
<div key={i} style={{ alignSelf: m.from === 'me' ? 'flex-end' : 'flex-start', maxWidth: '78%' }}>
<div style={{
background: m.from === 'me' ? 'var(--c-primary-darker)' : '#fff',
color: m.from === 'me' ? '#fff' : 'var(--c-fg-1)',
padding: '10px 14px', borderRadius: 16,
borderBottomRightRadius: m.from === 'me' ? 4 : 16,
borderBottomLeftRadius: m.from === 'me' ? 16 : 4,
fontSize: 14, lineHeight: 1.45,
boxShadow: m.from === 'me' ? 'none' : 'var(--sh-sm)',
}}>{m.t}</div>
<div className="sub" style={{ fontSize: 11, marginTop: 3, textAlign: m.from === 'me' ? 'right' : 'left', padding: '0 4px' }}>{m.tm}</div>
</div>
))}
</div>
<div style={{ padding: '10px 16px 100px', borderTop: '1px solid var(--c-border)', background: '#fff' }}>
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
<button style={{ width: 38, height: 38, borderRadius: 999, background: 'var(--c-bg)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.plus size={20} />
</button>
<div style={{ flex: 1, background: 'var(--c-bg)', borderRadius: 999, padding: '10px 16px', fontSize: 14, color: 'var(--c-fg-4)' }}>Сообщение...</div>
<button style={{ width: 38, height: 38, borderRadius: 999, background: 'var(--c-primary-darker)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.mic size={20} />
</button>
</div>
</div>
</div>
);
}
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:0021:00' },
]
},
{
title: 'Настройки',
items: [
{ i: I.bell, t: 'Уведомления' },
{ i: I.shield, t: 'Конфиденциальность' },
{ i: I.user, t: 'Члены семьи', s: '+ 2 профиля' },
]
},
];
return (
<div style={{ paddingBottom: 100 }}>
<div style={{ padding: '12px 20px 16px' }}>
<h1 className="h-screen" style={{ marginBottom: 18 }}>Профиль</h1>
<div className="card" style={{ padding: 18, display: 'flex', gap: 14, alignItems: 'center', background: 'linear-gradient(135deg, var(--c-primary-100), var(--c-warm-100))', border: 0 }}>
<Avatar init="АС" size={64} style={{ fontSize: 24, boxShadow: 'var(--sh-sm)' }} />
<div style={{ flex: 1 }}>
<div style={{ fontSize: 18, fontWeight: 700 }}>Анна Сергеевна</div>
<div className="sub" style={{ fontSize: 13, marginBottom: 6 }}>+7 (912) 485-- · 42 года</div>
<button onClick={() => nav.push('qr')} className="chip" style={{ fontSize: 12, fontWeight: 700 }}>
<I.qr size={12} /> QR пациента
</button>
</div>
</div>
</div>
<div style={{ padding: '0 16px' }}>
{sections.map((sec, si) => (
<div key={si} style={{ marginBottom: 18 }}>
<div style={{ fontSize: 11, color: 'var(--c-fg-3)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: .8, padding: '0 4px 8px' }}>{sec.title}</div>
<div className="card" style={{ padding: 0 }}>
{sec.items.map((it, i) => {
const II = it.i;
return (
<React.Fragment key={i}>
<button onClick={() => it.go && nav.push(it.go)} className="press" style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 14, padding: '13px 16px', textAlign: 'left' }}>
<div style={{ width: 34, height: 34, borderRadius: 9, background: 'var(--c-primary-100)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<II size={18} style={{ color: 'var(--c-primary-darker)' }} />
</div>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 14, fontWeight: 600 }}>{it.t}</div>
{it.s && <div className="sub" style={{ fontSize: 12 }}>{it.s}</div>}
</div>
{it.badge && <span className="chip chip-warm" style={{ fontSize: 11 }}>{it.badge}</span>}
<I.chev size={15} style={{ color: 'var(--c-fg-4)' }} />
</button>
{i < sec.items.length - 1 && <div style={{ height: 1, background: 'var(--c-divider)', marginLeft: 64 }} />}
</React.Fragment>
);
})}
</div>
</div>
))}
</div>
</div>
);
}
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 (
<div style={{ paddingBottom: 40, height: '100%', display: 'flex', flexDirection: 'column', background: 'linear-gradient(180deg, var(--c-primary-darker) 0%, var(--c-primary-dark) 100%)', color: '#fff' }}>
<div style={{ display: 'flex', padding: '12px 16px 8px' }}>
<button onClick={() => nav.pop()} className="press" style={{ width: 38, height: 38, borderRadius: 999, background: 'rgba(255,255,255,0.15)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.chevL size={20} style={{ color: '#fff' }} />
</button>
</div>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '0 32px' }}>
<div style={{ marginBottom: 24, textAlign: 'center' }}>
<div style={{ fontSize: 22, fontWeight: 700, marginBottom: 6 }}>Ваш QR-код</div>
<div style={{ fontSize: 13, opacity: .75 }}>Покажите на ресепшен, чтобы быстро отметиться</div>
</div>
<div style={{ background: '#fff', borderRadius: 24, padding: 20, marginBottom: 20 }}>
<div style={{ width: 210, height: 210, display: 'grid', gridTemplateColumns: 'repeat(21,1fr)', gap: 0 }}>
{cells.map((c, i) => (
<div key={i} style={{ background: c ? '#0F4A44' : 'transparent' }} />
))}
</div>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ fontSize: 13, opacity: .75, marginBottom: 3 }}>Пациент </div>
<div style={{ fontSize: 20, fontWeight: 700, letterSpacing: 1, fontFamily: 'var(--font-narrow)' }}>УГН-2014-00482</div>
</div>
</div>
<div style={{ padding: '0 20px 20px' }}>
<div style={{ background: 'rgba(255,255,255,0.12)', borderRadius: 16, padding: 14, display: 'flex', gap: 12, alignItems: 'center' }}>
<I.shield size={22} style={{ color: '#fff', opacity: .8 }} />
<div style={{ fontSize: 13, lineHeight: 1.45, opacity: .9 }}>Код обновляется каждые 60 секунд. Не передавайте третьим лицам.</div>
</div>
</div>
</div>
);
}
export function TelemedScreen({ nav }) {
return (
<div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: '#0F1A20', color: '#fff', position: 'relative' }}>
<div style={{ flex: 1, background: 'linear-gradient(135deg, #1F8F85, #166B63)', position: 'relative' }}>
<div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<div style={{ width: 140, height: 140, borderRadius: 999, background: 'rgba(255,255,255,0.15)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-narrow)', fontSize: 56, fontWeight: 700 }}>СА</div>
</div>
<div style={{ position: 'absolute', top: 60, left: 0, right: 0, padding: '0 20px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<button onClick={() => nav.pop()} className="press" style={{ width: 36, height: 36, borderRadius: 999, background: 'rgba(0,0,0,0.4)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.chevD size={22} style={{ color: '#fff' }} />
</button>
<div style={{ background: 'rgba(0,0,0,0.4)', borderRadius: 999, padding: '8px 14px', display: 'flex', alignItems: 'center', gap: 8 }}>
<span style={{ width: 8, height: 8, borderRadius: 999, background: '#E04E44', animation: 'blink 1.2s infinite' }} />
<span style={{ fontSize: 13, fontWeight: 700 }}>05:42</span>
</div>
<button className="press" style={{ width: 36, height: 36, borderRadius: 999, background: 'rgba(0,0,0,0.4)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.menu size={20} style={{ color: '#fff' }} />
</button>
</div>
<div style={{ position: 'absolute', bottom: 160, left: 0, right: 0, textAlign: 'center' }}>
<div style={{ fontSize: 18, fontWeight: 700, marginBottom: 3 }}>Синдяев А.В.</div>
<div style={{ fontSize: 13, opacity: .75 }}>ЛОР-хирург</div>
</div>
<div style={{ position: 'absolute', top: 110, right: 16, width: 96, height: 130, borderRadius: 14, background: '#2a3540', border: '2px solid rgba(255,255,255,0.2)', overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<div style={{ width: 44, height: 44, borderRadius: 999, background: 'var(--c-primary-100)', color: 'var(--c-primary-darker)', fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>АС</div>
</div>
</div>
<div style={{ padding: '24px 0 50px', background: 'rgba(15,26,32,0.9)', backdropFilter: 'blur(10px)', display: 'flex', justifyContent: 'center', gap: 14 }}>
{[
{ 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 (
<button key={i} className="press" style={{ width: 58, height: 58, borderRadius: 999, background: c.bg, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<CI size={24} style={{ color: '#fff' }} />
</button>
);
})}
</div>
</div>
);
}
export function MedcardScreen({ nav }) {
return (
<div style={{ paddingBottom: 40 }}>
<ScreenHeader title="Медицинская карта" onBack={() => nav.pop()} />
<div style={{ padding: '0 20px' }}>
<div className="card" style={{ marginBottom: 14 }}>
<div className="h-row" style={{ marginBottom: 10 }}>Основное</div>
{[['Пол','Женский'],['Возраст','42 года'],['Рост / Вес','168 см · 62 кг'],['Группа крови','II (A), Rh+']].map(([k,v])=>(
<div key={k} style={{ display: 'flex', justifyContent: 'space-between', padding: '8px 0' }}>
<span className="sub">{k}</span>
<span style={{ fontSize: 14, fontWeight: 700 }}>{v}</span>
</div>
))}
</div>
<div className="card" style={{ marginBottom: 14 }}>
<div className="h-row" style={{ marginBottom: 10 }}>Аллергии</div>
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
<span className="chip chip-danger">Пенициллин</span>
<span className="chip chip-danger">Пыльца берёзы</span>
<span className="chip chip-soft">+ добавить</span>
</div>
</div>
<div className="h-sec" style={{ padding: '4px 4px 10px' }}>История диагнозов</div>
<div className="card" style={{ padding: 0 }}>
{[
{ d: '12 апр 2026', t: 'Искривление носовой перегородки', doc: 'Синдяев А.В.', tag: 'Операция' },
{ d: '8 апр 2026', t: 'Хронический риносинусит', doc: 'Макарова Л.Г.', tag: 'Приём' },
{ d: '15 ноя 2025', t: 'ОРВИ', doc: 'Суворова С.В.', tag: 'Приём' },
].map((r,i,a)=>(
<div key={i}>
<div style={{ padding: '14px 16px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>
<span className="sub" style={{ fontSize: 12 }}>{r.d}</span>
<span className="chip chip-soft" style={{ fontSize: 10 }}>{r.tag}</span>
</div>
<div style={{ fontSize: 14, fontWeight: 700, marginBottom: 3 }}>{r.t}</div>
<div className="sub" style={{ fontSize: 12 }}>{r.doc}</div>
</div>
{i < a.length - 1 && <div className="divider" />}
</div>
))}
</div>
</div>
</div>
);
}
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 (
<div style={{ paddingBottom: 40 }}>
<ScreenHeader title="Уведомления" onBack={() => nav.pop()} />
<div style={{ padding: '0 16px', display: 'flex', flexDirection: 'column', gap: 8 }}>
{n.map((x,i)=>{
const t = tints[x.tint];
const XI = x.i;
return (
<div key={i} className="card" style={{ display: 'flex', gap: 12, alignItems: 'flex-start', padding: 14 }}>
<div style={{ width: 38, height: 38, borderRadius: 10, background: t.bg, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<XI size={18} style={{ color: t.c }} />
</div>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 2 }}>
<span style={{ fontSize: 14, fontWeight: 700 }}>{x.t}</span>
<span className="sub" style={{ fontSize: 11 }}>{x.tm}</span>
</div>
<div className="sub" style={{ fontSize: 13 }}>{x.s}</div>
</div>
</div>
);
})}
</div>
</div>
);
}