feat(web): screens from docs/mock — focus flow, today, meds, doctor, profile
- /flow renders the dialog engine's current step as a mock screen (consent,
age, onboarding and scales with progress, mood 0–10, free text, dose
reminder, crisis with hotlines and breathing, safety plan), so every
engine scenario gets the design without duplicating its logic
- today / meds / doctor / profile / messages tabs; navy sidebar and
emergency rail on desktop, emergency block and tab bar on phones
- API: GET /me/{token}/today (today's doses, week marks, next visit, demo
clock time); demo ЕМИАС sign-in seeds the persona's synthetic profile and
prescription from the dashboard fixtures
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+36
-128
@@ -4,142 +4,50 @@ import { AppShell } from "../components/AppShell";
|
||||
import { Icon } from "../components/Icon";
|
||||
import { ru } from "../content/ru";
|
||||
|
||||
const SCALE = [1, 2, 3, 4, 5] as const;
|
||||
const WEEK = [38, 52, 46, 60, 58, 72, 80]; // illustrative trend, %
|
||||
|
||||
function Facts({ items }: { items: readonly { ok: boolean; text: string }[] }) {
|
||||
return (
|
||||
<ul className="facts">
|
||||
{items.map((f) => (
|
||||
<li key={f.text} className={f.ok ? "fact" : "fact fact--no"}>
|
||||
<Icon name={f.ok ? "check" : "minus"} size={18} />
|
||||
<span>{f.text}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
// Illustration of a day with the service (decorative: the same facts are stated in text).
|
||||
function DayPreview() {
|
||||
const d = ru.welcome.day;
|
||||
return (
|
||||
<figure className="day" aria-hidden="true">
|
||||
<figcaption className="day__caption">{d.caption}</figcaption>
|
||||
<ol className="day__list">
|
||||
<li className="day__item day__item--meds">
|
||||
<span className="day__time">{d.meds.time}</span>
|
||||
<div className="day__card">
|
||||
<span className="day__track">
|
||||
<Icon name="pill" size={16} />
|
||||
{d.meds.track}
|
||||
</span>
|
||||
<div className="day__row">
|
||||
<span className="day__text">{d.meds.text}</span>
|
||||
<span className="day__done">
|
||||
<Icon name="check" size={16} />
|
||||
{d.meds.done}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li className="day__item day__item--mood">
|
||||
<span className="day__time">{d.mood.time}</span>
|
||||
<div className="day__card">
|
||||
<span className="day__track">
|
||||
<Icon name="pulse" size={16} />
|
||||
{d.mood.track}
|
||||
</span>
|
||||
<span className="day__text">{d.mood.text}</span>
|
||||
<div className="scale">
|
||||
{SCALE.map((n) => (
|
||||
<span key={n} className={`scale__dot scale__dot--${n}${n === 4 ? " is-picked" : ""}`}>
|
||||
{n}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="scale__ends">
|
||||
<span>{d.mood.low}</span>
|
||||
<span>{d.mood.high}</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li className="day__item day__item--doctor">
|
||||
<span className="day__time">{d.doctor.time}</span>
|
||||
<div className="day__card">
|
||||
<span className="day__track">
|
||||
<Icon name="doctor" size={16} />
|
||||
{d.doctor.track}
|
||||
</span>
|
||||
<div className="day__row">
|
||||
<span className="day__text">{d.doctor.text}</span>
|
||||
<span className="spark">
|
||||
{WEEK.map((v, i) => (
|
||||
<i key={i} style={{ height: `${v}%` }} />
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</figure>
|
||||
);
|
||||
}
|
||||
|
||||
// A1 · Выбор способа входа
|
||||
export function Welcome() {
|
||||
const navigate = useNavigate();
|
||||
const t = ru.welcome;
|
||||
|
||||
return (
|
||||
<AppShell>
|
||||
<main className="welcome" id="main">
|
||||
<div className="welcome__inner">
|
||||
<section className="welcome__intro" aria-labelledby="welcome-title">
|
||||
<h1 id="welcome-title" className="display">
|
||||
{t.title}
|
||||
</h1>
|
||||
<p className="lead">{t.lead}</p>
|
||||
</section>
|
||||
<AppShell signedIn={false}>
|
||||
<div className="stack">
|
||||
<header className="head">
|
||||
<h1 className="h1">{t.title}</h1>
|
||||
<p className="lead">{t.lead}</p>
|
||||
</header>
|
||||
|
||||
<section className="signin" aria-labelledby="choice-title">
|
||||
<h2 id="choice-title" className="signin__title">
|
||||
{t.choose}
|
||||
</h2>
|
||||
<div className="entry-grid">
|
||||
<button type="button" className="entry entry--emias" onClick={() => navigate("/emias")}>
|
||||
<span className="entry__top">
|
||||
<span className="tile-icon tile-icon--teal">
|
||||
<Icon name="docPlus" size={26} />
|
||||
</span>
|
||||
<span className="chip chip--teal">{ru.common.recommended}</span>
|
||||
</span>
|
||||
<span className="entry__title">
|
||||
{t.emias.title}
|
||||
<Icon name="chevronRight" />
|
||||
</span>
|
||||
<span className="entry__text">{t.emias.text}</span>
|
||||
</button>
|
||||
|
||||
<article className="option option--emias">
|
||||
<div className="option__head">
|
||||
<span className="option__icon">
|
||||
<Icon name="doctor" size={22} />
|
||||
</span>
|
||||
<h3 className="option__title">{t.emias.title}</h3>
|
||||
<span className="badge">{t.emias.badge}</span>
|
||||
</div>
|
||||
<Facts items={t.emias.facts} />
|
||||
<button type="button" className="btn btn--primary btn--block" onClick={() => navigate("/emias")}>
|
||||
{t.emias.action}
|
||||
</button>
|
||||
</article>
|
||||
|
||||
<article className="option option--anon">
|
||||
<div className="option__head">
|
||||
<span className="option__icon">
|
||||
<Icon name="lock" size={22} />
|
||||
</span>
|
||||
<h3 className="option__title">{t.anonymous.title}</h3>
|
||||
</div>
|
||||
<Facts items={t.anonymous.facts} />
|
||||
<button type="button" className="btn btn--secondary btn--block" onClick={() => navigate("/anonymous")}>
|
||||
{t.anonymous.action}
|
||||
</button>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<div className="welcome__aside">
|
||||
<DayPreview />
|
||||
<p className="disclaimer">{t.disclaimer}</p>
|
||||
</div>
|
||||
<button type="button" className="entry" onClick={() => navigate("/anonymous")}>
|
||||
<span className="entry__top">
|
||||
<span className="tile-icon">
|
||||
<Icon name="lock" size={26} />
|
||||
</span>
|
||||
</span>
|
||||
<span className="entry__title">
|
||||
{t.anonymous.title}
|
||||
<Icon name="chevronRight" />
|
||||
</span>
|
||||
<span className="entry__text">{t.anonymous.text}</span>
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<p className="muted small">{t.disclaimer}</p>
|
||||
</div>
|
||||
</AppShell>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user