From 21b60c8f6ff69bf114779a767a3ac3355f69a34f Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Tue, 26 Oct 2021 12:08:03 -0300
Subject: added core validators, worked on look and feel

---
 .../src/components/picker/DatePicker.tsx           | 324 +++++++++++++++++++++
 1 file changed, 324 insertions(+)
 create mode 100644 packages/anastasis-webui/src/components/picker/DatePicker.tsx

(limited to 'packages/anastasis-webui/src/components/picker/DatePicker.tsx')

diff --git a/packages/anastasis-webui/src/components/picker/DatePicker.tsx b/packages/anastasis-webui/src/components/picker/DatePicker.tsx
new file mode 100644
index 000000000..e51b3db68
--- /dev/null
+++ b/packages/anastasis-webui/src/components/picker/DatePicker.tsx
@@ -0,0 +1,324 @@
+/*
+ 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 { h, Component } from "preact";
+
+interface Props {
+  closeFunction?: () => void;
+  dateReceiver?: (d: Date) => void;
+  opened?: boolean;
+}
+interface State {
+  displayedMonth: number;
+  displayedYear: number;
+  selectYearMode: boolean;
+  currentDate: Date;
+}
+const now = new Date()
+
+const monthArrShortFull = [
+  'January',
+  'February',
+  'March',
+  'April',
+  'May',
+  'June',
+  'July',
+  'August',
+  'September',
+  'October',
+  'November',
+  'December'
+]
+
+const monthArrShort = [
+  'Jan',
+  'Feb',
+  'Mar',
+  'Apr',
+  'May',
+  'Jun',
+  'Jul',
+  'Aug',
+  'Sep',
+  'Oct',
+  'Nov',
+  'Dec'
+]
+
+const dayArr = [
+  'Sun',
+  'Mon',
+  'Tue',
+  'Wed',
+  'Thu',
+  'Fri',
+  'Sat'
+]
+
+const yearArr: number[] = []
+
+
+// inspired by https://codepen.io/m4r1vs/pen/MOOxyE
+export class DatePicker extends Component<Props, State> {
+
+  closeDatePicker() {
+    this.props.closeFunction && this.props.closeFunction(); // Function gets passed by parent
+  }
+
+  /**
+  * Gets fired when a day gets clicked.
+  * @param {object} e The event thrown by the <span /> element clicked
+  */
+  dayClicked(e: any) {
+
+    const element = e.target; // the actual element clicked
+
+    if (element.innerHTML === '') return false; // don't continue if <span /> empty
+
+    // get date from clicked element (gets attached when rendered)
+    const date = new Date(element.getAttribute('data-value'));
+
+    // update the state
+    this.setState({ currentDate: date });
+    this.passDateToParent(date)
+  }
+
+  /**
+  * returns days in month as array
+  * @param {number} month the month to display
+  * @param {number} year the year to display
+  */
+  getDaysByMonth(month: number, year: number) {
+
+    const calendar = [];
+
+    const date = new Date(year, month, 1); // month to display
+
+    const firstDay = new Date(year, month, 1).getDay(); // first weekday of month
+    const lastDate = new Date(year, month + 1, 0).getDate(); // last date of month
+
+    let day: number | null = 0;
+
+    // the calendar is 7*6 fields big, so 42 loops
+    for (let i = 0; i < 42; i++) {
+
+      if (i >= firstDay && day !== null) day = day + 1;
+      if (day !== null && day > lastDate) day = null;
+
+      // append the calendar Array
+      calendar.push({
+        day: (day === 0 || day === null) ? null : day, // null or number
+        date: (day === 0 || day === null) ? null : new Date(year, month, day), // null or Date()
+        today: (day === now.getDate() && month === now.getMonth() && year === now.getFullYear()) // boolean
+      });
+    }
+
+    return calendar;
+  }
+
+  /**
+  * Display previous month by updating state
+  */
+  displayPrevMonth() {
+    if (this.state.displayedMonth <= 0) {
+      this.setState({
+        displayedMonth: 11,
+        displayedYear: this.state.displayedYear - 1
+      });
+    }
+    else {
+      this.setState({
+        displayedMonth: this.state.displayedMonth - 1
+      });
+    }
+  }
+
+  /**
+  * Display next month by updating state
+  */
+  displayNextMonth() {
+    if (this.state.displayedMonth >= 11) {
+      this.setState({
+        displayedMonth: 0,
+        displayedYear: this.state.displayedYear + 1
+      });
+    }
+    else {
+      this.setState({
+        displayedMonth: this.state.displayedMonth + 1
+      });
+    }
+  }
+
+  /**
+  * Display the selected month (gets fired when clicking on the date string)
+  */
+  displaySelectedMonth() {
+    if (this.state.selectYearMode) {
+      this.toggleYearSelector();
+    }
+    else {
+      if (!this.state.currentDate) return false;
+      this.setState({
+        displayedMonth: this.state.currentDate.getMonth(),
+        displayedYear: this.state.currentDate.getFullYear()
+      });
+    }
+  }
+
+  toggleYearSelector() {
+    this.setState({ selectYearMode: !this.state.selectYearMode });
+  }
+
+  changeDisplayedYear(e: any) {
+    const element = e.target;
+    this.toggleYearSelector();
+    this.setState({ displayedYear: parseInt(element.innerHTML, 10), displayedMonth: 0 });
+  }
+
+  /**
+  * Pass the selected date to parent when 'OK' is clicked
+  */
+  passSavedDateDateToParent() {
+    this.passDateToParent(this.state.currentDate)
+  }
+  passDateToParent(date: Date) {
+    if (typeof this.props.dateReceiver === 'function') this.props.dateReceiver(date);
+    this.closeDatePicker();
+  }
+
+  componentDidUpdate() {
+    if (this.state.selectYearMode) {
+      document.getElementsByClassName('selected')[0].scrollIntoView(); // works in every browser incl. IE, replace with scrollIntoViewIfNeeded when browsers support it
+    }
+  }
+
+  constructor() {
+    super();
+
+    this.closeDatePicker = this.closeDatePicker.bind(this);
+    this.dayClicked = this.dayClicked.bind(this);
+    this.displayNextMonth = this.displayNextMonth.bind(this);
+    this.displayPrevMonth = this.displayPrevMonth.bind(this);
+    this.getDaysByMonth = this.getDaysByMonth.bind(this);
+    this.changeDisplayedYear = this.changeDisplayedYear.bind(this);
+    this.passDateToParent = this.passDateToParent.bind(this);
+    this.toggleYearSelector = this.toggleYearSelector.bind(this);
+    this.displaySelectedMonth = this.displaySelectedMonth.bind(this);
+
+
+    this.state = {
+      currentDate: now,
+      displayedMonth: now.getMonth(),
+      displayedYear: now.getFullYear(),
+      selectYearMode: false
+    }
+  }
+
+  render() {
+
+    const { currentDate, displayedMonth, displayedYear, selectYearMode } = this.state;
+
+    return (
+      <div>
+        <div class={`datePicker ${  this.props.opened && "datePicker--opened"}`}>
+
+          <div class="datePicker--titles">
+            <h3 style={{
+              color: selectYearMode ? 'rgba(255,255,255,.87)' : 'rgba(255,255,255,.57)'
+            }} onClick={this.toggleYearSelector}>{currentDate.getFullYear()}</h3>
+            <h2 style={{
+              color: !selectYearMode ? 'rgba(255,255,255,.87)' : 'rgba(255,255,255,.57)'
+            }} onClick={this.displaySelectedMonth}>
+              {dayArr[currentDate.getDay()]}, {monthArrShort[currentDate.getMonth()]} {currentDate.getDate()}
+            </h2>
+          </div>
+
+          {!selectYearMode && <nav>
+            <span onClick={this.displayPrevMonth} class="icon"><i style={{ transform: 'rotate(180deg)' }} class="mdi mdi-forward" /></span>
+            <h4>{monthArrShortFull[displayedMonth]} {displayedYear}</h4>
+            <span onClick={this.displayNextMonth} class="icon"><i class="mdi mdi-forward" /></span>
+          </nav>}
+
+          <div class="datePicker--scroll">
+
+            {!selectYearMode && <div class="datePicker--calendar" >
+
+              <div class="datePicker--dayNames">
+                {['S', 'M', 'T', 'W', 'T', 'F', 'S'].map((day,i) => <span key={i}>{day}</span>)}
+              </div>
+
+              <div onClick={this.dayClicked} class="datePicker--days">
+
+                {/*
+                  Loop through the calendar object returned by getDaysByMonth().
+                */}
+
+                {this.getDaysByMonth(this.state.displayedMonth, this.state.displayedYear)
+                  .map(
+                    day => {
+                      let selected = false;
+
+                      if (currentDate && day.date) selected = (currentDate.toLocaleDateString() === day.date.toLocaleDateString());
+
+                      return (<span key={day.day}
+                        class={(day.today ? 'datePicker--today ' : '') + (selected ? 'datePicker--selected' : '')}
+                        disabled={!day.date}
+                        data-value={day.date}
+                      >
+                        {day.day}
+                      </span>)
+                    }
+                  )
+                }
+
+              </div>
+
+            </div>}
+
+            {selectYearMode && <div class="datePicker--selectYear">
+
+              {yearArr.map(year => (
+                <span key={year} class={(year === displayedYear) ? 'selected' : ''} onClick={this.changeDisplayedYear}>
+                  {year}
+                </span>
+              ))}
+
+            </div>}
+
+          </div>
+        </div>
+
+        <div class="datePicker--background" onClick={this.closeDatePicker} style={{
+          display: this.props.opened ? 'block' : 'none',
+        }}
+        />
+
+      </div>
+    )
+  }
+}
+
+
+for (let i = 2010; i <= now.getFullYear() + 10; i++) {
+  yearArr.push(i);
+}
-- 
cgit v1.2.3


