aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/anastasis-webui/src/components/fields/DateInput.tsx4
-rw-r--r--packages/anastasis-webui/src/components/fields/NumberInput.tsx41
-rw-r--r--packages/anastasis-webui/src/components/fields/TextInput.tsx (renamed from packages/anastasis-webui/src/components/fields/LabeledInput.tsx)4
-rw-r--r--packages/anastasis-webui/src/components/menu/SideBar.tsx43
-rw-r--r--packages/anastasis-webui/src/components/picker/DatePicker.tsx10
-rw-r--r--packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx28
-rw-r--r--packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx25
-rw-r--r--packages/anastasis-webui/src/pages/home/AuthMethodEmailSetup.tsx4
-rw-r--r--packages/anastasis-webui/src/pages/home/AuthMethodPostSetup.tsx12
-rw-r--r--packages/anastasis-webui/src/pages/home/AuthMethodQuestionSetup.tsx6
-rw-r--r--packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx134
-rw-r--r--packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx118
-rw-r--r--packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx1
-rw-r--r--packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx2
-rw-r--r--packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx6
-rw-r--r--packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx116
-rw-r--r--packages/anastasis-webui/src/pages/home/SolveEmailEntry.tsx26
-rw-r--r--packages/anastasis-webui/src/pages/home/SolvePostEntry.tsx24
-rw-r--r--packages/anastasis-webui/src/pages/home/SolveQuestionEntry.tsx24
-rw-r--r--packages/anastasis-webui/src/pages/home/SolveScreen.tsx121
-rw-r--r--packages/anastasis-webui/src/pages/home/SolveSmsEntry.tsx26
-rw-r--r--packages/anastasis-webui/src/pages/home/SolveUnsupportedEntry.tsx12
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx14
23 files changed, 521 insertions, 280 deletions
diff --git a/packages/anastasis-webui/src/components/fields/DateInput.tsx b/packages/anastasis-webui/src/components/fields/DateInput.tsx
index c45acc6d2..e1c354f7b 100644
--- a/packages/anastasis-webui/src/components/fields/DateInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/DateInput.tsx
@@ -8,6 +8,7 @@ export interface DateInputProps {
grabFocus?: boolean;
tooltip?: string;
error?: string;
+ years?: Array<number>;
bind: [string, (x: string) => void];
}
@@ -19,7 +20,7 @@ export function DateInput(props: DateInputProps): VNode {
}
}, [props.grabFocus]);
const [opened, setOpened2] = useState(false)
- function setOpened(v: boolean) {
+ function setOpened(v: boolean): void {
console.log('dale', v)
setOpened2(v)
}
@@ -50,6 +51,7 @@ export function DateInput(props: DateInputProps): VNode {
{showError && <p class="help is-danger">{props.error}</p>}
<DatePicker
opened={opened}
+ years={props.years}
closeFunction={() => setOpened(false)}
dateReceiver={(d) => {
setDirty(true)
diff --git a/packages/anastasis-webui/src/components/fields/NumberInput.tsx b/packages/anastasis-webui/src/components/fields/NumberInput.tsx
new file mode 100644
index 000000000..af9bbe66b
--- /dev/null
+++ b/packages/anastasis-webui/src/components/fields/NumberInput.tsx
@@ -0,0 +1,41 @@
+import { h, VNode } from "preact";
+import { useLayoutEffect, useRef, useState } from "preact/hooks";
+
+export interface TextInputProps {
+ label: string;
+ grabFocus?: boolean;
+ error?: string;
+ tooltip?: string;
+ bind: [string, (x: string) => void];
+}
+
+export function NumberInput(props: TextInputProps): VNode {
+ const inputRef = useRef<HTMLInputElement>(null);
+ useLayoutEffect(() => {
+ if (props.grabFocus) {
+ inputRef.current?.focus();
+ }
+ }, [props.grabFocus]);
+ const value = props.bind[0];
+ const [dirty, setDirty] = useState(false)
+ const showError = dirty && props.error
+ return (<div class="field">
+ <label class="label">
+ {props.label}
+ {props.tooltip && <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
+ <i class="mdi mdi-information" />
+ </span>}
+ </label>
+ <div class="control has-icons-right">
+ <input
+ value={value}
+ type="number"
+ class={showError ? 'input is-danger' : 'input'}
+ onChange={(e) => {setDirty(true); props.bind[1]((e.target as HTMLInputElement).value)}}
+ ref={inputRef}
+ style={{ display: "block" }} />
+ </div>
+ {showError && <p class="help is-danger">{props.error}</p>}
+ </div>
+ );
+}
diff --git a/packages/anastasis-webui/src/components/fields/LabeledInput.tsx b/packages/anastasis-webui/src/components/fields/TextInput.tsx
index 96d634a4f..fa6fd9792 100644
--- a/packages/anastasis-webui/src/components/fields/LabeledInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/TextInput.tsx
@@ -1,7 +1,7 @@
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
-export interface LabeledInputProps {
+export interface TextInputProps {
label: string;
grabFocus?: boolean;
error?: string;
@@ -9,7 +9,7 @@ export interface LabeledInputProps {
bind: [string, (x: string) => void];
}
-export function LabeledInput(props: LabeledInputProps): VNode {
+export function TextInput(props: TextInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (props.grabFocus) {
diff --git a/packages/anastasis-webui/src/components/menu/SideBar.tsx b/packages/anastasis-webui/src/components/menu/SideBar.tsx
index 12223d473..87e771009 100644
--- a/packages/anastasis-webui/src/components/menu/SideBar.tsx
+++ b/packages/anastasis-webui/src/components/menu/SideBar.tsx
@@ -64,9 +64,8 @@ export function Sidebar({ mobile }: Props): VNode {
</li>
}
{reducer.currentReducerState && reducer.currentReducerState.backup_state ? <Fragment>
- <li class={
- reducer.currentReducerState.backup_state === BackupStates.ContinentSelecting ||
- reducer.currentReducerState.backup_state === BackupStates.CountrySelecting ? 'is-active' : ''}>
+ <li class={reducer.currentReducerState.backup_state === BackupStates.ContinentSelecting ||
+ reducer.currentReducerState.backup_state === BackupStates.CountrySelecting ? 'is-active' : ''}>
<div class="ml-4">
<span class="menu-item-label"><Translate>Location &amp; Currency</Translate></span>
</div>
@@ -79,73 +78,65 @@ export function Sidebar({ mobile }: Props): VNode {
<li class={reducer.currentReducerState.backup_state === BackupStates.AuthenticationsEditing ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>Auth methods</Translate></span>
+ <span class="menu-item-label"><Translate>Authorization methods</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.backup_state === BackupStates.PoliciesReviewing ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>PoliciesReviewing</Translate></span>
+ <span class="menu-item-label"><Translate>Policies reviewing</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.backup_state === BackupStates.SecretEditing ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>SecretEditing</Translate></span>
+ <span class="menu-item-label"><Translate>Secret input</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.backup_state === BackupStates.PoliciesPaying ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>PoliciesPaying</Translate></span>
+ <span class="menu-item-label"><Translate>Payment (optional)</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.backup_state === BackupStates.BackupFinished ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>BackupFinished</Translate></span>
+ <span class="menu-item-label"><Translate>Backup completed</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.backup_state === BackupStates.TruthsPaying ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>TruthsPaying</Translate></span>
+ <span class="menu-item-label"><Translate>Truth Paying</Translate></span>
</div>
</li>
</Fragment> : (reducer.currentReducerState && reducer.currentReducerState?.recovery_state && <Fragment>
- <li class={reducer.currentReducerState.recovery_state === RecoveryStates.ContinentSelecting ? 'is-active' : ''}>
+ <li class={reducer.currentReducerState.recovery_state === RecoveryStates.ContinentSelecting ||
+ reducer.currentReducerState.recovery_state === RecoveryStates.CountrySelecting ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>ContinentSelecting</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.recovery_state === RecoveryStates.CountrySelecting ? 'is-active' : ''}>
- <div class="ml-4">
- <span class="menu-item-label"><Translate>CountrySelecting</Translate></span>
+ <span class="menu-item-label"><Translate>Location &amp; Currency</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.recovery_state === RecoveryStates.UserAttributesCollecting ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>UserAttributesCollecting</Translate></span>
+ <span class="menu-item-label"><Translate>Personal information</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.recovery_state === RecoveryStates.SecretSelecting ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>SecretSelecting</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.recovery_state === RecoveryStates.ChallengeSelecting ? 'is-active' : ''}>
- <div class="ml-4">
- <span class="menu-item-label"><Translate>ChallengeSelecting</Translate></span>
+ <span class="menu-item-label"><Translate>Secret selection</Translate></span>
</div>
</li>
- <li class={reducer.currentReducerState.recovery_state === RecoveryStates.ChallengeSolving ? 'is-active' : ''}>
+ <li class={reducer.currentReducerState.recovery_state === RecoveryStates.ChallengeSelecting ||
+ reducer.currentReducerState.recovery_state === RecoveryStates.ChallengeSolving ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>ChallengeSolving</Translate></span>
+ <span class="menu-item-label"><Translate>Solve Challenges</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.recovery_state === RecoveryStates.RecoveryFinished ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>RecoveryFinished</Translate></span>
+ <span class="menu-item-label"><Translate>Secret recovered</Translate></span>
</div>
</li>
</Fragment>)}
diff --git a/packages/anastasis-webui/src/components/picker/DatePicker.tsx b/packages/anastasis-webui/src/components/picker/DatePicker.tsx
index e51b3db68..5b33fa8be 100644
--- a/packages/anastasis-webui/src/components/picker/DatePicker.tsx
+++ b/packages/anastasis-webui/src/components/picker/DatePicker.tsx
@@ -24,6 +24,7 @@ import { h, Component } from "preact";
interface Props {
closeFunction?: () => void;
dateReceiver?: (d: Date) => void;
+ years?: Array<number>;
opened?: boolean;
}
interface State {
@@ -207,9 +208,9 @@ export class DatePicker extends Component<Props, State> {
}
componentDidUpdate() {
- if (this.state.selectYearMode) {
- document.getElementsByClassName('selected')[0].scrollIntoView(); // works in every browser incl. IE, replace with scrollIntoViewIfNeeded when browsers support it
- }
+ // if (this.state.selectYearMode) {
+ // document.getElementsByClassName('selected')[0].scrollIntoView(); // works in every browser incl. IE, replace with scrollIntoViewIfNeeded when browsers support it
+ // }
}
constructor() {
@@ -296,8 +297,7 @@ export class DatePicker extends Component<Props, State> {
</div>}
{selectYearMode && <div class="datePicker--selectYear">
-
- {yearArr.map(year => (
+ {(this.props.years || yearArr).map(year => (
<span key={year} class={(year === displayedYear) ? 'selected' : ''} onClick={this.changeDisplayedYear}>
{year}
</span>
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx
index d9be48fb4..32d7817e3 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx
@@ -40,21 +40,21 @@ export default {
export const Backup = createExample(TestedComponent, {
...reducerStatesExample.backupAttributeEditing,
required_attributes: [{
- name: 'first',
+ name: 'first name',
label: 'first',
- type: 'type',
+ type: 'string',
uuid: 'asdasdsa1',
widget: 'wid',
}, {
- name: 'pepe',
+ name: 'last name',
label: 'second',
- type: 'type',
+ type: 'string',
uuid: 'asdasdsa2',
widget: 'wid',
}, {
- name: 'pepe2',
+ name: 'date',
label: 'third',
- type: 'type',
+ type: 'date',
uuid: 'asdasdsa3',
widget: 'calendar',
}]
@@ -65,19 +65,19 @@ export const Recovery = createExample(TestedComponent, {
required_attributes: [{
name: 'first',
label: 'first',
- type: 'type',
+ type: 'string',
uuid: 'asdasdsa1',
widget: 'wid',
}, {
name: 'pepe',
label: 'second',
- type: 'type',
+ type: 'string',
uuid: 'asdasdsa2',
widget: 'wid',
}, {
name: 'pepe2',
label: 'third',
- type: 'type',
+ type: 'date',
uuid: 'asdasdsa3',
widget: 'calendar',
}]
@@ -110,12 +110,20 @@ const allWidgets = [
"anastasis_gtk_xx_square",
]
+function typeForWidget(name: string): string {
+ if (["anastasis_gtk_xx_prime",
+ "anastasis_gtk_xx_square",
+ ].includes(name)) return "number";
+ if (["anastasis_gtk_ia_birthdate"].includes(name)) return "date"
+ return "string";
+}
+
export const WithAllPosibleWidget = createExample(TestedComponent, {
...reducerStatesExample.backupAttributeEditing,
required_attributes: allWidgets.map(w => ({
name: w,
label: `widget: ${w}`,
- type: 'type',
+ type: typeForWidget(w),
uuid: `uuid-${w}`,
widget: w
}))
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
index 3b39cf9c4..f74dcefba 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
@@ -4,8 +4,9 @@ import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame, withProcessLabel } from "./index";
-import { LabeledInput } from "../../components/fields/LabeledInput";
+import { TextInput } from "../../components/fields/TextInput";
import { DateInput } from "../../components/fields/DateInput";
+import { NumberInput } from "../../components/fields/NumberInput";
export function AttributeEntryScreen(): VNode {
const reducer = useAnastasisContext()
@@ -65,6 +66,7 @@ export function AttributeEntryScreen(): VNode {
</div>
<div class="column is-half" >
+ <p>This personal information will help to locate your secret in the first place</p>
<h1><b>This stay private</b></h1>
<p>The information you have entered here:
</p>
@@ -92,20 +94,33 @@ interface AttributeEntryFieldProps {
spec: UserAttributeSpec;
isValid: () => string | undefined;
}
-
+const possibleBirthdayYear: Array<number> = []
+for (let i = 0; i < 100; i++ ) {
+ possibleBirthdayYear.push(2020 - i)
+}
function AttributeEntryField(props: AttributeEntryFieldProps): VNode {
const errorMessage = props.isValid()
return (
<div>
- {props.spec.type === 'date' ?
+ {props.spec.type === 'date' &&
<DateInput
grabFocus={props.isFirst}
label={props.spec.label}
+ years={possibleBirthdayYear}
+ error={errorMessage}
+ bind={[props.value, props.setValue]}
+ />}
+ {props.spec.type === 'number' &&
+ <NumberInput
+ grabFocus={props.isFirst}
+ label={props.spec.label}
error={errorMessage}
bind={[props.value, props.setValue]}
- /> :
- <LabeledInput
+ />
+ }
+ {props.spec.type === 'string' &&
+ <TextInput
grabFocus={props.isFirst}
label={props.spec.label}
error={errorMessage}
diff --git a/packages/anastasis-webui/src/pages/home/AuthMethodEmailSetup.tsx b/packages/anastasis-webui/src/pages/home/AuthMethodEmailSetup.tsx
index 5243c5259..c3783ea6c 100644
--- a/packages/anastasis-webui/src/pages/home/AuthMethodEmailSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthMethodEmailSetup.tsx
@@ -7,7 +7,7 @@ import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AuthMethodSetupProps } from "./AuthenticationEditorScreen";
import { AnastasisClientFrame } from "./index";
-import { LabeledInput } from "../../components/fields/LabeledInput";
+import { TextInput } from "../../components/fields/TextInput";
export function AuthMethodEmailSetup(props: AuthMethodSetupProps): VNode {
const [email, setEmail] = useState("");
@@ -19,7 +19,7 @@ export function AuthMethodEmailSetup(props: AuthMethodSetupProps): VNode {
email.
</p>
<div>
- <LabeledInput
+ <TextInput
label="Email address"
grabFocus
bind={[email, setEmail]} />
diff --git a/packages/anastasis-webui/src/pages/home/AuthMethodPostSetup.tsx b/packages/anastasis-webui/src/pages/home/AuthMethodPostSetup.tsx
index 1c2a9a92e..c4ddeff91 100644
--- a/packages/anastasis-webui/src/pages/home/AuthMethodPostSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthMethodPostSetup.tsx
@@ -6,7 +6,7 @@ import {
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AuthMethodSetupProps } from "./AuthenticationEditorScreen";
-import { LabeledInput } from "../../components/fields/LabeledInput";
+import { TextInput } from "../../components/fields/TextInput";
export function AuthMethodPostSetup(props: AuthMethodSetupProps): VNode {
const [fullName, setFullName] = useState("");
@@ -42,22 +42,22 @@ export function AuthMethodPostSetup(props: AuthMethodSetupProps): VNode {
code that you will receive in a letter to that address.
</p>
<div>
- <LabeledInput
+ <TextInput
grabFocus
label="Full Name"
bind={[fullName, setFullName]} />
</div>
<div>
- <LabeledInput label="Street" bind={[street, setStreet]} />
+ <TextInput label="Street" bind={[street, setStreet]} />
</div>
<div>
- <LabeledInput label="City" bind={[city, setCity]} />
+ <TextInput label="City" bind={[city, setCity]} />
</div>
<div>
- <LabeledInput label="Postal Code" bind={[postcode, setPostcode]} />
+ <TextInput label="Postal Code" bind={[postcode, setPostcode]} />
</div>
<div>
- <LabeledInput label="Country" bind={[country, setCountry]} />
+ <TextInput label="Country" bind={[country, setCountry]} />
</div>
<div>
<button onClick={() => props.cancel()}>Cancel</button>
diff --git a/packages/anastasis-webui/src/pages/home/AuthMethodQuestionSetup.tsx b/packages/anastasis-webui/src/pages/home/AuthMethodQuestionSetup.tsx
index c2bd24ef9..f1bab94ab 100644
--- a/packages/anastasis-webui/src/pages/home/AuthMethodQuestionSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthMethodQuestionSetup.tsx
@@ -7,7 +7,7 @@ import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AuthMethodSetupProps } from "./AuthenticationEditorScreen";
import { AnastasisClientFrame } from "./index";
-import { LabeledInput } from "../../components/fields/LabeledInput";
+import { TextInput } from "../../components/fields/TextInput";
export function AuthMethodQuestionSetup(props: AuthMethodSetupProps): VNode {
const [questionText, setQuestionText] = useState("");
@@ -29,13 +29,13 @@ export function AuthMethodQuestionSetup(props: AuthMethodSetupProps): VNode {
here.
</p>
<div>
- <LabeledInput
+ <TextInput
label="Security question"
grabFocus
bind={[questionText, setQuestionText]} />
</div>
<div>
- <LabeledInput label="Answer" bind={[answerText, setAnswerText]} />
+ <TextInput label="Answer" bind={[answerText, setAnswerText]} />
</div>
<div>
<button onClick={() => props.cancel()}>Cancel</button>
diff --git a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx
index def44c5a6..758963574 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx
@@ -37,7 +37,7 @@ export default {
},
};
-export const OneChallenge = createExample(TestedComponent, {
+export const OneUnsolvedPolicy = createExample(TestedComponent, {
...reducerStatesExample.challengeSelecting,
recovery_information: {
policies: [[{ uuid: '1' }]],
@@ -50,7 +50,7 @@ export const OneChallenge = createExample(TestedComponent, {
},
} as ReducerState);
-export const MoreChallenges = createExample(TestedComponent, {
+export const SomePoliciesOneSolved = createExample(TestedComponent, {
...reducerStatesExample.challengeSelecting,
recovery_information: {
policies: [[{ uuid: '1' }, { uuid: '2' }], [{ uuid: 'uuid-3' }]],
@@ -75,13 +75,13 @@ export const MoreChallenges = createExample(TestedComponent, {
'uuid-3': {
state: 'solved'
}
- }
+ },
} as ReducerState);
export const OneBadConfiguredPolicy = createExample(TestedComponent, {
...reducerStatesExample.challengeSelecting,
recovery_information: {
- policies: [[{ uuid: '2' }]],
+ policies: [[{ uuid: '1' }, { uuid: '2' }]],
challenges: [{
cost: 'USD:1',
instructions: 'just go for it',
@@ -91,4 +91,130 @@ export const OneBadConfiguredPolicy = createExample(TestedComponent, {
},
} as ReducerState);
+export const OnePolicyWithAllTheChallenges = createExample(TestedComponent, {
+ ...reducerStatesExample.challengeSelecting,
+ recovery_information: {
+ policies: [[
+ { uuid: '1' },
+ { uuid: '2' },
+ { uuid: '3' },
+ { uuid: '4' },
+ { uuid: '5' },
+ { uuid: '6' },
+ ]],
+ challenges: [{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '1',
+ },{
+ cost: 'USD:1',
+ instructions: 'enter a text received by a sms',
+ type: 'sms',
+ uuid: '2',
+ },{
+ cost: 'USD:1',
+ instructions: 'enter a text received by a email',
+ type: 'email',
+ uuid: '3',
+ },{
+ cost: 'USD:1',
+ instructions: 'enter a code based on a time-based one-time password',
+ type: 'totp',
+ uuid: '4',
+ },{
+ cost: 'USD:1',
+ instructions: 'send a wire transfer to an account',
+ type: 'iban',
+ uuid: '5',
+ },{
+ cost: 'USD:1',
+ instructions: 'just go for it',
+ type: 'new-type-of-challenge',
+ uuid: '6',
+ }],
+ },
+} as ReducerState);
+
+
+export const OnePolicyWithAllTheChallengesInDifferentState = createExample(TestedComponent, {
+ ...reducerStatesExample.challengeSelecting,
+ recovery_information: {
+ policies: [[
+ { uuid: '1' },
+ { uuid: '2' },
+ { uuid: '3' },
+ { uuid: '4' },
+ { uuid: '5' },
+ { uuid: '6' },
+ { uuid: '7' },
+ { uuid: '8' },
+ { uuid: '9' },
+ { uuid: '10' },
+ ]],
+ challenges: [{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '1',
+ },{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '2',
+ },{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '3',
+ },{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '4',
+ },{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '5',
+ },{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '6',
+ },{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '7',
+ },{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '8',
+ },{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '9',
+ },{
+ cost: 'USD:1',
+ instructions: 'answer the a question correctly',
+ type: 'question',
+ uuid: '10',
+ }],
+ },
+ challenge_feedback: {
+ 1: { state: 'solved' },
+ 2: { state: 'hint' },
+ 3: { state: 'details' },
+ 4: { state: 'body' },
+ 5: { state: 'redirect' },
+ 6: { state: 'server-failure' },
+ 7: { state: 'truth-unknown' },
+ 8: { state: 'rate-limit-exceeded' },
+ 9: { state: 'authentication-timeout' },
+ 10: { state: 'external-instructions' },
+ }
+} as ReducerState);
export const NoPolicies = createExample(TestedComponent, reducerStatesExample.challengeSelecting);
diff --git a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
index c9b52e91b..3bb3fb837 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
@@ -1,3 +1,4 @@
+import { ChallengeFeedback } from "anastasis-core";
import { h, VNode } from "preact";
import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame } from "./index";
@@ -13,65 +14,94 @@ export function ChallengeOverviewScreen(): VNode {
}
const policies = reducer.currentReducerState.recovery_information?.policies ?? [];
- const chArr = reducer.currentReducerState.recovery_information?.challenges ?? [];
- const challengeFeedback = reducer.currentReducerState?.challenge_feedback;
+ const knownChallengesArray = reducer.currentReducerState.recovery_information?.challenges ?? [];
+ const challengeFeedback = reducer.currentReducerState?.challenge_feedback ?? {};
- const challenges: {
+ const knownChallengesMap: {
[uuid: string]: {
type: string;
instructions: string;
cost: string;
+ feedback: ChallengeFeedback | undefined;
};
} = {};
- for (const ch of chArr) {
- challenges[ch.uuid] = {
+ for (const ch of knownChallengesArray) {
+ knownChallengesMap[ch.uuid] = {
type: ch.type,
cost: ch.cost,
instructions: ch.instructions,
+ feedback: challengeFeedback[ch.uuid]
};
}
+ const policiesWithInfo = policies.map(row => {
+ let isPolicySolved = true
+ const challenges = row.map(({ uuid }) => {
+ const info = knownChallengesMap[uuid];
+ const isChallengeSolved = info?.feedback?.state === 'solved'
+ isPolicySolved = isPolicySolved && isChallengeSolved
+ return { info, uuid, isChallengeSolved }
+ }).filter(ch => ch.info !== undefined)
+
+ return { isPolicySolved, challenges }
+ })
+
+ const atLeastThereIsOnePolicySolved = policiesWithInfo.find(p => p.isPolicySolved) !== undefined
+
return (
- <AnastasisClientFrame title="Recovery: Solve challenges">
- <h2>Policies</h2>
- {!policies.length && <p>
- No policies found
- </p>}
- {policies.map((row, i) => {
+ <AnastasisClientFrame hideNext={!atLeastThereIsOnePolicySolved} title="Recovery: Solve challenges">
+ {!policies.length ? <p>
+ No policies found, try with another version of the secret
+ </p> : (policies.length === 1 ? <p>
+ One policy found for this secret. You need to solve all the challenges in order to recover your secret.
+ </p> : <p>
+ We have found {policies.length} polices. You need to solve all the challenges from one policy in order
+ to recover your secret.
+ </p>)}
+ {policiesWithInfo.map((row, i) => {
+ const tableBody = row.challenges.map(({ info, uuid }) => {
+ return (
+ <tr key={uuid}>
+ <td>{info.type}</td>
+ <td>
+ {info.instructions}
+ </td>
+ <td>{info.feedback?.state ?? "unknown"}</td>
+ <td>{info.cost}</td>
+ <td>
+ {info.feedback?.state !== "solved" ? (
+ <a onClick={() => reducer.transition("select_challenge", { uuid })}>
+ Solve
+ </a>
+ ) : null}
+ </td>
+ </tr>
+ );
+ })
return (
<div key={i}>
- <h3>Policy #{i + 1}</h3>
- {row.map(column => {
- const ch = challenges[column.uuid];
- if (!ch) return <div>
- There is no challenge for this policy
- </div>
- const feedback = challengeFeedback?.[column.uuid];
- return (
- <div key={column.uuid}
- style={{
- borderLeft: "2px solid gray",
- paddingLeft: "0.5em",
- borderRadius: "0.5em",
- marginTop: "0.5em",
- marginBottom: "0.5em",
- }}
- >
- <h4>
- {ch.type} ({ch.instructions})
- </h4>
- <p>Status: {feedback?.state ?? "unknown"}</p>
- {feedback?.state !== "solved" ? (
- <button
- onClick={() => reducer.transition("select_challenge", {
- uuid: column.uuid,
- })}
- >
- Solve
- </button>
- ) : null}
- </div>
- );
- })}
+ <b>Policy #{i + 1}</b>
+ {row.challenges.length === 0 && <p>
+ This policy doesn't have challenges
+ </p>}
+ {row.challenges.length === 1 && <p>
+ This policy just have one challenge to be solved
+ </p>}
+ {row.challenges.length > 1 && <p>
+ This policy have {row.challenges.length} challenges
+ </p>}
+ <table class="table">
+ <thead>
+ <tr>
+ <td>Challenge type</td>
+ <td>Description</td>
+ <td>Status</td>
+ <td>Cost</td>
+ </tr>
+ </thead>
+ <tbody>
+ {tableBody}
+ </tbody>
+ </table>
</div>
);
})}
diff --git a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx
index 8744a2b79..2186eb42d 100644
--- a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx
@@ -36,4 +36,5 @@ export default {
};
export const Backup = createExample(TestedComponent, reducerStatesExample.backupSelectContinent);
+
export const Recovery = createExample(TestedComponent, reducerStatesExample.recoverySelectContinent);
diff --git a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx
index b5933db17..0d2ebb778 100644
--- a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx
@@ -37,7 +37,7 @@ export default {
},
};
-export const NormalEnding = createExample(TestedComponent, {
+export const GoodEnding = createExample(TestedComponent, {
...reducerStatesExample.recoveryFinished,
core_secret: { mime: 'text/plain', value: 'hello' }
} as ReducerState);
diff --git a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
index f5fd7c0d1..79a46761c 100644
--- a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
@@ -5,7 +5,7 @@ import { useState } from "preact/hooks";
import { useAnastasisContext } from "../../context/anastasis";
import {
AnastasisClientFrame} from "./index";
-import { LabeledInput } from "../../components/fields/LabeledInput";
+import { TextInput } from "../../components/fields/TextInput";
export function SecretEditorScreen(): VNode {
const reducer = useAnastasisContext()
@@ -47,14 +47,14 @@ export function SecretEditorScreen(): VNode {
onNext={() => secretNext()}
>
<div>
- <LabeledInput
+ <TextInput
label="Secret Name:"
grabFocus
bind={[secretName, setSecretName]}
/>
</div>
<div>
- <LabeledInput
+ <TextInput
label="Secret Value:"
bind={[secretValue, setSecretValue]}
/>
diff --git a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
index 903f57868..5d67ee472 100644
--- a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
@@ -29,15 +29,31 @@ export function SecretSelectionScreen(): VNode {
version: n,
provider_url: p,
});
- setSelectingVersion(false);
});
+ setSelectingVersion(false);
}
+ const providerList = Object.keys(reducer.currentReducerState.authentication_providers ?? {})
const recoveryDocument = reducer.currentReducerState.recovery_document
if (!recoveryDocument) {
return (
- <AnastasisClientFrame hideNav title="Recovery: Problem">
- <p>No recovery document found</p>
+ <AnastasisClientFrame hideNext title="Recovery: Problem">
+ <p>No recovery document found, try with another provider</p>
+ <table class="table">
+ <tr>
+ <td><b>Provider</b></td>
+ <td>
+ <select onChange={(e) => setOtherProvider((e.target as any).value)}>
+ <option key="none" disabled selected > Choose another provider </option>
+ {providerList.map(prov => (
+ <option key={prov} value={prov}>
+ {prov}
+ </option>
+ ))}
+ </select>
+ </td>
+ </tr>
+ </table>
</AnastasisClientFrame>
)
}
@@ -45,43 +61,75 @@ export function SecretSelectionScreen(): VNode {
return (
<AnastasisClientFrame hideNav title="Recovery: Select secret">
<p>Select a different version of the secret</p>
- <select onChange={(e) => setOtherProvider((e.target as any).value)}>
- {Object.keys(reducer.currentReducerState.authentication_providers ?? {}).map(
- (x, i) => (
- <option key={i} selected={x === recoveryDocument.provider_url} value={x}>
- {x}
- </option>
- )
- )}
- </select>
- <div>
- <input
- value={otherVersion}
- onChange={(e) => setOtherVersion(Number((e.target as HTMLInputElement).value))}
- type="number" />
- <button onClick={() => selectVersion(otherProvider, otherVersion)}>
- Use this version
- </button>
- </div>
- <div>
- <button onClick={() => selectVersion(otherProvider, 0)}>
- Use latest version
- </button>
- </div>
- <div>
- <button onClick={() => setSelectingVersion(false)}>Cancel</button>
+ <table class="table">
+ <tr>
+ <td><b>Provider</b></td>
+ <td>
+ <select onChange={(e) => setOtherProvider((e.target as any).value)}>
+ {providerList.map(prov => (
+ <option key={prov} selected={prov === recoveryDocument.provider_url} value={prov}>
+ {prov}
+ </option>
+ ))}
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td><b>Version</b></td>
+ <td>
+ <input
+ value={otherVersion}
+ onChange={(e) => setOtherVersion(Number((e.target as HTMLInputElement).value))}
+ type="number" />
+ </td>
+ <td>
+ <a onClick={() => setOtherVersion(0)}>set to latest version</a>
+ </td>
+ </tr>
+ </table>
+ <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
+ <button class="button" onClick={() => setSelectingVersion(false)}>Cancel</button>
+ <button class="button is-info" onClick={() => selectVersion(otherProvider, otherVersion)}>Confirm</button>
</div>
+
</AnastasisClientFrame>
);
}
return (
<AnastasisClientFrame title="Recovery: Select secret">
- <p>Provider: {recoveryDocument.provider_url}</p>
- <p>Secret version: {recoveryDocument.version}</p>
- <p>Secret name: {recoveryDocument.secret_name}</p>
- <button onClick={() => setSelectingVersion(true)}>
- Select different secret
- </button>
+ <p>Secret found, you can select another version or continue to the challenges solving</p>
+ <table class="table">
+ <tr>
+ <td>
+ <b>Provider</b>
+ <span class="icon has-tooltip-right" data-tooltip="Service provider backing up your secret">
+ <i class="mdi mdi-information" />
+ </span>
+ </td>
+ <td>{recoveryDocument.provider_url}</td>
+ <td><a onClick={() => setSelectingVersion(true)}>use another provider</a></td>
+ </tr>
+ <tr>
+ <td>
+ <b>Secret version</b>
+ <span class="icon has-tooltip-right" data-tooltip="Secret version to be recovered">
+ <i class="mdi mdi-information" />
+ </span>
+ </td>
+ <td>{recoveryDocument.version}</td>
+ <td><a onClick={() => setSelectingVersion(true)}>use another version</a></td>
+ </tr>
+ <tr>
+ <td>
+ <b>Secret name</b>
+ <span class="icon has-tooltip-right" data-tooltip="Secret identifier">
+ <i class="mdi mdi-information" />
+ </span>
+ </td>
+ <td>{recoveryDocument.secret_name}</td>
+ <td> </td>
+ </tr>
+ </table>
</AnastasisClientFrame>
);
}
diff --git a/packages/anastasis-webui/src/pages/home/SolveEmailEntry.tsx b/packages/anastasis-webui/src/pages/home/SolveEmailEntry.tsx
deleted file mode 100644
index 0d70405e5..000000000
--- a/packages/anastasis-webui/src/pages/home/SolveEmailEntry.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { useAnastasisContext } from "../../context/anastasis";
-import { AnastasisClientFrame } from "./index";
-import { LabeledInput } from "../../components/fields/LabeledInput";
-import { SolveEntryProps } from "./SolveScreen";
-
-export function SolveEmailEntry({ challenge, feedback }: SolveEntryProps): VNode {
- const [answer, setAnswer] = useState("");
- const reducer = useAnastasisContext()
- const next = (): void => {
- if (reducer) reducer.transition("solve_challenge", {
- answer,
- })
- };
- return (
- <AnastasisClientFrame
- title="Recovery: Solve challenge"
- onNext={() => next()}
- >
- <p>Feedback: {JSON.stringify(feedback)}</p>
- <p>{challenge.instructions}</p>
- <LabeledInput label="Answer" grabFocus bind={[answer, setAnswer]} />
- </AnastasisClientFrame>
- );
-}
diff --git a/packages/anastasis-webui/src/pages/home/SolvePostEntry.tsx b/packages/anastasis-webui/src/pages/home/SolvePostEntry.tsx
deleted file mode 100644
index 22b8d470b..000000000
--- a/packages/anastasis-webui/src/pages/home/SolvePostEntry.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { useAnastasisContext } from "../../context/anastasis";
-import { AnastasisClientFrame } from "./index";
-import { LabeledInput } from "../../components/fields/LabeledInput";
-import { SolveEntryProps } from "./SolveScreen";
-
-export function SolvePostEntry({ challenge, feedback }: SolveEntryProps): VNode {
- const [answer, setAnswer] = useState("");
- const reducer = useAnastasisContext()
- const next = (): void => {
- if (reducer) reducer.transition("solve_challenge", { answer })
- };
- return (
- <AnastasisClientFrame
- title="Recovery: Solve challenge"
- onNext={() => next()}
- >
- <p>Feedback: {JSON.stringify(feedback)}</p>
- <p>{challenge.instructions}</p>
- <LabeledInput label="Answer" grabFocus bind={[answer, setAnswer]} />
- </AnastasisClientFrame>
- );
-}
diff --git a/packages/anastasis-webui/src/pages/home/SolveQuestionEntry.tsx b/packages/anastasis-webui/src/pages/home/SolveQuestionEntry.tsx
deleted file mode 100644
index 319289381..000000000
--- a/packages/anastasis-webui/src/pages/home/SolveQuestionEntry.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { useAnastasisContext } from "../../context/anastasis";
-import { AnastasisClientFrame } from "./index";
-import { LabeledInput } from "../../components/fields/LabeledInput";
-import { SolveEntryProps } from "./SolveScreen";
-
-export function SolveQuestionEntry({ challenge, feedback }: SolveEntryProps): VNode {
- const [answer, setAnswer] = useState("");
- const reducer = useAnastasisContext()
- const next = (): void => {
- if (reducer) reducer.transition("solve_challenge", { answer })
- };
- return (
- <AnastasisClientFrame
- title="Recovery: Solve challenge"
- onNext={() => next()}
- >
- <p>Feedback: {JSON.stringify(feedback)}</p>
- <p>Question: {challenge.instructions}</p>
- <LabeledInput label="Answer" grabFocus bind={[answer, setAnswer]} />
- </AnastasisClientFrame>
- );
-}
diff --git a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
index 05ae50b48..077726e02 100644
--- a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
@@ -1,28 +1,36 @@
-import { h, VNode } from "preact";
+import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { AnastasisClientFrame } from ".";
import { ChallengeFeedback, ChallengeInfo } from "../../../../anastasis-core/lib";
+import { TextInput } from "../../components/fields/TextInput";
import { useAnastasisContext } from "../../context/anastasis";
-import { SolveEmailEntry } from "./SolveEmailEntry";
-import { SolvePostEntry } from "./SolvePostEntry";
-import { SolveQuestionEntry } from "./SolveQuestionEntry";
-import { SolveSmsEntry } from "./SolveSmsEntry";
-import { SolveUnsupportedEntry } from "./SolveUnsupportedEntry";
export function SolveScreen(): VNode {
const reducer = useAnastasisContext()
-
+ const [answer, setAnswer] = useState("");
+
if (!reducer) {
- return <div>no reducer in context</div>
+ return <AnastasisClientFrame hideNext title="Recovery problem">
+ <div>no reducer in context</div>
+ </AnastasisClientFrame>
}
if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
- return <div>invalid state</div>
+ return <AnastasisClientFrame hideNext title="Recovery problem">
+ <div>invalid state</div>
+ </AnastasisClientFrame>
}
if (!reducer.currentReducerState.recovery_information) {
- return <div>no recovery information found</div>
+ return <AnastasisClientFrame hideNext title="Recovery problem">
+ <div>no recovery information found</div>
+ </AnastasisClientFrame>
}
if (!reducer.currentReducerState.selected_challenge_uuid) {
- return <div>no selected uuid</div>
+ return <AnastasisClientFrame hideNext title="Recovery problem">
+ <div>no selected uuid</div>
+ </AnastasisClientFrame>
}
+
const chArr = reducer.currentReducerState.recovery_information.challenges;
const challengeFeedback = reducer.currentReducerState.challenge_feedback ?? {};
const selectedUuid = reducer.currentReducerState.selected_challenge_uuid;
@@ -39,16 +47,99 @@ export function SolveScreen(): VNode {
email: SolveEmailEntry,
post: SolvePostEntry,
};
- const SolveDialog = dialogMap[selectedChallenge?.type] ?? SolveUnsupportedEntry;
+ const SolveDialog = selectedChallenge === undefined ? SolveUndefinedEntry : dialogMap[selectedChallenge.type] ?? SolveUnsupportedEntry;
+
+ function onNext(): void {
+ reducer?.transition("solve_challenge", { answer })
+ }
+ function onCancel(): void {
+ reducer?.back()
+ }
+
+
return (
- <SolveDialog
- challenge={selectedChallenge}
- feedback={challengeFeedback[selectedUuid]} />
+ <AnastasisClientFrame
+ hideNav
+ title="Recovery: Solve challenge"
+ >
+ <SolveDialog
+ id={selectedUuid}
+ answer={answer}
+ setAnswer={setAnswer}
+ challenge={selectedChallenge}
+ feedback={challengeFeedback[selectedUuid]} />
+
+ <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
+ <button class="button" onClick={onCancel}>Cancel</button>
+ <button class="button is-info" onClick={onNext} >Confirm</button>
+ </div>
+ </AnastasisClientFrame>
);
}
export interface SolveEntryProps {
+ id: string;
challenge: ChallengeInfo;
feedback?: ChallengeFeedback;
+ answer: string;
+ setAnswer: (s:string) => void;
}
+function SolveSmsEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
+ return (<Fragment>
+ <p>An sms has been sent to "<b>{challenge.instructions}</b>". Type the code below</p>
+ <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
+ </Fragment>
+ );
+}
+function SolveQuestionEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
+ return (
+ <Fragment>
+ <p>Type the answer to the following question:</p>
+ <pre>
+ {challenge.instructions}
+ </pre>
+ <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
+ </Fragment>
+ );
+}
+
+function SolvePostEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
+ return (
+ <Fragment>
+ <p>instruction for post type challenge "<b>{challenge.instructions}</b>"</p>
+ <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
+ </Fragment>
+ );
+}
+
+function SolveEmailEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
+ return (
+ <Fragment>
+ <p>An email has been sent to "<b>{challenge.instructions}</b>". Type the code below</p>
+ <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
+ </Fragment>
+ );
+}
+
+function SolveUnsupportedEntry(props: SolveEntryProps): VNode {
+ return (
+ <Fragment>
+ <p>
+ The challenge selected is not supported for this UI. Please update this version or try using another policy.
+ </p>
+ <p>
+ <b>Challenge type:</b> {props.challenge.type}
+ </p>
+ </Fragment>
+ );
+}
+function SolveUndefinedEntry(props: SolveEntryProps): VNode {
+ return (
+ <Fragment >
+ <p>
+ There is no challenge information for id <b>"{props.id}"</b>. Try resetting the recovery session.
+ </p>
+ </Fragment>
+ );
+}
diff --git a/packages/anastasis-webui/src/pages/home/SolveSmsEntry.tsx b/packages/anastasis-webui/src/pages/home/SolveSmsEntry.tsx
deleted file mode 100644
index c4cf3a680..000000000
--- a/packages/anastasis-webui/src/pages/home/SolveSmsEntry.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { useAnastasisContext } from "../../context/anastasis";
-import { AnastasisClientFrame } from "./index";
-import { LabeledInput } from "../../components/fields/LabeledInput";
-import { SolveEntryProps } from "./SolveScreen";
-
-export function SolveSmsEntry({ challenge, feedback }: SolveEntryProps): VNode {
- const [answer, setAnswer] = useState("");
- const reducer = useAnastasisContext()
- const next = (): void => {
- if (reducer) reducer.transition("solve_challenge", {
- answer,
- })
- };
- return (
- <AnastasisClientFrame
- title="Recovery: Solve challenge"
- onNext={() => next()}
- >
- <p>Feedback: {JSON.stringify(feedback)}</p>
- <p>{challenge.instructions}</p>
- <LabeledInput label="Answer" grabFocus bind={[answer, setAnswer]} />
- </AnastasisClientFrame>
- );
-}
diff --git a/packages/anastasis-webui/src/pages/home/SolveUnsupportedEntry.tsx b/packages/anastasis-webui/src/pages/home/SolveUnsupportedEntry.tsx
deleted file mode 100644
index 7f538d249..000000000
--- a/packages/anastasis-webui/src/pages/home/SolveUnsupportedEntry.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { h, VNode } from "preact";
-import { AnastasisClientFrame } from "./index";
-import { SolveEntryProps } from "./SolveScreen";
-
-export function SolveUnsupportedEntry(props: SolveEntryProps): VNode {
- return (
- <AnastasisClientFrame hideNext title="Recovery: Solve challenge">
- <p>{JSON.stringify(props.challenge)}</p>
- <p>Challenge not supported.</p>
- </AnastasisClientFrame>
- );
-}
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index 8a97ad50c..cf41efb59 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -14,17 +14,17 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AmountJson, AmountLike, Amounts, i18n, Transaction, TransactionType } from "@gnu-taler/taler-util";
+import { AmountLike, Amounts, i18n, Transaction, TransactionType } from "@gnu-taler/taler-util";
import { format } from "date-fns";
-import { Fragment, JSX, VNode, h } from "preact";
+import { JSX, VNode } from "preact";
import { route } from 'preact-router';
import { useEffect, useState } from "preact/hooks";
-import * as wxApi from "../wxApi";
-import { Pages } from "../NavigationBar";
-import emptyImg from "../../static/img/empty.png"
-import { Button, ButtonBox, ButtonBoxDestructive, ButtonDestructive, ButtonPrimary, ExtraLargeText, FontIcon, LargeText, ListOfProducts, PopupBox, Row, RowBorderGray, SmallLightText, WalletBox, WarningBox } from "../components/styled";
+import emptyImg from "../../static/img/empty.png";
import { ErrorMessage } from "../components/ErrorMessage";
import { Part } from "../components/Part";
+import { ButtonBox, ButtonBoxDestructive, ButtonPrimary, FontIcon, ListOfProducts, RowBorderGray, SmallLightText, WalletBox, WarningBox } from "../components/styled";
+import { Pages } from "../NavigationBar";
+import * as wxApi from "../wxApi";
export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
const [transaction, setTransaction] = useState<
@@ -42,7 +42,7 @@ export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
}
};
fetchData();
- }, []);
+ }, [tid]);
if (!transaction) {
return <div><i18n.Translate>Loading ...</i18n.Translate></div>;