feedback state rendering
This commit is contained in:
parent
d43ab6af87
commit
a9d2a4654b
@ -46,10 +46,10 @@ function messageStyle(type: MessageType): string {
|
|||||||
|
|
||||||
export function Notifications({ notifications, removeNotification }: Props): VNode {
|
export function Notifications({ notifications, removeNotification }: Props): VNode {
|
||||||
return <div class="block">
|
return <div class="block">
|
||||||
{notifications.map((n,i) => <article key={i} class={messageStyle(n.type)}>
|
{notifications.map((n, i) => <article key={i} class={messageStyle(n.type)}>
|
||||||
<div class="message-header">
|
<div class="message-header">
|
||||||
<p>{n.message}</p>
|
<p>{n.message}</p>
|
||||||
<button class="delete" onClick={() => removeNotification && removeNotification(n)} />
|
{removeNotification && <button class="delete" onClick={() => removeNotification && removeNotification(n)} />}
|
||||||
</div>
|
</div>
|
||||||
{n.description && <div class="message-body">
|
{n.description && <div class="message-body">
|
||||||
{n.description}
|
{n.description}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
|
||||||
/*
|
/*
|
||||||
This file is part of GNU Taler
|
This file is part of GNU Taler
|
||||||
(C) 2021 Taler Systems S.A.
|
(C) 2021 Taler Systems S.A.
|
||||||
@ -20,7 +19,7 @@
|
|||||||
* @author Sebastian Javier Marchano (sebasjm)
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RecoveryStates, ReducerState } from "anastasis-core";
|
import { ChallengeFeedbackStatus, RecoveryStates, ReducerState } from "anastasis-core";
|
||||||
import { createExample, reducerStatesExample } from "../../utils";
|
import { createExample, reducerStatesExample } from "../../utils";
|
||||||
import { ChallengeOverviewScreen as TestedComponent } from "./ChallengeOverviewScreen";
|
import { ChallengeOverviewScreen as TestedComponent } from "./ChallengeOverviewScreen";
|
||||||
|
|
||||||
@ -176,16 +175,15 @@ export const OnePolicyWithAllTheChallengesInDifferentState = createExample(
|
|||||||
recovery_information: {
|
recovery_information: {
|
||||||
policies: [
|
policies: [
|
||||||
[
|
[
|
||||||
{ uuid: "1" },
|
{ uuid: "uuid-1" },
|
||||||
{ uuid: "2" },
|
{ uuid: "uuid-2" },
|
||||||
{ uuid: "3" },
|
{ uuid: "uuid-3" },
|
||||||
{ uuid: "4" },
|
{ uuid: "uuid-4" },
|
||||||
{ uuid: "5" },
|
{ uuid: "uuid-5" },
|
||||||
{ uuid: "6" },
|
{ uuid: "uuid-6" },
|
||||||
{ uuid: "7" },
|
{ uuid: "uuid-7" },
|
||||||
{ uuid: "8" },
|
{ uuid: "uuid-8" },
|
||||||
{ uuid: "9" },
|
{ uuid: "uuid-9" },
|
||||||
{ uuid: "10" },
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
challenges: [
|
challenges: [
|
||||||
@ -193,20 +191,96 @@ export const OnePolicyWithAllTheChallengesInDifferentState = createExample(
|
|||||||
cost: "USD:1",
|
cost: "USD:1",
|
||||||
instructions: 'in state "solved"',
|
instructions: 'in state "solved"',
|
||||||
type: "question",
|
type: "question",
|
||||||
uuid: "1",
|
uuid: "uuid-1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cost: "USD:1",
|
cost: "USD:1",
|
||||||
instructions: 'in state "message"',
|
instructions: 'in state "message"',
|
||||||
type: "question",
|
type: "question",
|
||||||
uuid: "2",
|
uuid: "uuid-2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cost: "USD:1",
|
||||||
|
instructions: 'in state "auth iban"',
|
||||||
|
type: "question",
|
||||||
|
uuid: "uuid-3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cost: "USD:1",
|
||||||
|
instructions: 'in state "payment "',
|
||||||
|
type: "question",
|
||||||
|
uuid: "uuid-4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cost: "USD:1",
|
||||||
|
instructions: 'in state "rate limit"',
|
||||||
|
type: "question",
|
||||||
|
uuid: "uuid-5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cost: "USD:1",
|
||||||
|
instructions: 'in state "redirect"',
|
||||||
|
type: "question",
|
||||||
|
uuid: "uuid-6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cost: "USD:1",
|
||||||
|
instructions: 'in state "server failure"',
|
||||||
|
type: "question",
|
||||||
|
uuid: "uuid-7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cost: "USD:1",
|
||||||
|
instructions: 'in state "truth unknown"',
|
||||||
|
type: "question",
|
||||||
|
uuid: "uuid-8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cost: "USD:1",
|
||||||
|
instructions: 'in state "unsupported"',
|
||||||
|
type: "question",
|
||||||
|
uuid: "uuid-9",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
challenge_feedback: {
|
challenge_feedback: {
|
||||||
1: { state: "solved" },
|
"uuid-1": { state: ChallengeFeedbackStatus.Solved.toString() },
|
||||||
2: { state: "message", message: "Security question was not solved correctly" },
|
"uuid-2": {
|
||||||
// FIXME: add missing feedback states here!
|
state: ChallengeFeedbackStatus.Message.toString(),
|
||||||
|
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"
|
||||||
|
},
|
||||||
|
"uuid-4": {
|
||||||
|
state: ChallengeFeedbackStatus.Payment.toString(),
|
||||||
|
taler_pay_uri: "taler://pay/...",
|
||||||
|
provider: "https://localhost:8080/",
|
||||||
|
payment_secret: "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
|
||||||
|
},
|
||||||
|
"uuid-5": {
|
||||||
|
state: ChallengeFeedbackStatus.RateLimitExceeded.toString(),
|
||||||
|
// "error_code": 8121
|
||||||
|
},
|
||||||
|
"uuid-6": {
|
||||||
|
state: ChallengeFeedbackStatus.Redirect.toString(),
|
||||||
|
redirect_url: "https://videoconf.example.com/",
|
||||||
|
http_status: 303
|
||||||
|
},
|
||||||
|
"uuid-7": {
|
||||||
|
state: ChallengeFeedbackStatus.ServerFailure.toString(),
|
||||||
|
http_status: 500,
|
||||||
|
error_response: "some error message or error object",
|
||||||
|
},
|
||||||
|
"uuid-8": {
|
||||||
|
state: ChallengeFeedbackStatus.TruthUnknown.toString(),
|
||||||
|
// "error_code": 8108
|
||||||
|
},
|
||||||
|
"uuid-9": { state: ChallengeFeedbackStatus.Unsupported.toString() },
|
||||||
},
|
},
|
||||||
} as ReducerState,
|
} as ReducerState,
|
||||||
);
|
);
|
||||||
|
@ -12,27 +12,24 @@ function OverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
|
|||||||
switch (feedback.state) {
|
switch (feedback.state) {
|
||||||
case ChallengeFeedbackStatus.Message:
|
case ChallengeFeedbackStatus.Message:
|
||||||
return (
|
return (
|
||||||
<div>
|
<div class="block has-text-danger">{feedback.message}</div>
|
||||||
<p>{feedback.message}</p>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
|
case ChallengeFeedbackStatus.Solved:
|
||||||
|
return <div />
|
||||||
case ChallengeFeedbackStatus.Pending:
|
case ChallengeFeedbackStatus.Pending:
|
||||||
case ChallengeFeedbackStatus.AuthIban:
|
case ChallengeFeedbackStatus.AuthIban:
|
||||||
return null;
|
return null;
|
||||||
|
case ChallengeFeedbackStatus.ServerFailure:
|
||||||
|
return <div class="block has-text-danger">Server error.</div>;
|
||||||
case ChallengeFeedbackStatus.RateLimitExceeded:
|
case ChallengeFeedbackStatus.RateLimitExceeded:
|
||||||
return <div>Rate limit exceeded.</div>;
|
return <div class="block has-text-danger">There were to many failed attempts.</div>;
|
||||||
case ChallengeFeedbackStatus.Redirect:
|
|
||||||
return <div>Redirect (FIXME: not supported)</div>;
|
|
||||||
case ChallengeFeedbackStatus.Unsupported:
|
case ChallengeFeedbackStatus.Unsupported:
|
||||||
return <div>Challenge not supported by client.</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:
|
case ChallengeFeedbackStatus.TruthUnknown:
|
||||||
return <div>Truth unknown</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:
|
default:
|
||||||
return (
|
return <div />;
|
||||||
<div>
|
|
||||||
<pre>{JSON.stringify(feedback)}</pre>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,6 +110,77 @@ export function ChallengeOverviewScreen(): VNode {
|
|||||||
const tableBody = policy.challenges.map(({ info, uuid }) => {
|
const tableBody = policy.challenges.map(({ info, uuid }) => {
|
||||||
const isFree = !info.cost || info.cost.endsWith(":0");
|
const isFree = !info.cost || info.cost.endsWith(":0");
|
||||||
const method = authMethods[info.type as KnownAuthMethods];
|
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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
function ChallengeButton({ id, feedback }: { id: string; feedback?: ChallengeFeedback }): VNode {
|
||||||
|
function selectChallenge(): void {
|
||||||
|
if (reducer) reducer.transition("select_challenge", { uuid: id })
|
||||||
|
}
|
||||||
|
if (!feedback) {
|
||||||
|
return <div>
|
||||||
|
<button class="button" onClick={selectChallenge}>
|
||||||
|
Solve
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
switch (feedback.state) {
|
||||||
|
case ChallengeFeedbackStatus.ServerFailure:
|
||||||
|
case ChallengeFeedbackStatus.Unsupported:
|
||||||
|
case ChallengeFeedbackStatus.TruthUnknown:
|
||||||
|
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>
|
||||||
|
|
||||||
|
}
|
||||||
|
// 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 (
|
return (
|
||||||
<div
|
<div
|
||||||
key={uuid}
|
key={uuid}
|
||||||
@ -131,21 +199,9 @@ export function ChallengeOverviewScreen(): VNode {
|
|||||||
</div>
|
</div>
|
||||||
<OverviewFeedbackDisplay feedback={info.feedback} />
|
<OverviewFeedbackDisplay feedback={info.feedback} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
{method && info.feedback?.state !== "solved" ? (
|
<ChallengeButton id={uuid} feedback={info.feedback} />
|
||||||
<a
|
|
||||||
class="button"
|
|
||||||
onClick={() =>
|
|
||||||
reducer.transition("select_challenge", { uuid })
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{isFree ? "Solve" : `Pay and Solve`}
|
|
||||||
</a>
|
|
||||||
) : null}
|
|
||||||
{info.feedback?.state === "solved" ? (
|
|
||||||
<a class="button is-success"> Solved </a>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -156,8 +212,8 @@ export function ChallengeOverviewScreen(): VNode {
|
|||||||
const opa = !atLeastThereIsOnePolicySolved
|
const opa = !atLeastThereIsOnePolicySolved
|
||||||
? undefined
|
? undefined
|
||||||
: policy.isPolicySolved
|
: policy.isPolicySolved
|
||||||
? undefined
|
? undefined
|
||||||
: "0.6";
|
: "0.6";
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={policy_index}
|
key={policy_index}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { useAnastasisContext } from "../../context/anastasis";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
@ -104,7 +104,7 @@ 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 [otherProvider, setOtherProvider] = useState<string>(provider);
|
||||||
const [otherVersion, setOtherVersion] = useState(`${version}`);
|
const [otherVersion, setOtherVersion] = useState(version > 0 ? String(version) : "");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame hideNav title="Recovery: Select secret">
|
<AnastasisClientFrame hideNav title="Recovery: Select secret">
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
|
||||||
/*
|
/*
|
||||||
This file is part of GNU Taler
|
This file is part of GNU Taler
|
||||||
(C) 2021 Taler Systems S.A.
|
(C) 2021 Taler Systems S.A.
|
||||||
@ -20,7 +19,7 @@
|
|||||||
* @author Sebastian Javier Marchano (sebasjm)
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ReducerState } from 'anastasis-core';
|
import { ChallengeFeedbackStatus, ReducerState } from 'anastasis-core';
|
||||||
import { createExample, reducerStatesExample } from '../../utils';
|
import { createExample, reducerStatesExample } from '../../utils';
|
||||||
import { SolveScreen as TestedComponent } from './SolveScreen';
|
import { SolveScreen as TestedComponent } from './SolveScreen';
|
||||||
|
|
||||||
@ -50,7 +49,8 @@ export const NotSupportedChallenge = createExample(TestedComponent, {
|
|||||||
}],
|
}],
|
||||||
policies: [],
|
policies: [],
|
||||||
},
|
},
|
||||||
selected_challenge_uuid: 'ASDASDSAD!1'
|
selected_challenge_uuid: 'ASDASDSAD!1',
|
||||||
|
|
||||||
} as ReducerState);
|
} as ReducerState);
|
||||||
|
|
||||||
export const MismatchedChallengeId = createExample(TestedComponent, {
|
export const MismatchedChallengeId = createExample(TestedComponent, {
|
||||||
@ -78,7 +78,8 @@ export const SmsChallenge = createExample(TestedComponent, {
|
|||||||
}],
|
}],
|
||||||
policies: [],
|
policies: [],
|
||||||
},
|
},
|
||||||
selected_challenge_uuid: 'ASDASDSAD!1'
|
selected_challenge_uuid: 'ASDASDSAD!1',
|
||||||
|
|
||||||
} as ReducerState);
|
} as ReducerState);
|
||||||
|
|
||||||
export const QuestionChallenge = createExample(TestedComponent, {
|
export const QuestionChallenge = createExample(TestedComponent, {
|
||||||
@ -92,7 +93,8 @@ export const QuestionChallenge = createExample(TestedComponent, {
|
|||||||
}],
|
}],
|
||||||
policies: [],
|
policies: [],
|
||||||
},
|
},
|
||||||
selected_challenge_uuid: 'ASDASDSAD!1'
|
selected_challenge_uuid: 'ASDASDSAD!1',
|
||||||
|
|
||||||
} as ReducerState);
|
} as ReducerState);
|
||||||
|
|
||||||
export const EmailChallenge = createExample(TestedComponent, {
|
export const EmailChallenge = createExample(TestedComponent, {
|
||||||
@ -106,7 +108,8 @@ export const EmailChallenge = createExample(TestedComponent, {
|
|||||||
}],
|
}],
|
||||||
policies: [],
|
policies: [],
|
||||||
},
|
},
|
||||||
selected_challenge_uuid: 'ASDASDSAD!1'
|
selected_challenge_uuid: 'ASDASDSAD!1',
|
||||||
|
|
||||||
} as ReducerState);
|
} as ReducerState);
|
||||||
|
|
||||||
export const PostChallenge = createExample(TestedComponent, {
|
export const PostChallenge = createExample(TestedComponent, {
|
||||||
@ -120,5 +123,181 @@ export const PostChallenge = createExample(TestedComponent, {
|
|||||||
}],
|
}],
|
||||||
policies: [],
|
policies: [],
|
||||||
},
|
},
|
||||||
selected_challenge_uuid: 'ASDASDSAD!1'
|
selected_challenge_uuid: 'ASDASDSAD!1',
|
||||||
|
|
||||||
} as ReducerState);
|
} as ReducerState);
|
||||||
|
|
||||||
|
|
||||||
|
export const QuestionChallengeMessageFeedback = createExample(TestedComponent, {
|
||||||
|
...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.Message,
|
||||||
|
message: 'Challenge should be solved'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const QuestionChallengeServerFailureFeedback = createExample(TestedComponent, {
|
||||||
|
...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 QuestionChallengeRedirectFeedback = createExample(TestedComponent, {
|
||||||
|
...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.Redirect,
|
||||||
|
http_status: 302,
|
||||||
|
redirect_url: 'http://video.taler.net'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const QuestionChallengeMessageRateLimitExceededFeedback = createExample(TestedComponent, {
|
||||||
|
...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 QuestionChallengeUnsupportedFeedback = createExample(TestedComponent, {
|
||||||
|
...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.Unsupported,
|
||||||
|
http_status: 500,
|
||||||
|
unsupported_method: 'Question'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const QuestionChallengeTruthUnknownFeedback = createExample(TestedComponent, {
|
||||||
|
...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.TruthUnknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const QuestionChallengeAuthIbanFeedback = createExample(TestedComponent, {
|
||||||
|
...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.AuthIban,
|
||||||
|
challenge_amount: "EUR:1",
|
||||||
|
credit_iban: "DE12345789000",
|
||||||
|
business_name: "Data Loss Incorporated",
|
||||||
|
wire_transfer_subject: "Anastasis 987654321"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const QuestionChallengePaymentFeedback = createExample(TestedComponent, {
|
||||||
|
...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.Payment,
|
||||||
|
taler_pay_uri : "taler://pay/...",
|
||||||
|
provider : "https://localhost:8080/",
|
||||||
|
payment_secret : "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
@ -8,31 +8,67 @@ import {
|
|||||||
} from "../../../../anastasis-core/lib";
|
} from "../../../../anastasis-core/lib";
|
||||||
import { AsyncButton } from "../../components/AsyncButton";
|
import { AsyncButton } from "../../components/AsyncButton";
|
||||||
import { TextInput } from "../../components/fields/TextInput";
|
import { TextInput } from "../../components/fields/TextInput";
|
||||||
|
import { Notifications } from "../../components/Notifications";
|
||||||
import { useAnastasisContext } from "../../context/anastasis";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
|
||||||
function SolveOverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
|
function SolveOverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }): VNode {
|
||||||
const { feedback } = props;
|
const { feedback } = props;
|
||||||
if (!feedback) {
|
if (!feedback) {
|
||||||
return null;
|
return <div />;
|
||||||
}
|
}
|
||||||
switch (feedback.state) {
|
switch (feedback.state) {
|
||||||
case ChallengeFeedbackStatus.Message:
|
case ChallengeFeedbackStatus.Message:
|
||||||
return (
|
return (<Notifications notifications={[{
|
||||||
<div>
|
type: "INFO",
|
||||||
<p>{feedback.message}</p>
|
message: `Message from provider`,
|
||||||
</div>
|
description: feedback.message
|
||||||
);
|
}]} />);
|
||||||
case ChallengeFeedbackStatus.Pending:
|
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>
|
||||||
|
}]} />
|
||||||
case ChallengeFeedbackStatus.AuthIban:
|
case ChallengeFeedbackStatus.AuthIban:
|
||||||
return null;
|
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
|
||||||
|
}]} />);
|
||||||
case ChallengeFeedbackStatus.RateLimitExceeded:
|
case ChallengeFeedbackStatus.RateLimitExceeded:
|
||||||
return <div>Rate limit exceeded.</div>;
|
return (<Notifications notifications={[{
|
||||||
|
type: "ERROR",
|
||||||
|
message: `Message from provider`,
|
||||||
|
description: "There were to many failed attempts."
|
||||||
|
}]} />);
|
||||||
case ChallengeFeedbackStatus.Redirect:
|
case ChallengeFeedbackStatus.Redirect:
|
||||||
return <div>Redirect (FIXME: not supported)</div>;
|
return (<Notifications notifications={[{
|
||||||
|
type: "INFO",
|
||||||
|
message: `Message from provider`,
|
||||||
|
description: <span>
|
||||||
|
Please visit this link: <a>{feedback.redirect_url}</a>
|
||||||
|
</span>
|
||||||
|
}]} />);
|
||||||
case ChallengeFeedbackStatus.Unsupported:
|
case ChallengeFeedbackStatus.Unsupported:
|
||||||
return <div>Challenge not supported by client.</div>;
|
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:
|
case ChallengeFeedbackStatus.TruthUnknown:
|
||||||
return <div>Truth unknown</div>;
|
return (<Notifications notifications={[{
|
||||||
|
type: "ERROR",
|
||||||
|
message: `Provider doesn't recognize the type of challenge`,
|
||||||
|
description: "Contact the provider for further information"
|
||||||
|
}]} />);
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -79,8 +115,8 @@ export function SolveScreen(): VNode {
|
|||||||
<AnastasisClientFrame hideNav title="Recovery problem">
|
<AnastasisClientFrame hideNav title="Recovery problem">
|
||||||
<div>invalid state</div>
|
<div>invalid state</div>
|
||||||
<div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
|
<div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
|
||||||
<button class="button" onClick={() => reducer.back()}>Back</button>
|
<button class="button" onClick={() => reducer.back()}>Back</button>
|
||||||
</div>
|
</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -114,17 +150,23 @@ export function SolveScreen(): VNode {
|
|||||||
reducer?.back();
|
reducer?.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const feedback = challengeFeedback[selectedUuid]
|
||||||
|
const shouldHideConfirm = feedback?.state === ChallengeFeedbackStatus.RateLimitExceeded
|
||||||
|
|| feedback?.state === ChallengeFeedbackStatus.Redirect
|
||||||
|
|| feedback?.state === ChallengeFeedbackStatus.Unsupported
|
||||||
|
|| feedback?.state === ChallengeFeedbackStatus.TruthUnknown
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame hideNav title="Recovery: Solve challenge">
|
<AnastasisClientFrame hideNav title="Recovery: Solve challenge">
|
||||||
<SolveOverviewFeedbackDisplay
|
<SolveOverviewFeedbackDisplay
|
||||||
feedback={challengeFeedback[selectedUuid]}
|
feedback={feedback}
|
||||||
/>
|
/>
|
||||||
<SolveDialog
|
<SolveDialog
|
||||||
id={selectedUuid}
|
id={selectedUuid}
|
||||||
answer={answer}
|
answer={answer}
|
||||||
setAnswer={setAnswer}
|
setAnswer={setAnswer}
|
||||||
challenge={selectedChallenge}
|
challenge={selectedChallenge}
|
||||||
feedback={challengeFeedback[selectedUuid]}
|
feedback={feedback}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -137,9 +179,9 @@ export function SolveScreen(): VNode {
|
|||||||
<button class="button" onClick={onCancel}>
|
<button class="button" onClick={onCancel}>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<AsyncButton class="button is-info" onClick={onNext}>
|
{!shouldHideConfirm && <AsyncButton class="button is-info" onClick={onNext}>
|
||||||
Confirm
|
Confirm
|
||||||
</AsyncButton>
|
</AsyncButton>}
|
||||||
</div>
|
</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
);
|
);
|
||||||
@ -160,6 +202,7 @@ function SolveSmsEntry({
|
|||||||
}: SolveEntryProps): VNode {
|
}: SolveEntryProps): VNode {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
An sms has been sent to "<b>{challenge.instructions}</b>". Type the code
|
An sms has been sent to "<b>{challenge.instructions}</b>". Type the code
|
||||||
below
|
below
|
||||||
|
Loading…
Reference in New Issue
Block a user