From 32318a80f48bf52ca7823a0c055164f43bdaf1d6 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Wed, 27 Oct 2021 15:13:35 -0300
Subject: working version with improved ui

---
 .../src/components/fields/DateInput.tsx            |   4 +-
 .../src/components/fields/LabeledInput.tsx         |  40 ------
 .../src/components/fields/NumberInput.tsx          |  41 +++++++
 .../src/components/fields/TextInput.tsx            |  40 ++++++
 .../src/components/menu/SideBar.tsx                |  43 +++----
 .../src/components/picker/DatePicker.tsx           |  10 +-
 .../pages/home/AttributeEntryScreen.stories.tsx    |  28 +++--
 .../src/pages/home/AttributeEntryScreen.tsx        |  25 +++-
 .../src/pages/home/AuthMethodEmailSetup.tsx        |   4 +-
 .../src/pages/home/AuthMethodPostSetup.tsx         |  12 +-
 .../src/pages/home/AuthMethodQuestionSetup.tsx     |   6 +-
 .../pages/home/ChallengeOverviewScreen.stories.tsx | 134 ++++++++++++++++++++-
 .../src/pages/home/ChallengeOverviewScreen.tsx     | 118 +++++++++++-------
 .../home/ContinentSelectionScreen.stories.tsx      |   1 +
 .../pages/home/RecoveryFinishedScreen.stories.tsx  |   2 +-
 .../src/pages/home/SecretEditorScreen.tsx          |   6 +-
 .../src/pages/home/SecretSelectionScreen.tsx       | 116 ++++++++++++------
 .../src/pages/home/SolveEmailEntry.tsx             |  26 ----
 .../src/pages/home/SolvePostEntry.tsx              |  24 ----
 .../src/pages/home/SolveQuestionEntry.tsx          |  24 ----
 .../anastasis-webui/src/pages/home/SolveScreen.tsx | 121 ++++++++++++++++---
 .../src/pages/home/SolveSmsEntry.tsx               |  26 ----
 .../src/pages/home/SolveUnsupportedEntry.tsx       |  12 --
 .../src/wallet/Transaction.tsx                     |  14 +--
 24 files changed, 559 insertions(+), 318 deletions(-)
 delete mode 100644 packages/anastasis-webui/src/components/fields/LabeledInput.tsx
 create mode 100644 packages/anastasis-webui/src/components/fields/NumberInput.tsx
 create mode 100644 packages/anastasis-webui/src/components/fields/TextInput.tsx
 delete mode 100644 packages/anastasis-webui/src/pages/home/SolveEmailEntry.tsx
 delete mode 100644 packages/anastasis-webui/src/pages/home/SolvePostEntry.tsx
 delete mode 100644 packages/anastasis-webui/src/pages/home/SolveQuestionEntry.tsx
 delete mode 100644 packages/anastasis-webui/src/pages/home/SolveSmsEntry.tsx
 delete mode 100644 packages/anastasis-webui/src/pages/home/SolveUnsupportedEntry.tsx

