ChannelDropdownMenu.tsx raw

   1  import {
   2    ExternalLinkIcon,
   3    HandCoinsIcon,
   4    MoreHorizontalIcon,
   5    ScaleIcon,
   6    Trash2Icon,
   7  } from "lucide-react";
   8  import React from "react";
   9  import { useSearchParams } from "react-router";
  10  import { CloseChannelDialogContent } from "src/components/CloseChannelDialogContent";
  11  import ExternalLink from "src/components/ExternalLink";
  12  import { RebalanceChannelDialogContent } from "src/components/RebalanceChannelDialogContent";
  13  import { RoutingFeeDialogContent } from "src/components/RoutingFeeDialogContent";
  14  import {
  15    AlertDialog,
  16    AlertDialogTrigger,
  17  } from "src/components/ui/alert-dialog";
  18  import { Button } from "src/components/ui/button.tsx";
  19  import {
  20    DropdownMenu,
  21    DropdownMenuContent,
  22    DropdownMenuItem,
  23    DropdownMenuTrigger,
  24  } from "src/components/ui/dropdown-menu.tsx";
  25  import { useInfo } from "src/hooks/useInfo";
  26  import { Channel } from "src/types";
  27  
  28  type ChannelDropdownMenuProps = {
  29    alias: string;
  30    channel: Channel;
  31    hasMultipleChannels: boolean;
  32  };
  33  
  34  export function ChannelDropdownMenu({
  35    alias,
  36    channel,
  37    hasMultipleChannels,
  38  }: ChannelDropdownMenuProps) {
  39    const { data: info } = useInfo();
  40    const [searchParams] = useSearchParams();
  41    const [dialog, setDialog] = React.useState<
  42      "closeChannel" | "routingFee" | "rebalance"
  43    >();
  44  
  45    React.useEffect(() => {
  46      // when opening the swap dialog, close existing dialog
  47      if (searchParams.has("swap", "true")) {
  48        setDialog(undefined);
  49      }
  50    }, [searchParams]);
  51  
  52    return (
  53      <AlertDialog
  54        open={!!dialog}
  55        onOpenChange={(open) => {
  56          if (!open) {
  57            setDialog(undefined);
  58          }
  59        }}
  60      >
  61        <DropdownMenu modal={false}>
  62          <Button asChild size="icon" variant="ghost">
  63            <DropdownMenuTrigger>
  64              <MoreHorizontalIcon />
  65            </DropdownMenuTrigger>
  66          </Button>
  67          <DropdownMenuContent align="end" className="w-64">
  68            {channel.status == "online" &&
  69              channel.remoteBalanceMsat > channel.localSpendableBalanceMsat &&
  70              hasMultipleChannels && (
  71                <AlertDialogTrigger asChild>
  72                  <DropdownMenuItem onClick={() => setDialog("rebalance")}>
  73                    <ScaleIcon />
  74                    Rebalance In
  75                  </DropdownMenuItem>
  76                </AlertDialogTrigger>
  77              )}
  78            <DropdownMenuItem>
  79              <ExternalLink
  80                className="flex flex-1 flex-row items-center gap-2"
  81                to={`${info?.mempoolUrl}/tx/${channel.fundingTxId}#flow=&vout=${channel.fundingTxVout}`}
  82              >
  83                <ExternalLinkIcon />
  84                View Funding Transaction
  85              </ExternalLink>
  86            </DropdownMenuItem>
  87            <DropdownMenuItem>
  88              <ExternalLink
  89                className="flex flex-1 flex-row items-center gap-2"
  90                to={`https://amboss.space/node/${channel.remotePubkey}`}
  91              >
  92                <ExternalLinkIcon />
  93                View Node on amboss.space
  94              </ExternalLink>
  95            </DropdownMenuItem>
  96            {channel.public && (
  97              <AlertDialogTrigger asChild>
  98                <DropdownMenuItem onClick={() => setDialog("routingFee")}>
  99                  <HandCoinsIcon />
 100                  Set Routing Fee
 101                </DropdownMenuItem>
 102              </AlertDialogTrigger>
 103            )}
 104            <AlertDialogTrigger asChild>
 105              <DropdownMenuItem
 106                variant="destructive"
 107                onClick={() => setDialog("closeChannel")}
 108              >
 109                <Trash2Icon />
 110                Close Channel
 111              </DropdownMenuItem>
 112            </AlertDialogTrigger>
 113          </DropdownMenuContent>
 114        </DropdownMenu>
 115        {dialog === "closeChannel" && (
 116          <CloseChannelDialogContent alias={alias} channel={channel} />
 117        )}
 118        {dialog === "routingFee" && <RoutingFeeDialogContent channel={channel} />}
 119        {dialog === "rebalance" && (
 120          <RebalanceChannelDialogContent
 121            receiveThroughNodePubkey={channel.remotePubkey}
 122            closeDialog={() => setDialog(undefined)}
 123          />
 124        )}
 125      </AlertDialog>
 126    );
 127  }
 128