feat(web): patient web app with ЕМИАС (demo) and anonymous sign-in

A second channel to the same dialog engine as the Telegram bot: consent,
onboarding, scales and check-ins come from app/dialog; the bot is unchanged.

- API: /auth/emias (doctor's one-time connect code via EmiasMock),
  /auth/emias/demo (synthetic personas), /auth/anonymous (random token,
  nothing stored in the identity DB), /crisis/resources from crisis.yaml
- web/: React + TS + Vite, mobile-first, safe areas, hash routing,
  tokens and texts isolated for a Capacitor mobile build

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-04 07:57:00 +03:00
co-authored by Claude Opus 5.5
parent 4d331e4c05
commit b8a93ce9d4
28 changed files with 4697 additions and 5 deletions
+39
View File
@@ -0,0 +1,39 @@
import "@fontsource/golos-text/400.css";
import "@fontsource/golos-text/500.css";
import "@fontsource/golos-text/600.css";
import "./theme/tokens.css";
import "./theme/global.css";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { HashRouter, Navigate, Route, Routes } from "react-router-dom";
import { AnonymousSignIn } from "./screens/AnonymousSignIn";
import { Chat } from "./screens/Chat";
import { EmiasSignIn } from "./screens/EmiasSignIn";
import { Welcome } from "./screens/Welcome";
import { SessionProvider, useSession } from "./session/SessionContext";
// Hash routing works the same on a static host, file:// and inside the Capacitor WebView.
function AppRoutes() {
const { session } = useSession();
return (
<Routes>
<Route path="/" element={session ? <Navigate to="/chat" replace /> : <Welcome />} />
<Route path="/emias" element={<EmiasSignIn />} />
<Route path="/anonymous" element={<AnonymousSignIn />} />
<Route path="/chat" element={<Chat />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<SessionProvider>
<HashRouter>
<AppRoutes />
</HashRouter>
</SessionProvider>
</StrictMode>,
);