(limited to 'packages/anastasis-webui/src/components/picker/DatePicker.tsx')

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/LabeledInput.tsx b/packages/anastasis-webui/src/components/fields/LabeledInput.tsx
deleted file mode 100644
index 96d634a4f..000000000
--- a/packages/anastasis-webui/src/components/fields/LabeledInput.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { h, VNode } from "preact";
-import { useLayoutEffect, useRef, useState } from "preact/hooks";
-
-export interface LabeledInputProps {
-  label: string;
-  grabFocus?: boolean;
-  error?: string;
-  tooltip?: string;
-  bind: [string, (x: string) => void];
-}
-
-export function LabeledInput(props: LabeledInputProps): 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}
-        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/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/TextInput.tsx b/packages/anastasis-webui/src/components/fields/TextInput.tsx
new file mode 100644
index 000000000..fa6fd9792
--- /dev/null
+++ b/packages/anastasis-webui/src/components/fields/TextInput.tsx
@@ -0,0 +1,40 @@
+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 TextInput(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}
+        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/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>;
-- 
cgit v1.2.3


From a82b5a6992fda61d6eaa0bb079e284805a394777 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Wed, 3 Nov 2021 17:30:11 -0300
Subject: feedback from meeting and editing policy

---
 packages/anastasis-webui/package.json              |   4 +-
 .../anastasis-webui/src/components/AsyncButton.tsx |  51 ++++++++
 .../src/components/fields/DateInput.tsx            |  46 ++++---
 .../src/components/menu/NavigationBar.tsx          |   2 +-
 .../src/components/menu/SideBar.tsx                |  14 +--
 .../src/components/picker/DatePicker.tsx           |  12 +-
 packages/anastasis-webui/src/hooks/async.ts        |  77 ++++++++++++
 .../pages/home/AttributeEntryScreen.stories.tsx    |   4 +-
 .../src/pages/home/AttributeEntryScreen.tsx        |  37 ++++--
 .../src/pages/home/AuthenticationEditorScreen.tsx  |   4 +
 .../src/pages/home/BackupFinishedScreen.tsx        |   7 +-
 .../home/ContinentSelectionScreen.stories.tsx      |  18 ++-
 .../src/pages/home/ContinentSelectionScreen.tsx    |  36 +++---
 .../pages/home/CountrySelectionScreen.stories.tsx  |  39 ------
 .../src/pages/home/CountrySelectionScreen.tsx      |  31 -----
 .../src/pages/home/EditPoliciesScreen.stories.tsx  | 109 +++++++++++++++++
 .../src/pages/home/EditPoliciesScreen.tsx          | 133 +++++++++++++++++++++
 .../pages/home/ReviewPoliciesScreen.stories.tsx    |   8 +-
 .../src/pages/home/ReviewPoliciesScreen.tsx        |  57 +++++++--
 .../anastasis-webui/src/pages/home/StartScreen.tsx |  42 +++----
 .../home/authMethod/AuthMethodQuestionSetup.tsx    |  15 +--
 packages/anastasis-webui/src/pages/home/index.tsx  |  33 ++---
 packages/anastasis-webui/src/scss/main.scss        |   2 +-
 packages/anastasis-webui/src/utils/index.tsx       |  97 ++++++++++++---
 24 files changed, 657 insertions(+), 221 deletions(-)
 create mode 100644 packages/anastasis-webui/src/components/AsyncButton.tsx
 create mode 100644 packages/anastasis-webui/src/hooks/async.ts
 delete mode 100644 packages/anastasis-webui/src/pages/home/CountrySelectionScreen.stories.tsx
 delete mode 100644 packages/anastasis-webui/src/pages/home/CountrySelectionScreen.tsx
 create mode 100644 packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx
 create mode 100644 packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx

