From 0748148337a076ff0a20d41f2d13bc8f4c70830d Mon Sep 17 00:00:00 2001 From: Paul Miller Date: Sat, 13 Jan 2024 16:26:40 +0000 Subject: [PATCH] method chooser for send --- src/components/AmountEditable.tsx | 67 +++++- src/components/MethodChooser.tsx | 71 ------- src/components/index.ts | 1 - src/routes/Send.tsx | 62 +++++- src/routes/Swap.tsx | 340 ++++++++++++++---------------- 5 files changed, 282 insertions(+), 259 deletions(-) delete mode 100644 src/components/MethodChooser.tsx diff --git a/src/components/AmountEditable.tsx b/src/components/AmountEditable.tsx index 2fe4d96..a029ead 100644 --- a/src/components/AmountEditable.tsx +++ b/src/components/AmountEditable.tsx @@ -7,8 +7,7 @@ import { Show } from "solid-js"; -import { AmountSmall, BigMoney } from "~/components"; -import { useI18n } from "~/i18n/context"; +import { AmountSats, BigMoney } from "~/components"; import { useMegaStore } from "~/state/megaStore"; import { btcFloatRounding, @@ -19,17 +18,32 @@ import { toDisplayHandleNaN } 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<{ initialAmountSats: string | bigint; setAmountSats: (s: bigint) => void; - maxAmountSats?: bigint; fee?: string; frozenAmount?: boolean; onSubmit?: () => void; + activeMethod?: MethodChoice; + methods?: MethodChoice[]; + setChosenMethod?: (method: MethodChoice) => void; }> = (props) => { const [state, _actions] = useMegaStore(); const [mode, setMode] = createSignal<"fiat" | "sats">("sats"); - const i18n = useI18n(); const [localSats, setLocalSats] = createSignal( props.initialAmountSats.toString() || "0" ); @@ -229,12 +243,47 @@ export const AmountEditable: ParentComponent<{ onFocus={() => focus()} /> - -

- {`${i18n.t("receive.amount_editable.balance")} `} - -

+ + ); }; + +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 ( + + ); +} diff --git a/src/components/MethodChooser.tsx b/src/components/MethodChooser.tsx deleted file mode 100644 index 05d2323..0000000 --- a/src/components/MethodChooser.tsx +++ /dev/null @@ -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 ( - - - - - - - - - - - - ); -} diff --git a/src/components/index.ts b/src/components/index.ts index 97dae08..241728b 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -49,5 +49,4 @@ export * from "./BigMoney"; export * from "./FeeDisplay"; export * from "./ReceiveWarnings"; export * from "./SimpleInput"; -export * from "./MethodChooser"; export * from "./LabelCircle"; diff --git a/src/routes/Send.tsx b/src/routes/Send.tsx index f12ab62..76ed611 100644 --- a/src/routes/Send.tsx +++ b/src/routes/Send.tsx @@ -33,6 +33,7 @@ import { MegaCheck, MegaClock, MegaEx, + MethodChoice, MutinyWalletGuard, NavBar, showToast, @@ -637,6 +638,59 @@ export function Send() { ); }); + const lightningMethod = createMemo(() => { + return { + method: "lightning", + maxAmountSats: maxLightning() + }; + }); + + const onchainMethod = createMemo(() => { + return { + method: "onchain", + maxAmountSats: maxOnchain() + }; + }); + + const sendMethods = createMemo(() => { + 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 ( @@ -726,23 +780,27 @@ export function Send() { sendButtonDisabled() ? undefined : handleSend() } + activeMethod={activeMethod()} + methods={sendMethods()} + setChosenMethod={setSourceFromMethod} />
sendButtonDisabled() ? undefined : handleSend() } + activeMethod={activeMethod()} + methods={sendMethods()} + setChosenMethod={setSourceFromMethod} /> diff --git a/src/routes/Swap.tsx b/src/routes/Swap.tsx index f82df36..a56a291 100644 --- a/src/routes/Swap.tsx +++ b/src/routes/Swap.tsx @@ -25,10 +25,8 @@ import { LargeHeader, MegaCheck, MegaEx, - MethodChooser, MutinyWalletGuard, NavBar, - SafeArea, showToast, SuccessModal, TextField, @@ -36,7 +34,6 @@ import { } from "~/components"; import { useI18n } from "~/i18n/context"; import { Network } from "~/logic/mutinyWalletSetup"; -import { SendSource } from "~/routes/Send"; import { useMegaStore } from "~/state/megaStore"; import { eify, vibrateSuccess } from "~/utils"; @@ -57,7 +54,6 @@ export function Swap() { const navigate = useNavigate(); const i18n = useI18n(); - const [source, setSource] = createSignal("onchain"); const [amountSats, setAmountSats] = createSignal(0n); const [isConnecting, setIsConnecting] = createSignal(false); @@ -92,7 +88,6 @@ export function Swap() { } function resetState() { - setSource("onchain"); setAmountSats(0n); setIsConnecting(false); setLoading(false); @@ -275,179 +270,172 @@ export function Swap() { return ( - - - - {i18n.t("swap.header")} - { - if (!open) resetState(); - }} - onConfirm={() => { - resetState(); - navigate("/"); - }} - > - - - -

- {channelOpenResult()?.failure_reason - ? channelOpenResult()?.failure_reason - ?.message - : ""} -

- {/*TODO: Error hint needs to be added for possible failure reasons*/} -
- - - - - -
-

- {i18n.t("swap.initiated")} -

-

- {i18n.t("swap.sats_added", { - amount: ( - Number( - channelOpenResult()?.channel - ?.balance - ) + - Number( - channelOpenResult()?.channel - ?.reserve - ) - ).toLocaleString() - })} -

-
- -
-
-
-

- {i18n.t("common.view_payment_details")} -

- {/*
{JSON.stringify(channelOpenResult()?.channel?.value, null, 2)}
*/} -
-
-
- - - - - - -
- - -
- -
- - {(field, props) => ( - - )} - - -
-
-
-
+ + + {i18n.t("swap.header")} + { + if (!open) resetState(); + }} + onConfirm={() => { + resetState(); + navigate("/"); + }} + > + + + +

+ {channelOpenResult()?.failure_reason + ? channelOpenResult()?.failure_reason + ?.message + : ""} +

+ {/*TODO: Error hint needs to be added for possible failure reasons*/} +
+ + + -
+ +
+

+ {i18n.t("swap.initiated")} +

+

+ {i18n.t("swap.sats_added", { + amount: ( + Number( + channelOpenResult()?.channel + ?.balance + ) + + Number( + channelOpenResult()?.channel + ?.reserve + ) + ).toLocaleString() + })} +

+
+ +
+
+
+

+ {i18n.t("common.view_payment_details")} +

+ {/*
{JSON.stringify(channelOpenResult()?.channel?.value, null, 2)}
*/} + + + +
+
+ + + + +
+ + +
+ +
+ + {(field, props) => ( + + )} + + +
+
+
+
+
0n}>
- - - +
+ + ); }