CI / ruff · pytest (pull_request) Failing after 2m33s
- POST /auth/demo/fresh + «Демо: войти как Андрей» on the welcome screen: every sign-in gets a fresh private copy of veteran Andrey (consent, prescription, ЕМИАС record) and lands in the chat — no codes, nobody's crisis or half-done questionnaire leaks into another viewer. - Initial screening switch: SCREENING_ENABLED env default + /demo/settings + a toggle in the demo console; off → after consent straight to the chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
119 lines
3.9 KiB
TypeScript
119 lines
3.9 KiB
TypeScript
import { useState } from "react";
|
|
import { useNavigate } from "react-router-dom";
|
|
|
|
import { api } from "../api/client";
|
|
import { useSession } from "../session/SessionContext";
|
|
|
|
import { telHref, useHelp } from "../components/HelpSheet";
|
|
import { Icon, LogoMark } from "../components/Icon";
|
|
import { ru } from "../content/ru";
|
|
|
|
// A1 · Вход: без сайдбара, одна карточка по центру. ЕМИАС — основной путь, анонимный — по желанию
|
|
export function Welcome() {
|
|
const navigate = useNavigate();
|
|
const { signIn } = useSession();
|
|
const [demoBusy, setDemoBusy] = useState(false);
|
|
const [demoError, setDemoError] = useState(false);
|
|
const { resources, open } = useHelp();
|
|
const t = ru.welcome;
|
|
const emergency = resources[0];
|
|
|
|
// Presentation: one click → a fresh private demo patient → the chat.
|
|
const demo = async () => {
|
|
setDemoBusy(true);
|
|
setDemoError(false);
|
|
try {
|
|
signIn(await api.signInDemoFresh());
|
|
navigate("/messages", { replace: true });
|
|
} catch {
|
|
setDemoError(true);
|
|
setDemoBusy(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="signin-page">
|
|
<main className="signin" id="main">
|
|
<div className="signin__brand">
|
|
<LogoMark size={44} />
|
|
<span>
|
|
<span className="signin__name">{ru.product.name}</span>
|
|
<span className="signin__tag">{ru.product.tagline}</span>
|
|
</span>
|
|
</div>
|
|
|
|
<section className="signin__card">
|
|
<h1 className="h1">{t.title}</h1>
|
|
|
|
<button type="button" className="entry entry--emias" onClick={demo} disabled={demoBusy}>
|
|
<span className="entry__top">
|
|
<span className="tile-icon tile-icon--teal">
|
|
<Icon name="check" size={26} />
|
|
</span>
|
|
<span className="entry__title">
|
|
{demoBusy ? t.demo.busy : t.demo.title}
|
|
<Icon name="chevronRight" />
|
|
</span>
|
|
</span>
|
|
<span className="muted small">{t.demo.text}</span>
|
|
</button>
|
|
{demoError && (
|
|
<p className="muted small center" role="alert">
|
|
{t.demo.error}
|
|
</p>
|
|
)}
|
|
|
|
<div className="divider" role="separator">
|
|
<span>{t.or}</span>
|
|
</div>
|
|
|
|
<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="entry__title">
|
|
{t.emias.title}
|
|
<Icon name="chevronRight" />
|
|
</span>
|
|
</span>
|
|
<ul className="signin__perks">
|
|
{t.emias.perks.map((p) => (
|
|
<li key={p}>
|
|
<Icon name="check" size={18} />
|
|
{p}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</button>
|
|
|
|
<div className="divider" role="separator">
|
|
<span>{t.or}</span>
|
|
</div>
|
|
|
|
<div className="stack stack--sm">
|
|
<button type="button" className="btn btn--ghost" onClick={() => navigate("/anonymous")}>
|
|
<Icon name="lock" size={20} />
|
|
{t.anonymous.title}
|
|
</button>
|
|
<p className="muted small center">{t.anonymous.text}</p>
|
|
</div>
|
|
</section>
|
|
|
|
<div className="signin__foot">
|
|
<button type="button" className="signin__sos" onClick={open}>
|
|
<Icon name="phone" size={18} />
|
|
{ru.help.block}
|
|
</button>
|
|
{emergency && (
|
|
<a className="signin__tel" href={telHref(emergency.phone)}>
|
|
{emergency.phone}
|
|
</a>
|
|
)}
|
|
</div>
|
|
<p className="muted small center">{t.disclaimer}</p>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|