show error details in devmode
This commit is contained in:
parent
c3b01ad9e4
commit
505eb07d8e
@ -17,6 +17,7 @@ import { TalerErrorDetails } from "@gnu-taler/taler-util";
|
|||||||
import { VNode, h, Fragment } from "preact";
|
import { VNode, h, Fragment } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import arrowDown from "../../static/img/chevron-down.svg";
|
import arrowDown from "../../static/img/chevron-down.svg";
|
||||||
|
import { useDevContext } from "../context/devContext";
|
||||||
import { ErrorBox } from "./styled";
|
import { ErrorBox } from "./styled";
|
||||||
|
|
||||||
export function ErrorTalerOperation({
|
export function ErrorTalerOperation({
|
||||||
@ -26,8 +27,8 @@ export function ErrorTalerOperation({
|
|||||||
title?: string;
|
title?: string;
|
||||||
error?: TalerErrorDetails;
|
error?: TalerErrorDetails;
|
||||||
}): VNode | null {
|
}): VNode | null {
|
||||||
|
const { devMode } = useDevContext();
|
||||||
const [showErrorDetail, setShowErrorDetail] = useState(false);
|
const [showErrorDetail, setShowErrorDetail] = useState(false);
|
||||||
const [showExtraInfo, setShowExtraInfo] = useState(false);
|
|
||||||
if (!title || !error) return null;
|
if (!title || !error) return null;
|
||||||
return (
|
return (
|
||||||
<ErrorBox style={{ paddingTop: 0, paddingBottom: 0 }}>
|
<ErrorBox style={{ paddingTop: 0, paddingBottom: 0 }}>
|
||||||
@ -47,11 +48,8 @@ export function ErrorTalerOperation({
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
<div style={{ padding: 5, textAlign: "left" }}>
|
<div style={{ padding: 5, textAlign: "left" }}>
|
||||||
<div>{error.message}</div>
|
<div>{error.message}</div>
|
||||||
<a href="#" onClick={() => setShowExtraInfo((v) => !v)}>
|
|
||||||
more
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
{showExtraInfo && (
|
{devMode && (
|
||||||
<div style={{ textAlign: "left", overflowX: "auto" }}>
|
<div style={{ textAlign: "left", overflowX: "auto" }}>
|
||||||
<pre>{JSON.stringify(error, undefined, 2)}</pre>
|
<pre>{JSON.stringify(error, undefined, 2)}</pre>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { createContext, h, VNode } from "preact";
|
import { createContext, h, VNode } from "preact";
|
||||||
import { useContext, useState } from "preact/hooks";
|
import { useContext } from "preact/hooks";
|
||||||
import { useLocalStorage } from "../hooks/useLocalStorage";
|
import { useLocalStorage } from "../hooks/useLocalStorage";
|
||||||
|
|
||||||
interface Type {
|
interface Type {
|
||||||
@ -34,6 +34,10 @@ const Context = createContext<Type>({
|
|||||||
|
|
||||||
export const useDevContext = (): Type => useContext(Context);
|
export const useDevContext = (): Type => useContext(Context);
|
||||||
|
|
||||||
|
export const DevContextProviderForTesting = ({ value, children }: { value: boolean, children: any }): VNode => {
|
||||||
|
return h(Context.Provider, { value: { devMode: value, toggleDevMode: () => { null } }, children });
|
||||||
|
};
|
||||||
|
|
||||||
export const DevContextProvider = ({ children }: { children: any }): VNode => {
|
export const DevContextProvider = ({ children }: { children: any }): VNode => {
|
||||||
const [value, setter] = useLocalStorage("devMode");
|
const [value, setter] = useLocalStorage("devMode");
|
||||||
const devMode = value === "true";
|
const devMode = value === "true";
|
||||||
|
@ -33,6 +33,7 @@ import {
|
|||||||
ConfirmPayResultType,
|
ConfirmPayResultType,
|
||||||
ContractTerms,
|
ContractTerms,
|
||||||
i18n,
|
i18n,
|
||||||
|
NotificationType,
|
||||||
PreparePayResult,
|
PreparePayResult,
|
||||||
PreparePayResultType,
|
PreparePayResultType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
@ -56,6 +57,7 @@ import * as wxApi from "../wxApi";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
talerPayUri?: string;
|
talerPayUri?: string;
|
||||||
|
goToWalletManualWithdraw: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// export function AlreadyPaid({ payStatus }: { payStatus: PreparePayResult }) {
|
// export function AlreadyPaid({ payStatus }: { payStatus: PreparePayResult }) {
|
||||||
@ -102,7 +104,10 @@ const doPayment = async (
|
|||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function PayPage({ talerPayUri }: Props): VNode {
|
export function PayPage({
|
||||||
|
talerPayUri,
|
||||||
|
goToWalletManualWithdraw,
|
||||||
|
}: Props): VNode {
|
||||||
const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(
|
const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
@ -113,7 +118,9 @@ export function PayPage({ talerPayUri }: Props): VNode {
|
|||||||
OperationFailedError | string | undefined
|
OperationFailedError | string | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
|
|
||||||
const balance = useAsyncAsHook(wxApi.getBalance);
|
const balance = useAsyncAsHook(wxApi.getBalance, [
|
||||||
|
NotificationType.CoinWithdrawn,
|
||||||
|
]);
|
||||||
const balanceWithoutError = balance?.hasError
|
const balanceWithoutError = balance?.hasError
|
||||||
? []
|
? []
|
||||||
: balance?.response.balances || [];
|
: balance?.response.balances || [];
|
||||||
@ -144,7 +151,7 @@ export function PayPage({ talerPayUri }: Props): VNode {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
doFetch();
|
doFetch();
|
||||||
}, [talerPayUri]);
|
}, [talerPayUri, foundAmount]);
|
||||||
|
|
||||||
if (!talerPayUri) {
|
if (!talerPayUri) {
|
||||||
return <span>missing pay uri</span>;
|
return <span>missing pay uri</span>;
|
||||||
@ -198,6 +205,7 @@ export function PayPage({ talerPayUri }: Props): VNode {
|
|||||||
payStatus={payStatus}
|
payStatus={payStatus}
|
||||||
payResult={payResult}
|
payResult={payResult}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
goToWalletManualWithdraw={goToWalletManualWithdraw}
|
||||||
balance={foundAmount}
|
balance={foundAmount}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -209,6 +217,7 @@ export interface PaymentRequestViewProps {
|
|||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
payErrMsg?: string;
|
payErrMsg?: string;
|
||||||
uri: string;
|
uri: string;
|
||||||
|
goToWalletManualWithdraw: () => void;
|
||||||
balance: AmountJson | undefined;
|
balance: AmountJson | undefined;
|
||||||
}
|
}
|
||||||
export function PaymentRequestView({
|
export function PaymentRequestView({
|
||||||
@ -216,6 +225,7 @@ export function PaymentRequestView({
|
|||||||
payStatus,
|
payStatus,
|
||||||
payResult,
|
payResult,
|
||||||
onClick,
|
onClick,
|
||||||
|
goToWalletManualWithdraw,
|
||||||
balance,
|
balance,
|
||||||
}: PaymentRequestViewProps): VNode {
|
}: PaymentRequestViewProps): VNode {
|
||||||
let totalFees: AmountJson = Amounts.getZero(payStatus.amountRaw);
|
let totalFees: AmountJson = Amounts.getZero(payStatus.amountRaw);
|
||||||
@ -306,7 +316,7 @@ export function PaymentRequestView({
|
|||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<ButtonSuccess upperCased>
|
<ButtonSuccess upperCased onClick={goToWalletManualWithdraw}>
|
||||||
{i18n.str`Withdraw digital cash`}
|
{i18n.str`Withdraw digital cash`}
|
||||||
</ButtonSuccess>
|
</ButtonSuccess>
|
||||||
</section>
|
</section>
|
||||||
|
@ -14,15 +14,27 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ComponentChildren, FunctionalComponent, h as render } from "preact";
|
import { ComponentChildren, FunctionalComponent, h as render, VNode } from "preact";
|
||||||
|
|
||||||
export function createExample<Props>(
|
export function createExample<Props>(
|
||||||
Component: FunctionalComponent<Props>,
|
Component: FunctionalComponent<Props>,
|
||||||
props: Partial<Props>,
|
props: Partial<Props>,
|
||||||
) {
|
): ComponentChildren {
|
||||||
const r = (args: any) => render(Component, args);
|
const Render = (args: any) => render(Component, args);
|
||||||
r.args = props;
|
Render.args = props;
|
||||||
return r;
|
return Render;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createExampleWithCustomContext<Props, ContextProps>(
|
||||||
|
Component: FunctionalComponent<Props>,
|
||||||
|
props: Partial<Props>,
|
||||||
|
ContextProvider: FunctionalComponent<ContextProps>,
|
||||||
|
contextProps: Partial<ContextProps>,
|
||||||
|
): ComponentChildren {
|
||||||
|
const Render = (args: any): VNode => render(Component, args);
|
||||||
|
const WithContext = (args: any): VNode => render(ContextProvider, { ...contextProps, children: [Render(args)] } as any);
|
||||||
|
WithContext.args = props
|
||||||
|
return WithContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NullLink({ children }: { children?: ComponentChildren }) {
|
export function NullLink({ children }: { children?: ComponentChildren }) {
|
||||||
|
@ -31,7 +31,12 @@ import {
|
|||||||
TransactionWithdrawal,
|
TransactionWithdrawal,
|
||||||
WithdrawalType,
|
WithdrawalType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { createExample } from "../test-utils";
|
import { ComponentChildren, h } from "preact";
|
||||||
|
import { DevContextProviderForTesting } from "../context/devContext";
|
||||||
|
import {
|
||||||
|
createExample,
|
||||||
|
createExampleWithCustomContext as createExampleInCustomContext,
|
||||||
|
} from "../test-utils";
|
||||||
import { TransactionView as TestedComponent } from "./Transaction";
|
import { TransactionView as TestedComponent } from "./Transaction";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -128,6 +133,25 @@ export const Withdraw = createExample(TestedComponent, {
|
|||||||
transaction: exampleData.withdraw,
|
transaction: exampleData.withdraw,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const WithdrawOneMinuteAgo = createExample(TestedComponent, {
|
||||||
|
transaction: {
|
||||||
|
...exampleData.withdraw,
|
||||||
|
timestamp: {
|
||||||
|
t_ms: new Date().getTime() - 60 * 1000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WithdrawOneMinuteAgoAndPending = createExample(TestedComponent, {
|
||||||
|
transaction: {
|
||||||
|
...exampleData.withdraw,
|
||||||
|
timestamp: {
|
||||||
|
t_ms: new Date().getTime() - 60 * 1000,
|
||||||
|
},
|
||||||
|
pending: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const WithdrawError = createExample(TestedComponent, {
|
export const WithdrawError = createExample(TestedComponent, {
|
||||||
transaction: {
|
transaction: {
|
||||||
...exampleData.withdraw,
|
...exampleData.withdraw,
|
||||||
@ -135,6 +159,18 @@ export const WithdrawError = createExample(TestedComponent, {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const WithdrawErrorInDevMode = createExampleInCustomContext(
|
||||||
|
TestedComponent,
|
||||||
|
{
|
||||||
|
transaction: {
|
||||||
|
...exampleData.withdraw,
|
||||||
|
error: transactionError,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DevContextProviderForTesting,
|
||||||
|
{ value: true },
|
||||||
|
);
|
||||||
|
|
||||||
export const WithdrawPendingManual = createExample(TestedComponent, {
|
export const WithdrawPendingManual = createExample(TestedComponent, {
|
||||||
transaction: {
|
transaction: {
|
||||||
...exampleData.withdraw,
|
...exampleData.withdraw,
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
TransactionType,
|
TransactionType,
|
||||||
WithdrawalType,
|
WithdrawalType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { differenceInSeconds } from "date-fns";
|
||||||
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
||||||
import { route } from "preact-router";
|
import { route } from "preact-router";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
@ -110,6 +111,7 @@ export function TransactionView({
|
|||||||
onBack,
|
onBack,
|
||||||
}: WalletTransactionProps): VNode {
|
}: WalletTransactionProps): VNode {
|
||||||
const [confirmBeforeForget, setConfirmBeforeForget] = useState(false);
|
const [confirmBeforeForget, setConfirmBeforeForget] = useState(false);
|
||||||
|
|
||||||
function doCheckBeforeForget(): void {
|
function doCheckBeforeForget(): void {
|
||||||
if (
|
if (
|
||||||
transaction.pending &&
|
transaction.pending &&
|
||||||
@ -120,11 +122,18 @@ export function TransactionView({
|
|||||||
onDelete();
|
onDelete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function TransactionTemplate({
|
function TransactionTemplate({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
|
const showRetry =
|
||||||
|
transaction.error !== undefined ||
|
||||||
|
transaction.timestamp.t_ms === "never" ||
|
||||||
|
(transaction.pending &&
|
||||||
|
differenceInSeconds(new Date(), transaction.timestamp.t_ms) > 10);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<section style={{ padding: 8, textAlign: "center" }}>
|
<section style={{ padding: 8, textAlign: "center" }}>
|
||||||
@ -144,7 +153,7 @@ export function TransactionView({
|
|||||||
<i18n.Translate> < Back </i18n.Translate>
|
<i18n.Translate> < Back </i18n.Translate>
|
||||||
</Button>
|
</Button>
|
||||||
<div>
|
<div>
|
||||||
{transaction?.error ? (
|
{showRetry ? (
|
||||||
<ButtonPrimary onClick={onRetry}>
|
<ButtonPrimary onClick={onRetry}>
|
||||||
<i18n.Translate>retry</i18n.Translate>
|
<i18n.Translate>retry</i18n.Translate>
|
||||||
</ButtonPrimary>
|
</ButtonPrimary>
|
||||||
|
@ -164,7 +164,13 @@ function Application(): VNode {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/** call to action */}
|
{/** call to action */}
|
||||||
<Route path={Pages.pay} component={PayPage} />
|
<Route
|
||||||
|
path={Pages.pay}
|
||||||
|
component={PayPage}
|
||||||
|
goToWalletManualWithdraw={() =>
|
||||||
|
goToWalletPage(Pages.manual_withdraw)
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route path={Pages.refund} component={RefundPage} />
|
<Route path={Pages.refund} component={RefundPage} />
|
||||||
<Route path={Pages.tips} component={TipPage} />
|
<Route path={Pages.tips} component={TipPage} />
|
||||||
<Route path={Pages.withdraw} component={WithdrawPage} />
|
<Route path={Pages.withdraw} component={WithdrawPage} />
|
||||||
@ -176,6 +182,16 @@ function Application(): VNode {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goToWalletPage(page: Pages | string): null {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
chrome.tabs.create({
|
||||||
|
active: true,
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
url: chrome.extension.getURL(`/static/wallet.html#${page}`),
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function Redirect({ to }: { to: string }): null {
|
function Redirect({ to }: { to: string }): null {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
route(to, true);
|
route(to, true);
|
||||||
|
Loading…
Reference in New Issue
Block a user