Files
PTSRaiAgent/web/src/screens/Welcome.tsx
T
ElebobaandClaude Opus 5.5 cdd5ad9cde
CI / ruff · pytest (pull_request) Failing after 2m33s
feat: presentation demo mode — one-click private demo patient, screening on/off switch
- 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>
2026-10-04 21:01:05 +03:00

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>
);
}