mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2026-02-20 13:44:21 +01:00
sending state and sent modal
This commit is contained in:
37
src/components/Sent.tsx
Normal file
37
src/components/Sent.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Dialog } from "@kobalte/core";
|
||||
import { ButtonLink, SmallHeader } from "~/components/layout";
|
||||
|
||||
const OVERLAY = "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
|
||||
const DIALOG_POSITIONER = "fixed inset-0 z-50 flex items-center justify-center"
|
||||
const DIALOG_CONTENT = "w-[80vw] max-w-[400px] p-4 bg-gray/50 backdrop-blur-md shadow-xl rounded-xl border border-white/10"
|
||||
|
||||
export function SentModal(props: { details?: { nice: string } }) {
|
||||
|
||||
return (
|
||||
<Dialog.Root isOpen={!!props.details}>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay class={OVERLAY} />
|
||||
<div class={DIALOG_POSITIONER}>
|
||||
<Dialog.Content class={DIALOG_CONTENT}>
|
||||
<div class="flex justify-between mb-2">
|
||||
<Dialog.Title>
|
||||
<SmallHeader>
|
||||
Sent!
|
||||
</SmallHeader>
|
||||
</Dialog.Title>
|
||||
<Dialog.CloseButton class="dialog__close-button">
|
||||
<code>X</code>
|
||||
</Dialog.CloseButton>
|
||||
</div>
|
||||
<Dialog.Description class="flex flex-col gap-4">
|
||||
<pre>
|
||||
{JSON.stringify(props.details)}
|
||||
</pre>
|
||||
<ButtonLink href="/">Nice</ButtonLink>
|
||||
</Dialog.Description>
|
||||
</Dialog.Content>
|
||||
</div>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root >
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { cva, VariantProps } from "class-variance-authority";
|
||||
import { children, JSX, ParentComponent, splitProps } from "solid-js";
|
||||
import { children, JSX, ParentComponent, Show, splitProps, Switch } from "solid-js";
|
||||
import { Dynamic } from "solid-js/web";
|
||||
import { A } from "solid-start";
|
||||
import { LoadingSpinner } from ".";
|
||||
|
||||
const button = cva("p-3 rounded-xl text-xl font-semibold disabled:opacity-50 disabled:grayscale transition", {
|
||||
variants: {
|
||||
@@ -30,7 +31,9 @@ const button = cva("p-3 rounded-xl text-xl font-semibold disabled:opacity-50 dis
|
||||
// Help from https://github.com/arpadgabor/credee/blob/main/packages/www/src/components/ui/button.tsx
|
||||
|
||||
type StyleProps = VariantProps<typeof button>
|
||||
interface ButtonProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement>, StyleProps { }
|
||||
interface ButtonProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement>, StyleProps {
|
||||
loading?: boolean
|
||||
}
|
||||
|
||||
export const Button: ParentComponent<ButtonProps> = props => {
|
||||
const slot = children(() => props.children)
|
||||
@@ -45,8 +48,13 @@ export const Button: ParentComponent<ButtonProps> = props => {
|
||||
layout: local.layout,
|
||||
})}
|
||||
>
|
||||
{slot()}
|
||||
</button>
|
||||
<Show when={props.loading} fallback={slot()} >
|
||||
<div class="flex justify-center">
|
||||
{/* TODO: constrain this to the exact height of the button */}
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
</Show>
|
||||
</button >
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { bip21decode } from "~/utils/TEMPbip21";
|
||||
import { AmountEditable } from "~/components/AmountEditable";
|
||||
import { useLocation } from "solid-start";
|
||||
import { StyledRadioGroup } from "~/components/layout/Radio";
|
||||
import { SentModal } from "~/components/Sent";
|
||||
|
||||
type SendSource = "lightning" | "onchain";
|
||||
|
||||
@@ -19,9 +20,12 @@ const PAYMENT_METHODS = [{ value: "lightning", label: "Lightning", caption: "Fas
|
||||
// const TEST_DEST = "bitcoin:tb1pdh43en28jmhnsrhxkusja46aufdlae5qnfrhucw5jvefw9flce3sdxfcwe?amount=0.00001&label=heyo&lightning=lntbs10u1pjrwrdedq8dpjhjmcnp4qd60w268ve0jencwzhz048ruprkxefhj0va2uspgj4q42azdg89uupp5gngy2pqte5q5uvnwcxwl2t8fsdlla5s6xl8aar4xcsvxeus2w2pqsp5n5jp3pz3vpu92p3uswttxmw79a5lc566herwh3f2amwz2sp6f9tq9qyysgqcqpcxqrpwugv5m534ww5ukcf6sdw2m75f2ntjfh3gzeqay649256yvtecgnhjyugf74zakaf56sdh66ec9fqep2kvu6xv09gcwkv36rrkm38ylqsgpw3yfjl"
|
||||
// const TEST_DEST_ADDRESS = "tb1pdh43en28jmhnsrhxkusja46aufdlae5qnfrhucw5jvefw9flce3sdxfcwe"
|
||||
|
||||
type SentDetails = { nice: string }
|
||||
|
||||
export default function Send() {
|
||||
const [state, _] = useMegaStore();
|
||||
|
||||
|
||||
// These can only be set by the user
|
||||
const [destination, setDestination] = createSignal("");
|
||||
const [privateLabel, setPrivateLabel] = createSignal("");
|
||||
@@ -35,6 +39,10 @@ export default function Send() {
|
||||
const [address, setAddress] = createSignal<string>();
|
||||
const [description, setDescription] = createSignal<string>();
|
||||
|
||||
// Is sending / sent
|
||||
const [sending, setSending] = createSignal(false);
|
||||
const [sentDetails, setSentDetails] = createSignal<SentDetails>();
|
||||
|
||||
function clearAll() {
|
||||
setDestination("");
|
||||
setPrivateLabel("");
|
||||
@@ -110,29 +118,39 @@ export default function Send() {
|
||||
}
|
||||
|
||||
async function handleSend() {
|
||||
const bolt11 = invoice()?.bolt11;
|
||||
if (source() === "lightning" && invoice() && bolt11) {
|
||||
const nodes = await state.node_manager?.list_nodes();
|
||||
const firstNode = nodes[0] as string || ""
|
||||
// If the invoice has sats use that, otherwise we pass the user-defined amount
|
||||
if (invoice()?.amount_sats) {
|
||||
await state.node_manager?.pay_invoice(firstNode, bolt11);
|
||||
try {
|
||||
setSending(true);
|
||||
const bolt11 = invoice()?.bolt11;
|
||||
if (source() === "lightning" && invoice() && bolt11) {
|
||||
const nodes = await state.node_manager?.list_nodes();
|
||||
const firstNode = nodes[0] as string || ""
|
||||
// If the invoice has sats use that, otherwise we pass the user-defined amount
|
||||
if (invoice()?.amount_sats) {
|
||||
await state.node_manager?.pay_invoice(firstNode, bolt11);
|
||||
} else {
|
||||
await state.node_manager?.pay_invoice(firstNode, bolt11, amountSats());
|
||||
}
|
||||
} else {
|
||||
await state.node_manager?.pay_invoice(firstNode, bolt11, amountSats());
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const txid = await state.node_manager?.send_to_address(address()!, amountSats());
|
||||
console.error(txid)
|
||||
}
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const txid = await state.node_manager?.send_to_address(address()!, amountSats());
|
||||
console.error(txid)
|
||||
|
||||
setSentDetails({ nice: "nice" });
|
||||
clearAll();
|
||||
console.error("SENT");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
setSending(false);
|
||||
}
|
||||
console.error("SENT");
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<LargeHeader>Send Bitcoin</LargeHeader>
|
||||
<SentModal details={sentDetails()} />
|
||||
<dl>
|
||||
<dt>
|
||||
<SmallHeader>Destination</SmallHeader>
|
||||
@@ -225,7 +243,7 @@ export default function Send() {
|
||||
</TextField.Root>
|
||||
</Show>
|
||||
</dl>
|
||||
<Button disabled={!destination()} intent="blue" onClick={handleSend}>Confirm Send</Button>
|
||||
<Button disabled={!destination() || sending()} intent="blue" onClick={handleSend} loading={sending()}>{sending() ? "Sending..." : "Confirm Send"}</Button>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="send" />
|
||||
</SafeArea >
|
||||
|
||||
Reference in New Issue
Block a user