(limited to 'packages/anastasis-webui/src/components/picker/DatePicker.tsx')

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,
 
-- 
cgit v1.2.3


From ae0a35df2b2934c517954d2a73af4cc6e1734e30 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Thu, 4 Nov 2021 15:17:57 -0300
Subject: async, onInput, and some fixes

---
 .../anastasis-webui/src/components/AsyncButton.tsx |  4 +-
 .../src/components/fields/DateInput.tsx            |  2 +-
 .../src/components/fields/EmailInput.tsx           |  2 +-
 .../src/components/fields/NumberInput.tsx          |  2 +-
 .../src/components/fields/TextInput.tsx            |  2 +-
 .../src/components/picker/DatePicker.tsx           |  2 +-
 packages/anastasis-webui/src/hooks/async.ts        |  4 +-
 .../src/pages/home/AttributeEntryScreen.tsx        |  4 +-
 .../src/pages/home/AuthenticationEditorScreen.tsx  |  4 +-
 .../src/pages/home/ChallengeOverviewScreen.tsx     |  1 -
 .../src/pages/home/ContinentSelectionScreen.tsx    |  4 +-
 .../src/pages/home/RecoveryFinishedScreen.tsx      |  3 +
 .../src/pages/home/SecretEditorScreen.tsx          | 31 ++++++----
 .../src/pages/home/SecretSelectionScreen.tsx       | 71 ++++++++++++----------
 .../anastasis-webui/src/pages/home/SolveScreen.tsx |  3 +
 packages/anastasis-webui/src/pages/home/index.tsx  |  6 +-
 packages/anastasis-webui/src/utils/index.tsx       |  8 +--
 packages/taler-wallet-webextension/package.json    |  4 +-
 pnpm-lock.yaml                                     | 49 +++++----------
 19 files changed, 101 insertions(+), 105 deletions(-)

