some storybook exmaples
This commit is contained in:
parent
3740010117
commit
2ec2161a7e
@ -51,7 +51,7 @@ export interface ReducerStateBackup {
|
|||||||
identity_attributes?: { [n: string]: string };
|
identity_attributes?: { [n: string]: string };
|
||||||
authentication_providers?: { [url: string]: AuthenticationProviderStatus };
|
authentication_providers?: { [url: string]: AuthenticationProviderStatus };
|
||||||
authentication_methods?: AuthMethod[];
|
authentication_methods?: AuthMethod[];
|
||||||
required_attributes?: any;
|
required_attributes?: UserAttributeSpec[];
|
||||||
selected_continent?: string;
|
selected_continent?: string;
|
||||||
selected_country?: string;
|
selected_country?: string;
|
||||||
secret_name?: string;
|
secret_name?: string;
|
||||||
@ -133,7 +133,7 @@ export interface ReducerStateRecovery {
|
|||||||
selected_country?: string;
|
selected_country?: string;
|
||||||
currencies?: string[];
|
currencies?: string[];
|
||||||
|
|
||||||
required_attributes?: any;
|
required_attributes?: UserAttributeSpec[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recovery information, used by the UI.
|
* Recovery information, used by the UI.
|
||||||
|
1
packages/anastasis-webui/.gitignore
vendored
1
packages/anastasis-webui/.gitignore
vendored
@ -2,3 +2,4 @@ node_modules
|
|||||||
/build
|
/build
|
||||||
/*.log
|
/*.log
|
||||||
/size-plugin.json
|
/size-plugin.json
|
||||||
|
/storybook-static/
|
||||||
|
25
packages/anastasis-webui/.storybook/.babelrc
Normal file
25
packages/anastasis-webui/.storybook/.babelrc
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
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)
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
"preact-cli/babel"
|
||||||
|
]
|
||||||
|
}
|
57
packages/anastasis-webui/.storybook/main.js
Normal file
57
packages/anastasis-webui/.storybook/main.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
"stories": [
|
||||||
|
"../src/**/*.stories.mdx",
|
||||||
|
"../src/**/*.stories.@(js|jsx|ts|tsx)"
|
||||||
|
],
|
||||||
|
"addons": [
|
||||||
|
"@storybook/preset-scss",
|
||||||
|
"@storybook/addon-a11y",
|
||||||
|
"@storybook/addon-essentials" //docs, control, actions, viewpot, toolbar, background
|
||||||
|
],
|
||||||
|
// sb does not yet support new jsx transform by default
|
||||||
|
// https://github.com/storybookjs/storybook/issues/12881
|
||||||
|
// https://github.com/storybookjs/storybook/issues/12952
|
||||||
|
babel: async (options) => ({
|
||||||
|
...options,
|
||||||
|
presets: [
|
||||||
|
...options.presets,
|
||||||
|
[
|
||||||
|
'@babel/preset-react', {
|
||||||
|
runtime: 'automatic',
|
||||||
|
},
|
||||||
|
'preset-react-jsx-transform'
|
||||||
|
],
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
webpackFinal: (config) => {
|
||||||
|
// should be removed after storybook 6.3
|
||||||
|
// https://github.com/storybookjs/storybook/issues/12853#issuecomment-821576113
|
||||||
|
config.resolve.alias = {
|
||||||
|
react: "preact/compat",
|
||||||
|
"react-dom": "preact/compat",
|
||||||
|
};
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
}
|
49
packages/anastasis-webui/.storybook/preview.js
Normal file
49
packages/anastasis-webui/.storybook/preview.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
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/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "../src/scss/main.scss"
|
||||||
|
import { TranslationProvider } from '../src/context/translation'
|
||||||
|
import { h } from 'preact';
|
||||||
|
|
||||||
|
|
||||||
|
export const parameters = {
|
||||||
|
controls: { expanded: true },
|
||||||
|
}
|
||||||
|
|
||||||
|
export const globalTypes = {
|
||||||
|
locale: {
|
||||||
|
name: 'Locale',
|
||||||
|
description: 'Internationalization locale',
|
||||||
|
defaultValue: 'en',
|
||||||
|
toolbar: {
|
||||||
|
icon: 'globe',
|
||||||
|
items: [
|
||||||
|
{ value: 'en', right: '🇺🇸', title: 'English' },
|
||||||
|
{ value: 'es', right: '🇪🇸', title: 'Spanish' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decorators = [
|
||||||
|
(Story, { globals }) => {
|
||||||
|
document.body.parentElement.classList = "has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded"
|
||||||
|
return <Story />
|
||||||
|
},
|
||||||
|
(Story, { globals }) => <TranslationProvider initial='en' forceLang={globals.locale}>
|
||||||
|
<Story />
|
||||||
|
</TranslationProvider>,
|
||||||
|
];
|
@ -8,7 +8,9 @@
|
|||||||
"serve": "sirv build --port 8080 --cors --single",
|
"serve": "sirv build --port 8080 --cors --single",
|
||||||
"dev": "preact watch",
|
"dev": "preact watch",
|
||||||
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
|
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
|
||||||
"test": "jest ./tests"
|
"test": "jest ./tests",
|
||||||
|
"build-storybook": "build-storybook",
|
||||||
|
"storybook": "start-storybook -p 6006"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
@ -30,6 +32,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@creativebulma/bulma-tooltip": "^1.2.0",
|
"@creativebulma/bulma-tooltip": "^1.2.0",
|
||||||
|
"@storybook/addon-a11y": "^6.2.9",
|
||||||
|
"@storybook/addon-actions": "^6.2.9",
|
||||||
|
"@storybook/addon-essentials": "^6.2.9",
|
||||||
|
"@storybook/addon-links": "^6.2.9",
|
||||||
|
"@storybook/preact": "^6.2.9",
|
||||||
|
"@storybook/preset-scss": "^1.0.3",
|
||||||
"@types/enzyme": "^3.10.5",
|
"@types/enzyme": "^3.10.5",
|
||||||
"@types/jest": "^26.0.8",
|
"@types/jest": "^26.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.25.0",
|
"@typescript-eslint/eslint-plugin": "^2.25.0",
|
||||||
|
@ -20,7 +20,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import { h, VNode } from 'preact';
|
import { Fragment, h, VNode } from 'preact';
|
||||||
|
import { BackupStates, RecoveryStates } from '../../../../anastasis-core/lib';
|
||||||
|
import { useAnastasisContext } from '../../context/anastasis';
|
||||||
import { Translate } from '../../i18n';
|
import { Translate } from '../../i18n';
|
||||||
import { LangSelector } from './LangSelector';
|
import { LangSelector } from './LangSelector';
|
||||||
|
|
||||||
@ -31,7 +33,8 @@ interface Props {
|
|||||||
export function Sidebar({ mobile }: Props): VNode {
|
export function Sidebar({ mobile }: Props): VNode {
|
||||||
// const config = useConfigContext();
|
// const config = useConfigContext();
|
||||||
const config = { version: 'none' }
|
const config = { version: 'none' }
|
||||||
const process = { env : { __VERSION__: '0.0.0'}}
|
const process = { env: { __VERSION__: '0.0.0' } }
|
||||||
|
const reducer = useAnastasisContext()!
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside class="aside is-placed-left is-expanded">
|
<aside class="aside is-placed-left is-expanded">
|
||||||
@ -47,52 +50,117 @@ export function Sidebar({ mobile }: Props): VNode {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="menu is-menu-main">
|
<div class="menu is-menu-main">
|
||||||
|
{!reducer.currentReducerState &&
|
||||||
<p class="menu-label">
|
<p class="menu-label">
|
||||||
<Translate>Back up a secret</Translate>
|
<Translate>Backup or Recorver</Translate>
|
||||||
</p>
|
</p>
|
||||||
|
}
|
||||||
<ul class="menu-list">
|
<ul class="menu-list">
|
||||||
|
{!reducer.currentReducerState &&
|
||||||
<li>
|
<li>
|
||||||
<div class="has-icon">
|
<div class="ml-4">
|
||||||
<span class="icon"><i class="mdi mdi-square-edit-outline" /></span>
|
<span class="menu-item-label"><Translate>Start one options</Translate></span>
|
||||||
<span class="menu-item-label"><Translate>Location & Currency</Translate></span>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="is-active">
|
}
|
||||||
<div class="has-icon">
|
{reducer.currentReducerState && reducer.currentReducerState.backup_state ? <Fragment>
|
||||||
<span class="icon"><i class="mdi mdi-cash-register" /></span>
|
<li class={reducer.currentReducerState.backup_state === BackupStates.ContinentSelecting ? 'is-active' : ''}>
|
||||||
<span class="menu-item-label"><Translate>Personal information</Translate></span>
|
<div class="ml-4">
|
||||||
|
<span class="menu-item-label"><Translate>Continent selection</Translate></span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
<li class={reducer.currentReducerState.backup_state === BackupStates.CountrySelecting ? 'is-active' : ''}>
|
||||||
|
<div class="ml-4">
|
||||||
|
<span class="menu-item-label"><Translate>Country selection</Translate></span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class={reducer.currentReducerState.backup_state === BackupStates.UserAttributesCollecting ? 'is-active' : ''}>
|
||||||
|
<div class="ml-4">
|
||||||
|
|
||||||
|
<span class="menu-item-label"><Translate>User attributes</Translate></span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class={reducer.currentReducerState.backup_state === BackupStates.AuthenticationsEditing ? 'is-active' : ''}>
|
||||||
|
<div class="ml-4">
|
||||||
|
|
||||||
|
<span class="menu-item-label"><Translate>Auth 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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</Fragment> : (reducer.currentReducerState && reducer.currentReducerState?.recovery_state && <Fragment>
|
||||||
|
<li class={reducer.currentReducerState.recovery_state === RecoveryStates.ContinentSelecting ? 'is-active' : ''}>
|
||||||
|
<div class="ml-4">
|
||||||
|
<span class="menu-item-label"><Translate>TruthsPaying</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class={reducer.currentReducerState.recovery_state === RecoveryStates.ChallengeSolving ? 'is-active' : ''}>
|
||||||
|
<div class="ml-4">
|
||||||
|
<span class="menu-item-label"><Translate>ChallengeSolving</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>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</Fragment>)}
|
||||||
|
{reducer.currentReducerState &&
|
||||||
<li>
|
<li>
|
||||||
<div class="has-icon">
|
<div class="buttons ml-4">
|
||||||
<span class="icon"><i class="mdi mdi-shopping" /></span>
|
<button class="button is-danger is-right" onClick={() => reducer.reset()}>Reset session</button>
|
||||||
<span class="menu-item-label"><Translate>Authorization methods</Translate></span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div class="has-icon">
|
|
||||||
<span class="icon"><i class="mdi mdi-bank" /></span>
|
|
||||||
<span class="menu-item-label"><Translate>Recovery policies</Translate></span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div class="has-icon">
|
|
||||||
<span class="icon"><i class="mdi mdi-bank" /></span>
|
|
||||||
<span class="menu-item-label"><Translate>Enter secrets</Translate></span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div class="has-icon">
|
|
||||||
<span class="icon"><i class="mdi mdi-bank" /></span>
|
|
||||||
<span class="menu-item-label"><Translate>Payment (optional)</Translate></span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div class="has-icon">
|
|
||||||
<span class="icon"><i class="mdi mdi-cash" /></span>
|
|
||||||
<span class="menu-item-label">Backup completed</span>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
41
packages/anastasis-webui/src/context/anastasis.ts
Normal file
41
packages/anastasis-webui/src/context/anastasis.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
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 { createContext, h, VNode } from 'preact';
|
||||||
|
import { useContext } from 'preact/hooks';
|
||||||
|
import { AnastasisReducerApi } from '../hooks/use-anastasis-reducer';
|
||||||
|
|
||||||
|
type Type = AnastasisReducerApi | undefined;
|
||||||
|
|
||||||
|
const initial = undefined
|
||||||
|
|
||||||
|
const Context = createContext<Type>(initial)
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value: AnastasisReducerApi;
|
||||||
|
children: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AnastasisProvider = ({ value, children }: Props): VNode => {
|
||||||
|
return h(Context.Provider, { value, children });
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAnastasisContext = (): Type => useContext(Context);
|
@ -0,0 +1,63 @@
|
|||||||
|
/* 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 { AttributeEntryScreen as TestedComponent } from './AttributeEntryScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/AttributeEntryScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithSomeAttributes = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.attributeEditing,
|
||||||
|
required_attributes: [{
|
||||||
|
name: 'first',
|
||||||
|
label: 'first',
|
||||||
|
type: 'type',
|
||||||
|
uuid: 'asdasdsa1',
|
||||||
|
widget: 'wid',
|
||||||
|
}, {
|
||||||
|
name: 'pepe',
|
||||||
|
label: 'second',
|
||||||
|
type: 'type',
|
||||||
|
uuid: 'asdasdsa2',
|
||||||
|
widget: 'wid',
|
||||||
|
}, {
|
||||||
|
name: 'pepe2',
|
||||||
|
label: 'third',
|
||||||
|
type: 'type',
|
||||||
|
uuid: 'asdasdsa3',
|
||||||
|
widget: 'calendar',
|
||||||
|
}]
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const Empty = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.attributeEditing,
|
||||||
|
required_attributes: undefined
|
||||||
|
} as ReducerState);
|
@ -1,15 +1,24 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { ReducerStateRecovery, ReducerStateBackup } from "../../../../anastasis-core/lib";
|
import { ReducerStateRecovery, ReducerStateBackup, UserAttributeSpec } from "anastasis-core/lib";
|
||||||
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import { AnastasisReducerApi } from "../../hooks/use-anastasis-reducer";
|
import { AnastasisReducerApi } from "../../hooks/use-anastasis-reducer";
|
||||||
import { AnastasisClientFrame, withProcessLabel, LabeledInput } from "./index";
|
import { AnastasisClientFrame, withProcessLabel, LabeledInput } from "./index";
|
||||||
|
|
||||||
export function AttributeEntryScreen(props: AttributeEntryProps): VNode {
|
export function AttributeEntryScreen(): VNode {
|
||||||
const { reducer, reducerState: backupState } = props;
|
const reducer = useAnastasisContext()
|
||||||
const [attrs, setAttrs] = useState<Record<string, string>>(
|
const state = reducer?.currentReducerState
|
||||||
props.reducerState.identity_attributes ?? {}
|
const currentIdentityAttributes = state && "identity_attributes" in state ? (state.identity_attributes || {}) : {}
|
||||||
);
|
const [attrs, setAttrs] = useState<Record<string, string>>(currentIdentityAttributes);
|
||||||
|
|
||||||
|
if (!reducer) {
|
||||||
|
return <div>no reducer in context</div>
|
||||||
|
}
|
||||||
|
if (!reducer.currentReducerState || !("required_attributes" in reducer.currentReducerState)) {
|
||||||
|
return <div>invalid state</div>
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame
|
<AnastasisClientFrame
|
||||||
title={withProcessLabel(reducer, "Select Country")}
|
title={withProcessLabel(reducer, "Select Country")}
|
||||||
@ -17,7 +26,7 @@ export function AttributeEntryScreen(props: AttributeEntryProps): VNode {
|
|||||||
identity_attributes: attrs,
|
identity_attributes: attrs,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{backupState.required_attributes.map((x: any, i: number) => {
|
{reducer.currentReducerState.required_attributes?.map((x, i: number) => {
|
||||||
return (
|
return (
|
||||||
<AttributeEntryField
|
<AttributeEntryField
|
||||||
key={i}
|
key={i}
|
||||||
@ -40,7 +49,7 @@ export interface AttributeEntryFieldProps {
|
|||||||
isFirst: boolean;
|
isFirst: boolean;
|
||||||
value: string;
|
value: string;
|
||||||
setValue: (newValue: string) => void;
|
setValue: (newValue: string) => void;
|
||||||
spec: any;
|
spec: UserAttributeSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AttributeEntryField(props: AttributeEntryFieldProps): VNode {
|
export function AttributeEntryField(props: AttributeEntryFieldProps): VNode {
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
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 { AuthenticationEditorScreen as TestedComponent } from './AuthenticationEditorScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/AuthenticationEditorScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Example = createExample(TestedComponent, reducerStatesExample.authEditing);
|
@ -1,7 +1,8 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
|
import { AuthMethod, ReducerStateBackup } from "anastasis-core";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { AuthMethod, ReducerStateBackup } from "anastasis-core";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import { AnastasisReducerApi } from "../../hooks/use-anastasis-reducer";
|
import { AnastasisReducerApi } from "../../hooks/use-anastasis-reducer";
|
||||||
import { AuthMethodEmailSetup } from "./AuthMethodEmailSetup";
|
import { AuthMethodEmailSetup } from "./AuthMethodEmailSetup";
|
||||||
import { AuthMethodPostSetup } from "./AuthMethodPostSetup";
|
import { AuthMethodPostSetup } from "./AuthMethodPostSetup";
|
||||||
@ -9,12 +10,18 @@ import { AuthMethodQuestionSetup } from "./AuthMethodQuestionSetup";
|
|||||||
import { AuthMethodSmsSetup } from "./AuthMethodSmsSetup";
|
import { AuthMethodSmsSetup } from "./AuthMethodSmsSetup";
|
||||||
import { AnastasisClientFrame } from "./index";
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
export function AuthenticationEditorScreen(props: AuthenticationEditorProps): VNode {
|
export function AuthenticationEditorScreen(): VNode {
|
||||||
const [selectedMethod, setSelectedMethod] = useState<string | undefined>(
|
const [selectedMethod, setSelectedMethod] = useState<string | undefined>(
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
const { reducer, backupState } = props;
|
const reducer = useAnastasisContext()
|
||||||
const providers = backupState.authentication_providers!;
|
if (!reducer) {
|
||||||
|
return <div>no reducer in context</div>
|
||||||
|
}
|
||||||
|
if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
|
||||||
|
return <div>invalid state</div>
|
||||||
|
}
|
||||||
|
const providers = reducer.currentReducerState.authentication_providers!;
|
||||||
const authAvailableSet = new Set<string>();
|
const authAvailableSet = new Set<string>();
|
||||||
for (const provKey of Object.keys(providers)) {
|
for (const provKey of Object.keys(providers)) {
|
||||||
const p = providers[provKey];
|
const p = providers[provKey];
|
||||||
@ -52,14 +59,14 @@ export function AuthenticationEditorScreen(props: AuthenticationEditorProps): VN
|
|||||||
disabled={!authAvailableSet.has(props.method)}
|
disabled={!authAvailableSet.has(props.method)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedMethod(props.method);
|
setSelectedMethod(props.method);
|
||||||
reducer.dismissError();
|
if (reducer) reducer.dismissError();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.label}
|
{props.label}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const configuredAuthMethods: AuthMethod[] = backupState.authentication_methods ?? [];
|
const configuredAuthMethods: AuthMethod[] = reducer.currentReducerState.authentication_methods ?? [];
|
||||||
const haveMethodsConfigured = configuredAuthMethods.length;
|
const haveMethodsConfigured = configuredAuthMethods.length;
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame title="Backup: Configure Authentication Methods">
|
<AnastasisClientFrame title="Backup: Configure Authentication Methods">
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
/* 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 { BackupFinishedScreen as TestedComponent } from './BackupFinishedScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/BackupFinishedScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Simple = createExample(TestedComponent, reducerStatesExample.backupFinished);
|
||||||
|
|
||||||
|
export const WithName = createExample(TestedComponent, {...reducerStatesExample.backupFinished,
|
||||||
|
secret_name: 'super_secret',
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const WithDetails = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.backupFinished,
|
||||||
|
secret_name: 'super_secret',
|
||||||
|
success_details: {
|
||||||
|
'http://anastasis.net': {
|
||||||
|
policy_expiration: {
|
||||||
|
t_ms: 'never'
|
||||||
|
},
|
||||||
|
policy_version: 0
|
||||||
|
},
|
||||||
|
'http://taler.net': {
|
||||||
|
policy_expiration: {
|
||||||
|
t_ms: new Date().getTime() + 60*60*24*1000
|
||||||
|
},
|
||||||
|
policy_version: 1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} as ReducerState);
|
@ -1,23 +1,33 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { BackupReducerProps, AnastasisClientFrame } from "./index";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
export function BackupFinishedScreen(props: BackupReducerProps): VNode {
|
export function BackupFinishedScreen(): VNode {
|
||||||
|
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 details = reducer.currentReducerState.success_details
|
||||||
return (<AnastasisClientFrame hideNext title="Backup finished">
|
return (<AnastasisClientFrame hideNext title="Backup finished">
|
||||||
<p>
|
<p>
|
||||||
Your backup of secret "{props.backupState.secret_name ?? "??"}" was
|
Your backup of secret "{reducer.currentReducerState.secret_name ?? "??"}" was
|
||||||
successful.
|
successful.
|
||||||
</p>
|
</p>
|
||||||
<p>The backup is stored by the following providers:</p>
|
<p>The backup is stored by the following providers:</p>
|
||||||
<ul>
|
|
||||||
{Object.keys(props.backupState.success_details!).map((x, i) => {
|
{details && <ul>
|
||||||
const sd = props.backupState.success_details![x];
|
{Object.keys(details).map((x, i) => {
|
||||||
|
const sd = details[x];
|
||||||
return (
|
return (
|
||||||
<li key={i}>
|
<li key={i}>
|
||||||
{x} (Policy version {sd.policy_version})
|
{x} (Policy version {sd.policy_version})
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>}
|
||||||
<button onClick={() => props.reducer.reset()}>Back to start</button>
|
<button onClick={() => reducer.reset()}>Back to start</button>
|
||||||
</AnastasisClientFrame>);
|
</AnastasisClientFrame>);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
/* 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 { ChallengeOverviewScreen as TestedComponent } from './ChallengeOverviewScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/ChallengeOverviewScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const OneChallenge = createExample(TestedComponent, {...reducerStatesExample.challengeSelecting,
|
||||||
|
recovery_information: {
|
||||||
|
policies: [[{uuid:'1'}]],
|
||||||
|
challenges: [{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'just go for it',
|
||||||
|
type: 'question',
|
||||||
|
uuid: '1',
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const MoreChallenges = createExample(TestedComponent, {...reducerStatesExample.challengeSelecting,
|
||||||
|
recovery_information: {
|
||||||
|
policies: [[{uuid:'1'}, {uuid:'2'}],[{uuid:'3'}]],
|
||||||
|
challenges: [{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'just go for it',
|
||||||
|
type: 'question',
|
||||||
|
uuid: '1',
|
||||||
|
},{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'just go for it',
|
||||||
|
type: 'question',
|
||||||
|
uuid: '2',
|
||||||
|
},{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'just go for it',
|
||||||
|
type: 'question',
|
||||||
|
uuid: '3',
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const OneBadConfiguredPolicy = createExample(TestedComponent, {...reducerStatesExample.challengeSelecting,
|
||||||
|
recovery_information: {
|
||||||
|
policies: [[{uuid:'2'}]],
|
||||||
|
challenges: [{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'just go for it',
|
||||||
|
type: 'sasd',
|
||||||
|
uuid: '1',
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const NoPolicies = createExample(TestedComponent, reducerStatesExample.challengeSelecting);
|
@ -1,10 +1,21 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { RecoveryReducerProps, AnastasisClientFrame } from "./index";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
|
export function ChallengeOverviewScreen(): VNode {
|
||||||
|
const reducer = useAnastasisContext()
|
||||||
|
|
||||||
|
if (!reducer) {
|
||||||
|
return <div>no reducer in context</div>
|
||||||
|
}
|
||||||
|
if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
|
||||||
|
return <div>invalid state</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const policies = reducer.currentReducerState.recovery_information?.policies ?? [];
|
||||||
|
const chArr = reducer.currentReducerState.recovery_information?.challenges ?? [];
|
||||||
|
const challengeFeedback = reducer.currentReducerState?.challenge_feedback;
|
||||||
|
|
||||||
export function ChallengeOverviewScreen(props: RecoveryReducerProps): VNode {
|
|
||||||
const { recoveryState, reducer } = props;
|
|
||||||
const policies = recoveryState.recovery_information!.policies;
|
|
||||||
const chArr = recoveryState.recovery_information!.challenges;
|
|
||||||
const challenges: {
|
const challenges: {
|
||||||
[uuid: string]: {
|
[uuid: string]: {
|
||||||
type: string;
|
type: string;
|
||||||
@ -22,15 +33,21 @@ export function ChallengeOverviewScreen(props: RecoveryReducerProps): VNode {
|
|||||||
return (
|
return (
|
||||||
<AnastasisClientFrame title="Recovery: Solve challenges">
|
<AnastasisClientFrame title="Recovery: Solve challenges">
|
||||||
<h2>Policies</h2>
|
<h2>Policies</h2>
|
||||||
{policies.map((x, i) => {
|
{!policies.length && <p>
|
||||||
|
No policies found
|
||||||
|
</p>}
|
||||||
|
{policies.map((row, i) => {
|
||||||
return (
|
return (
|
||||||
<div key={i}>
|
<div key={i}>
|
||||||
<h3>Policy #{i + 1}</h3>
|
<h3>Policy #{i + 1}</h3>
|
||||||
{x.map((x, j) => {
|
{row.map(column => {
|
||||||
const ch = challenges[x.uuid];
|
const ch = challenges[column.uuid];
|
||||||
const feedback = recoveryState.challenge_feedback?.[x.uuid];
|
if (!ch) return <div>
|
||||||
|
There is no challenge for this policy
|
||||||
|
</div>
|
||||||
|
const feedback = challengeFeedback?.[column.uuid];
|
||||||
return (
|
return (
|
||||||
<div key={j}
|
<div key={column.uuid}
|
||||||
style={{
|
style={{
|
||||||
borderLeft: "2px solid gray",
|
borderLeft: "2px solid gray",
|
||||||
paddingLeft: "0.5em",
|
paddingLeft: "0.5em",
|
||||||
@ -46,7 +63,7 @@ export function ChallengeOverviewScreen(props: RecoveryReducerProps): VNode {
|
|||||||
{feedback?.state !== "solved" ? (
|
{feedback?.state !== "solved" ? (
|
||||||
<button
|
<button
|
||||||
onClick={() => reducer.transition("select_challenge", {
|
onClick={() => reducer.transition("select_challenge", {
|
||||||
uuid: x.uuid,
|
uuid: column.uuid,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
Solve
|
Solve
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
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 { ContinentSelectionScreen as TestedComponent } from './ContinentSelectionScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/ContinentSelectionScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Backup = createExample(TestedComponent, reducerStatesExample.backupSelectCountry);
|
||||||
|
export const Recovery = createExample(TestedComponent, reducerStatesExample.recoverySelectCountry);
|
@ -1,15 +1,16 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { CommonReducerProps, AnastasisClientFrame, withProcessLabel } from "./index";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
import { AnastasisClientFrame, withProcessLabel } from "./index";
|
||||||
|
|
||||||
export function ContinentSelectionScreen(props: CommonReducerProps): VNode {
|
export function ContinentSelectionScreen(): VNode {
|
||||||
const { reducer, reducerState } = props;
|
const reducer = useAnastasisContext()
|
||||||
|
if (!reducer || !reducer.currentReducerState || !("continents" in reducer.currentReducerState)) {
|
||||||
|
return <div />
|
||||||
|
}
|
||||||
const sel = (x: string): void => reducer.transition("select_continent", { continent: x });
|
const sel = (x: string): void => reducer.transition("select_continent", { continent: x });
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame
|
<AnastasisClientFrame hideNext title={withProcessLabel(reducer, "Select Continent")}>
|
||||||
hideNext
|
{reducer.currentReducerState.continents.map((x: any) => (
|
||||||
title={withProcessLabel(reducer, "Select Continent")}
|
|
||||||
>
|
|
||||||
{reducerState.continents.map((x: any) => (
|
|
||||||
<button onClick={() => sel(x.name)} key={x.name}>
|
<button onClick={() => sel(x.name)} key={x.name}>
|
||||||
{x.name}
|
{x.name}
|
||||||
</button>
|
</button>
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
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,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Backup = createExample(TestedComponent, reducerStatesExample.backupSelectCountry);
|
||||||
|
export const Recovery = createExample(TestedComponent, reducerStatesExample.recoverySelectCountry);
|
@ -1,19 +1,23 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { CommonReducerProps, AnastasisClientFrame, withProcessLabel } from "./index";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
import { AnastasisClientFrame, withProcessLabel } from "./index";
|
||||||
|
|
||||||
export function CountrySelectionScreen(props: CommonReducerProps): VNode {
|
export function CountrySelectionScreen(): VNode {
|
||||||
const { reducer, reducerState } = props;
|
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", {
|
const sel = (x: any): void => reducer.transition("select_country", {
|
||||||
country_code: x.code,
|
country_code: x.code,
|
||||||
currencies: [x.currency],
|
currencies: [x.currency],
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame
|
<AnastasisClientFrame hideNext title={withProcessLabel(reducer, "Select Country")} >
|
||||||
hideNext
|
{reducer.currentReducerState.countries.map((x: any) => (
|
||||||
title={withProcessLabel(reducer, "Select Country")}
|
|
||||||
>
|
|
||||||
{reducerState.countries.map((x: any) => (
|
|
||||||
<button onClick={() => sel(x)} key={x.name}>
|
<button onClick={() => sel(x)} key={x.name}>
|
||||||
{x.name} ({x.currency})
|
{x.name} ({x.currency})
|
||||||
</button>
|
</button>
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/* 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 { PoliciesPayingScreen as TestedComponent } from './PoliciesPayingScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/PoliciesPayingScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Example = createExample(TestedComponent, reducerStatesExample.policyPay);
|
||||||
|
export const WithSomePaymentRequest = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.policyPay,
|
||||||
|
policy_payment_requests: [{
|
||||||
|
payto: 'payto://x-taler-bank/bank.taler/account-a',
|
||||||
|
provider: 'provider1'
|
||||||
|
}, {
|
||||||
|
payto: 'payto://x-taler-bank/bank.taler/account-b',
|
||||||
|
provider: 'provider2'
|
||||||
|
}]
|
||||||
|
} as ReducerState);
|
@ -1,8 +1,16 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { BackupReducerProps, AnastasisClientFrame } from "./index";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
export function PoliciesPayingScreen(props: BackupReducerProps): VNode {
|
export function PoliciesPayingScreen(): VNode {
|
||||||
const payments = props.backupState.policy_payment_requests ?? [];
|
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 payments = reducer.currentReducerState.policy_payment_requests ?? [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame hideNext title="Backup: Recovery Document Payments">
|
<AnastasisClientFrame hideNext title="Backup: Recovery Document Payments">
|
||||||
@ -19,7 +27,7 @@ export function PoliciesPayingScreen(props: BackupReducerProps): VNode {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
<button onClick={() => props.reducer.transition("pay", {})}>
|
<button onClick={() => reducer.transition("pay", {})}>
|
||||||
Check payment status now
|
Check payment status now
|
||||||
</button>
|
</button>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/* 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 { RecoveryFinishedScreen as TestedComponent } from './RecoveryFinishedScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/RecoveryFinishedScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NormalEnding = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.recoveryFinished,
|
||||||
|
core_secret: { mime: 'text/plain', value: 'hello' }
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const BadEnding = createExample(TestedComponent, reducerStatesExample.recoveryFinished);
|
@ -3,13 +3,31 @@ import {
|
|||||||
decodeCrock
|
decodeCrock
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { RecoveryReducerProps, AnastasisClientFrame } from "./index";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
export function RecoveryFinishedScreen(props: RecoveryReducerProps): VNode {
|
export function RecoveryFinishedScreen(): VNode {
|
||||||
|
const reducer = useAnastasisContext()
|
||||||
|
|
||||||
|
if (!reducer) {
|
||||||
|
return <div>no reducer in context</div>
|
||||||
|
}
|
||||||
|
if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
|
||||||
|
return <div>invalid state</div>
|
||||||
|
}
|
||||||
|
const encodedSecret = reducer.currentReducerState.core_secret?.value
|
||||||
|
if (!encodedSecret) {
|
||||||
|
return <AnastasisClientFrame title="Recovery Problem" hideNext>
|
||||||
|
<p>
|
||||||
|
Secret not found
|
||||||
|
</p>
|
||||||
|
</AnastasisClientFrame>
|
||||||
|
}
|
||||||
|
const secret = bytesToString(decodeCrock(encodedSecret))
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame title="Recovery Finished" hideNext>
|
<AnastasisClientFrame title="Recovery Finished" hideNext>
|
||||||
<p>
|
<p>
|
||||||
Secret: {bytesToString(decodeCrock(props.recoveryState.core_secret?.value!))}
|
Secret: {secret}
|
||||||
</p>
|
</p>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
/* 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 { ReviewPoliciesScreen as TestedComponent } from './ReviewPoliciesScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/ReviewPoliciesScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HasPoliciesButMethodListIsEmpty = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.policyReview,
|
||||||
|
policies: [{
|
||||||
|
methods: [{
|
||||||
|
authentication_method: 0,
|
||||||
|
provider: 'asd'
|
||||||
|
},{
|
||||||
|
authentication_method: 1,
|
||||||
|
provider: 'asd'
|
||||||
|
}]
|
||||||
|
},{
|
||||||
|
methods: [{
|
||||||
|
authentication_method: 1,
|
||||||
|
provider: 'asd'
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
authentication_methods: []
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const SomePoliciesWithMethods = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.policyReview,
|
||||||
|
policies: [{
|
||||||
|
methods: [{
|
||||||
|
authentication_method: 0,
|
||||||
|
provider: 'asd'
|
||||||
|
},{
|
||||||
|
authentication_method: 1,
|
||||||
|
provider: 'asd'
|
||||||
|
}]
|
||||||
|
},{
|
||||||
|
methods: [{
|
||||||
|
authentication_method: 1,
|
||||||
|
provider: 'asd'
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
authentication_methods: [{
|
||||||
|
challenge: 'asd',
|
||||||
|
instructions: 'ins',
|
||||||
|
type: 'type',
|
||||||
|
},{
|
||||||
|
challenge: 'asd2',
|
||||||
|
instructions: 'ins2',
|
||||||
|
type: 'type2',
|
||||||
|
}]
|
||||||
|
} as ReducerState);
|
@ -1,35 +1,49 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { BackupReducerProps, AnastasisClientFrame } from "./index";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
|
export function ReviewPoliciesScreen(): VNode {
|
||||||
|
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 authMethods = reducer.currentReducerState.authentication_methods ?? [];
|
||||||
|
const policies = reducer.currentReducerState.policies ?? [];
|
||||||
|
|
||||||
export function ReviewPoliciesScreen(props: BackupReducerProps): VNode {
|
|
||||||
const { reducer, backupState } = props;
|
|
||||||
const authMethods = backupState.authentication_methods!;
|
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame title="Backup: Review Recovery Policies">
|
<AnastasisClientFrame title="Backup: Review Recovery Policies">
|
||||||
{backupState.policies?.map((p, i) => {
|
{policies.map((p, policy_index) => {
|
||||||
const policyName = p.methods
|
const methods = p.methods
|
||||||
.map((x, i) => authMethods[x.authentication_method].type)
|
.map(x => authMethods[x.authentication_method] && ({ ...authMethods[x.authentication_method], provider: x.provider }))
|
||||||
.join(" + ");
|
.filter(x => !!x)
|
||||||
|
|
||||||
|
const policyName = methods.map(x => x.type).join(" + ");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={i} class="policy">
|
<div key={policy_index} class="policy">
|
||||||
<h3>
|
<h3>
|
||||||
Policy #{i + 1}: {policyName}
|
Policy #{policy_index + 1}: {policyName}
|
||||||
</h3>
|
</h3>
|
||||||
Required Authentications:
|
Required Authentications:
|
||||||
|
{!methods.length && <p>
|
||||||
|
No auth method found
|
||||||
|
</p>}
|
||||||
<ul>
|
<ul>
|
||||||
{p.methods.map((x, i) => {
|
{methods.map((m, i) => {
|
||||||
const m = authMethods[x.authentication_method];
|
|
||||||
return (
|
return (
|
||||||
<li key={i}>
|
<li key={i}>
|
||||||
{m.type} ({m.instructions}) at provider {x.provider}
|
{m.type} ({m.instructions}) at provider {m.provider}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
onClick={() => reducer.transition("delete_policy", { policy_index: i })}
|
onClick={() => reducer.transition("delete_policy", { policy_index })}
|
||||||
>
|
>
|
||||||
Delete Policy
|
Delete Policy
|
||||||
</button>
|
</button>
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/* 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 { SecretEditorScreen as TestedComponent } from './SecretEditorScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/SecretEditorScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithSecretNamePreselected = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.secretEdition,
|
||||||
|
secret_name: 'someSecretName',
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const WithoutName = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.secretEdition,
|
||||||
|
} as ReducerState);
|
@ -2,18 +2,29 @@
|
|||||||
import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util";
|
import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import {
|
import {
|
||||||
BackupReducerProps,
|
|
||||||
AnastasisClientFrame,
|
AnastasisClientFrame,
|
||||||
LabeledInput,
|
LabeledInput
|
||||||
} from "./index";
|
} from "./index";
|
||||||
|
|
||||||
export function SecretEditorScreen(props: BackupReducerProps): VNode {
|
export function SecretEditorScreen(): VNode {
|
||||||
const { reducer } = props;
|
const reducer = useAnastasisContext()
|
||||||
const [secretName, setSecretName] = useState(
|
|
||||||
props.backupState.secret_name ?? "",
|
|
||||||
);
|
|
||||||
const [secretValue, setSecretValue] = useState("");
|
const [secretValue, setSecretValue] = useState("");
|
||||||
|
|
||||||
|
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>
|
||||||
|
}
|
||||||
|
if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
|
||||||
|
return <div>invalid state</div>
|
||||||
|
}
|
||||||
|
|
||||||
const secretNext = (): void => {
|
const secretNext = (): void => {
|
||||||
reducer.runTransaction(async (tx) => {
|
reducer.runTransaction(async (tx) => {
|
||||||
await tx.transition("enter_secret_name", {
|
await tx.transition("enter_secret_name", {
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
/* 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 { SecretSelectionScreen as TestedComponent } from './SecretSelectionScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/SecretSelectionScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Example = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.secretSelection,
|
||||||
|
recovery_document: {
|
||||||
|
provider_url: 'http://anastasis.url/',
|
||||||
|
secret_name: 'secretName',
|
||||||
|
version: 1,
|
||||||
|
},
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
|
||||||
|
export const NoRecoveryDocumentFound = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.secretSelection,
|
||||||
|
recovery_document: undefined,
|
||||||
|
} as ReducerState);
|
@ -1,17 +1,29 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { RecoveryReducerProps, AnastasisClientFrame } from "./index";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
export function SecretSelectionScreen(props: RecoveryReducerProps): VNode {
|
export function SecretSelectionScreen(): VNode {
|
||||||
const { reducer, recoveryState } = props;
|
|
||||||
const [selectingVersion, setSelectingVersion] = useState<boolean>(false);
|
const [selectingVersion, setSelectingVersion] = useState<boolean>(false);
|
||||||
const [otherVersion, setOtherVersion] = useState<number>(
|
|
||||||
recoveryState.recovery_document?.version ?? 0
|
|
||||||
);
|
|
||||||
const recoveryDocument = recoveryState.recovery_document!;
|
|
||||||
const [otherProvider, setOtherProvider] = useState<string>("");
|
const [otherProvider, setOtherProvider] = useState<string>("");
|
||||||
|
const reducer = useAnastasisContext()
|
||||||
|
|
||||||
|
const currentVersion = reducer?.currentReducerState
|
||||||
|
&& ("recovery_document" in reducer.currentReducerState)
|
||||||
|
&& reducer.currentReducerState.recovery_document?.version;
|
||||||
|
|
||||||
|
const [otherVersion, setOtherVersion] = useState<number>(currentVersion || 0);
|
||||||
|
|
||||||
|
if (!reducer) {
|
||||||
|
return <div>no reducer in context</div>
|
||||||
|
}
|
||||||
|
if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
|
||||||
|
return <div>invalid state</div>
|
||||||
|
}
|
||||||
|
|
||||||
function selectVersion(p: string, n: number): void {
|
function selectVersion(p: string, n: number): void {
|
||||||
|
if (!reducer) return;
|
||||||
reducer.runTransaction(async (tx) => {
|
reducer.runTransaction(async (tx) => {
|
||||||
await tx.transition("change_version", {
|
await tx.transition("change_version", {
|
||||||
version: n,
|
version: n,
|
||||||
@ -20,12 +32,21 @@ export function SecretSelectionScreen(props: RecoveryReducerProps): VNode {
|
|||||||
setSelectingVersion(false);
|
setSelectingVersion(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const recoveryDocument = reducer.currentReducerState.recovery_document
|
||||||
|
if (!recoveryDocument) {
|
||||||
|
return (
|
||||||
|
<AnastasisClientFrame hideNav title="Recovery: Problem">
|
||||||
|
<p>No recovery document found</p>
|
||||||
|
</AnastasisClientFrame>
|
||||||
|
)
|
||||||
|
}
|
||||||
if (selectingVersion) {
|
if (selectingVersion) {
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame hideNav title="Recovery: Select secret">
|
<AnastasisClientFrame hideNav title="Recovery: Select secret">
|
||||||
<p>Select a different version of the secret</p>
|
<p>Select a different version of the secret</p>
|
||||||
<select onChange={(e) => setOtherProvider((e.target as any).value)}>
|
<select onChange={(e) => setOtherProvider((e.target as any).value)}>
|
||||||
{Object.keys(recoveryState.authentication_providers ?? {}).map(
|
{Object.keys(reducer.currentReducerState.authentication_providers ?? {}).map(
|
||||||
(x, i) => (
|
(x, i) => (
|
||||||
<option key={i} selected={x === recoveryDocument.provider_url} value={x}>
|
<option key={i} selected={x === recoveryDocument.provider_url} value={x}>
|
||||||
{x}
|
{x}
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import { AnastasisClientFrame, LabeledInput } from "./index";
|
import { AnastasisClientFrame, LabeledInput } from "./index";
|
||||||
import { SolveEntryProps } from "./SolveScreen";
|
import { SolveEntryProps } from "./SolveScreen";
|
||||||
|
|
||||||
export function SolveEmailEntry(props: SolveEntryProps): VNode {
|
export function SolveEmailEntry({ challenge, feedback }: SolveEntryProps): VNode {
|
||||||
const [answer, setAnswer] = useState("");
|
const [answer, setAnswer] = useState("");
|
||||||
const { reducer, challenge, feedback } = props;
|
const reducer = useAnastasisContext()
|
||||||
const next = (): void => reducer.transition("solve_challenge", {
|
const next = (): void => {
|
||||||
|
if (reducer) reducer.transition("solve_challenge", {
|
||||||
answer,
|
answer,
|
||||||
});
|
})
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame
|
<AnastasisClientFrame
|
||||||
title="Recovery: Solve challenge"
|
title="Recovery: Solve challenge"
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import { AnastasisClientFrame, LabeledInput } from "./index";
|
import { AnastasisClientFrame, LabeledInput } from "./index";
|
||||||
import { SolveEntryProps } from "./SolveScreen";
|
import { SolveEntryProps } from "./SolveScreen";
|
||||||
|
|
||||||
export function SolvePostEntry(props: SolveEntryProps): VNode {
|
export function SolvePostEntry({ challenge, feedback }: SolveEntryProps): VNode {
|
||||||
const [answer, setAnswer] = useState("");
|
const [answer, setAnswer] = useState("");
|
||||||
const { reducer, challenge, feedback } = props;
|
const reducer = useAnastasisContext()
|
||||||
const next = (): void => reducer.transition("solve_challenge", {
|
const next = (): void => {
|
||||||
answer,
|
if (reducer) reducer.transition("solve_challenge", { answer })
|
||||||
});
|
};
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame
|
<AnastasisClientFrame
|
||||||
title="Recovery: Solve challenge"
|
title="Recovery: Solve challenge"
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import { AnastasisClientFrame, LabeledInput } from "./index";
|
import { AnastasisClientFrame, LabeledInput } from "./index";
|
||||||
import { SolveEntryProps } from "./SolveScreen";
|
import { SolveEntryProps } from "./SolveScreen";
|
||||||
|
|
||||||
export function SolveQuestionEntry(props: SolveEntryProps): VNode {
|
export function SolveQuestionEntry({ challenge, feedback }: SolveEntryProps): VNode {
|
||||||
const [answer, setAnswer] = useState("");
|
const [answer, setAnswer] = useState("");
|
||||||
const { reducer, challenge, feedback } = props;
|
const reducer = useAnastasisContext()
|
||||||
const next = (): void => reducer.transition("solve_challenge", {
|
const next = (): void => {
|
||||||
answer,
|
if (reducer) reducer.transition("solve_challenge", { answer })
|
||||||
});
|
};
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame
|
<AnastasisClientFrame
|
||||||
title="Recovery: Solve challenge"
|
title="Recovery: Solve challenge"
|
||||||
|
121
packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx
Normal file
121
packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/* 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 { SolveScreen as TestedComponent } from './SolveScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/SolveScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NoInformation = createExample(TestedComponent, reducerStatesExample.challengeSolving);
|
||||||
|
|
||||||
|
export const NotSupportedChallenge = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.challengeSolving,
|
||||||
|
recovery_information: {
|
||||||
|
challenges: [{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'follow htis instructions',
|
||||||
|
type: 'chall-type',
|
||||||
|
uuid: 'ASDASDSAD!1'
|
||||||
|
}],
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
selected_challenge_uuid: 'ASDASDSAD!1'
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const MismatchedChallengeId = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.challengeSolving,
|
||||||
|
recovery_information: {
|
||||||
|
challenges: [{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'follow htis instructions',
|
||||||
|
type: 'chall-type',
|
||||||
|
uuid: 'ASDASDSAD!1'
|
||||||
|
}],
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
selected_challenge_uuid: 'no-no-no'
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const SmsChallenge = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.challengeSolving,
|
||||||
|
recovery_information: {
|
||||||
|
challenges: [{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'follow htis instructions',
|
||||||
|
type: 'sms',
|
||||||
|
uuid: 'ASDASDSAD!1'
|
||||||
|
}],
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
selected_challenge_uuid: 'ASDASDSAD!1'
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const QuestionChallenge = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.challengeSolving,
|
||||||
|
recovery_information: {
|
||||||
|
challenges: [{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'follow htis instructions',
|
||||||
|
type: 'question',
|
||||||
|
uuid: 'ASDASDSAD!1'
|
||||||
|
}],
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
selected_challenge_uuid: 'ASDASDSAD!1'
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const EmailChallenge = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.challengeSolving,
|
||||||
|
recovery_information: {
|
||||||
|
challenges: [{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'follow htis instructions',
|
||||||
|
type: 'email',
|
||||||
|
uuid: 'ASDASDSAD!1'
|
||||||
|
}],
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
selected_challenge_uuid: 'ASDASDSAD!1'
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const PostChallenge = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.challengeSolving,
|
||||||
|
recovery_information: {
|
||||||
|
challenges: [{
|
||||||
|
cost: 'USD:1',
|
||||||
|
instructions: 'follow htis instructions',
|
||||||
|
type: 'post',
|
||||||
|
uuid: 'ASDASDSAD!1'
|
||||||
|
}],
|
||||||
|
policies: [],
|
||||||
|
},
|
||||||
|
selected_challenge_uuid: 'ASDASDSAD!1'
|
||||||
|
} as ReducerState);
|
@ -1,17 +1,31 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { AnastasisReducerApi } from "../../hooks/use-anastasis-reducer";
|
import { ChallengeFeedback, ChallengeInfo } from "../../../../anastasis-core/lib";
|
||||||
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import { SolveEmailEntry } from "./SolveEmailEntry";
|
import { SolveEmailEntry } from "./SolveEmailEntry";
|
||||||
import { SolvePostEntry } from "./SolvePostEntry";
|
import { SolvePostEntry } from "./SolvePostEntry";
|
||||||
import { SolveQuestionEntry } from "./SolveQuestionEntry";
|
import { SolveQuestionEntry } from "./SolveQuestionEntry";
|
||||||
import { SolveSmsEntry } from "./SolveSmsEntry";
|
import { SolveSmsEntry } from "./SolveSmsEntry";
|
||||||
import { SolveUnsupportedEntry } from "./SolveUnsupportedEntry";
|
import { SolveUnsupportedEntry } from "./SolveUnsupportedEntry";
|
||||||
import { RecoveryReducerProps } from "./index";
|
|
||||||
import { ChallengeInfo, ChallengeFeedback } from "../../../../anastasis-core/lib";
|
|
||||||
|
|
||||||
export function SolveScreen(props: RecoveryReducerProps): VNode {
|
export function SolveScreen(): VNode {
|
||||||
const chArr = props.recoveryState.recovery_information!.challenges;
|
const reducer = useAnastasisContext()
|
||||||
const challengeFeedback = props.recoveryState.challenge_feedback ?? {};
|
|
||||||
const selectedUuid = props.recoveryState.selected_challenge_uuid!;
|
if (!reducer) {
|
||||||
|
return <div>no reducer in context</div>
|
||||||
|
}
|
||||||
|
if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
|
||||||
|
return <div>invalid state</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reducer.currentReducerState.recovery_information) {
|
||||||
|
return <div>no recovery information found</div>
|
||||||
|
}
|
||||||
|
if (!reducer.currentReducerState.selected_challenge_uuid) {
|
||||||
|
return <div>no selected uuid</div>
|
||||||
|
}
|
||||||
|
const chArr = reducer.currentReducerState.recovery_information.challenges;
|
||||||
|
const challengeFeedback = reducer.currentReducerState.challenge_feedback ?? {};
|
||||||
|
const selectedUuid = reducer.currentReducerState.selected_challenge_uuid;
|
||||||
const challenges: {
|
const challenges: {
|
||||||
[uuid: string]: ChallengeInfo;
|
[uuid: string]: ChallengeInfo;
|
||||||
} = {};
|
} = {};
|
||||||
@ -25,17 +39,15 @@ export function SolveScreen(props: RecoveryReducerProps): VNode {
|
|||||||
email: SolveEmailEntry,
|
email: SolveEmailEntry,
|
||||||
post: SolvePostEntry,
|
post: SolvePostEntry,
|
||||||
};
|
};
|
||||||
const SolveDialog = dialogMap[selectedChallenge.type] ?? SolveUnsupportedEntry;
|
const SolveDialog = dialogMap[selectedChallenge?.type] ?? SolveUnsupportedEntry;
|
||||||
return (
|
return (
|
||||||
<SolveDialog
|
<SolveDialog
|
||||||
challenge={selectedChallenge}
|
challenge={selectedChallenge}
|
||||||
reducer={props.reducer}
|
|
||||||
feedback={challengeFeedback[selectedUuid]} />
|
feedback={challengeFeedback[selectedUuid]} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SolveEntryProps {
|
export interface SolveEntryProps {
|
||||||
reducer: AnastasisReducerApi;
|
|
||||||
challenge: ChallengeInfo;
|
challenge: ChallengeInfo;
|
||||||
feedback?: ChallengeFeedback;
|
feedback?: ChallengeFeedback;
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import { AnastasisClientFrame, LabeledInput } from "./index";
|
import { AnastasisClientFrame, LabeledInput } from "./index";
|
||||||
import { SolveEntryProps } from "./SolveScreen";
|
import { SolveEntryProps } from "./SolveScreen";
|
||||||
|
|
||||||
export function SolveSmsEntry(props: SolveEntryProps): VNode {
|
export function SolveSmsEntry({ challenge, feedback }: SolveEntryProps): VNode {
|
||||||
const [answer, setAnswer] = useState("");
|
const [answer, setAnswer] = useState("");
|
||||||
const { reducer, challenge, feedback } = props;
|
const reducer = useAnastasisContext()
|
||||||
const next = (): void => reducer.transition("solve_challenge", {
|
const next = (): void => {
|
||||||
|
if (reducer) reducer.transition("solve_challenge", {
|
||||||
answer,
|
answer,
|
||||||
});
|
})
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame
|
<AnastasisClientFrame
|
||||||
title="Recovery: Solve challenge"
|
title="Recovery: Solve challenge"
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
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 { StartScreen as TestedComponent } from './StartScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/StartScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InitialState = createExample(TestedComponent, reducerStatesExample.initial);
|
@ -1,14 +1,34 @@
|
|||||||
|
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { AnastasisReducerApi } from "../../hooks/use-anastasis-reducer";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import { AnastasisClientFrame } from "./index";
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
export function StartScreen(props: { reducer: AnastasisReducerApi; }): VNode {
|
export function StartScreen(): VNode {
|
||||||
|
const reducer = useAnastasisContext()
|
||||||
|
if (!reducer) {
|
||||||
|
return <div>no reducer in context</div>
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame hideNav title="Home">
|
<AnastasisClientFrame hideNav title="Home">
|
||||||
<button autoFocus onClick={() => props.reducer.startBackup()}>
|
<div>
|
||||||
|
<section class="section is-main-section">
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column" />
|
||||||
|
<div class="column is-four-fifths">
|
||||||
|
|
||||||
|
<div class="buttons is-right">
|
||||||
|
<button class="button is-success" autoFocus onClick={() => reducer.startBackup()}>
|
||||||
Backup
|
Backup
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => props.reducer.startRecover()}>Recover</button>
|
|
||||||
|
<button class="button is-info" onClick={() => reducer.startRecover()}>Recover</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="column" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
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 { TruthsPayingScreen as TestedComponent } from './TruthsPayingScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/TruthsPayingScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Example = createExample(TestedComponent, reducerStatesExample.truthsPaying);
|
||||||
|
export const WithPaytoList = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.truthsPaying,
|
||||||
|
payments: ['payto://x-taler-bank/bank/account']
|
||||||
|
} as ReducerState);
|
@ -1,8 +1,16 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { BackupReducerProps, AnastasisClientFrame } from "./index";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
export function TruthsPayingScreen(props: BackupReducerProps): VNode {
|
export function TruthsPayingScreen(): VNode {
|
||||||
const payments = props.backupState.payments ?? [];
|
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 payments = reducer.currentReducerState.payments ?? [];
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame
|
<AnastasisClientFrame
|
||||||
hideNext
|
hideNext
|
||||||
@ -17,7 +25,7 @@ export function TruthsPayingScreen(props: BackupReducerProps): VNode {
|
|||||||
return <li key={i}>{x}</li>;
|
return <li key={i}>{x}</li>;
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
<button onClick={() => props.reducer.transition("pay", {})}>
|
<button onClick={() => reducer.transition("pay", {})}>
|
||||||
Check payment status now
|
Check payment status now
|
||||||
</button>
|
</button>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
|
@ -1,28 +1,25 @@
|
|||||||
import {
|
|
||||||
Component,
|
|
||||||
ComponentChildren,
|
|
||||||
createContext,
|
|
||||||
Fragment,
|
|
||||||
FunctionalComponent,
|
|
||||||
h,
|
|
||||||
VNode,
|
|
||||||
} from "preact";
|
|
||||||
import {
|
|
||||||
useContext,
|
|
||||||
useErrorBoundary,
|
|
||||||
useLayoutEffect,
|
|
||||||
useRef,
|
|
||||||
} from "preact/hooks";
|
|
||||||
import { Menu } from "../../components/menu";
|
|
||||||
import {
|
import {
|
||||||
BackupStates,
|
BackupStates,
|
||||||
RecoveryStates,
|
RecoveryStates,
|
||||||
ReducerStateBackup,
|
ReducerStateBackup,
|
||||||
ReducerStateRecovery,
|
ReducerStateRecovery
|
||||||
} from "anastasis-core";
|
} from "anastasis-core";
|
||||||
|
import {
|
||||||
|
ComponentChildren, Fragment,
|
||||||
|
FunctionalComponent,
|
||||||
|
h,
|
||||||
|
VNode
|
||||||
|
} from "preact";
|
||||||
|
import {
|
||||||
|
useErrorBoundary,
|
||||||
|
useLayoutEffect,
|
||||||
|
useRef
|
||||||
|
} from "preact/hooks";
|
||||||
|
import { Menu } from "../../components/menu";
|
||||||
|
import { AnastasisProvider, useAnastasisContext } from "../../context/anastasis";
|
||||||
import {
|
import {
|
||||||
AnastasisReducerApi,
|
AnastasisReducerApi,
|
||||||
useAnastasisReducer,
|
useAnastasisReducer
|
||||||
} from "../../hooks/use-anastasis-reducer";
|
} from "../../hooks/use-anastasis-reducer";
|
||||||
import { AttributeEntryScreen } from "./AttributeEntryScreen";
|
import { AttributeEntryScreen } from "./AttributeEntryScreen";
|
||||||
import { AuthenticationEditorScreen } from "./AuthenticationEditorScreen";
|
import { AuthenticationEditorScreen } from "./AuthenticationEditorScreen";
|
||||||
@ -38,19 +35,11 @@ import { SecretSelectionScreen } from "./SecretSelectionScreen";
|
|||||||
import { SolveScreen } from "./SolveScreen";
|
import { SolveScreen } from "./SolveScreen";
|
||||||
import { StartScreen } from "./StartScreen";
|
import { StartScreen } from "./StartScreen";
|
||||||
import { TruthsPayingScreen } from "./TruthsPayingScreen";
|
import { TruthsPayingScreen } from "./TruthsPayingScreen";
|
||||||
import "./../home/style";
|
|
||||||
|
|
||||||
const WithReducer = createContext<AnastasisReducerApi | undefined>(undefined);
|
|
||||||
|
|
||||||
function isBackup(reducer: AnastasisReducerApi): boolean {
|
function isBackup(reducer: AnastasisReducerApi): boolean {
|
||||||
return !!reducer.currentReducerState?.backup_state;
|
return !!reducer.currentReducerState?.backup_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommonReducerProps {
|
|
||||||
reducer: AnastasisReducerApi;
|
|
||||||
reducerState: ReducerStateBackup | ReducerStateRecovery;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function withProcessLabel(
|
export function withProcessLabel(
|
||||||
reducer: AnastasisReducerApi,
|
reducer: AnastasisReducerApi,
|
||||||
text: string,
|
text: string,
|
||||||
@ -61,16 +50,6 @@ export function withProcessLabel(
|
|||||||
return `Recovery: ${text}`;
|
return `Recovery: ${text}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BackupReducerProps {
|
|
||||||
reducer: AnastasisReducerApi;
|
|
||||||
backupState: ReducerStateBackup;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RecoveryReducerProps {
|
|
||||||
reducer: AnastasisReducerApi;
|
|
||||||
recoveryState: ReducerStateRecovery;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AnastasisClientFrameProps {
|
interface AnastasisClientFrameProps {
|
||||||
onNext?(): void;
|
onNext?(): void;
|
||||||
title: string;
|
title: string;
|
||||||
@ -88,7 +67,7 @@ interface AnastasisClientFrameProps {
|
|||||||
function ErrorBoundary(props: {
|
function ErrorBoundary(props: {
|
||||||
reducer: AnastasisReducerApi;
|
reducer: AnastasisReducerApi;
|
||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
}) {
|
}): VNode {
|
||||||
const [error, resetError] = useErrorBoundary((error) =>
|
const [error, resetError] = useErrorBoundary((error) =>
|
||||||
console.log("got error", error),
|
console.log("got error", error),
|
||||||
);
|
);
|
||||||
@ -113,7 +92,7 @@ function ErrorBoundary(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
|
export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
|
||||||
const reducer = useContext(WithReducer);
|
const reducer = useAnastasisContext();
|
||||||
if (!reducer) {
|
if (!reducer) {
|
||||||
return <p>Fatal: Reducer must be in context.</p>;
|
return <p>Fatal: Reducer must be in context.</p>;
|
||||||
}
|
}
|
||||||
@ -135,9 +114,8 @@ export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
|
|||||||
<Menu title="Anastasis" />
|
<Menu title="Anastasis" />
|
||||||
<div>
|
<div>
|
||||||
<div class="home" onKeyPress={(e) => handleKeyPress(e)}>
|
<div class="home" onKeyPress={(e) => handleKeyPress(e)}>
|
||||||
<button onClick={() => reducer.reset()}>Reset session</button>
|
|
||||||
<h1>{props.title}</h1>
|
<h1>{props.title}</h1>
|
||||||
<ErrorBanner reducer={reducer} />
|
<ErrorBanner />
|
||||||
{props.children}
|
{props.children}
|
||||||
{!props.hideNav ? (
|
{!props.hideNav ? (
|
||||||
<div>
|
<div>
|
||||||
@ -154,96 +132,94 @@ export function AnastasisClientFrame(props: AnastasisClientFrameProps): VNode {
|
|||||||
const AnastasisClient: FunctionalComponent = () => {
|
const AnastasisClient: FunctionalComponent = () => {
|
||||||
const reducer = useAnastasisReducer();
|
const reducer = useAnastasisReducer();
|
||||||
return (
|
return (
|
||||||
<WithReducer.Provider value={reducer}>
|
<AnastasisProvider value={reducer}>
|
||||||
<ErrorBoundary reducer={reducer}>
|
<ErrorBoundary reducer={reducer}>
|
||||||
<AnastasisClientImpl />
|
<AnastasisClientImpl />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</WithReducer.Provider>
|
</AnastasisProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const AnastasisClientImpl: FunctionalComponent = () => {
|
const AnastasisClientImpl: FunctionalComponent = () => {
|
||||||
const reducer = useContext(WithReducer)!;
|
const reducer = useAnastasisContext()
|
||||||
const reducerState = reducer.currentReducerState;
|
if (!reducer) {
|
||||||
if (!reducerState) {
|
return <p>Fatal: Reducer must be in context.</p>;
|
||||||
return <StartScreen reducer={reducer} />;
|
}
|
||||||
|
const state = reducer.currentReducerState;
|
||||||
|
if (!state) {
|
||||||
|
return <StartScreen />;
|
||||||
}
|
}
|
||||||
console.log("state", reducer.currentReducerState);
|
console.log("state", reducer.currentReducerState);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
reducerState.backup_state === BackupStates.ContinentSelecting ||
|
state.backup_state === BackupStates.ContinentSelecting ||
|
||||||
reducerState.recovery_state === RecoveryStates.ContinentSelecting
|
state.recovery_state === RecoveryStates.ContinentSelecting
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<ContinentSelectionScreen reducer={reducer} reducerState={reducerState} />
|
<ContinentSelectionScreen />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
reducerState.backup_state === BackupStates.CountrySelecting ||
|
state.backup_state === BackupStates.CountrySelecting ||
|
||||||
reducerState.recovery_state === RecoveryStates.CountrySelecting
|
state.recovery_state === RecoveryStates.CountrySelecting
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<CountrySelectionScreen reducer={reducer} reducerState={reducerState} />
|
<CountrySelectionScreen />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
reducerState.backup_state === BackupStates.UserAttributesCollecting ||
|
state.backup_state === BackupStates.UserAttributesCollecting ||
|
||||||
reducerState.recovery_state === RecoveryStates.UserAttributesCollecting
|
state.recovery_state === RecoveryStates.UserAttributesCollecting
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<AttributeEntryScreen reducer={reducer} reducerState={reducerState} />
|
<AttributeEntryScreen />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (reducerState.backup_state === BackupStates.AuthenticationsEditing) {
|
if (state.backup_state === BackupStates.AuthenticationsEditing) {
|
||||||
return (
|
return (
|
||||||
<AuthenticationEditorScreen
|
<AuthenticationEditorScreen />
|
||||||
backupState={reducerState}
|
|
||||||
reducer={reducer}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (reducerState.backup_state === BackupStates.PoliciesReviewing) {
|
if (state.backup_state === BackupStates.PoliciesReviewing) {
|
||||||
return (
|
return (
|
||||||
<ReviewPoliciesScreen reducer={reducer} backupState={reducerState} />
|
<ReviewPoliciesScreen />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (reducerState.backup_state === BackupStates.SecretEditing) {
|
if (state.backup_state === BackupStates.SecretEditing) {
|
||||||
return <SecretEditorScreen reducer={reducer} backupState={reducerState} />;
|
return <SecretEditorScreen />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reducerState.backup_state === BackupStates.BackupFinished) {
|
if (state.backup_state === BackupStates.BackupFinished) {
|
||||||
const backupState: ReducerStateBackup = reducerState;
|
return <BackupFinishedScreen />;
|
||||||
return <BackupFinishedScreen reducer={reducer} backupState={backupState} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reducerState.backup_state === BackupStates.TruthsPaying) {
|
if (state.backup_state === BackupStates.TruthsPaying) {
|
||||||
return <TruthsPayingScreen reducer={reducer} backupState={reducerState} />;
|
return <TruthsPayingScreen />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reducerState.backup_state === BackupStates.PoliciesPaying) {
|
if (state.backup_state === BackupStates.PoliciesPaying) {
|
||||||
const backupState: ReducerStateBackup = reducerState;
|
return <PoliciesPayingScreen />;
|
||||||
return <PoliciesPayingScreen reducer={reducer} backupState={backupState} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reducerState.recovery_state === RecoveryStates.SecretSelecting) {
|
if (state.recovery_state === RecoveryStates.SecretSelecting) {
|
||||||
return (
|
return (
|
||||||
<SecretSelectionScreen reducer={reducer} recoveryState={reducerState} />
|
<SecretSelectionScreen />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reducerState.recovery_state === RecoveryStates.ChallengeSelecting) {
|
if (state.recovery_state === RecoveryStates.ChallengeSelecting) {
|
||||||
return (
|
return (
|
||||||
<ChallengeOverviewScreen reducer={reducer} recoveryState={reducerState} />
|
<ChallengeOverviewScreen />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reducerState.recovery_state === RecoveryStates.ChallengeSolving) {
|
if (state.recovery_state === RecoveryStates.ChallengeSolving) {
|
||||||
return <SolveScreen reducer={reducer} recoveryState={reducerState} />;
|
return <SolveScreen />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reducerState.recovery_state === RecoveryStates.RecoveryFinished) {
|
if (state.recovery_state === RecoveryStates.RecoveryFinished) {
|
||||||
return (
|
return (
|
||||||
<RecoveryFinishedScreen reducer={reducer} recoveryState={reducerState} />
|
<RecoveryFinishedScreen />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +227,9 @@ const AnastasisClientImpl: FunctionalComponent = () => {
|
|||||||
return (
|
return (
|
||||||
<AnastasisClientFrame hideNav title="Bug">
|
<AnastasisClientFrame hideNav title="Bug">
|
||||||
<p>Bug: Unknown state.</p>
|
<p>Bug: Unknown state.</p>
|
||||||
<button onClick={() => reducer.reset()}>Reset</button>
|
<div class="buttons is-right">
|
||||||
|
<button class="button" onClick={() => reducer.reset()}>Reset</button>
|
||||||
|
</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -282,26 +260,20 @@ export function LabeledInput(props: LabeledInputProps): VNode {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ErrorBannerProps {
|
|
||||||
reducer: AnastasisReducerApi;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a dismissable error banner if there is a current error.
|
* Show a dismissible error banner if there is a current error.
|
||||||
*/
|
*/
|
||||||
function ErrorBanner(props: ErrorBannerProps): VNode | null {
|
function ErrorBanner(): VNode | null {
|
||||||
const currentError = props.reducer.currentError;
|
const reducer = useAnastasisContext();
|
||||||
if (currentError) {
|
if (!reducer || !reducer.currentError) return null;
|
||||||
return (
|
return (
|
||||||
<div id="error">
|
<div id="error">
|
||||||
<p>Error: {JSON.stringify(currentError)}</p>
|
<p>Error: {JSON.stringify(reducer.currentError)}</p>
|
||||||
<button onClick={() => props.reducer.dismissError()}>
|
<button onClick={() => reducer.dismissError()}>
|
||||||
Dismiss Error
|
Dismiss Error
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AnastasisClient;
|
export default AnastasisClient;
|
||||||
|
161
packages/anastasis-webui/src/utils/index.tsx
Normal file
161
packages/anastasis-webui/src/utils/index.tsx
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
|
import { BackupStates, RecoveryStates, ReducerState } from 'anastasis-core';
|
||||||
|
import { FunctionalComponent, h, VNode } from 'preact';
|
||||||
|
import { AnastasisProvider } from '../context/anastasis';
|
||||||
|
|
||||||
|
export function createExample<Props>(Component: FunctionalComponent<Props>, currentReducerState?: ReducerState, props?: Partial<Props>): { (args: Props): VNode } {
|
||||||
|
const r = (args: Props): VNode => {
|
||||||
|
return <AnastasisProvider value={{
|
||||||
|
currentReducerState,
|
||||||
|
currentError: undefined,
|
||||||
|
back: () => { null },
|
||||||
|
dismissError: () => { null },
|
||||||
|
reset: () => { null },
|
||||||
|
runTransaction: () => { null },
|
||||||
|
startBackup: () => { null },
|
||||||
|
startRecover: () => { null },
|
||||||
|
transition: () => { null },
|
||||||
|
}}>
|
||||||
|
<Component {...args} />
|
||||||
|
</AnastasisProvider>
|
||||||
|
}
|
||||||
|
r.args = props
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
const base = {
|
||||||
|
continents: [
|
||||||
|
{
|
||||||
|
name: "Europe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "India"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Asia"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "North America"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Testcontinent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
countries: [
|
||||||
|
{
|
||||||
|
code: "xx",
|
||||||
|
name: "Testland",
|
||||||
|
continent: "Testcontinent",
|
||||||
|
continent_i18n: {
|
||||||
|
de_DE: "Testkontinent"
|
||||||
|
},
|
||||||
|
name_i18n: {
|
||||||
|
de_DE: "Testlandt",
|
||||||
|
de_CH: "Testlandi",
|
||||||
|
fr_FR: "Testpais",
|
||||||
|
en_UK: "Testland"
|
||||||
|
},
|
||||||
|
currency: "TESTKUDOS",
|
||||||
|
call_code: "+00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "xy",
|
||||||
|
name: "Demoland",
|
||||||
|
continent: "Testcontinent",
|
||||||
|
continent_i18n: {
|
||||||
|
de_DE: "Testkontinent"
|
||||||
|
},
|
||||||
|
name_i18n: {
|
||||||
|
de_DE: "Demolandt",
|
||||||
|
de_CH: "Demolandi",
|
||||||
|
fr_FR: "Demopais",
|
||||||
|
en_UK: "Demoland"
|
||||||
|
},
|
||||||
|
currency: "KUDOS",
|
||||||
|
call_code: "+01"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
authentication_providers: {
|
||||||
|
"http://localhost:8086/": {
|
||||||
|
http_status: 200,
|
||||||
|
annual_fee: "COL:0",
|
||||||
|
business_name: "ana",
|
||||||
|
currency: "COL",
|
||||||
|
liability_limit: "COL:10",
|
||||||
|
methods: [
|
||||||
|
{
|
||||||
|
type: "question",
|
||||||
|
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"
|
||||||
|
},
|
||||||
|
"http://localhost:8088/": {
|
||||||
|
code: 8414,
|
||||||
|
hint: "request to provider failed"
|
||||||
|
},
|
||||||
|
"http://localhost:8089/": {
|
||||||
|
code: 8414,
|
||||||
|
hint: "request to provider failed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// expiration: {
|
||||||
|
// d_ms: 1792525051855 // check t_ms
|
||||||
|
// },
|
||||||
|
} as Partial<ReducerState>
|
||||||
|
|
||||||
|
export const reducerStatesExample = {
|
||||||
|
initial: undefined,
|
||||||
|
recoverySelectCountry: {...base,
|
||||||
|
recovery_state: RecoveryStates.CountrySelecting
|
||||||
|
} as ReducerState,
|
||||||
|
backupSelectCountry: {...base,
|
||||||
|
backup_state: BackupStates.CountrySelecting
|
||||||
|
} as ReducerState,
|
||||||
|
recoverySelectContinent: {...base,
|
||||||
|
recovery_state: RecoveryStates.ContinentSelecting,
|
||||||
|
} as ReducerState,
|
||||||
|
backupSelectContinent: {...base,
|
||||||
|
backup_state: BackupStates.ContinentSelecting,
|
||||||
|
} as ReducerState,
|
||||||
|
secretSelection: {...base,
|
||||||
|
recovery_state: RecoveryStates.SecretSelecting,
|
||||||
|
} as ReducerState,
|
||||||
|
recoveryFinished: {...base,
|
||||||
|
recovery_state: RecoveryStates.RecoveryFinished,
|
||||||
|
} as ReducerState,
|
||||||
|
challengeSelecting: {...base,
|
||||||
|
recovery_state: RecoveryStates.ChallengeSelecting,
|
||||||
|
} as ReducerState,
|
||||||
|
challengeSolving: {...base,
|
||||||
|
recovery_state: RecoveryStates.ChallengeSolving,
|
||||||
|
} as ReducerState,
|
||||||
|
secretEdition: {...base,
|
||||||
|
backup_state: BackupStates.SecretEditing,
|
||||||
|
} as ReducerState,
|
||||||
|
policyReview: {...base,
|
||||||
|
backup_state: BackupStates.PoliciesReviewing,
|
||||||
|
} as ReducerState,
|
||||||
|
policyPay: {...base,
|
||||||
|
backup_state: BackupStates.PoliciesPaying,
|
||||||
|
} as ReducerState,
|
||||||
|
backupFinished: {...base,
|
||||||
|
backup_state: BackupStates.BackupFinished,
|
||||||
|
} as ReducerState,
|
||||||
|
authEditing: {...base,
|
||||||
|
backup_state: BackupStates.AuthenticationsEditing
|
||||||
|
} as ReducerState,
|
||||||
|
attributeEditing: {...base,
|
||||||
|
backup_state: BackupStates.UserAttributesCollecting
|
||||||
|
} as ReducerState,
|
||||||
|
truthsPaying: {...base,
|
||||||
|
backup_state: BackupStates.TruthsPaying
|
||||||
|
} as ReducerState,
|
||||||
|
|
||||||
|
}
|
1155
pnpm-lock.yaml
1155
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user