summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension/src/components/PendingTransactions.tsx')
-rw-r--r--packages/taler-wallet-webextension/src/components/PendingTransactions.tsx180
1 files changed, 134 insertions, 46 deletions
diff --git a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
index 5d5dae092..c94010ede 100644
--- a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
+++ b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
@@ -18,45 +18,63 @@ import {
Amounts,
NotificationType,
Transaction,
+ TransactionMajorState,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { Fragment, h, JSX, VNode } from "preact";
import { useEffect } from "preact/hooks";
-import { useTranslationContext } from "../context/translation.js";
+import { useBackendContext } from "../context/backend.js";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { Avatar } from "../mui/Avatar.js";
+import { Grid } from "../mui/Grid.js";
import { Typography } from "../mui/Typography.js";
-import { wxApi } from "../wxApi.js";
import Banner from "./Banner.js";
import { Time } from "./Time.js";
interface Props extends JSX.HTMLAttributes {
- goToTransaction: (id: string) => Promise<void>;
+ goToTransaction?: (id: string) => Promise<void>;
+ goToURL: (url: string) => void;
}
-export function PendingTransactions({ goToTransaction }: Props): VNode {
+/**
+ * this cache will save the tx from the previous render
+ */
+const cache = { tx: [] as Transaction[] };
+
+export function PendingTransactions({
+ goToTransaction,
+ goToURL,
+}: Props): VNode {
+ const api = useBackendContext();
const state = useAsyncAsHook(() =>
- wxApi.wallet.call(WalletApiOperation.GetTransactions, {}),
+ api.wallet.call(WalletApiOperation.GetTransactions, {}),
);
useEffect(() => {
- return wxApi.listener.onUpdateNotification(
- [NotificationType.WithdrawGroupFinished],
+ return api.listener.onUpdateNotification(
+ [NotificationType.TransactionStateTransition],
state?.retry,
);
});
const transactions =
!state || state.hasError
- ? []
- : state.response.transactions.filter((t) => t.pending);
+ ? cache.tx
+ : state.response.transactions.filter(
+ (t) => t.txState.major === TransactionMajorState.Pending,
+ );
- if (!state || state.hasError || !transactions.length) {
+ if (state && !state.hasError) {
+ cache.tx = transactions;
+ }
+ if (!transactions.length) {
return <Fragment />;
}
return (
<PendingTransactionsView
goToTransaction={goToTransaction}
+ goToURL={goToURL}
transactions={transactions}
/>
);
@@ -65,52 +83,122 @@ export function PendingTransactions({ goToTransaction }: Props): VNode {
export function PendingTransactionsView({
transactions,
goToTransaction,
+ goToURL,
}: {
- goToTransaction: (id: string) => Promise<void>;
+ goToTransaction?: (id: string) => Promise<void>;
+ goToURL: (id: string) => void;
transactions: Transaction[];
}): VNode {
const { i18n } = useTranslationContext();
+ const kycTransaction = transactions.find((tx) => tx.kycUrl);
+ if (kycTransaction) {
+ return (
+ <div
+ style={{
+ backgroundColor: "#fff3cd",
+ color: "#664d03",
+ display: "flex",
+ justifyContent: "center",
+ }}
+ >
+ <Banner
+ titleHead={i18n.str`KYC requirement`}
+ style={{
+ backgroundColor: "lightred",
+ maxHeight: 150,
+ padding: 8,
+ flexGrow: 1, //#fff3cd //#ffecb5
+ maxWidth: 500,
+ overflowY: transactions.length > 3 ? "scroll" : "hidden",
+ }}
+ >
+ <Grid
+ container
+ item
+ xs={1}
+ wrap="nowrap"
+ role="button"
+ spacing={1}
+ alignItems="center"
+ onClick={() => {
+ goToURL(kycTransaction.kycUrl ?? "#");
+ }}
+ >
+ <Grid item>
+ <Typography inline bold>
+ One or more transaction require a KYC step to complete
+ </Typography>
+ </Grid>
+ </Grid>
+ </Banner>
+ </div>
+ );
+ }
+
+ if (!goToTransaction) return <Fragment />;
+
return (
- <Banner
- titleHead={<i18n.Translate>PENDING OPERATIONS</i18n.Translate>}
+ <div
style={{
backgroundColor: "lightcyan",
- maxHeight: 150,
- padding: 8,
- flexGrow: 1,
- maxWidth: 500,
- overflowY: transactions.length > 3 ? "scroll" : "hidden",
+ display: "flex",
+ justifyContent: "center",
}}
- elements={transactions.map((t) => {
- const amount = Amounts.parseOrThrow(t.amountEffective);
- return {
- icon: (
- <Avatar
- style={{
- border: "solid blue 1px",
- color: "blue",
- boxSizing: "border-box",
+ >
+ <Banner
+ titleHead={i18n.str`PENDING OPERATIONS`}
+ style={{
+ backgroundColor: "lightcyan",
+ maxHeight: 150,
+ padding: 8,
+ flexGrow: 1,
+ maxWidth: 500,
+ overflowY: transactions.length > 3 ? "scroll" : "hidden",
+ }}
+ >
+ {transactions.map((t, i) => {
+ const amount = Amounts.parseOrThrow(t.amountEffective);
+ return (
+ <Grid
+ container
+ item
+ xs={1}
+ key={i}
+ wrap="nowrap"
+ role="button"
+ spacing={1}
+ alignItems="center"
+ onClick={() => {
+ goToTransaction(t.transactionId);
}}
>
- {t.type.substring(0, 1)}
- </Avatar>
- ),
- action: () => goToTransaction(t.transactionId),
- description: (
- <Fragment>
- <Typography inline bold>
- {amount.currency} {Amounts.stringifyValue(amount)}
- </Typography>
- &nbsp;-&nbsp;
- <Time
- timestamp={AbsoluteTime.fromTimestamp(t.timestamp)}
- format="dd MMMM yyyy"
- />
- </Fragment>
- ),
- };
- })}
- />
+ <Grid item xs={"auto"}>
+ <Avatar
+ style={{
+ border: "solid blue 1px",
+ color: "blue",
+ boxSizing: "border-box",
+ }}
+ >
+ {t.type.substring(0, 1)}
+ </Avatar>
+ </Grid>
+
+ <Grid item>
+ <Typography inline bold>
+ {amount.currency} {Amounts.stringifyValue(amount)}
+ </Typography>
+ &nbsp;-&nbsp;
+ <Time
+ timestamp={AbsoluteTime.fromPreciseTimestamp(t.timestamp)}
+ format="dd MMMM yyyy"
+ />
+ </Grid>
+ </Grid>
+ );
+ })}
+ </Banner>
+ </div>
);
}