feat(ui): единый дизайн всех страниц по образцу кабинета врача #88
@@ -204,6 +204,7 @@ export const ru = {
|
|||||||
toIntake: "Пройти первичный опрос",
|
toIntake: "Пройти первичный опрос",
|
||||||
},
|
},
|
||||||
flow: {
|
flow: {
|
||||||
|
home: "На главный экран",
|
||||||
question: (n: number, total: number) => `Вопрос ${n} из ${total}`,
|
question: (n: number, total: number) => `Вопрос ${n} из ${total}`,
|
||||||
period: "За последний месяц",
|
period: "За последний месяц",
|
||||||
textPlaceholder: "Напишите несколько слов",
|
textPlaceholder: "Напишите несколько слов",
|
||||||
|
|||||||
+14
-15
@@ -265,7 +265,7 @@ function FreeText({
|
|||||||
{skip.label}
|
{skip.label}
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button type="button" className="btn btn--ghost" onClick={onExit}>
|
<button type="button" className="btn btn--ghost" disabled={busy} onClick={onExit}>
|
||||||
{ru.flow.exit}
|
{ru.flow.exit}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@@ -362,6 +362,7 @@ function SurveyAct({
|
|||||||
press,
|
press,
|
||||||
say,
|
say,
|
||||||
onPause,
|
onPause,
|
||||||
|
onHome,
|
||||||
}: {
|
}: {
|
||||||
step: Survey;
|
step: Survey;
|
||||||
stepKey: string;
|
stepKey: string;
|
||||||
@@ -369,6 +370,7 @@ function SurveyAct({
|
|||||||
press: (b: DialogButton) => void;
|
press: (b: DialogButton) => void;
|
||||||
say: (text: string) => void;
|
say: (text: string) => void;
|
||||||
onPause: (b: DialogButton) => void;
|
onPause: (b: DialogButton) => void;
|
||||||
|
onHome: () => void;
|
||||||
}) {
|
}) {
|
||||||
let answer: ReactNode;
|
let answer: ReactNode;
|
||||||
switch (step.input) {
|
switch (step.input) {
|
||||||
@@ -381,7 +383,7 @@ function SurveyAct({
|
|||||||
break;
|
break;
|
||||||
case "text":
|
case "text":
|
||||||
answer = (
|
answer = (
|
||||||
<FreeText key={stepKey} skip={step.skip} busy={busy} onSend={say} onSkip={press} onExit={() => undefined} />
|
<FreeText key={stepKey} skip={step.skip} busy={busy} onSend={say} onSkip={press} onExit={onHome} />
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -522,17 +524,6 @@ export function Flow() {
|
|||||||
navigate("/today", { replace: true });
|
navigate("/today", { replace: true });
|
||||||
}, [step, stepKey, navigate, toast]);
|
}, [step, stepKey, navigate, toast]);
|
||||||
|
|
||||||
// Questionnaire: answers are saved on the server per question, and there is no going back to change one.
|
|
||||||
// The browser «back» is absorbed by a duplicate history entry of this same screen.
|
|
||||||
const testing = step?.kind === "survey" || step?.kind === "choice" || step?.kind === "consent";
|
|
||||||
useEffect(() => {
|
|
||||||
if (!testing) return;
|
|
||||||
window.history.pushState(null, "", window.location.href);
|
|
||||||
const stay = () => window.history.pushState(null, "", window.location.href);
|
|
||||||
window.addEventListener("popstate", stay);
|
|
||||||
return () => window.removeEventListener("popstate", stay);
|
|
||||||
}, [testing]);
|
|
||||||
|
|
||||||
const press = (b: DialogButton) => void dialog.send({ type: "button", button: b.data }, b.label);
|
const press = (b: DialogButton) => void dialog.send({ type: "button", button: b.data }, b.label);
|
||||||
// «Продолжить позже»: answers are already saved on the server — pause and go straight home, no confirmation.
|
// «Продолжить позже»: answers are already saved on the server — pause and go straight home, no confirmation.
|
||||||
const pause = (b: DialogButton) =>
|
const pause = (b: DialogButton) =>
|
||||||
@@ -588,7 +579,7 @@ export function Flow() {
|
|||||||
) : item ? (
|
) : item ? (
|
||||||
<Progress n={item.index} total={item.total} adaptive={item.adaptive} />
|
<Progress n={item.index} total={item.total} adaptive={item.adaptive} />
|
||||||
) : null;
|
) : null;
|
||||||
const top = <TopBar onBack={testing ? undefined : home}>{progress}</TopBar>;
|
const top = progress ? <TopBar>{progress}</TopBar> : null;
|
||||||
// Phone: one column. Desktop: question and context on the left, answers and actions on the right.
|
// Phone: one column. Desktop: question and context on the left, answers and actions on the right.
|
||||||
let lead: ReactNode;
|
let lead: ReactNode;
|
||||||
let act: ReactNode;
|
let act: ReactNode;
|
||||||
@@ -702,7 +693,7 @@ export function Flow() {
|
|||||||
break;
|
break;
|
||||||
case "survey":
|
case "survey":
|
||||||
lead = <SurveyLead step={step} catalog={catalog} />;
|
lead = <SurveyLead step={step} catalog={catalog} />;
|
||||||
act = <SurveyAct step={step} stepKey={stepKey} busy={dialog.busy} press={press} say={say} onPause={pause} />;
|
act = <SurveyAct step={step} stepKey={stepKey} busy={dialog.busy} press={press} say={say} onPause={pause} onHome={home} />;
|
||||||
break;
|
break;
|
||||||
case "choice":
|
case "choice":
|
||||||
lead = <Head title={step.title} lead={step.lead} />;
|
lead = <Head title={step.title} lead={step.lead} />;
|
||||||
@@ -725,6 +716,14 @@ export function Flow() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AppShell focus bare sos={step?.kind !== "crisis"}>
|
<AppShell focus bare sos={step?.kind !== "crisis"}>
|
||||||
|
<nav className="flow-nav" aria-label={ru.flow.home}>
|
||||||
|
{/* Leaving does not send an answer or clear pending: Today can reopen this same question.
|
||||||
|
Wait for an in-flight answer before leaving so its result has reached the shared dialog. */}
|
||||||
|
<button type="button" className="btn btn--ghost btn--auto" disabled={dialog.busy} onClick={home}>
|
||||||
|
<Icon name="home" size={20} />
|
||||||
|
{ru.flow.home}
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
{content}
|
{content}
|
||||||
</AppShell>
|
</AppShell>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user