(limited to 'packages/anastasis-webui/src/components/picker/DatePicker.tsx')

diff --git a/packages/anastasis-webui/src/components/AsyncButton.tsx b/packages/anastasis-webui/src/components/AsyncButton.tsx
index 5602715e4..af85016e8 100644
--- a/packages/anastasis-webui/src/components/AsyncButton.tsx
+++ b/packages/anastasis-webui/src/components/AsyncButton.tsx
@@ -37,9 +37,7 @@ export function AsyncButton({ onClick, disabled, children, ...rest }: Props): VN
   // if (isSlow) {
   //   return <LoadingModal onCancel={cancel} />;
   // }
-  console.log(isLoading)
-  if (isLoading) {
-    
+  if (isLoading) {    
     return <button class="button">Loading...</button>;
   }
 
diff --git a/packages/anastasis-webui/src/components/fields/DateInput.tsx b/packages/anastasis-webui/src/components/fields/DateInput.tsx
index c406b85d1..3148c953f 100644
--- a/packages/anastasis-webui/src/components/fields/DateInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/DateInput.tsx
@@ -41,7 +41,7 @@ export function DateInput(props: DateInputProps): VNode {
             type="text"
             class={showError ? 'input is-danger' : 'input'}
             value={value}
-            onChange={(e) => {
+            onInput={(e) => {
               const text = e.currentTarget.value
               setDirty(true)
               props.bind[1](text);
diff --git a/packages/anastasis-webui/src/components/fields/EmailInput.tsx b/packages/anastasis-webui/src/components/fields/EmailInput.tsx
index e0fca0f46..e21418fea 100644
--- a/packages/anastasis-webui/src/components/fields/EmailInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/EmailInput.tsx
@@ -34,7 +34,7 @@ export function EmailInput(props: TextInputProps): VNode {
         placeholder={props.placeholder}
         type="email"
         class={showError ? 'input is-danger' : 'input'}
-        onChange={(e) => {setDirty(true); props.bind[1]((e.target as HTMLInputElement).value)}}
+        onInput={(e) => {setDirty(true); props.bind[1]((e.target as HTMLInputElement).value)}}
         ref={inputRef}
         style={{ display: "block" }} />
     </div>
diff --git a/packages/anastasis-webui/src/components/fields/NumberInput.tsx b/packages/anastasis-webui/src/components/fields/NumberInput.tsx
index 2b6cdcd2c..2afb242b8 100644
--- a/packages/anastasis-webui/src/components/fields/NumberInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/NumberInput.tsx
@@ -33,7 +33,7 @@ export function NumberInput(props: TextInputProps): VNode {
         type="number"
         placeholder={props.placeholder}
         class={showError ? 'input is-danger' : 'input'}
-        onChange={(e) => {setDirty(true); props.bind[1]((e.target as HTMLInputElement).value)}}
+        onInput={(e) => {setDirty(true); props.bind[1]((e.target as HTMLInputElement).value)}}
         ref={inputRef}
         style={{ display: "block" }} />
     </div>
diff --git a/packages/anastasis-webui/src/components/fields/TextInput.tsx b/packages/anastasis-webui/src/components/fields/TextInput.tsx
index 4bb785cd3..c093689c5 100644
--- a/packages/anastasis-webui/src/components/fields/TextInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/TextInput.tsx
@@ -32,7 +32,7 @@ export function TextInput(props: TextInputProps): VNode {
         value={value}
         placeholder={props.placeholder}
         class={showError ? 'input is-danger' : 'input'}
-        onChange={(e) => {setDirty(true); props.bind[1]((e.target as HTMLInputElement).value)}}
+        onInput={(e) => {setDirty(true); props.bind[1]((e.target as HTMLInputElement).value)}}
         ref={inputRef}
         style={{ display: "block" }} />
     </div>
diff --git a/packages/anastasis-webui/src/components/picker/DatePicker.tsx b/packages/anastasis-webui/src/components/picker/DatePicker.tsx
index a94b3708e..eb5d8145d 100644
--- a/packages/anastasis-webui/src/components/picker/DatePicker.tsx
+++ b/packages/anastasis-webui/src/components/picker/DatePicker.tsx
@@ -214,7 +214,7 @@ export class DatePicker extends Component<Props, State> {
     // }
   }
 
-  constructor(props) {
+  constructor(props: any) {
     super(props);
 
     this.closeDatePicker = this.closeDatePicker.bind(this);
diff --git a/packages/anastasis-webui/src/hooks/async.ts b/packages/anastasis-webui/src/hooks/async.ts
index f142a5dc5..ea3ff6acf 100644
--- a/packages/anastasis-webui/src/hooks/async.ts
+++ b/packages/anastasis-webui/src/hooks/async.ts
@@ -43,14 +43,14 @@ export function useAsync<T>(fn?: (...args: any) => Promise<T>, { slowTolerance:
   const request = async (...args: any) => {
     if (!fn) return;
     setLoading(true);
-    console.log("loading true")
     const handler = setTimeout(() => {
       setSlow(true)
     }, tooLong)
 
     try {
+      console.log("calling async", args)
       const result = await fn(...args);
-      console.log(result)
+      console.log("async back", result)
       setData(result);
     } catch (error) {
       setError(error);
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
index 52046b216..f86994c97 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
@@ -48,10 +48,10 @@ export function AttributeEntryScreen(): VNode {
       })}
     >
       <div class="columns" style={{ maxWidth: 'unset' }}>
-        <div class="column is-one-third">
+        <div class="column is-half">
           {fieldList}
         </div>
-        <div class="column is-two-third" >
+        <div class="column is-is-half" >
           <p>This personal information will help to locate your secret.</p>
           <h1 class="title">This stays private</h1>
           <p>The information you have entered here:</p>
diff --git a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
index b95d3f1e3..93ca81194 100644
--- a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
@@ -135,7 +135,7 @@ export function AuthenticationEditorScreen(): VNode {
   return (
     <AnastasisClientFrame title="Backup: Configure Authentication Methods" hideNext={errors}>
       <div class="columns">
-        <div class="column one-third">
+        <div class="column is-half">
           <div>
             {getKeys(authMethods).map(method => <MethodButton key={method} method={method} />)}
           </div>
@@ -152,7 +152,7 @@ export function AuthenticationEditorScreen(): VNode {
             </p>
           </ConfirmModal>}
         </div>
-        <div class="column two-third">
+        <div class="column is-half">
           <p class="block">
             When recovering your wallet, you will be asked to verify your identity via the methods you configure here.
             The list of authentication method is defined by the backup provider list.
diff --git a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
index 7bafbe06a..ed34bbde2 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable @typescript-eslint/camelcase */
 import { ChallengeFeedback, ChallengeFeedbackStatus } from "anastasis-core";
 import { h, VNode } from "preact";
 import { useAnastasisContext } from "../../context/anastasis";
diff --git a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
index 4ab0e6a9b..0e43f982d 100644
--- a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
@@ -1,5 +1,4 @@
 /* eslint-disable @typescript-eslint/camelcase */
-import { BackupStates, ContinentInfo, RecoveryStates } from "anastasis-core";
 import { h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { useAnastasisContext } from "../../context/anastasis";
@@ -9,7 +8,8 @@ export function ContinentSelectionScreen(): VNode {
   const reducer = useAnastasisContext()
 
   //FIXME: remove this when #7056 is fixed
-  const [countryCode, setCountryCode] = useState("")
+  const countryFromReducer = (reducer?.currentReducerState as any).selected_country || "" 
+  const [countryCode, setCountryCode] = useState( countryFromReducer )
 
   if (!reducer || !reducer.currentReducerState || !("continents" in reducer.currentReducerState)) {
     return <div />
diff --git a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
index bbcaa10a5..3740592b1 100644
--- a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
@@ -29,6 +29,9 @@ export function RecoveryFinishedScreen(): VNode {
       <p>
         Secret: {secret}
       </p>
+      <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/SecretEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
index 915465c3f..1b36a1b21 100644
--- a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
@@ -4,7 +4,8 @@ import { h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { useAnastasisContext } from "../../context/anastasis";
 import {
-  AnastasisClientFrame} from "./index";
+  AnastasisClientFrame
+} from "./index";
 import { TextInput } from "../../components/fields/TextInput";
 import { FileInput } from "../../components/fields/FileInput";
 
@@ -12,12 +13,12 @@ export function SecretEditorScreen(): VNode {
   const reducer = useAnastasisContext()
   const [secretValue, setSecretValue] = useState("");
 
-  const currentSecretName = reducer?.currentReducerState 
-    && ("secret_name" in reducer.currentReducerState) 
+  const currentSecretName = reducer?.currentReducerState
+    && ("secret_name" in reducer.currentReducerState)
     && reducer.currentReducerState.secret_name;
 
   const [secretName, setSecretName] = useState(currentSecretName || "");
-  
+
   if (!reducer) {
     return <div>no reducer in context</div>
   }
@@ -25,8 +26,8 @@ export function SecretEditorScreen(): VNode {
     return <div>invalid state</div>
   }
 
-  const secretNext = (): void => {
-    reducer.runTransaction(async (tx) => {
+  const secretNext = async (): Promise<void> => {
+    return reducer.runTransaction(async (tx) => {
       await tx.transition("enter_secret_name", {
         name: secretName,
       });
@@ -44,25 +45,29 @@ export function SecretEditorScreen(): VNode {
   };
   return (
     <AnastasisClientFrame
-      title="Backup: Provide secret"
+      title="Backup: Provide secret to backup"
       onNext={() => secretNext()}
     >
       <div>
         <TextInput
-          label="Secret Name:"
+          label="Secret's name:"
           grabFocus
           bind={[secretName, setSecretName]}
         />
       </div>
       <div>
         <TextInput
-          label="Secret Value:"
-          bind={[secretValue, setSecretValue]}
-        /> or import a file
-        <FileInput 
-          label="Open file from your device"
+          label="Enter the secret as text:"
           bind={[secretValue, setSecretValue]}
         />
+        <div style={{display:'flex',}}>
+          or&nbsp; 
+          <FileInput
+            label="click here"
+            bind={[secretValue, setSecretValue]}
+          />
+          &nbsp;to import a file
+        </div>
       </div>
     </AnastasisClientFrame>
   );
diff --git a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
index d0b83bda5..e1aeb3939 100644
--- a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
@@ -97,39 +97,44 @@ export function SecretSelectionScreen(): VNode {
   }
   return (
     <AnastasisClientFrame title="Recovery: Select secret">
-      <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>
+      <div class="columns">
+        <div class="column is-half">
+          <div class="box">
+            <h1 class="subtitle">{recoveryDocument.provider_url}</h1>
+            <table class="table">
+              <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>
+            <div class="buttons is-right">
+              <button class="button" disabled onClick={() => reducer.reset()}>Use this provider</button>
+            </div>
+          </div>
+          <div class="buttons is-right">
+            <button class="button" disabled onClick={() => reducer.reset()}>Change provider</button>
+          </div>
+        </div>
+        <div class="column is-two-third">
+          <p>Secret found, you can select another version or continue to the challenges solving</p>
+        </div>
+      </div>
     </AnastasisClientFrame>
   );
 }
diff --git a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
index d4d9271b4..df55de6ab 100644
--- a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
@@ -77,6 +77,9 @@ export function SolveScreen(): VNode {
     return (
       <AnastasisClientFrame hideNav title="Recovery problem">
         <div>invalid state</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/index.tsx b/packages/anastasis-webui/src/pages/home/index.tsx
index 415cf6e98..346738c26 100644
--- a/packages/anastasis-webui/src/pages/home/index.tsx
+++ b/packages/anastasis-webui/src/pages/home/index.tsx
@@ -96,12 +96,12 @@ export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
     return <p>Fatal: Reducer must be in context.</p>;
   }
   const next = async (): Promise<void> => {
-    return new Promise((res, rej) => {
+    return new Promise(async (res, rej) => {
       try {
         if (props.onNext) {
-          props.onNext();
+          await props.onNext();
         } else {
-          reducer.transition("next", {});
+          await reducer.transition("next", {});
         }
         res()
       } catch {
diff --git a/packages/anastasis-webui/src/utils/index.tsx b/packages/anastasis-webui/src/utils/index.tsx
index 244be8af8..9c01aa6ba 100644
--- a/packages/anastasis-webui/src/utils/index.tsx
+++ b/packages/anastasis-webui/src/utils/index.tsx
@@ -8,13 +8,13 @@ export function createExample<Props>(Component: FunctionalComponent<Props>, curr
     return <AnastasisProvider value={{
       currentReducerState,
       currentError: undefined,
-      back: () => { null },
-      dismissError: () => { null },
+      back: async () => { null },
+      dismissError: async () => { null },
       reset: () => { null },
-      runTransaction: () => { null },
+      runTransaction: async () => { null },
       startBackup: () => { null },
       startRecover: () => { null },
-      transition: () => { null },
+      transition: async () => { null },
     }}>
       <Component {...args} />
     </AnastasisProvider>
diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json
index 4023e4ebd..3a43f1e76 100644
--- a/packages/taler-wallet-webextension/package.json
+++ b/packages/taler-wallet-webextension/package.json
@@ -45,7 +45,7 @@
     "@storybook/preact": "^6.2.9",
     "@testing-library/preact": "^2.0.1",
     "@types/chrome": "^0.0.128",
-    "@types/enzyme": "^3.10.8",
+    "@types/enzyme": "^3.10.10",
     "@types/history": "^4.7.8",
     "@types/jest": "^26.0.23",
     "@types/node": "^14.14.22",
@@ -80,4 +80,4 @@
       "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|po)$": "<rootDir>/tests/__mocks__/fileTransformer.js"
     }
   }
-}
\ No newline at end of file
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 100bde514..ce6296f3d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -341,7 +341,7 @@ importers:
       '@storybook/preact': ^6.2.9
       '@testing-library/preact': ^2.0.1
       '@types/chrome': ^0.0.128
-      '@types/enzyme': ^3.10.8
+      '@types/enzyme': ^3.10.10
       '@types/history': ^4.7.8
       '@types/jest': ^26.0.23
       '@types/node': ^14.14.22
@@ -397,7 +397,7 @@ importers:
       '@storybook/preact': 6.3.7_9cd0ede338ef3d2deb8dbc69bc115c66
       '@testing-library/preact': 2.0.1_preact@10.5.14
       '@types/chrome': 0.0.128
-      '@types/enzyme': 3.10.9
+      '@types/enzyme': 3.10.10
       '@types/history': 4.7.9
       '@types/jest': 26.0.24
       '@types/node': 14.17.10
@@ -9881,13 +9881,6 @@ packages:
       '@types/react': 17.0.34
     dev: true
 
-  /@types/enzyme/3.10.9:
-    resolution: {integrity: sha512-dx5UvcWe2Vtye6S9Hw2rFB7Ul9uMXOAje2FAbXvVYieQDNle9qPAo7DfvFMSztZ9NFiD3dVZ4JsRYGTrSLynJg==}
-    dependencies:
-      '@types/cheerio': 0.22.30
-      '@types/react': 17.0.19
-    dev: true
-
   /@types/estree/0.0.39:
     resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
     dev: true
@@ -10099,14 +10092,6 @@ packages:
       '@types/react': 17.0.34
     dev: true
 
-  /@types/react/17.0.19:
-    resolution: {integrity: sha512-sX1HisdB1/ZESixMTGnMxH9TDe8Sk709734fEQZzCV/4lSu9kJCPbo2PbTRoZM+53Pp0P10hYVyReUueGwUi4A==}
-    dependencies:
-      '@types/prop-types': 15.7.4
-      '@types/scheduler': 0.16.2
-      csstype: 3.0.8
-    dev: true
-
   /@types/react/17.0.34:
     resolution: {integrity: sha512-46FEGrMjc2+8XhHXILr+3+/sTe3OfzSPU9YGKILLrUYbQ1CLQC9Daqo1KzENGXAWwrFwiY0l4ZbF20gRvgpWTg==}
     dependencies:
@@ -11397,7 +11382,7 @@ packages:
   /axios/0.21.4:
     resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
     dependencies:
-      follow-redirects: 1.14.5
+      follow-redirects: 1.14.5_debug@4.3.2
     transitivePeerDependencies:
       - debug
     dev: true
@@ -13562,10 +13547,6 @@ packages:
     resolution: {integrity: sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==}
     dev: true
 
-  /csstype/3.0.8:
-    resolution: {integrity: sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==}
-    dev: true
-
   /csstype/3.0.9:
     resolution: {integrity: sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==}
     dev: true
@@ -15471,16 +15452,6 @@ packages:
         optional: true
     dev: false
 
-  /follow-redirects/1.14.5:
-    resolution: {integrity: sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==}
-    engines: {node: '>=4.0'}
-    peerDependencies:
-      debug: '*'
-    peerDependenciesMeta:
-      debug:
-        optional: true
-    dev: true
-
   /follow-redirects/1.14.5_debug@4.3.2:
     resolution: {integrity: sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==}
     engines: {node: '>=4.0'}
@@ -20713,7 +20684,7 @@ packages:
     resolution: {integrity: sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==}
     engines: {node: '>=6'}
     dependencies:
-      ts-pnp: 1.2.0_typescript@4.4.3
+      ts-pnp: 1.2.0_typescript@4.3.5
     transitivePeerDependencies:
       - typescript
     dev: true
@@ -24776,6 +24747,18 @@ packages:
       tslib: 2.3.1
     dev: true
 
+  /ts-pnp/1.2.0_typescript@4.3.5:
+    resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}
+    engines: {node: '>=6'}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      typescript: 4.3.5
+    dev: true
+
   /ts-pnp/1.2.0_typescript@4.4.3:
     resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}
     engines: {node: '>=6'}
-- 
cgit v1.2.3

