diff --git a/public/locales/en.json b/public/locales/en.json
index f3ca78b..2e52d70 100644
--- a/public/locales/en.json
+++ b/public/locales/en.json
@@ -328,6 +328,8 @@
"cardRecentTransactionsTitle": "Recent transactions",
"cardNamesTitle": "Names",
+ "transactionsError": "There was an error fetching the transactions. See the console for details.",
+
"resultInvalidTitle": "Invalid address",
"resultInvalid": "That does not look like a valid Krist address.",
"resultNotFoundTitle": "Address not found",
diff --git a/src/pages/addresses/AddressPage.less b/src/pages/addresses/AddressPage.less
index 51af0a0..07a72e3 100644
--- a/src/pages/addresses/AddressPage.less
+++ b/src/pages/addresses/AddressPage.less
@@ -26,5 +26,6 @@
.address-info-row {
max-width: 768px;
+ margin-bottom: @margin-lg;
}
}
diff --git a/src/pages/addresses/AddressPage.tsx b/src/pages/addresses/AddressPage.tsx
index e077b4d..7297ba8 100644
--- a/src/pages/addresses/AddressPage.tsx
+++ b/src/pages/addresses/AddressPage.tsx
@@ -18,13 +18,15 @@
import * as api from "../../krist/api";
import { lookupAddress, KristAddressWithNames } from "../../krist/api/lookup";
+import { AddressTransactionsCard } from "./AddressTransactionsCard";
+
import "./AddressPage.less";
interface ParamTypes {
address: string;
}
-function Page({ address }: { address: KristAddressWithNames }): JSX.Element {
+function PageContents({ address }: { address: KristAddressWithNames }): JSX.Element {
const { t } = useTranslation();
return <>
@@ -73,6 +75,15 @@
/>
+
+ {/* Transaction and name row */}
+
+ {/* Recent transactions */}
+
+
+
+
+
>;
}
@@ -115,7 +126,7 @@
{error
?
: (kristAddress
- ?
+ ?
: )}
;
}
diff --git a/src/pages/addresses/AddressTransactionsCard.tsx b/src/pages/addresses/AddressTransactionsCard.tsx
new file mode 100644
index 0000000..92f3217
--- /dev/null
+++ b/src/pages/addresses/AddressTransactionsCard.tsx
@@ -0,0 +1,69 @@
+// Copyright (c) 2020-2021 Drew Lemmy
+// This file is part of KristWeb 2 under GPL-3.0.
+// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt
+import React, { useState, useEffect, useMemo } from "react";
+import classNames from "classnames";
+import { Card, Skeleton, Empty } from "antd";
+
+import { useTranslation } from "react-i18next";
+
+import { TransactionSummary } from "../../components/transactions/TransactionSummary";
+import { lookupTransactions, LookupTransactionsResponse } from "../../krist/api/lookup";
+
+import { useSyncNode } from "../../krist/api";
+
+import { SmallResult } from "../../components/SmallResult";
+
+import Debug from "debug";
+const debug = Debug("kristweb:address-transactions-card");
+
+async function fetchTransactions(address: string): Promise {
+ debug("fetching transactions");
+ return lookupTransactions(
+ [address],
+ { includeMined: true, limit: 5, orderBy: "id", order: "DESC" }
+ );
+}
+
+export function AddressTransactionsCard({ address }: { address: string }): JSX.Element {
+ const { t } = useTranslation();
+ const syncNode = useSyncNode();
+
+ const [res, setRes] = useState();
+ const [error, setError] = useState();
+ const [loading, setLoading] = useState(true);
+
+ // Fetch transactions on page load or sync node reload
+ // TODO: set up something to temporarily subscribe to an address via the
+ // websocket service, so this can be updated in realtime
+ useEffect(() => {
+ if (!syncNode) return;
+
+ fetchTransactions(address)
+ .then(setRes)
+ .catch(setError)
+ .finally(() => setLoading(false));
+ }, [syncNode, address]);
+
+ const isEmpty = !loading && (error || !res || res.count === 0);
+ const classes = classNames("kw-card", "address-card-transactions", {
+ "empty": isEmpty
+ });
+
+ return
+
+ {error
+ ?
+ : (res && res.count > 0
+ ? (
+
+ )
+ :
+ )}
+
+ ;
+}
diff --git a/src/pages/dashboard/WalletOverviewCard.tsx b/src/pages/dashboard/WalletOverviewCard.tsx
index e009889..09d7254 100644
--- a/src/pages/dashboard/WalletOverviewCard.tsx
+++ b/src/pages/dashboard/WalletOverviewCard.tsx
@@ -19,21 +19,27 @@
const { wallets } = useWallets();
const { t } = useTranslation();
+ // Turn the wallets into an array, to sort them later
const clonedWallets = [...Object.values(wallets)];
+ // Sum the balance and names of all wallets
const balance = clonedWallets.filter(w => w.balance !== undefined)
.reduce((acc, w) => acc + w.balance!, 0);
const names = clonedWallets.filter(w => w.names !== undefined)
.reduce((acc, w) => acc + w.names!, 0);
+ // Pick the top 4 wallets sorted by balance descending
const topWallets = [...clonedWallets];
const sort = keyedNullSort("balance", undefined);
topWallets.sort((a: Wallet, b: Wallet) => sort(a, b, "descend"));
topWallets.reverse();
+
const top4Wallets = topWallets.slice(0, 4);
return
+ {/* Top row (summaries) */}
+ {/* Total balance */}
+ {/* Names */}
+ {/* Wallet list */}
{top4Wallets.map(w => )}
+ {/* See more link */}
+ {/* Show an 'add wallets' button instead if there are no wallets yet */}
{clonedWallets.length > 0
? t("dashboard.walletOverviewSeeMore", { count: clonedWallets.length })
: }