aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-11-03 17:30:11 -0300
committerSebastian <sebasjm@gmail.com>2021-11-03 17:35:29 -0300
commita82b5a6992fda61d6eaa0bb079e284805a394777 (patch)
tree857168ae8c28d93253ec319708ae0818bd76c30f /packages
parent9fb6536fbc91adaf7a8a80860fcef5e1f80bfb3b (diff)
feedback from meeting and editing policy
Diffstat (limited to 'packages')
-rw-r--r--packages/anastasis-webui/package.json4
-rw-r--r--packages/anastasis-webui/src/components/AsyncButton.tsx51
-rw-r--r--packages/anastasis-webui/src/components/fields/DateInput.tsx46
-rw-r--r--packages/anastasis-webui/src/components/menu/NavigationBar.tsx2
-rw-r--r--packages/anastasis-webui/src/components/menu/SideBar.tsx14
-rw-r--r--packages/anastasis-webui/src/components/picker/DatePicker.tsx12
-rw-r--r--packages/anastasis-webui/src/hooks/async.ts77
-rw-r--r--packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx4
-rw-r--r--packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx37
-rw-r--r--packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx4
-rw-r--r--packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx7
-rw-r--r--packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx18
-rw-r--r--packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx36
-rw-r--r--packages/anastasis-webui/src/pages/home/CountrySelectionScreen.stories.tsx39
-rw-r--r--packages/anastasis-webui/src/pages/home/CountrySelectionScreen.tsx31
-rw-r--r--packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx109
-rw-r--r--packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx133
-rw-r--r--packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx8
-rw-r--r--packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx57
-rw-r--r--packages/anastasis-webui/src/pages/home/StartScreen.tsx42
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx15
-rw-r--r--packages/anastasis-webui/src/pages/home/index.tsx33
-rw-r--r--packages/anastasis-webui/src/scss/main.scss2
-rw-r--r--packages/anastasis-webui/src/utils/index.tsx97
24 files changed, 657 insertions, 221 deletions
diff --git a/packages/anastasis-webui/package.json b/packages/anastasis-webui/package.json
index b032c563c..3042d8ca1 100644
--- a/packages/anastasis-webui/package.json
+++ b/packages/anastasis-webui/package.json
@@ -4,9 +4,9 @@
"version": "0.0.0",
"license": "MIT",
"scripts": {
- "build": "preact build",
+ "build": "preact build --no-sw --no-esm",
"serve": "sirv build --port 8080 --cors --single",
- "dev": "preact watch",
+ "dev": "preact watch --no-sw --no-esm",
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
"test": "jest ./tests",
"build-storybook": "build-storybook",
diff --git a/packages/anastasis-webui/src/components/AsyncButton.tsx b/packages/anastasis-webui/src/components/AsyncButton.tsx
new file mode 100644
index 000000000..5602715e4
--- /dev/null
+++ b/packages/anastasis-webui/src/components/AsyncButton.tsx
@@ -0,0 +1,51 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { ComponentChildren, h, VNode } from "preact";
+// import { LoadingModal } from "../modal";
+import { useAsync } from "../hooks/async";
+// import { Translate } from "../../i18n";
+
+type Props = {
+ children: ComponentChildren;
+ disabled: boolean;
+ onClick?: () => Promise<void>;
+ [rest: string]: any;
+};
+
+export function AsyncButton({ onClick, disabled, children, ...rest }: Props): VNode {
+ const { isLoading, request } = useAsync(onClick);
+
+ // if (isSlow) {
+ // return <LoadingModal onCancel={cancel} />;
+ // }
+ console.log(isLoading)
+ if (isLoading) {
+
+ return <button class="button">Loading...</button>;
+ }
+
+ return <span {...rest}>
+ <button class="button is-info" onClick={request} disabled={disabled}>
+ {children}
+ </button>
+ </span>;
+}
diff --git a/packages/anastasis-webui/src/components/fields/DateInput.tsx b/packages/anastasis-webui/src/components/fields/DateInput.tsx
index 69a05fcf3..c406b85d1 100644
--- a/packages/anastasis-webui/src/components/fields/DateInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/DateInput.tsx
@@ -1,4 +1,4 @@
-import { format } from "date-fns";
+import { format, isAfter, parse, sub, subYears } from "date-fns";
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
import { DatePicker } from "../picker/DatePicker";
@@ -19,16 +19,14 @@ export function DateInput(props: DateInputProps): VNode {
inputRef.current?.focus();
}
}, [props.grabFocus]);
- const [opened, setOpened2] = useState(false)
- function setOpened(v: boolean): void {
- console.log('dale', v)
- setOpened2(v)
- }
+ const [opened, setOpened] = useState(false)
const value = props.bind[0] || "";
const [dirty, setDirty] = useState(false)
const showError = dirty && props.error
+ const calendar = subYears(new Date(), 30)
+
return <div class="field">
<label class="label">
{props.label}
@@ -36,27 +34,37 @@ export function DateInput(props: DateInputProps): VNode {
<i class="mdi mdi-information" />
</span>}
</label>
- <div class="control has-icons-right">
- <input
- type="text"
- class={showError ? 'input is-danger' : 'input'}
- readonly
- onFocus={() => { setOpened(true) } }
- value={value}
- ref={inputRef} />
-
- <span class="control icon is-right">
- <span class="icon"><i class="mdi mdi-calendar" /></span>
- </span>
+ <div class="control">
+ <div class="field has-addons">
+ <p class="control">
+ <input
+ type="text"
+ class={showError ? 'input is-danger' : 'input'}
+ value={value}
+ onChange={(e) => {
+ const text = e.currentTarget.value
+ setDirty(true)
+ props.bind[1](text);
+ }}
+ ref={inputRef} />
+ </p>
+ <p class="control">
+ <a class="button" onClick={() => { setOpened(true) }}>
+ <span class="icon"><i class="mdi mdi-calendar" /></span>
+ </a>
+ </p>
+ </div>
</div>
+ <p class="help">Using the format yyyy-mm-dd</p>
{showError && <p class="help is-danger">{props.error}</p>}
<DatePicker
opened={opened}
+ initialDate={calendar}
years={props.years}
closeFunction={() => setOpened(false)}
dateReceiver={(d) => {
setDirty(true)
- const v = format(d, 'yyyy/MM/dd')
+ const v = format(d, 'yyyy-MM-dd')
props.bind[1](v);
}}
/>
diff --git a/packages/anastasis-webui/src/components/menu/NavigationBar.tsx b/packages/anastasis-webui/src/components/menu/NavigationBar.tsx
index e1bb4c7c0..935951ab9 100644
--- a/packages/anastasis-webui/src/components/menu/NavigationBar.tsx
+++ b/packages/anastasis-webui/src/components/menu/NavigationBar.tsx
@@ -49,7 +49,7 @@ export function NavigationBar({ onMobileMenu, title }: Props): VNode {
</a>
<div class="navbar-end">
<div class="navbar-item" style={{ paddingTop: 4, paddingBottom: 4 }}>
- <LangSelector />
+ {/* <LangSelector /> */}
</div>
</div>
</div>
diff --git a/packages/anastasis-webui/src/components/menu/SideBar.tsx b/packages/anastasis-webui/src/components/menu/SideBar.tsx
index 35720e0f1..72655662f 100644
--- a/packages/anastasis-webui/src/components/menu/SideBar.tsx
+++ b/packages/anastasis-webui/src/components/menu/SideBar.tsx
@@ -39,9 +39,9 @@ export function Sidebar({ mobile }: Props): VNode {
return (
<aside class="aside is-placed-left is-expanded">
- {mobile && <div class="footer" onClick={(e) => { return e.stopImmediatePropagation() }}>
+ {/* {mobile && <div class="footer" onClick={(e) => { return e.stopImmediatePropagation() }}>
<LangSelector />
- </div>}
+ </div>} */}
<div class="aside-tools">
<div class="aside-tools-label">
<div><b>Anastasis</b> Reducer</div>
@@ -68,7 +68,7 @@ export function Sidebar({ mobile }: Props): VNode {
<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>
+ <span class="menu-item-label"><Translate>Location</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.backup_state === BackupStates.UserAttributesCollecting ? 'is-active' : ''}>
@@ -85,7 +85,7 @@ export function Sidebar({ mobile }: Props): VNode {
<li class={reducer.currentReducerState.backup_state === BackupStates.PoliciesReviewing ? 'is-active' : ''}>
<div class="ml-4">
- <span class="menu-item-label"><Translate>Policies reviewing</Translate></span>
+ <span class="menu-item-label"><Translate>Policies</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.backup_state === BackupStates.SecretEditing ? 'is-active' : ''}>
@@ -94,12 +94,12 @@ export function Sidebar({ mobile }: Props): VNode {
<span class="menu-item-label"><Translate>Secret input</Translate></span>
</div>
</li>
- <li class={reducer.currentReducerState.backup_state === BackupStates.PoliciesPaying ? 'is-active' : ''}>
+ {/* <li class={reducer.currentReducerState.backup_state === BackupStates.PoliciesPaying ? 'is-active' : ''}>
<div class="ml-4">
<span class="menu-item-label"><Translate>Payment (optional)</Translate></span>
</div>
- </li>
+ </li> */}
<li class={reducer.currentReducerState.backup_state === BackupStates.BackupFinished ? 'is-active' : ''}>
<div class="ml-4">
@@ -116,7 +116,7 @@ export function Sidebar({ mobile }: Props): VNode {
<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>Location &amp; Currency</Translate></span>
+ <span class="menu-item-label"><Translate>Location</Translate></span>
</div>
</li>
<li class={reducer.currentReducerState.recovery_state === RecoveryStates.UserAttributesCollecting ? 'is-active' : ''}>
diff --git a/packages/anastasis-webui/src/components/picker/DatePicker.tsx b/packages/anastasis-webui/src/components/picker/DatePicker.tsx
index 5b33fa8be..a94b3708e 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;
+ initialDate?: Date;
years?: Array<number>;
opened?: boolean;
}
@@ -213,8 +214,8 @@ export class DatePicker extends Component<Props, State> {
// }
}
- constructor() {
- super();
+ constructor(props) {
+ super(props);
this.closeDatePicker = this.closeDatePicker.bind(this);
this.dayClicked = this.dayClicked.bind(this);
@@ -226,11 +227,12 @@ export class DatePicker extends Component<Props, State> {
this.toggleYearSelector = this.toggleYearSelector.bind(this);
this.displaySelectedMonth = this.displaySelectedMonth.bind(this);
+ const initial = props.initialDate || now;
this.state = {
- currentDate: now,
- displayedMonth: now.getMonth(),
- displayedYear: now.getFullYear(),
+ currentDate: initial,
+ displayedMonth: initial.getMonth(),
+ displayedYear: initial.getFullYear(),
selectYearMode: false
}
}
diff --git a/packages/anastasis-webui/src/hooks/async.ts b/packages/anastasis-webui/src/hooks/async.ts
new file mode 100644
index 000000000..f142a5dc5
--- /dev/null
+++ b/packages/anastasis-webui/src/hooks/async.ts
@@ -0,0 +1,77 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+import { useState } from "preact/hooks";
+// import { cancelPendingRequest } from "./backend";
+
+export interface Options {
+ slowTolerance: number;
+}
+
+export interface AsyncOperationApi<T> {
+ request: (...a: any) => void;
+ cancel: () => void;
+ data: T | undefined;
+ isSlow: boolean;
+ isLoading: boolean;
+ error: string | undefined;
+}
+
+export function useAsync<T>(fn?: (...args: any) => Promise<T>, { slowTolerance: tooLong }: Options = { slowTolerance: 1000 }): AsyncOperationApi<T> {
+ const [data, setData] = useState<T | undefined>(undefined);
+ const [isLoading, setLoading] = useState<boolean>(false);
+ const [error, setError] = useState<any>(undefined);
+ const [isSlow, setSlow] = useState(false)
+
+ const request = async (...args: any) => {
+ if (!fn) return;
+ setLoading(true);
+ console.log("loading true")
+ const handler = setTimeout(() => {
+ setSlow(true)
+ }, tooLong)
+
+ try {
+ const result = await fn(...args);
+ console.log(result)
+ setData(result);
+ } catch (error) {
+ setError(error);
+ }
+ setLoading(false);
+ setSlow(false)
+ clearTimeout(handler)
+ };
+
+ function cancel() {
+ // cancelPendingRequest()
+ setLoading(false);
+ setSlow(false)
+ }
+
+ return {
+ request,
+ cancel,
+ data,
+ isSlow,
+ isLoading,
+ error
+ };
+}
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx
index 32d7817e3..549686616 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx
@@ -52,8 +52,8 @@ export const Backup = createExample(TestedComponent, {
uuid: 'asdasdsa2',
widget: 'wid',
}, {
- name: 'date',
- label: 'third',
+ name: 'birthdate',
+ label: 'birthdate',
type: 'date',
uuid: 'asdasdsa3',
widget: 'calendar',
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
index 2c7f54c5b..52046b216 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
@@ -7,6 +7,7 @@ import { AnastasisClientFrame, withProcessLabel } from "./index";
import { TextInput } from "../../components/fields/TextInput";
import { DateInput } from "../../components/fields/DateInput";
import { NumberInput } from "../../components/fields/NumberInput";
+import { isAfter, parse } from "date-fns";
export function AttributeEntryScreen(): VNode {
const reducer = useAnastasisContext()
@@ -46,15 +47,14 @@ export function AttributeEntryScreen(): VNode {
identity_attributes: attrs,
})}
>
- <div class="columns">
- <div class="column is-half">
+ <div class="columns" style={{ maxWidth: 'unset' }}>
+ <div class="column is-one-third">
{fieldList}
</div>
- <div class="column is-half" >
+ <div class="column is-two-third" >
<p>This personal information will help to locate your secret.</p>
- <h1><b>This stay private</b></h1>
- <p>The information you have entered here:
- </p>
+ <h1 class="title">This stays private</h1>
+ <p>The information you have entered here:</p>
<ul>
<li>
<span class="icon is-right">
@@ -111,15 +111,17 @@ function AttributeEntryField(props: AttributeEntryFieldProps): VNode {
bind={[props.value, props.setValue]}
/>
}
- <span>
+ <div class="block">
+ This stays private
<span class="icon is-right">
<i class="mdi mdi-eye-off" />
</span>
- This stay private
- </span>
+ </div>
</div>
);
}
+const YEAR_REGEX = /^[0-9]+-[0-9]+-[0-9]+$/
+
function checkIfValid(value: string, spec: UserAttributeSpec): string | undefined {
const pattern = spec['validation-regex']
@@ -136,5 +138,22 @@ function checkIfValid(value: string, spec: UserAttributeSpec): string | undefine
if (!optional && !value) {
return 'This value is required'
}
+ if ("date" === spec.type) {
+ if (!YEAR_REGEX.test(value)) {
+ return "The date doesn't follow the format"
+ }
+
+ try {
+ const v = parse(value, 'yyyy-MM-dd', new Date());
+ if (Number.isNaN(v.getTime())) {
+ return "Some numeric values seems out of range for a date"
+ }
+ if ("birthdate" === spec.name && isAfter(v, new Date())) {
+ return "A birthdate cannot be in the future"
+ }
+ } catch (e) {
+ return "Could not parse the date"
+ }
+ }
return undefined
}
diff --git a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
index 4e7819a77..ab482044f 100644
--- a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
@@ -142,6 +142,10 @@ export function AuthenticationEditorScreen(): VNode {
</div>
<div class="column is-half">
When recovering your wallet, you will be asked to verify your identity via the methods you configure here.
+
+ <b>Explain the exclamation marks</b>
+
+ <a>Explain how to add providers</a>
</div>
</div>
</AnastasisClientFrame>
diff --git a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx
index 70ac8157d..7938baca4 100644
--- a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx
@@ -23,7 +23,7 @@ export function BackupFinishedScreen(): VNode {
</p>}
{details && <div class="block">
- <p>The backup is stored by the following providers:</p>
+ <p>The backup is stored by the following providers:</p>
{Object.keys(details).map((x, i) => {
const sd = details[x];
return (
@@ -31,11 +31,14 @@ export function BackupFinishedScreen(): VNode {
{x}
<p>
version {sd.policy_version}
- {sd.policy_expiration.t_ms !== 'never' ? ` expires at: ${format(sd.policy_expiration.t_ms, 'dd/MM/yyyy')}` : ' without expiration date'}
+ {sd.policy_expiration.t_ms !== 'never' ? ` expires at: ${format(sd.policy_expiration.t_ms, 'dd-MM-yyyy')}` : ' without expiration date'}
</p>
</div>
);
})}
</div>}
+ <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
+ <button class="button" onClick={() => reducer.back()}>Back</button>
+ </div>
</AnastasisClientFrame>);
}
diff --git a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx
index 2186eb42d..6bdb3515d 100644
--- a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/camelcase */
/*
This file is part of GNU Taler
(C) 2021 Taler Systems S.A.
@@ -19,12 +20,13 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
+import { ReducerState } from 'anastasis-core';
import { createExample, reducerStatesExample } from '../../utils';
import { ContinentSelectionScreen as TestedComponent } from './ContinentSelectionScreen';
export default {
- title: 'Pages/ContinentSelectionScreen',
+ title: 'Pages/Location',
component: TestedComponent,
args: {
order: 2,
@@ -35,6 +37,16 @@ export default {
},
};
-export const Backup = createExample(TestedComponent, reducerStatesExample.backupSelectContinent);
+export const BackupSelectContinent = createExample(TestedComponent, reducerStatesExample.backupSelectContinent);
-export const Recovery = createExample(TestedComponent, reducerStatesExample.recoverySelectContinent);
+export const BackupSelectCountry = createExample(TestedComponent, {
+ ...reducerStatesExample.backupSelectContinent,
+ selected_continent: 'Testcontinent',
+} as ReducerState);
+
+export const RecoverySelectContinent = createExample(TestedComponent, reducerStatesExample.recoverySelectContinent);
+
+export const RecoverySelectCountry = createExample(TestedComponent, {
+ ...reducerStatesExample.recoverySelectContinent,
+ selected_continent: 'Testcontinent',
+} as ReducerState);
diff --git a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
index 713655625..4ab0e6a9b 100644
--- a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
@@ -36,20 +36,21 @@ export function ContinentSelectionScreen(): VNode {
})
}
- const step1 = reducer.currentReducerState.backup_state === BackupStates.ContinentSelecting ||
- reducer.currentReducerState.recovery_state === RecoveryStates.ContinentSelecting;
+ // const step1 = reducer.currentReducerState.backup_state === BackupStates.ContinentSelecting ||
+ // reducer.currentReducerState.recovery_state === RecoveryStates.ContinentSelecting;
const errors = !theCountry ? "Select a country" : undefined
return (
- <AnastasisClientFrame hideNext={errors} title={withProcessLabel(reducer, "Select location")} onNext={selectCountryAction}>
- <div class="columns">
- <div class="column is-half">
+ <AnastasisClientFrame hideNext={errors} title={withProcessLabel(reducer, "Where do you live?")} onNext={selectCountryAction}>
+
+ <div class="columns" >
+ <div class="column is-one-third">
<div class="field">
<label class="label">Continent</label>
- <div class="control has-icons-left">
- <div class="select " >
- <select onChange={(e) => selectContinent(e.currentTarget.value)} value={theContinent} disabled={!step1}>
+ <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 => (
<option key={prov.name} value={prov.name}>
@@ -61,18 +62,13 @@ export function ContinentSelectionScreen(): VNode {
<i class="mdi mdi-earth" />
</div>
</div>
- {!step1 && <span class="control">
- <a class="button is-danger" onClick={() => reducer.back()}>
- X
- </a>
- </span>}
</div>
</div>
<div class="field">
<label class="label">Country</label>
- <div class="control has-icons-left">
- <div class="select" >
+ <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 => (
@@ -88,17 +84,17 @@ export function ContinentSelectionScreen(): VNode {
</div>
</div>
- {theCountry && <div class="field">
+ {/* {theCountry && <div class="field">
<label class="label">Available currencies:</label>
<div class="control">
<input class="input is-small" type="text" readonly value={theCountry.currency} />
</div>
- </div>}
+ </div>} */}
</div>
- <div class="column is-half">
+ <div class="column is-two-third">
<p>
- A location will help to define a common information that will be use to locate your secret and a currency
- for payments if needed.
+ Your location will help us to determine which personal information
+ ask you for the next step.
</p>
</div>
</div>
diff --git a/packages/anastasis-webui/src/pages/home/CountrySelectionScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/CountrySelectionScreen.stories.tsx
deleted file mode 100644
index 3a642748a..000000000
--- a/packages/anastasis-webui/src/pages/home/CountrySelectionScreen.stories.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample, reducerStatesExample } from '../../utils';
-import { CountrySelectionScreen as TestedComponent } from './CountrySelectionScreen';
-
-
-export default {
- title: 'Pages/CountrySelectionScreen',
- component: TestedComponent,
- args: {
- order: 3,
- },
- argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
- },
-};
-
-export const Backup = createExample(TestedComponent, reducerStatesExample.backupSelectCountry);
-export const Recovery = createExample(TestedComponent, reducerStatesExample.recoverySelectCountry);
diff --git a/packages/anastasis-webui/src/pages/home/CountrySelectionScreen.tsx b/packages/anastasis-webui/src/pages/home/CountrySelectionScreen.tsx
deleted file mode 100644
index b64e1a096..000000000
--- a/packages/anastasis-webui/src/pages/home/CountrySelectionScreen.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-/* eslint-disable @typescript-eslint/camelcase */
-import { h, VNode } from "preact";
-import { useAnastasisContext } from "../../context/anastasis";
-import { AnastasisClientFrame, withProcessLabel } from "./index";
-
-export function CountrySelectionScreen(): VNode {
- const reducer = useAnastasisContext()
- if (!reducer) {
- return <div>no reducer in context</div>
- }
- if (!reducer.currentReducerState || !("countries" in reducer.currentReducerState)) {
- return <div>invalid state</div>
- }
- const sel = (x: any): void => reducer.transition("select_country", {
- country_code: x.code,
- currencies: [x.currency],
- });
- return (
- <AnastasisClientFrame hideNext={"FIXME"} title={withProcessLabel(reducer, "Select Country")} >
- <div style={{ display: 'flex', flexDirection: 'column' }}>
- {reducer.currentReducerState.countries!.map((x: any) => (
- <div key={x.name}>
- <button class="button" onClick={() => sel(x)} >
- {x.name} ({x.currency})
- </button>
- </div>
- ))}
- </div>
- </AnastasisClientFrame>
- );
-}
diff --git a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx
new file mode 100644
index 000000000..fc339e48e
--- /dev/null
+++ b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx
@@ -0,0 +1,109 @@
+/* eslint-disable @typescript-eslint/camelcase */
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { ReducerState } from 'anastasis-core';
+import { createExample, reducerStatesExample } from '../../utils';
+import { EditPoliciesScreen as TestedComponent } from './EditPoliciesScreen';
+
+
+export default {
+ title: 'Pages/backup/ReviewPoliciesScreen/EditPoliciesScreen',
+ args: {
+ order: 6,
+ },
+ component: TestedComponent,
+ argTypes: {
+ onUpdate: { action: 'onUpdate' },
+ onBack: { action: 'onBack' },
+ },
+};
+
+export const EditingAPolicy = createExample(TestedComponent, {
+ ...reducerStatesExample.policyReview,
+ policies: [{
+ methods: [{
+ authentication_method: 1,
+ provider: 'https://anastasis.demo.taler.net/'
+ }, {
+ authentication_method: 2,
+ provider: 'http://localhost:8086/'
+ }]
+ }, {
+ methods: [{
+ authentication_method: 1,
+ provider: 'http://localhost:8086/'
+ }]
+ }],
+ authentication_methods: [{
+ type: "email",
+ instructions: "Email to qwe@asd.com",
+ challenge: "E5VPA"
+ }, {
+ type: "totp",
+ instructions: "Response code for 'Anastasis'",
+ challenge: "E5VPA"
+ }, {
+ type: "sms",
+ instructions: "SMS to 6666-6666",
+ challenge: ""
+ }, {
+ type: "question",
+ instructions: "How did the chicken cross the road?",
+ challenge: "C5SP8"
+ }]
+} as ReducerState, { index : 0});
+
+export const CreatingAPolicy = createExample(TestedComponent, {
+ ...reducerStatesExample.policyReview,
+ policies: [{
+ methods: [{
+ authentication_method: 1,
+ provider: 'https://anastasis.demo.taler.net/'
+ }, {
+ authentication_method: 2,
+ provider: 'http://localhost:8086/'
+ }]
+ }, {
+ methods: [{
+ authentication_method: 1,
+ provider: 'http://localhost:8086/'
+ }]
+ }],
+ authentication_methods: [{
+ type: "email",
+ instructions: "Email to qwe@asd.com",
+ challenge: "E5VPA"
+ }, {
+ type: "totp",
+ instructions: "Response code for 'Anastasis'",
+ challenge: "E5VPA"
+ }, {
+ type: "sms",
+ instructions: "SMS to 6666-6666",
+ challenge: ""
+ }, {
+ type: "question",
+ instructions: "How did the chicken cross the road?",
+ challenge: "C5SP8"
+ }]
+} as ReducerState, { index : 3});
+
diff --git a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx
new file mode 100644
index 000000000..85cc96c46
--- /dev/null
+++ b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx
@@ -0,0 +1,133 @@
+/* eslint-disable @typescript-eslint/camelcase */
+import { AuthMethod, Policy } from "anastasis-core";
+import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { useAnastasisContext } from "../../context/anastasis";
+import { authMethods, KnownAuthMethods } from "./authMethod";
+import { AnastasisClientFrame } from "./index";
+
+export interface ProviderInfo {
+ url: string;
+ cost: string;
+ isFree: boolean;
+}
+
+export type ProviderInfoByType = {
+ [type in KnownAuthMethods]?: ProviderInfo[];
+};
+
+interface Props {
+ index: number;
+ cancel: () => void;
+ confirm: (changes: MethodProvider[]) => void;
+
+}
+
+export interface MethodProvider {
+ authentication_method: number;
+ provider: string;
+}
+
+export function EditPoliciesScreen({ index: policy_index, cancel, confirm }: Props): VNode {
+ const [changedProvider, setChangedProvider] = useState<Array<string>>([])
+
+ const reducer = useAnastasisContext()
+ if (!reducer) {
+ return <div>no reducer in context</div>
+ }
+ if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
+ return <div>invalid state</div>
+ }
+
+ const selectableProviders: ProviderInfoByType = {}
+ const allProviders = Object.entries(reducer.currentReducerState.authentication_providers || {})
+ for (let index = 0; index < allProviders.length; index++) {
+ const [url, status] = allProviders[index]
+ if ("methods" in status) {
+ status.methods.map(m => {
+ const type: KnownAuthMethods = m.type as KnownAuthMethods
+ const values = selectableProviders[type] || []
+ const isFree = !m.usage_fee || m.usage_fee.endsWith(":0")
+ values.push({ url, cost: m.usage_fee, isFree })
+ selectableProviders[type] = values
+ })
+ }
+ }
+
+ const allAuthMethods = reducer.currentReducerState.authentication_methods ?? [];
+ const policies = reducer.currentReducerState.policies ?? [];
+ const policy = policies[policy_index]
+
+ for(let method_index = 0; method_index < allAuthMethods.length; method_index++ ) {
+ policy?.methods.find(m => m.authentication_method === method_index)?.provider
+ }
+
+ function sendChanges(): void {
+ const newMethods: MethodProvider[] = []
+ allAuthMethods.forEach((method, index) => {
+ const oldValue = policy?.methods.find(m => m.authentication_method === index)
+ if (changedProvider[index] === undefined && oldValue !== undefined) {
+ newMethods.push(oldValue)
+ }
+ if (changedProvider[index] !== undefined && changedProvider[index] !== "") {
+ newMethods.push({
+ authentication_method: index,
+ provider: changedProvider[index]
+ })
+ }
+ })
+ confirm(newMethods)
+ }
+
+ return <AnastasisClientFrame hideNav title={!policy ? "Backup: New Policy" : "Backup: Edit Policy"}>
+ <section class="section">
+ {!policy ? <p>
+ Creating a new policy #{policy_index}
+ </p> : <p>
+ Editing policy #{policy_index}
+ </p>}
+ {allAuthMethods.map((method, index) => {
+ //take the url from the updated change or from the policy
+ const providerURL = changedProvider[index] === undefined ?
+ policy?.methods.find(m => m.authentication_method === index)?.provider :
+ changedProvider[index];
+
+ const type: KnownAuthMethods = method.type as KnownAuthMethods
+ function changeProviderTo(url: string): void {
+ const copy = [...changedProvider]
+ copy[index] = url
+ setChangedProvider(copy)
+ }
+ return (
+ <div key={index} class="block" style={{ display: 'flex', alignItems: 'center' }}>
+ <span class="icon">
+ {authMethods[type]?.icon}
+ </span>
+ <span>
+ {method.instructions}
+ </span>
+ <span>
+ <span class="select " >
+ <select onChange={(e) => changeProviderTo(e.currentTarget.value)} value={providerURL ?? ""}>
+ <option key="none" value=""> &lt;&lt; off &gt;&gt; </option>
+ {selectableProviders[type]?.map(prov => (
+ <option key={prov.url} value={prov.url}>
+ {prov.url}
+ </option>
+ ))}
+ </select>
+ </span>
+ </span>
+ </div>
+ );
+ })}
+ <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
+ <button class="button" onClick={cancel}>Cancel</button>
+ <span class="buttons">
+ <button class="button" onClick={() => setChangedProvider([])}>Reset</button>
+ <button class="button is-info" onClick={sendChanges}>Confirm</button>
+ </span>
+ </div>
+ </section>
+ </AnastasisClientFrame>
+}
diff --git a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx
index 5ba0c937d..9f7e26c16 100644
--- a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx
@@ -233,16 +233,16 @@ export const SomePoliciesWithMethods = createExample(TestedComponent, {
instructions: "Does P equal NP?",
challenge: "C5SP8"
},{
- type: "email",
- instructions: "Email to qwe@asd.com",
+ type: "totp",
+ instructions: "Response code for 'Anastasis'",
challenge: "E5VPA"
}, {
type: "sms",
- instructions: "SMS to 555-555",
+ instructions: "SMS to 6666-6666",
challenge: ""
}, {
type: "question",
- instructions: "Does P equal NP?",
+ instructions: "How did the chicken cross the road?",
challenge: "C5SP8"
}]
} as ReducerState);
diff --git a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
index 673f215e2..b8beb7b47 100644
--- a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
@@ -1,10 +1,14 @@
/* eslint-disable @typescript-eslint/camelcase */
+import { AuthMethod } from "anastasis-core";
import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
import { useAnastasisContext } from "../../context/anastasis";
-import { AnastasisClientFrame } from "./index";
import { authMethods, KnownAuthMethods } from "./authMethod";
+import { EditPoliciesScreen } from "./EditPoliciesScreen";
+import { AnastasisClientFrame } from "./index";
export function ReviewPoliciesScreen(): VNode {
+ const [editingPolicy, setEditingPolicy] = useState<number | undefined>()
const reducer = useAnastasisContext()
if (!reducer) {
return <div>no reducer in context</div>
@@ -12,20 +16,44 @@ export function ReviewPoliciesScreen(): VNode {
if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
return <div>invalid state</div>
}
+
const configuredAuthMethods = reducer.currentReducerState.authentication_methods ?? [];
const policies = reducer.currentReducerState.policies ?? [];
+ if (editingPolicy !== undefined) {
+ return (
+ <EditPoliciesScreen
+ index={editingPolicy}
+ cancel={() => setEditingPolicy(undefined)}
+ confirm={(newMethods) => {
+ reducer.runTransaction(async (tx) => {
+ await tx.transition("delete_policy", {
+ policy_index: editingPolicy
+ });
+ await tx.transition("add_policy", {
+ policy: newMethods
+ });
+ });
+ setEditingPolicy(undefined)
+ }}
+ />
+ )
+ }
+
const errors = policies.length < 1 ? 'Need more policies' : undefined
return (
<AnastasisClientFrame hideNext={errors} title="Backup: Review Recovery Policies">
{policies.length > 0 && <p class="block">
Based on your configured authentication method you have created, some policies
- have been configured. In order to recover your secret you have to solve all the
+ have been configured. In order to recover your secret you have to solve all the
challenges of at least one policy.
- </p> }
+ </p>}
{policies.length < 1 && <p class="block">
No policies had been created. Go back and add more authentication methods.
- </p> }
+ </p>}
+ <div class="block" onClick={() => setEditingPolicy(policies.length + 1)}>
+ <button class="button is-success">Add new policy</button>
+ </div>
{policies.map((p, policy_index) => {
const methods = p.methods
.map(x => configuredAuthMethods[x.authentication_method] && ({ ...configuredAuthMethods[x.authentication_method], provider: x.provider }))
@@ -44,18 +72,21 @@ export function ReviewPoliciesScreen(): VNode {
</p>}
{methods.map((m, i) => {
return (
- <p key={i} class="block" style={{display:'flex', alignItems:'center'}}>
- <span class="icon">
- {authMethods[m.type as KnownAuthMethods]?.icon}
- </span>
- <span>
- {m.instructions} recovery provided by <a href={m.provider}>{m.provider}</a>
- </span>
- </p>
+ <p key={i} class="block" style={{ display: 'flex', alignItems: 'center' }}>
+ <span class="icon">
+ {authMethods[m.type as KnownAuthMethods]?.icon}
+ </span>
+ <span>
+ {m.instructions} recovery provided by <a href={m.provider}>{m.provider}</a>
+ </span>
+ </p>
);
})}
</div>
- <div style={{ marginTop: 'auto', marginBottom: 'auto' }}><button class="button is-danger" onClick={() => reducer.transition("delete_policy", { policy_index })}>Delete</button></div>
+ <div style={{ marginTop: 'auto', marginBottom: 'auto', display: 'flex', justifyContent: 'space-between', flexDirection: 'column' }}>
+ <button class="button is-info block" onClick={() => setEditingPolicy(policy_index)}>Edit</button>
+ <button class="button is-danger block" onClick={() => reducer.transition("delete_policy", { policy_index })}>Delete</button>
+ </div>
</div>
);
})}
diff --git a/packages/anastasis-webui/src/pages/home/StartScreen.tsx b/packages/anastasis-webui/src/pages/home/StartScreen.tsx
index c751ad9e4..6e97eb586 100644
--- a/packages/anastasis-webui/src/pages/home/StartScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/StartScreen.tsx
@@ -10,33 +10,29 @@ export function StartScreen(): VNode {
}
return (
<AnastasisClientFrame hideNav title="Home">
- <div>
- <section class="section is-main-section">
- <div class="columns">
- <div class="column" />
- <div class="column is-four-fifths">
+ <div class="columns">
+ <div class="column" />
+ <div class="column is-four-fifths">
- <div class="buttons">
- <button class="button is-success" autoFocus onClick={() => reducer.startBackup()}>
- <div class="icon"><i class="mdi mdi-arrow-up" /></div>
- <span>Backup a secret</span>
- </button>
+ <div class="buttons">
+ <button class="button is-success" autoFocus onClick={() => reducer.startBackup()}>
+ <div class="icon"><i class="mdi mdi-arrow-up" /></div>
+ <span>Backup a secret</span>
+ </button>
- <button class="button is-info" onClick={() => reducer.startRecover()}>
- <div class="icon"><i class="mdi mdi-arrow-down" /></div>
- <span>Recover a secret</span>
- </button>
+ <button class="button is-info" onClick={() => reducer.startRecover()}>
+ <div class="icon"><i class="mdi mdi-arrow-down" /></div>
+ <span>Recover a secret</span>
+ </button>
- <button class="button">
- <div class="icon"><i class="mdi mdi-file" /></div>
- <span>Restore a session</span>
- </button>
- </div>
-
- </div>
- <div class="column" />
+ <button class="button">
+ <div class="icon"><i class="mdi mdi-file" /></div>
+ <span>Restore a session</span>
+ </button>
</div>
- </section>
+
+ </div>
+ <div class="column" />
</div>
</AnastasisClientFrame>
);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
index eab800e35..04fa00d59 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
@@ -27,7 +27,7 @@ export function AuthMethodQuestionSetup({ cancel, addAuthMethod, configured }: A
<AnastasisClientFrame hideNav title="Add Security Question">
<div>
<p>
- For security question authentication, you need to provide a question
+ For2 security question authentication, you need to provide a question
and its answer. When recovering your secret, you will be shown the
question and you will need to type the answer exactly as you typed it
here.
@@ -47,6 +47,13 @@ export function AuthMethodQuestionSetup({ cancel, addAuthMethod, configured }: A
/>
</div>
+ <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
+ <button class="button" onClick={cancel}>Cancel</button>
+ <span data-tooltip={errors}>
+ <button class="button is-info" disabled={errors !== undefined} onClick={addQuestionAuth}>Add</button>
+ </span>
+ </div>
+
{configured.length > 0 && <section class="section">
<div class="block">
Your security questions:
@@ -58,12 +65,6 @@ export function AuthMethodQuestionSetup({ cancel, addAuthMethod, configured }: A
</div>
})}
</div></section>}
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={cancel}>Cancel</button>
- <span data-tooltip={errors}>
- <button class="button is-info" disabled={errors !== undefined} onClick={addQuestionAuth}>Add</button>
- </span>
- </div>
</div>
</AnastasisClientFrame >
);
diff --git a/packages/anastasis-webui/src/pages/home/index.tsx b/packages/anastasis-webui/src/pages/home/index.tsx
index fefaa184c..415cf6e98 100644
--- a/packages/anastasis-webui/src/pages/home/index.tsx
+++ b/packages/anastasis-webui/src/pages/home/index.tsx
@@ -13,6 +13,7 @@ import {
import {
useErrorBoundary
} from "preact/hooks";
+import { AsyncButton } from "../../components/AsyncButton";
import { Menu } from "../../components/menu";
import { AnastasisProvider, useAnastasisContext } from "../../context/anastasis";
import {
@@ -25,7 +26,6 @@ import { BackupFinishedScreen } from "./BackupFinishedScreen";
import { ChallengeOverviewScreen } from "./ChallengeOverviewScreen";
import { ChallengePayingScreen } from "./ChallengePayingScreen";
import { ContinentSelectionScreen } from "./ContinentSelectionScreen";
-import { CountrySelectionScreen } from "./CountrySelectionScreen";
import { PoliciesPayingScreen } from "./PoliciesPayingScreen";
import { RecoveryFinishedScreen } from "./RecoveryFinishedScreen";
import { ReviewPoliciesScreen } from "./ReviewPoliciesScreen";
@@ -95,12 +95,19 @@ export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
if (!reducer) {
return <p>Fatal: Reducer must be in context.</p>;
}
- const next = (): void => {
- if (props.onNext) {
- props.onNext();
- } else {
- reducer.transition("next", {});
- }
+ const next = async (): Promise<void> => {
+ return new Promise((res, rej) => {
+ try {
+ if (props.onNext) {
+ props.onNext();
+ } else {
+ reducer.transition("next", {});
+ }
+ res()
+ } catch {
+ rej()
+ }
+ })
};
const handleKeyPress = (
e: h.JSX.TargetedKeyboardEvent<HTMLDivElement>,
@@ -111,20 +118,18 @@ export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
return (
<Fragment>
<Menu title="Anastasis" />
- <div>
- <div class="home" onKeyPress={(e) => handleKeyPress(e)}>
- <h1 class="title">{props.title}</h1>
+ <div class="home" onKeyPress={(e) => handleKeyPress(e)}>
+ <h1 class="title">{props.title}</h1>
+ <section class="section is-main-section">
<ErrorBanner />
{props.children}
{!props.hideNav ? (
<div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
<button class="button" onClick={() => reducer.back()}>Back</button>
- <span data-tooltip={props.hideNext}>
- <button class="button is-info" onClick={next} disabled={props.hideNext !== undefined}>Next</button>
- </span>
+ <AsyncButton data-tooltip={props.hideNext} onClick={next} disabled={props.hideNext !== undefined}>Next</AsyncButton>
</div>
) : null}
- </div>
+ </section>
</div>
</Fragment>
);
diff --git a/packages/anastasis-webui/src/scss/main.scss b/packages/anastasis-webui/src/scss/main.scss
index 1e0d3fded..b5335073f 100644
--- a/packages/anastasis-webui/src/scss/main.scss
+++ b/packages/anastasis-webui/src/scss/main.scss
@@ -195,7 +195,7 @@ div[data-tooltip]::before {
padding: 1em 1em;
min-height: 100%;
width: 100%;
- max-width: 40em;
+ // max-width: 40em;
}
// .home div {
diff --git a/packages/anastasis-webui/src/utils/index.tsx b/packages/anastasis-webui/src/utils/index.tsx
index 48ac47544..244be8af8 100644
--- a/packages/anastasis-webui/src/utils/index.tsx
+++ b/packages/anastasis-webui/src/utils/index.tsx
@@ -86,10 +86,10 @@ const base = {
{
type: "question",
usage_fee: "COL:0"
- },{
+ }, {
type: "sms",
usage_fee: "COL:0"
- },{
+ }, {
type: "email",
usage_fee: "COL:0"
},
@@ -98,6 +98,48 @@ const base = {
storage_limit_in_megabytes: 16,
truth_upload_fee: "COL:0"
},
+ "https://kudos.demo.anastasis.lu/": {
+ http_status: 200,
+ annual_fee: "COL:0",
+ business_name: "ana",
+ currency: "COL",
+ liability_limit: "COL:10",
+ methods: [
+ {
+ type: "question",
+ usage_fee: "COL:0"
+ }, {
+ type: "email",
+ usage_fee: "COL:0"
+ },
+ ],
+ salt: "WBMDD76BR1E90YQ5AHBMKPH7GW",
+ storage_limit_in_megabytes: 16,
+ truth_upload_fee: "COL:0"
+ },
+ "https://anastasis.demo.taler.net/": {
+ http_status: 200,
+ annual_fee: "COL:0",
+ business_name: "ana",
+ currency: "COL",
+ liability_limit: "COL:10",
+ methods: [
+ {
+ type: "question",
+ usage_fee: "COL:0"
+ }, {
+ type: "sms",
+ usage_fee: "COL:0"
+ }, {
+ type: "totp",
+ usage_fee: "COL:0"
+ },
+ ],
+ salt: "WBMDD76BR1E90YQ5AHBMKPH7GW",
+ storage_limit_in_megabytes: 16,
+ truth_upload_fee: "COL:0"
+ },
+
"http://localhost:8087/": {
code: 8414,
hint: "request to provider failed"
@@ -118,55 +160,72 @@ const base = {
export const reducerStatesExample = {
initial: undefined,
- recoverySelectCountry: {...base,
+ recoverySelectCountry: {
+ ...base,
recovery_state: RecoveryStates.CountrySelecting
} as ReducerState,
- recoverySelectContinent: {...base,
+ recoverySelectContinent: {
+ ...base,
recovery_state: RecoveryStates.ContinentSelecting,
} as ReducerState,
- secretSelection: {...base,
+ secretSelection: {
+ ...base,
recovery_state: RecoveryStates.SecretSelecting,
} as ReducerState,
- recoveryFinished: {...base,
+ recoveryFinished: {
+ ...base,
recovery_state: RecoveryStates.RecoveryFinished,
} as ReducerState,
- challengeSelecting: {...base,
+ challengeSelecting: {
+ ...base,
recovery_state: RecoveryStates.ChallengeSelecting,
} as ReducerState,
- challengeSolving: {...base,
+ challengeSolving: {
+ ...base,
recovery_state: RecoveryStates.ChallengeSolving,
} as ReducerState,
- challengePaying: {...base,
+ challengePaying: {
+ ...base,
recovery_state: RecoveryStates.ChallengePaying,
} as ReducerState,
- recoveryAttributeEditing: {...base,
+ recoveryAttributeEditing: {
+ ...base,
recovery_state: RecoveryStates.UserAttributesCollecting
} as ReducerState,
- backupSelectCountry: {...base,
+ backupSelectCountry: {
+ ...base,
backup_state: BackupStates.CountrySelecting
} as ReducerState,
- backupSelectContinent: {...base,
+ backupSelectContinent: {
+ ...base,
backup_state: BackupStates.ContinentSelecting,
} as ReducerState,
- secretEdition: {...base,
+ secretEdition: {
+ ...base,
backup_state: BackupStates.SecretEditing,
} as ReducerState,
- policyReview: {...base,
+ policyReview: {
+ ...base,
backup_state: BackupStates.PoliciesReviewing,
} as ReducerState,
- policyPay: {...base,
+ policyPay: {
+ ...base,
backup_state: BackupStates.PoliciesPaying,
} as ReducerState,
- backupFinished: {...base,
+ backupFinished: {
+ ...base,
backup_state: BackupStates.BackupFinished,
} as ReducerState,
- authEditing: {...base,
+ authEditing: {
+ ...base,
backup_state: BackupStates.AuthenticationsEditing
} as ReducerState,
- backupAttributeEditing: {...base,
+ backupAttributeEditing: {
+ ...base,
backup_state: BackupStates.UserAttributesCollecting
} as ReducerState,
- truthsPaying: {...base,
+ truthsPaying: {
+ ...base,
backup_state: BackupStates.TruthsPaying
} as ReducerState,