прототип мобильного приложения Клиники ухо, горло, нос им. проф. Е.Н.Оленевой. подготволен совместно с Claude.ai design и Claude CLI
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

681 lines
39 KiB

import React from 'react';
import { I } from '../icons.jsx';
import { CLINIC_DATA } from '../data.js';
import { Avatar, AppointmentCard, SectionHeader } from '../components.jsx';
export function HomeCardsScreen({ nav }) {
const { doctors, appointments, specializations, clinic, articles } = CLINIC_DATA;
const upcoming = appointments.find(a => a.status === 'upcoming');
const upDoc = upcoming && doctors.find(d => d.id === upcoming.doctor);
return (
<div style={{ paddingBottom: 100 }}>
<div style={{ padding: '8px 20px 16px', background: 'linear-gradient(180deg,#F5EDDF 0%,transparent 100%)' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
<div>
<div className="sub" style={{ marginBottom: 2 }}>Добрый день,</div>
<div style={{ fontSize: 22, fontWeight: 700, color: 'var(--c-fg-1)' }}>Анна Сергеевна</div>
</div>
<div style={{ display: 'flex', gap: 8 }}>
<button onClick={() => nav.push('notifications')} className="press" style={{ width: 42, height: 42, borderRadius: 999, background: '#fff', border: '1px solid var(--c-border)', display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative' }}>
<I.bell size={20} style={{ color: 'var(--c-fg-1)' }} />
<span style={{ position: 'absolute', top: 7, right: 9, width: 8, height: 8, borderRadius: 999, background: 'var(--c-accent)' }} />
</button>
<button onClick={() => nav.push('qr')} className="press" style={{ width: 42, height: 42, borderRadius: 999, background: '#fff', border: '1px solid var(--c-border)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.qr size={20} style={{ color: 'var(--c-fg-1)' }} />
</button>
</div>
</div>
<button onClick={() => nav.push('booking-specs')} className="press" style={{
width: '100%', textAlign: 'left',
background: 'var(--c-primary-darker)', color: '#fff',
borderRadius: 20, padding: 18,
display: 'flex', alignItems: 'center', gap: 14,
boxShadow: '0 10px 30px rgba(22,107,99,.25)',
}}>
<div style={{ width: 48, height: 48, borderRadius: 14, background: 'rgba(255,255,255,0.15)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.plus size={26} />
</div>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 16, fontWeight: 700, marginBottom: 2 }}>Записаться на приём</div>
<div style={{ fontSize: 13, opacity: .8 }}>К ЛОР-врачу · сегодня или завтра</div>
</div>
<I.arrow size={22} />
</button>
</div>
{upcoming && upDoc && (
<div style={{ padding: '16px 20px 8px' }}>
<SectionHeader title="Ближайший приём" pad="0 0 0 0" action="Все" onAction={() => nav.set('appts')} />
<AppointmentCard appt={upcoming} doctor={upDoc} addr={clinic.addresses.find(a => a.id === upcoming.address)} onClick={() => nav.push('appt:' + upcoming.id)} />
</div>
)}
<div style={{ padding: '16px 20px 8px' }}>
<SectionHeader title="Специализации" pad="0 0 0 0" />
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: 10 }}>
{specializations.map(s => {
const icons = { ear: I.ear, hear: I.hearing, leaf: I.heart, mic: I.mic, baby: I.profile, scalpel: I.stetho };
const Ic = icons[s.icon];
return (
<button key={s.id} onClick={() => nav.push('doctors')} className="press card" style={{ padding: 14, display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 10 }}>
<div style={{ width: 36, height: 36, borderRadius: 10, background: 'var(--c-primary-100)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Ic size={20} style={{ color: 'var(--c-primary-darker)' }} />
</div>
<div>
<div style={{ fontSize: 13, fontWeight: 700, color: 'var(--c-fg-1)', marginBottom: 1 }}>{s.label}</div>
<div className="sub" style={{ fontSize: 11 }}>{s.count} врачей</div>
</div>
</button>
);
})}
</div>
</div>
<div style={{ padding: '16px 20px 8px' }}>
<SectionHeader title="Быстрые действия" pad="0 0 0 0" />
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2,1fr)', gap: 10 }}>
<button onClick={() => nav.push('telemed')} className="press card" style={{ padding: 14, display: 'flex', gap: 12, alignItems: 'center', textAlign: 'left' }}>
<div style={{ width: 40, height: 40, borderRadius: 10, background: 'var(--c-accent-50)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.video size={20} style={{ color: 'var(--c-accent)' }} />
</div>
<div>
<div style={{ fontSize: 13, fontWeight: 700 }}>Телемедицина</div>
<div className="sub" style={{ fontSize: 11 }}>Видео с врачом</div>
</div>
</button>
<button onClick={() => nav.push('audiotest')} className="press card" style={{ padding: 14, display: 'flex', gap: 12, alignItems: 'center', textAlign: 'left' }}>
<div style={{ width: 40, height: 40, borderRadius: 10, background: 'var(--c-primary-100)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.hearing size={20} style={{ color: 'var(--c-primary-darker)' }} />
</div>
<div>
<div style={{ fontSize: 13, fontWeight: 700 }}>Тест слуха</div>
<div className="sub" style={{ fontSize: 11 }}>За 3 минуты</div>
</div>
</button>
<button onClick={() => nav.push('results')} className="press card" style={{ padding: 14, display: 'flex', gap: 12, alignItems: 'center', textAlign: 'left' }}>
<div style={{ width: 40, height: 40, borderRadius: 10, background: 'var(--c-warm-100)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.doc size={20} style={{ color: 'var(--c-warm-text)' }} />
</div>
<div>
<div style={{ fontSize: 13, fontWeight: 700 }}>Анализы</div>
<div className="sub" style={{ fontSize: 11 }}>5 результатов</div>
</div>
</button>
<button onClick={() => nav.push('recovery')} className="press card" style={{ padding: 14, display: 'flex', gap: 12, alignItems: 'center', textAlign: 'left' }}>
<div style={{ width: 40, height: 40, borderRadius: 10, background: 'var(--c-success-50)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.shield size={20} style={{ color: 'var(--c-success)' }} />
</div>
<div>
<div style={{ fontSize: 13, fontWeight: 700 }}>Восстановление</div>
<div className="sub" style={{ fontSize: 11 }}>День 6 из 14</div>
</div>
</button>
</div>
</div>
<div style={{ padding: '16px 0 8px' }}>
<SectionHeader title="Статьи врачей" action="Все" onAction={() => nav.push('articles')} />
<div style={{ display: 'flex', gap: 12, overflowX: 'auto', padding: '0 20px 8px' }} className="noscroll">
{articles.map((a, i) => (
<button key={a.id} onClick={() => nav.push('article:' + a.id)} className="press card" style={{
flexShrink: 0, width: 220, padding: 0, overflow: 'hidden', textAlign: 'left',
}}>
<div style={{
height: 90, background: a.hero || ['#F5EDDF','#E3F4F2','#FDF8E6','#FCF1F0'][i % 4],
display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', padding: 12,
}}>
<span className="chip chip-warm" style={{ background: 'rgba(255,255,255,0.85)' }}>{a.tag}</span>
<span style={{ fontSize: 28, lineHeight: 1 }}>{a.emoji}</span>
</div>
<div style={{ padding: 12 }}>
<div style={{ fontSize: 13, fontWeight: 700, color: 'var(--c-fg-1)', lineHeight: 1.3, marginBottom: 6, minHeight: 34 }}>{a.title}</div>
<div className="sub" style={{ fontSize: 11 }}>{a.author} · {a.mins} мин</div>
</div>
</button>
))}
</div>
</div>
</div>
);
}
export function HomeListScreen({ nav }) {
const { doctors, appointments, clinic } = CLINIC_DATA;
const upcoming = appointments.find(a => a.status === 'upcoming');
const upDoc = upcoming && doctors.find(d => d.id === upcoming.doctor);
const items = [
{ id: 'book', icon: I.plus, title: 'Записаться на приём', sub: 'ЛОР, сурдолог, фониатр', tint: 'var(--c-primary-darker)', bg: 'var(--c-primary-100)', cta: true, go: 'booking-specs' },
{ id: 'appt', icon: I.calendar, title: 'Мои приёмы', sub: `${appointments.filter(a=>a.status==='upcoming').length} предстоящих · ${appointments.filter(a=>a.status==='past').length} прошедших`, go: 'appts' },
{ id: 'card', icon: I.file, title: 'Медицинская карта', sub: 'История, результаты, заключения', go: 'medcard' },
{ id: 'results', icon: I.doc, title: 'Анализы и обследования', sub: '5 результатов · 1 в работе', go: 'results' },
{ id: 'telemed', icon: I.video, title: 'Видеоконсультация', sub: 'Онлайн с ЛОР-врачом', go: 'telemed' },
{ id: 'audio', icon: I.hearing, title: 'Тест слуха', sub: 'Аудиограмма за 3 минуты', go: 'audiotest' },
{ id: 'recovery', icon: I.shield, title: 'Восстановление', sub: 'Септопластика · день 6', go: 'recovery' },
{ id: 'chat', icon: I.chat, title: 'Чат с врачом', sub: '2 непрочитанных', badge: 2, go: 'chat' },
];
return (
<div style={{ paddingBottom: 100 }}>
<div style={{ padding: '8px 20px 16px' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
<div>
<div className="sub">Здравствуйте,</div>
<div style={{ fontSize: 20, fontWeight: 700 }}>Анна Сергеевна</div>
</div>
<button onClick={() => nav.push('notifications')} className="press" style={{ width: 40, height: 40, borderRadius: 999, background: '#fff', border: '1px solid var(--c-border)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.bell size={18} />
</button>
</div>
{upcoming && upDoc && (
<div style={{ marginBottom: 18 }}>
<AppointmentCard appt={upcoming} doctor={upDoc} addr={clinic.addresses.find(a=>a.id===upcoming.address)} onClick={() => nav.push('appt:' + upcoming.id)} compact />
</div>
)}
</div>
<div className="card" style={{ margin: '0 16px', padding: 0, overflow: 'hidden' }}>
{items.map((it, i) => (
<React.Fragment key={it.id}>
<button onClick={() => nav.push(it.go)} className="press" style={{
width: '100%', display: 'flex', alignItems: 'center', gap: 14,
padding: '14px 16px', textAlign: 'left',
background: it.cta ? 'var(--c-primary-50)' : 'transparent',
}}>
<div style={{
width: 40, height: 40, borderRadius: 10,
background: it.bg || 'var(--c-primary-100)',
display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
}}>
{React.createElement(it.icon, { size: 20, style: { color: it.tint || 'var(--c-primary-darker)' } })}
</div>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: 15, fontWeight: 700, color: 'var(--c-fg-1)', marginBottom: 2 }}>{it.title}</div>
<div className="sub" style={{ fontSize: 12 }}>{it.sub}</div>
</div>
{it.badge && <span style={{ background: 'var(--c-accent)', color: '#fff', fontSize: 11, fontWeight: 700, padding: '2px 7px', borderRadius: 999 }}>{it.badge}</span>}
<I.chev size={16} style={{ color: 'var(--c-fg-4)' }} />
</button>
{i < items.length - 1 && <div style={{ height: 1, background: 'var(--c-divider)', marginLeft: 70 }} />}
</React.Fragment>
))}
</div>
</div>
);
}
export function HomeTimelineXScreen({ nav }) {
const { doctors, appointments, clinic, articles, chronic } = CLINIC_DATA;
const upcoming = appointments.find(a => a.status === 'upcoming');
const upDoc = upcoming && doctors.find(d => d.id === upcoming.doctor);
const myDoctor = doctors.find(d => d.id === chronic.doctorId);
const typeColors = {
diagnosis: { bg: 'var(--c-primary-100)', fg: 'var(--c-primary-darker)' },
procedure: { bg: 'var(--c-primary-100)', fg: 'var(--c-primary-darker)' },
therapy: { bg: 'var(--c-warm-100)', fg: 'var(--c-warm-text)' },
flareup: { bg: 'var(--c-accent-50)', fg: 'var(--c-accent)' },
checkup: { bg: 'var(--c-success-50)', fg: 'var(--c-success)' },
};
return (
<div style={{ paddingBottom: 100 }}>
{/* Greeting header */}
<div style={{ padding: '8px 20px 14px' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div>
<div className="sub">20 апреля, понедельник</div>
<div style={{ fontSize: 22, fontWeight: 700 }}>Здравствуйте, Анна</div>
</div>
<button onClick={() => nav.push('profile')} className="press">
<Avatar init="АС" size={42} />
</button>
</div>
</div>
{/* Health status hero */}
<div style={{ padding: '0 16px 16px' }}>
<div className="card" style={{
padding: 18,
background: 'linear-gradient(135deg, var(--c-primary-100), var(--c-warm-100))',
border: '1px solid var(--c-primary-200)',
}}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
<span style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: .8, color: 'var(--c-primary-darker)', fontWeight: 700 }}>Ваше состояние</span>
<span style={{
padding: '4px 10px', borderRadius: 999,
background: 'rgba(255,255,255,0.75)', color: 'var(--c-success)',
fontSize: 11, fontWeight: 700, display: 'inline-flex', alignItems: 'center', gap: 5,
}}>
<span style={{ width: 6, height: 6, borderRadius: 999, background: 'var(--c-success)' }} />
{chronic.stage}
</span>
</div>
<div style={{ fontSize: 19, fontWeight: 700, color: 'var(--c-fg-1)', marginBottom: 4 }}>{chronic.condition}</div>
<div style={{ fontSize: 12, color: 'var(--c-fg-3)', marginBottom: 16 }}>
Наблюдение с {chronic.diagnosed} · {myDoctor.name.split(' ').slice(0, 2).join(' ')}
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8, paddingTop: 14, borderTop: '1px solid rgba(255,255,255,0.6)' }}>
<div>
<div style={{ fontFamily: 'var(--font-narrow)', fontSize: 26, fontWeight: 700, lineHeight: 1, color: 'var(--c-primary-darker)' }}>{chronic.daysSinceLastFlareup}</div>
<div style={{ fontSize: 10, color: 'var(--c-fg-3)', marginTop: 3 }}>дней без обострений</div>
</div>
<div>
<div style={{ fontFamily: 'var(--font-narrow)', fontSize: 26, fontWeight: 700, lineHeight: 1, color: 'var(--c-primary-darker)' }}>{chronic.complianceScore}%</div>
<div style={{ fontSize: 10, color: 'var(--c-fg-3)', marginTop: 3 }}>комплаенс</div>
</div>
<div>
<div style={{ fontFamily: 'var(--font-narrow)', fontSize: 26, fontWeight: 700, lineHeight: 1, color: 'var(--c-primary-darker)' }}>{chronic.flareupsThisYear}</div>
<div style={{ fontSize: 10, color: 'var(--c-fg-3)', marginTop: 3 }}>обострение в году</div>
</div>
</div>
</div>
</div>
{/* Current tasks */}
<div style={{ padding: '0 20px 18px' }}>
<SectionHeader title="Задачи сегодня" pad="0 0 8px 0" action="История" onAction={() => nav.push('medcard')} />
<div className="card" style={{ padding: 0 }}>
{chronic.currentTasks.map((t, i, a) => {
const isDaily = t.type === 'daily';
return (
<React.Fragment key={t.id}>
<div style={{ display: 'flex', gap: 12, alignItems: 'center', padding: '12px 14px' }}>
{isDaily ? (
<div style={{
width: 28, height: 28, borderRadius: 999, flexShrink: 0,
background: t.done ? 'var(--c-primary-darker)' : '#fff',
border: t.done ? 0 : '2px solid var(--c-border-strong)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
}}>
{t.done && <I.check size={16} style={{ color: '#fff' }} sw={3} />}
</div>
) : (
<div style={{
width: 28, height: 28, borderRadius: 8, flexShrink: 0,
background: 'var(--c-primary-100)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
}}>
<I.calendar size={14} style={{ color: 'var(--c-primary-darker)' }} />
</div>
)}
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{
fontSize: 14, fontWeight: 600,
color: isDaily && t.done ? 'var(--c-fg-3)' : 'var(--c-fg-1)',
textDecoration: isDaily && t.done ? 'line-through' : 'none',
}}>{t.text}</div>
<div className="sub" style={{ fontSize: 11 }}>
{isDaily ? (t.streak > 0 ? `Серия: ${t.streak} дней` : 'Ежедневно') : `До ${t.nextDate}`}
</div>
</div>
{isDaily && t.streak > 0 && <span style={{ fontSize: 18 }}>🔥</span>}
{!isDaily && <I.chev size={15} style={{ color: 'var(--c-fg-4)' }} />}
</div>
{i < a.length - 1 && <div style={{ height: 1, background: 'var(--c-divider)', marginLeft: 54 }} />}
</React.Fragment>
);
})}
</div>
</div>
{/* Promotion: ask AI or doctor */}
<div style={{ padding: '0 20px 18px' }}>
<SectionHeader title="Есть вопрос?" pad="0 0 8px 0" />
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
<button onClick={() => nav.push('chat:ai')} className="press" style={{
padding: 14, borderRadius: 16,
background: 'linear-gradient(135deg, var(--c-primary-darker), var(--c-primary-dark))',
color: '#fff', textAlign: 'left', display: 'flex', flexDirection: 'column', gap: 6,
}}>
<div style={{ fontSize: 26 }}></div>
<div>
<div style={{ fontSize: 13, fontWeight: 700, marginBottom: 2 }}>Спросить помощника</div>
<div style={{ fontSize: 11, opacity: .85, lineHeight: 1.4 }}>Быстрый ответ круглосуточно</div>
</div>
</button>
<button onClick={() => nav.push('chat:doctor-syndaev')} className="press card" style={{
padding: 14, textAlign: 'left', display: 'flex', flexDirection: 'column', gap: 6,
}}>
<Avatar init={myDoctor.init} size={32} />
<div>
<div style={{ fontSize: 13, fontWeight: 700, marginBottom: 2 }}>Написать врачу</div>
<div className="sub" style={{ fontSize: 11, lineHeight: 1.4 }}>{myDoctor.name.split(' ').slice(0, 2).join(' ')}</div>
</div>
</button>
</div>
</div>
{/* History timeline */}
<div style={{ padding: '0 20px 18px' }}>
<SectionHeader title="История наблюдения" pad="0 0 8px 0" action="Вся карта" onAction={() => nav.push('medcard')} />
<div className="card" style={{ padding: '8px 0' }}>
{chronic.pastVisits.map((v, i, a) => {
const d = doctors.find(x => x.id === v.doctorId);
const c = typeColors[v.type] || typeColors.checkup;
const isLast = i === a.length - 1;
return (
<div key={v.id} style={{ display: 'flex', gap: 14, padding: '10px 14px', alignItems: 'flex-start', position: 'relative' }}>
{!isLast && (
<div style={{
position: 'absolute', left: 27, top: 32, bottom: -6,
width: 2, background: 'var(--c-divider)',
}} />
)}
<div style={{
width: 28, height: 28, borderRadius: 999, flexShrink: 0,
background: c.bg, color: c.fg,
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: 11, fontWeight: 700,
position: 'relative', zIndex: 1,
}}>
{d.init}
</div>
<div style={{ flex: 1, paddingBottom: 4, minWidth: 0 }}>
<div style={{ fontSize: 13, fontWeight: 700, color: 'var(--c-fg-1)', marginBottom: 2, lineHeight: 1.35 }}>{v.title}</div>
<div className="sub" style={{ fontSize: 11 }}>{v.date} · {d.name.split(' ').slice(0, 2).join(' ')}</div>
</div>
</div>
);
})}
</div>
</div>
{/* Upcoming appointment */}
{upcoming && upDoc && (
<div style={{ padding: '0 20px 18px' }}>
<SectionHeader title="Ближайший приём" pad="0 0 8px 0" />
<AppointmentCard appt={upcoming} doctor={upDoc} addr={clinic.addresses.find(a => a.id === upcoming.address)} onClick={() => nav.push('appt:' + upcoming.id)} />
</div>
)}
{/* Recommendations */}
<div style={{ padding: '0 0 18px' }}>
<SectionHeader title="Рекомендации" />
<div style={{ display: 'flex', gap: 10, overflowX: 'auto', padding: '0 20px 8px' }} className="noscroll">
{chronic.recommendations.map((r, i) => (
<div key={i} className="card" style={{
flexShrink: 0, width: 170, padding: 14,
}}>
<div style={{ fontSize: 28, marginBottom: 8, lineHeight: 1 }}>{r.icon}</div>
<div style={{ fontSize: 13, fontWeight: 700, marginBottom: 3, lineHeight: 1.3 }}>{r.title}</div>
<div className="sub" style={{ fontSize: 11, lineHeight: 1.4 }}>{r.sub}</div>
</div>
))}
</div>
</div>
{/* Book CTA */}
<div style={{ padding: '0 20px 18px' }}>
<button onClick={() => nav.push('booking-specs')} className="btn-p block">
<I.plus size={18} /> Записаться на осмотр
</button>
</div>
{/* Articles */}
<div style={{ padding: '0 0 8px' }}>
<SectionHeader title="Полезное чтение" action="Все" onAction={() => nav.push('articles')} />
<div style={{ display: 'flex', gap: 12, overflowX: 'auto', padding: '0 20px 8px' }} className="noscroll">
{articles.slice(0, 3).map(a => (
<button key={a.id} onClick={() => nav.push('article:' + a.id)} className="press card" style={{
flexShrink: 0, width: 200, padding: 0, overflow: 'hidden', textAlign: 'left',
}}>
<div style={{
height: 80, background: a.hero,
display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', padding: 10,
}}>
<span className="chip chip-warm" style={{ background: 'rgba(255,255,255,0.85)' }}>{a.tag}</span>
<span style={{ fontSize: 24, lineHeight: 1 }}>{a.emoji}</span>
</div>
<div style={{ padding: 12 }}>
<div style={{ fontSize: 13, fontWeight: 700, lineHeight: 1.3, marginBottom: 6, minHeight: 34 }}>{a.title}</div>
<div className="sub" style={{ fontSize: 11 }}>{a.mins} мин</div>
</div>
</button>
))}
</div>
</div>
</div>
);
}
export function HomeSplashScreen({ nav }) {
const { patient, doctors, appointments, articles } = CLINIC_DATA;
const firstName = patient.shortName.split(' ')[0];
const upcoming = appointments.find(a => a.status === 'upcoming');
const upDoc = upcoming && doctors.find(d => d.id === upcoming.doctor);
const article = articles[0];
return (
<div style={{ paddingBottom: 100 }}>
<div style={{ padding: '8px 20px 8px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<button onClick={() => nav.push('profile')} className="press" style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<div style={{ width: 34, height: 34, borderRadius: 999, background: 'var(--c-primary-200)' }} />
<span style={{ fontSize: 16, fontWeight: 600, color: 'var(--c-fg-1)' }}>Главная</span>
</button>
<button onClick={() => nav.push('notifications')} className="press" style={{ width: 40, height: 40, borderRadius: 999, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.bell size={22} style={{ color: 'var(--c-primary-darker)' }} />
</button>
</div>
<div style={{ padding: '4px 20px 14px' }}>
<h1 style={{ fontSize: 28, fontWeight: 800, lineHeight: 1.15, color: 'var(--c-fg-1)', margin: 0 }}>Добрый день, {firstName}!</h1>
</div>
<div style={{ padding: '0 20px 20px' }}>
<button onClick={() => nav.push('search')} className="press" style={{
width: '100%', display: 'flex', alignItems: 'center', gap: 12,
padding: '14px 16px', background: '#fff',
border: '1px solid var(--c-border)', borderRadius: 14,
textAlign: 'left',
}}>
<I.search size={18} style={{ color: 'var(--c-fg-3)' }} />
<span style={{ color: 'var(--c-fg-3)', fontSize: 15 }}>Поиск врача...</span>
</button>
</div>
<div style={{ padding: '0 20px 8px' }}>
<div style={{ fontSize: 14, fontWeight: 700, color: 'var(--c-fg-1)', marginBottom: 10 }}>Записи на прием</div>
{upcoming && upDoc && (
<button onClick={() => nav.push('appt:' + upcoming.id)} className="press" style={{
width: '100%', textAlign: 'left',
background: 'var(--c-primary-50)',
border: '1px solid var(--c-primary-100)',
borderRadius: 16, padding: 16, marginBottom: 10,
}}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
<span style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, fontWeight: 700, letterSpacing: .7, color: 'var(--c-primary-darker)' }}>
<span style={{ width: 6, height: 6, borderRadius: 999, background: 'var(--c-primary-darker)' }} />
БЛИЖАЙШАЯ ЗАПИСЬ
</span>
<span style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 12, color: 'var(--c-primary-darker)', fontWeight: 700 }}>
<I.star size={12} /> Активно
</span>
</div>
<div style={{ display: 'flex', gap: 12, alignItems: 'center', marginBottom: 10 }}>
<Avatar init={upDoc.init} size={48} />
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: 15, fontWeight: 700, color: 'var(--c-fg-1)' }}>{upDoc.name}</div>
<div style={{ fontSize: 13, color: 'var(--c-primary-darker)', marginTop: 2 }}>{upDoc.spec.split(' · ')[0]}</div>
</div>
</div>
<div style={{ display: 'flex', gap: 8, marginBottom: 10 }}>
<span style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '6px 12px', background: '#fff', border: '1px solid var(--c-primary-100)', borderRadius: 10, fontSize: 13, fontWeight: 600 }}>
<I.calendar size={14} style={{ color: 'var(--c-primary-darker)' }} /> {upcoming.date}
</span>
<span style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '6px 12px', background: '#fff', border: '1px solid var(--c-primary-100)', borderRadius: 10, fontSize: 13, fontWeight: 600 }}>
<I.clock size={14} style={{ color: 'var(--c-primary-darker)' }} /> {upcoming.time}
</span>
</div>
<I.pin size={16} style={{ color: 'var(--c-primary-darker)', opacity: .6 }} />
</button>
)}
<button onClick={() => nav.set('appts')} className="press" style={{
width: '100%', textAlign: 'left',
background: 'var(--c-primary-50)',
border: '1px solid var(--c-primary-100)',
borderRadius: 16, padding: 16, marginBottom: 10,
display: 'flex', gap: 14, alignItems: 'center',
}}>
<div style={{ width: 54, height: 54, borderRadius: 999, background: 'var(--c-primary-darker)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<I.calendar size={24} style={{ color: '#fff' }} />
</div>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: 11, fontWeight: 700, letterSpacing: .7, color: 'var(--c-primary-darker)', marginBottom: 4 }}>МОИ ПРИЕМЫ</div>
<div style={{ fontSize: 15, fontWeight: 700, color: 'var(--c-fg-1)', marginBottom: 2 }}>Ближайшие приемы</div>
<div style={{ fontSize: 12, color: 'var(--c-fg-3)', lineHeight: 1.35 }}>Просмотрите ваши предстоящие прием</div>
</div>
</button>
<button onClick={() => nav.push('booking-specs')} className="press" style={{
width: '100%', textAlign: 'left', position: 'relative', overflow: 'hidden',
background: 'var(--c-warm-100)',
borderRadius: 16, padding: 16, marginBottom: 18,
}}>
<div style={{ position: 'absolute', top: -20, right: -20, width: 90, height: 90, borderRadius: 999, background: 'rgba(255,255,255,0.35)' }} />
<div style={{ position: 'absolute', top: 30, right: 30, width: 40, height: 40, borderRadius: 999, background: 'rgba(255,255,255,0.25)' }} />
<div style={{ position: 'relative', display: 'flex', gap: 14, alignItems: 'center', marginBottom: 14 }}>
<div style={{ width: 48, height: 48, borderRadius: 999, background: 'var(--c-warm-text)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<I.calendar size={22} style={{ color: '#fff' }} />
</div>
<div style={{ fontSize: 16, fontWeight: 700, color: 'var(--c-fg-1)' }}>Записаться на прием</div>
</div>
<div style={{ position: 'relative', padding: 12, background: '#fff', borderRadius: 12, textAlign: 'center', fontSize: 14, fontWeight: 600, color: 'var(--c-fg-1)' }}>
Выбрать удобное время
</div>
</button>
</div>
<div style={{ padding: '0 20px 8px' }}>
<div style={{ fontSize: 14, fontWeight: 700, color: 'var(--c-fg-1)', marginBottom: 10 }}>Услуги и консультации</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2,1fr)', gap: 10, marginBottom: 18 }}>
<SplashTile icon={I.calendar} sub="Записаться на прием" main="К врачу" onClick={() => nav.push('booking-specs')} />
<SplashTile icon={I.chat} sub="Связаться с врачом в" main="Чате" onClick={() => nav.set('chat')} />
</div>
</div>
<div style={{ padding: '0 20px 20px' }}>
<div style={{ fontSize: 14, fontWeight: 700, color: 'var(--c-fg-1)', marginBottom: 10 }}>Полезная информация</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2,1fr)', gap: 10 }}>
<SplashTile icon={I.doc} sub="Статья" main={article.title.split(' ').slice(0,2).join(' ')} onClick={() => nav.push('article:' + article.id)} />
<SplashTile icon={I.file} sub="Все" main="Статьи" onClick={() => nav.push('articles')} />
<SplashTile icon={I.shield} sub="Информация" main="Цены" onClick={() => nav.push('prices')} />
<SplashTile icon={I.phone} sub="Информация" main="Контакты" onClick={() => nav.push('contacts')} />
</div>
</div>
</div>
);
}
function SplashTile({ icon: Ic, sub, main, onClick }) {
return (
<button onClick={onClick} className="press" style={{
background: 'var(--c-primary-50)',
border: '1px solid var(--c-primary-100)',
borderRadius: 16, padding: 16,
textAlign: 'left', minHeight: 120,
display: 'flex', flexDirection: 'column', justifyContent: 'space-between', gap: 12,
}}>
<div style={{ width: 40, height: 40, borderRadius: 999, background: 'var(--c-primary-darker)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Ic size={20} style={{ color: '#fff' }} />
</div>
<div>
<div style={{ fontSize: 12, color: 'var(--c-primary-darker)', marginBottom: 2 }}>{sub}</div>
<div style={{ fontSize: 15, fontWeight: 700, color: 'var(--c-fg-1)' }}>{main}</div>
</div>
</button>
);
}
export function HomeFeedScreen({ nav }) {
const { doctors, appointments, clinic, articles, recovery } = CLINIC_DATA;
const upcoming = appointments.find(a => a.status === 'upcoming');
const upDoc = upcoming && doctors.find(d => d.id === upcoming.doctor);
return (
<div style={{ paddingBottom: 100 }}>
<div style={{ padding: '8px 20px 12px' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div>
<div className="sub">18 апреля, суббота</div>
<div style={{ fontSize: 24, fontWeight: 700 }}>Как Ваше самочувствие?</div>
</div>
<button onClick={() => nav.push('profile')} className="press">
<Avatar init="АС" size={42} />
</button>
</div>
</div>
<div style={{ padding: '0 16px' }}>
<button onClick={() => nav.push('recovery')} className="press card" style={{
width: '100%', textAlign: 'left', padding: 18, marginBottom: 14,
background: 'linear-gradient(135deg,#E3F4F2,#F2FAF9)',
border: '1px solid var(--c-primary-200)',
}}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<div style={{ width: 36, height: 36, borderRadius: 10, background: 'var(--c-primary-darker)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<I.shield size={18} style={{ color: '#fff' }} />
</div>
<div>
<div style={{ fontWeight: 700, fontSize: 14 }}>Восстановление</div>
<div className="sub" style={{ fontSize: 12 }}>{recovery.op}</div>
</div>
</div>
<span className="chip">День {recovery.dayNow} из {recovery.totalDays}</span>
</div>
<div style={{ height: 6, background: 'rgba(255,255,255,0.7)', borderRadius: 999, overflow: 'hidden', marginBottom: 12 }}>
<div style={{ width: `${recovery.dayNow/recovery.totalDays*100}%`, height: '100%', background: 'var(--c-primary-darker)', borderRadius: 999 }} />
</div>
<div style={{ fontSize: 13, color: 'var(--c-fg-2)' }}>
Сегодня: <strong>осмотр хирурга, снятие корочек</strong>
</div>
</button>
<div className="card" style={{ padding: 14, marginBottom: 14, display: 'flex', gap: 12, alignItems: 'center' }}>
<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 }}>Амоксиклав 625 мг</div>
<div className="sub" style={{ fontSize: 12 }}>Принять в 20:00 через 2 часа</div>
</div>
<button className="btn-s" style={{ padding: '8px 12px', fontSize: 13 }}>Принял</button>
</div>
{upcoming && upDoc && (
<>
<SectionHeader title="Ближайший приём" pad="4px 4px 8px" />
<AppointmentCard appt={upcoming} doctor={upDoc} addr={clinic.addresses.find(a=>a.id===upcoming.address)} onClick={() => nav.push('appt:' + upcoming.id)} />
</>
)}
<button onClick={() => nav.push('booking-specs')} className="press" style={{
width: '100%', marginTop: 14, padding: '14px 18px', borderRadius: 16,
background: 'var(--c-accent)', color: '#fff', fontWeight: 700, fontSize: 15,
display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
}}>
<I.plus size={20} /> Записаться на приём
</button>
</div>
<div style={{ padding: '18px 20px 8px' }}>
<SectionHeader title="Полезно прочитать" action="Все" onAction={() => nav.push('articles')} pad="0 0 0 0" />
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
{articles.slice(0,3).map((a)=>(
<button key={a.id} onClick={() => nav.push('article:' + a.id)} className="press card" style={{ display: 'flex', gap: 12, alignItems: 'center', padding: 14, textAlign: 'left' }}>
<div style={{ width: 56, height: 56, borderRadius: 12, background: a.hero, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 28 }}>
{a.emoji}
</div>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 11, color: 'var(--c-primary-dark)', fontWeight: 700, textTransform: 'uppercase', letterSpacing: .5, marginBottom: 3 }}>{a.tag}</div>
<div style={{ fontSize: 14, fontWeight: 700, lineHeight: 1.3, marginBottom: 3 }}>{a.title}</div>
<div className="sub" style={{ fontSize: 12 }}>{a.author} · {a.mins} мин</div>
</div>
</button>
))}
</div>
</div>
</div>
);
}