mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2025-12-17 06:14:21 +01:00
method chooser for send
This commit is contained in:
@@ -7,8 +7,7 @@ import {
|
|||||||
Show
|
Show
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
|
|
||||||
import { AmountSmall, BigMoney } from "~/components";
|
import { AmountSats, BigMoney } from "~/components";
|
||||||
import { useI18n } from "~/i18n/context";
|
|
||||||
import { useMegaStore } from "~/state/megaStore";
|
import { useMegaStore } from "~/state/megaStore";
|
||||||
import {
|
import {
|
||||||
btcFloatRounding,
|
btcFloatRounding,
|
||||||
@@ -19,17 +18,32 @@ import {
|
|||||||
toDisplayHandleNaN
|
toDisplayHandleNaN
|
||||||
} from "~/utils";
|
} from "~/utils";
|
||||||
|
|
||||||
|
export type MethodChoice = {
|
||||||
|
method: "lightning" | "onchain";
|
||||||
|
maxAmountSats?: bigint;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure to update this when we get the fedi option in here!
|
||||||
|
function methodToIcon(method: MethodChoice["method"]) {
|
||||||
|
if (method === "lightning") {
|
||||||
|
return "lightning";
|
||||||
|
} else if (method === "onchain") {
|
||||||
|
return "chain";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const AmountEditable: ParentComponent<{
|
export const AmountEditable: ParentComponent<{
|
||||||
initialAmountSats: string | bigint;
|
initialAmountSats: string | bigint;
|
||||||
setAmountSats: (s: bigint) => void;
|
setAmountSats: (s: bigint) => void;
|
||||||
maxAmountSats?: bigint;
|
|
||||||
fee?: string;
|
fee?: string;
|
||||||
frozenAmount?: boolean;
|
frozenAmount?: boolean;
|
||||||
onSubmit?: () => void;
|
onSubmit?: () => void;
|
||||||
|
activeMethod?: MethodChoice;
|
||||||
|
methods?: MethodChoice[];
|
||||||
|
setChosenMethod?: (method: MethodChoice) => void;
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
const [state, _actions] = useMegaStore();
|
const [state, _actions] = useMegaStore();
|
||||||
const [mode, setMode] = createSignal<"fiat" | "sats">("sats");
|
const [mode, setMode] = createSignal<"fiat" | "sats">("sats");
|
||||||
const i18n = useI18n();
|
|
||||||
const [localSats, setLocalSats] = createSignal(
|
const [localSats, setLocalSats] = createSignal(
|
||||||
props.initialAmountSats.toString() || "0"
|
props.initialAmountSats.toString() || "0"
|
||||||
);
|
);
|
||||||
@@ -229,12 +243,47 @@ export const AmountEditable: ParentComponent<{
|
|||||||
onFocus={() => focus()}
|
onFocus={() => focus()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Show when={props.maxAmountSats}>
|
<Show when={props.methods?.length && props.activeMethod}>
|
||||||
<p class="flex gap-2 px-4 py-2 text-sm font-light text-m-grey-400 md:text-base">
|
<MethodChooser
|
||||||
{`${i18n.t("receive.amount_editable.balance")} `}
|
methods={props.methods!}
|
||||||
<AmountSmall amountSats={props.maxAmountSats!} />
|
activeMethod={props.activeMethod!}
|
||||||
</p>
|
setChosenMethod={props.setChosenMethod}
|
||||||
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function MethodChooser(props: {
|
||||||
|
activeMethod: MethodChoice;
|
||||||
|
methods: MethodChoice[];
|
||||||
|
setChosenMethod?: (method: MethodChoice) => void;
|
||||||
|
}) {
|
||||||
|
function setNextMethod() {
|
||||||
|
const activeIndex = props.methods.findIndex(
|
||||||
|
(m) => m.method === props.activeMethod.method
|
||||||
|
);
|
||||||
|
const nextMethod =
|
||||||
|
props.methods[
|
||||||
|
activeIndex === props.methods.length - 1 ? 0 : activeIndex + 1
|
||||||
|
];
|
||||||
|
props.setChosenMethod && props.setChosenMethod(nextMethod);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={setNextMethod}
|
||||||
|
disabled={props.methods.length === 1}
|
||||||
|
class="flex gap-2 rounded px-2 py-1 text-sm font-light text-m-grey-400 md:text-base"
|
||||||
|
classList={{
|
||||||
|
"border-b border-t border-b-white/10 border-t-white/50 bg-neutral-700":
|
||||||
|
props.methods?.length > 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AmountSats
|
||||||
|
amountSats={props.activeMethod.maxAmountSats!}
|
||||||
|
denominationSize="sm"
|
||||||
|
icon={methodToIcon(props.activeMethod.method)}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
import { createMemo, Match, Switch } from "solid-js";
|
|
||||||
|
|
||||||
import { StyledRadioGroup } from "~/components";
|
|
||||||
import { useMegaStore } from "~/state/megaStore";
|
|
||||||
|
|
||||||
type SendSource = "lightning" | "onchain";
|
|
||||||
|
|
||||||
export function MethodChooser(props: {
|
|
||||||
source: SendSource;
|
|
||||||
setSource: (source: string) => void;
|
|
||||||
both?: boolean;
|
|
||||||
}) {
|
|
||||||
const [store, _actions] = useMegaStore();
|
|
||||||
|
|
||||||
const methods = createMemo(() => {
|
|
||||||
const lnBalance =
|
|
||||||
(store.balance?.lightning || 0n) +
|
|
||||||
(store.balance?.federation || 0n);
|
|
||||||
const onchainBalance =
|
|
||||||
(store.balance?.confirmed || 0n) +
|
|
||||||
(store.balance?.unconfirmed || 0n);
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
value: "lightning",
|
|
||||||
label: "Lightning Balance",
|
|
||||||
caption:
|
|
||||||
lnBalance > 0n
|
|
||||||
? `${lnBalance.toLocaleString()} SATS`
|
|
||||||
: "No balance",
|
|
||||||
disabled: lnBalance === 0n
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "onchain",
|
|
||||||
label: "On-chain Balance",
|
|
||||||
caption:
|
|
||||||
onchainBalance > 0n
|
|
||||||
? `${onchainBalance.toLocaleString()} SATS`
|
|
||||||
: "No balance",
|
|
||||||
disabled: onchainBalance === 0n
|
|
||||||
}
|
|
||||||
];
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<Switch>
|
|
||||||
<Match when={props.both}>
|
|
||||||
<StyledRadioGroup
|
|
||||||
accent="white"
|
|
||||||
initialValue={props.source}
|
|
||||||
onValueChange={props.setSource}
|
|
||||||
choices={methods()}
|
|
||||||
/>
|
|
||||||
</Match>
|
|
||||||
<Match when={props.source === "lightning"}>
|
|
||||||
<StyledRadioGroup
|
|
||||||
accent="white"
|
|
||||||
initialValue={props.source}
|
|
||||||
onValueChange={props.setSource}
|
|
||||||
choices={[methods()[0]]}
|
|
||||||
/>
|
|
||||||
</Match>
|
|
||||||
<Match when={props.source === "onchain"}>
|
|
||||||
<StyledRadioGroup
|
|
||||||
accent="white"
|
|
||||||
initialValue={props.source}
|
|
||||||
onValueChange={props.setSource}
|
|
||||||
choices={[methods()[1]]}
|
|
||||||
/>
|
|
||||||
</Match>
|
|
||||||
</Switch>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -49,5 +49,4 @@ export * from "./BigMoney";
|
|||||||
export * from "./FeeDisplay";
|
export * from "./FeeDisplay";
|
||||||
export * from "./ReceiveWarnings";
|
export * from "./ReceiveWarnings";
|
||||||
export * from "./SimpleInput";
|
export * from "./SimpleInput";
|
||||||
export * from "./MethodChooser";
|
|
||||||
export * from "./LabelCircle";
|
export * from "./LabelCircle";
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
MegaCheck,
|
MegaCheck,
|
||||||
MegaClock,
|
MegaClock,
|
||||||
MegaEx,
|
MegaEx,
|
||||||
|
MethodChoice,
|
||||||
MutinyWalletGuard,
|
MutinyWalletGuard,
|
||||||
NavBar,
|
NavBar,
|
||||||
showToast,
|
showToast,
|
||||||
@@ -637,6 +638,59 @@ export function Send() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const lightningMethod = createMemo<MethodChoice>(() => {
|
||||||
|
return {
|
||||||
|
method: "lightning",
|
||||||
|
maxAmountSats: maxLightning()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const onchainMethod = createMemo<MethodChoice>(() => {
|
||||||
|
return {
|
||||||
|
method: "onchain",
|
||||||
|
maxAmountSats: maxOnchain()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const sendMethods = createMemo<MethodChoice[]>(() => {
|
||||||
|
if (lnAddress() || lnurlp() || nodePubkey()) {
|
||||||
|
return [lightningMethod()];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invoice() && address()) {
|
||||||
|
return [lightningMethod(), onchainMethod()];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invoice()) {
|
||||||
|
return [lightningMethod()];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address()) {
|
||||||
|
return [onchainMethod()];
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should never get here
|
||||||
|
console.error("No send methods found");
|
||||||
|
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
function setSourceFromMethod(method: MethodChoice) {
|
||||||
|
if (method.method === "lightning") {
|
||||||
|
setSource("lightning");
|
||||||
|
} else if (method.method === "onchain") {
|
||||||
|
setSource("onchain");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeMethod = createMemo(() => {
|
||||||
|
if (source() === "lightning") {
|
||||||
|
return lightningMethod();
|
||||||
|
} else if (source() === "onchain") {
|
||||||
|
return onchainMethod();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MutinyWalletGuard>
|
<MutinyWalletGuard>
|
||||||
<DefaultMain>
|
<DefaultMain>
|
||||||
@@ -726,23 +780,27 @@ export function Send() {
|
|||||||
<AmountEditable
|
<AmountEditable
|
||||||
initialAmountSats={amountSats()}
|
initialAmountSats={amountSats()}
|
||||||
setAmountSats={setAmountInput}
|
setAmountSats={setAmountInput}
|
||||||
maxAmountSats={maxAmountSats()}
|
|
||||||
fee={feeEstimate()?.toString()}
|
fee={feeEstimate()?.toString()}
|
||||||
onSubmit={() =>
|
onSubmit={() =>
|
||||||
sendButtonDisabled() ? undefined : handleSend()
|
sendButtonDisabled() ? undefined : handleSend()
|
||||||
}
|
}
|
||||||
|
activeMethod={activeMethod()}
|
||||||
|
methods={sendMethods()}
|
||||||
|
setChosenMethod={setSourceFromMethod}
|
||||||
/>
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={!isAmtEditable()}>
|
<Show when={!isAmtEditable()}>
|
||||||
<AmountEditable
|
<AmountEditable
|
||||||
initialAmountSats={amountSats()}
|
initialAmountSats={amountSats()}
|
||||||
setAmountSats={setAmountInput}
|
setAmountSats={setAmountInput}
|
||||||
maxAmountSats={maxAmountSats()}
|
|
||||||
fee={feeEstimate()?.toString()}
|
fee={feeEstimate()?.toString()}
|
||||||
frozenAmount={true}
|
frozenAmount={true}
|
||||||
onSubmit={() =>
|
onSubmit={() =>
|
||||||
sendButtonDisabled() ? undefined : handleSend()
|
sendButtonDisabled() ? undefined : handleSend()
|
||||||
}
|
}
|
||||||
|
activeMethod={activeMethod()}
|
||||||
|
methods={sendMethods()}
|
||||||
|
setChosenMethod={setSourceFromMethod}
|
||||||
/>
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={feeEstimate()}>
|
<Show when={feeEstimate()}>
|
||||||
|
|||||||
@@ -25,10 +25,8 @@ import {
|
|||||||
LargeHeader,
|
LargeHeader,
|
||||||
MegaCheck,
|
MegaCheck,
|
||||||
MegaEx,
|
MegaEx,
|
||||||
MethodChooser,
|
|
||||||
MutinyWalletGuard,
|
MutinyWalletGuard,
|
||||||
NavBar,
|
NavBar,
|
||||||
SafeArea,
|
|
||||||
showToast,
|
showToast,
|
||||||
SuccessModal,
|
SuccessModal,
|
||||||
TextField,
|
TextField,
|
||||||
@@ -36,7 +34,6 @@ import {
|
|||||||
} from "~/components";
|
} from "~/components";
|
||||||
import { useI18n } from "~/i18n/context";
|
import { useI18n } from "~/i18n/context";
|
||||||
import { Network } from "~/logic/mutinyWalletSetup";
|
import { Network } from "~/logic/mutinyWalletSetup";
|
||||||
import { SendSource } from "~/routes/Send";
|
|
||||||
import { useMegaStore } from "~/state/megaStore";
|
import { useMegaStore } from "~/state/megaStore";
|
||||||
import { eify, vibrateSuccess } from "~/utils";
|
import { eify, vibrateSuccess } from "~/utils";
|
||||||
|
|
||||||
@@ -57,7 +54,6 @@ export function Swap() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const [source, setSource] = createSignal<SendSource>("onchain");
|
|
||||||
const [amountSats, setAmountSats] = createSignal(0n);
|
const [amountSats, setAmountSats] = createSignal(0n);
|
||||||
const [isConnecting, setIsConnecting] = createSignal(false);
|
const [isConnecting, setIsConnecting] = createSignal(false);
|
||||||
|
|
||||||
@@ -92,7 +88,6 @@ export function Swap() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resetState() {
|
function resetState() {
|
||||||
setSource("onchain");
|
|
||||||
setAmountSats(0n);
|
setAmountSats(0n);
|
||||||
setIsConnecting(false);
|
setIsConnecting(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -275,179 +270,172 @@ export function Swap() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<MutinyWalletGuard>
|
<MutinyWalletGuard>
|
||||||
<SafeArea>
|
<DefaultMain>
|
||||||
<DefaultMain>
|
<BackLink />
|
||||||
<BackLink />
|
<LargeHeader>{i18n.t("swap.header")}</LargeHeader>
|
||||||
<LargeHeader>{i18n.t("swap.header")}</LargeHeader>
|
<SuccessModal
|
||||||
<SuccessModal
|
confirmText={
|
||||||
confirmText={
|
channelOpenResult()?.channel
|
||||||
channelOpenResult()?.channel
|
? i18n.t("common.nice")
|
||||||
? i18n.t("common.nice")
|
: i18n.t("common.home")
|
||||||
: i18n.t("common.home")
|
}
|
||||||
}
|
open={!!channelOpenResult()}
|
||||||
open={!!channelOpenResult()}
|
setOpen={(open: boolean) => {
|
||||||
setOpen={(open: boolean) => {
|
if (!open) resetState();
|
||||||
if (!open) resetState();
|
}}
|
||||||
}}
|
onConfirm={() => {
|
||||||
onConfirm={() => {
|
resetState();
|
||||||
resetState();
|
navigate("/");
|
||||||
navigate("/");
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<Switch>
|
||||||
<Switch>
|
<Match when={channelOpenResult()?.failure_reason}>
|
||||||
<Match when={channelOpenResult()?.failure_reason}>
|
<MegaEx />
|
||||||
<MegaEx />
|
<h1 class="mb-2 mt-4 w-full text-center text-2xl font-semibold md:text-3xl">
|
||||||
<h1 class="mb-2 mt-4 w-full text-center text-2xl font-semibold md:text-3xl">
|
{channelOpenResult()?.failure_reason
|
||||||
{channelOpenResult()?.failure_reason
|
? channelOpenResult()?.failure_reason
|
||||||
? channelOpenResult()?.failure_reason
|
?.message
|
||||||
?.message
|
: ""}
|
||||||
: ""}
|
</h1>
|
||||||
</h1>
|
{/*TODO: Error hint needs to be added for possible failure reasons*/}
|
||||||
{/*TODO: Error hint needs to be added for possible failure reasons*/}
|
</Match>
|
||||||
</Match>
|
<Match when={channelOpenResult()?.channel}>
|
||||||
<Match when={channelOpenResult()?.channel}>
|
<Show when={detailsId() && detailsKind()}>
|
||||||
<Show when={detailsId() && detailsKind()}>
|
<ActivityDetailsModal
|
||||||
<ActivityDetailsModal
|
open={detailsOpen()}
|
||||||
open={detailsOpen()}
|
kind={detailsKind()}
|
||||||
kind={detailsKind()}
|
id={detailsId()}
|
||||||
id={detailsId()}
|
setOpen={setDetailsOpen}
|
||||||
setOpen={setDetailsOpen}
|
/>
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
<MegaCheck />
|
|
||||||
<div class="flex flex-col justify-center">
|
|
||||||
<h1 class="mb-2 mt-4 w-full justify-center text-center text-2xl font-semibold md:text-3xl">
|
|
||||||
{i18n.t("swap.initiated")}
|
|
||||||
</h1>
|
|
||||||
<p class="text-center text-xl">
|
|
||||||
{i18n.t("swap.sats_added", {
|
|
||||||
amount: (
|
|
||||||
Number(
|
|
||||||
channelOpenResult()?.channel
|
|
||||||
?.balance
|
|
||||||
) +
|
|
||||||
Number(
|
|
||||||
channelOpenResult()?.channel
|
|
||||||
?.reserve
|
|
||||||
)
|
|
||||||
).toLocaleString()
|
|
||||||
})}
|
|
||||||
</p>
|
|
||||||
<div class="text-center text-sm text-white/70">
|
|
||||||
<AmountFiat
|
|
||||||
amountSats={
|
|
||||||
Number(
|
|
||||||
channelOpenResult()?.channel
|
|
||||||
?.balance
|
|
||||||
) +
|
|
||||||
Number(
|
|
||||||
channelOpenResult()?.channel
|
|
||||||
?.reserve
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr class="w-16 bg-m-grey-400" />
|
|
||||||
<p
|
|
||||||
class="cursor-pointer underline"
|
|
||||||
onClick={openDetailsModal}
|
|
||||||
>
|
|
||||||
{i18n.t("common.view_payment_details")}
|
|
||||||
</p>
|
|
||||||
{/* <pre>{JSON.stringify(channelOpenResult()?.channel?.value, null, 2)}</pre> */}
|
|
||||||
</Match>
|
|
||||||
</Switch>
|
|
||||||
</SuccessModal>
|
|
||||||
<VStack biggap>
|
|
||||||
<MethodChooser
|
|
||||||
source={source()}
|
|
||||||
setSource={setSource}
|
|
||||||
both={false}
|
|
||||||
/>
|
|
||||||
<VStack>
|
|
||||||
<Show when={!hasLsp()}>
|
|
||||||
<Card>
|
|
||||||
<VStack>
|
|
||||||
<div class="flex w-full flex-col gap-2">
|
|
||||||
<label
|
|
||||||
for="peerselect"
|
|
||||||
class="text-sm font-semibold uppercase"
|
|
||||||
>
|
|
||||||
{i18n.t("swap.use_existing")}
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
name="peerselect"
|
|
||||||
class="w-full truncate rounded bg-black px-4 py-2"
|
|
||||||
onChange={handlePeerSelect}
|
|
||||||
value={selectedPeer()}
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
value=""
|
|
||||||
class=""
|
|
||||||
selected
|
|
||||||
>
|
|
||||||
{i18n.t("swap.choose_peer")}
|
|
||||||
</option>
|
|
||||||
<For each={peers()}>
|
|
||||||
{(peer) => (
|
|
||||||
<option
|
|
||||||
value={peer.pubkey}
|
|
||||||
>
|
|
||||||
{peer.alias ??
|
|
||||||
peer.pubkey}
|
|
||||||
</option>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<Show when={!selectedPeer()}>
|
|
||||||
<Form
|
|
||||||
onSubmit={onSubmit}
|
|
||||||
class="flex flex-col gap-4"
|
|
||||||
>
|
|
||||||
<Field
|
|
||||||
name="peer"
|
|
||||||
validate={[required("")]}
|
|
||||||
>
|
|
||||||
{(field, props) => (
|
|
||||||
<TextField
|
|
||||||
{...props}
|
|
||||||
value={field.value}
|
|
||||||
error={field.error}
|
|
||||||
label={i18n.t(
|
|
||||||
"swap.peer_connect_label"
|
|
||||||
)}
|
|
||||||
placeholder={i18n.t(
|
|
||||||
"swap.peer_connect_placeholder"
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
<Button
|
|
||||||
layout="small"
|
|
||||||
type="submit"
|
|
||||||
disabled={isConnecting()}
|
|
||||||
>
|
|
||||||
{isConnecting()
|
|
||||||
? i18n.t(
|
|
||||||
"swap.connecting"
|
|
||||||
)
|
|
||||||
: i18n.t(
|
|
||||||
"swap.connect"
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</Form>
|
|
||||||
</Show>
|
|
||||||
</VStack>
|
|
||||||
</Card>
|
|
||||||
</Show>
|
</Show>
|
||||||
</VStack>
|
<MegaCheck />
|
||||||
|
<div class="flex flex-col justify-center">
|
||||||
|
<h1 class="mb-2 mt-4 w-full justify-center text-center text-2xl font-semibold md:text-3xl">
|
||||||
|
{i18n.t("swap.initiated")}
|
||||||
|
</h1>
|
||||||
|
<p class="text-center text-xl">
|
||||||
|
{i18n.t("swap.sats_added", {
|
||||||
|
amount: (
|
||||||
|
Number(
|
||||||
|
channelOpenResult()?.channel
|
||||||
|
?.balance
|
||||||
|
) +
|
||||||
|
Number(
|
||||||
|
channelOpenResult()?.channel
|
||||||
|
?.reserve
|
||||||
|
)
|
||||||
|
).toLocaleString()
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
<div class="text-center text-sm text-white/70">
|
||||||
|
<AmountFiat
|
||||||
|
amountSats={
|
||||||
|
Number(
|
||||||
|
channelOpenResult()?.channel
|
||||||
|
?.balance
|
||||||
|
) +
|
||||||
|
Number(
|
||||||
|
channelOpenResult()?.channel
|
||||||
|
?.reserve
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="w-16 bg-m-grey-400" />
|
||||||
|
<p
|
||||||
|
class="cursor-pointer underline"
|
||||||
|
onClick={openDetailsModal}
|
||||||
|
>
|
||||||
|
{i18n.t("common.view_payment_details")}
|
||||||
|
</p>
|
||||||
|
{/* <pre>{JSON.stringify(channelOpenResult()?.channel?.value, null, 2)}</pre> */}
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
|
</SuccessModal>
|
||||||
|
<div class="flex flex-1 flex-col justify-between gap-2">
|
||||||
|
<div class="flex-1" />
|
||||||
|
<VStack biggap>
|
||||||
|
<Show when={!hasLsp()}>
|
||||||
|
<Card>
|
||||||
|
<VStack>
|
||||||
|
<div class="flex w-full flex-col gap-2">
|
||||||
|
<label
|
||||||
|
for="peerselect"
|
||||||
|
class="text-sm font-semibold uppercase"
|
||||||
|
>
|
||||||
|
{i18n.t("swap.use_existing")}
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
name="peerselect"
|
||||||
|
class="w-full truncate rounded bg-black px-4 py-2"
|
||||||
|
onChange={handlePeerSelect}
|
||||||
|
value={selectedPeer()}
|
||||||
|
>
|
||||||
|
<option value="" class="" selected>
|
||||||
|
{i18n.t("swap.choose_peer")}
|
||||||
|
</option>
|
||||||
|
<For each={peers()}>
|
||||||
|
{(peer) => (
|
||||||
|
<option value={peer.pubkey}>
|
||||||
|
{peer.alias ??
|
||||||
|
peer.pubkey}
|
||||||
|
</option>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<Show when={!selectedPeer()}>
|
||||||
|
<Form
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
class="flex flex-col gap-4"
|
||||||
|
>
|
||||||
|
<Field
|
||||||
|
name="peer"
|
||||||
|
validate={[required("")]}
|
||||||
|
>
|
||||||
|
{(field, props) => (
|
||||||
|
<TextField
|
||||||
|
{...props}
|
||||||
|
value={field.value}
|
||||||
|
error={field.error}
|
||||||
|
label={i18n.t(
|
||||||
|
"swap.peer_connect_label"
|
||||||
|
)}
|
||||||
|
placeholder={i18n.t(
|
||||||
|
"swap.peer_connect_placeholder"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
<Button
|
||||||
|
layout="small"
|
||||||
|
type="submit"
|
||||||
|
disabled={isConnecting()}
|
||||||
|
>
|
||||||
|
{isConnecting()
|
||||||
|
? i18n.t("swap.connecting")
|
||||||
|
: i18n.t("swap.connect")}
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
</Show>
|
||||||
|
</VStack>
|
||||||
|
</Card>
|
||||||
|
</Show>
|
||||||
<AmountEditable
|
<AmountEditable
|
||||||
initialAmountSats={amountSats()}
|
initialAmountSats={amountSats()}
|
||||||
setAmountSats={setAmountSats}
|
setAmountSats={setAmountSats}
|
||||||
fee={feeEstimate()?.toString()}
|
fee={feeEstimate()?.toString()}
|
||||||
maxAmountSats={maxOnchain()}
|
activeMethod={{
|
||||||
|
method: "onchain",
|
||||||
|
maxAmountSats: maxOnchain()
|
||||||
|
}}
|
||||||
|
methods={[
|
||||||
|
{
|
||||||
|
method: "onchain",
|
||||||
|
maxAmountSats: maxOnchain()
|
||||||
|
}
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
<Show when={feeEstimate() && amountSats() > 0n}>
|
<Show when={feeEstimate() && amountSats() > 0n}>
|
||||||
<FeeDisplay
|
<FeeDisplay
|
||||||
@@ -471,9 +459,9 @@ export function Swap() {
|
|||||||
{i18n.t("swap.confirm_swap")}
|
{i18n.t("swap.confirm_swap")}
|
||||||
</Button>
|
</Button>
|
||||||
</VStack>
|
</VStack>
|
||||||
</DefaultMain>
|
</div>
|
||||||
<NavBar activeTab="none" />
|
</DefaultMain>
|
||||||
</SafeArea>
|
<NavBar activeTab="none" />
|
||||||
</MutinyWalletGuard>
|
</MutinyWalletGuard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user