Skip to content

Commit

Permalink
Merge branch 'feat/transaction-list' of https://github.com/getAlby/li…
Browse files Browse the repository at this point in the history
…ghtning-browser-extension into feat/transaction-list
  • Loading branch information
pavanjoshi914 committed Nov 1, 2023
2 parents e56e496 + 8d380d8 commit cb9755e
Show file tree
Hide file tree
Showing 18 changed files with 270 additions and 227 deletions.
9 changes: 6 additions & 3 deletions src/app/components/TransactionsTable/TransactionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ArrowUpIcon,
} from "@bitcoin-design/bitcoin-icons-react/outline";
import dayjs from "dayjs";
import { useState } from "react";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import Hyperlink from "~/app/components/Hyperlink";
import Modal from "~/app/components/Modal";
Expand Down Expand Up @@ -37,6 +37,10 @@ export default function TransactionModal({
setShowMoreFields(!showMoreFields);
}

useEffect(() => {
setShowMoreFields(false);
}, [transaction]);

function getTransactionType(tx: Transaction): "incoming" | "outgoing" {
return [tx.type && "sent", "sending"].includes(tx.type)
? "outgoing"
Expand All @@ -48,7 +52,6 @@ export default function TransactionModal({
isOpen={isOpen}
close={() => {
onClose();
setShowMoreFields(false);
}}
contentLabel={"Transactions"}
>
Expand Down Expand Up @@ -183,7 +186,7 @@ const Dt = ({ children }: { children: React.ReactNode }) => (
);

const Dd = ({ children }: { children: React.ReactNode }) => (
<dd className="flex-1 text-gray-800 dark:text-neutral-200 break-all">
<dd className="flex-1 text-gray-800 dark:text-neutral-200 break-all whitespace-pre-wrap">
{children}
</dd>
);
Expand Down
146 changes: 75 additions & 71 deletions src/app/components/TransactionsTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,83 +41,87 @@ export default function TransactionsTable({
: "incoming";
}

return loading ? (
<div className="w-full flex flex-col items-center mt-4">
<Loading />
</div>
) : !transactions?.length && noResultMsg ? (
<p className="text-gray-500 dark:text-neutral-400">{noResultMsg}</p>
) : (
<>
<div className="overflow-hidden">
{transactions?.map((tx) => {
const type = getTransactionType(tx);
return (
<div className="mt-4">
{loading ? (
<div className="w-full flex flex-col items-center">
<Loading />
</div>
) : !transactions?.length && noResultMsg ? (
<p className="text-gray-500 dark:text-neutral-400">{noResultMsg}</p>
) : (
<>
<div className="overflow-hidden">
{transactions?.map((tx) => {
const type = getTransactionType(tx);

return (
<div
key={tx.id}
className="px-3 py-2 hover:bg-gray-100 dark:hover:bg-surface-02dp cursor-pointer rounded-md"
onClick={() => openDetails(tx)}
>
<div className="flex gap-4">
<div className="flex items-center">
{type == "outgoing" ? (
<div className="flex justify-center items-center bg-orange-100 dark:bg-[#261911] rounded-full w-8 h-8">
<ArrowUpIcon className="w-4 h-4 text-orange-400 stroke-[4px]" />
return (
<div
key={tx.id}
className="px-3 py-2 hover:bg-gray-100 dark:hover:bg-surface-02dp cursor-pointer rounded-md"
onClick={() => openDetails(tx)}
>
<div className="flex gap-4">
<div className="flex items-center">
{type == "outgoing" ? (
<div className="flex justify-center items-center bg-orange-100 dark:bg-[#261911] rounded-full w-8 h-8">
<ArrowUpIcon className="w-4 h-4 text-orange-400 stroke-[4px]" />
</div>
) : (
<div className="flex justify-center items-center bg-green-100 dark:bg-[#0F1E1A] rounded-full w-8 h-8">
<ArrowDownIcon className="w-4 h-4 text-green-400 stroke-[4px]" />
</div>
)}
</div>
) : (
<div className="flex justify-center items-center bg-green-100 dark:bg-[#0F1E1A] rounded-full w-8 h-8">
<ArrowDownIcon className="w-4 h-4 text-green-400 stroke-[4px]" />
<div className="overflow-hidden mr-3">
<div className="text-sm font-medium text-black truncate dark:text-white">
<p className="truncate">
{tx.title ||
tx.boostagram?.message ||
(type == "incoming" ? t("received") : t("sent"))}
</p>
</div>
<p className="text-xs text-gray-400 dark:text-neutral-500">
{tx.date}
</p>
</div>
)}
</div>
<div className="overflow-hidden mr-3">
<div className="text-sm font-medium text-black truncate dark:text-white">
<p className="truncate">
{tx.title ||
tx.boostagram?.message ||
(type == "incoming" ? t("received") : t("sent"))}
</p>
</div>
<p className="text-xs text-gray-400 dark:text-neutral-500">
{tx.date}
</p>
</div>
<div className="flex ml-auto text-right space-x-3 shrink-0 dark:text-white">
<div>
<p
className={classNames(
"text-sm font-medium",
type == "incoming"
? "text-green-600 dark:color-green-400"
: "text-orange-600 dark:color-orange-400"
)}
>
{type == "outgoing" ? "-" : "+"}{" "}
{getFormattedSats(tx.totalAmount)}
</p>
<div className="flex ml-auto text-right space-x-3 shrink-0 dark:text-white">
<div>
<p
className={classNames(
"text-sm font-medium",
type == "incoming"
? "text-green-600 dark:color-green-400"
: "text-orange-600 dark:color-orange-400"
)}
>
{type == "outgoing" ? "-" : "+"}{" "}
{getFormattedSats(tx.totalAmount)}
</p>

{!!tx.totalAmountFiat && (
<p className="text-xs text-gray-400 dark:text-neutral-600">
~{tx.totalAmountFiat}
</p>
)}
{!!tx.totalAmountFiat && (
<p className="text-xs text-gray-400 dark:text-neutral-600">
~{tx.totalAmountFiat}
</p>
)}
</div>
</div>
</div>
</div>
</div>
</div>
);
})}
</div>
{transaction && (
<TransactionModal
transaction={transaction}
isOpen={modalOpen}
onClose={() => {
setModalOpen(false);
}}
/>
);
})}
</div>
{transaction && (
<TransactionModal
transaction={transaction}
isOpen={modalOpen}
onClose={() => {
setModalOpen(false);
}}
/>
)}
</>
)}
</>
</div>
);
}
9 changes: 1 addition & 8 deletions src/app/hooks/useTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const useTransactions = () => {
isSettled: true,
limit,
});

const transactions = getTransactionsResponse.transactions.map(
(transaction) => ({
...transaction,
Expand All @@ -33,15 +34,7 @@ export const useTransactions = () => {
: "";
}

// Sort the final list by date in descending order.
transactions.sort((a, b) => {
const dateA = a.timestamp;
const dateB = b.timestamp;
return dateB - dateA;
});

setTransactions(transactions);

setIsLoadingTransactions(false);
} catch (e) {
console.error(e);
Expand Down
7 changes: 4 additions & 3 deletions src/app/screens/Home/DefaultView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ export type Props = {
};

const DefaultView: FC<Props> = (props) => {
const itemsLimit = 8;

const { t } = useTranslation("translation", { keyPrefix: "home" });
const { t: tCommon } = useTranslation("common");

const navigate = useNavigate();

const { account, balancesDecorated, accountLoading } = useAccount();
const { account, accountLoading } = useAccount();

const lightningAddress = account?.lightningAddress || "";

Expand All @@ -47,11 +49,10 @@ const DefaultView: FC<Props> = (props) => {
useTransactions();

const isLoading = accountLoading || isLoadingTransactions;
const itemsLimit = 8;

useEffect(() => {
loadTransactions(itemsLimit);
}, [balancesDecorated?.accountBalance, loadTransactions, itemsLimit]);
}, [loadTransactions, itemsLimit]);

// check if currentURL is blocked
useEffect(() => {
Expand Down
10 changes: 4 additions & 6 deletions src/app/screens/Transactions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,15 @@ function Transactions() {
keyPrefix: "transactions",
});

const { balancesDecorated, accountLoading } = useAccount();

const { accountLoading } = useAccount();
const { transactions, isLoadingTransactions, loadTransactions } =
useTransactions();

const isLoading = accountLoading || isLoadingTransactions;
const listItems = transactions;

useEffect(() => {
loadTransactions();
}, [balancesDecorated?.accountBalance, loadTransactions]);
}, [loadTransactions]);

return (
<Container>
Expand All @@ -39,8 +37,8 @@ function Transactions() {
</div>
) : (
<div>
{listItems && listItems.length > 0 && (
<TransactionsTable transactions={listItems} />
{transactions && transactions.length > 0 && (
<TransactionsTable transactions={transactions} />
)}
</div>
)}
Expand Down
6 changes: 5 additions & 1 deletion src/extension/background-script/actions/ln/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ const transactions = async (message: MessageTransactions) => {
const boostagram = utils.getBoostagramFromInvoiceCustomRecords(
transaction.custom_records
);
return { ...transaction, boostagram };
return {
...transaction,
boostagram,
paymentHash: transaction.payment_hash,
};
});

if (limit) {
Expand Down
16 changes: 9 additions & 7 deletions src/extension/background-script/connectors/alby.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import state from "../state";
import Connector, {
CheckPaymentArgs,
CheckPaymentResponse,
ConnectorInvoice,
ConnectorTransaction,
ConnectPeerResponse,
GetBalanceResponse,
GetInfoResponse,
Expand Down Expand Up @@ -94,15 +94,16 @@ export default class Alby implements Connector {
client.incomingInvoices({})
)) as Invoice[];

const invoices: ConnectorInvoice[] = incomingInvoices.map(
(invoice, index): ConnectorInvoice => ({
const invoices: ConnectorTransaction[] = incomingInvoices.map(
(invoice, index): ConnectorTransaction => ({
custom_records: invoice.custom_records,
id: `${invoice.payment_request}-${index}`,
payment_hash: invoice.payment_hash,
memo: invoice.comment || invoice.memo,
preimage: "", // alby wallet api doesn't support preimage (yet)
settled: invoice.settled,
settleDate: new Date(invoice.settled_at).getTime(),
totalAmount: `${invoice.amount}`,
totalAmount: invoice.amount,
type: "received",
})
);
Expand All @@ -118,15 +119,16 @@ export default class Alby implements Connector {
client.invoices({})
)) as Invoice[];

const transactions: ConnectorInvoice[] = invoicesResponse.map(
(invoice, index): ConnectorInvoice => ({
const transactions: ConnectorTransaction[] = invoicesResponse.map(
(invoice, index): ConnectorTransaction => ({
custom_records: invoice.custom_records,
id: `${invoice.payment_request}-${index}`,
memo: invoice.comment || invoice.memo,
preimage: "", // alby wallet api doesn't support preimage (yet)
payment_hash: invoice.payment_hash,
settled: invoice.settled,
settleDate: new Date(invoice.settled_at).getTime(),
totalAmount: `${invoice.amount}`,
totalAmount: invoice.amount,
type: invoice.type == "incoming" ? "received" : "sent",
})
);
Expand Down
4 changes: 2 additions & 2 deletions src/extension/background-script/connectors/citadel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class CitadelConnector implements Connector {
// not yet implemented
async getInvoices(): Promise<GetInvoicesResponse> {
console.error(
`Not yet supported with the currently used account: ${this.constructor.name}`
`getInvoices() is not yet supported with the currently used account: ${this.constructor.name}`
);
throw new Error(
`${this.constructor.name}: "getInvoices" is not yet supported. Contact us if you need it.`
Expand All @@ -89,7 +89,7 @@ class CitadelConnector implements Connector {

async getTransactions(): Promise<GetTransactionsResponse> {
console.error(
`Not yet supported with the currently used account: ${this.constructor.name}`
`getTransactions() is not yet supported with the currently used account: ${this.constructor.name}`
);
return { data: { transactions: [] } };
}
Expand Down
Loading

0 comments on commit cb9755e

Please sign in to comment.