Skip to content
This repository was archived by the owner on Sep 2, 2024. It is now read-only.

Commit ed99efc

Browse files
committed
feat: add transaction popup
1 parent 46f4504 commit ed99efc

File tree

6 files changed

+612
-62
lines changed

6 files changed

+612
-62
lines changed

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"swr": "^2.2.4",
5555
"tailwind-merge": "^2.2.2",
5656
"tailwindcss-animate": "^1.0.7",
57+
"vaul": "^0.9.1",
5758
"zustand": "^4.5.0"
5859
},
5960
"devDependencies": {

frontend/src/components/TransactionsList.tsx

Lines changed: 188 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,41 @@
11
import dayjs from "dayjs";
2-
import { ArrowDownIcon, ArrowUpIcon, Drum } from "lucide-react";
2+
import {
3+
ArrowDownIcon,
4+
ArrowUpIcon,
5+
ChevronDown,
6+
ChevronUp,
7+
CopyIcon,
8+
Drum,
9+
} from "lucide-react";
10+
import React from "react";
311
import EmptyState from "src/components/EmptyState";
4-
512
import Loading from "src/components/Loading";
13+
import {
14+
Credenza,
15+
CredenzaBody,
16+
CredenzaContent,
17+
CredenzaFooter,
18+
CredenzaHeader,
19+
CredenzaTitle,
20+
CredenzaTrigger,
21+
} from "src/components/ui/credenza";
22+
import { toast } from "src/components/ui/use-toast";
623
import { useTransactions } from "src/hooks/useTransactions";
24+
import { copyToClipboard } from "src/lib/clipboard";
725

826
function TransactionsList() {
927
const { data: transactions, isLoading } = useTransactions();
28+
const [showDetails, setShowDetails] = React.useState(false);
1029

1130
if (isLoading) {
1231
return <Loading />;
1332
}
1433

34+
const copy = (text: string) => {
35+
copyToClipboard(text);
36+
toast({ title: "Copied to clipboard." });
37+
};
38+
1539
return (
1640
<div>
1741
{!transactions?.length ? (
@@ -28,79 +52,182 @@ function TransactionsList() {
2852
const type = tx.type;
2953

3054
return (
31-
<div
55+
<Credenza
3256
key={`tx-${i}`}
33-
className="p-3 mb-4 rounded-md"
34-
// TODO: Add modal onclick to show payment details
57+
onOpenChange={(open) => {
58+
if (!open) {
59+
setShowDetails(false);
60+
}
61+
}}
3562
>
36-
<div className="flex gap-3">
37-
<div className="flex items-center">
38-
{type == "outgoing" ? (
39-
<div
40-
className={
41-
"flex justify-center items-center bg-orange-100 dark:bg-orange-950 rounded-full w-10 h-10 md:w-14 md:h-14"
42-
}
43-
>
44-
<ArrowUpIcon
45-
strokeWidth={3}
46-
className="w-6 h-6 md:w-8 md:h-8 text-orange-400 dark:text-amber-600 stroke-orange-400 dark:stroke-amber-600"
47-
/>
48-
</div>
49-
) : (
50-
<div className="flex justify-center items-center bg-green-100 dark:bg-emerald-950 rounded-full w-10 h-10 md:w-14 md:h-14">
51-
<ArrowDownIcon
52-
strokeWidth={3}
53-
className="w-6 h-6 md:w-8 md:h-8 text-green-500 dark:text-emerald-500 stroke-green-400 dark:stroke-emerald-500"
54-
/>
63+
<CredenzaTrigger
64+
asChild
65+
className="p-3 mb-4 hover:bg-gray-100 dark:hover:bg-surface-02dp cursor-pointer rounded-md slashed-zero"
66+
>
67+
<div className="flex gap-3">
68+
<div className="flex items-center">
69+
{type == "outgoing" ? (
70+
<div
71+
className={
72+
"flex justify-center items-center bg-orange-100 dark:bg-orange-950 rounded-full w-10 h-10 md:w-14 md:h-14"
73+
}
74+
>
75+
<ArrowUpIcon
76+
strokeWidth={3}
77+
className="w-6 h-6 md:w-8 md:h-8 text-orange-400 dark:text-amber-600 stroke-orange-400 dark:stroke-amber-600"
78+
/>
79+
</div>
80+
) : (
81+
<div className="flex justify-center items-center bg-green-100 dark:bg-emerald-950 rounded-full w-10 h-10 md:w-14 md:h-14">
82+
<ArrowDownIcon
83+
strokeWidth={3}
84+
className="w-6 h-6 md:w-8 md:h-8 text-green-500 dark:text-emerald-500 stroke-green-400 dark:stroke-emerald-500"
85+
/>
86+
</div>
87+
)}
88+
</div>
89+
<div className="overflow-hidden mr-3">
90+
<div className="flex items-center gap-2 truncate dark:text-white">
91+
<p className="text-lg md:text-xl font-semibold">
92+
{type == "incoming" ? "Received" : "Sent"}
93+
</p>
94+
<p className="text-sm md:text-base truncate text-muted-foreground">
95+
{dayjs(tx.settled_at * 1000).fromNow()}
96+
</p>
5597
</div>
56-
)}
57-
</div>
58-
<div className="overflow-hidden mr-3">
59-
<div className="flex items-center gap-2 truncate dark:text-white">
60-
<p className="text-lg md:text-xl font-semibold">
61-
{type == "incoming" ? "Received" : "Sent"}
62-
</p>
63-
<p className="text-sm md:text-base truncate text-muted-foreground">
64-
{dayjs(tx.settled_at * 1000).fromNow()}
98+
<p className="text-sm md:text-base text-muted-foreground">
99+
{tx.description || "Lightning invoice"}
65100
</p>
66101
</div>
67-
<p className="text-sm md:text-base text-muted-foreground">
68-
{tx.description || "Lightning invoice"}
69-
</p>
70-
</div>
71-
<div className="flex ml-auto text-right space-x-3 shrink-0 dark:text-white">
72-
<div className="flex items-center gap-2 text-xl">
73-
<p
74-
className={`font-semibold ${
75-
type == "incoming" &&
76-
"text-green-600 dark:color-green-400"
77-
}`}
78-
>
79-
{type == "outgoing" ? "-" : "+"}{" "}
80-
{Math.floor(tx.amount / 1000)}
81-
</p>
82-
<p className="text-muted-foreground">sats</p>
102+
<div className="flex ml-auto text-right space-x-3 shrink-0 dark:text-white">
103+
<div className="flex items-center gap-2 text-xl">
104+
<p
105+
className={`font-semibold ${
106+
type == "incoming" &&
107+
"text-green-600 dark:color-green-400"
108+
}`}
109+
>
110+
{type == "outgoing" ? "-" : "+"}{" "}
111+
{Math.floor(tx.amount / 1000)}
112+
</p>
113+
<p className="text-muted-foreground">sats</p>
83114

84-
{/* {!!tx.totalAmountFiat && (
115+
{/* {!!tx.totalAmountFiat && (
85116
<p className="text-xs text-gray-400 dark:text-neutral-600">
86117
~{tx.totalAmountFiat}
87118
</p>
88119
)} */}
120+
</div>
89121
</div>
90122
</div>
91-
</div>
92-
</div>
123+
</CredenzaTrigger>
124+
<CredenzaContent className="slashed-zero">
125+
<CredenzaHeader>
126+
<CredenzaTitle>
127+
{type == "outgoing" ? "Sent Bitcoin" : "Received Bitcoin"}
128+
</CredenzaTitle>
129+
</CredenzaHeader>
130+
<CredenzaBody>
131+
<div className="flex items-center mt-6">
132+
{type == "outgoing" ? (
133+
<div
134+
className={
135+
"flex justify-center items-center bg-orange-100 dark:bg-orange-950 rounded-full w-10 h-10 md:w-14 md:h-14"
136+
}
137+
>
138+
<ArrowUpIcon
139+
strokeWidth={3}
140+
className="w-6 h-6 md:w-8 md:h-8 text-orange-400 dark:text-amber-600 stroke-orange-400 dark:stroke-amber-600"
141+
/>
142+
</div>
143+
) : (
144+
<div className="flex justify-center items-center bg-green-100 dark:bg-emerald-950 rounded-full w-10 h-10 md:w-14 md:h-14">
145+
<ArrowDownIcon
146+
strokeWidth={3}
147+
className="w-6 h-6 md:w-8 md:h-8 text-green-500 dark:text-emerald-500 stroke-green-400 dark:stroke-emerald-500"
148+
/>
149+
</div>
150+
)}
151+
<div className="ml-4">
152+
<p className="text-xl md:text-2xl font-semibold">
153+
{Math.floor(tx.amount / 1000)}{" "}
154+
{Math.floor(tx.amount / 1000) == 1 ? "sat" : "sats"}
155+
</p>
156+
{/* <p className="text-sm md:text-base text-gray-500">
157+
Fiat Amount
158+
</p> */}
159+
</div>
160+
</div>
161+
<div className="mt-8">
162+
<p className="dark:text-white">Date & Time</p>
163+
<p className="text-muted-foreground">
164+
{dayjs(tx.settled_at).toString()}
165+
</p>
166+
</div>
167+
<div className="mt-6">
168+
<p className="dark:text-white">Fee</p>
169+
<p className="text-muted-foreground">
170+
{tx.fees_paid} {tx.fees_paid == 1 ? "sat" : "sats"}
171+
</p>
172+
</div>
173+
{tx.description && (
174+
<div className="mt-6">
175+
<p className="dark:text-white">Description</p>
176+
<p className="text-muted-foreground">
177+
{tx.description}
178+
</p>
179+
</div>
180+
)}
181+
</CredenzaBody>
182+
<CredenzaFooter className="!justify-start mt-4 !flex-col">
183+
<div
184+
className="flex items-center gap-2 cursor-pointer"
185+
onClick={() => setShowDetails(!showDetails)}
186+
>
187+
Details
188+
{showDetails ? (
189+
<ChevronUp className="w-4 h-4" />
190+
) : (
191+
<ChevronDown className="w-4 h-4" />
192+
)}
193+
</div>
194+
{showDetails && (
195+
<>
196+
<div className="mt-6 !ml-0">
197+
<p className="dark:text-white">Preimage</p>
198+
<div className="flex items-center gap-4">
199+
<p className="text-muted-foreground break-all">
200+
{tx.preimage}
201+
</p>
202+
<CopyIcon
203+
className="cursor-pointer text-muted-foreground w-6 h-6"
204+
onClick={() => {
205+
copy(tx.preimage);
206+
}}
207+
/>
208+
</div>
209+
</div>
210+
<div className="mt-6 !ml-0">
211+
<p className="dark:text-white">Hash</p>
212+
<div className="flex items-center gap-4">
213+
<p className="text-muted-foreground break-all">
214+
{tx.payment_hash}
215+
</p>
216+
<CopyIcon
217+
className="cursor-pointer text-muted-foreground w-6 h-6"
218+
onClick={() => {
219+
copy(tx.payment_hash);
220+
}}
221+
/>
222+
</div>
223+
</div>
224+
</>
225+
)}
226+
</CredenzaFooter>
227+
</CredenzaContent>
228+
</Credenza>
93229
);
94230
})}
95-
{/* {transaction && (
96-
<TransactionModal
97-
transaction={transaction}
98-
isOpen={modalOpen}
99-
onClose={() => {
100-
setModalOpen(false);
101-
}}
102-
/>
103-
)} */}
104231
</>
105232
)}
106233
</div>

0 commit comments

Comments
 (0)