aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/anastasis-webui/package.json8
-rw-r--r--packages/anastasis-webui/src/.babelrc4
-rw-r--r--packages/anastasis-webui/src/components/AsyncButton.tsx27
-rw-r--r--packages/anastasis-webui/src/components/Notifications.tsx59
-rw-r--r--packages/anastasis-webui/src/components/QR.tsx27
-rw-r--r--packages/anastasis-webui/src/components/app.tsx1
-rw-r--r--packages/anastasis-webui/src/components/fields/DateInput.tsx104
-rw-r--r--packages/anastasis-webui/src/components/fields/EmailInput.tsx49
-rw-r--r--packages/anastasis-webui/src/components/fields/FileInput.tsx92
-rw-r--r--packages/anastasis-webui/src/components/fields/ImageInput.tsx96
-rw-r--r--packages/anastasis-webui/src/components/fields/TextInput.tsx45
-rw-r--r--packages/anastasis-webui/src/components/menu/LangSelector.tsx99
-rw-r--r--packages/anastasis-webui/src/components/menu/SideBar.tsx302
-rw-r--r--packages/anastasis-webui/src/components/menu/index.tsx6
-rw-r--r--packages/anastasis-webui/src/components/picker/DatePicker.tsx314
-rw-r--r--packages/anastasis-webui/src/components/picker/DurationPicker.stories.tsx45
-rw-r--r--packages/anastasis-webui/src/components/picker/DurationPicker.tsx217
-rw-r--r--packages/anastasis-webui/src/context/anastasis.ts20
-rw-r--r--packages/anastasis-webui/src/context/translation.ts43
-rw-r--r--packages/anastasis-webui/src/declaration.d.ts28
-rw-r--r--packages/anastasis-webui/src/hooks/async.ts29
-rw-r--r--packages/anastasis-webui/src/hooks/index.ts113
-rw-r--r--packages/anastasis-webui/src/i18n/index.tsx54
-rw-r--r--packages/anastasis-webui/src/i18n/strings.ts38
-rw-r--r--packages/anastasis-webui/src/index.ts4
-rw-r--r--packages/anastasis-webui/src/manifest.json2
-rw-r--r--packages/anastasis-webui/src/pages/home/AddingProviderScreen.stories.tsx52
-rw-r--r--packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx261
-rw-r--r--packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx120
-rw-r--r--packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx107
-rw-r--r--packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.stories.tsx105
-rw-r--r--packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx26
-rw-r--r--packages/anastasis-webui/src/pages/home/BackupFinishedScreen.stories.tsx45
-rw-r--r--packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx85
-rw-r--r--packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx14
-rw-r--r--packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx208
-rw-r--r--packages/anastasis-webui/src/pages/home/ChallengePayingScreen.stories.tsx22
-rw-r--r--packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx18
-rw-r--r--packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx33
-rw-r--r--packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx190
-rw-r--r--packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx200
-rw-r--r--packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.stories.tsx41
-rw-r--r--packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx17
-rw-r--r--packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx26
-rw-r--r--packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx60
-rw-r--r--packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx216
-rw-r--r--packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx119
-rw-r--r--packages/anastasis-webui/src/pages/home/SecretEditorScreen.stories.tsx21
-rw-r--r--packages/anastasis-webui/src/pages/home/SecretSelectionScreen.stories.tsx24
-rw-r--r--packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx185
-rw-r--r--packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx62
-rw-r--r--packages/anastasis-webui/src/pages/home/SolveScreen.tsx196
-rw-r--r--packages/anastasis-webui/src/pages/home/StartScreen.stories.tsx22
-rw-r--r--packages/anastasis-webui/src/pages/home/StartScreen.tsx26
-rw-r--r--packages/anastasis-webui/src/pages/home/TruthsPayingScreen.stories.tsx26
-rw-r--r--packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx16
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.stories.tsx84
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.tsx95
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.stories.tsx106
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx38
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.stories.tsx84
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.tsx110
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.stories.tsx58
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.tsx39
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.stories.tsx84
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.tsx118
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.stories.tsx58
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx37
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.stories.tsx86
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx95
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.stories.tsx293
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.tsx37
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.stories.tsx84
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx72
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx58
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx37
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.stories.tsx84
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx109
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.stories.tsx58
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx37
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.stories.tsx85
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.tsx81
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.stories.tsx58
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.tsx37
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/index.tsx29
-rw-r--r--packages/anastasis-webui/src/pages/home/authMethod/totp.ts57
-rw-r--r--packages/anastasis-webui/src/pages/notfound/index.tsx22
-rw-r--r--packages/anastasis-webui/src/pages/profile/index.tsx61
-rw-r--r--packages/anastasis-webui/src/template.html67
-rw-r--r--packages/anastasis-webui/src/utils/index.tsx150
90 files changed, 4183 insertions, 2794 deletions
diff --git a/packages/anastasis-webui/package.json b/packages/anastasis-webui/package.json
index 96d2d65f9..7a92afd43 100644
--- a/packages/anastasis-webui/package.json
+++ b/packages/anastasis-webui/package.json
@@ -5,11 +5,14 @@
"license": "MIT",
"scripts": {
"build": "preact build --no-sw --no-esm",
- "serve": "sirv build --port 8080 --cors --single",
- "dev": "preact watch --no-sw --no-esm",
+ "serve": "sirv build --port ${PORT:=8080} --cors --single",
+ "dev": "preact watch --port ${PORT:=8080} --no-sw --no-esm",
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
"test": "jest ./tests",
"build-storybook": "build-storybook",
+ "build-single": "preact build --no-sw --no-esm -c preact.single-config.js --dest single && sh remove-link-stylesheet.sh",
+ "serve-single": "sirv single --port ${PORT:=8080} --cors --single",
+ "pretty": "prettier --write src",
"storybook": "start-storybook -p 6006"
},
"eslintConfig": {
@@ -25,6 +28,7 @@
"dependencies": {
"@gnu-taler/taler-util": "workspace:^0.8.3",
"anastasis-core": "workspace:^0.0.1",
+ "base64-inline-loader": "1.1.1",
"date-fns": "2.25.0",
"jed": "1.1.1",
"preact": "^10.5.15",
diff --git a/packages/anastasis-webui/src/.babelrc b/packages/anastasis-webui/src/.babelrc
index 123002210..05f4dcc81 100644
--- a/packages/anastasis-webui/src/.babelrc
+++ b/packages/anastasis-webui/src/.babelrc
@@ -1,5 +1,3 @@
{
- "presets": [
- "preact-cli/babel"
- ]
+ "presets": ["preact-cli/babel"]
}
diff --git a/packages/anastasis-webui/src/components/AsyncButton.tsx b/packages/anastasis-webui/src/components/AsyncButton.tsx
index 92bef2219..33f3a7258 100644
--- a/packages/anastasis-webui/src/components/AsyncButton.tsx
+++ b/packages/anastasis-webui/src/components/AsyncButton.tsx
@@ -15,9 +15,9 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { ComponentChildren, h, VNode } from "preact";
// import { LoadingModal } from "../modal";
@@ -31,19 +31,26 @@ type Props = {
[rest: string]: any;
};
-export function AsyncButton({ onClick, disabled, children, ...rest }: Props): VNode {
+export function AsyncButton({
+ onClick,
+ disabled,
+ children,
+ ...rest
+}: Props): VNode {
const { isLoading, request } = useAsync(onClick);
// if (isSlow) {
// return <LoadingModal onCancel={cancel} />;
// }
- if (isLoading) {
+ if (isLoading) {
return <button class="button">Loading...</button>;
}
- return <span data-tooltip={rest['data-tooltip']} style={{marginLeft: 5}}>
- <button {...rest} onClick={request} disabled={disabled}>
- {children}
- </button>
- </span>;
+ return (
+ <span data-tooltip={rest["data-tooltip"]} style={{ marginLeft: 5 }}>
+ <button {...rest} onClick={request} disabled={disabled}>
+ {children}
+ </button>
+ </span>
+ );
}
diff --git a/packages/anastasis-webui/src/components/Notifications.tsx b/packages/anastasis-webui/src/components/Notifications.tsx
index 097ebb4de..e34550386 100644
--- a/packages/anastasis-webui/src/components/Notifications.tsx
+++ b/packages/anastasis-webui/src/components/Notifications.tsx
@@ -15,9 +15,9 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { h, VNode } from "preact";
@@ -27,7 +27,7 @@ export interface Notification {
type: MessageType;
}
-export type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS'
+export type MessageType = "INFO" | "WARN" | "ERROR" | "SUCCESS";
interface Props {
notifications: Notification[];
@@ -36,24 +36,39 @@ interface Props {
function messageStyle(type: MessageType): string {
switch (type) {
- case "INFO": return "message is-info";
- case "WARN": return "message is-warning";
- case "ERROR": return "message is-danger";
- case "SUCCESS": return "message is-success";
- default: return "message"
+ case "INFO":
+ return "message is-info";
+ case "WARN":
+ return "message is-warning";
+ case "ERROR":
+ return "message is-danger";
+ case "SUCCESS":
+ return "message is-success";
+ default:
+ return "message";
}
}
-export function Notifications({ notifications, removeNotification }: Props): VNode {
- return <div class="block">
- {notifications.map((n, i) => <article key={i} class={messageStyle(n.type)}>
- <div class="message-header">
- <p>{n.message}</p>
- {removeNotification && <button class="delete" onClick={() => removeNotification && removeNotification(n)} />}
- </div>
- {n.description && <div class="message-body">
- {n.description}
- </div>}
- </article>)}
- </div>
-} \ No newline at end of file
+export function Notifications({
+ notifications,
+ removeNotification,
+}: Props): VNode {
+ return (
+ <div class="block">
+ {notifications.map((n, i) => (
+ <article key={i} class={messageStyle(n.type)}>
+ <div class="message-header">
+ <p>{n.message}</p>
+ {removeNotification && (
+ <button
+ class="delete"
+ onClick={() => removeNotification && removeNotification(n)}
+ />
+ )}
+ </div>
+ {n.description && <div class="message-body">{n.description}</div>}
+ </article>
+ ))}
+ </div>
+ );
+}
diff --git a/packages/anastasis-webui/src/components/QR.tsx b/packages/anastasis-webui/src/components/QR.tsx
index 48f1a7c12..9a05f6097 100644
--- a/packages/anastasis-webui/src/components/QR.tsx
+++ b/packages/anastasis-webui/src/components/QR.tsx
@@ -21,15 +21,28 @@ import qrcode from "qrcode-generator";
export function QR({ text }: { text: string }): VNode {
const divRef = useRef<HTMLDivElement>(null);
useEffect(() => {
- const qr = qrcode(0, 'L');
+ const qr = qrcode(0, "L");
qr.addData(text);
qr.make();
- if (divRef.current) divRef.current.innerHTML = qr.createSvgTag({
- scalable: true,
- });
+ if (divRef.current)
+ divRef.current.innerHTML = qr.createSvgTag({
+ scalable: true,
+ });
});
- return <div style={{ width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
- <div style={{ width: '50%', minWidth: 200, maxWidth: 300 }} ref={divRef} />
- </div>;
+ return (
+ <div
+ style={{
+ width: "100%",
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ }}
+ >
+ <div
+ style={{ width: "50%", minWidth: 200, maxWidth: 300 }}
+ ref={divRef}
+ />
+ </div>
+ );
}
diff --git a/packages/anastasis-webui/src/components/app.tsx b/packages/anastasis-webui/src/components/app.tsx
index c6b4cfc14..4c6683c0c 100644
--- a/packages/anastasis-webui/src/components/app.tsx
+++ b/packages/anastasis-webui/src/components/app.tsx
@@ -1,6 +1,5 @@
import { FunctionalComponent, h } from "preact";
import { TranslationProvider } from "../context/translation";
-
import AnastasisClient from "../pages/home";
const App: FunctionalComponent = () => {
diff --git a/packages/anastasis-webui/src/components/fields/DateInput.tsx b/packages/anastasis-webui/src/components/fields/DateInput.tsx
index 3148c953f..0b6a7e316 100644
--- a/packages/anastasis-webui/src/components/fields/DateInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/DateInput.tsx
@@ -19,56 +19,66 @@ export function DateInput(props: DateInputProps): VNode {
inputRef.current?.focus();
}
}, [props.grabFocus]);
- const [opened, setOpened] = useState(false)
+ const [opened, setOpened] = useState(false);
const value = props.bind[0] || "";
- const [dirty, setDirty] = useState(false)
- const showError = dirty && props.error
+ const [dirty, setDirty] = useState(false);
+ const showError = dirty && props.error;
- const calendar = subYears(new Date(), 30)
-
- return <div class="field">
- <label class="label">
- {props.label}
- {props.tooltip && <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
- <i class="mdi mdi-information" />
- </span>}
- </label>
- <div class="control">
- <div class="field has-addons">
- <p class="control">
- <input
- type="text"
- class={showError ? 'input is-danger' : 'input'}
- value={value}
- onInput={(e) => {
- const text = e.currentTarget.value
- setDirty(true)
- props.bind[1](text);
- }}
- ref={inputRef} />
- </p>
- <p class="control">
- <a class="button" onClick={() => { setOpened(true) }}>
- <span class="icon"><i class="mdi mdi-calendar" /></span>
- </a>
- </p>
+ const calendar = subYears(new Date(), 30);
+
+ return (
+ <div class="field">
+ <label class="label">
+ {props.label}
+ {props.tooltip && (
+ <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
+ <i class="mdi mdi-information" />
+ </span>
+ )}
+ </label>
+ <div class="control">
+ <div class="field has-addons">
+ <p class="control">
+ <input
+ type="text"
+ class={showError ? "input is-danger" : "input"}
+ value={value}
+ onInput={(e) => {
+ const text = e.currentTarget.value;
+ setDirty(true);
+ props.bind[1](text);
+ }}
+ ref={inputRef}
+ />
+ </p>
+ <p class="control">
+ <a
+ class="button"
+ onClick={() => {
+ setOpened(true);
+ }}
+ >
+ <span class="icon">
+ <i class="mdi mdi-calendar" />
+ </span>
+ </a>
+ </p>
+ </div>
</div>
+ <p class="help">Using the format yyyy-mm-dd</p>
+ {showError && <p class="help is-danger">{props.error}</p>}
+ <DatePicker
+ opened={opened}
+ initialDate={calendar}
+ years={props.years}
+ closeFunction={() => setOpened(false)}
+ dateReceiver={(d) => {
+ setDirty(true);
+ const v = format(d, "yyyy-MM-dd");
+ props.bind[1](v);
+ }}
+ />
</div>
- <p class="help">Using the format yyyy-mm-dd</p>
- {showError && <p class="help is-danger">{props.error}</p>}
- <DatePicker
- opened={opened}
- initialDate={calendar}
- years={props.years}
- closeFunction={() => setOpened(false)}
- dateReceiver={(d) => {
- setDirty(true)
- const v = format(d, 'yyyy-MM-dd')
- props.bind[1](v);
- }}
- />
- </div>
- ;
-
+ );
}
diff --git a/packages/anastasis-webui/src/components/fields/EmailInput.tsx b/packages/anastasis-webui/src/components/fields/EmailInput.tsx
index e21418fea..fe676f284 100644
--- a/packages/anastasis-webui/src/components/fields/EmailInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/EmailInput.tsx
@@ -18,27 +18,34 @@ export function EmailInput(props: TextInputProps): VNode {
}
}, [props.grabFocus]);
const value = props.bind[0];
- const [dirty, setDirty] = useState(false)
- const showError = dirty && props.error
- return (<div class="field">
- <label class="label">
- {props.label}
- {props.tooltip && <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
- <i class="mdi mdi-information" />
- </span>}
- </label>
- <div class="control has-icons-right">
- <input
- value={value}
- required
- placeholder={props.placeholder}
- type="email"
- class={showError ? 'input is-danger' : 'input'}
- onInput={(e) => {setDirty(true); props.bind[1]((e.target as HTMLInputElement).value)}}
- ref={inputRef}
- style={{ display: "block" }} />
+ const [dirty, setDirty] = useState(false);
+ const showError = dirty && props.error;
+ return (
+ <div class="field">
+ <label class="label">
+ {props.label}
+ {props.tooltip && (
+ <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
+ <i class="mdi mdi-information" />
+ </span>
+ )}
+ </label>
+ <div class="control has-icons-right">
+ <input
+ value={value}
+ required
+ placeholder={props.placeholder}
+ type="email"
+ class={showError ? "input is-danger" : "input"}
+ onInput={(e) => {
+ setDirty(true);
+ props.bind[1]((e.target as HTMLInputElement).value);
+ }}
+ ref={inputRef}
+ style={{ display: "block" }}
+ />
+ </div>
+ {showError && <p class="help is-danger">{props.error}</p>}
</div>
- {showError && <p class="help is-danger">{props.error}</p>}
- </div>
);
}
diff --git a/packages/anastasis-webui/src/components/fields/FileInput.tsx b/packages/anastasis-webui/src/components/fields/FileInput.tsx
index 8b144ea43..52d6eab4a 100644
--- a/packages/anastasis-webui/src/components/fields/FileInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/FileInput.tsx
@@ -15,14 +15,14 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
import { TextInputProps } from "./TextInput";
-const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024
+const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
export function FileInput(props: TextInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
@@ -34,48 +34,54 @@ export function FileInput(props: TextInputProps): VNode {
const value = props.bind[0];
// const [dirty, setDirty] = useState(false)
- const image = useRef<HTMLInputElement>(null)
- const [sizeError, setSizeError] = useState(false)
+ const image = useRef<HTMLInputElement>(null);
+ const [sizeError, setSizeError] = useState(false);
function onChange(v: string): void {
// setDirty(true);
props.bind[1](v);
}
- return <div class="field">
- <label class="label">
- <a onClick={() => image.current?.click()}>
- {props.label}
- </a>
- {props.tooltip && <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
- <i class="mdi mdi-information" />
- </span>}
- </label>
- <div class="control">
- <input
- ref={image} style={{ display: 'none' }}
- type="file" name={String(name)}
- onChange={e => {
- const f: FileList | null = e.currentTarget.files
- if (!f || f.length != 1) {
- return onChange("")
- }
- if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
- setSizeError(true)
- return onChange("")
- }
- setSizeError(false)
- return f[0].arrayBuffer().then(b => {
- const b64 = btoa(
- new Uint8Array(b)
- .reduce((data, byte) => data + String.fromCharCode(byte), '')
- )
- return onChange(`data:${f[0].type};base64,${b64}` as any)
- })
- }} />
- {props.error && <p class="help is-danger">{props.error}</p>}
- {sizeError && <p class="help is-danger">
- File should be smaller than 1 MB
- </p>}
+ return (
+ <div class="field">
+ <label class="label">
+ <a onClick={() => image.current?.click()}>{props.label}</a>
+ {props.tooltip && (
+ <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
+ <i class="mdi mdi-information" />
+ </span>
+ )}
+ </label>
+ <div class="control">
+ <input
+ ref={image}
+ style={{ display: "none" }}
+ type="file"
+ name={String(name)}
+ onChange={(e) => {
+ const f: FileList | null = e.currentTarget.files;
+ if (!f || f.length != 1) {
+ return onChange("");
+ }
+ if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
+ setSizeError(true);
+ return onChange("");
+ }
+ setSizeError(false);
+ return f[0].arrayBuffer().then((b) => {
+ const b64 = btoa(
+ new Uint8Array(b).reduce(
+ (data, byte) => data + String.fromCharCode(byte),
+ "",
+ ),
+ );
+ return onChange(`data:${f[0].type};base64,${b64}` as any);
+ });
+ }}
+ />
+ {props.error && <p class="help is-danger">{props.error}</p>}
+ {sizeError && (
+ <p class="help is-danger">File should be smaller than 1 MB</p>
+ )}
+ </div>
</div>
- </div>
+ );
}
-
diff --git a/packages/anastasis-webui/src/components/fields/ImageInput.tsx b/packages/anastasis-webui/src/components/fields/ImageInput.tsx
index d5bf643d4..3f8cc58dd 100644
--- a/packages/anastasis-webui/src/components/fields/ImageInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/ImageInput.tsx
@@ -15,15 +15,15 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
import emptyImage from "../../assets/empty.png";
import { TextInputProps } from "./TextInput";
-const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024
+const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
export function ImageInput(props: TextInputProps): VNode {
const inputRef = useRef<HTMLInputElement>(null);
@@ -35,47 +35,59 @@ export function ImageInput(props: TextInputProps): VNode {
const value = props.bind[0];
// const [dirty, setDirty] = useState(false)
- const image = useRef<HTMLInputElement>(null)
- const [sizeError, setSizeError] = useState(false)
+ const image = useRef<HTMLInputElement>(null);
+ const [sizeError, setSizeError] = useState(false);
function onChange(v: string): void {
// setDirty(true);
props.bind[1](v);
}
- return <div class="field">
- <label class="label">
- {props.label}
- {props.tooltip && <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
- <i class="mdi mdi-information" />
- </span>}
- </label>
- <div class="control">
- <img src={!value ? emptyImage : value} style={{ width: 200, height: 200 }} onClick={() => image.current?.click()} />
- <input
- ref={image} style={{ display: 'none' }}
- type="file" name={String(name)}
- onChange={e => {
- const f: FileList | null = e.currentTarget.files
- if (!f || f.length != 1) {
- return onChange(emptyImage)
- }
- if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
- setSizeError(true)
- return onChange(emptyImage)
- }
- setSizeError(false)
- return f[0].arrayBuffer().then(b => {
- const b64 = btoa(
- new Uint8Array(b)
- .reduce((data, byte) => data + String.fromCharCode(byte), '')
- )
- return onChange(`data:${f[0].type};base64,${b64}` as any)
- })
- }} />
- {props.error && <p class="help is-danger">{props.error}</p>}
- {sizeError && <p class="help is-danger">
- Image should be smaller than 1 MB
- </p>}
+ return (
+ <div class="field">
+ <label class="label">
+ {props.label}
+ {props.tooltip && (
+ <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
+ <i class="mdi mdi-information" />
+ </span>
+ )}
+ </label>
+ <div class="control">
+ <img
+ src={!value ? emptyImage : value}
+ style={{ width: 200, height: 200 }}
+ onClick={() => image.current?.click()}
+ />
+ <input
+ ref={image}
+ style={{ display: "none" }}
+ type="file"
+ name={String(name)}
+ onChange={(e) => {
+ const f: FileList | null = e.currentTarget.files;
+ if (!f || f.length != 1) {
+ return onChange(emptyImage);
+ }
+ if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
+ setSizeError(true);
+ return onChange(emptyImage);
+ }
+ setSizeError(false);
+ return f[0].arrayBuffer().then((b) => {
+ const b64 = btoa(
+ new Uint8Array(b).reduce(
+ (data, byte) => data + String.fromCharCode(byte),
+ "",
+ ),
+ );
+ return onChange(`data:${f[0].type};base64,${b64}` as any);
+ });
+ }}
+ />
+ {props.error && <p class="help is-danger">{props.error}</p>}
+ {sizeError && (
+ <p class="help is-danger">Image should be smaller than 1 MB</p>
+ )}
+ </div>
</div>
- </div>
+ );
}
-
diff --git a/packages/anastasis-webui/src/components/fields/TextInput.tsx b/packages/anastasis-webui/src/components/fields/TextInput.tsx
index c093689c5..fd0c658ed 100644
--- a/packages/anastasis-webui/src/components/fields/TextInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/TextInput.tsx
@@ -18,25 +18,32 @@ export function TextInput(props: TextInputProps): VNode {
}
}, [props.grabFocus]);
const value = props.bind[0];
- const [dirty, setDirty] = useState(false)
- const showError = dirty && props.error
- return (<div class="field">
- <label class="label">
- {props.label}
- {props.tooltip && <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
- <i class="mdi mdi-information" />
- </span>}
- </label>
- <div class="control has-icons-right">
- <input
- value={value}
- placeholder={props.placeholder}
- class={showError ? 'input is-danger' : 'input'}
- onInput={(e) => {setDirty(true); props.bind[1]((e.target as HTMLInputElement).value)}}
- ref={inputRef}
- style={{ display: "block" }} />
+ const [dirty, setDirty] = useState(false);
+ const showError = dirty && props.error;
+ return (
+ <div class="field">
+ <label class="label">
+ {props.label}
+ {props.tooltip && (
+ <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
+ <i class="mdi mdi-information" />
+ </span>
+ )}
+ </label>
+ <div class="control has-icons-right">
+ <input
+ value={value}
+ placeholder={props.placeholder}
+ class={showError ? "input is-danger" : "input"}
+ onInput={(e) => {
+ setDirty(true);
+ props.bind[1]((e.target as HTMLInputElement).value);
+ }}
+ ref={inputRef}
+ style={{ display: "block" }}
+ />
+ </div>
+ {showError && <p class="help is-danger">{props.error}</p>}
</div>
- {showError && <p class="help is-danger">{props.error}</p>}
- </div>
);
}
diff --git a/packages/anastasis-webui/src/components/menu/LangSelector.tsx b/packages/anastasis-webui/src/components/menu/LangSelector.tsx
index 0f91abd7e..fa22a29c0 100644
--- a/packages/anastasis-webui/src/components/menu/LangSelector.tsx
+++ b/packages/anastasis-webui/src/components/menu/LangSelector.tsx
@@ -15,59 +15,78 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
-import langIcon from '../../assets/icons/languageicon.svg';
+import langIcon from "../../assets/icons/languageicon.svg";
import { useTranslationContext } from "../../context/translation";
-import { strings as messages } from '../../i18n/strings'
+import { strings as messages } from "../../i18n/strings";
type LangsNames = {
- [P in keyof typeof messages]: string
-}
+ [P in keyof typeof messages]: string;
+};
const names: LangsNames = {
- es: 'Español [es]',
- en: 'English [en]',
- fr: 'Français [fr]',
- de: 'Deutsch [de]',
- sv: 'Svenska [sv]',
- it: 'Italiano [it]',
-}
+ es: "Español [es]",
+ en: "English [en]",
+ fr: "Français [fr]",
+ de: "Deutsch [de]",
+ sv: "Svenska [sv]",
+ it: "Italiano [it]",
+};
function getLangName(s: keyof LangsNames | string): string {
- if (names[s]) return names[s]
- return String(s)
+ if (names[s]) return names[s];
+ return String(s);
}
export function LangSelector(): VNode {
- const [updatingLang, setUpdatingLang] = useState(false)
- const { lang, changeLanguage } = useTranslationContext()
+ const [updatingLang, setUpdatingLang] = useState(false);
+ const { lang, changeLanguage } = useTranslationContext();
- return <div class="dropdown is-active ">
- <div class="dropdown-trigger">
- <button class="button has-tooltip-left"
- data-tooltip="change language selection"
- aria-haspopup="true"
- aria-controls="dropdown-menu" onClick={() => setUpdatingLang(!updatingLang)}>
- <div class="icon is-small is-left">
- <img src={langIcon} />
- </div>
- <span>{getLangName(lang)}</span>
- <div class="icon is-right">
- <i class="mdi mdi-chevron-down" />
+ return (
+ <div class="dropdown is-active ">
+ <div class="dropdown-trigger">
+ <button
+ class="button has-tooltip-left"
+ data-tooltip="change language selection"
+ aria-haspopup="true"
+ aria-controls="dropdown-menu"
+ onClick={() => setUpdatingLang(!updatingLang)}
+ >
+ <div class="icon is-small is-left">
+ <img src={langIcon} />
+ </div>
+ <span>{getLangName(lang)}</span>
+ <div class="icon is-right">
+ <i class="mdi mdi-chevron-down" />
+ </div>
+ </button>
+ </div>
+ {updatingLang && (
+ <div class="dropdown-menu" id="dropdown-menu" role="menu">
+ <div class="dropdown-content">
+ {Object.keys(messages)
+ .filter((l) => l !== lang)
+ .map((l) => (
+ <a
+ key={l}
+ class="dropdown-item"
+ value={l}
+ onClick={() => {
+ changeLanguage(l);
+ setUpdatingLang(false);
+ }}
+ >
+ {getLangName(l)}
+ </a>
+ ))}
+ </div>
</div>
- </button>
+ )}
</div>
- {updatingLang && <div class="dropdown-menu" id="dropdown-menu" role="menu">
- <div class="dropdown-content">
- {Object.keys(messages)
- .filter((l) => l !== lang)
- .map(l => <a key={l} class="dropdown-item" value={l} onClick={() => { changeLanguage(l); setUpdatingLang(false) }}>{getLangName(l)}</a>)}
- </div>
- </div>}
- </div>
-} \ No newline at end of file
+ );
+}
diff --git a/packages/anastasis-webui/src/components/menu/SideBar.tsx b/packages/anastasis-webui/src/components/menu/SideBar.tsx
index a40f4be09..c73369dd6 100644
--- a/packages/anastasis-webui/src/components/menu/SideBar.tsx
+++ b/packages/anastasis-webui/src/components/menu/SideBar.tsx
@@ -15,16 +15,15 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { Fragment, h, VNode } from 'preact';
-import { BackupStates, RecoveryStates } from '../../../../anastasis-core/lib';
-import { useAnastasisContext } from '../../context/anastasis';
-import { Translate } from '../../i18n';
-import { LangSelector } from './LangSelector';
+import { Fragment, h, VNode } from "preact";
+import { BackupStates, RecoveryStates } from "../../../../anastasis-core/lib";
+import { useAnastasisContext } from "../../context/anastasis";
+import { Translate } from "../../i18n";
+import { LangSelector } from "./LangSelector";
interface Props {
mobile?: boolean;
@@ -32,10 +31,10 @@ interface Props {
export function Sidebar({ mobile }: Props): VNode {
// const config = useConfigContext();
- const config = { version: 'none' }
+ const config = { version: "none" };
// FIXME: add replacement for __VERSION__ with the current version
- const process = { env: { __VERSION__: '0.0.0' } }
- const reducer = useAnastasisContext()!
+ const process = { env: { __VERSION__: "0.0.0" } };
+ const reducer = useAnastasisContext()!;
return (
<aside class="aside is-placed-left is-expanded">
@@ -44,114 +43,235 @@ export function Sidebar({ mobile }: Props): VNode {
</div>} */}
<div class="aside-tools">
<div class="aside-tools-label">
- <div><b>Anastasis</b></div>
- <div class="is-size-7 has-text-right" style={{ lineHeight: 0, marginTop: -10 }}>
+ <div>
+ <b>Anastasis</b>
+ </div>
+ <div
+ class="is-size-7 has-text-right"
+ style={{ lineHeight: 0, marginTop: -10 }}
+ >
Version {process.env.__VERSION__} ({config.version})
</div>
</div>
</div>
<div class="menu is-menu-main">
- {!reducer.currentReducerState &&
+ {!reducer.currentReducerState && (
<p class="menu-label">
<Translate>Backup or Recorver</Translate>
</p>
- }
+ )}
<ul class="menu-list">
- {!reducer.currentReducerState &&
+ {!reducer.currentReducerState && (
<li>
<div class="ml-4">
- <span class="menu-item-label"><Translate>Select one option</Translate></span>
- </div>
- </li>
- }
- {reducer.currentReducerState && reducer.currentReducerState.backup_state ? <Fragment>
- <li class={reducer.currentReducerState.backup_state === BackupStates.ContinentSelecting ||
- reducer.currentReducerState.backup_state === BackupStates.CountrySelecting ? 'is-active' : ''}>
- <div class="ml-4">
- <span class="menu-item-label"><Translate>Location</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.backup_state === BackupStates.UserAttributesCollecting ? 'is-active' : ''}>
- <div class="ml-4">
- <span class="menu-item-label"><Translate>Personal information</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.backup_state === BackupStates.AuthenticationsEditing ? 'is-active' : ''}>
- <div class="ml-4">
-
- <span class="menu-item-label"><Translate>Authorization methods</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.backup_state === BackupStates.PoliciesReviewing ? 'is-active' : ''}>
- <div class="ml-4">
-
- <span class="menu-item-label"><Translate>Policies</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.backup_state === BackupStates.SecretEditing ? 'is-active' : ''}>
- <div class="ml-4">
-
- <span class="menu-item-label"><Translate>Secret input</Translate></span>
+ <span class="menu-item-label">
+ <Translate>Select one option</Translate>
+ </span>
</div>
</li>
- {/* <li class={reducer.currentReducerState.backup_state === BackupStates.PoliciesPaying ? 'is-active' : ''}>
+ )}
+ {reducer.currentReducerState &&
+ reducer.currentReducerState.backup_state ? (
+ <Fragment>
+ <li
+ class={
+ reducer.currentReducerState.backup_state ===
+ BackupStates.ContinentSelecting ||
+ reducer.currentReducerState.backup_state ===
+ BackupStates.CountrySelecting
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Location</Translate>
+ </span>
+ </div>
+ </li>
+ <li
+ class={
+ reducer.currentReducerState.backup_state ===
+ BackupStates.UserAttributesCollecting
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Personal information</Translate>
+ </span>
+ </div>
+ </li>
+ <li
+ class={
+ reducer.currentReducerState.backup_state ===
+ BackupStates.AuthenticationsEditing
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Authorization methods</Translate>
+ </span>
+ </div>
+ </li>
+ <li
+ class={
+ reducer.currentReducerState.backup_state ===
+ BackupStates.PoliciesReviewing
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Policies</Translate>
+ </span>
+ </div>
+ </li>
+ <li
+ class={
+ reducer.currentReducerState.backup_state ===
+ BackupStates.SecretEditing
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Secret input</Translate>
+ </span>
+ </div>
+ </li>
+ {/* <li class={reducer.currentReducerState.backup_state === BackupStates.PoliciesPaying ? 'is-active' : ''}>
<div class="ml-4">
<span class="menu-item-label"><Translate>Payment (optional)</Translate></span>
</div>
</li> */}
- <li class={reducer.currentReducerState.backup_state === BackupStates.BackupFinished ? 'is-active' : ''}>
- <div class="ml-4">
-
- <span class="menu-item-label"><Translate>Backup completed</Translate></span>
- </div>
- </li>
- {/* <li class={reducer.currentReducerState.backup_state === BackupStates.TruthsPaying ? 'is-active' : ''}>
+ <li
+ class={
+ reducer.currentReducerState.backup_state ===
+ BackupStates.BackupFinished
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Backup completed</Translate>
+ </span>
+ </div>
+ </li>
+ {/* <li class={reducer.currentReducerState.backup_state === BackupStates.TruthsPaying ? 'is-active' : ''}>
<div class="ml-4">
<span class="menu-item-label"><Translate>Truth Paying</Translate></span>
</div>
</li> */}
- </Fragment> : (reducer.currentReducerState && reducer.currentReducerState?.recovery_state && <Fragment>
- <li class={reducer.currentReducerState.recovery_state === RecoveryStates.ContinentSelecting ||
- reducer.currentReducerState.recovery_state === RecoveryStates.CountrySelecting ? 'is-active' : ''}>
- <div class="ml-4">
- <span class="menu-item-label"><Translate>Location</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.recovery_state === RecoveryStates.UserAttributesCollecting ? 'is-active' : ''}>
- <div class="ml-4">
- <span class="menu-item-label"><Translate>Personal information</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.recovery_state === RecoveryStates.SecretSelecting ? 'is-active' : ''}>
- <div class="ml-4">
- <span class="menu-item-label"><Translate>Secret selection</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.recovery_state === RecoveryStates.ChallengeSelecting ||
- reducer.currentReducerState.recovery_state === RecoveryStates.ChallengeSolving ? 'is-active' : ''}>
- <div class="ml-4">
- <span class="menu-item-label"><Translate>Solve Challenges</Translate></span>
- </div>
- </li>
- <li class={reducer.currentReducerState.recovery_state === RecoveryStates.RecoveryFinished ? 'is-active' : ''}>
- <div class="ml-4">
- <span class="menu-item-label"><Translate>Secret recovered</Translate></span>
- </div>
- </li>
- </Fragment>)}
- {reducer.currentReducerState &&
+ </Fragment>
+ ) : (
+ reducer.currentReducerState &&
+ reducer.currentReducerState?.recovery_state && (
+ <Fragment>
+ <li
+ class={
+ reducer.currentReducerState.recovery_state ===
+ RecoveryStates.ContinentSelecting ||
+ reducer.currentReducerState.recovery_state ===
+ RecoveryStates.CountrySelecting
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Location</Translate>
+ </span>
+ </div>
+ </li>
+ <li
+ class={
+ reducer.currentReducerState.recovery_state ===
+ RecoveryStates.UserAttributesCollecting
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Personal information</Translate>
+ </span>
+ </div>
+ </li>
+ <li
+ class={
+ reducer.currentReducerState.recovery_state ===
+ RecoveryStates.SecretSelecting
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Secret selection</Translate>
+ </span>
+ </div>
+ </li>
+ <li
+ class={
+ reducer.currentReducerState.recovery_state ===
+ RecoveryStates.ChallengeSelecting ||
+ reducer.currentReducerState.recovery_state ===
+ RecoveryStates.ChallengeSolving
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Solve Challenges</Translate>
+ </span>
+ </div>
+ </li>
+ <li
+ class={
+ reducer.currentReducerState.recovery_state ===
+ RecoveryStates.RecoveryFinished
+ ? "is-active"
+ : ""
+ }
+ >
+ <div class="ml-4">
+ <span class="menu-item-label">
+ <Translate>Secret recovered</Translate>
+ </span>
+ </div>
+ </li>
+ </Fragment>
+ )
+ )}
+ {reducer.currentReducerState && (
<li>
<div class="buttons ml-4">
- <button class="button is-danger is-right" onClick={() => reducer.reset()}>Reset session</button>
+ <button
+ class="button is-danger is-right"
+ onClick={() => reducer.reset()}
+ >
+ Reset session
+ </button>
</div>
</li>
- }
-
+ )}
+ {/* <li>
+ <div class="buttons ml-4">
+ <button class="button is-info is-right" >Manage providers</button>
+ </div>
+ </li> */}
</ul>
</div>
</aside>
);
}
-
diff --git a/packages/anastasis-webui/src/components/menu/index.tsx b/packages/anastasis-webui/src/components/menu/index.tsx
index fd4aab149..99d0f7646 100644
--- a/packages/anastasis-webui/src/components/menu/index.tsx
+++ b/packages/anastasis-webui/src/components/menu/index.tsx
@@ -85,8 +85,8 @@ export function NotificationCard({
n.type === "ERROR"
? "message is-danger"
: n.type === "WARN"
- ? "message is-warning"
- : "message is-info"
+ ? "message is-warning"
+ : "message is-info"
}
>
<div class="message-header">
@@ -113,7 +113,7 @@ export function NotYetReadyAppMenu({
return (
<div
class="has-aside-mobile-expanded"
- // class={mobileOpen ? "has-aside-mobile-expanded" : ""}
+ // class={mobileOpen ? "has-aside-mobile-expanded" : ""}
onClick={() => setMobileOpen(false)}
>
<NavigationBar
diff --git a/packages/anastasis-webui/src/components/picker/DatePicker.tsx b/packages/anastasis-webui/src/components/picker/DatePicker.tsx
index eb5d8145d..d689db386 100644
--- a/packages/anastasis-webui/src/components/picker/DatePicker.tsx
+++ b/packages/anastasis-webui/src/components/picker/DatePicker.tsx
@@ -15,9 +15,9 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { h, Component } from "preact";
@@ -34,83 +34,71 @@ interface State {
selectYearMode: boolean;
currentDate: Date;
}
-const now = new Date()
+const now = new Date();
const monthArrShortFull = [
- 'January',
- 'February',
- 'March',
- 'April',
- 'May',
- 'June',
- 'July',
- 'August',
- 'September',
- 'October',
- 'November',
- 'December'
-]
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+];
const monthArrShort = [
- 'Jan',
- 'Feb',
- 'Mar',
- 'Apr',
- 'May',
- 'Jun',
- 'Jul',
- 'Aug',
- 'Sep',
- 'Oct',
- 'Nov',
- 'Dec'
-]
-
-const dayArr = [
- 'Sun',
- 'Mon',
- 'Tue',
- 'Wed',
- 'Thu',
- 'Fri',
- 'Sat'
-]
-
-const yearArr: number[] = []
-
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec",
+];
+
+const dayArr = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+
+const yearArr: number[] = [];
// inspired by https://codepen.io/m4r1vs/pen/MOOxyE
export class DatePicker extends Component<Props, State> {
-
closeDatePicker() {
this.props.closeFunction && this.props.closeFunction(); // Function gets passed by parent
}
/**
- * Gets fired when a day gets clicked.
- * @param {object} e The event thrown by the <span /> element clicked
- */
+ * Gets fired when a day gets clicked.
+ * @param {object} e The event thrown by the <span /> element clicked
+ */
dayClicked(e: any) {
-
const element = e.target; // the actual element clicked
- if (element.innerHTML === '') return false; // don't continue if <span /> empty
+ if (element.innerHTML === "") return false; // don't continue if <span /> empty
// get date from clicked element (gets attached when rendered)
- const date = new Date(element.getAttribute('data-value'));
+ const date = new Date(element.getAttribute("data-value"));
// update the state
this.setState({ currentDate: date });
- this.passDateToParent(date)
+ this.passDateToParent(date);
}
/**
- * returns days in month as array
- * @param {number} month the month to display
- * @param {number} year the year to display
- */
+ * returns days in month as array
+ * @param {number} month the month to display
+ * @param {number} year the year to display
+ */
getDaysByMonth(month: number, year: number) {
-
const calendar = [];
const date = new Date(year, month, 1); // month to display
@@ -122,15 +110,17 @@ export class DatePicker extends Component<Props, State> {
// the calendar is 7*6 fields big, so 42 loops
for (let i = 0; i < 42; i++) {
-
if (i >= firstDay && day !== null) day = day + 1;
if (day !== null && day > lastDate) day = null;
// append the calendar Array
calendar.push({
- day: (day === 0 || day === null) ? null : day, // null or number
- date: (day === 0 || day === null) ? null : new Date(year, month, day), // null or Date()
- today: (day === now.getDate() && month === now.getMonth() && year === now.getFullYear()) // boolean
+ day: day === 0 || day === null ? null : day, // null or number
+ date: day === 0 || day === null ? null : new Date(year, month, day), // null or Date()
+ today:
+ day === now.getDate() &&
+ month === now.getMonth() &&
+ year === now.getFullYear(), // boolean
});
}
@@ -138,51 +128,48 @@ export class DatePicker extends Component<Props, State> {
}
/**
- * Display previous month by updating state
- */
+ * Display previous month by updating state
+ */
displayPrevMonth() {
if (this.state.displayedMonth <= 0) {
this.setState({
displayedMonth: 11,
- displayedYear: this.state.displayedYear - 1
+ displayedYear: this.state.displayedYear - 1,
});
- }
- else {
+ } else {
this.setState({
- displayedMonth: this.state.displayedMonth - 1
+ displayedMonth: this.state.displayedMonth - 1,
});
}
}
/**
- * Display next month by updating state
- */
+ * Display next month by updating state
+ */
displayNextMonth() {
if (this.state.displayedMonth >= 11) {
this.setState({
displayedMonth: 0,
- displayedYear: this.state.displayedYear + 1
+ displayedYear: this.state.displayedYear + 1,
});
- }
- else {
+ } else {
this.setState({
- displayedMonth: this.state.displayedMonth + 1
+ displayedMonth: this.state.displayedMonth + 1,
});
}
}
/**
- * Display the selected month (gets fired when clicking on the date string)
- */
+ * Display the selected month (gets fired when clicking on the date string)
+ */
displaySelectedMonth() {
if (this.state.selectYearMode) {
this.toggleYearSelector();
- }
- else {
+ } else {
if (!this.state.currentDate) return false;
this.setState({
displayedMonth: this.state.currentDate.getMonth(),
- displayedYear: this.state.currentDate.getFullYear()
+ displayedYear: this.state.currentDate.getFullYear(),
});
}
}
@@ -194,17 +181,21 @@ export class DatePicker extends Component<Props, State> {
changeDisplayedYear(e: any) {
const element = e.target;
this.toggleYearSelector();
- this.setState({ displayedYear: parseInt(element.innerHTML, 10), displayedMonth: 0 });
+ this.setState({
+ displayedYear: parseInt(element.innerHTML, 10),
+ displayedMonth: 0,
+ });
}
/**
- * Pass the selected date to parent when 'OK' is clicked
- */
+ * Pass the selected date to parent when 'OK' is clicked
+ */
passSavedDateDateToParent() {
- this.passDateToParent(this.state.currentDate)
+ this.passDateToParent(this.state.currentDate);
}
passDateToParent(date: Date) {
- if (typeof this.props.dateReceiver === 'function') this.props.dateReceiver(date);
+ if (typeof this.props.dateReceiver === "function")
+ this.props.dateReceiver(date);
this.closeDatePicker();
}
@@ -233,94 +224,133 @@ export class DatePicker extends Component<Props, State> {
currentDate: initial,
displayedMonth: initial.getMonth(),
displayedYear: initial.getFullYear(),
- selectYearMode: false
- }
+ selectYearMode: false,
+ };
}
render() {
-
- const { currentDate, displayedMonth, displayedYear, selectYearMode } = this.state;
+ const {
+ currentDate,
+ displayedMonth,
+ displayedYear,
+ selectYearMode,
+ } = this.state;
return (
<div>
- <div class={`datePicker ${ this.props.opened && "datePicker--opened"}`}>
-
+ <div class={`datePicker ${this.props.opened && "datePicker--opened"}`}>
<div class="datePicker--titles">
- <h3 style={{
- color: selectYearMode ? 'rgba(255,255,255,.87)' : 'rgba(255,255,255,.57)'
- }} onClick={this.toggleYearSelector}>{currentDate.getFullYear()}</h3>
- <h2 style={{
- color: !selectYearMode ? 'rgba(255,255,255,.87)' : 'rgba(255,255,255,.57)'
- }} onClick={this.displaySelectedMonth}>
- {dayArr[currentDate.getDay()]}, {monthArrShort[currentDate.getMonth()]} {currentDate.getDate()}
+ <h3
+ style={{
+ color: selectYearMode
+ ? "rgba(255,255,255,.87)"
+ : "rgba(255,255,255,.57)",
+ }}
+ onClick={this.toggleYearSelector}
+ >
+ {currentDate.getFullYear()}
+ </h3>
+ <h2
+ style={{
+ color: !selectYearMode
+ ? "rgba(255,255,255,.87)"
+ : "rgba(255,255,255,.57)",
+ }}
+ onClick={this.displaySelectedMonth}
+ >
+ {dayArr[currentDate.getDay()]},{" "}
+ {monthArrShort[currentDate.getMonth()]} {currentDate.getDate()}
</h2>
</div>
- {!selectYearMode && <nav>
- <span onClick={this.displayPrevMonth} class="icon"><i style={{ transform: 'rotate(180deg)' }} class="mdi mdi-forward" /></span>
- <h4>{monthArrShortFull[displayedMonth]} {displayedYear}</h4>
- <span onClick={this.displayNextMonth} class="icon"><i class="mdi mdi-forward" /></span>
- </nav>}
+ {!selectYearMode && (
+ <nav>
+ <span onClick={this.displayPrevMonth} class="icon">
+ <i
+ style={{ transform: "rotate(180deg)" }}
+ class="mdi mdi-forward"
+ />
+ </span>
+ <h4>
+ {monthArrShortFull[displayedMonth]} {displayedYear}
+ </h4>
+ <span onClick={this.displayNextMonth} class="icon">
+ <i class="mdi mdi-forward" />
+ </span>
+ </nav>
+ )}
<div class="datePicker--scroll">
-
- {!selectYearMode && <div class="datePicker--calendar" >
-
- <div class="datePicker--dayNames">
- {['S', 'M', 'T', 'W', 'T', 'F', 'S'].map((day,i) => <span key={i}>{day}</span>)}
- </div>
-
- <div onClick={this.dayClicked} class="datePicker--days">
-
- {/*
+ {!selectYearMode && (
+ <div class="datePicker--calendar">
+ <div class="datePicker--dayNames">
+ {["S", "M", "T", "W", "T", "F", "S"].map((day, i) => (
+ <span key={i}>{day}</span>
+ ))}
+ </div>
+
+ <div onClick={this.dayClicked} class="datePicker--days">
+ {/*
Loop through the calendar object returned by getDaysByMonth().
*/}
- {this.getDaysByMonth(this.state.displayedMonth, this.state.displayedYear)
- .map(
- day => {
- let selected = false;
-
- if (currentDate && day.date) selected = (currentDate.toLocaleDateString() === day.date.toLocaleDateString());
-
- return (<span key={day.day}
- class={(day.today ? 'datePicker--today ' : '') + (selected ? 'datePicker--selected' : '')}
+ {this.getDaysByMonth(
+ this.state.displayedMonth,
+ this.state.displayedYear,
+ ).map((day) => {
+ let selected = false;
+
+ if (currentDate && day.date)
+ selected =
+ currentDate.toLocaleDateString() ===
+ day.date.toLocaleDateString();
+
+ return (
+ <span
+ key={day.day}
+ class={
+ (day.today ? "datePicker--today " : "") +
+ (selected ? "datePicker--selected" : "")
+ }
disabled={!day.date}
data-value={day.date}
>
{day.day}
- </span>)
- }
- )
- }
-
+ </span>
+ );
+ })}
+ </div>
</div>
-
- </div>}
-
- {selectYearMode && <div class="datePicker--selectYear">
- {(this.props.years || yearArr).map(year => (
- <span key={year} class={(year === displayedYear) ? 'selected' : ''} onClick={this.changeDisplayedYear}>
- {year}
- </span>
- ))}
-
- </div>}
-
+ )}
+
+ {selectYearMode && (
+ <div class="datePicker--selectYear">
+ {(this.props.years || yearArr).map((year) => (
+ <span
+ key={year}
+ class={year === displayedYear ? "selected" : ""}
+ onClick={this.changeDisplayedYear}
+ >
+ {year}
+ </span>
+ ))}
+ </div>
+ )}
</div>
</div>
- <div class="datePicker--background" onClick={this.closeDatePicker} style={{
- display: this.props.opened ? 'block' : 'none',
- }}
+ <div
+ class="datePicker--background"
+ onClick={this.closeDatePicker}
+ style={{
+ display: this.props.opened ? "block" : "none",
+ }}
/>
-
</div>
- )
+ );
}
}
-
for (let i = 2010; i <= now.getFullYear() + 10; i++) {
yearArr.push(i);
}
diff --git a/packages/anastasis-webui/src/components/picker/DurationPicker.stories.tsx b/packages/anastasis-webui/src/components/picker/DurationPicker.stories.tsx
index 275c80fa6..7f96cc15b 100644
--- a/packages/anastasis-webui/src/components/picker/DurationPicker.stories.tsx
+++ b/packages/anastasis-webui/src/components/picker/DurationPicker.stories.tsx
@@ -15,36 +15,41 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { h, FunctionalComponent } from 'preact';
-import { useState } from 'preact/hooks';
-import { DurationPicker as TestedComponent } from './DurationPicker';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { h, FunctionalComponent } from "preact";
+import { useState } from "preact/hooks";
+import { DurationPicker as TestedComponent } from "./DurationPicker";
export default {
- title: 'Components/Picker/Duration',
+ title: "Components/Picker/Duration",
component: TestedComponent,
argTypes: {
- onCreate: { action: 'onCreate' },
- goBack: { action: 'goBack' },
- }
+ onCreate: { action: "onCreate" },
+ goBack: { action: "goBack" },
+ },
};
-function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) {
- const r = (args: any) => <Component {...args} />
- r.args = props
- return r
+function createExample<Props>(
+ Component: FunctionalComponent<Props>,
+ props: Partial<Props>,
+) {
+ const r = (args: any) => <Component {...args} />;
+ r.args = props;
+ return r;
}
export const Example = createExample(TestedComponent, {
- days: true, minutes: true, hours: true, seconds: true,
- value: 10000000
+ days: true,
+ minutes: true,
+ hours: true,
+ seconds: true,
+ value: 10000000,
});
export const WithState = () => {
- const [v,s] = useState<number>(1000000)
- return <TestedComponent value={v} onChange={s} days minutes hours seconds />
-}
+ const [v, s] = useState<number>(1000000);
+ return <TestedComponent value={v} onChange={s} days minutes hours seconds />;
+};
diff --git a/packages/anastasis-webui/src/components/picker/DurationPicker.tsx b/packages/anastasis-webui/src/components/picker/DurationPicker.tsx
index 235a63e2d..8a1faf4d0 100644
--- a/packages/anastasis-webui/src/components/picker/DurationPicker.tsx
+++ b/packages/anastasis-webui/src/components/picker/DurationPicker.tsx
@@ -15,9 +15,9 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
@@ -30,75 +30,123 @@ export interface Props {
seconds?: boolean;
days?: boolean;
onChange: (value: number) => void;
- value: number
+ value: number;
}
// inspiration taken from https://github.com/flurmbo/react-duration-picker
-export function DurationPicker({ days, hours, minutes, seconds, onChange, value }: Props): VNode {
- const ss = 1000
- const ms = ss * 60
- const hs = ms * 60
- const ds = hs * 24
- const i18n = useTranslator()
-
- return <div class="rdp-picker">
- {days && <DurationColumn unit={i18n`days`} max={99}
- value={Math.floor(value / ds)}
- onDecrease={value >= ds ? () => onChange(value - ds) : undefined}
- onIncrease={value < 99 * ds ? () => onChange(value + ds) : undefined}
- onChange={diff => onChange(value + diff * ds)}
- />}
- {hours && <DurationColumn unit={i18n`hours`} max={23} min={1}
- value={Math.floor(value / hs) % 24}
- onDecrease={value >= hs ? () => onChange(value - hs) : undefined}
- onIncrease={value < 99 * ds ? () => onChange(value + hs) : undefined}
- onChange={diff => onChange(value + diff * hs)}
- />}
- {minutes && <DurationColumn unit={i18n`minutes`} max={59} min={1}
- value={Math.floor(value / ms) % 60}
- onDecrease={value >= ms ? () => onChange(value - ms) : undefined}
- onIncrease={value < 99 * ds ? () => onChange(value + ms) : undefined}
- onChange={diff => onChange(value + diff * ms)}
- />}
- {seconds && <DurationColumn unit={i18n`seconds`} max={59}
- value={Math.floor(value / ss) % 60}
- onDecrease={value >= ss ? () => onChange(value - ss) : undefined}
- onIncrease={value < 99 * ds ? () => onChange(value + ss) : undefined}
- onChange={diff => onChange(value + diff * ss)}
- />}
- </div>
+export function DurationPicker({
+ days,
+ hours,
+ minutes,
+ seconds,
+ onChange,
+ value,
+}: Props): VNode {
+ const ss = 1000;
+ const ms = ss * 60;
+ const hs = ms * 60;
+ const ds = hs * 24;
+ const i18n = useTranslator();
+
+ return (
+ <div class="rdp-picker">
+ {days && (
+ <DurationColumn
+ unit={i18n`days`}
+ max={99}
+ value={Math.floor(value / ds)}
+ onDecrease={value >= ds ? () => onChange(value - ds) : undefined}
+ onIncrease={value < 99 * ds ? () => onChange(value + ds) : undefined}
+ onChange={(diff) => onChange(value + diff * ds)}
+ />
+ )}
+ {hours && (
+ <DurationColumn
+ unit={i18n`hours`}
+ max={23}
+ min={1}
+ value={Math.floor(value / hs) % 24}
+ onDecrease={value >= hs ? () => onChange(value - hs) : undefined}
+ onIncrease={value < 99 * ds ? () => onChange(value + hs) : undefined}
+ onChange={(diff) => onChange(value + diff * hs)}
+ />
+ )}
+ {minutes && (
+ <DurationColumn
+ unit={i18n`minutes`}
+ max={59}
+ min={1}
+ value={Math.floor(value / ms) % 60}
+ onDecrease={value >= ms ? () => onChange(value - ms) : undefined}
+ onIncrease={value < 99 * ds ? () => onChange(value + ms) : undefined}
+ onChange={(diff) => onChange(value + diff * ms)}
+ />
+ )}
+ {seconds && (
+ <DurationColumn
+ unit={i18n`seconds`}
+ max={59}
+ value={Math.floor(value / ss) % 60}
+ onDecrease={value >= ss ? () => onChange(value - ss) : undefined}
+ onIncrease={value < 99 * ds ? () => onChange(value + ss) : undefined}
+ onChange={(diff) => onChange(value + diff * ss)}
+ />
+ )}
+ </div>
+ );
}
interface ColProps {
- unit: string,
- min?: number,
- max: number,
- value: number,
+ unit: string;
+ min?: number;
+ max: number;
+ value: number;
onIncrease?: () => void;
onDecrease?: () => void;
onChange?: (diff: number) => void;
}
-function InputNumber({ initial, onChange }: { initial: number, onChange: (n: number) => void }) {
- const [value, handler] = useState<{v:string}>({
- v: toTwoDigitString(initial)
- })
-
- return <input
- value={value.v}
- onBlur={(e) => onChange(parseInt(value.v, 10))}
- onInput={(e) => {
- e.preventDefault()
- const n = Number.parseInt(e.currentTarget.value, 10);
- if (isNaN(n)) return handler({v:toTwoDigitString(initial)})
- return handler({v:toTwoDigitString(n)})
- }}
- style={{ width: 50, border: 'none', fontSize: 'inherit', background: 'inherit' }} />
-}
+function InputNumber({
+ initial,
+ onChange,
+}: {
+ initial: number;
+ onChange: (n: number) => void;
+}) {
+ const [value, handler] = useState<{ v: string }>({
+ v: toTwoDigitString(initial),
+ });
-function DurationColumn({ unit, min = 0, max, value, onIncrease, onDecrease, onChange }: ColProps): VNode {
+ return (
+ <input
+ value={value.v}
+ onBlur={(e) => onChange(parseInt(value.v, 10))}
+ onInput={(e) => {
+ e.preventDefault();
+ const n = Number.parseInt(e.currentTarget.value, 10);
+ if (isNaN(n)) return handler({ v: toTwoDigitString(initial) });
+ return handler({ v: toTwoDigitString(n) });
+ }}
+ style={{
+ width: 50,
+ border: "none",
+ fontSize: "inherit",
+ background: "inherit",
+ }}
+ />
+ );
+}
- const cellHeight = 35
+function DurationColumn({
+ unit,
+ min = 0,
+ max,
+ value,
+ onIncrease,
+ onDecrease,
+ onChange,
+}: ColProps): VNode {
+ const cellHeight = 35;
return (
<div class="rdp-column-container">
<div class="rdp-masked-div">
@@ -106,49 +154,58 @@ function DurationColumn({ unit, min = 0, max, value, onIncrease, onDecrease, onC
<hr class="rdp-reticule" style={{ top: cellHeight * 3 - 1 }} />
<div class="rdp-column" style={{ top: 0 }}>
-
<div class="rdp-cell" key={value - 2}>
- {onDecrease && <button style={{ width: '100%', textAlign: 'center', margin: 5 }}
- onClick={onDecrease}>
- <span class="icon">
- <i class="mdi mdi-chevron-up" />
- </span>
- </button>}
+ {onDecrease && (
+ <button
+ style={{ width: "100%", textAlign: "center", margin: 5 }}
+ onClick={onDecrease}
+ >
+ <span class="icon">
+ <i class="mdi mdi-chevron-up" />
+ </span>
+ </button>
+ )}
</div>
<div class="rdp-cell" key={value - 1}>
- {value > min ? toTwoDigitString(value - 1) : ''}
+ {value > min ? toTwoDigitString(value - 1) : ""}
</div>
<div class="rdp-cell rdp-center" key={value}>
- {onChange ?
- <InputNumber initial={value} onChange={(n) => onChange(n - value)} /> :
+ {onChange ? (
+ <InputNumber
+ initial={value}
+ onChange={(n) => onChange(n - value)}
+ />
+ ) : (
toTwoDigitString(value)
- }
+ )}
<div>{unit}</div>
</div>
<div class="rdp-cell" key={value + 1}>
- {value < max ? toTwoDigitString(value + 1) : ''}
+ {value < max ? toTwoDigitString(value + 1) : ""}
</div>
<div class="rdp-cell" key={value + 2}>
- {onIncrease && <button style={{ width: '100%', textAlign: 'center', margin: 5 }}
- onClick={onIncrease}>
- <span class="icon">
- <i class="mdi mdi-chevron-down" />
- </span>
- </button>}
+ {onIncrease && (
+ <button
+ style={{ width: "100%", textAlign: "center", margin: 5 }}
+ onClick={onIncrease}
+ >
+ <span class="icon">
+ <i class="mdi mdi-chevron-down" />
+ </span>
+ </button>
+ )}
</div>
-
</div>
</div>
</div>
);
}
-
function toTwoDigitString(n: number) {
if (n < 10) {
return `0${n}`;
}
return `${n}`;
-} \ No newline at end of file
+}
diff --git a/packages/anastasis-webui/src/context/anastasis.ts b/packages/anastasis-webui/src/context/anastasis.ts
index e7f93ed43..c2e7b2a47 100644
--- a/packages/anastasis-webui/src/context/anastasis.ts
+++ b/packages/anastasis-webui/src/context/anastasis.ts
@@ -15,19 +15,19 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createContext, h, VNode } from 'preact';
-import { useContext } from 'preact/hooks';
-import { AnastasisReducerApi } from '../hooks/use-anastasis-reducer';
+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 initial = undefined;
-const Context = createContext<Type>(initial)
+const Context = createContext<Type>(initial);
interface Props {
value: AnastasisReducerApi;
@@ -36,6 +36,6 @@ interface Props {
export const AnastasisProvider = ({ value, children }: Props): VNode => {
return h(Context.Provider, { value, children });
-}
+};
-export const useAnastasisContext = (): Type => useContext(Context); \ No newline at end of file
+export const useAnastasisContext = (): Type => useContext(Context);
diff --git a/packages/anastasis-webui/src/context/translation.ts b/packages/anastasis-webui/src/context/translation.ts
index 5ceb5d428..a47864d75 100644
--- a/packages/anastasis-webui/src/context/translation.ts
+++ b/packages/anastasis-webui/src/context/translation.ts
@@ -15,13 +15,13 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createContext, h, VNode } from 'preact'
-import { useContext, useEffect } from 'preact/hooks'
-import { useLang } from '../hooks'
+import { createContext, h, VNode } from "preact";
+import { useContext, useEffect } from "preact/hooks";
+import { useLang } from "../hooks";
import * as jedLib from "jed";
import { strings } from "../i18n/strings";
@@ -31,13 +31,13 @@ interface Type {
changeLanguage: (l: string) => void;
}
const initial = {
- lang: 'en',
+ lang: "en",
handler: null,
changeLanguage: () => {
// do not change anything
- }
-}
-const Context = createContext<Type>(initial)
+ },
+};
+const Context = createContext<Type>(initial);
interface Props {
initial?: string;
@@ -45,15 +45,22 @@ interface Props {
forceLang?: string;
}
-export const TranslationProvider = ({ initial, children, forceLang }: Props): VNode => {
- const [lang, changeLanguage] = useLang(initial)
+export const TranslationProvider = ({
+ initial,
+ children,
+ forceLang,
+}: Props): VNode => {
+ const [lang, changeLanguage] = useLang(initial);
useEffect(() => {
if (forceLang) {
- changeLanguage(forceLang)
+ changeLanguage(forceLang);
}
- })
- const handler = new jedLib.Jed(strings[lang] || strings['en']);
- return h(Context.Provider, { value: { lang, handler, changeLanguage }, children });
-}
+ });
+ const handler = new jedLib.Jed(strings[lang] || strings["en"]);
+ return h(Context.Provider, {
+ value: { lang, handler, changeLanguage },
+ children,
+ });
+};
-export const useTranslationContext = (): Type => useContext(Context); \ No newline at end of file
+export const useTranslationContext = (): Type => useContext(Context);
diff --git a/packages/anastasis-webui/src/declaration.d.ts b/packages/anastasis-webui/src/declaration.d.ts
index 2c4b7cb3a..00b3d41d5 100644
--- a/packages/anastasis-webui/src/declaration.d.ts
+++ b/packages/anastasis-webui/src/declaration.d.ts
@@ -1,20 +1,20 @@
declare module "*.css" {
- const mapping: Record<string, string>;
- export default mapping;
+ const mapping: Record<string, string>;
+ export default mapping;
}
-declare module '*.svg' {
- const content: any;
- export default content;
+declare module "*.svg" {
+ const content: any;
+ export default content;
}
-declare module '*.jpeg' {
- const content: any;
- export default content;
+declare module "*.jpeg" {
+ const content: any;
+ export default content;
}
-declare module '*.png' {
- const content: any;
- export default content;
+declare module "*.png" {
+ const content: any;
+ export default content;
}
-declare module 'jed' {
- const x: any;
- export = x;
+declare module "jed" {
+ const x: any;
+ export = x;
}
diff --git a/packages/anastasis-webui/src/hooks/async.ts b/packages/anastasis-webui/src/hooks/async.ts
index ea3ff6acf..0fc197554 100644
--- a/packages/anastasis-webui/src/hooks/async.ts
+++ b/packages/anastasis-webui/src/hooks/async.ts
@@ -15,9 +15,9 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { useState } from "preact/hooks";
// import { cancelPendingRequest } from "./backend";
@@ -34,36 +34,39 @@ export interface AsyncOperationApi<T> {
error: string | undefined;
}
-export function useAsync<T>(fn?: (...args: any) => Promise<T>, { slowTolerance: tooLong }: Options = { slowTolerance: 1000 }): AsyncOperationApi<T> {
+export function useAsync<T>(
+ fn?: (...args: any) => Promise<T>,
+ { slowTolerance: tooLong }: Options = { slowTolerance: 1000 },
+): AsyncOperationApi<T> {
const [data, setData] = useState<T | undefined>(undefined);
const [isLoading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<any>(undefined);
- const [isSlow, setSlow] = useState(false)
+ const [isSlow, setSlow] = useState(false);
const request = async (...args: any) => {
if (!fn) return;
setLoading(true);
const handler = setTimeout(() => {
- setSlow(true)
- }, tooLong)
+ setSlow(true);
+ }, tooLong);
try {
- console.log("calling async", args)
+ console.log("calling async", args);
const result = await fn(...args);
- console.log("async back", result)
+ console.log("async back", result);
setData(result);
} catch (error) {
setError(error);
}
setLoading(false);
- setSlow(false)
- clearTimeout(handler)
+ setSlow(false);
+ clearTimeout(handler);
};
function cancel() {
// cancelPendingRequest()
setLoading(false);
- setSlow(false)
+ setSlow(false);
}
return {
@@ -72,6 +75,6 @@ export function useAsync<T>(fn?: (...args: any) => Promise<T>, { slowTolerance:
data,
isSlow,
isLoading,
- error
+ error,
};
}
diff --git a/packages/anastasis-webui/src/hooks/index.ts b/packages/anastasis-webui/src/hooks/index.ts
index 15df4f154..9a1b50a11 100644
--- a/packages/anastasis-webui/src/hooks/index.ts
+++ b/packages/anastasis-webui/src/hooks/index.ts
@@ -15,81 +15,110 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { StateUpdater, useState } from "preact/hooks";
-export type ValueOrFunction<T> = T | ((p: T) => T)
-
+export type ValueOrFunction<T> = T | ((p: T) => T);
const calculateRootPath = () => {
- const rootPath = typeof window !== undefined ? window.location.origin + window.location.pathname : '/'
- return rootPath
-}
-
-export function useBackendURL(url?: string): [string, boolean, StateUpdater<string>, () => void] {
- const [value, setter] = useNotNullLocalStorage('backend-url', url || calculateRootPath())
- const [triedToLog, setTriedToLog] = useLocalStorage('tried-login')
+ const rootPath =
+ typeof window !== undefined
+ ? window.location.origin + window.location.pathname
+ : "/";
+ return rootPath;
+};
+
+export function useBackendURL(
+ url?: string,
+): [string, boolean, StateUpdater<string>, () => void] {
+ const [value, setter] = useNotNullLocalStorage(
+ "backend-url",
+ url || calculateRootPath(),
+ );
+ const [triedToLog, setTriedToLog] = useLocalStorage("tried-login");
const checkedSetter = (v: ValueOrFunction<string>) => {
- setTriedToLog('yes')
- return setter(p => (v instanceof Function ? v(p) : v).replace(/\/$/, ''))
- }
+ setTriedToLog("yes");
+ return setter((p) => (v instanceof Function ? v(p) : v).replace(/\/$/, ""));
+ };
const resetBackend = () => {
- setTriedToLog(undefined)
- }
- return [value, !!triedToLog, checkedSetter, resetBackend]
+ setTriedToLog(undefined);
+ };
+ return [value, !!triedToLog, checkedSetter, resetBackend];
}
-export function useBackendDefaultToken(): [string | undefined, StateUpdater<string | undefined>] {
- return useLocalStorage('backend-token')
+export function useBackendDefaultToken(): [
+ string | undefined,
+ StateUpdater<string | undefined>,
+] {
+ return useLocalStorage("backend-token");
}
-export function useBackendInstanceToken(id: string): [string | undefined, StateUpdater<string | undefined>] {
- const [token, setToken] = useLocalStorage(`backend-token-${id}`)
- const [defaultToken, defaultSetToken] = useBackendDefaultToken()
+export function useBackendInstanceToken(
+ id: string,
+): [string | undefined, StateUpdater<string | undefined>] {
+ const [token, setToken] = useLocalStorage(`backend-token-${id}`);
+ const [defaultToken, defaultSetToken] = useBackendDefaultToken();
// instance named 'default' use the default token
- if (id === 'default') {
- return [defaultToken, defaultSetToken]
+ if (id === "default") {
+ return [defaultToken, defaultSetToken];
}
- return [token, setToken]
+ return [token, setToken];
}
export function useLang(initial?: string): [string, StateUpdater<string>] {
- const browserLang = typeof window !== "undefined" ? navigator.language || (navigator as any).userLanguage : undefined;
- const defaultLang = (browserLang || initial || 'en').substring(0, 2)
- return useNotNullLocalStorage('lang-preference', defaultLang)
+ const browserLang =
+ typeof window !== "undefined"
+ ? navigator.language || (navigator as any).userLanguage
+ : undefined;
+ const defaultLang = (browserLang || initial || "en").substring(0, 2);
+ return useNotNullLocalStorage("lang-preference", defaultLang);
}
-export function useLocalStorage(key: string, initialValue?: string): [string | undefined, StateUpdater<string | undefined>] {
- const [storedValue, setStoredValue] = useState<string | undefined>((): string | undefined => {
- return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue;
+export function useLocalStorage(
+ key: string,
+ initialValue?: string,
+): [string | undefined, StateUpdater<string | undefined>] {
+ const [storedValue, setStoredValue] = useState<string | undefined>(():
+ | string
+ | undefined => {
+ return typeof window !== "undefined"
+ ? window.localStorage.getItem(key) || initialValue
+ : initialValue;
});
- const setValue = (value?: string | ((val?: string) => string | undefined)) => {
- setStoredValue(p => {
- const toStore = value instanceof Function ? value(p) : value
+ const setValue = (
+ value?: string | ((val?: string) => string | undefined),
+ ) => {
+ setStoredValue((p) => {
+ const toStore = value instanceof Function ? value(p) : value;
if (typeof window !== "undefined") {
if (!toStore) {
- window.localStorage.removeItem(key)
+ window.localStorage.removeItem(key);
} else {
window.localStorage.setItem(key, toStore);
}
}
- return toStore
- })
+ return toStore;
+ });
};
return [storedValue, setValue];
}
-export function useNotNullLocalStorage(key: string, initialValue: string): [string, StateUpdater<string>] {
+export function useNotNullLocalStorage(
+ key: string,
+ initialValue: string,
+): [string, StateUpdater<string>] {
const [storedValue, setStoredValue] = useState<string>((): string => {
- return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue;
+ return typeof window !== "undefined"
+ ? window.localStorage.getItem(key) || initialValue
+ : initialValue;
});
const setValue = (value: string | ((val: string) => string)) => {
@@ -97,7 +126,7 @@ export function useNotNullLocalStorage(key: string, initialValue: string): [stri
setStoredValue(valueToStore);
if (typeof window !== "undefined") {
if (!valueToStore) {
- window.localStorage.removeItem(key)
+ window.localStorage.removeItem(key);
} else {
window.localStorage.setItem(key, valueToStore);
}
@@ -106,5 +135,3 @@ export function useNotNullLocalStorage(key: string, initialValue: string): [stri
return [storedValue, setValue];
}
-
-
diff --git a/packages/anastasis-webui/src/i18n/index.tsx b/packages/anastasis-webui/src/i18n/index.tsx
index 63c8e1934..6e2c4e79a 100644
--- a/packages/anastasis-webui/src/i18n/index.tsx
+++ b/packages/anastasis-webui/src/i18n/index.tsx
@@ -27,23 +27,25 @@ import { useTranslationContext } from "../context/translation";
export function useTranslator() {
const ctx = useTranslationContext();
- const jed = ctx.handler
- return function str(stringSeq: TemplateStringsArray, ...values: any[]): string {
+ const jed = ctx.handler;
+ return function str(
+ stringSeq: TemplateStringsArray,
+ ...values: any[]
+ ): string {
const s = toI18nString(stringSeq);
- if (!s) return s
+ if (!s) return s;
const tr = jed
.translate(s)
.ifPlural(1, s)
.fetch(...values);
return tr;
- }
+ };
}
-
/**
* Convert template strings to a msgid
*/
- function toI18nString(stringSeq: ReadonlyArray<string>): string {
+function toI18nString(stringSeq: ReadonlyArray<string>): string {
let s = "";
for (let i = 0; i < stringSeq.length; i++) {
s += stringSeq[i];
@@ -54,7 +56,6 @@ export function useTranslator() {
return s;
}
-
interface TranslateSwitchProps {
target: number;
children: ComponentChildren;
@@ -110,7 +111,7 @@ function getTranslatedChildren(
// Text
result.push(tr[i]);
} else {
- const childIdx = Number.parseInt(tr[i],10) - 1;
+ const childIdx = Number.parseInt(tr[i], 10) - 1;
result.push(placeholderChildren[childIdx]);
}
}
@@ -131,9 +132,9 @@ function getTranslatedChildren(
*/
export function Translate({ children }: TranslateProps): VNode {
const s = stringifyChildren(children);
- const ctx = useTranslationContext()
+ const ctx = useTranslationContext();
const translation: string = ctx.handler.ngettext(s, s, 1);
- const result = getTranslatedChildren(translation, children)
+ const result = getTranslatedChildren(translation, children);
return <Fragment>{result}</Fragment>;
}
@@ -154,14 +155,16 @@ export function TranslateSwitch({ children, target }: TranslateSwitchProps) {
let plural: VNode<TranslationPluralProps> | undefined;
// const children = this.props.children;
if (children) {
- (children instanceof Array ? children : [children]).forEach((child: any) => {
- if (child.type === TranslatePlural) {
- plural = child;
- }
- if (child.type === TranslateSingular) {
- singular = child;
- }
- });
+ (children instanceof Array ? children : [children]).forEach(
+ (child: any) => {
+ if (child.type === TranslatePlural) {
+ plural = child;
+ }
+ if (child.type === TranslateSingular) {
+ singular = child;
+ }
+ },
+ );
}
if (!singular || !plural) {
console.error("translation not found");
@@ -182,9 +185,12 @@ interface TranslationPluralProps {
/**
* See [[TranslateSwitch]].
*/
-export function TranslatePlural({ children, target }: TranslationPluralProps): VNode {
+export function TranslatePlural({
+ children,
+ target,
+}: TranslationPluralProps): VNode {
const s = stringifyChildren(children);
- const ctx = useTranslationContext()
+ const ctx = useTranslationContext();
const translation = ctx.handler.ngettext(s, s, 1);
const result = getTranslatedChildren(translation, children);
return <Fragment>{result}</Fragment>;
@@ -193,11 +199,13 @@ export function TranslatePlural({ children, target }: TranslationPluralProps): V
/**
* See [[TranslateSwitch]].
*/
-export function TranslateSingular({ children, target }: TranslationPluralProps): VNode {
+export function TranslateSingular({
+ children,
+ target,
+}: TranslationPluralProps): VNode {
const s = stringifyChildren(children);
- const ctx = useTranslationContext()
+ const ctx = useTranslationContext();
const translation = ctx.handler.ngettext(s, s, target);
const result = getTranslatedChildren(translation, children);
return <Fragment>{result}</Fragment>;
-
}
diff --git a/packages/anastasis-webui/src/i18n/strings.ts b/packages/anastasis-webui/src/i18n/strings.ts
index b4f376ce0..d12e63e88 100644
--- a/packages/anastasis-webui/src/i18n/strings.ts
+++ b/packages/anastasis-webui/src/i18n/strings.ts
@@ -15,30 +15,30 @@
*/
/*eslint quote-props: ["error", "consistent"]*/
-export const strings: {[s: string]: any} = {};
+export const strings: { [s: string]: any } = {};
-strings['de'] = {
- "domain": "messages",
- "locale_data": {
- "messages": {
+strings["de"] = {
+ domain: "messages",
+ locale_data: {
+ messages: {
"": {
- "domain": "messages",
- "plural_forms": "nplurals=2; plural=(n != 1);",
- "lang": ""
+ domain: "messages",
+ plural_forms: "nplurals=2; plural=(n != 1);",
+ lang: "",
},
- }
- }
+ },
+ },
};
-strings['en'] = {
- "domain": "messages",
- "locale_data": {
- "messages": {
+strings["en"] = {
+ domain: "messages",
+ locale_data: {
+ messages: {
"": {
- "domain": "messages",
- "plural_forms": "nplurals=2; plural=(n != 1);",
- "lang": ""
+ domain: "messages",
+ plural_forms: "nplurals=2; plural=(n != 1);",
+ lang: "",
},
- }
- }
+ },
+ },
};
diff --git a/packages/anastasis-webui/src/index.ts b/packages/anastasis-webui/src/index.ts
index e78b9c194..4bd7b28f3 100644
--- a/packages/anastasis-webui/src/index.ts
+++ b/packages/anastasis-webui/src/index.ts
@@ -1,4 +1,4 @@
-import App from './components/app';
-import './scss/main.scss';
+import App from "./components/app";
+import "./scss/main.scss";
export default App;
diff --git a/packages/anastasis-webui/src/manifest.json b/packages/anastasis-webui/src/manifest.json
index 6b44a2b31..2752dad77 100644
--- a/packages/anastasis-webui/src/manifest.json
+++ b/packages/anastasis-webui/src/manifest.json
@@ -18,4 +18,4 @@
"sizes": "512x512"
}
]
-} \ No newline at end of file
+}
diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.stories.tsx
index 08e2b4371..9b067127d 100644
--- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.stories.tsx
@@ -15,24 +15,23 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { AddingProviderScreen as TestedComponent } from './AddingProviderScreen';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../utils";
+import { AddingProviderScreen as TestedComponent } from "./AddingProviderScreen";
export default {
- title: 'Pages/ManageProvider',
+ title: "Pages/ManageProvider",
component: TestedComponent,
args: {
order: 1,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
@@ -40,20 +39,31 @@ export const NewProvider = createExample(TestedComponent, {
...reducerStatesExample.authEditing,
} as ReducerState);
-
export const NewProviderWithoutProviderList = createExample(TestedComponent, {
...reducerStatesExample.authEditing,
- authentication_providers: {}
+ authentication_providers: {},
} as ReducerState);
-export const NewVideoProvider = createExample(TestedComponent, {
- ...reducerStatesExample.authEditing,
-} as ReducerState, { providerType: 'video'});
+export const NewVideoProvider = createExample(
+ TestedComponent,
+ {
+ ...reducerStatesExample.authEditing,
+ } as ReducerState,
+ { providerType: "video" },
+);
-export const NewSmsProvider = createExample(TestedComponent, {
- ...reducerStatesExample.authEditing,
-} as ReducerState, { providerType: 'sms'});
+export const NewSmsProvider = createExample(
+ TestedComponent,
+ {
+ ...reducerStatesExample.authEditing,
+ } as ReducerState,
+ { providerType: "sms" },
+);
-export const NewIBANProvider = createExample(TestedComponent, {
- ...reducerStatesExample.authEditing,
-} as ReducerState, { providerType: 'iban' });
+export const NewIBANProvider = createExample(
+ TestedComponent,
+ {
+ ...reducerStatesExample.authEditing,
+ } as ReducerState,
+ { providerType: "iban" },
+);
diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
index 7504f4d2b..96b38e92d 100644
--- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
@@ -11,185 +11,250 @@ interface Props {
onCancel: () => void;
}
-
-async function testProvider(url: string, expectedMethodType?: string): Promise<void> {
+async function testProvider(
+ url: string,
+ expectedMethodType?: string,
+): Promise<void> {
try {
- const response = await fetch(new URL("config", url).href)
- const json = await (response.json().catch(d => ({})))
+ const response = await fetch(new URL("config", url).href);
+ const json = await response.json().catch((d) => ({}));
if (!("methods" in json) || !Array.isArray(json.methods)) {
- throw Error("This provider doesn't have authentication method. Check the provider URL")
+ throw Error(
+ "This provider doesn't have authentication method. Check the provider URL",
+ );
}
- console.log("expected", expectedMethodType)
+ console.log("expected", expectedMethodType);
if (!expectedMethodType) {
- return
+ return;
}
- let found = false
+ let found = false;
for (let i = 0; i < json.methods.length && !found; i++) {
- found = json.methods[i].type === expectedMethodType
+ found = json.methods[i].type === expectedMethodType;
}
if (!found) {
- throw Error(`This provider does not support authentication method ${expectedMethodType}`)
+ throw Error(
+ `This provider does not support authentication method ${expectedMethodType}`,
+ );
}
- return
+ return;
} catch (e) {
- console.log("error", e)
- const error = e instanceof Error ?
- Error(`There was an error testing this provider, try another one. ${e.message}`) :
- Error(`There was an error testing this provider, try another one.`)
- throw error
+ console.log("error", e);
+ const error =
+ e instanceof Error
+ ? Error(
+ `There was an error testing this provider, try another one. ${e.message}`,
+ )
+ : Error(`There was an error testing this provider, try another one.`);
+ throw error;
}
-
}
export function AddingProviderScreen({ providerType, onCancel }: Props): VNode {
const reducer = useAnastasisContext();
const [providerURL, setProviderURL] = useState("");
- const [error, setError] = useState<string | undefined>()
- const [testing, setTesting] = useState(false)
- const providerLabel = providerType ? authMethods[providerType].label : undefined
+ const [error, setError] = useState<string | undefined>();
+ const [testing, setTesting] = useState(false);
+ const providerLabel = providerType
+ ? authMethods[providerType].label
+ : undefined;
//FIXME: move this timeout logic into a hook
const timeout = useRef<number | undefined>(undefined);
useEffect(() => {
- if (timeout) window.clearTimeout(timeout.current)
+ if (timeout) window.clearTimeout(timeout.current);
timeout.current = window.setTimeout(async () => {
- const url = providerURL.endsWith('/') ? providerURL : (providerURL + '/')
+ const url = providerURL.endsWith("/") ? providerURL : providerURL + "/";
if (!providerURL || authProviders.includes(url)) return;
try {
- setTesting(true)
- await testProvider(url, providerType)
+ setTesting(true);
+ await testProvider(url, providerType);
// this is use as tested but everything when ok
// undefined will mean that the field is not dirty
- setError("")
+ setError("");
} catch (e) {
- console.log("tuvieja", e)
- if (e instanceof Error) setError(e.message)
+ console.log("tuvieja", e);
+ if (e instanceof Error) setError(e.message);
}
- setTesting(false)
+ setTesting(false);
}, 200);
- }, [providerURL, reducer])
-
+ }, [providerURL, reducer]);
if (!reducer) {
return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || !("authentication_providers" in reducer.currentReducerState)) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ !("authentication_providers" in reducer.currentReducerState)
+ ) {
+ return <div>invalid state</div>;
}
async function addProvider(provider_url: string): Promise<void> {
- await reducer?.transition("add_provider", { provider_url })
- onCancel()
+ await reducer?.transition("add_provider", { provider_url });
+ onCancel();
}
function deleteProvider(provider_url: string): void {
- reducer?.transition("delete_provider", { provider_url })
+ reducer?.transition("delete_provider", { provider_url });
}
- const allAuthProviders = reducer.currentReducerState.authentication_providers || {}
- const authProviders = Object.keys(allAuthProviders).filter(provUrl => {
+ const allAuthProviders =
+ reducer.currentReducerState.authentication_providers || {};
+ const authProviders = Object.keys(allAuthProviders).filter((provUrl) => {
const p = allAuthProviders[provUrl];
if (!providerLabel) {
- return p && ("currency" in p)
+ return p && "currency" in p;
} else {
- return p && ("currency" in p) && p.methods.findIndex(m => m.type === providerType) !== -1
+ return (
+ p &&
+ "currency" in p &&
+ p.methods.findIndex((m) => m.type === providerType) !== -1
+ );
}
- })
+ });
- let errors = !providerURL ? 'Add provider URL' : undefined
+ let errors = !providerURL ? "Add provider URL" : undefined;
let url: string | undefined;
try {
- url = new URL("",providerURL).href
+ url = new URL("", providerURL).href;
} catch {
- errors = 'Check the URL'
+ errors = "Check the URL";
}
if (!!error && !errors) {
- errors = error
+ errors = error;
}
if (!errors && authProviders.includes(url!)) {
- errors = 'That provider is already known'
+ errors = "That provider is already known";
}
return (
- <AnastasisClientFrame hideNav
+ <AnastasisClientFrame
+ hideNav
title="Backup: Manage providers"
- hideNext={errors}>
+ hideNext={errors}
+ >
<div>
- {!providerLabel ?
- <p>
- Add a provider url
- </p> :
- <p>
- Add a provider url for a {providerLabel} service
- </p>
- }
+ {!providerLabel ? (
+ <p>Add a provider url</p>
+ ) : (
+ <p>Add a provider url for a {providerLabel} service</p>
+ )}
<div class="container">
<TextInput
label="Provider URL"
placeholder="https://provider.com"
grabFocus
error={errors}
- bind={[providerURL, setProviderURL]} />
+ bind={[providerURL, setProviderURL]}
+ />
</div>
- <p class="block">
- Example: https://kudos.demo.anastasis.lu
- </p>
+ <p class="block">Example: https://kudos.demo.anastasis.lu</p>
{testing && <p class="has-text-info">Testing</p>}
-
- <div class="block" style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={onCancel}>Cancel</button>
+
+ <div
+ class="block"
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={onCancel}>
+ Cancel
+ </button>
<span data-tooltip={errors}>
- <button class="button is-info" disabled={error !== "" || testing} onClick={() => addProvider(url!)}>Add</button>
+ <button
+ class="button is-info"
+ disabled={error !== "" || testing}
+ onClick={() => addProvider(url!)}
+ >
+ Add
+ </button>
</span>
</div>
{authProviders.length > 0 ? (
- !providerLabel ?
+ !providerLabel ? (
+ <p class="subtitle">Current providers</p>
+ ) : (
<p class="subtitle">
- Current providers
- </p> : <p class="subtitle">
Current providers for {providerLabel} service
</p>
+ )
+ ) : !providerLabel ? (
+ <p class="subtitle">No known providers, add one.</p>
) : (
- !providerLabel ? <p class="subtitle">
- No known providers, add one.
- </p> : <p class="subtitle">
- No known providers for {providerLabel} service
- </p>
+ <p class="subtitle">No known providers for {providerLabel} service</p>
)}
- {authProviders.map(k => {
- const p = allAuthProviders[k] as AuthenticationProviderStatusOk
- return <TableRow url={k} info={p} onDelete={deleteProvider} />
+ {authProviders.map((k) => {
+ const p = allAuthProviders[k] as AuthenticationProviderStatusOk;
+ return <TableRow url={k} info={p} onDelete={deleteProvider} />;
})}
</div>
</AnastasisClientFrame>
);
}
-function TableRow({ url, info, onDelete }: { onDelete: (s: string) => void, url: string, info: AuthenticationProviderStatusOk }) {
- const [status, setStatus] = useState("checking")
+function TableRow({
+ url,
+ info,
+ onDelete,
+}: {
+ onDelete: (s: string) => void;
+ url: string;
+ info: AuthenticationProviderStatusOk;
+}) {
+ const [status, setStatus] = useState("checking");
useEffect(function () {
- testProvider(url.endsWith('/') ? url.substring(0, url.length - 1) : url)
- .then(function () { setStatus('responding') })
- .catch(function () { setStatus('failed to contact') })
- })
- return <div class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
- <div>
- <div class="subtitle">{url}</div>
- <dl>
- <dt><b>Business Name</b></dt>
- <dd>{info.business_name}</dd>
- <dt><b>Supported methods</b></dt>
- <dd>{info.methods.map(m => m.type).join(',')}</dd>
- <dt><b>Maximum storage</b></dt>
- <dd>{info.storage_limit_in_megabytes} Mb</dd>
- <dt><b>Status</b></dt>
- <dd>{status}</dd>
- </dl>
- </div>
- <div class="block" style={{ marginTop: 'auto', marginBottom: 'auto', display: 'flex', justifyContent: 'space-between', flexDirection: 'column' }}>
- <button class="button is-danger" onClick={() => onDelete(url)}>Remove</button>
+ testProvider(url.endsWith("/") ? url.substring(0, url.length - 1) : url)
+ .then(function () {
+ setStatus("responding");
+ })
+ .catch(function () {
+ setStatus("failed to contact");
+ });
+ });
+ return (
+ <div
+ class="box"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
+ <div>
+ <div class="subtitle">{url}</div>
+ <dl>
+ <dt>
+ <b>Business Name</b>
+ </dt>
+ <dd>{info.business_name}</dd>
+ <dt>
+ <b>Supported methods</b>
+ </dt>
+ <dd>{info.methods.map((m) => m.type).join(",")}</dd>
+ <dt>
+ <b>Maximum storage</b>
+ </dt>
+ <dd>{info.storage_limit_in_megabytes} Mb</dd>
+ <dt>
+ <b>Status</b>
+ </dt>
+ <dd>{status}</dd>
+ </dl>
+ </div>
+ <div
+ class="block"
+ style={{
+ marginTop: "auto",
+ marginBottom: "auto",
+ display: "flex",
+ justifyContent: "space-between",
+ flexDirection: "column",
+ }}
+ >
+ <button class="button is-danger" onClick={() => onDelete(url)}>
+ Remove
+ </button>
+ </div>
</div>
- </div>
-} \ No newline at end of file
+ );
+}
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx
index 9cdd132ef..d48e94403 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx
@@ -15,76 +15,83 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { AttributeEntryScreen as TestedComponent } from './AttributeEntryScreen';
+ *
+ * @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/PersonalInformation',
+ title: "Pages/PersonalInformation",
component: TestedComponent,
args: {
order: 3,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
export const Backup = createExample(TestedComponent, {
...reducerStatesExample.backupAttributeEditing,
- required_attributes: [{
- name: 'first name',
- label: 'first',
- type: 'string',
- uuid: 'asdasdsa1',
- widget: 'wid',
- }, {
- name: 'last name',
- label: 'second',
- type: 'string',
- uuid: 'asdasdsa2',
- widget: 'wid',
- }, {
- name: 'birthdate',
- label: 'birthdate',
- type: 'date',
- uuid: 'asdasdsa3',
- widget: 'calendar',
- }]
+ required_attributes: [
+ {
+ name: "first name",
+ label: "first",
+ type: "string",
+ uuid: "asdasdsa1",
+ widget: "wid",
+ },
+ {
+ name: "last name",
+ label: "second",
+ type: "string",
+ uuid: "asdasdsa2",
+ widget: "wid",
+ },
+ {
+ name: "birthdate",
+ label: "birthdate",
+ type: "date",
+ uuid: "asdasdsa3",
+ widget: "calendar",
+ },
+ ],
} as ReducerState);
export const Recovery = createExample(TestedComponent, {
...reducerStatesExample.recoveryAttributeEditing,
- required_attributes: [{
- name: 'first',
- label: 'first',
- type: 'string',
- uuid: 'asdasdsa1',
- widget: 'wid',
- }, {
- name: 'pepe',
- label: 'second',
- type: 'string',
- uuid: 'asdasdsa2',
- widget: 'wid',
- }, {
- name: 'pepe2',
- label: 'third',
- type: 'date',
- uuid: 'asdasdsa3',
- widget: 'calendar',
- }]
+ required_attributes: [
+ {
+ name: "first",
+ label: "first",
+ type: "string",
+ uuid: "asdasdsa1",
+ widget: "wid",
+ },
+ {
+ name: "pepe",
+ label: "second",
+ type: "string",
+ uuid: "asdasdsa2",
+ widget: "wid",
+ },
+ {
+ name: "pepe2",
+ label: "third",
+ type: "date",
+ uuid: "asdasdsa3",
+ widget: "calendar",
+ },
+ ],
} as ReducerState);
export const WithNoRequiredAttribute = createExample(TestedComponent, {
...reducerStatesExample.backupAttributeEditing,
- required_attributes: undefined
+ required_attributes: undefined,
} as ReducerState);
const allWidgets = [
@@ -107,23 +114,22 @@ const allWidgets = [
"anastasis_gtk_ia_tax_de",
"anastasis_gtk_xx_prime",
"anastasis_gtk_xx_square",
-]
+];
function typeForWidget(name: string): string {
- if (["anastasis_gtk_xx_prime",
- "anastasis_gtk_xx_square",
- ].includes(name)) return "number";
- if (["anastasis_gtk_ia_birthdate"].includes(name)) return "date"
+ if (["anastasis_gtk_xx_prime", "anastasis_gtk_xx_square"].includes(name))
+ return "number";
+ if (["anastasis_gtk_ia_birthdate"].includes(name)) return "date";
return "string";
}
export const WithAllPosibleWidget = createExample(TestedComponent, {
...reducerStatesExample.backupAttributeEditing,
- required_attributes: allWidgets.map(w => ({
+ required_attributes: allWidgets.map((w) => ({
name: w,
label: `widget: ${w}`,
type: typeForWidget(w),
uuid: `uuid-${w}`,
- widget: w
- }))
+ widget: w,
+ })),
} as ReducerState);
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
index 557718458..0918c2db5 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
@@ -9,24 +9,32 @@ import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame, withProcessLabel } from "./index";
export function AttributeEntryScreen(): VNode {
- const reducer = useAnastasisContext()
- const state = reducer?.currentReducerState
- const currentIdentityAttributes = state && "identity_attributes" in state ? (state.identity_attributes || {}) : {}
- const [attrs, setAttrs] = useState<Record<string, string>>(currentIdentityAttributes);
+ const reducer = useAnastasisContext();
+ const state = reducer?.currentReducerState;
+ 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>
+ return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || !("required_attributes" in reducer.currentReducerState)) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ !("required_attributes" in reducer.currentReducerState)
+ ) {
+ return <div>invalid state</div>;
}
- const reqAttr = reducer.currentReducerState.required_attributes || []
+ const reqAttr = reducer.currentReducerState.required_attributes || [];
let hasErrors = false;
const fieldList: VNode[] = reqAttr.map((spec, i: number) => {
- const value = attrs[spec.name]
- const error = checkIfValid(value, spec)
- hasErrors = hasErrors || error !== undefined
+ const value = attrs[spec.name];
+ const error = checkIfValid(value, spec);
+ hasErrors = hasErrors || error !== undefined;
return (
<AttributeEntryField
key={i}
@@ -34,23 +42,24 @@ export function AttributeEntryScreen(): VNode {
setValue={(v: string) => setAttrs({ ...attrs, [spec.name]: v })}
spec={spec}
errorMessage={error}
- value={value} />
+ value={value}
+ />
);
- })
+ });
return (
<AnastasisClientFrame
title={withProcessLabel(reducer, "Who are you?")}
hideNext={hasErrors ? "Complete the form." : undefined}
- onNext={() => reducer.transition("enter_user_attributes", {
- identity_attributes: attrs,
- })}
+ onNext={() =>
+ reducer.transition("enter_user_attributes", {
+ identity_attributes: attrs,
+ })
+ }
>
- <div class="columns" style={{ maxWidth: 'unset' }}>
+ <div class="columns" style={{ maxWidth: "unset" }}>
+ <div class="column">{fieldList}</div>
<div class="column">
- {fieldList}
- </div>
- <div class="column" >
<p>This personal information will help to locate your secret.</p>
<h1 class="title">This stays private</h1>
<p>The information you have entered here:</p>
@@ -61,9 +70,12 @@ export function AttributeEntryScreen(): VNode {
</span>
Will be hashed, and therefore unreadable
</li>
- <li><span class="icon is-right">
- <i class="mdi mdi-circle-small" />
- </span>The non-hashed version is not shared</li>
+ <li>
+ <span class="icon is-right">
+ <i class="mdi mdi-circle-small" />
+ </span>
+ The non-hashed version is not shared
+ </li>
</ul>
</div>
</div>
@@ -78,22 +90,22 @@ interface AttributeEntryFieldProps {
spec: UserAttributeSpec;
errorMessage: string | undefined;
}
-const possibleBirthdayYear: Array<number> = []
+const possibleBirthdayYear: Array<number> = [];
for (let i = 0; i < 100; i++) {
- possibleBirthdayYear.push(2020 - i)
+ possibleBirthdayYear.push(2020 - i);
}
function AttributeEntryField(props: AttributeEntryFieldProps): VNode {
-
return (
<div>
- {props.spec.type === 'date' &&
+ {props.spec.type === "date" &&
<DateInput
grabFocus={props.isFirst}
label={props.spec.label}
years={possibleBirthdayYear}
error={props.errorMessage}
bind={[props.value, props.setValue]}
- />}
+ />
+ }
{props.spec.type === 'number' &&
<PhoneNumberInput
grabFocus={props.isFirst}
@@ -102,14 +114,14 @@ function AttributeEntryField(props: AttributeEntryFieldProps): VNode {
bind={[props.value, props.setValue]}
/>
}
- {props.spec.type === 'string' &&
+ {props.spec.type === "string" && (
<TextInput
grabFocus={props.isFirst}
label={props.spec.label}
error={props.errorMessage}
bind={[props.value, props.setValue]}
/>
- }
+ )}
<div class="block">
This stays private
<span class="icon is-right">
@@ -119,40 +131,43 @@ function AttributeEntryField(props: AttributeEntryFieldProps): VNode {
</div>
);
}
-const YEAR_REGEX = /^[0-9]+-[0-9]+-[0-9]+$/
-
+const YEAR_REGEX = /^[0-9]+-[0-9]+-[0-9]+$/;
-function checkIfValid(value: string, spec: UserAttributeSpec): string | undefined {
- const pattern = spec['validation-regex']
+function checkIfValid(
+ value: string,
+ spec: UserAttributeSpec,
+): string | undefined {
+ const pattern = spec["validation-regex"];
if (pattern) {
- const re = new RegExp(pattern)
- if (!re.test(value)) return 'The value is invalid'
+ const re = new RegExp(pattern);
+ if (!re.test(value)) return "The value is invalid";
}
- const logic = spec['validation-logic']
+ const logic = spec["validation-logic"];
if (logic) {
const func = (validators as any)[logic];
- if (func && typeof func === 'function' && !func(value)) return 'Please check the value'
+ if (func && typeof func === "function" && !func(value))
+ return "Please check the value";
}
- const optional = spec.optional
+ const optional = spec.optional;
if (!optional && !value) {
- return 'This value is required'
+ return "This value is required";
}
if ("date" === spec.type) {
if (!YEAR_REGEX.test(value)) {
- return "The date doesn't follow the format"
+ return "The date doesn't follow the format";
}
try {
- const v = parse(value, 'yyyy-MM-dd', new Date());
+ const v = parse(value, "yyyy-MM-dd", new Date());
if (Number.isNaN(v.getTime())) {
- return "Some numeric values seems out of range for a date"
+ return "Some numeric values seems out of range for a date";
}
if ("birthdate" === spec.name && isAfter(v, new Date())) {
- return "A birthdate cannot be in the future"
+ return "A birthdate cannot be in the future";
}
} catch (e) {
- return "Could not parse the date"
+ return "Could not parse the date";
}
}
- return undefined
+ return undefined;
}
diff --git a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.stories.tsx
index 2712522ce..8acf1c8c8 100644
--- a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.stories.tsx
@@ -15,73 +15,84 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { AuthenticationEditorScreen as TestedComponent } from './AuthenticationEditorScreen';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../utils";
+import { AuthenticationEditorScreen as TestedComponent } from "./AuthenticationEditorScreen";
export default {
- title: 'Pages/backup/AuthorizationMethod',
+ title: "Pages/backup/AuthorizationMethod",
component: TestedComponent,
args: {
order: 4,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-export const InitialState = createExample(TestedComponent, reducerStatesExample.authEditing);
+export const InitialState = createExample(
+ TestedComponent,
+ reducerStatesExample.authEditing,
+);
export const OneAuthMethodConfigured = createExample(TestedComponent, {
...reducerStatesExample.authEditing,
- authentication_methods: [{
- type: 'question',
- instructions: 'what time is it?',
- challenge: 'asd',
- }]
+ authentication_methods: [
+ {
+ type: "question",
+ instructions: "what time is it?",
+ challenge: "asd",
+ },
+ ],
} as ReducerState);
-
export const SomeMoreAuthMethodConfigured = createExample(TestedComponent, {
...reducerStatesExample.authEditing,
- authentication_methods: [{
- type: 'question',
- instructions: 'what time is it?',
- challenge: 'asd',
- },{
- type: 'question',
- instructions: 'what time is it?',
- challenge: 'qwe',
- },{
- type: 'sms',
- instructions: 'what time is it?',
- challenge: 'asd',
- },{
- type: 'email',
- instructions: 'what time is it?',
- challenge: 'asd',
- },{
- type: 'email',
- instructions: 'what time is it?',
- challenge: 'asd',
- },{
- type: 'email',
- instructions: 'what time is it?',
- challenge: 'asd',
- },{
- type: 'email',
- instructions: 'what time is it?',
- challenge: 'asd',
- }]
+ authentication_methods: [
+ {
+ type: "question",
+ instructions: "what time is it?",
+ challenge: "asd",
+ },
+ {
+ type: "question",
+ instructions: "what time is it?",
+ challenge: "qwe",
+ },
+ {
+ type: "sms",
+ instructions: "what time is it?",
+ challenge: "asd",
+ },
+ {
+ type: "email",
+ instructions: "what time is it?",
+ challenge: "asd",
+ },
+ {
+ type: "email",
+ instructions: "what time is it?",
+ challenge: "asd",
+ },
+ {
+ type: "email",
+ instructions: "what time is it?",
+ challenge: "asd",
+ },
+ {
+ type: "email",
+ instructions: "what time is it?",
+ challenge: "asd",
+ },
+ ],
} as ReducerState);
export const NoAuthMethodProvided = createExample(TestedComponent, {
...reducerStatesExample.authEditing,
authentication_providers: {},
- authentication_methods: []
+ authentication_methods: [],
} as ReducerState);
diff --git a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
index 00eb54d4d..1ef326773 100644
--- a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
@@ -20,7 +20,9 @@ export function AuthenticationEditorScreen(): VNode {
KnownAuthMethods | undefined
>(undefined);
const [tooFewAuths, setTooFewAuths] = useState(false);
- const [manageProvider, setManageProvider] = useState<string | undefined>(undefined)
+ const [manageProvider, setManageProvider] = useState<string | undefined>(
+ undefined,
+ );
// const [addingProvider, setAddingProvider] = useState<string | undefined>(undefined)
const reducer = useAnastasisContext();
@@ -68,11 +70,14 @@ export function AuthenticationEditorScreen(): VNode {
}
if (manageProvider !== undefined) {
-
- return <AddingProviderScreen
- onCancel={() => setManageProvider(undefined)}
- providerType={isKnownAuthMethods(manageProvider) ? manageProvider : undefined}
- />
+ return (
+ <AddingProviderScreen
+ onCancel={() => setManageProvider(undefined)}
+ providerType={
+ isKnownAuthMethods(manageProvider) ? manageProvider : undefined
+ }
+ />
+ );
}
if (selectedMethod) {
@@ -100,7 +105,7 @@ export function AuthenticationEditorScreen(): VNode {
description="No providers founds"
label="Add a provider manually"
onConfirm={() => {
- setManageProvider(selectedMethod)
+ setManageProvider(selectedMethod);
}}
>
<p>
@@ -193,7 +198,7 @@ export function AuthenticationEditorScreen(): VNode {
description="No providers founds"
label="Add a provider manually"
onConfirm={() => {
- setManageProvider("")
+ setManageProvider("");
}}
>
<p>
@@ -214,7 +219,10 @@ export function AuthenticationEditorScreen(): VNode {
authentication method is defined by the backup provider list.
</p>
<p class="block">
- <button class="button is-info" onClick={() => setManageProvider("")}>
+ <button
+ class="button is-info"
+ onClick={() => setManageProvider("")}
+ >
Manage backup providers
</button>
</p>
diff --git a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.stories.tsx
index 306adacbb..0789ee6ad 100644
--- a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.stories.tsx
@@ -15,48 +15,51 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { BackupFinishedScreen as TestedComponent } from './BackupFinishedScreen';
+ *
+ * @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/backup/Finished',
+ title: "Pages/backup/Finished",
component: TestedComponent,
args: {
order: 8,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-export const WithoutName = createExample(TestedComponent, reducerStatesExample.backupFinished);
+export const WithoutName = createExample(
+ TestedComponent,
+ reducerStatesExample.backupFinished,
+);
-export const WithName = createExample(TestedComponent, {...reducerStatesExample.backupFinished,
- secret_name: 'super_secret',
+export const WithName = createExample(TestedComponent, {
+ ...reducerStatesExample.backupFinished,
+ secret_name: "super_secret",
} as ReducerState);
export const WithDetails = createExample(TestedComponent, {
...reducerStatesExample.backupFinished,
- secret_name: 'super_secret',
+ secret_name: "super_secret",
success_details: {
- 'http://anastasis.net': {
+ "http://anastasis.net": {
policy_expiration: {
- t_ms: 'never'
+ t_ms: "never",
},
- policy_version: 0
+ policy_version: 0,
},
- 'http://taler.net': {
+ "http://taler.net": {
policy_expiration: {
- t_ms: new Date().getTime() + 60*60*24*1000
+ t_ms: new Date().getTime() + 60 * 60 * 24 * 1000,
},
- policy_version: 1
+ policy_version: 1,
},
- }
+ },
} as ReducerState);
diff --git a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx
index 7938baca4..825ec5dc0 100644
--- a/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/BackupFinishedScreen.tsx
@@ -4,41 +4,62 @@ import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame } from "./index";
export function BackupFinishedScreen(): VNode {
- const reducer = useAnastasisContext()
+ const reducer = useAnastasisContext();
if (!reducer) {
- return <div>no reducer in context</div>
+ return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ reducer.currentReducerState.backup_state === undefined
+ ) {
+ return <div>invalid state</div>;
}
- const details = reducer.currentReducerState.success_details
+ const details = reducer.currentReducerState.success_details;
- return (<AnastasisClientFrame hideNav title="Backup finished">
- {reducer.currentReducerState.secret_name ? <p>
- Your backup of secret <b>"{reducer.currentReducerState.secret_name}"</b> was
- successful.
- </p> :
- <p>
- Your secret was successfully backed up.
- </p>}
+ return (
+ <AnastasisClientFrame hideNav title="Backup finished">
+ {reducer.currentReducerState.secret_name ? (
+ <p>
+ Your backup of secret{" "}
+ <b>"{reducer.currentReducerState.secret_name}"</b> was successful.
+ </p>
+ ) : (
+ <p>Your secret was successfully backed up.</p>
+ )}
- {details && <div class="block">
- <p>The backup is stored by the following providers:</p>
- {Object.keys(details).map((x, i) => {
- const sd = details[x];
- return (
- <div key={i} class="box">
- {x}
- <p>
- version {sd.policy_version}
- {sd.policy_expiration.t_ms !== 'never' ? ` expires at: ${format(sd.policy_expiration.t_ms, 'dd-MM-yyyy')}` : ' without expiration date'}
- </p>
- </div>
- );
- })}
- </div>}
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
- </div>
- </AnastasisClientFrame>);
+ {details && (
+ <div class="block">
+ <p>The backup is stored by the following providers:</p>
+ {Object.keys(details).map((x, i) => {
+ const sd = details[x];
+ return (
+ <div key={i} class="box">
+ {x}
+ <p>
+ version {sd.policy_version}
+ {sd.policy_expiration.t_ms !== "never"
+ ? ` expires at: ${format(
+ sd.policy_expiration.t_ms,
+ "dd-MM-yyyy",
+ )}`
+ : " without expiration date"}
+ </p>
+ </div>
+ );
+ })}
+ </div>
+ )}
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
+ </div>
+ </AnastasisClientFrame>
+ );
}
diff --git a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx
index 46c574cf2..56aee8763 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.stories.tsx
@@ -19,7 +19,11 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { ChallengeFeedbackStatus, RecoveryStates, ReducerState } from "anastasis-core";
+import {
+ ChallengeFeedbackStatus,
+ RecoveryStates,
+ ReducerState,
+} from "anastasis-core";
import { createExample, reducerStatesExample } from "../../utils";
import { ChallengeOverviewScreen as TestedComponent } from "./ChallengeOverviewScreen";
@@ -247,20 +251,20 @@ export const OnePolicyWithAllTheChallengesInDifferentState = createExample(
"uuid-1": { state: ChallengeFeedbackStatus.Solved.toString() },
"uuid-2": {
state: ChallengeFeedbackStatus.Message.toString(),
- message: 'Challenge should be solved'
+ message: "Challenge should be solved",
},
"uuid-3": {
state: ChallengeFeedbackStatus.AuthIban.toString(),
challenge_amount: "EUR:1",
credit_iban: "DE12345789000",
business_name: "Data Loss Incorporated",
- wire_transfer_subject: "Anastasis 987654321"
+ wire_transfer_subject: "Anastasis 987654321",
},
"uuid-4": {
state: ChallengeFeedbackStatus.Payment.toString(),
taler_pay_uri: "taler://pay/...",
provider: "https://localhost:8080/",
- payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
+ payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG",
},
"uuid-5": {
state: ChallengeFeedbackStatus.RateLimitExceeded.toString(),
@@ -269,7 +273,7 @@ export const OnePolicyWithAllTheChallengesInDifferentState = createExample(
"uuid-6": {
state: ChallengeFeedbackStatus.Redirect.toString(),
redirect_url: "https://videoconf.example.com/",
- http_status: 303
+ http_status: 303,
},
"uuid-7": {
state: ChallengeFeedbackStatus.ServerFailure.toString(),
diff --git a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
index ae03dd4d4..c6de00e98 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
@@ -11,23 +11,34 @@ function OverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
}
switch (feedback.state) {
case ChallengeFeedbackStatus.Message:
- return (
- <div class="block has-text-danger">{feedback.message}</div>
- );
+ return <div class="block has-text-danger">{feedback.message}</div>;
case ChallengeFeedbackStatus.Solved:
- return <div />
+ return <div />;
case ChallengeFeedbackStatus.Pending:
- case ChallengeFeedbackStatus.Solved:
case ChallengeFeedbackStatus.AuthIban:
return null;
case ChallengeFeedbackStatus.ServerFailure:
return <div class="block has-text-danger">Server error.</div>;
case ChallengeFeedbackStatus.RateLimitExceeded:
- return <div class="block has-text-danger">There were to many failed attempts.</div>;
+ return (
+ <div class="block has-text-danger">
+ There were to many failed attempts.
+ </div>
+ );
case ChallengeFeedbackStatus.Unsupported:
- return <div class="block has-text-danger">This client doesn't support solving this type of challenge. Use another version or contact the provider.</div>;
+ return (
+ <div class="block has-text-danger">
+ This client doesn't support solving this type of challenge. Use
+ another version or contact the provider.
+ </div>
+ );
case ChallengeFeedbackStatus.TruthUnknown:
- return <div class="block has-text-danger">Provider doesn't recognize the challenge of the policy. Contact the provider for further information.</div>;
+ return (
+ <div class="block has-text-danger">
+ Provider doesn't recognize the challenge of the policy. Contact the
+ provider for further information.
+ </div>
+ );
case ChallengeFeedbackStatus.Redirect:
default:
return <div />;
@@ -70,19 +81,25 @@ export function ChallengeOverviewScreen(): VNode {
feedback: challengeFeedback[ch.uuid],
};
}
- const policiesWithInfo = policies.map((row) => {
- let isPolicySolved = true;
- const challenges = row
- .map(({ uuid }) => {
- const info = knownChallengesMap[uuid];
- const isChallengeSolved = info?.feedback?.state === "solved";
- isPolicySolved = isPolicySolved && isChallengeSolved;
- return { info, uuid, isChallengeSolved };
- })
- .filter((ch) => ch.info !== undefined);
+ const policiesWithInfo = policies
+ .map((row) => {
+ let isPolicySolved = true;
+ const challenges = row
+ .map(({ uuid }) => {
+ const info = knownChallengesMap[uuid];
+ const isChallengeSolved = info?.feedback?.state === "solved";
+ isPolicySolved = isPolicySolved && isChallengeSolved;
+ return { info, uuid, isChallengeSolved };
+ })
+ .filter((ch) => ch.info !== undefined);
- return { isPolicySolved, challenges };
- });
+ return {
+ isPolicySolved,
+ challenges,
+ corrupted: row.length > challenges.length,
+ };
+ })
+ .filter((p) => !p.corrupted);
const atLeastThereIsOnePolicySolved =
policiesWithInfo.find((p) => p.isPolicySolved) !== undefined;
@@ -92,19 +109,19 @@ export function ChallengeOverviewScreen(): VNode {
: undefined;
return (
<AnastasisClientFrame hideNext={errors} title="Recovery: Solve challenges">
- {!policies.length ? (
+ {!policiesWithInfo.length ? (
<p class="block">
No policies found, try with another version of the secret
</p>
- ) : policies.length === 1 ? (
+ ) : policiesWithInfo.length === 1 ? (
<p class="block">
One policy found for this secret. You need to solve all the challenges
in order to recover your secret.
</p>
) : (
<p class="block">
- We have found {policies.length} polices. You need to solve all the
- challenges from one policy in order to recover your secret.
+ We have found {policiesWithInfo.length} polices. You need to solve all
+ the challenges from one policy in order to recover your secret.
</p>
)}
{policiesWithInfo.map((policy, policy_index) => {
@@ -113,74 +130,100 @@ export function ChallengeOverviewScreen(): VNode {
const method = authMethods[info.type as KnownAuthMethods];
if (!method) {
- return <div
- key={uuid}
- class="block"
- style={{ display: "flex", justifyContent: "space-between" }}
- >
- <div style={{ display: "flex", alignItems: "center" }}>
- <span>unknown challenge</span>
+ return (
+ <div
+ key={uuid}
+ class="block"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
+ <div style={{ display: "flex", alignItems: "center" }}>
+ <span>unknown challenge</span>
+ </div>
</div>
-
- </div>
+ );
}
- function ChallengeButton({ id, feedback }: { id: string; feedback?: ChallengeFeedback }): VNode {
+ function ChallengeButton({
+ id,
+ feedback,
+ }: {
+ id: string;
+ feedback?: ChallengeFeedback;
+ }): VNode {
function selectChallenge(): void {
- if (reducer) reducer.transition("select_challenge", { uuid: id })
+ if (reducer) reducer.transition("select_challenge", { uuid: id });
}
if (!feedback) {
- return <div>
- <button class="button" onClick={selectChallenge}>
- Solve
- </button>
- </div>
+ return (
+ <div>
+ <button
+ class="button"
+ disabled={
+ atLeastThereIsOnePolicySolved && !policy.isPolicySolved
+ }
+ onClick={selectChallenge}
+ >
+ Solve
+ </button>
+ </div>
+ );
}
switch (feedback.state) {
case ChallengeFeedbackStatus.ServerFailure:
case ChallengeFeedbackStatus.Unsupported:
case ChallengeFeedbackStatus.TruthUnknown:
- case ChallengeFeedbackStatus.RateLimitExceeded: return <div />
+ case ChallengeFeedbackStatus.RateLimitExceeded:
+ return <div />;
case ChallengeFeedbackStatus.AuthIban:
- case ChallengeFeedbackStatus.Payment: return <div>
- <button class="button" onClick={selectChallenge}>
- Pay
- </button>
- </div>
- case ChallengeFeedbackStatus.Redirect: return <div>
- <button class="button" onClick={selectChallenge}>
- Go to {feedback.redirect_url}
- </button>
- </div>
- case ChallengeFeedbackStatus.Solved: return <div>
- <div class="tag is-success is-large">
- Solved
- </div>
- </div>
- default: return <div>
- <button class="button" onClick={selectChallenge}>
- Solve
- </button>
- </div>
-
+ case ChallengeFeedbackStatus.Payment:
+ return (
+ <div>
+ <button
+ class="button"
+ disabled={
+ atLeastThereIsOnePolicySolved && !policy.isPolicySolved
+ }
+ onClick={selectChallenge}
+ >
+ Pay
+ </button>
+ </div>
+ );
+ case ChallengeFeedbackStatus.Redirect:
+ return (
+ <div>
+ <button
+ class="button"
+ disabled={
+ atLeastThereIsOnePolicySolved && !policy.isPolicySolved
+ }
+ onClick={selectChallenge}
+ >
+ Go to {feedback.redirect_url}
+ </button>
+ </div>
+ );
+ case ChallengeFeedbackStatus.Solved:
+ return (
+ <div>
+ <div class="tag is-success is-large">Solved</div>
+ </div>
+ );
+ default:
+ return (
+ <div>
+ <button
+ class="button"
+ disabled={
+ atLeastThereIsOnePolicySolved && !policy.isPolicySolved
+ }
+ onClick={selectChallenge}
+ >
+ Solve
+ </button>
+ </div>
+ );
}
- // return <div>
- // {feedback.state !== "solved" ? (
- // <a
- // class="button"
- // onClick={() =>
-
- // }
- // >
- // {isFree ? "Solve" : `Pay and Solve`}
- // </a>
- // ) : null}
- // {feedback.state === "solved" ? (
- // // <div class="block is-success" > Solved </div>
- // <div class="tag is-success is-large">Solved</div>
-
- // ) : null}
- // </div>
}
return (
<div
@@ -202,7 +245,6 @@ export function ChallengeOverviewScreen(): VNode {
</div>
<ChallengeButton id={uuid} feedback={info.feedback} />
-
</div>
);
});
@@ -210,11 +252,13 @@ export function ChallengeOverviewScreen(): VNode {
const policyName = policy.challenges
.map((x) => x.info.type)
.join(" + ");
+
const opa = !atLeastThereIsOnePolicySolved
? undefined
: policy.isPolicySolved
- ? undefined
- : "0.6";
+ ? undefined
+ : "0.6";
+
return (
<div
key={policy_index}
diff --git a/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.stories.tsx
index fbcaa0e95..8c788e556 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.stories.tsx
@@ -15,24 +15,26 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample, reducerStatesExample } from '../../utils';
-import { ChallengePayingScreen as TestedComponent } from './ChallengePayingScreen';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample, reducerStatesExample } from "../../utils";
+import { ChallengePayingScreen as TestedComponent } from "./ChallengePayingScreen";
export default {
- title: 'Pages/recovery/__ChallengePaying',
+ title: "Pages/recovery/__ChallengePaying",
component: TestedComponent,
args: {
order: 10,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-export const Example = createExample(TestedComponent, reducerStatesExample.challengePaying);
+export const Example = createExample(
+ TestedComponent,
+ reducerStatesExample.challengePaying,
+);
diff --git a/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx b/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx
index 84896a2ec..ffcc8fafc 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengePayingScreen.tsx
@@ -3,19 +3,19 @@ import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame } from "./index";
export function ChallengePayingScreen(): VNode {
- const reducer = useAnastasisContext()
+ const reducer = useAnastasisContext();
if (!reducer) {
- return <div>no reducer in context</div>
+ return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ reducer.currentReducerState.recovery_state === undefined
+ ) {
+ return <div>invalid state</div>;
}
- const payments = ['']; //reducer.currentReducerState.payments ??
+ const payments = [""]; //reducer.currentReducerState.payments ??
return (
- <AnastasisClientFrame
- hideNav
- title="Recovery: Challenge Paying"
- >
+ <AnastasisClientFrame hideNav title="Recovery: Challenge Paying">
<p>
Some of the providers require a payment to store the encrypted
authentication information.
diff --git a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx
index 6bdb3515d..0948d603e 100644
--- a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.stories.tsx
@@ -16,37 +16,42 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { ContinentSelectionScreen as TestedComponent } from './ContinentSelectionScreen';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../utils";
+import { ContinentSelectionScreen as TestedComponent } from "./ContinentSelectionScreen";
export default {
- title: 'Pages/Location',
+ title: "Pages/Location",
component: TestedComponent,
args: {
order: 2,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-export const BackupSelectContinent = createExample(TestedComponent, reducerStatesExample.backupSelectContinent);
+export const BackupSelectContinent = createExample(
+ TestedComponent,
+ reducerStatesExample.backupSelectContinent,
+);
export const BackupSelectCountry = createExample(TestedComponent, {
...reducerStatesExample.backupSelectContinent,
- selected_continent: 'Testcontinent',
+ selected_continent: "Testcontinent",
} as ReducerState);
-export const RecoverySelectContinent = createExample(TestedComponent, reducerStatesExample.recoverySelectContinent);
+export const RecoverySelectContinent = createExample(
+ TestedComponent,
+ reducerStatesExample.recoverySelectContinent,
+);
export const RecoverySelectCountry = createExample(TestedComponent, {
...reducerStatesExample.recoverySelectContinent,
- selected_continent: 'Testcontinent',
+ selected_continent: "Testcontinent",
} as ReducerState);
diff --git a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx
index 3d5fcce55..4cbeb8308 100644
--- a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.stories.tsx
@@ -16,94 +16,126 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { EditPoliciesScreen as TestedComponent } from './EditPoliciesScreen';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../utils";
+import { EditPoliciesScreen as TestedComponent } from "./EditPoliciesScreen";
export default {
- title: 'Pages/backup/ReviewPolicies/EditPolicies',
+ title: "Pages/backup/ReviewPolicies/EditPolicies",
args: {
order: 6,
},
component: TestedComponent,
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-export const EditingAPolicy = createExample(TestedComponent, {
- ...reducerStatesExample.policyReview,
- policies: [{
- methods: [{
- authentication_method: 1,
- provider: 'https://anastasis.demo.taler.net/'
- }, {
- authentication_method: 2,
- provider: 'http://localhost:8086/'
- }]
- }, {
- methods: [{
- authentication_method: 1,
- provider: 'http://localhost:8086/'
- }]
- }],
- authentication_methods: [{
- type: "email",
- instructions: "Email to qwe@asd.com",
- challenge: "E5VPA"
- }, {
- type: "totp",
- instructions: "Response code for 'Anastasis'",
- challenge: "E5VPA"
- }, {
- type: "sms",
- instructions: "SMS to 6666-6666",
- challenge: ""
- }, {
- type: "question",
- instructions: "How did the chicken cross the road?",
- challenge: "C5SP8"
- }]
-} as ReducerState, { index : 0});
-
-export const CreatingAPolicy = createExample(TestedComponent, {
- ...reducerStatesExample.policyReview,
- policies: [{
- methods: [{
- authentication_method: 1,
- provider: 'https://anastasis.demo.taler.net/'
- }, {
- authentication_method: 2,
- provider: 'http://localhost:8086/'
- }]
- }, {
- methods: [{
- authentication_method: 1,
- provider: 'http://localhost:8086/'
- }]
- }],
- authentication_methods: [{
- type: "email",
- instructions: "Email to qwe@asd.com",
- challenge: "E5VPA"
- }, {
- type: "totp",
- instructions: "Response code for 'Anastasis'",
- challenge: "E5VPA"
- }, {
- type: "sms",
- instructions: "SMS to 6666-6666",
- challenge: ""
- }, {
- type: "question",
- instructions: "How did the chicken cross the road?",
- challenge: "C5SP8"
- }]
-} as ReducerState, { index : 3});
+export const EditingAPolicy = createExample(
+ TestedComponent,
+ {
+ ...reducerStatesExample.policyReview,
+ policies: [
+ {
+ methods: [
+ {
+ authentication_method: 1,
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ {
+ authentication_method: 2,
+ provider: "http://localhost:8086/",
+ },
+ ],
+ },
+ {
+ methods: [
+ {
+ authentication_method: 1,
+ provider: "http://localhost:8086/",
+ },
+ ],
+ },
+ ],
+ authentication_methods: [
+ {
+ type: "email",
+ instructions: "Email to qwe@asd.com",
+ challenge: "E5VPA",
+ },
+ {
+ type: "totp",
+ instructions: "Response code for 'Anastasis'",
+ challenge: "E5VPA",
+ },
+ {
+ type: "sms",
+ instructions: "SMS to 6666-6666",
+ challenge: "",
+ },
+ {
+ type: "question",
+ instructions: "How did the chicken cross the road?",
+ challenge: "C5SP8",
+ },
+ ],
+ } as ReducerState,
+ { index: 0 },
+);
+export const CreatingAPolicy = createExample(
+ TestedComponent,
+ {
+ ...reducerStatesExample.policyReview,
+ policies: [
+ {
+ methods: [
+ {
+ authentication_method: 1,
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ {
+ authentication_method: 2,
+ provider: "http://localhost:8086/",
+ },
+ ],
+ },
+ {
+ methods: [
+ {
+ authentication_method: 1,
+ provider: "http://localhost:8086/",
+ },
+ ],
+ },
+ ],
+ authentication_methods: [
+ {
+ type: "email",
+ instructions: "Email to qwe@asd.com",
+ challenge: "E5VPA",
+ },
+ {
+ type: "totp",
+ instructions: "Response code for 'Anastasis'",
+ challenge: "E5VPA",
+ },
+ {
+ type: "sms",
+ instructions: "SMS to 6666-6666",
+ challenge: "",
+ },
+ {
+ type: "question",
+ instructions: "How did the chicken cross the road?",
+ challenge: "C5SP8",
+ },
+ ],
+ } as ReducerState,
+ { index: 3 },
+);
diff --git a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx
index 85cc96c46..198209399 100644
--- a/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/EditPoliciesScreen.tsx
@@ -20,7 +20,6 @@ interface Props {
index: number;
cancel: () => void;
confirm: (changes: MethodProvider[]) => void;
-
}
export interface MethodProvider {
@@ -28,106 +27,151 @@ export interface MethodProvider {
provider: string;
}
-export function EditPoliciesScreen({ index: policy_index, cancel, confirm }: Props): VNode {
- const [changedProvider, setChangedProvider] = useState<Array<string>>([])
+export function EditPoliciesScreen({
+ index: policy_index,
+ cancel,
+ confirm,
+}: Props): VNode {
+ const [changedProvider, setChangedProvider] = useState<Array<string>>([]);
- const reducer = useAnastasisContext()
+ const reducer = useAnastasisContext();
if (!reducer) {
- return <div>no reducer in context</div>
+ return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ reducer.currentReducerState.backup_state === undefined
+ ) {
+ return <div>invalid state</div>;
}
- const selectableProviders: ProviderInfoByType = {}
- const allProviders = Object.entries(reducer.currentReducerState.authentication_providers || {})
+ const selectableProviders: ProviderInfoByType = {};
+ const allProviders = Object.entries(
+ reducer.currentReducerState.authentication_providers || {},
+ );
for (let index = 0; index < allProviders.length; index++) {
- const [url, status] = allProviders[index]
+ const [url, status] = allProviders[index];
if ("methods" in status) {
- status.methods.map(m => {
- const type: KnownAuthMethods = m.type as KnownAuthMethods
- const values = selectableProviders[type] || []
- const isFree = !m.usage_fee || m.usage_fee.endsWith(":0")
- values.push({ url, cost: m.usage_fee, isFree })
- selectableProviders[type] = values
- })
+ status.methods.map((m) => {
+ const type: KnownAuthMethods = m.type as KnownAuthMethods;
+ const values = selectableProviders[type] || [];
+ const isFree = !m.usage_fee || m.usage_fee.endsWith(":0");
+ values.push({ url, cost: m.usage_fee, isFree });
+ selectableProviders[type] = values;
+ });
}
}
- const allAuthMethods = reducer.currentReducerState.authentication_methods ?? [];
+ const allAuthMethods =
+ reducer.currentReducerState.authentication_methods ?? [];
const policies = reducer.currentReducerState.policies ?? [];
- const policy = policies[policy_index]
-
- for(let method_index = 0; method_index < allAuthMethods.length; method_index++ ) {
- policy?.methods.find(m => m.authentication_method === method_index)?.provider
+ const policy = policies[policy_index];
+
+ for (
+ let method_index = 0;
+ method_index < allAuthMethods.length;
+ method_index++
+ ) {
+ policy?.methods.find((m) => m.authentication_method === method_index)
+ ?.provider;
}
function sendChanges(): void {
- const newMethods: MethodProvider[] = []
+ const newMethods: MethodProvider[] = [];
allAuthMethods.forEach((method, index) => {
- const oldValue = policy?.methods.find(m => m.authentication_method === index)
+ const oldValue = policy?.methods.find(
+ (m) => m.authentication_method === index,
+ );
if (changedProvider[index] === undefined && oldValue !== undefined) {
- newMethods.push(oldValue)
+ newMethods.push(oldValue);
}
- if (changedProvider[index] !== undefined && changedProvider[index] !== "") {
+ if (
+ changedProvider[index] !== undefined &&
+ changedProvider[index] !== ""
+ ) {
newMethods.push({
authentication_method: index,
- provider: changedProvider[index]
- })
+ provider: changedProvider[index],
+ });
}
- })
- confirm(newMethods)
+ });
+ confirm(newMethods);
}
- return <AnastasisClientFrame hideNav title={!policy ? "Backup: New Policy" : "Backup: Edit Policy"}>
- <section class="section">
- {!policy ? <p>
- Creating a new policy #{policy_index}
- </p> : <p>
- Editing policy #{policy_index}
- </p>}
- {allAuthMethods.map((method, index) => {
- //take the url from the updated change or from the policy
- const providerURL = changedProvider[index] === undefined ?
- policy?.methods.find(m => m.authentication_method === index)?.provider :
- changedProvider[index];
+ return (
+ <AnastasisClientFrame
+ hideNav
+ title={!policy ? "Backup: New Policy" : "Backup: Edit Policy"}
+ >
+ <section class="section">
+ {!policy ? (
+ <p>Creating a new policy #{policy_index}</p>
+ ) : (
+ <p>Editing policy #{policy_index}</p>
+ )}
+ {allAuthMethods.map((method, index) => {
+ //take the url from the updated change or from the policy
+ const providerURL =
+ changedProvider[index] === undefined
+ ? policy?.methods.find((m) => m.authentication_method === index)
+ ?.provider
+ : changedProvider[index];
- const type: KnownAuthMethods = method.type as KnownAuthMethods
- function changeProviderTo(url: string): void {
- const copy = [...changedProvider]
- copy[index] = url
- setChangedProvider(copy)
- }
- return (
- <div key={index} class="block" style={{ display: 'flex', alignItems: 'center' }}>
- <span class="icon">
- {authMethods[type]?.icon}
- </span>
- <span>
- {method.instructions}
- </span>
- <span>
- <span class="select " >
- <select onChange={(e) => changeProviderTo(e.currentTarget.value)} value={providerURL ?? ""}>
- <option key="none" value=""> &lt;&lt; off &gt;&gt; </option>
- {selectableProviders[type]?.map(prov => (
- <option key={prov.url} value={prov.url}>
- {prov.url}
+ const type: KnownAuthMethods = method.type as KnownAuthMethods;
+ function changeProviderTo(url: string): void {
+ const copy = [...changedProvider];
+ copy[index] = url;
+ setChangedProvider(copy);
+ }
+ return (
+ <div
+ key={index}
+ class="block"
+ style={{ display: "flex", alignItems: "center" }}
+ >
+ <span class="icon">{authMethods[type]?.icon}</span>
+ <span>{method.instructions}</span>
+ <span>
+ <span class="select ">
+ <select
+ onChange={(e) => changeProviderTo(e.currentTarget.value)}
+ value={providerURL ?? ""}
+ >
+ <option key="none" value="">
+ {" "}
+ &lt;&lt; off &gt;&gt;{" "}
</option>
- ))}
- </select>
+ {selectableProviders[type]?.map((prov) => (
+ <option key={prov.url} value={prov.url}>
+ {prov.url}
+ </option>
+ ))}
+ </select>
+ </span>
</span>
- </span>
- </div>
- );
- })}
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={cancel}>Cancel</button>
- <span class="buttons">
- <button class="button" onClick={() => setChangedProvider([])}>Reset</button>
- <button class="button is-info" onClick={sendChanges}>Confirm</button>
- </span>
- </div>
- </section>
- </AnastasisClientFrame>
+ </div>
+ );
+ })}
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={cancel}>
+ Cancel
+ </button>
+ <span class="buttons">
+ <button class="button" onClick={() => setChangedProvider([])}>
+ Reset
+ </button>
+ <button class="button is-info" onClick={sendChanges}>
+ Confirm
+ </button>
+ </span>
+ </div>
+ </section>
+ </AnastasisClientFrame>
+ );
}
diff --git a/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.stories.tsx
index 3ddf8011e..9bebcfbc9 100644
--- a/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.stories.tsx
@@ -15,35 +15,40 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { PoliciesPayingScreen as TestedComponent } from './PoliciesPayingScreen';
+ *
+ * @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/backup/__PoliciesPaying',
+ title: "Pages/backup/__PoliciesPaying",
component: TestedComponent,
args: {
order: 9,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-export const Example = createExample(TestedComponent, reducerStatesExample.policyPay);
+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'
- }]
+ 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);
diff --git a/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx b/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx
index a470f5155..c3568b32d 100644
--- a/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/PoliciesPayingScreen.tsx
@@ -3,20 +3,23 @@ import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame } from "./index";
export function PoliciesPayingScreen(): VNode {
- const reducer = useAnastasisContext()
+ const reducer = useAnastasisContext();
if (!reducer) {
- return <div>no reducer in context</div>
+ return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ reducer.currentReducerState.backup_state === undefined
+ ) {
+ return <div>invalid state</div>;
}
const payments = reducer.currentReducerState.policy_payment_requests ?? [];
-
+
return (
<AnastasisClientFrame hideNav title="Backup: Recovery Document Payments">
<p>
- Some of the providers require a payment to store the encrypted
- recovery document.
+ Some of the providers require a payment to store the encrypted recovery
+ document.
</p>
<ul>
{payments.map((x, i) => {
diff --git a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx
index e92a231a8..47860db29 100644
--- a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.stories.tsx
@@ -16,30 +16,32 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { RecoveryFinishedScreen as TestedComponent } from './RecoveryFinishedScreen';
+ *
+ * @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/recovery/Finished',
+ title: "Pages/recovery/Finished",
args: {
order: 7,
},
component: TestedComponent,
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
export const GoodEnding = createExample(TestedComponent, {
...reducerStatesExample.recoveryFinished,
- core_secret: { mime: 'text/plain', value: 'hello' }
+ core_secret: { mime: "text/plain", value: "hello" },
} as ReducerState);
-export const BadEnding = createExample(TestedComponent, reducerStatesExample.recoveryFinished);
+export const BadEnding = createExample(
+ TestedComponent,
+ reducerStatesExample.recoveryFinished,
+);
diff --git a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
index a61ef9efa..11ae09d4f 100644
--- a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
@@ -1,39 +1,53 @@
-import {
- bytesToString,
- decodeCrock
-} from "@gnu-taler/taler-util";
+import { bytesToString, decodeCrock } from "@gnu-taler/taler-util";
import { h, VNode } from "preact";
import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame } from "./index";
export function RecoveryFinishedScreen(): VNode {
- const reducer = useAnastasisContext()
+ const reducer = useAnastasisContext();
if (!reducer) {
- return <div>no reducer in context</div>
+ return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ reducer.currentReducerState.recovery_state === undefined
+ ) {
+ return <div>invalid state</div>;
}
- const encodedSecret = reducer.currentReducerState.core_secret
+ const encodedSecret = reducer.currentReducerState.core_secret;
if (!encodedSecret) {
- return <AnastasisClientFrame title="Recovery Problem" hideNav>
- <p>
- Secret not found
- </p>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
- </div>
- </AnastasisClientFrame>
+ return (
+ <AnastasisClientFrame title="Recovery Problem" hideNav>
+ <p>Secret not found</p>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
+ </div>
+ </AnastasisClientFrame>
+ );
}
- const secret = bytesToString(decodeCrock(encodedSecret.value))
+ const secret = bytesToString(decodeCrock(encodedSecret.value));
return (
<AnastasisClientFrame title="Recovery Finished" hideNav>
- <p>
- Secret: {secret}
- </p>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ <p>Your secret: {secret}</p>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
</AnastasisClientFrame>
);
diff --git a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx
index e348101ee..4a1cba6a8 100644
--- a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.stories.tsx
@@ -15,44 +15,51 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { ReviewPoliciesScreen as TestedComponent } from './ReviewPoliciesScreen';
+ *
+ * @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/backup/ReviewPolicies',
+ title: "Pages/backup/ReviewPolicies",
args: {
order: 6,
},
component: TestedComponent,
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ 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: []
+ 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, {
@@ -62,186 +69,193 @@ export const SomePoliciesWithMethods = createExample(TestedComponent, {
methods: [
{
authentication_method: 0,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 1,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 2,
- provider: "https://kudos.demo.anastasis.lu/"
- }
- ]
+ provider: "https://kudos.demo.anastasis.lu/",
+ },
+ ],
},
{
methods: [
{
authentication_method: 0,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 1,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 3,
- provider: "https://anastasis.demo.taler.net/"
- }
- ]
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ ],
},
{
methods: [
{
authentication_method: 0,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 1,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 4,
- provider: "https://anastasis.demo.taler.net/"
- }
- ]
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ ],
},
{
methods: [
{
authentication_method: 0,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 2,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 3,
- provider: "https://anastasis.demo.taler.net/"
- }
- ]
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ ],
},
{
methods: [
{
authentication_method: 0,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 2,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 4,
- provider: "https://anastasis.demo.taler.net/"
- }
- ]
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ ],
},
{
methods: [
{
authentication_method: 0,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 3,
- provider: "https://anastasis.demo.taler.net/"
+ provider: "https://anastasis.demo.taler.net/",
},
{
authentication_method: 4,
- provider: "https://anastasis.demo.taler.net/"
- }
- ]
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ ],
},
{
methods: [
{
authentication_method: 1,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 2,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 3,
- provider: "https://anastasis.demo.taler.net/"
- }
- ]
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ ],
},
{
methods: [
{
authentication_method: 1,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 2,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 4,
- provider: "https://anastasis.demo.taler.net/"
- }
- ]
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ ],
},
{
methods: [
{
authentication_method: 1,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 3,
- provider: "https://anastasis.demo.taler.net/"
+ provider: "https://anastasis.demo.taler.net/",
},
{
authentication_method: 4,
- provider: "https://anastasis.demo.taler.net/"
- }
- ]
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ ],
},
{
methods: [
{
authentication_method: 2,
- provider: "https://kudos.demo.anastasis.lu/"
+ provider: "https://kudos.demo.anastasis.lu/",
},
{
authentication_method: 3,
- provider: "https://anastasis.demo.taler.net/"
+ provider: "https://anastasis.demo.taler.net/",
},
{
authentication_method: 4,
- provider: "https://anastasis.demo.taler.net/"
- }
- ]
- }
+ provider: "https://anastasis.demo.taler.net/",
+ },
+ ],
+ },
+ ],
+ authentication_methods: [
+ {
+ type: "email",
+ instructions: "Email to qwe@asd.com",
+ challenge: "E5VPA",
+ },
+ {
+ type: "sms",
+ instructions: "SMS to 555-555",
+ challenge: "",
+ },
+ {
+ type: "question",
+ instructions: "Does P equal NP?",
+ challenge: "C5SP8",
+ },
+ {
+ type: "totp",
+ instructions: "Response code for 'Anastasis'",
+ challenge: "E5VPA",
+ },
+ {
+ type: "sms",
+ instructions: "SMS to 6666-6666",
+ challenge: "",
+ },
+ {
+ type: "question",
+ instructions: "How did the chicken cross the road?",
+ challenge: "C5SP8",
+ },
],
- authentication_methods: [{
- type: "email",
- instructions: "Email to qwe@asd.com",
- challenge: "E5VPA"
- }, {
- type: "sms",
- instructions: "SMS to 555-555",
- challenge: ""
- }, {
- type: "question",
- instructions: "Does P equal NP?",
- challenge: "C5SP8"
- },{
- type: "totp",
- instructions: "Response code for 'Anastasis'",
- challenge: "E5VPA"
- }, {
- type: "sms",
- instructions: "SMS to 6666-6666",
- challenge: ""
- }, {
- type: "question",
- instructions: "How did the chicken cross the road?",
- challenge: "C5SP8"
-}]
} as ReducerState);
diff --git a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
index aa98b5dd9..c43f0cdea 100644
--- a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
@@ -6,16 +6,20 @@ import { EditPoliciesScreen } from "./EditPoliciesScreen";
import { AnastasisClientFrame } from "./index";
export function ReviewPoliciesScreen(): VNode {
- const [editingPolicy, setEditingPolicy] = useState<number | undefined>()
- const reducer = useAnastasisContext()
+ const [editingPolicy, setEditingPolicy] = useState<number | undefined>();
+ const reducer = useAnastasisContext();
if (!reducer) {
- return <div>no reducer in context</div>
+ return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ reducer.currentReducerState.backup_state === undefined
+ ) {
+ return <div>invalid state</div>;
}
- const configuredAuthMethods = reducer.currentReducerState.authentication_methods ?? [];
+ const configuredAuthMethods =
+ reducer.currentReducerState.authentication_methods ?? [];
const policies = reducer.currentReducerState.policies ?? [];
if (editingPolicy !== undefined) {
@@ -28,58 +32,109 @@ export function ReviewPoliciesScreen(): VNode {
policy_index: editingPolicy,
policy: newMethods,
});
- setEditingPolicy(undefined)
+ setEditingPolicy(undefined);
}}
/>
- )
+ );
}
- const errors = policies.length < 1 ? 'Need more policies' : undefined
+ const errors = policies.length < 1 ? "Need more policies" : undefined;
return (
- <AnastasisClientFrame hideNext={errors} title="Backup: Review Recovery Policies">
- {policies.length > 0 && <p class="block">
- Based on your configured authentication method you have created, some policies
- have been configured. In order to recover your secret you have to solve all the
- challenges of at least one policy.
- </p>}
- {policies.length < 1 && <p class="block">
- No policies had been created. Go back and add more authentication methods.
- </p>}
- <div class="block" style={{ justifyContent: 'flex-end' }} >
- <button class="button is-success" onClick={() => setEditingPolicy(policies.length + 1)}>Add new policy</button>
+ <AnastasisClientFrame
+ hideNext={errors}
+ title="Backup: Review Recovery Policies"
+ >
+ {policies.length > 0 && (
+ <p class="block">
+ Based on your configured authentication method you have created, some
+ policies have been configured. In order to recover your secret you
+ have to solve all the challenges of at least one policy.
+ </p>
+ )}
+ {policies.length < 1 && (
+ <p class="block">
+ No policies had been created. Go back and add more authentication
+ methods.
+ </p>
+ )}
+ <div class="block" style={{ justifyContent: "flex-end" }}>
+ <button
+ class="button is-success"
+ onClick={() => setEditingPolicy(policies.length + 1)}
+ >
+ Add new policy
+ </button>
</div>
{policies.map((p, policy_index) => {
const methods = p.methods
- .map(x => configuredAuthMethods[x.authentication_method] && ({ ...configuredAuthMethods[x.authentication_method], provider: x.provider }))
- .filter(x => !!x)
+ .map(
+ (x) =>
+ configuredAuthMethods[x.authentication_method] && {
+ ...configuredAuthMethods[x.authentication_method],
+ provider: x.provider,
+ },
+ )
+ .filter((x) => !!x);
- const policyName = methods.map(x => x.type).join(" + ");
+ const policyName = methods.map((x) => x.type).join(" + ");
+
+ if (p.methods.length > methods.length) {
+ //there is at least one authentication method that is corrupted
+ return null;
+ }
return (
- <div key={policy_index} class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
+ <div
+ key={policy_index}
+ class="box"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
<div>
<h3 class="subtitle">
Policy #{policy_index + 1}: {policyName}
</h3>
- {!methods.length && <p>
- No auth method found
- </p>}
+ {!methods.length && <p>No auth method found</p>}
{methods.map((m, i) => {
return (
- <p key={i} class="block" style={{ display: 'flex', alignItems: 'center' }}>
+ <p
+ key={i}
+ class="block"
+ style={{ display: "flex", alignItems: "center" }}
+ >
<span class="icon">
{authMethods[m.type as KnownAuthMethods]?.icon}
</span>
<span>
- {m.instructions} recovery provided by <a href={m.provider}>{m.provider}</a>
+ {m.instructions} recovery provided by{" "}
+ <a href={m.provider}>{m.provider}</a>
</span>
</p>
);
})}
</div>
- <div style={{ marginTop: 'auto', marginBottom: 'auto', display: 'flex', justifyContent: 'space-between', flexDirection: 'column' }}>
- <button class="button is-info block" onClick={() => setEditingPolicy(policy_index)}>Edit</button>
- <button class="button is-danger block" onClick={() => reducer.transition("delete_policy", { policy_index })}>Delete</button>
+ <div
+ style={{
+ marginTop: "auto",
+ marginBottom: "auto",
+ display: "flex",
+ justifyContent: "space-between",
+ flexDirection: "column",
+ }}
+ >
+ <button
+ class="button is-info block"
+ onClick={() => setEditingPolicy(policy_index)}
+ >
+ Edit
+ </button>
+ <button
+ class="button is-danger block"
+ onClick={() =>
+ reducer.transition("delete_policy", { policy_index })
+ }
+ >
+ Delete
+ </button>
</div>
</div>
);
diff --git a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.stories.tsx
index db061d936..3f2c6a245 100644
--- a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.stories.tsx
@@ -15,30 +15,29 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { SecretEditorScreen as TestedComponent } from './SecretEditorScreen';
+ *
+ * @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/backup/SecretInput',
+ title: "Pages/backup/SecretInput",
component: TestedComponent,
args: {
order: 7,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
export const WithSecretNamePreselected = createExample(TestedComponent, {
...reducerStatesExample.secretEdition,
- secret_name: 'someSecretName',
+ secret_name: "someSecretName",
} as ReducerState);
export const WithoutName = createExample(TestedComponent, {
diff --git a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.stories.tsx
index 8d02ebfbe..01ce3f0a7 100644
--- a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.stories.tsx
@@ -15,37 +15,35 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { SecretSelectionScreen as TestedComponent } from './SecretSelectionScreen';
+ *
+ * @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/recovery/SecretSelection',
+ title: "Pages/recovery/SecretSelection",
component: TestedComponent,
args: {
order: 4,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
export const Example = createExample(TestedComponent, {
...reducerStatesExample.secretSelection,
recovery_document: {
- provider_url: 'https://kudos.demo.anastasis.lu/',
- secret_name: 'secretName',
+ provider_url: "https://kudos.demo.anastasis.lu/",
+ secret_name: "secretName",
version: 1,
},
} as ReducerState);
-
export const NoRecoveryDocumentFound = createExample(TestedComponent, {
...reducerStatesExample.secretSelection,
recovery_document: undefined,
diff --git a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
index 398393619..4000f9bfe 100644
--- a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
@@ -8,18 +8,23 @@ import { AnastasisClientFrame } from "./index";
export function SecretSelectionScreen(): VNode {
const [selectingVersion, setSelectingVersion] = useState<boolean>(false);
- const reducer = useAnastasisContext()
+ const reducer = useAnastasisContext();
- const [manageProvider, setManageProvider] = useState(false)
- const currentVersion = (reducer?.currentReducerState
- && ("recovery_document" in reducer.currentReducerState)
- && reducer.currentReducerState.recovery_document?.version) || 0;
+ const [manageProvider, setManageProvider] = useState(false);
+ const currentVersion =
+ (reducer?.currentReducerState &&
+ "recovery_document" in reducer.currentReducerState &&
+ reducer.currentReducerState.recovery_document?.version) ||
+ 0;
if (!reducer) {
- return <div>no reducer in context</div>
+ return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ reducer.currentReducerState.recovery_state === undefined
+ ) {
+ return <div>invalid state</div>;
}
async function doSelectVersion(p: string, n: number): Promise<void> {
@@ -33,72 +38,101 @@ export function SecretSelectionScreen(): VNode {
});
}
- const providerList = Object.keys(reducer.currentReducerState.authentication_providers ?? {})
- const recoveryDocument = reducer.currentReducerState.recovery_document
+ const providerList = Object.keys(
+ reducer.currentReducerState.authentication_providers ?? {},
+ );
+ const recoveryDocument = reducer.currentReducerState.recovery_document;
if (!recoveryDocument) {
- return <ChooseAnotherProviderScreen
- providers={providerList} selected=""
- onChange={(newProv) => doSelectVersion(newProv, 0)}
- />
+ return (
+ <ChooseAnotherProviderScreen
+ providers={providerList}
+ selected=""
+ onChange={(newProv) => doSelectVersion(newProv, 0)}
+ />
+ );
}
if (selectingVersion) {
- return <SelectOtherVersionProviderScreen providers={providerList}
- provider={recoveryDocument.provider_url} version={recoveryDocument.version}
- onCancel={() => setSelectingVersion(false)}
- onConfirm={doSelectVersion}
- />
+ return (
+ <SelectOtherVersionProviderScreen
+ providers={providerList}
+ provider={recoveryDocument.provider_url}
+ version={recoveryDocument.version}
+ onCancel={() => setSelectingVersion(false)}
+ onConfirm={doSelectVersion}
+ />
+ );
}
if (manageProvider) {
- return <AddingProviderScreen onCancel={() => setManageProvider(false)} />
+ return <AddingProviderScreen onCancel={() => setManageProvider(false)} />;
}
return (
<AnastasisClientFrame title="Recovery: Select secret">
<div class="columns">
<div class="column">
- <div class="box" style={{ border: '2px solid green' }}>
+ <div class="box" style={{ border: "2px solid green" }}>
<h1 class="subtitle">{recoveryDocument.provider_url}</h1>
<div class="block">
- {currentVersion === 0 ? <p>
- Set to recover the latest version
- </p> : <p>
- Set to recover the version number {currentVersion}
- </p>}
+ {currentVersion === 0 ? (
+ <p>Set to recover the latest version</p>
+ ) : (
+ <p>Set to recover the version number {currentVersion}</p>
+ )}
</div>
<div class="buttons is-right">
- <button class="button" onClick={(e) => setSelectingVersion(true)}>Change secret's version</button>
+ <button class="button" onClick={(e) => setSelectingVersion(true)}>
+ Change secret's version
+ </button>
</div>
</div>
</div>
<div class="column">
- <p>Secret found, you can select another version or continue to the challenges solving</p>
+ <p>
+ Secret found, you can select another version or continue to the
+ challenges solving
+ </p>
<p class="block">
- <button class="button is-info" onClick={() => setManageProvider(true)}>
+ <a onClick={() => setManageProvider(true)}>
Manage recovery providers
- </button>
+ </a>
</p>
-
</div>
</div>
</AnastasisClientFrame>
);
}
-
-function ChooseAnotherProviderScreen({ providers, selected, onChange }: { selected: string; providers: string[]; onChange: (prov: string) => void }): VNode {
+function ChooseAnotherProviderScreen({
+ providers,
+ selected,
+ onChange,
+}: {
+ selected: string;
+ providers: string[];
+ onChange: (prov: string) => void;
+}): VNode {
return (
- <AnastasisClientFrame hideNext="Recovery document not found" title="Recovery: Problem">
+ <AnastasisClientFrame
+ hideNext="Recovery document not found"
+ title="Recovery: Problem"
+ >
<p>No recovery document found, try with another provider</p>
<div class="field">
<label class="label">Provider</label>
<div class="control is-expanded has-icons-left">
<div class="select is-fullwidth">
- <select onChange={(e) => onChange(e.currentTarget.value)} value={selected}>
- <option key="none" disabled selected value=""> Choose a provider </option>
- {providers.map(prov => (
+ <select
+ onChange={(e) => onChange(e.currentTarget.value)}
+ value={selected}
+ >
+ <option key="none" disabled selected value="">
+ {" "}
+ Choose a provider{" "}
+ </option>
+ {providers.map((prov) => (
<option key={prov} value={prov}>
{prov}
</option>
@@ -114,9 +148,23 @@ function ChooseAnotherProviderScreen({ providers, selected, onChange }: { select
);
}
-function SelectOtherVersionProviderScreen({ providers, provider, version, onConfirm, onCancel }: { onCancel: () => void; provider: string; version: number; providers: string[]; onConfirm: (prov: string, v: number) => Promise<void>; }): VNode {
+function SelectOtherVersionProviderScreen({
+ providers,
+ provider,
+ version,
+ onConfirm,
+ onCancel,
+}: {
+ onCancel: () => void;
+ provider: string;
+ version: number;
+ providers: string[];
+ onConfirm: (prov: string, v: number) => Promise<void>;
+}): VNode {
const [otherProvider, setOtherProvider] = useState<string>(provider);
- const [otherVersion, setOtherVersion] = useState(version > 0 ? String(version) : "");
+ const [otherVersion, setOtherVersion] = useState(
+ version > 0 ? String(version) : "",
+ );
return (
<AnastasisClientFrame hideNav title="Recovery: Select secret">
@@ -125,11 +173,11 @@ function SelectOtherVersionProviderScreen({ providers, provider, version, onConf
<div class="box">
<h1 class="subtitle">Provider {otherProvider}</h1>
<div class="block">
- {version === 0 ? <p>
- Set to recover the latest version
- </p> : <p>
- Set to recover the version number {version}
- </p>}
+ {version === 0 ? (
+ <p>Set to recover the latest version</p>
+ ) : (
+ <p>Set to recover the version number {version}</p>
+ )}
<p>Specify other version below or use the latest</p>
</div>
@@ -137,9 +185,15 @@ function SelectOtherVersionProviderScreen({ providers, provider, version, onConf
<label class="label">Provider</label>
<div class="control is-expanded has-icons-left">
<div class="select is-fullwidth">
- <select onChange={(e) => setOtherProvider(e.currentTarget.value)} value={otherProvider}>
- <option key="none" disabled selected value=""> Choose a provider </option>
- {providers.map(prov => (
+ <select
+ onChange={(e) => setOtherProvider(e.currentTarget.value)}
+ value={otherProvider}
+ >
+ <option key="none" disabled selected value="">
+ {" "}
+ Choose a provider{" "}
+ </option>
+ {providers.map((prov) => (
<option key={prov} value={prov}>
{prov}
</option>
@@ -156,23 +210,40 @@ function SelectOtherVersionProviderScreen({ providers, provider, version, onConf
label="Version"
placeholder="version number to recover"
grabFocus
- bind={[otherVersion, setOtherVersion]} />
+ bind={[otherVersion, setOtherVersion]}
+ />
</div>
</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={onCancel}>Cancel</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={onCancel}>
+ Cancel
+ </button>
<div class="buttons">
- <AsyncButton class="button" onClick={() => onConfirm(otherProvider, 0)}>Use latest</AsyncButton>
- <AsyncButton class="button is-info" onClick={() => onConfirm(otherProvider, parseInt(otherVersion, 10))}>Confirm</AsyncButton>
+ <AsyncButton
+ class="button"
+ onClick={() => onConfirm(otherProvider, 0)}
+ >
+ Use latest
+ </AsyncButton>
+ <AsyncButton
+ class="button is-info"
+ onClick={() =>
+ onConfirm(otherProvider, parseInt(otherVersion, 10))
+ }
+ >
+ Confirm
+ </AsyncButton>
</div>
</div>
</div>
- <div class="column">
- .
- </div>
+ <div class="column">.</div>
</div>
-
</AnastasisClientFrame>
);
-
}
diff --git a/packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx
index f1f2802ae..76d0700db 100644
--- a/packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/SolveScreen.stories.tsx
@@ -15,55 +15,63 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ChallengeFeedbackStatus, RecoveryStates, ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { SolveScreen as TestedComponent } from './SolveScreen';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import {
+ ChallengeFeedbackStatus,
+ RecoveryStates,
+ ReducerState,
+} from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../utils";
+import { SolveScreen as TestedComponent } from "./SolveScreen";
export default {
- title: 'Pages/recovery/SolveChallenge/Solve',
+ title: "Pages/recovery/SolveChallenge/Solve",
component: TestedComponent,
args: {
order: 6,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-export const NoInformation = createExample(TestedComponent, reducerStatesExample.challengeSolving);
+export const NoInformation = createExample(
+ TestedComponent,
+ reducerStatesExample.challengeSolving,
+);
export const NotSupportedChallenge = createExample(TestedComponent, {
...reducerStatesExample.challengeSolving,
recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'chall-type',
- uuid: 'ASDASDSAD!1'
- }],
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "chall-type",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
policies: [],
},
- selected_challenge_uuid: 'ASDASDSAD!1',
-
+ selected_challenge_uuid: "ASDASDSAD!1",
} as ReducerState);
export const MismatchedChallengeId = createExample(TestedComponent, {
...reducerStatesExample.challengeSolving,
recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'chall-type',
- uuid: 'ASDASDSAD!1'
- }],
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "chall-type",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
policies: [],
},
- selected_challenge_uuid: 'no-no-no'
+ selected_challenge_uuid: "no-no-no",
} as ReducerState);
-
diff --git a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
index 5e17c9aa1..b87dad2ce 100644
--- a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
@@ -2,76 +2,126 @@ import { h, VNode } from "preact";
import { AnastasisClientFrame } from ".";
import {
ChallengeFeedback,
- ChallengeFeedbackStatus
+ ChallengeFeedbackStatus,
} from "../../../../anastasis-core/lib";
import { Notifications } from "../../components/Notifications";
import { useAnastasisContext } from "../../context/anastasis";
import { authMethods, KnownAuthMethods } from "./authMethod";
-export function SolveOverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }): VNode {
+export function SolveOverviewFeedbackDisplay(props: {
+ feedback?: ChallengeFeedback;
+}): VNode {
const { feedback } = props;
if (!feedback) {
return <div />;
}
switch (feedback.state) {
case ChallengeFeedbackStatus.Message:
- return (<Notifications notifications={[{
- type: "INFO",
- message: `Message from provider`,
- description: feedback.message
- }]} />);
+ return (
+ <Notifications
+ notifications={[
+ {
+ type: "INFO",
+ message: `Message from provider`,
+ description: feedback.message,
+ },
+ ]}
+ />
+ );
case ChallengeFeedbackStatus.Payment:
- return <Notifications notifications={[{
- type: "INFO",
- message: `Message from provider`,
- description: <span>
- To pay you can <a href={feedback.taler_pay_uri}>click here</a>
- </span>
- }]} />
+ return (
+ <Notifications
+ notifications={[
+ {
+ type: "INFO",
+ message: `Message from provider`,
+ description: (
+ <span>
+ To pay you can <a href={feedback.taler_pay_uri}>click here</a>
+ </span>
+ ),
+ },
+ ]}
+ />
+ );
case ChallengeFeedbackStatus.AuthIban:
- return <Notifications notifications={[{
- type: "INFO",
- message: `Message from provider`,
- description: `Need to send a wire transfer to "${feedback.business_name}"`
- }]} />;
+ return (
+ <Notifications
+ notifications={[
+ {
+ type: "INFO",
+ message: `Message from provider`,
+ description: `Need to send a wire transfer to "${feedback.business_name}"`,
+ },
+ ]}
+ />
+ );
case ChallengeFeedbackStatus.ServerFailure:
- return (<Notifications notifications={[{
- type: "ERROR",
- message: `Server error: Code ${feedback.http_status}`,
- description: feedback.error_response
- }]} />);
+ return (
+ <Notifications
+ notifications={[
+ {
+ type: "ERROR",
+ message: `Server error: Code ${feedback.http_status}`,
+ description: feedback.error_response,
+ },
+ ]}
+ />
+ );
case ChallengeFeedbackStatus.RateLimitExceeded:
- return (<Notifications notifications={[{
- type: "ERROR",
- message: `Message from provider`,
- description: "There were to many failed attempts."
- }]} />);
+ return (
+ <Notifications
+ notifications={[
+ {
+ type: "ERROR",
+ message: `Message from provider`,
+ description: "There were to many failed attempts.",
+ },
+ ]}
+ />
+ );
case ChallengeFeedbackStatus.Redirect:
- return (<Notifications notifications={[{
- type: "INFO",
- message: `Message from provider`,
- description: <span>
- Please visit this link: <a>{feedback.redirect_url}</a>
- </span>
- }]} />);
+ return (
+ <Notifications
+ notifications={[
+ {
+ type: "INFO",
+ message: `Message from provider`,
+ description: (
+ <span>
+ Please visit this link: <a>{feedback.redirect_url}</a>
+ </span>
+ ),
+ },
+ ]}
+ />
+ );
case ChallengeFeedbackStatus.Unsupported:
- return (<Notifications notifications={[{
- type: "ERROR",
- message: `This client doesn't support solving this type of challenge`,
- description: `Use another version or contact the provider. Type of challenge "${feedback.unsupported_method}"`
- }]} />);
+ return (
+ <Notifications
+ notifications={[
+ {
+ type: "ERROR",
+ message: `This client doesn't support solving this type of challenge`,
+ description: `Use another version or contact the provider. Type of challenge "${feedback.unsupported_method}"`,
+ },
+ ]}
+ />
+ );
case ChallengeFeedbackStatus.TruthUnknown:
- return (<Notifications notifications={[{
- type: "ERROR",
- message: `Provider doesn't recognize the type of challenge`,
- description: "Contact the provider for further information"
- }]} />);
- default:
return (
- <div>
- <pre>{JSON.stringify(feedback)}</pre>
- </div>
+ <Notifications
+ notifications={[
+ {
+ type: "ERROR",
+ message: `Provider doesn't recognize the type of challenge`,
+ description: "Contact the provider for further information",
+ },
+ ]}
+ />
);
+ default:
+ return <div />;
}
}
@@ -110,8 +160,16 @@ export function SolveScreen(): VNode {
return (
<AnastasisClientFrame hideNav title="Recovery problem">
<div>invalid state</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
</AnastasisClientFrame>
);
@@ -120,26 +178,36 @@ export function SolveScreen(): VNode {
return (
<AnastasisClientFrame hideNav title="Not implemented">
<p>
- The challenge selected is not supported for this UI. Please update this
- version or try using another policy.
+ The challenge selected is not supported for this UI. Please update
+ this version or try using another policy.
</p>
- {reducer &&
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ {reducer && (
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
- }
+ )}
</AnastasisClientFrame>
);
}
-
const chArr = reducer.currentReducerState.recovery_information.challenges;
const selectedUuid = reducer.currentReducerState.selected_challenge_uuid;
- const selectedChallenge = chArr.find(ch => ch.uuid === selectedUuid)
+ const selectedChallenge = chArr.find((ch) => ch.uuid === selectedUuid);
- const SolveDialog = !selectedChallenge || !authMethods[selectedChallenge.type as KnownAuthMethods] ?
- SolveNotImplemented :
- authMethods[selectedChallenge.type as KnownAuthMethods].solve ?? SolveNotImplemented
+ const SolveDialog =
+ !selectedChallenge ||
+ !authMethods[selectedChallenge.type as KnownAuthMethods]
+ ? SolveNotImplemented
+ : authMethods[selectedChallenge.type as KnownAuthMethods].solve ??
+ SolveNotImplemented;
- return <SolveDialog id={selectedUuid} />
+ return <SolveDialog id={selectedUuid} />;
}
diff --git a/packages/anastasis-webui/src/pages/home/StartScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/StartScreen.stories.tsx
index 41082c128..fcddaf87a 100644
--- a/packages/anastasis-webui/src/pages/home/StartScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/StartScreen.stories.tsx
@@ -15,24 +15,26 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample, reducerStatesExample } from '../../utils';
-import { StartScreen as TestedComponent } from './StartScreen';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample, reducerStatesExample } from "../../utils";
+import { StartScreen as TestedComponent } from "./StartScreen";
export default {
- title: 'Pages/Start',
+ title: "Pages/Start",
component: TestedComponent,
args: {
order: 1,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-export const InitialState = createExample(TestedComponent, reducerStatesExample.initial); \ No newline at end of file
+export const InitialState = createExample(
+ TestedComponent,
+ reducerStatesExample.initial,
+);
diff --git a/packages/anastasis-webui/src/pages/home/StartScreen.tsx b/packages/anastasis-webui/src/pages/home/StartScreen.tsx
index d53df4cae..8b24ef684 100644
--- a/packages/anastasis-webui/src/pages/home/StartScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/StartScreen.tsx
@@ -1,27 +1,36 @@
-
import { h, VNode } from "preact";
import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame } from "./index";
export function StartScreen(): VNode {
- const reducer = useAnastasisContext()
+ const reducer = useAnastasisContext();
if (!reducer) {
- return <div>no reducer in context</div>
+ return <div>no reducer in context</div>;
}
return (
<AnastasisClientFrame hideNav title="Home">
<div class="columns">
<div class="column" />
<div class="column is-four-fifths">
-
<div class="buttons">
- <button class="button is-success" autoFocus onClick={() => reducer.startBackup()}>
- <div class="icon"><i class="mdi mdi-arrow-up" /></div>
+ <button
+ class="button is-success"
+ autoFocus
+ onClick={() => reducer.startBackup()}
+ >
+ <div class="icon">
+ <i class="mdi mdi-arrow-up" />
+ </div>
<span>Backup a secret</span>
</button>
- <button class="button is-info" onClick={() => reducer.startRecover()}>
- <div class="icon"><i class="mdi mdi-arrow-down" /></div>
+ <button
+ class="button is-info"
+ onClick={() => reducer.startRecover()}
+ >
+ <div class="icon">
+ <i class="mdi mdi-arrow-down" />
+ </div>
<span>Recover a secret</span>
</button>
@@ -30,7 +39,6 @@ export function StartScreen(): VNode {
<span>Restore a session</span>
</button> */}
</div>
-
</div>
<div class="column" />
</div>
diff --git a/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.stories.tsx
index 38b71bc36..245ad8889 100644
--- a/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.stories.tsx
@@ -15,29 +15,31 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../utils';
-import { TruthsPayingScreen as TestedComponent } from './TruthsPayingScreen';
+ *
+ * @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/backup/__TruthsPaying',
+ title: "Pages/backup/__TruthsPaying",
component: TestedComponent,
args: {
order: 10,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-export const Example = createExample(TestedComponent, reducerStatesExample.truthsPaying);
+export const Example = createExample(
+ TestedComponent,
+ reducerStatesExample.truthsPaying,
+);
export const WithPaytoList = createExample(TestedComponent, {
...reducerStatesExample.truthsPaying,
- payments: ['payto://x-taler-bank/bank/account']
+ payments: ["payto://x-taler-bank/bank/account"],
} as ReducerState);
diff --git a/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx b/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx
index 0b32e0db5..6f95fa93b 100644
--- a/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/TruthsPayingScreen.tsx
@@ -3,19 +3,19 @@ import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame } from "./index";
export function TruthsPayingScreen(): VNode {
- const reducer = useAnastasisContext()
+ const reducer = useAnastasisContext();
if (!reducer) {
- return <div>no reducer in context</div>
+ return <div>no reducer in context</div>;
}
- if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
- return <div>invalid state</div>
+ if (
+ !reducer.currentReducerState ||
+ reducer.currentReducerState.backup_state === undefined
+ ) {
+ return <div>invalid state</div>;
}
const payments = reducer.currentReducerState.payments ?? [];
return (
- <AnastasisClientFrame
- hideNext={"FIXME"}
- title="Backup: Truths Paying"
- >
+ <AnastasisClientFrame hideNext={"FIXME"} title="Backup: Truths Paying">
<p>
Some of the providers require a payment to store the encrypted
authentication information.
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.stories.tsx
index da87b7a8b..080a7ab31 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.stories.tsx
@@ -15,51 +15,67 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/backup/AuthorizationMethod/AuthMethods/email',
+ title: "Pages/backup/AuthorizationMethod/AuthMethods/email",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'email'
+const type: KnownAuthMethods = "email";
-export const Empty = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: []
-});
+export const Empty = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [],
+ },
+);
-export const WithOneExample = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Email to sebasjm@email.com ',
- remove: () => null
- }]
-});
+export const WithOneExample = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Email to sebasjm@email.com ",
+ remove: () => null,
+ },
+ ],
+ },
+);
-export const WithMoreExamples = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Email to sebasjm@email.com',
- remove: () => null
- },{
- challenge: 'qwe',
- type,
- instructions: 'Email to someone@sebasjm.com',
- remove: () => null
- }]
-});
+export const WithMoreExamples = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Email to sebasjm@email.com",
+ remove: () => null,
+ },
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Email to someone@sebasjm.com",
+ remove: () => null,
+ },
+ ],
+ },
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.tsx
index 27a0685b2..61c66c8c8 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.tsx
@@ -1,57 +1,90 @@
-import {
- encodeCrock,
- stringToBytes
-} from "@gnu-taler/taler-util";
+import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util";
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { EmailInput } from "../../../components/fields/EmailInput";
import { AnastasisClientFrame } from "../index";
import { AuthMethodSetupProps } from "./index";
-const EMAIL_PATTERN = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+const EMAIL_PATTERN = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
-export function AuthMethodEmailSetup({ cancel, addAuthMethod, configured }: AuthMethodSetupProps): VNode {
+export function AuthMethodEmailSetup({
+ cancel,
+ addAuthMethod,
+ configured,
+}: AuthMethodSetupProps): VNode {
const [email, setEmail] = useState("");
- const addEmailAuth = (): void => addAuthMethod({
- authentication_method: {
- type: "email",
- instructions: `Email to ${email}`,
- challenge: encodeCrock(stringToBytes(email)),
- },
- });
- const emailError = !EMAIL_PATTERN.test(email) ? 'Email address is not valid' : undefined
- const errors = !email ? 'Add your email' : emailError
+ const addEmailAuth = (): void =>
+ addAuthMethod({
+ authentication_method: {
+ type: "email",
+ instructions: `Email to ${email}`,
+ challenge: encodeCrock(stringToBytes(email)),
+ },
+ });
+ const emailError = !EMAIL_PATTERN.test(email)
+ ? "Email address is not valid"
+ : undefined;
+ const errors = !email ? "Add your email" : emailError;
return (
<AnastasisClientFrame hideNav title="Add email authentication">
<p>
For email authentication, you need to provide an email address. When
recovering your secret, you will need to enter the code you receive by
- email.
+ email. Add the uuid from the challenge
</p>
<div>
<EmailInput
label="Email address"
error={emailError}
placeholder="email@domain.com"
- bind={[email, setEmail]} />
+ bind={[email, setEmail]}
+ />
</div>
- {configured.length > 0 && <section class="section">
- <div class="block">
- Your emails:
- </div><div class="block">
- {configured.map((c, i) => {
- return <div key={i} class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
- <p style={{ marginBottom: 'auto', marginTop: 'auto' }}>{c.instructions}</p>
- <div><button class="button is-danger" onClick={c.remove} >Delete</button></div>
- </div>
- })}
- </div></section>}
+ {configured.length > 0 && (
+ <section class="section">
+ <div class="block">Your emails:</div>
+ <div class="block">
+ {configured.map((c, i) => {
+ return (
+ <div
+ key={i}
+ class="box"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
+ <p style={{ marginBottom: "auto", marginTop: "auto" }}>
+ {c.instructions}
+ </p>
+ <div>
+ <button class="button is-danger" onClick={c.remove}>
+ Delete
+ </button>
+ </div>
+ </div>
+ );
+ })}
+ </div>
+ </section>
+ )}
<div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={cancel}>Cancel</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={cancel}>
+ Cancel
+ </button>
<span data-tooltip={errors}>
- <button class="button is-info" disabled={errors !== undefined} onClick={addEmailAuth}>Add</button>
+ <button
+ class="button is-info"
+ disabled={errors !== undefined}
+ onClick={addEmailAuth}
+ >
+ Add
+ </button>
</span>
</div>
</div>
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.stories.tsx
index 525cd2b07..6a8a2a347 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.stories.tsx
@@ -15,66 +15,76 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ChallengeFeedbackStatus, ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ChallengeFeedbackStatus, ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/recovery/SolveChallenge/AuthMethods/email',
+ title: "Pages/recovery/SolveChallenge/AuthMethods/email",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'email'
+const type: KnownAuthMethods = "email";
-export const WithoutFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'uuid-1'
- }],
- policies: [],
+export const WithoutFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "uuid-1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "uuid-1",
+ } as ReducerState,
+ {
+ id: "uuid-1",
},
- selected_challenge_uuid: 'uuid-1',
-} as ReducerState, {
- id: 'uuid-1',
-});
+);
-export const PaymentFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'uuid-1'
- }],
- policies: [],
+export const PaymentFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "uuid-1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "uuid-1",
+ challenge_feedback: {
+ "uuid-1": {
+ state: ChallengeFeedbackStatus.Payment,
+ taler_pay_uri: "taler://pay/...",
+ provider: "https://localhost:8080/",
+ payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG",
+ },
+ },
+ } as ReducerState,
+ {
+ id: "uuid-1",
},
- selected_challenge_uuid: 'uuid-1',
- challenge_feedback: {
- 'uuid-1': {
- state: ChallengeFeedbackStatus.Payment,
- taler_pay_uri: "taler://pay/...",
- provider: "https://localhost:8080/",
- payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
- }
- }
-} as ReducerState, {
- id: 'uuid-1',
-});
-
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx
index bd4f43740..ff6c51d1c 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx
@@ -44,8 +44,16 @@ export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode {
return (
<AnastasisClientFrame hideNav title="Recovery problem">
<div>invalid state</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
</AnastasisClientFrame>
);
@@ -62,8 +70,7 @@ export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode {
challenges[ch.uuid] = ch;
}
const selectedChallenge = challenges[selectedUuid];
- const feedback = challengeFeedback[selectedUuid]
-
+ const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> {
return reducer?.transition("solve_challenge", { answer });
@@ -72,18 +79,19 @@ export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode {
reducer?.back();
}
-
- const shouldHideConfirm = feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded
- || feedback?.state === ChallengeFeedbackStatus.Redirect
- || feedback?.state === ChallengeFeedbackStatus.Unsupported
- || feedback?.state === ChallengeFeedbackStatus.TruthUnknown
+ const shouldHideConfirm =
+ feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded ||
+ feedback?.state === ChallengeFeedbackStatus.Redirect ||
+ feedback?.state === ChallengeFeedbackStatus.Unsupported ||
+ feedback?.state === ChallengeFeedbackStatus.TruthUnknown;
return (
<AnastasisClientFrame hideNav title="Add email authentication">
<SolveOverviewFeedbackDisplay feedback={feedback} />
<p>
- An email has been sent to "<b>{selectedChallenge.instructions}</b>". Type the
- code below
+ An email has been sent to "<b>{selectedChallenge.instructions}</b>".
+ Type the code below.
+ <b>Here we need to add the code "{selectedUuid}"</b>
</p>
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
@@ -97,9 +105,11 @@ export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode {
<button class="button" onClick={onCancel}>
Cancel
</button>
- {!shouldHideConfirm && <AsyncButton class="button is-info" onClick={onNext}>
- Confirm
- </AsyncButton>}
+ {!shouldHideConfirm && (
+ <AsyncButton class="button is-info" onClick={onNext}>
+ Confirm
+ </AsyncButton>
+ )}
</div>
</AnastasisClientFrame>
);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.stories.tsx
index be0a04847..c521e18fd 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.stories.tsx
@@ -15,50 +15,66 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/backup/AuthorizationMethod/AuthMethods/IBAN',
+ title: "Pages/backup/AuthorizationMethod/AuthMethods/IBAN",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'iban'
+const type: KnownAuthMethods = "iban";
-export const Empty = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: []
-});
+export const Empty = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [],
+ },
+);
-export const WithOneExample = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Wire transfer from QWEASD123123 with holder Sebastian',
- remove: () => null
- }]
-});
-export const WithMoreExamples = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Wire transfer from QWEASD123123 with holder Javier',
- remove: () => null
- },{
- challenge: 'qwe',
- type,
- instructions: 'Wire transfer from QWEASD123123 with holder Sebastian',
- remove: () => null
- }]
-},);
+export const WithOneExample = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Wire transfer from QWEASD123123 with holder Sebastian",
+ remove: () => null,
+ },
+ ],
+ },
+);
+export const WithMoreExamples = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Wire transfer from QWEASD123123 with holder Javier",
+ remove: () => null,
+ },
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Wire transfer from QWEASD123123 with holder Sebastian",
+ remove: () => null,
+ },
+ ],
+ },
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.tsx
index 87969ab27..dee550e5b 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.tsx
@@ -1,7 +1,7 @@
import {
canonicalJson,
encodeCrock,
- stringToBytes
+ stringToBytes,
} from "@gnu-taler/taler-util";
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
@@ -9,56 +9,98 @@ import { AuthMethodSetupProps } from ".";
import { TextInput } from "../../../components/fields/TextInput";
import { AnastasisClientFrame } from "../index";
-export function AuthMethodIbanSetup({ addAuthMethod, cancel, configured }: AuthMethodSetupProps): VNode {
+export function AuthMethodIbanSetup({
+ addAuthMethod,
+ cancel,
+ configured,
+}: AuthMethodSetupProps): VNode {
const [name, setName] = useState("");
const [account, setAccount] = useState("");
- const addIbanAuth = (): void => addAuthMethod({
- authentication_method: {
- type: "iban",
- instructions: `Wire transfer from ${account} with holder ${name}`,
- challenge: encodeCrock(stringToBytes(canonicalJson({
- name, account
- }))),
- },
- });
- const errors = !name ? 'Add an account name' : (
- !account ? 'Add an account IBAN number' : undefined
- )
+ const addIbanAuth = (): void =>
+ addAuthMethod({
+ authentication_method: {
+ type: "iban",
+ instructions: `Wire transfer from ${account} with holder ${name}`,
+ challenge: encodeCrock(
+ stringToBytes(
+ canonicalJson({
+ name,
+ account,
+ }),
+ ),
+ ),
+ },
+ });
+ const errors = !name
+ ? "Add an account name"
+ : !account
+ ? "Add an account IBAN number"
+ : undefined;
return (
<AnastasisClientFrame hideNav title="Add bank transfer authentication">
<p>
- For bank transfer authentication, you need to provide a bank
- account (account holder name and IBAN). When recovering your
- secret, you will be asked to pay the recovery fee via bank
- transfer from the account you provided here.
+ For bank transfer authentication, you need to provide a bank account
+ (account holder name and IBAN). When recovering your secret, you will be
+ asked to pay the recovery fee via bank transfer from the account you
+ provided here.
</p>
<div>
<TextInput
label="Bank account holder name"
grabFocus
placeholder="John Smith"
- bind={[name, setName]} />
+ bind={[name, setName]}
+ />
<TextInput
label="IBAN"
placeholder="DE91100000000123456789"
- bind={[account, setAccount]} />
+ bind={[account, setAccount]}
+ />
</div>
- {configured.length > 0 && <section class="section">
- <div class="block">
- Your bank accounts:
- </div><div class="block">
- {configured.map((c, i) => {
- return <div key={i} class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
- <p style={{ marginBottom: 'auto', marginTop: 'auto' }}>{c.instructions}</p>
- <div><button class="button is-danger" onClick={c.remove} >Delete</button></div>
- </div>
- })}
- </div></section>}
+ {configured.length > 0 && (
+ <section class="section">
+ <div class="block">Your bank accounts:</div>
+ <div class="block">
+ {configured.map((c, i) => {
+ return (
+ <div
+ key={i}
+ class="box"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
+ <p style={{ marginBottom: "auto", marginTop: "auto" }}>
+ {c.instructions}
+ </p>
+ <div>
+ <button class="button is-danger" onClick={c.remove}>
+ Delete
+ </button>
+ </div>
+ </div>
+ );
+ })}
+ </div>
+ </section>
+ )}
<div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={cancel}>Cancel</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={cancel}>
+ Cancel
+ </button>
<span data-tooltip={errors}>
- <button class="button is-info" disabled={errors !== undefined} onClick={addIbanAuth}>Add</button>
+ <button
+ class="button is-info"
+ disabled={errors !== undefined}
+ onClick={addIbanAuth}
+ >
+ Add
+ </button>
</span>
</div>
</div>
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.stories.tsx
index df73a9214..cbbc253e9 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.stories.tsx
@@ -15,42 +15,46 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ChallengeFeedbackStatus, ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ChallengeFeedbackStatus, ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/recovery/SolveChallenge/AuthMethods/Iban',
+ title: "Pages/recovery/SolveChallenge/AuthMethods/Iban",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'iban'
-
-export const WithoutFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'uuid-1'
- }],
- policies: [],
+const type: KnownAuthMethods = "iban";
+
+export const WithoutFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "uuid-1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "uuid-1",
+ } as ReducerState,
+ {
+ id: "uuid-1",
},
- selected_challenge_uuid: 'uuid-1',
-} as ReducerState, {
- id: 'uuid-1',
-});
-
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.tsx
index 1e4353da6..46cf0502c 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSolve.tsx
@@ -44,8 +44,16 @@ export function AuthMethodIbanSolve({ id }: AuthMethodSolveProps): VNode {
return (
<AnastasisClientFrame hideNav title="Recovery problem">
<div>invalid state</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
</AnastasisClientFrame>
);
@@ -62,8 +70,7 @@ export function AuthMethodIbanSolve({ id }: AuthMethodSolveProps): VNode {
challenges[ch.uuid] = ch;
}
const selectedChallenge = challenges[selectedUuid];
- const feedback = challengeFeedback[selectedUuid]
-
+ const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> {
return reducer?.transition("solve_challenge", { answer });
@@ -72,19 +79,17 @@ export function AuthMethodIbanSolve({ id }: AuthMethodSolveProps): VNode {
reducer?.back();
}
-
- const shouldHideConfirm = feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded
- || feedback?.state === ChallengeFeedbackStatus.Redirect
- || feedback?.state === ChallengeFeedbackStatus.Unsupported
- || feedback?.state === ChallengeFeedbackStatus.TruthUnknown
+ const shouldHideConfirm =
+ feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded ||
+ feedback?.state === ChallengeFeedbackStatus.Redirect ||
+ feedback?.state === ChallengeFeedbackStatus.Unsupported ||
+ feedback?.state === ChallengeFeedbackStatus.TruthUnknown;
return (
<AnastasisClientFrame hideNav title="Add email authentication">
<SolveOverviewFeedbackDisplay feedback={feedback} />
- <p>
- Send a wire transfer to the address
- </p>
- <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
+ <p>Send a wire transfer to the address,</p>
+ <button class="button">Check</button>
<div
style={{
@@ -96,9 +101,11 @@ export function AuthMethodIbanSolve({ id }: AuthMethodSolveProps): VNode {
<button class="button" onClick={onCancel}>
Cancel
</button>
- {!shouldHideConfirm && <AsyncButton class="button is-info" onClick={onNext}>
- Confirm
- </AsyncButton>}
+ {!shouldHideConfirm && (
+ <AsyncButton class="button is-info" onClick={onNext}>
+ Confirm
+ </AsyncButton>
+ )}
</div>
</AnastasisClientFrame>
);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.stories.tsx
index adc83d6fe..2977586ac 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.stories.tsx
@@ -16,51 +16,67 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/backup/AuthorizationMethod/AuthMethods/Post',
+ title: "Pages/backup/AuthorizationMethod/AuthMethods/Post",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'post'
+const type: KnownAuthMethods = "post";
-export const Empty = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: []
-});
+export const Empty = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [],
+ },
+);
-export const WithOneExample = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Letter to address in postal code QWE456',
- remove: () => null
- }]
-});
+export const WithOneExample = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Letter to address in postal code QWE456",
+ remove: () => null,
+ },
+ ],
+ },
+);
-export const WithMoreExamples = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Letter to address in postal code QWE456',
- remove: () => null
- },{
- challenge: 'qwe',
- type,
- instructions: 'Letter to address in postal code ABC123',
- remove: () => null
- }]
-});
+export const WithMoreExamples = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Letter to address in postal code QWE456",
+ remove: () => null,
+ },
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Letter to address in postal code ABC123",
+ remove: () => null,
+ },
+ ],
+ },
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.tsx
index 692421d74..6c8d36bcf 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.tsx
@@ -1,6 +1,7 @@
import {
- canonicalJson, encodeCrock,
- stringToBytes
+ canonicalJson,
+ encodeCrock,
+ stringToBytes,
} from "@gnu-taler/taler-util";
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
@@ -8,7 +9,11 @@ import { AnastasisClientFrame } from "..";
import { TextInput } from "../../../components/fields/TextInput";
import { AuthMethodSetupProps } from "./index";
-export function AuthMethodPostSetup({ addAuthMethod, cancel, configured }: AuthMethodSetupProps): VNode {
+export function AuthMethodPostSetup({
+ addAuthMethod,
+ cancel,
+ configured,
+}: AuthMethodSetupProps): VNode {
const [fullName, setFullName] = useState("");
const [street, setStreet] = useState("");
const [city, setCity] = useState("");
@@ -32,68 +37,83 @@ export function AuthMethodPostSetup({ addAuthMethod, cancel, configured }: AuthM
});
};
- const errors = !fullName ? 'The full name is missing' : (
- !street ? 'The street is missing' : (
- !city ? 'The city is missing' : (
- !postcode ? 'The postcode is missing' : (
- !country ? 'The country is missing' : undefined
- )
- )
- )
- )
+ const errors = !fullName
+ ? "The full name is missing"
+ : !street
+ ? "The street is missing"
+ : !city
+ ? "The city is missing"
+ : !postcode
+ ? "The postcode is missing"
+ : !country
+ ? "The country is missing"
+ : undefined;
return (
<AnastasisClientFrame hideNav title="Add postal authentication">
<p>
- For postal letter authentication, you need to provide a postal
- address. When recovering your secret, you will be asked to enter a
- code that you will receive in a letter to that address.
+ For postal letter authentication, you need to provide a postal address.
+ When recovering your secret, you will be asked to enter a code that you
+ will receive in a letter to that address.
</p>
<div>
- <TextInput
- grabFocus
- label="Full Name"
- bind={[fullName, setFullName]}
- />
+ <TextInput grabFocus label="Full Name" bind={[fullName, setFullName]} />
</div>
<div>
- <TextInput
- label="Street"
- bind={[street, setStreet]}
- />
+ <TextInput label="Street" bind={[street, setStreet]} />
</div>
<div>
- <TextInput
- label="City" bind={[city, setCity]}
- />
+ <TextInput label="City" bind={[city, setCity]} />
</div>
<div>
- <TextInput
- label="Postal Code" bind={[postcode, setPostcode]}
- />
+ <TextInput label="Postal Code" bind={[postcode, setPostcode]} />
</div>
<div>
- <TextInput
- label="Country"
- bind={[country, setCountry]}
- />
+ <TextInput label="Country" bind={[country, setCountry]} />
</div>
- {configured.length > 0 && <section class="section">
- <div class="block">
- Your postal code:
- </div><div class="block">
- {configured.map((c, i) => {
- return <div key={i} class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
- <p style={{ marginBottom: 'auto', marginTop: 'auto' }}>{c.instructions}</p>
- <div><button class="button is-danger" onClick={c.remove} >Delete</button></div>
- </div>
- })}
- </div>
- </section>}
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={cancel}>Cancel</button>
+ {configured.length > 0 && (
+ <section class="section">
+ <div class="block">Your postal code:</div>
+ <div class="block">
+ {configured.map((c, i) => {
+ return (
+ <div
+ key={i}
+ class="box"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
+ <p style={{ marginBottom: "auto", marginTop: "auto" }}>
+ {c.instructions}
+ </p>
+ <div>
+ <button class="button is-danger" onClick={c.remove}>
+ Delete
+ </button>
+ </div>
+ </div>
+ );
+ })}
+ </div>
+ </section>
+ )}
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={cancel}>
+ Cancel
+ </button>
<span data-tooltip={errors}>
- <button class="button is-info" disabled={errors !== undefined} onClick={addPostAuth}>Add</button>
+ <button
+ class="button is-info"
+ disabled={errors !== undefined}
+ onClick={addPostAuth}
+ >
+ Add
+ </button>
</span>
</div>
</AnastasisClientFrame>
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.stories.tsx
index 99451090b..3b67ee884 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.stories.tsx
@@ -15,42 +15,46 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ChallengeFeedbackStatus, ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ChallengeFeedbackStatus, ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/recovery/SolveChallenge/AuthMethods/post',
+ title: "Pages/recovery/SolveChallenge/AuthMethods/post",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'post'
-
-export const WithoutFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'uuid-1'
- }],
- policies: [],
+const type: KnownAuthMethods = "post";
+
+export const WithoutFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "uuid-1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "uuid-1",
+ } as ReducerState,
+ {
+ id: "uuid-1",
},
- selected_challenge_uuid: 'uuid-1',
-} as ReducerState, {
- id: 'uuid-1',
-});
-
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx
index 7e3c45abe..ee001ebe9 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx
@@ -44,8 +44,16 @@ export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode {
return (
<AnastasisClientFrame hideNav title="Recovery problem">
<div>invalid state</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
</AnastasisClientFrame>
);
@@ -62,8 +70,7 @@ export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode {
challenges[ch.uuid] = ch;
}
const selectedChallenge = challenges[selectedUuid];
- const feedback = challengeFeedback[selectedUuid]
-
+ const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> {
return reducer?.transition("solve_challenge", { answer });
@@ -72,18 +79,16 @@ export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode {
reducer?.back();
}
-
- const shouldHideConfirm = feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded
- || feedback?.state === ChallengeFeedbackStatus.Redirect
- || feedback?.state === ChallengeFeedbackStatus.Unsupported
- || feedback?.state === ChallengeFeedbackStatus.TruthUnknown
+ const shouldHideConfirm =
+ feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded ||
+ feedback?.state === ChallengeFeedbackStatus.Redirect ||
+ feedback?.state === ChallengeFeedbackStatus.Unsupported ||
+ feedback?.state === ChallengeFeedbackStatus.TruthUnknown;
return (
<AnastasisClientFrame hideNav title="Add email authentication">
<SolveOverviewFeedbackDisplay feedback={feedback} />
- <p>
- Wait for the answer
- </p>
+ <p>Wait for the answer</p>
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
<div
@@ -96,9 +101,11 @@ export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode {
<button class="button" onClick={onCancel}>
Cancel
</button>
- {!shouldHideConfirm && <AsyncButton class="button is-info" onClick={onNext}>
- Confirm
- </AsyncButton>}
+ {!shouldHideConfirm && (
+ <AsyncButton class="button is-info" onClick={onNext}>
+ Confirm
+ </AsyncButton>
+ )}
</div>
</AnastasisClientFrame>
);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.stories.tsx
index 0c3ee2b77..991301cbf 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.stories.tsx
@@ -16,51 +16,69 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/backup/AuthorizationMethod/AuthMethods/Question',
+ title: "Pages/backup/AuthorizationMethod/AuthMethods/Question",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'question'
+const type: KnownAuthMethods = "question";
-export const Empty = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: []
-});
+export const Empty = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [],
+ },
+);
-export const WithOneExample = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Is integer factorization polynomial? (non-quantum computer)',
- remove: () => null
- }]
-});
+export const WithOneExample = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions:
+ "Is integer factorization polynomial? (non-quantum computer)",
+ remove: () => null,
+ },
+ ],
+ },
+);
-export const WithMoreExamples = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Does P equal NP?',
- remove: () => null
- },{
- challenge: 'asd',
- type,
- instructions: 'Are continuous groups automatically differential groups?',
- remove: () => null
- }]
-});
+export const WithMoreExamples = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: "Does P equal NP?",
+ remove: () => null,
+ },
+ {
+ challenge: "asd",
+ type,
+ instructions:
+ "Are continuous groups automatically differential groups?",
+ remove: () => null,
+ },
+ ],
+ },
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
index 780bfcb82..0a14021dd 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
@@ -1,27 +1,31 @@
-import {
- encodeCrock,
- stringToBytes
-} from "@gnu-taler/taler-util";
+import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AuthMethodSetupProps } from "./index";
import { AnastasisClientFrame } from "../index";
import { TextInput } from "../../../components/fields/TextInput";
-export function AuthMethodQuestionSetup({ cancel, addAuthMethod, configured }: AuthMethodSetupProps): VNode {
+export function AuthMethodQuestionSetup({
+ cancel,
+ addAuthMethod,
+ configured,
+}: AuthMethodSetupProps): VNode {
const [questionText, setQuestionText] = useState("");
const [answerText, setAnswerText] = useState("");
- const addQuestionAuth = (): void => addAuthMethod({
- authentication_method: {
- type: "question",
- instructions: questionText,
- challenge: encodeCrock(stringToBytes(answerText)),
- },
- });
+ const addQuestionAuth = (): void =>
+ addAuthMethod({
+ authentication_method: {
+ type: "question",
+ instructions: questionText,
+ challenge: encodeCrock(stringToBytes(answerText)),
+ },
+ });
- const errors = !questionText ? "Add your security question" : (
- !answerText ? 'Add the answer to your question' : undefined
- )
+ const errors = !questionText
+ ? "Add your security question"
+ : !answerText
+ ? "Add the answer to your question"
+ : undefined;
return (
<AnastasisClientFrame hideNav title="Add Security Question">
<div>
@@ -36,7 +40,8 @@ export function AuthMethodQuestionSetup({ cancel, addAuthMethod, configured }: A
label="Security question"
grabFocus
placeholder="Your question"
- bind={[questionText, setQuestionText]} />
+ bind={[questionText, setQuestionText]}
+ />
</div>
<div>
<TextInput
@@ -46,25 +51,53 @@ export function AuthMethodQuestionSetup({ cancel, addAuthMethod, configured }: A
/>
</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={cancel}>Cancel</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={cancel}>
+ Cancel
+ </button>
<span data-tooltip={errors}>
- <button class="button is-info" disabled={errors !== undefined} onClick={addQuestionAuth}>Add</button>
+ <button
+ class="button is-info"
+ disabled={errors !== undefined}
+ onClick={addQuestionAuth}
+ >
+ Add
+ </button>
</span>
</div>
- {configured.length > 0 && <section class="section">
- <div class="block">
- Your security questions:
- </div><div class="block">
- {configured.map((c, i) => {
- return <div key={i} class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
- <p style={{ marginBottom: 'auto', marginTop: 'auto' }}>{c.instructions}</p>
- <div><button class="button is-danger" onClick={c.remove} >Delete</button></div>
- </div>
- })}
- </div></section>}
+ {configured.length > 0 && (
+ <section class="section">
+ <div class="block">Your security questions:</div>
+ <div class="block">
+ {configured.map((c, i) => {
+ return (
+ <div
+ key={i}
+ class="box"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
+ <p style={{ marginBottom: "auto", marginTop: "auto" }}>
+ {c.instructions}
+ </p>
+ <div>
+ <button class="button is-danger" onClick={c.remove}>
+ Delete
+ </button>
+ </div>
+ </div>
+ );
+ })}
+ </div>
+ </section>
+ )}
</div>
- </AnastasisClientFrame >
+ </AnastasisClientFrame>
);
}
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.stories.tsx
index f0ec92d4d..1fa9fd6ec 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.stories.tsx
@@ -15,186 +15,205 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ChallengeFeedbackStatus, ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ChallengeFeedbackStatus, ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/recovery/SolveChallenge/AuthMethods/question',
+ title: "Pages/recovery/SolveChallenge/AuthMethods/question",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'question'
+const type: KnownAuthMethods = "question";
-export const WithoutFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'uuid-1'
- }],
- policies: [],
+export const WithoutFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "uuid-1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "uuid-1",
+ } as ReducerState,
+ {
+ id: "uuid-1",
},
- selected_challenge_uuid: 'uuid-1',
-} as ReducerState, {
- id: 'uuid-1',
-});
+);
export const MessageFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'ASDASDSAD!1'
- }],
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
policies: [],
},
- selected_challenge_uuid: 'ASDASDSAD!1',
+ selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
- 'ASDASDSAD!1': {
+ "ASDASDSAD!1": {
state: ChallengeFeedbackStatus.Message,
- message: 'Challenge should be solved'
- }
- }
-
-} as ReducerState);
-
-export const ServerFailureFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'ASDASDSAD!1'
- }],
- policies: [],
+ message: "Challenge should be solved",
+ },
},
- selected_challenge_uuid: 'ASDASDSAD!1',
- challenge_feedback: {
- 'ASDASDSAD!1': {
- state: ChallengeFeedbackStatus.ServerFailure,
- http_status: 500,
- error_response: "Couldn't connect to mysql"
- }
- }
-
} as ReducerState);
+export const ServerFailureFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "ASDASDSAD!1",
+ challenge_feedback: {
+ "ASDASDSAD!1": {
+ state: ChallengeFeedbackStatus.ServerFailure,
+ http_status: 500,
+ error_response: "Couldn't connect to mysql",
+ },
+ },
+ } as ReducerState,
+);
+
export const RedirectFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'ASDASDSAD!1'
- }],
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
policies: [],
},
- selected_challenge_uuid: 'ASDASDSAD!1',
+ selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
- 'ASDASDSAD!1': {
+ "ASDASDSAD!1": {
state: ChallengeFeedbackStatus.Redirect,
http_status: 302,
- redirect_url: 'http://video.taler.net'
- }
- }
-
-} as ReducerState);
-
-export const MessageRateLimitExceededFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'ASDASDSAD!1'
- }],
- policies: [],
+ redirect_url: "http://video.taler.net",
+ },
},
- selected_challenge_uuid: 'ASDASDSAD!1',
- challenge_feedback: {
- 'ASDASDSAD!1': {
- state: ChallengeFeedbackStatus.RateLimitExceeded,
- }
- }
-
} as ReducerState);
+export const MessageRateLimitExceededFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "ASDASDSAD!1",
+ challenge_feedback: {
+ "ASDASDSAD!1": {
+ state: ChallengeFeedbackStatus.RateLimitExceeded,
+ },
+ },
+ } as ReducerState,
+);
+
export const UnsupportedFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'ASDASDSAD!1'
- }],
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
policies: [],
},
- selected_challenge_uuid: 'ASDASDSAD!1',
+ selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
- 'ASDASDSAD!1': {
+ "ASDASDSAD!1": {
state: ChallengeFeedbackStatus.Unsupported,
http_status: 500,
- unsupported_method: 'Question'
- }
- }
-
+ unsupported_method: "Question",
+ },
+ },
} as ReducerState);
export const TruthUnknownFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'ASDASDSAD!1'
- }],
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
policies: [],
},
- selected_challenge_uuid: 'ASDASDSAD!1',
+ selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
- 'ASDASDSAD!1': {
+ "ASDASDSAD!1": {
state: ChallengeFeedbackStatus.TruthUnknown,
- }
- }
-
+ },
+ },
} as ReducerState);
export const AuthIbanFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'ASDASDSAD!1'
- }],
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
policies: [],
},
- selected_challenge_uuid: 'ASDASDSAD!1',
+ selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
- 'ASDASDSAD!1': {
+ "ASDASDSAD!1": {
state: ChallengeFeedbackStatus.AuthIban,
challenge_amount: "EUR:1",
credit_iban: "DE12345789000",
@@ -210,30 +229,30 @@ export const AuthIbanFeedback = createExample(TestedComponent[type].solve, {
wire_transfer_subject: "foo",
},
method: "iban",
- }
- }
-
+ },
+ },
} as ReducerState);
export const PaymentFeedback = createExample(TestedComponent[type].solve, {
...reducerStatesExample.challengeSolving,
recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'ASDASDSAD!1'
- }],
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "ASDASDSAD!1",
+ },
+ ],
policies: [],
},
- selected_challenge_uuid: 'ASDASDSAD!1',
+ selected_challenge_uuid: "ASDASDSAD!1",
challenge_feedback: {
- 'ASDASDSAD!1': {
+ "ASDASDSAD!1": {
state: ChallengeFeedbackStatus.Payment,
- taler_pay_uri : "taler://pay/...",
- provider : "https://localhost:8080/",
- payment_secret : "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
- }
- }
+ taler_pay_uri: "taler://pay/...",
+ provider: "https://localhost:8080/",
+ payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG",
+ },
+ },
} as ReducerState);
-
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.tsx
index ee1c0028f..222789507 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.tsx
@@ -44,8 +44,16 @@ export function AuthMethodQuestionSolve({ id }: AuthMethodSolveProps): VNode {
return (
<AnastasisClientFrame hideNav title="Recovery problem">
<div>invalid state</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
</AnastasisClientFrame>
);
@@ -62,8 +70,7 @@ export function AuthMethodQuestionSolve({ id }: AuthMethodSolveProps): VNode {
challenges[ch.uuid] = ch;
}
const selectedChallenge = challenges[selectedUuid];
- const feedback = challengeFeedback[selectedUuid]
-
+ const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> {
return reducer?.transition("solve_challenge", { answer });
@@ -72,18 +79,16 @@ export function AuthMethodQuestionSolve({ id }: AuthMethodSolveProps): VNode {
reducer?.back();
}
-
- const shouldHideConfirm = feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded
- || feedback?.state === ChallengeFeedbackStatus.Redirect
- || feedback?.state === ChallengeFeedbackStatus.Unsupported
- || feedback?.state === ChallengeFeedbackStatus.TruthUnknown
+ const shouldHideConfirm =
+ feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded ||
+ feedback?.state === ChallengeFeedbackStatus.Redirect ||
+ feedback?.state === ChallengeFeedbackStatus.Unsupported ||
+ feedback?.state === ChallengeFeedbackStatus.TruthUnknown;
return (
<AnastasisClientFrame hideNav title="Add email authentication">
<SolveOverviewFeedbackDisplay feedback={feedback} />
- <p>
- Answer the question please
- </p>
+ <p>Answer the question please</p>
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
<div
@@ -96,9 +101,11 @@ export function AuthMethodQuestionSolve({ id }: AuthMethodSolveProps): VNode {
<button class="button" onClick={onCancel}>
Cancel
</button>
- {!shouldHideConfirm && <AsyncButton class="button is-info" onClick={onNext}>
- Confirm
- </AsyncButton>}
+ {!shouldHideConfirm && (
+ <AsyncButton class="button is-info" onClick={onNext}>
+ Confirm
+ </AsyncButton>
+ )}
</div>
</AnastasisClientFrame>
);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.stories.tsx
index da2087ce1..3a44c7ad0 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.stories.tsx
@@ -16,51 +16,67 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/backup/AuthorizationMethod/AuthMethods/Sms',
+ title: "Pages/backup/AuthorizationMethod/AuthMethods/Sms",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'sms'
+const type: KnownAuthMethods = "sms";
-export const Empty = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: []
-});
+export const Empty = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [],
+ },
+);
-export const WithOneExample = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'SMS to +11-1234-2345',
- remove: () => null
- }]
-});
+export const WithOneExample = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: "SMS to +11-1234-2345",
+ remove: () => null,
+ },
+ ],
+ },
+);
-export const WithMoreExamples = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'SMS to +11-1234-2345',
- remove: () => null
- },{
- challenge: 'qwe',
- type,
- instructions: 'SMS to +11-5555-2345',
- remove: () => null
- }]
-});
+export const WithMoreExamples = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: "SMS to +11-1234-2345",
+ remove: () => null,
+ },
+ {
+ challenge: "qwe",
+ type,
+ instructions: "SMS to +11-5555-2345",
+ remove: () => null,
+ },
+ ],
+ },
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx
index 9a0459d78..056b1b175 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx
@@ -1,14 +1,15 @@
-import {
- encodeCrock,
- stringToBytes
-} from "@gnu-taler/taler-util";
+import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util";
import { Fragment, h, VNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
import { AuthMethodSetupProps } from ".";
import { PhoneNumberInput } from "../../../components/fields/NumberInput";
import { AnastasisClientFrame } from "../index";
-export function AuthMethodSmsSetup({ addAuthMethod, cancel, configured }: AuthMethodSetupProps): VNode {
+export function AuthMethodSmsSetup({
+ addAuthMethod,
+ cancel,
+ configured,
+}: AuthMethodSetupProps): VNode {
const [mobileNumber, setMobileNumber] = useState("");
const addSmsAuth = (): void => {
addAuthMethod({
@@ -23,7 +24,7 @@ export function AuthMethodSmsSetup({ addAuthMethod, cancel, configured }: AuthMe
useLayoutEffect(() => {
inputRef.current?.focus();
}, []);
- const errors = !mobileNumber ? 'Add a mobile number' : undefined
+ const errors = !mobileNumber ? "Add a mobile number" : undefined;
return (
<AnastasisClientFrame hideNav title="Add SMS authentication">
<div>
@@ -37,23 +38,52 @@ export function AuthMethodSmsSetup({ addAuthMethod, cancel, configured }: AuthMe
label="Mobile number"
placeholder="Your mobile number"
grabFocus
- bind={[mobileNumber, setMobileNumber]} />
+ bind={[mobileNumber, setMobileNumber]}
+ />
</div>
- {configured.length > 0 && <section class="section">
- <div class="block">
- Your mobile numbers:
- </div><div class="block">
- {configured.map((c, i) => {
- return <div key={i} class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
- <p style={{ marginTop: 'auto', marginBottom: 'auto' }}>{c.instructions}</p>
- <div><button class="button is-danger" onClick={c.remove}>Delete</button></div>
- </div>
- })}
- </div></section>}
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={cancel}>Cancel</button>
+ {configured.length > 0 && (
+ <section class="section">
+ <div class="block">Your mobile numbers:</div>
+ <div class="block">
+ {configured.map((c, i) => {
+ return (
+ <div
+ key={i}
+ class="box"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
+ <p style={{ marginTop: "auto", marginBottom: "auto" }}>
+ {c.instructions}
+ </p>
+ <div>
+ <button class="button is-danger" onClick={c.remove}>
+ Delete
+ </button>
+ </div>
+ </div>
+ );
+ })}
+ </div>
+ </section>
+ )}
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={cancel}>
+ Cancel
+ </button>
<span data-tooltip={errors}>
- <button class="button is-info" disabled={errors !== undefined} onClick={addSmsAuth}>Add</button>
+ <button
+ class="button is-info"
+ disabled={errors !== undefined}
+ onClick={addSmsAuth}
+ >
+ Add
+ </button>
</span>
</div>
</div>
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx
index 76e769303..3dc3adb2b 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx
@@ -15,42 +15,46 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ChallengeFeedbackStatus, ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ChallengeFeedbackStatus, ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/recovery/SolveChallenge/AuthMethods/sms',
+ title: "Pages/recovery/SolveChallenge/AuthMethods/sms",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'sms'
-
-export const WithoutFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'uuid-1'
- }],
- policies: [],
+const type: KnownAuthMethods = "sms";
+
+export const WithoutFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "uuid-1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "uuid-1",
+ } as ReducerState,
+ {
+ id: "uuid-1",
},
- selected_challenge_uuid: 'uuid-1',
-} as ReducerState, {
- id: 'uuid-1',
-});
-
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx
index ce7159bd0..8ee4d600a 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx
@@ -44,8 +44,16 @@ export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode {
return (
<AnastasisClientFrame hideNav title="Recovery problem">
<div>invalid state</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
</AnastasisClientFrame>
);
@@ -62,8 +70,7 @@ export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode {
challenges[ch.uuid] = ch;
}
const selectedChallenge = challenges[selectedUuid];
- const feedback = challengeFeedback[selectedUuid]
-
+ const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> {
return reducer?.transition("solve_challenge", { answer });
@@ -72,18 +79,18 @@ export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode {
reducer?.back();
}
-
- const shouldHideConfirm = feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded
- || feedback?.state === ChallengeFeedbackStatus.Redirect
- || feedback?.state === ChallengeFeedbackStatus.Unsupported
- || feedback?.state === ChallengeFeedbackStatus.TruthUnknown
+ const shouldHideConfirm =
+ feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded ||
+ feedback?.state === ChallengeFeedbackStatus.Redirect ||
+ feedback?.state === ChallengeFeedbackStatus.Unsupported ||
+ feedback?.state === ChallengeFeedbackStatus.TruthUnknown;
return (
<AnastasisClientFrame hideNav title="Add email authentication">
<SolveOverviewFeedbackDisplay feedback={feedback} />
<p>
- An sms has been sent to "<b>{selectedChallenge.instructions}</b>". Type the code
- below
+ An sms has been sent to "<b>{selectedChallenge.instructions}</b>". Type
+ the code below
</p>
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
@@ -97,9 +104,11 @@ export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode {
<button class="button" onClick={onCancel}>
Cancel
</button>
- {!shouldHideConfirm && <AsyncButton class="button is-info" onClick={onNext}>
- Confirm
- </AsyncButton>}
+ {!shouldHideConfirm && (
+ <AsyncButton class="button is-info" onClick={onNext}>
+ Confirm
+ </AsyncButton>
+ )}
</div>
</AnastasisClientFrame>
);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.stories.tsx
index c0a52924c..bc4628828 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.stories.tsx
@@ -16,49 +16,65 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/backup/AuthorizationMethod/AuthMethods/TOTP',
+ title: "Pages/backup/AuthorizationMethod/AuthMethods/TOTP",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'totp'
+const type: KnownAuthMethods = "totp";
-export const Empty = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: []
-});
-export const WithOneExample = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Enter 8 digits code for "Anastasis"',
- remove: () => null
- }]
-});
-export const WithMoreExample = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: 'Enter 8 digits code for "Anastasis1"',
- remove: () => null
- },{
- challenge: 'qwe',
- type,
- instructions: 'Enter 8 digits code for "Anastasis2"',
- remove: () => null
- }]
-});
+export const Empty = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [],
+ },
+);
+export const WithOneExample = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: 'Enter 8 digits code for "Anastasis"',
+ remove: () => null,
+ },
+ ],
+ },
+);
+export const WithMoreExample = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: 'Enter 8 digits code for "Anastasis1"',
+ remove: () => null,
+ },
+ {
+ challenge: "qwe",
+ type,
+ instructions: 'Enter 8 digits code for "Anastasis2"',
+ remove: () => null,
+ },
+ ],
+ },
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx
index a8ac499b2..1451aadc8 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx
@@ -1,7 +1,4 @@
-import {
- encodeCrock,
- stringToBytes
-} from "@gnu-taler/taler-util";
+import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util";
import { h, VNode } from "preact";
import { useMemo, useState } from "preact/hooks";
import { AuthMethodSetupProps } from "./index";
@@ -10,30 +7,37 @@ import { TextInput } from "../../../components/fields/TextInput";
import { QR } from "../../../components/QR";
import { base32enc, computeTOTPandCheck } from "./totp";
-export function AuthMethodTotpSetup({ addAuthMethod, cancel, configured }: AuthMethodSetupProps): VNode {
+export function AuthMethodTotpSetup({
+ addAuthMethod,
+ cancel,
+ configured,
+}: AuthMethodSetupProps): VNode {
const [name, setName] = useState("anastasis");
const [test, setTest] = useState("");
- const digits = 8
+ const digits = 8;
const secretKey = useMemo(() => {
- const array = new Uint8Array(32)
- return window.crypto.getRandomValues(array)
- }, [])
+ const array = new Uint8Array(32);
+ return window.crypto.getRandomValues(array);
+ }, []);
const secret32 = base32enc(secretKey);
- const totpURL = `otpauth://totp/${name}?digits=${digits}&secret=${secret32}`
+ const totpURL = `otpauth://totp/${name}?digits=${digits}&secret=${secret32}`;
- const addTotpAuth = (): void => addAuthMethod({
- authentication_method: {
- type: "totp",
- instructions: `Enter ${digits} digits code for "${name}"`,
- challenge: encodeCrock(stringToBytes(totpURL)),
- },
- });
+ const addTotpAuth = (): void =>
+ addAuthMethod({
+ authentication_method: {
+ type: "totp",
+ instructions: `Enter ${digits} digits code for "${name}"`,
+ challenge: encodeCrock(stringToBytes(totpURL)),
+ },
+ });
const testCodeMatches = computeTOTPandCheck(secretKey, 8, parseInt(test, 10));
- const errors = !name ? 'The TOTP name is missing' : (
- !testCodeMatches ? 'The test code doesnt match' : undefined
- );
+ const errors = !name
+ ? "The TOTP name is missing"
+ : !testCodeMatches
+ ? "The test code doesnt match"
+ : undefined;
return (
<AnastasisClientFrame hideNav title="Add TOTP authentication">
<p>
@@ -42,10 +46,7 @@ export function AuthMethodTotpSetup({ addAuthMethod, cancel, configured }: AuthM
with your TOTP App to import the TOTP secret into your TOTP App.
</p>
<div class="block">
- <TextInput
- label="TOTP Name"
- grabFocus
- bind={[name, setName]} />
+ <TextInput label="TOTP Name" grabFocus bind={[name, setName]} />
</div>
<div style={{ height: 300 }}>
<QR text={totpURL} />
@@ -53,25 +54,51 @@ export function AuthMethodTotpSetup({ addAuthMethod, cancel, configured }: AuthM
<p>
After scanning the code with your TOTP App, test it in the input below.
</p>
- <TextInput
- label="Test code"
- bind={[test, setTest]} />
- {configured.length > 0 && <section class="section">
- <div class="block">
- Your TOTP numbers:
- </div><div class="block">
- {configured.map((c, i) => {
- return <div key={i} class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
- <p style={{ marginTop: 'auto', marginBottom: 'auto' }}>{c.instructions}</p>
- <div><button class="button is-danger" onClick={c.remove}>Delete</button></div>
- </div>
- })}
- </div></section>}
+ <TextInput label="Test code" bind={[test, setTest]} />
+ {configured.length > 0 && (
+ <section class="section">
+ <div class="block">Your TOTP numbers:</div>
+ <div class="block">
+ {configured.map((c, i) => {
+ return (
+ <div
+ key={i}
+ class="box"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
+ <p style={{ marginTop: "auto", marginBottom: "auto" }}>
+ {c.instructions}
+ </p>
+ <div>
+ <button class="button is-danger" onClick={c.remove}>
+ Delete
+ </button>
+ </div>
+ </div>
+ );
+ })}
+ </div>
+ </section>
+ )}
<div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={cancel}>Cancel</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={cancel}>
+ Cancel
+ </button>
<span data-tooltip={errors}>
- <button class="button is-info" disabled={errors !== undefined} onClick={addTotpAuth}>Add</button>
+ <button
+ class="button is-info"
+ disabled={errors !== undefined}
+ onClick={addTotpAuth}
+ >
+ Add
+ </button>
</span>
</div>
</div>
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.stories.tsx
index a301931b2..8743c5a73 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.stories.tsx
@@ -15,42 +15,46 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ChallengeFeedbackStatus, ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ChallengeFeedbackStatus, ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/recovery/SolveChallenge/AuthMethods/totp',
+ title: "Pages/recovery/SolveChallenge/AuthMethods/totp",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'totp'
-
-export const WithoutFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'uuid-1'
- }],
- policies: [],
+const type: KnownAuthMethods = "totp";
+
+export const WithoutFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "uuid-1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "uuid-1",
+ } as ReducerState,
+ {
+ id: "uuid-1",
},
- selected_challenge_uuid: 'uuid-1',
-} as ReducerState, {
- id: 'uuid-1',
-});
-
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx
index 30fc44f0e..98c2e51df 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx
@@ -44,8 +44,16 @@ export function AuthMethodTotpSolve({ id }: AuthMethodSolveProps): VNode {
return (
<AnastasisClientFrame hideNav title="Recovery problem">
<div>invalid state</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
</AnastasisClientFrame>
);
@@ -62,8 +70,7 @@ export function AuthMethodTotpSolve({ id }: AuthMethodSolveProps): VNode {
challenges[ch.uuid] = ch;
}
const selectedChallenge = challenges[selectedUuid];
- const feedback = challengeFeedback[selectedUuid]
-
+ const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> {
return reducer?.transition("solve_challenge", { answer });
@@ -72,18 +79,16 @@ export function AuthMethodTotpSolve({ id }: AuthMethodSolveProps): VNode {
reducer?.back();
}
-
- const shouldHideConfirm = feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded
- || feedback?.state === ChallengeFeedbackStatus.Redirect
- || feedback?.state === ChallengeFeedbackStatus.Unsupported
- || feedback?.state === ChallengeFeedbackStatus.TruthUnknown
+ const shouldHideConfirm =
+ feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded ||
+ feedback?.state === ChallengeFeedbackStatus.Redirect ||
+ feedback?.state === ChallengeFeedbackStatus.Unsupported ||
+ feedback?.state === ChallengeFeedbackStatus.TruthUnknown;
return (
<AnastasisClientFrame hideNav title="Add email authentication">
<SolveOverviewFeedbackDisplay feedback={feedback} />
- <p>
- enter the totp solution
- </p>
+ <p>enter the totp solution</p>
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
<div
@@ -96,9 +101,11 @@ export function AuthMethodTotpSolve({ id }: AuthMethodSolveProps): VNode {
<button class="button" onClick={onCancel}>
Cancel
</button>
- {!shouldHideConfirm && <AsyncButton class="button is-info" onClick={onNext}>
- Confirm
- </AsyncButton>}
+ {!shouldHideConfirm && (
+ <AsyncButton class="button is-info" onClick={onNext}>
+ Confirm
+ </AsyncButton>
+ )}
</div>
</AnastasisClientFrame>
);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.stories.tsx
index 52e897c60..4aad0a097 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.stories.tsx
@@ -16,51 +16,68 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
-import logoImage from '../../../assets/logo.jpeg'
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
+import logoImage from "../../../assets/logo.jpeg";
export default {
- title: 'Pages/backup/AuthorizationMethod/AuthMethods/Video',
+ title: "Pages/backup/AuthorizationMethod/AuthMethods/Video",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'video'
+const type: KnownAuthMethods = "video";
-export const Empty = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: []
-});
+export const Empty = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [],
+ },
+);
-export const WithOneExample = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: logoImage,
- remove: () => null
- }]
-});
+export const WithOneExample = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: logoImage,
+ remove: () => null,
+ },
+ ],
+ },
+);
-export const WithMoreExamples = createExample(TestedComponent[type].setup, reducerStatesExample.authEditing, {
- configured: [{
- challenge: 'qwe',
- type,
- instructions: logoImage,
- remove: () => null
- },{
- challenge: 'qwe',
- type,
- instructions: logoImage,
- remove: () => null
- }]
-});
+export const WithMoreExamples = createExample(
+ TestedComponent[type].setup,
+ reducerStatesExample.authEditing,
+ {
+ configured: [
+ {
+ challenge: "qwe",
+ type,
+ instructions: logoImage,
+ remove: () => null,
+ },
+ {
+ challenge: "qwe",
+ type,
+ instructions: logoImage,
+ remove: () => null,
+ },
+ ],
+ },
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.tsx
index 22abe4a49..672b23500 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.tsx
@@ -1,53 +1,86 @@
-import {
- encodeCrock,
- stringToBytes
-} from "@gnu-taler/taler-util";
+import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util";
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { ImageInput } from "../../../components/fields/ImageInput";
import { AuthMethodSetupProps } from "./index";
import { AnastasisClientFrame } from "../index";
-export function AuthMethodVideoSetup({cancel, addAuthMethod, configured}: AuthMethodSetupProps): VNode {
+export function AuthMethodVideoSetup({
+ cancel,
+ addAuthMethod,
+ configured,
+}: AuthMethodSetupProps): VNode {
const [image, setImage] = useState("");
const addVideoAuth = (): void => {
addAuthMethod({
authentication_method: {
type: "video",
- instructions: 'Join a video call',
+ instructions: "Join a video call",
challenge: encodeCrock(stringToBytes(image)),
},
- })
+ });
};
return (
<AnastasisClientFrame hideNav title="Add video authentication">
<p>
- For video identification, you need to provide a passport-style
- photograph. When recovering your secret, you will be asked to join a
- video call. During that call, a human will use the photograph to
- verify your identity.
+ For video identification, you need to provide a passport-style
+ photograph. When recovering your secret, you will be asked to join a
+ video call. During that call, a human will use the photograph to verify
+ your identity.
</p>
- <div style={{textAlign:'center'}}>
+ <div style={{ textAlign: "center" }}>
<ImageInput
label="Choose photograph"
grabFocus
- bind={[image, setImage]} />
+ bind={[image, setImage]}
+ />
</div>
- {configured.length > 0 && <section class="section">
+ {configured.length > 0 && (
+ <section class="section">
+ <div class="block">Your photographs:</div>
<div class="block">
- Your photographs:
- </div><div class="block">
{configured.map((c, i) => {
- return <div key={i} class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
- <img style={{ marginTop: 'auto', marginBottom: 'auto', width: 100, height:100, border: 'solid 1px black' }} src={c.instructions} />
- <div style={{marginTop: 'auto', marginBottom: 'auto'}}><button class="button is-danger" onClick={c.remove}>Delete</button></div>
- </div>
+ return (
+ <div
+ key={i}
+ class="box"
+ style={{ display: "flex", justifyContent: "space-between" }}
+ >
+ <img
+ style={{
+ marginTop: "auto",
+ marginBottom: "auto",
+ width: 100,
+ height: 100,
+ border: "solid 1px black",
+ }}
+ src={c.instructions}
+ />
+ <div style={{ marginTop: "auto", marginBottom: "auto" }}>
+ <button class="button is-danger" onClick={c.remove}>
+ Delete
+ </button>
+ </div>
+ </div>
+ );
})}
- </div></section>}
+ </div>
+ </section>
+ )}
<div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={cancel}>Cancel</button>
- <button class="button is-info" onClick={addVideoAuth}>Add</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={cancel}>
+ Cancel
+ </button>
+ <button class="button is-info" onClick={addVideoAuth}>
+ Add
+ </button>
</div>
</div>
</AnastasisClientFrame>
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.stories.tsx
index 5c4976b87..7c5511c5a 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.stories.tsx
@@ -15,42 +15,46 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { ChallengeFeedbackStatus, ReducerState } from 'anastasis-core';
-import { createExample, reducerStatesExample } from '../../../utils';
-import { authMethods as TestedComponent, KnownAuthMethods } from './index';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { ChallengeFeedbackStatus, ReducerState } from "anastasis-core";
+import { createExample, reducerStatesExample } from "../../../utils";
+import { authMethods as TestedComponent, KnownAuthMethods } from "./index";
export default {
- title: 'Pages/recovery/SolveChallenge/AuthMethods/video',
+ title: "Pages/recovery/SolveChallenge/AuthMethods/video",
component: TestedComponent,
args: {
order: 5,
},
argTypes: {
- onUpdate: { action: 'onUpdate' },
- onBack: { action: 'onBack' },
+ onUpdate: { action: "onUpdate" },
+ onBack: { action: "onBack" },
},
};
-const type: KnownAuthMethods = 'video'
-
-export const WithoutFeedback = createExample(TestedComponent[type].solve, {
- ...reducerStatesExample.challengeSolving,
- recovery_information: {
- challenges: [{
- cost: 'USD:1',
- instructions: 'does P equals NP?',
- type: 'question',
- uuid: 'uuid-1'
- }],
- policies: [],
+const type: KnownAuthMethods = "video";
+
+export const WithoutFeedback = createExample(
+ TestedComponent[type].solve,
+ {
+ ...reducerStatesExample.challengeSolving,
+ recovery_information: {
+ challenges: [
+ {
+ cost: "USD:1",
+ instructions: "does P equals NP?",
+ type: "question",
+ uuid: "uuid-1",
+ },
+ ],
+ policies: [],
+ },
+ selected_challenge_uuid: "uuid-1",
+ } as ReducerState,
+ {
+ id: "uuid-1",
},
- selected_challenge_uuid: 'uuid-1',
-} as ReducerState, {
- id: 'uuid-1',
-});
-
+);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.tsx
index 79401028a..efadb9a9a 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSolve.tsx
@@ -44,8 +44,16 @@ export function AuthMethodVideoSolve({ id }: AuthMethodSolveProps): VNode {
return (
<AnastasisClientFrame hideNav title="Recovery problem">
<div>invalid state</div>
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={() => reducer.back()}>Back</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={() => reducer.back()}>
+ Back
+ </button>
</div>
</AnastasisClientFrame>
);
@@ -62,8 +70,7 @@ export function AuthMethodVideoSolve({ id }: AuthMethodSolveProps): VNode {
challenges[ch.uuid] = ch;
}
const selectedChallenge = challenges[selectedUuid];
- const feedback = challengeFeedback[selectedUuid]
-
+ const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> {
return reducer?.transition("solve_challenge", { answer });
@@ -72,18 +79,16 @@ export function AuthMethodVideoSolve({ id }: AuthMethodSolveProps): VNode {
reducer?.back();
}
-
- const shouldHideConfirm = feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded
- || feedback?.state === ChallengeFeedbackStatus.Redirect
- || feedback?.state === ChallengeFeedbackStatus.Unsupported
- || feedback?.state === ChallengeFeedbackStatus.TruthUnknown
+ const shouldHideConfirm =
+ feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded ||
+ feedback?.state === ChallengeFeedbackStatus.Redirect ||
+ feedback?.state === ChallengeFeedbackStatus.Unsupported ||
+ feedback?.state === ChallengeFeedbackStatus.TruthUnknown;
return (
<AnastasisClientFrame hideNav title="Add email authentication">
<SolveOverviewFeedbackDisplay feedback={feedback} />
- <p>
- You are gonna be called to check your identity
- </p>
+ <p>You are gonna be called to check your identity</p>
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
<div
@@ -96,9 +101,11 @@ export function AuthMethodVideoSolve({ id }: AuthMethodSolveProps): VNode {
<button class="button" onClick={onCancel}>
Cancel
</button>
- {!shouldHideConfirm && <AsyncButton class="button is-info" onClick={onNext}>
- Confirm
- </AsyncButton>}
+ {!shouldHideConfirm && (
+ <AsyncButton class="button is-info" onClick={onNext}>
+ Confirm
+ </AsyncButton>
+ )}
</div>
</AnastasisClientFrame>
);
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/index.tsx b/packages/anastasis-webui/src/pages/home/authMethod/index.tsx
index 8b0126ce7..b4f649488 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/index.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/index.tsx
@@ -1,9 +1,9 @@
import { AuthMethod } from "anastasis-core";
import { h, VNode } from "preact";
-import postalIcon from '../../../assets/icons/auth_method/postal.svg';
-import questionIcon from '../../../assets/icons/auth_method/question.svg';
-import smsIcon from '../../../assets/icons/auth_method/sms.svg';
-import videoIcon from '../../../assets/icons/auth_method/video.svg';
+import postalIcon from "../../../assets/icons/auth_method/postal.svg";
+import questionIcon from "../../../assets/icons/auth_method/question.svg";
+import smsIcon from "../../../assets/icons/auth_method/sms.svg";
+import videoIcon from "../../../assets/icons/auth_method/video.svg";
import { AuthMethodEmailSetup as EmailSetup } from "./AuthMethodEmailSetup";
import { AuthMethodEmailSolve as EmailSolve } from "./AuthMethodEmailSolve";
import { AuthMethodIbanSetup as IbanSetup } from "./AuthMethodIbanSetup";
@@ -20,8 +20,7 @@ import { AuthMethodSmsSolve as SmsSolve } from "./AuthMethodSmsSolve";
import { AuthMethodTotpSolve as TotpSolve } from "./AuthMethodTotpSolve";
import { AuthMethodVideoSolve as VideoSolve } from "./AuthMethodVideoSolve";
-
-export type AuthMethodWithRemove = AuthMethod & { remove: () => void }
+export type AuthMethodWithRemove = AuthMethod & { remove: () => void };
export interface AuthMethodSetupProps {
method: string;
@@ -43,10 +42,18 @@ interface AuthMethodConfiguration {
}
// export type KnownAuthMethods = "sms" | "email" | "post" | "question" | "video" | "totp" | "iban";
-const ALL_METHODS = ['sms', 'email', 'post', 'question', 'video' , 'totp', 'iban'] as const;
-export type KnownAuthMethods = (typeof ALL_METHODS)[number];
+const ALL_METHODS = [
+ "sms",
+ "email",
+ "post",
+ "question",
+ "video",
+ "totp",
+ "iban",
+] as const;
+export type KnownAuthMethods = typeof ALL_METHODS[number];
export function isKnownAuthMethods(value: string): value is KnownAuthMethods {
- return ALL_METHODS.includes(value as KnownAuthMethods)
+ return ALL_METHODS.includes(value as KnownAuthMethods);
}
type KnowMethodConfig = {
@@ -96,5 +103,5 @@ export const authMethods: KnowMethodConfig = {
setup: VideoSetup,
solve: VideoSolve,
skip: true,
- }
-} \ No newline at end of file
+ },
+};
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/totp.ts b/packages/anastasis-webui/src/pages/home/authMethod/totp.ts
index 0bc3feaf8..c2288671c 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/totp.ts
+++ b/packages/anastasis-webui/src/pages/home/authMethod/totp.ts
@@ -1,54 +1,61 @@
/* eslint-disable @typescript-eslint/camelcase */
-import jssha from 'jssha'
+import jssha from "jssha";
-const SEARCH_RANGE = 16
-const timeStep = 30
+const SEARCH_RANGE = 16;
+const timeStep = 30;
-export function computeTOTPandCheck(secretKey: Uint8Array, digits: number, code: number): boolean {
- const now = new Date().getTime()
+export function computeTOTPandCheck(
+ secretKey: Uint8Array,
+ digits: number,
+ code: number,
+): boolean {
+ const now = new Date().getTime();
const epoch = Math.floor(Math.round(now / 1000.0) / timeStep);
for (let ms = -SEARCH_RANGE; ms < SEARCH_RANGE; ms++) {
const movingFactor = (epoch + ms).toString(16).padStart(16, "0");
- const hmacSha = new jssha('SHA-1', 'HEX', { hmacKey: { value: secretKey, format: 'UINT8ARRAY' } });
+ const hmacSha = new jssha("SHA-1", "HEX", {
+ hmacKey: { value: secretKey, format: "UINT8ARRAY" },
+ });
hmacSha.update(movingFactor);
- const hmac_text = hmacSha.getHMAC('UINT8ARRAY');
+ const hmac_text = hmacSha.getHMAC("UINT8ARRAY");
- const offset = (hmac_text[hmac_text.length - 1] & 0xf)
+ const offset = hmac_text[hmac_text.length - 1] & 0xf;
- const otp = ((
- (hmac_text[offset + 0] << 24) +
- (hmac_text[offset + 1] << 16) +
- (hmac_text[offset + 2] << 8) +
- (hmac_text[offset + 3])
- ) & 0x7fffffff) % Math.pow(10, digits)
+ const otp =
+ (((hmac_text[offset + 0] << 24) +
+ (hmac_text[offset + 1] << 16) +
+ (hmac_text[offset + 2] << 8) +
+ hmac_text[offset + 3]) &
+ 0x7fffffff) %
+ Math.pow(10, digits);
- if (otp == code) return true
+ if (otp == code) return true;
}
- return false
+ return false;
}
-const encTable__ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".split('')
+const encTable__ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".split("");
export function base32enc(buffer: Uint8Array): string {
- let rpos = 0
- let bits = 0
- let vbit = 0
+ let rpos = 0;
+ let bits = 0;
+ let vbit = 0;
- let result = ""
- while ((rpos < buffer.length) || (vbit > 0)) {
- if ((rpos < buffer.length) && (vbit < 5)) {
+ let result = "";
+ while (rpos < buffer.length || vbit > 0) {
+ if (rpos < buffer.length && vbit < 5) {
bits = (bits << 8) | buffer[rpos++];
vbit += 8;
}
if (vbit < 5) {
- bits <<= (5 - vbit);
+ bits <<= 5 - vbit;
vbit = 5;
}
result += encTable__[(bits >> (vbit - 5)) & 31];
vbit -= 5;
}
- return result
+ return result;
}
// const array = new Uint8Array(256)
diff --git a/packages/anastasis-webui/src/pages/notfound/index.tsx b/packages/anastasis-webui/src/pages/notfound/index.tsx
index 4e74d1d9f..bb22429b0 100644
--- a/packages/anastasis-webui/src/pages/notfound/index.tsx
+++ b/packages/anastasis-webui/src/pages/notfound/index.tsx
@@ -1,16 +1,16 @@
-import { FunctionalComponent, h } from 'preact';
-import { Link } from 'preact-router/match';
+import { FunctionalComponent, h } from "preact";
+import { Link } from "preact-router/match";
const Notfound: FunctionalComponent = () => {
- return (
- <div>
- <h1>Error 404</h1>
- <p>That page doesn&apos;t exist.</p>
- <Link href="/">
- <h4>Back to Home</h4>
- </Link>
- </div>
- );
+ return (
+ <div>
+ <h1>Error 404</h1>
+ <p>That page doesn&apos;t exist.</p>
+ <Link href="/">
+ <h4>Back to Home</h4>
+ </Link>
+ </div>
+ );
};
export default Notfound;
diff --git a/packages/anastasis-webui/src/pages/profile/index.tsx b/packages/anastasis-webui/src/pages/profile/index.tsx
index 859a83ed4..bcd26370e 100644
--- a/packages/anastasis-webui/src/pages/profile/index.tsx
+++ b/packages/anastasis-webui/src/pages/profile/index.tsx
@@ -1,43 +1,42 @@
-import { FunctionalComponent, h } from 'preact';
-import { useEffect, useState } from 'preact/hooks';
+import { FunctionalComponent, h } from "preact";
+import { useEffect, useState } from "preact/hooks";
interface Props {
- user: string;
+ user: string;
}
const Profile: FunctionalComponent<Props> = (props: Props) => {
- const { user } = props;
- const [time, setTime] = useState<number>(Date.now());
- const [count, setCount] = useState<number>(0);
-
- // gets called when this route is navigated to
- useEffect(() => {
- const timer = window.setInterval(() => setTime(Date.now()), 1000);
-
- // gets called just before navigating away from the route
- return (): void => {
- clearInterval(timer);
- };
- }, []);
-
- // update the current time
- const increment = (): void => {
- setCount(count + 1);
+ const { user } = props;
+ const [time, setTime] = useState<number>(Date.now());
+ const [count, setCount] = useState<number>(0);
+
+ // gets called when this route is navigated to
+ useEffect(() => {
+ const timer = window.setInterval(() => setTime(Date.now()), 1000);
+
+ // gets called just before navigating away from the route
+ return (): void => {
+ clearInterval(timer);
};
+ }, []);
+
+ // update the current time
+ const increment = (): void => {
+ setCount(count + 1);
+ };
- return (
- <div>
- <h1>Profile: {user}</h1>
- <p>This is the user profile for a user named {user}.</p>
+ return (
+ <div>
+ <h1>Profile: {user}</h1>
+ <p>This is the user profile for a user named {user}.</p>
- <div>Current time: {new Date(time).toLocaleString()}</div>
+ <div>Current time: {new Date(time).toLocaleString()}</div>
- <p>
- <button onClick={increment}>Click Me</button> Clicked {count}{' '}
- times.
- </p>
- </div>
- );
+ <p>
+ <button onClick={increment}>Click Me</button> Clicked {count} times.
+ </p>
+ </div>
+ );
};
export default Profile;
diff --git a/packages/anastasis-webui/src/template.html b/packages/anastasis-webui/src/template.html
index 351f1829c..2a216916e 100644
--- a/packages/anastasis-webui/src/template.html
+++ b/packages/anastasis-webui/src/template.html
@@ -1,15 +1,56 @@
+<!--
+ 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
+-->
<!DOCTYPE html>
-<html lang="en" class="has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded">
- <head>
- <meta charset="utf-8">
- <title><% preact.title %></title>
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <meta name="mobile-web-app-capable" content="yes">
- <meta name="apple-mobile-web-app-capable" content="yes">
- <link rel="apple-touch-icon" href="/assets/icons/apple-touch-icon.png">
- <% preact.headEnd %>
- </head>
- <body>
- <% preact.bodyEnd %>
- </body>
+<html
+ lang="en"
+ class="has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded"
+>
+ <head>
+ <meta charset="utf-8" />
+ <title><%= htmlWebpackPlugin.options.title %></title>
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
+ <meta name="mobile-web-app-capable" content="yes" />
+ <meta name="apple-mobile-web-app-capable" content="yes" />
+
+ <link
+ rel="icon"
+ href="data:;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////////////7//v38//78/P/+/fz//vz7///+/v/+/f3//vz7///+/v/+/fz//v38///////////////////////+/v3///7+/////////////////////////////////////////////////////////v3//v79///////+/v3///////r28v/ct5//06SG/9Gffv/Xqo7/7N/V/9e2nf/bsJb/6uDW/9Sskf/euKH/+/j2///////+/v3//////+3azv+/eE3/2rWd/9Kkhv/Vr5T/48i2/8J+VP/Qn3//3ryn/795Tf/WrpP/2LCW/8B6T//w4Nb///////Pn4P+/d0v/9u3n/+7d0v/EhV7//v///+HDr//fxLD/zph2/+TJt//8/Pv/woBX//Lm3f/y5dz/v3hN//bu6f/JjGn/4sW0///////Df1j/8OLZ//v6+P+/elH/+vj1//jy7f+/elL//////+zYzP/Eg13//////967p//MlHT/wn5X///////v4Nb/yY1s///////jw7H/06KG////////////z5t9/+fNvf//////x4pn//Pp4v/8+vn/w39X/8WEX///////5s/A/9CbfP//////27Oc/9y2n////////////9itlf/gu6f//////86Vdf/r2Mz//////8SCXP/Df1j//////+7d0v/KkG7//////+HBrf/VpYr////////////RnoH/5sq6///////Ii2n/8ubf//39/P/Cf1j/xohk/+bNvv//////wn5W//Tq4//58/D/wHxV//7+/f/59fH/v3xU//39/P/w4Nf/xIFb///////hw7H/yo9t/+/f1f/AeU3/+/n2/+nSxP/FhmD//////9qzm//Upon/4MSx/96+qf//////xINc/+3bz//48e3/v3hN//Pn3///////6M+//752S//gw6//06aK/8J+VP/kzLr/zZd1/8OCWv/q18r/17KZ/9Ooi//fv6r/v3dK/+vWyP///////v39///////27un/1aeK/9Opjv/m1cf/1KCC/9a0nP/n08T/0Jx8/82YdP/QnHz/16yR//jx7P///////v39///////+/f3///7+///////+//7//v7+///////+/v7//v/+/////////////////////////v7//v79///////////////////+/v/+/Pv//v39///+/v/+/Pv///7+//7+/f/+/Pv//v39//79/P/+/Pv///7+////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
+ />
+ <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
+
+ <% if (htmlWebpackPlugin.options.manifest.theme_color) { %>
+ <meta
+ name="theme-color"
+ content="<%= htmlWebpackPlugin.options.manifest.theme_color %>"
+ />
+ <% } %> <% for (const index in htmlWebpackPlugin.files.css) { %> <% const
+ file = htmlWebpackPlugin.files.css[index] %>
+ <style data-href="<%= file %>">
+ <%= compilation.assets[file.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
+ </style>
+ <% } %>
+ </head>
+ <body>
+ <script>
+ <%= compilation.assets[htmlWebpackPlugin.files.chunks["polyfills"].entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
+ </script>
+ <script>
+ <%= compilation.assets[htmlWebpackPlugin.files.chunks["bundle"].entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
+ </script>
+ </body>
</html>
diff --git a/packages/anastasis-webui/src/utils/index.tsx b/packages/anastasis-webui/src/utils/index.tsx
index 9c01aa6ba..04cc8c921 100644
--- a/packages/anastasis-webui/src/utils/index.tsx
+++ b/packages/anastasis-webui/src/utils/index.tsx
@@ -1,45 +1,67 @@
/* eslint-disable @typescript-eslint/camelcase */
-import { BackupStates, RecoveryStates, ReducerState } from 'anastasis-core';
-import { FunctionalComponent, h, VNode } from 'preact';
-import { AnastasisProvider } from '../context/anastasis';
+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 } {
+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: async () => { null },
- dismissError: async () => { null },
- reset: () => { null },
- runTransaction: async () => { null },
- startBackup: () => { null },
- startRecover: () => { null },
- transition: async () => { null },
- }}>
- <Component {...args} />
- </AnastasisProvider>
- }
- r.args = props
- return r
+ return (
+ <AnastasisProvider
+ value={{
+ currentReducerState,
+ currentError: undefined,
+ back: async () => {
+ null;
+ },
+ dismissError: async () => {
+ null;
+ },
+ reset: () => {
+ null;
+ },
+ runTransaction: async () => {
+ null;
+ },
+ startBackup: () => {
+ null;
+ },
+ startRecover: () => {
+ null;
+ },
+ transition: async () => {
+ null;
+ },
+ }}
+ >
+ <Component {...args} />
+ </AnastasisProvider>
+ );
+ };
+ r.args = props;
+ return r;
}
const base = {
continents: [
{
- name: "Europe"
+ name: "Europe",
},
{
- name: "India"
+ name: "India",
},
{
- name: "Asia"
+ name: "Asia",
},
{
- name: "North America"
+ name: "North America",
},
{
- name: "Testcontinent"
- }
+ name: "Testcontinent",
+ },
],
countries: [
{
@@ -47,33 +69,33 @@ const base = {
name: "Testland",
continent: "Testcontinent",
continent_i18n: {
- de_DE: "Testkontinent"
+ de_DE: "Testkontinent",
},
name_i18n: {
de_DE: "Testlandt",
de_CH: "Testlandi",
fr_FR: "Testpais",
- en_UK: "Testland"
+ en_UK: "Testland",
},
currency: "TESTKUDOS",
- call_code: "+00"
+ call_code: "+00",
},
{
code: "xy",
name: "Demoland",
continent: "Testcontinent",
continent_i18n: {
- de_DE: "Testkontinent"
+ de_DE: "Testkontinent",
},
name_i18n: {
de_DE: "Demolandt",
de_CH: "Demolandi",
fr_FR: "Demopais",
- en_UK: "Demoland"
+ en_UK: "Demoland",
},
currency: "KUDOS",
- call_code: "+01"
- }
+ call_code: "+01",
+ },
],
authentication_providers: {
"http://localhost:8086/": {
@@ -85,18 +107,20 @@ const base = {
methods: [
{
type: "question",
- usage_fee: "COL:0"
- }, {
+ usage_fee: "COL:0",
+ },
+ {
type: "sms",
- usage_fee: "COL:0"
- }, {
+ usage_fee: "COL:0",
+ },
+ {
type: "email",
- usage_fee: "COL:0"
+ usage_fee: "COL:0",
},
],
salt: "WBMDD76BR1E90YQ5AHBMKPH7GW",
storage_limit_in_megabytes: 16,
- truth_upload_fee: "COL:0"
+ truth_upload_fee: "COL:0",
},
"https://kudos.demo.anastasis.lu/": {
http_status: 200,
@@ -107,15 +131,16 @@ const base = {
methods: [
{
type: "question",
- usage_fee: "COL:0"
- }, {
+ usage_fee: "COL:0",
+ },
+ {
type: "email",
- usage_fee: "COL:0"
+ usage_fee: "COL:0",
},
],
salt: "WBMDD76BR1E90YQ5AHBMKPH7GW",
storage_limit_in_megabytes: 16,
- truth_upload_fee: "COL:0"
+ truth_upload_fee: "COL:0",
},
"https://anastasis.demo.taler.net/": {
http_status: 200,
@@ -126,43 +151,45 @@ const base = {
methods: [
{
type: "question",
- usage_fee: "COL:0"
- }, {
+ usage_fee: "COL:0",
+ },
+ {
type: "sms",
- usage_fee: "COL:0"
- }, {
+ usage_fee: "COL:0",
+ },
+ {
type: "totp",
- usage_fee: "COL:0"
+ usage_fee: "COL:0",
},
],
salt: "WBMDD76BR1E90YQ5AHBMKPH7GW",
storage_limit_in_megabytes: 16,
- truth_upload_fee: "COL:0"
+ truth_upload_fee: "COL:0",
},
"http://localhost:8087/": {
code: 8414,
- hint: "request to provider failed"
+ hint: "request to provider failed",
},
"http://localhost:8088/": {
code: 8414,
- hint: "request to provider failed"
+ hint: "request to provider failed",
},
"http://localhost:8089/": {
code: 8414,
- hint: "request to provider failed"
- }
+ hint: "request to provider failed",
+ },
},
// expiration: {
// d_ms: 1792525051855 // check t_ms
// },
-} as Partial<ReducerState>
+} as Partial<ReducerState>;
export const reducerStatesExample = {
initial: undefined,
recoverySelectCountry: {
...base,
- recovery_state: RecoveryStates.CountrySelecting
+ recovery_state: RecoveryStates.CountrySelecting,
} as ReducerState,
recoverySelectContinent: {
...base,
@@ -190,11 +217,11 @@ export const reducerStatesExample = {
} as ReducerState,
recoveryAttributeEditing: {
...base,
- recovery_state: RecoveryStates.UserAttributesCollecting
+ recovery_state: RecoveryStates.UserAttributesCollecting,
} as ReducerState,
backupSelectCountry: {
...base,
- backup_state: BackupStates.CountrySelecting
+ backup_state: BackupStates.CountrySelecting,
} as ReducerState,
backupSelectContinent: {
...base,
@@ -218,15 +245,14 @@ export const reducerStatesExample = {
} as ReducerState,
authEditing: {
...base,
- backup_state: BackupStates.AuthenticationsEditing
+ backup_state: BackupStates.AuthenticationsEditing,
} as ReducerState,
backupAttributeEditing: {
...base,
- backup_state: BackupStates.UserAttributesCollecting
+ backup_state: BackupStates.UserAttributesCollecting,
} as ReducerState,
truthsPaying: {
...base,
- backup_state: BackupStates.TruthsPaying
+ backup_state: BackupStates.TruthsPaying,
} as ReducerState,
-
-}
+};