From ea8a03e3b11d9f04f003df8ddb7b57073a36e80a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Aaron?= Date: Thu, 2 May 2024 19:44:04 +0200 Subject: [PATCH] fix: some more styles and ux improvements --- .../src/screens/channels/ChannelOrder.tsx | 110 +++--- frontend/src/screens/channels/Channels.tsx | 36 +- frontend/src/screens/channels/NewChannel.tsx | 338 ++++++------------ 3 files changed, 150 insertions(+), 334 deletions(-) diff --git a/frontend/src/screens/channels/ChannelOrder.tsx b/frontend/src/screens/channels/ChannelOrder.tsx index db097a79..322f244a 100644 --- a/frontend/src/screens/channels/ChannelOrder.tsx +++ b/frontend/src/screens/channels/ChannelOrder.tsx @@ -13,8 +13,9 @@ import { useNavigate } from "react-router-dom"; import AppHeader from "src/components/AppHeader"; import Loading from "src/components/Loading"; import TwoColumnLayoutHeader from "src/components/TwoColumnLayoutHeader"; -import { Card, CardContent } from "src/components/ui/card"; +import { Label } from "src/components/ui/label"; import { LoadingButton } from "src/components/ui/loading-button"; +import { Separator } from "src/components/ui/separator"; import { Table, TableBody, TableCell, TableRow } from "src/components/ui/table"; import { useToast } from "src/components/ui/use-toast"; import { useCSRF } from "src/hooks/useCSRF"; @@ -77,6 +78,7 @@ export function PayBitcoinChannelOrder({ order }: { order: NewChannelOrder }) { const [loading, setLoading] = React.useState(false); const [nodeDetails, setNodeDetails] = React.useState(); const { data: csrf } = useCSRF(); + const navigate = useNavigate(); const { pubkey, host } = order; @@ -142,29 +144,11 @@ export function PayBitcoinChannelOrder({ order }: { order: NewChannelOrder }) { ) { return; } - if ( - !confirm( - `Are you sure you want to peer with ${nodeDetails?.alias || pubkey}?` - ) - ) { - return; - } setLoading(true); await connectPeer(); - if ( - !confirm( - `Are you sure you want to open a ${order.amount} sat channel to ${ - nodeDetails?.alias || pubkey - }?` - ) - ) { - setLoading(false); - return; - } - console.log(`🎬 Opening channel with ${pubkey}`); const openChannelRequest: OpenChannelRequest = { @@ -187,8 +171,9 @@ export function PayBitcoinChannelOrder({ order }: { order: NewChannelOrder }) { if (!openChannelResponse?.fundingTxId) { throw new Error("No funding txid in response"); } - + // TODO: Success screen? alert(`🎉 Published tx: ${openChannelResponse.fundingTxId}`); + navigate("/channels"); } catch (error) { console.error(error); alert("Something went wrong: " + error); @@ -197,54 +182,51 @@ export function PayBitcoinChannelOrder({ order }: { order: NewChannelOrder }) { } } - const description = nodeDetails?.alias ? ( - <> - Open a channel with{" "} - ⬤{" "} - {nodeDetails.alias} ({nodeDetails.active_channel_count} channels) - - ) : ( - "Connect to other nodes on the lightning network" - ); - return (
- - - -
-
-

- - ⬤ - - {nodeDetails?.alias ? ( - <> - {nodeDetails.alias} ({nodeDetails.active_channel_count}{" "} - channels) - - ) : ( - <> - {pubkey} -  (? channels) - - )} -

-
+ -
- - Open Channel ({new Intl.NumberFormat().format(+order.amount)}{" "} - sats) - -
+
+
+ +
+ + ⬤ + + {nodeDetails?.alias ? ( + <> + {nodeDetails.alias} + + ({nodeDetails.active_channel_count}{" "} + channels) + + + ) : ( + <> + {pubkey} +  (? channels) + + )} +
+
+
+ +
+ {new Intl.NumberFormat().format(+order.amount)}{" "} + sats
- - +
+ +
+ + Confirm + +
+
); } diff --git a/frontend/src/screens/channels/Channels.tsx b/frontend/src/screens/channels/Channels.tsx index 6e154db4..de17b7b3 100644 --- a/frontend/src/screens/channels/Channels.tsx +++ b/frontend/src/screens/channels/Channels.tsx @@ -11,7 +11,6 @@ import { import React from "react"; import { Link, useNavigate } from "react-router-dom"; import AppHeader from "src/components/AppHeader.tsx"; -import CardButton from "src/components/CardButton.tsx"; import Loading from "src/components/Loading.tsx"; import { Badge } from "src/components/ui/badge.tsx"; import { Button } from "src/components/ui/button.tsx"; @@ -22,7 +21,6 @@ import { CardHeader, CardTitle, } from "src/components/ui/card.tsx"; -import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "src/components/ui/dialog.tsx"; import { DropdownMenu, DropdownMenuContent, @@ -217,7 +215,6 @@ export default function Channels() { Node
- {/* TODO: replace with skeleton loader */} {nodeConnectionInfo?.pubkey || "Loading..."}
{nodeConnectionInfo && ( @@ -267,33 +264,9 @@ export default function Channels() { )} - - - - - - - - Open a channel - - - Choose how you want to obtain a new channel. - -
- - Migrate your funds from Alby Recommended} - description="Use funds from your hosted Alby Account to fund your first channel." /> - - -
-
-
- + + + } > @@ -380,9 +353,6 @@ export default function Channels() { )} - - - diff --git a/frontend/src/screens/channels/NewChannel.tsx b/frontend/src/screens/channels/NewChannel.tsx index 379d40b5..979fce8d 100644 --- a/frontend/src/screens/channels/NewChannel.tsx +++ b/frontend/src/screens/channels/NewChannel.tsx @@ -9,15 +9,10 @@ import Loading from "src/components/Loading"; import { Alert, AlertDescription, AlertTitle } from "src/components/ui/alert"; import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "src/components/ui/breadcrumb"; import { Button } from "src/components/ui/button"; -import { - Card, - CardContent, - CardHeader, - CardTitle, -} from "src/components/ui/card"; import { Checkbox } from "src/components/ui/checkbox"; import { Input } from "src/components/ui/input"; import { Label } from "src/components/ui/label"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "src/components/ui/select"; import { ALBY_MIN_BALANCE, ALBY_SERVICE_FEE, @@ -57,7 +52,6 @@ const recommendedPeers: RecommendedPeer[] = [ name: "Alby", image: albyImage, }, - { network: "testnet", paymentMethod: "onchain", @@ -94,6 +88,16 @@ const recommendedPeers: RecommendedPeer[] = [ name: "Olympus Mutinynet (Flow 2.0)", image: olympusImage, }, + + { + network: "signet", + paymentMethod: "onchain", + pubkey: "", + host: "", + minimumChannelSize: 0, + name: "Custom", + image: albyImage, + }, ]; export default function NewChannel() { @@ -109,9 +113,7 @@ export default function NewChannel() { function NewChannelInternal({ network }: { network: Network }) { const { data: info } = useInfo(); const { data: albyBalance } = useAlbyBalance(); - const [showAdvanced, setShowAdvanced] = React.useState(false); const navigate = useNavigate(); - // const [loading, setLoading] = React.useState(false); const [order, setOrder] = React.useState>({ paymentMethod: "onchain", @@ -128,6 +130,7 @@ function NewChannelInternal({ network }: { network: Network }) { paymentMethod, }); } + const setAmount = React.useCallback((amount: string) => { setOrder((current) => ({ ...current, @@ -211,7 +214,7 @@ function NewChannelInternal({ network }: { network: Network }) { )} -
+
- - <> -
- {selectedPeer && - (selectedPeer.paymentMethod === "lightning" || - (order.paymentMethod === "onchain" && - selectedPeer.pubkey === order.pubkey)) ? ( -
+
+ {selectedPeer && + (selectedPeer.paymentMethod === "lightning" || + (order.paymentMethod === "onchain" && + selectedPeer.pubkey === order.pubkey)) && ( +
-
- -

{selectedPeer.name}

-
- {showAdvanced && ( - <> - Select another peer -
- {recommendedPeers - .filter( - (peer) => - peer.network === network && - peer.paymentMethod === order.paymentMethod - ) - .map((peer) => ( - setSelectedPeer(peer)} - > - - - {peer.name} - - - - - - - ))} -
- - )} + + {selectedPeer.name === "Custom" && <> +
+ +
+ }
- ) : ( -

No recommended peer found

)} - -
- +
{order.paymentMethod === "onchain" && ( )} {order.paymentMethod === "lightning" && ( @@ -349,7 +331,7 @@ function NewChannelLightning(props: NewChannelLightningProps) { type NewChannelOnchainProps = { order: Partial; setOrder(order: Partial): void; - showAdvanced: boolean; + showCustomOptions: boolean; }; function NewChannelOnchain(props: NewChannelOnchainProps) { @@ -385,6 +367,7 @@ function NewChannelOnchain(props: NewChannelOnchainProps) { const fetchNodeDetails = React.useCallback(async () => { if (!pubkey) { + setNodeDetails(undefined); return; } try { @@ -402,181 +385,62 @@ function NewChannelOnchain(props: NewChannelOnchainProps) { fetchNodeDetails(); }, [fetchNodeDetails]); - /*const connectPeer = React.useCallback(async () => { - if (!csrf) { - throw new Error("csrf not loaded"); - } - if (!nodeDetails && !host) { - throw new Error("node details not found"); - } - const _host = nodeDetails ? nodeDetails.sockets.split(",")[0] : host; - if (!_host || !pubkey) { - throw new Error("host or pubkey unset"); - } - const [address, port] = _host.split(":"); - if (!address || !port) { - throw new Error("host not found"); - } - console.log(`🔌 Peering with ${pubkey}`); - const connectPeerRequest: ConnectPeerRequest = { - pubkey, - address, - port: +port, - }; - await request("/api/peers", { - method: "POST", - headers: { - "X-CSRF-Token": csrf, - "Content-Type": "application/json", - }, - body: JSON.stringify(connectPeerRequest), - }); - }, [csrf, nodeDetails, pubkey, host]);*/ - - /*async function openChannel() { - try { - if (!csrf) { - throw new Error("csrf not loaded"); - } - if ( - isPublic && - !confirm( - `Are you sure you want to open a public channel? in most cases a private channel is recommended.` - ) - ) { - return; - } - if ( - !confirm( - `Are you sure you want to peer with ${nodeDetails?.alias || pubkey}?` - ) - ) { - return; - } - - setLoading(true); - - await connectPeer(); - - if ( - !confirm( - `Are you sure you want to open a ${localAmount} sat channel to ${ - nodeDetails?.alias || pubkey - }?` - ) - ) { - setLoading(false); - return; - } - - console.log(`🎬 Opening channel with ${pubkey}`); - - const openChannelRequest: OpenChannelRequest = { - pubkey, - amount: +localAmount, - public: isPublic, - }; - const openChannelResponse = await request( - "/api/channels", - { - method: "POST", - headers: { - "X-CSRF-Token": csrf, - "Content-Type": "application/json", - }, - body: JSON.stringify(openChannelRequest), - } - ); - - if (!openChannelResponse?.fundingTxId) { - throw new Error("No funding txid in response"); - } - - alert(`🎉 Published tx: ${openChannelResponse.fundingTxId}`); - } catch (error) { - console.error(error); - alert("Something went wrong: " + error); - } finally { - setLoading(false); - } - }*/ - - /*const description = nodeDetails?.alias ? ( - <> - Open a channel with an onchain payment to{" "} - ⬤{" "} - {nodeDetails.alias} (${nodeDetails.active_channel_count} channels) - - ) : ( - "Open a channel with an onchain payment to a node on the lightning network" - );*/ - return ( <> - {props.showAdvanced && ( -
-
- {nodeDetails && ( -

- ⬤ - {nodeDetails.alias && ( - <> - {nodeDetails.alias} ({nodeDetails.active_channel_count}{" "} - channels) - - )} -

- )} -
- -
- - { - setPubkey(e.target.value.trim()); - }} - /> -
- - {!nodeDetails && pubkey && ( +
+ {props.showCustomOptions && ( + <>
- + { - setHost(e.target.value.trim()); + setPubkey(e.target.value.trim()); }} /> + {nodeDetails && ( +
+ ⬤ + {nodeDetails.alias && ( + <> + {nodeDetails.alias} ({nodeDetails.active_channel_count}{" "} + channels) + + )} +
+ )}
- )} -
- setPublic(!isPublic)} - className="mr-2" - /> - -
-
-
- )} + {!nodeDetails && pubkey && ( +
+ + { + setHost(e.target.value.trim()); + }} + /> +
+ )} + + )} - {/* - Next - */} +
+ setPublic(!isPublic)} + className="mr-2" + /> + +
+
); }