import { InfoIcon } from "lucide-react";
import React, { FormEvent } from "react";
import { Link, useNavigate } from "react-router";
import { toast } from "sonner";
import AppHeader from "src/components/AppHeader";
import { ChannelPeerNote } from "src/components/channels/ChannelPeerNote";
import { ChannelPublicPrivateAlert } from "src/components/channels/ChannelPublicPrivateAlert";
import { DuplicateChannelAlert } from "src/components/channels/DuplicateChannelAlert";
import { SwapAlert } from "src/components/channels/SwapAlert";
import ExternalLink from "src/components/ExternalLink";
import { FormattedBitcoinAmount } from "src/components/FormattedBitcoinAmount";
import Loading from "src/components/Loading";
import { MempoolAlert } from "src/components/MempoolAlert";
import { Alert, AlertDescription } from "src/components/ui/alert";
import { Button } from "src/components/ui/button";
import { Checkbox } from "src/components/ui/checkbox";
import { ExternalLinkButton } from "src/components/ui/custom/external-link-button";
import { LinkButton } from "src/components/ui/custom/link-button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "src/components/ui/dialog";
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 {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "src/components/ui/tooltip";
import { useBalances } from "src/hooks/useBalances";
import { useChannelPeerSuggestions } from "src/hooks/useChannelPeerSuggestions";
import { useChannels } from "src/hooks/useChannels";
import { useInfo } from "src/hooks/useInfo";
import { usePeers } from "src/hooks/usePeers";
import { cn, formatAmount } from "src/lib/utils";
import useChannelOrderStore from "src/state/ChannelOrderStore";
import {
Channel,
Network,
NewChannelOrder,
OnchainOrder,
RecommendedChannelPeer,
} from "src/types";
import LightningNetworkDarkSVG from "public/images/illustrations/lightning-network-dark.svg";
import LightningNetworkLightSVG from "public/images/illustrations/lightning-network-light.svg";
import { useNodeDetails } from "src/hooks/useNodeDetails";
function getPeerKey(peer: RecommendedChannelPeer) {
return JSON.stringify(peer);
}
export default function IncreaseOutgoingCapacity() {
const { data: info } = useInfo();
const { data: channels } = useChannels();
if (!info?.network || !channels) {
return ;
}
return ;
}
function NewChannelInternal({
network,
channels,
}: {
network: Network;
channels: Channel[];
}) {
const { data: _channelPeerSuggestions } = useChannelPeerSuggestions();
const { data: balances } = useBalances();
const navigate = useNavigate();
const presetAmounts = [250_000, 500_000, 1_000_000];
const [order, setOrder] = React.useState>({
paymentMethod: "onchain",
status: "pay",
amountSat: presetAmounts[0].toString(),
isPublic: !!channels.length && channels.every((channel) => channel.public),
});
const [selectedPeer, setSelectedPeer] = React.useState<
RecommendedChannelPeer | undefined
>();
const [showConfirmModal, setShowConfirmModal] = React.useState(false);
const channelPeerSuggestions = React.useMemo(() => {
const customOption: RecommendedChannelPeer = {
name: "Custom",
network,
paymentMethod: "onchain",
minimumChannelSizeSat: 0,
maximumChannelSizeSat: 0,
description: "",
pubkey: "",
host: "",
image: "",
note: "",
publicChannelsAllowed: true,
};
return _channelPeerSuggestions
? [
..._channelPeerSuggestions.filter(
(peer) => peer.paymentMethod !== "lightning"
),
customOption,
]
: [customOption];
}, [_channelPeerSuggestions, network]);
function setPublic(isPublic: boolean) {
setOrder((current) => ({
...current,
isPublic,
}));
}
const setAmountSat = React.useCallback((amountSat: string) => {
setOrder((current) => ({
...current,
amountSat,
}));
}, []);
React.useEffect(() => {
if (!channelPeerSuggestions) {
return;
}
const recommendedPeer = channelPeerSuggestions.find(
(peer) =>
peer.network === network && peer.paymentMethod === order.paymentMethod
);
setSelectedPeer(recommendedPeer);
}, [network, order.paymentMethod, channelPeerSuggestions]);
React.useEffect(() => {
if (selectedPeer) {
if (
selectedPeer.paymentMethod === "onchain" &&
order.paymentMethod === "onchain"
) {
setOrder((current) => ({
...current,
pubkey: selectedPeer.pubkey,
host: selectedPeer.host,
...(!selectedPeer.publicChannelsAllowed && { isPublic: false }),
}));
}
}
}, [order.paymentMethod, selectedPeer]);
function onSubmit(e: FormEvent) {
e.preventDefault();
setShowConfirmModal(true);
}
function handleConfirmSubmit() {
try {
if (!channels) {
throw new Error("Channels not loaded");
}
if (
channels.some(
(channel) =>
channel.status === "opening" &&
channel.isOutbound &&
!channel.confirmations
)
) {
throw new Error(
"You already are opening a channel which has not been confirmed yet. Please wait for one block confirmation."
);
}
useChannelOrderStore.getState().setOrder(order as NewChannelOrder);
setShowConfirmModal(false);
navigate("/channels/order");
} catch (error) {
toast.error("Something went wrong", {
description: `${error}`,
});
setShowConfirmModal(false);
}
}
if (!channelPeerSuggestions || !balances) {
return ;
}
const openImmediately =
order.amountSat &&
order.paymentMethod === "onchain" &&
+order.amountSat < balances.onchain.spendableSat;
return (
<>
Open Channel with Lightning
}
/>
Open a channel with on-chain funds. Both parties are free to close the
channel at any time. However, by keeping more funds on your side of
the channel and using it regularly, there is more chance the channel
will stay open.{" "}
Learn more
.