anastasis-webui: hotfix behavior of back button on country selection screen

This commit is contained in:
Florian Dold 2021-11-08 16:10:22 +01:00
parent 8da58bd494
commit 16662b194d
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
2 changed files with 119 additions and 71 deletions

View File

@ -1,58 +1,81 @@
/* eslint-disable @typescript-eslint/camelcase */
import { BackupStates, RecoveryStates } from "anastasis-core";
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame, withProcessLabel } from "./index";
export function ContinentSelectionScreen(): VNode {
const reducer = useAnastasisContext()
const reducer = useAnastasisContext();
// FIXME: remove this when #7056 is fixed
const countryFromReducer = (reducer?.currentReducerState as any).selected_country || ""
const [countryCode, setCountryCode] = useState( countryFromReducer )
const countryFromReducer =
(reducer?.currentReducerState as any).selected_country || "";
const [countryCode, setCountryCode] = useState(countryFromReducer);
if (!reducer || !reducer.currentReducerState || !("continents" in reducer.currentReducerState)) {
return <div />
if (
!reducer ||
!reducer.currentReducerState ||
!("continents" in reducer.currentReducerState)
) {
return <div />;
}
const selectContinent = (continent: string): void => {
reducer.transition("select_continent", { continent })
reducer.transition("select_continent", { continent });
};
const selectCountry = (country: string): void => {
setCountryCode(country)
setCountryCode(country);
};
const continentList = reducer.currentReducerState.continents || [];
const countryList = reducer.currentReducerState.countries || [];
const theContinent = reducer.currentReducerState.selected_continent || ""
const theContinent = reducer.currentReducerState.selected_continent || "";
// const cc = reducer.currentReducerState.selected_country || "";
const theCountry = countryList.find(c => c.code === countryCode)
const theCountry = countryList.find((c) => c.code === countryCode);
const selectCountryAction = () => {
//selection should be when the select box changes it value
if (!theCountry) return;
reducer.transition("select_country", {
country_code: countryCode,
currencies: [theCountry.currency],
})
}
});
};
// const step1 = reducer.currentReducerState.backup_state === BackupStates.ContinentSelecting ||
// reducer.currentReducerState.recovery_state === RecoveryStates.ContinentSelecting;
const errors = !theCountry ? "Select a country" : undefined
const errors = !theCountry ? "Select a country" : undefined;
const handleBack = async () => {
// We want to go to the start, even if we already selected
// a country.
// FIXME: What if we don't want to lose all information here?
// Can we do some kind of soft reset?
reducer.reset();
};
return (
<AnastasisClientFrame hideNext={errors} title={withProcessLabel(reducer, "Where do you live?")} onNext={selectCountryAction}>
<AnastasisClientFrame
hideNext={errors}
title={withProcessLabel(reducer, "Where do you live?")}
onNext={selectCountryAction}
onBack={handleBack}
>
<div class="columns">
<div class="column is-one-third">
<div class="field">
<label class="label">Continent</label>
<div class="control is-expanded has-icons-left">
<div class="select is-fullwidth">
<select onChange={(e) => selectContinent(e.currentTarget.value)} value={theContinent} >
<option key="none" disabled selected value=""> Choose a continent </option>
{continentList.map(prov => (
<select
onChange={(e) => selectContinent(e.currentTarget.value)}
value={theContinent}
>
<option key="none" disabled selected value="">
{" "}
Choose a continent{" "}
</option>
{continentList.map((prov) => (
<option key={prov.name} value={prov.name}>
{prov.name}
</option>
@ -69,9 +92,16 @@ export function ContinentSelectionScreen(): VNode {
<label class="label">Country</label>
<div class="control is-expanded has-icons-left">
<div class="select is-fullwidth">
<select onChange={(e) => selectCountry((e.target as any).value)} disabled={!theContinent} value={theCountry?.code || ""}>
<option key="none" disabled selected value=""> Choose a country </option>
{countryList.map(prov => (
<select
onChange={(e) => selectCountry((e.target as any).value)}
disabled={!theContinent}
value={theCountry?.code || ""}
>
<option key="none" disabled selected value="">
{" "}
Choose a country{" "}
</option>
{countryList.map((prov) => (
<option key={prov.name} value={prov.code}>
{prov.name}
</option>
@ -94,11 +124,14 @@ export function ContinentSelectionScreen(): VNode {
<div class="column is-two-third">
<p>
Your location will help us to determine which personal information
ask you for the next step.
to ask you for the next step.
</p>
<p>
You should choose the country that issued most of your long-term
legal documents or personal identifiers.
</p>
</div>
</div>
</AnastasisClientFrame>
);
}

View File

@ -1,23 +1,22 @@
import { BackupStates, RecoveryStates } from "anastasis-core";
import {
BackupStates,
RecoveryStates
} from "anastasis-core";
import {
ComponentChildren, Fragment,
ComponentChildren,
Fragment,
FunctionalComponent,
h,
VNode
VNode,
} from "preact";
import {
useErrorBoundary
} from "preact/hooks";
import { useErrorBoundary } from "preact/hooks";
import { AsyncButton } from "../../components/AsyncButton";
import { Menu } from "../../components/menu";
import { Notifications } from "../../components/Notifications";
import { AnastasisProvider, useAnastasisContext } from "../../context/anastasis";
import {
AnastasisProvider,
useAnastasisContext,
} from "../../context/anastasis";
import {
AnastasisReducerApi,
useAnastasisReducer
useAnastasisReducer,
} from "../../hooks/use-anastasis-reducer";
import { AttributeEntryScreen } from "./AttributeEntryScreen";
import { AuthenticationEditorScreen } from "./AuthenticationEditorScreen";
@ -50,6 +49,10 @@ export function withProcessLabel(
interface AnastasisClientFrameProps {
onNext?(): void;
/**
* Override for the "back" functionality.
*/
onBack?(): Promise<void>;
title: string;
children: ComponentChildren;
/**
@ -116,9 +119,27 @@ export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
<section class="section is-main-section">
{props.children}
{!props.hideNav ? (
<div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
<button class="button" onClick={() => reducer.back()}>Back</button>
<AsyncButton class="button is-info" data-tooltip={props.hideNext} onClick={next} disabled={props.hideNext !== undefined}>Next</AsyncButton>
<div
style={{
marginTop: "2em",
display: "flex",
justifyContent: "space-between",
}}
>
<button
class="button"
onClick={() => (props.onBack ?? reducer.back)()}
>
Back
</button>
<AsyncButton
class="button is-info"
data-tooltip={props.hideNext}
onClick={next}
disabled={props.hideNext !== undefined}
>
Next
</AsyncButton>
</div>
) : null}
</section>
@ -139,7 +160,7 @@ const AnastasisClient: FunctionalComponent = () => {
};
function AnastasisClientImpl(): VNode {
const reducer = useAnastasisContext()
const reducer = useAnastasisContext();
if (!reducer) {
return <p>Fatal: Reducer must be in context.</p>;
}
@ -155,27 +176,19 @@ function AnastasisClientImpl(): VNode {
state.backup_state === BackupStates.CountrySelecting ||
state.recovery_state === RecoveryStates.CountrySelecting
) {
return (
<ContinentSelectionScreen />
);
return <ContinentSelectionScreen />;
}
if (
state.backup_state === BackupStates.UserAttributesCollecting ||
state.recovery_state === RecoveryStates.UserAttributesCollecting
) {
return (
<AttributeEntryScreen />
);
return <AttributeEntryScreen />;
}
if (state.backup_state === BackupStates.AuthenticationsEditing) {
return (
<AuthenticationEditorScreen />
);
return <AuthenticationEditorScreen />;
}
if (state.backup_state === BackupStates.PoliciesReviewing) {
return (
<ReviewPoliciesScreen />
);
return <ReviewPoliciesScreen />;
}
if (state.backup_state === BackupStates.SecretEditing) {
return <SecretEditorScreen />;
@ -194,15 +207,11 @@ function AnastasisClientImpl(): VNode {
}
if (state.recovery_state === RecoveryStates.SecretSelecting) {
return (
<SecretSelectionScreen />
);
return <SecretSelectionScreen />;
}
if (state.recovery_state === RecoveryStates.ChallengeSelecting) {
return (
<ChallengeOverviewScreen />
);
return <ChallengeOverviewScreen />;
}
if (state.recovery_state === RecoveryStates.ChallengeSolving) {
@ -210,9 +219,7 @@ function AnastasisClientImpl(): VNode {
}
if (state.recovery_state === RecoveryStates.RecoveryFinished) {
return (
<RecoveryFinishedScreen />
);
return <RecoveryFinishedScreen />;
}
if (state.recovery_state === RecoveryStates.ChallengePaying) {
return <ChallengePayingScreen />;
@ -222,7 +229,9 @@ function AnastasisClientImpl(): VNode {
<AnastasisClientFrame hideNav title="Bug">
<p>Bug: Unknown state.</p>
<div class="buttons is-right">
<button class="button" onClick={() => reducer.reset()}>Reset</button>
<button class="button" onClick={() => reducer.reset()}>
Reset
</button>
</div>
</AnastasisClientFrame>
);
@ -234,11 +243,17 @@ function AnastasisClientImpl(): VNode {
function ErrorBanner(): VNode | null {
const reducer = useAnastasisContext();
if (!reducer || !reducer.currentError) return null;
return (<Notifications removeNotification={reducer.dismissError} notifications={[{
return (
<Notifications
removeNotification={reducer.dismissError}
notifications={[
{
type: "ERROR",
message: `Error code: ${reducer.currentError.code}`,
description: reducer.currentError.hint
}]} />
description: reducer.currentError.hint,
},
]}
/>
);
}