diff --git a/src/assets/icons/private-eye.svg b/src/assets/icons/private-eye.svg new file mode 100644 index 0000000..3d63610 --- /dev/null +++ b/src/assets/icons/private-eye.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/components/AmountEditable.tsx b/src/components/AmountEditable.tsx index a029ead..2ea426d 100644 --- a/src/components/AmountEditable.tsx +++ b/src/components/AmountEditable.tsx @@ -7,7 +7,7 @@ import { Show } from "solid-js"; -import { AmountSats, BigMoney } from "~/components"; +import { AmountSats, BigMoney, SharpButton } from "~/components"; import { useMegaStore } from "~/state/megaStore"; import { btcFloatRounding, @@ -106,7 +106,6 @@ export const AmountEditable: ParentComponent<{ ); } } else { - console.log("we're in the fiat branch"); sane = fiatInputSanitizer( value.replace(",", "."), state.fiat.maxFractionalDigits @@ -270,20 +269,17 @@ function MethodChooser(props: { props.setChosenMethod && props.setChosenMethod(nextMethod); } return ( - + <> + + + + ); } diff --git a/src/components/BigMoney.tsx b/src/components/BigMoney.tsx index 956efd5..0898761 100644 --- a/src/components/BigMoney.tsx +++ b/src/components/BigMoney.tsx @@ -103,7 +103,7 @@ export function BigMoney(props: {
diff --git a/src/components/SharpButton.tsx b/src/components/SharpButton.tsx new file mode 100644 index 0000000..b17da58 --- /dev/null +++ b/src/components/SharpButton.tsx @@ -0,0 +1,21 @@ +import { JSX } from "solid-js"; + +export function SharpButton(props: { + onClick: () => void; + children: JSX.Element; + disabled?: boolean; +}) { + return ( + + ); +} diff --git a/src/components/index.ts b/src/components/index.ts index 241728b..0bd0e28 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -50,3 +50,4 @@ export * from "./FeeDisplay"; export * from "./ReceiveWarnings"; export * from "./SimpleInput"; export * from "./LabelCircle"; +export * from "./SharpButton"; diff --git a/src/i18n/en/translations.ts b/src/i18n/en/translations.ts index 120f9e8..6d32bb8 100644 --- a/src/i18n/en/translations.ts +++ b/src/i18n/en/translations.ts @@ -126,6 +126,7 @@ export default { sats_sent: "sats sent" }, what_for: "What's this for?", + zap_note: "Zap note", error_low_balance: "We do not have enough balance to pay the given amount.", error_invoice_match: @@ -144,7 +145,9 @@ export default { payment_pending_description: "It's taking a while, but it's possible this payment may still go through. Please check 'Activity' for the current status.", hodl_invoice_warning: - "This is a hodl invoice. Payments to hodl invoices can cause channel force closes, which results in high on-chain fees. Pay at your own risk!" + "This is a hodl invoice. Payments to hodl invoices can cause channel force closes, which results in high on-chain fees. Pay at your own risk!", + private: "Private", + anonzap: "Anon Zap" }, feedback: { header: "Give us feedback!", diff --git a/src/routes/Send.tsx b/src/routes/Send.tsx index 208fdf7..4d4164e 100644 --- a/src/routes/Send.tsx +++ b/src/routes/Send.tsx @@ -1,4 +1,4 @@ -import { MutinyInvoice } from "@mutinywallet/mutiny-wasm"; +import { MutinyInvoice, TagItem } from "@mutinywallet/mutiny-wasm"; import { A, useNavigate, useSearchParams } from "@solidjs/router"; import { createEffect, @@ -16,6 +16,7 @@ import { import bolt from "~/assets/icons/bolt.svg"; import chain from "~/assets/icons/chain.svg"; import close from "~/assets/icons/close.svg"; +import privateEye from "~/assets/icons/private-eye.svg"; import { ActivityDetailsModal, AmountEditable, @@ -36,6 +37,7 @@ import { MethodChoice, MutinyWalletGuard, NavBar, + SharpButton, showToast, SimpleInput, SmallHeader, @@ -72,36 +74,18 @@ function DestinationShower(props: { nodePubkey?: string; lnurl?: string; lightning_address?: string; - contact_id?: string; + contact?: TagItem; }) { - const [state, _actions] = useMegaStore(); - - async function getContact(id: string) { - console.log("fetching contact", id); - try { - const contact = state.mutiny_wallet?.get_tag_item(id); - console.log("fetching contact", contact); - // This shouldn't happen - if (!contact) throw new Error("Contact not found"); - return contact; - } catch (e) { - console.error(e); - showToast(eify(e)); - } - } - - const [contact] = createResource(() => props.contact_id, getContact); - return ( - + @@ -253,6 +237,7 @@ export function Send() { // These can be derived from the destination or set by the user const [amountSats, setAmountSats] = createSignal(0n); + const [unparsedAmount, setUnparsedAmount] = createSignal(true); // These are derived from the incoming destination const [isAmtEditable, setIsAmtEditable] = createSignal(true); @@ -509,8 +494,14 @@ export function Send() { } else { const parsed = BigInt(amountInput()); console.log("parsed", parsed); + if (!parsed) { + setUnparsedAmount(true); + } if (parsed > 0n) { setAmountSats(parsed); + setUnparsedAmount(false); + } else { + setUnparsedAmount(true); } } }); @@ -574,12 +565,18 @@ export function Send() { sentDetails.fee_estimate = payment?.fees_paid || 0; } } else if (source() === "lightning" && lnurlp()) { + const zapNpub = + visibility() === "anonzap" && contact()?.npub + ? contact()?.npub + : undefined; + console.log("zapnpub", zapNpub); + const comment = zapNpub ? whatForInput() : undefined; const payment = await state.mutiny_wallet?.lnurl_pay( lnurlp()!, amountSats(), - undefined, // zap_npub + zapNpub, // zap_npub tags, - undefined // comment + comment // comment ); sentDetails.payment_hash = payment?.payment_hash; @@ -646,9 +643,11 @@ export function Send() { const sendButtonDisabled = createMemo(() => { return ( + unparsedAmount() || parsingDestination() || sending() || - amountSats() === 0n || + amountSats() == 0n || + amountSats() === undefined || !!error() ); }); @@ -706,6 +705,34 @@ export function Send() { } }); + const [visibility, setVisibility] = createSignal<"private" | "anonzap">( + "private" + ); + + function toggleVisibility() { + if (visibility() === "private") { + setVisibility("anonzap"); + } else { + setVisibility("private"); + } + } + + async function getContact(id: string) { + console.log("fetching contact", id); + try { + const contact = state.mutiny_wallet?.get_tag_item(id); + console.log("fetching contact", contact); + // This shouldn't happen + if (!contact) throw new Error("Contact not found"); + return contact; + } catch (e) { + console.error(e); + showToast(eify(e)); + } + } + + const [contact] = createResource(contactId, getContact); + return ( @@ -786,7 +813,7 @@ export function Send() { nodePubkey={nodePubkey()} lnurl={lnurlp()} lightning_address={lnAddress()} - contact_id={contactId()} + contact={contact()} />
@@ -843,6 +870,45 @@ export function Send() {
+ +
+ +
+ + + Private + + {i18n.t("send.private")} + + + + Anon Zap + + {i18n.t("send.anonzap")} + + + +
+
+
+
{ e.preventDefault(); @@ -853,7 +919,11 @@ export function Send() { > setWhatForInput(e.currentTarget.value) }