props.onClick && props.onClick()}
- class="grid grid-cols-[auto_minmax(0,_1fr)_minmax(0,_max-content)] pb-4 gap-4 border-b border-neutral-800 last:border-b-0"
- classList={{ "cursor-pointer": !!props.onClick }}
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
+ return (
+
props.onClick && props.onClick()}
+ class="grid grid-cols-[auto_minmax(0,_1fr)_minmax(0,_max-content)] pb-4 gap-4 border-b border-neutral-800 last:border-b-0"
+ classList={{ "cursor-pointer": !!props.onClick }}
+ >
+
+
+
+ 0}
+ label={props.labels?.length > 0}
+ />
+
+
+
+
+
+
+ {firstContact()?.name}
+
+
+ 0}>
+
+ {props.labels[0]}
+
+
+
+
+ Unknown
+
+
+
+
+ 2147483647}>
+
+
+
+
+
+
+
+
-
- 0}
- label={props.labels?.length > 0}
- />
-
-
-
-
-
- {firstContact()?.name}
-
- 0}>
- {props.labels[0]}
-
-
- Unknown
-
-
-
- 2147483647}>
-
-
-
-
-
-
-
-
-
- );
+ );
}
diff --git a/src/components/Amount.tsx b/src/components/Amount.tsx
index 97fb8e2..d54c48e 100644
--- a/src/components/Amount.tsx
+++ b/src/components/Amount.tsx
@@ -1,49 +1,56 @@
-import { Show } from "solid-js"
-import { useMegaStore } from "~/state/megaStore"
-import { satsToUsd } from "~/utils/conversions"
+import { Show } from "solid-js";
+import { useMegaStore } from "~/state/megaStore";
+import { satsToUsd } from "~/utils/conversions";
function prettyPrintAmount(n?: number | bigint): string {
- if (!n || n.valueOf() === 0) {
- return "0"
- }
- return n.toLocaleString()
+ if (!n || n.valueOf() === 0) {
+ return "0";
+ }
+ return n.toLocaleString();
}
export function Amount(props: {
- amountSats: bigint | number | undefined;
- showFiat?: boolean;
- loading?: boolean;
- centered?: boolean;
+ amountSats: bigint | number | undefined;
+ showFiat?: boolean;
+ loading?: boolean;
+ centered?: boolean;
}) {
- const [state, _] = useMegaStore();
+ const [state, _] = useMegaStore();
- const amountInUsd = () => satsToUsd(state.price, Number(props.amountSats) || 0, true);
+ const amountInUsd = () =>
+ satsToUsd(state.price, Number(props.amountSats) || 0, true);
- return (
-
-
- {props.loading ? "..." : prettyPrintAmount(props.amountSats)}
- SATS
-
-
-
- ≈ {props.loading ? "..." : amountInUsd()}
- USD
-
-
-
- );
+ return (
+
+
+ {props.loading ? "..." : prettyPrintAmount(props.amountSats)}
+
+ SATS
+
+
+
+ ≈ {props.loading ? "..." : amountInUsd()}
+ USD
+
+
+
+ );
}
export function AmountSmall(props: {
- amountSats: bigint | number | undefined
+ amountSats: bigint | number | undefined;
}) {
- return (
-
- {prettyPrintAmount(props.amountSats)}
-
- {props.amountSats === 1 || props.amountSats === 1n ? "SAT" : "SATS"}
-
-
- );
+ return (
+
+ {prettyPrintAmount(props.amountSats)}
+
+ {props.amountSats === 1 || props.amountSats === 1n
+ ? "SAT"
+ : "SATS"}
+
+
+ );
}
diff --git a/src/components/AmountCard.tsx b/src/components/AmountCard.tsx
index c6cc476..eec9f05 100644
--- a/src/components/AmountCard.tsx
+++ b/src/components/AmountCard.tsx
@@ -5,132 +5,172 @@ import { satsToUsd } from "~/utils/conversions";
import { AmountEditable } from "./AmountEditable";
const noop = () => {
- // do nothing
+ // do nothing
};
const KeyValue: ParentComponent<{ key: string; gray?: boolean }> = (props) => {
- return (
-
-
{props.key}
-
{props.children}
-
- );
+ return (
+
+
{props.key}
+
{props.children}
+
+ );
};
-export const InlineAmount: ParentComponent<{ amount: string; sign?: string; fiat?: boolean }> = (
- props
-) => {
- const prettyPrint = createMemo(() => {
- const parsed = Number(props.amount);
- if (isNaN(parsed)) {
- return props.amount;
- } else {
- return parsed.toLocaleString();
- }
- });
+export const InlineAmount: ParentComponent<{
+ amount: string;
+ sign?: string;
+ fiat?: boolean;
+}> = (props) => {
+ const prettyPrint = createMemo(() => {
+ const parsed = Number(props.amount);
+ if (isNaN(parsed)) {
+ return props.amount;
+ } else {
+ return parsed.toLocaleString();
+ }
+ });
- return (
-
- {props.sign ? `${props.sign} ` : ""}
- {props.fiat ? "$" : ""}
- {prettyPrint()} {props.fiat ? "USD" : "SATS"}
-
- );
+ return (
+
+ {props.sign ? `${props.sign} ` : ""}
+ {props.fiat ? "$" : ""}
+ {prettyPrint()}{" "}
+ {props.fiat ? "USD" : "SATS"}
+
+ );
};
function USDShower(props: { amountSats: string; fee?: string }) {
- const [state, _] = useMegaStore();
- const amountInUsd = () => satsToUsd(state.price, add(props.amountSats, props.fee), true);
+ const [state, _] = useMegaStore();
+ const amountInUsd = () =>
+ satsToUsd(state.price, add(props.amountSats, props.fee), true);
- return (
-
-
-
- ≈ {amountInUsd()} USD
-
-
-
- );
+ return (
+
+
+
+ ≈ {amountInUsd()}
+ USD
+
+
+
+ );
}
function add(a: string, b?: string) {
- return Number(a || 0) + Number(b || 0);
+ return Number(a || 0) + Number(b || 0);
}
export function AmountCard(props: {
- amountSats: string;
- fee?: string;
- reserve?: string;
- initialOpen?: boolean;
- isAmountEditable?: boolean;
- setAmountSats?: (amount: bigint) => void;
+ amountSats: string;
+ fee?: string;
+ reserve?: string;
+ initialOpen?: boolean;
+ isAmountEditable?: boolean;
+ setAmountSats?: (amount: bigint) => void;
}) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
diff --git a/src/components/AmountEditable.tsx b/src/components/AmountEditable.tsx
index 2cd53c4..dca324b 100644
--- a/src/components/AmountEditable.tsx
+++ b/src/components/AmountEditable.tsx
@@ -1,4 +1,11 @@
-import { For, ParentComponent, Show, createResource, createSignal, onMount } from "solid-js";
+import {
+ For,
+ ParentComponent,
+ Show,
+ createResource,
+ createSignal,
+ onMount
+} from "solid-js";
import { Button } from "~/components/layout";
import { useMegaStore } from "~/state/megaStore";
import { satsToUsd, usdToSats } from "~/utils/conversions";
@@ -10,328 +17,393 @@ import { DIALOG_CONTENT, DIALOG_POSITIONER } from "~/styles/dialogs";
import { InfoBox } from "./InfoBox";
import { Network } from "~/logic/mutinyWalletSetup";
-const CHARACTERS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "0", "DEL"];
+const CHARACTERS = [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ ".",
+ "0",
+ "DEL"
+];
const FIXED_AMOUNTS_SATS = [
- { label: "10k", amount: "10000" },
- { label: "100k", amount: "100000" },
- { label: "1m", amount: "1000000" }
+ { label: "10k", amount: "10000" },
+ { label: "100k", amount: "100000" },
+ { label: "1m", amount: "1000000" }
];
const FIXED_AMOUNTS_USD = [
- { label: "$1", amount: "1" },
- { label: "$10", amount: "10" },
- { label: "$100", amount: "100" }
+ { label: "$1", amount: "1" },
+ { label: "$10", amount: "10" },
+ { label: "$100", amount: "100" }
];
function fiatInputSanitizer(input: string): string {
- // Make sure only numbers and a single decimal point are allowed
- const numeric = input.replace(/[^0-9.]/g, "").replace(/(\..*)\./g, "$1");
-
- // Remove leading zeros if not a decimal, add 0 if starts with a decimal
- const cleaned = numeric.replace(/^0([^.]|$)/g, "$1").replace(/^\./g, "0.");
+ // Make sure only numbers and a single decimal point are allowed
+ const numeric = input.replace(/[^0-9.]/g, "").replace(/(\..*)\./g, "$1");
- // If there are three characters after the decimal, shift the decimal
- const shifted = cleaned.match(/(\.[0-9]{3}).*/g) ? (parseFloat(cleaned) * 10).toFixed(2) : cleaned;
+ // Remove leading zeros if not a decimal, add 0 if starts with a decimal
+ const cleaned = numeric.replace(/^0([^.]|$)/g, "$1").replace(/^\./g, "0.");
- // Truncate any numbers two past the decimal
- const twoDecimals = shifted.replace(/(\.[0-9]{2}).*/g, "$1");
+ // If there are three characters after the decimal, shift the decimal
+ const shifted = cleaned.match(/(\.[0-9]{3}).*/g)
+ ? (parseFloat(cleaned) * 10).toFixed(2)
+ : cleaned;
- return twoDecimals;
+ // Truncate any numbers two past the decimal
+ const twoDecimals = shifted.replace(/(\.[0-9]{2}).*/g, "$1");
+
+ return twoDecimals;
}
function satsInputSanitizer(input: string): string {
- // Make sure only numbers are allowed
- const numeric = input.replace(/[^0-9]/g, "");
- // If it starts with a 0, remove the 0
- const noLeadingZero = numeric.replace(/^0([^.]|$)/g, "$1");
+ // Make sure only numbers are allowed
+ const numeric = input.replace(/[^0-9]/g, "");
+ // If it starts with a 0, remove the 0
+ const noLeadingZero = numeric.replace(/^0([^.]|$)/g, "$1");
- return noLeadingZero;
+ return noLeadingZero;
}
function SingleDigitButton(props: {
- character: string;
- onClick: (c: string) => void;
- fiat: boolean;
+ character: string;
+ onClick: (c: string) => void;
+ fiat: boolean;
}) {
- return (
- // Skip the "." if it's fiat
-
}>
-
-
- );
+ return (
+ // Skip the "." if it's fiat
+
}
+ >
+
+
+ );
}
function BigScalingText(props: { text: string; fiat: boolean }) {
- const chars = () => props.text.length;
+ const chars = () => props.text.length;
- return (
-
9,
- "scale-95": chars() > 8,
- "scale-100": chars() > 7,
- "scale-105": chars() > 6,
- "scale-110": chars() > 5,
- "scale-125": chars() > 4,
- "scale-150": chars() <= 4
- }}
- >
- {props.text} {props.fiat ? "USD" : "SATS"}
-
- );
+ return (
+
9,
+ "scale-95": chars() > 8,
+ "scale-100": chars() > 7,
+ "scale-105": chars() > 6,
+ "scale-110": chars() > 5,
+ "scale-125": chars() > 4,
+ "scale-150": chars() <= 4
+ }}
+ >
+ {props.text}
+ {props.fiat ? "USD" : "SATS"}
+
+ );
}
function SmallSubtleAmount(props: { text: string; fiat: boolean }) {
- return (
-
- ≈ {props.text} {props.fiat ? "USD" : "SATS"}
-
- );
+ return (
+
+ ≈ {props.text}
+ {props.fiat ? "USD" : "SATS"}
+
+ );
}
function toDisplayHandleNaN(input: string, _fiat: boolean): string {
- const parsed = Number(input);
- if (isNaN(parsed)) {
- return "0";
- } else {
- return parsed.toLocaleString();
- }
+ const parsed = Number(input);
+ if (isNaN(parsed)) {
+ return "0";
+ } else {
+ return parsed.toLocaleString();
+ }
}
export const AmountEditable: ParentComponent<{
- initialAmountSats: string;
- initialOpen: boolean;
- setAmountSats: (s: bigint) => void;
+ initialAmountSats: string;
+ initialOpen: boolean;
+ setAmountSats: (s: bigint) => void;
}> = (props) => {
- const [isOpen, setIsOpen] = createSignal(props.initialOpen);
- const [state, _actions] = useMegaStore();
- const [mode, setMode] = createSignal<"fiat" | "sats">("sats");
- const [localSats, setLocalSats] = createSignal(props.initialAmountSats || "0");
- const [localFiat, setLocalFiat] = createSignal(
- satsToUsd(state.price, parseInt(props.initialAmountSats || "0") || 0, false)
- );
+ const [isOpen, setIsOpen] = createSignal(props.initialOpen);
+ const [state, _actions] = useMegaStore();
+ const [mode, setMode] = createSignal<"fiat" | "sats">("sats");
+ const [localSats, setLocalSats] = createSignal(
+ props.initialAmountSats || "0"
+ );
+ const [localFiat, setLocalFiat] = createSignal(
+ satsToUsd(
+ state.price,
+ parseInt(props.initialAmountSats || "0") || 0,
+ false
+ )
+ );
- const displaySats = () => toDisplayHandleNaN(localSats(), false);
- const displayFiat = () => `$${toDisplayHandleNaN(localFiat(), true)}`;
+ const displaySats = () => toDisplayHandleNaN(localSats(), false);
+ const displayFiat = () => `$${toDisplayHandleNaN(localFiat(), true)}`;
- let satsInputRef!: HTMLInputElement;
- let fiatInputRef!: HTMLInputElement;
+ let satsInputRef!: HTMLInputElement;
+ let fiatInputRef!: HTMLInputElement;
- const [inboundCapacity] = createResource(async () => {
- const channels = await state.mutiny_wallet?.list_channels();
- let inbound = 0;
+ const [inboundCapacity] = createResource(async () => {
+ const channels = await state.mutiny_wallet?.list_channels();
+ let inbound = 0;
- for (const channel of channels) {
- inbound += channel.size - (channel.balance + channel.reserve);
+ for (const channel of channels) {
+ inbound += channel.size - (channel.balance + channel.reserve);
+ }
+
+ return inbound;
+ });
+
+ const warningText = () => {
+ if ((state.balance?.lightning || 0n) === 0n) {
+ const network = state.mutiny_wallet?.get_network() as Network;
+ if (network === "bitcoin") {
+ return "Your first lightning receive needs to be 50,000 sats or greater.";
+ } else {
+ return "Your first lightning receive needs to be 10,000 sats or greater.";
+ }
+ }
+
+ const parsed = Number(localSats());
+ if (isNaN(parsed)) {
+ return undefined;
+ }
+
+ if (parsed > (inboundCapacity() || 0)) {
+ return "A lightning setup fee will be charged if paid over lightning.";
+ }
+
+ return undefined;
+ };
+
+ function handleCharacterInput(character: string) {
+ const isFiatMode = mode() === "fiat";
+ const inputSanitizer = isFiatMode
+ ? fiatInputSanitizer
+ : satsInputSanitizer;
+ const localValue = isFiatMode ? localFiat : localSats;
+
+ let sane;
+
+ if (character === "DEL") {
+ sane = inputSanitizer(localValue().slice(0, -1));
+ } else {
+ if (localValue() === "0") {
+ sane = inputSanitizer(character);
+ } else {
+ sane = inputSanitizer(localValue() + character);
+ }
+ }
+
+ if (isFiatMode) {
+ setLocalFiat(sane);
+ setLocalSats(
+ usdToSats(state.price, parseFloat(sane || "0") || 0, false)
+ );
+ } else {
+ setLocalSats(sane);
+ setLocalFiat(satsToUsd(state.price, Number(sane) || 0, false));
+ }
+
+ // After a button press make sure we re-focus the input
+ focus();
}
- return inbound;
- });
-
- const warningText = () => {
- if ((state.balance?.lightning || 0n) === 0n) {
- const network = state.mutiny_wallet?.get_network() as Network;
- if (network === "bitcoin") {
- return "Your first lightning receive needs to be 50,000 sats or greater.";
- } else {
- return "Your first lightning receive needs to be 10,000 sats or greater.";
- }
+ function setFixedAmount(amount: string) {
+ if (mode() === "fiat") {
+ setLocalFiat(amount);
+ setLocalSats(
+ usdToSats(state.price, parseFloat(amount || "0") || 0, false)
+ );
+ } else {
+ setLocalSats(amount);
+ setLocalFiat(satsToUsd(state.price, Number(amount) || 0, false));
+ }
}
- const parsed = Number(localSats());
- if (isNaN(parsed)) {
- return undefined;
+ // What we're all here for in the first place: returning a value
+ function handleSubmit(e: SubmitEvent | MouseEvent) {
+ e.preventDefault();
+ props.setAmountSats(BigInt(localSats()));
+ setIsOpen(false);
}
- if (parsed > (inboundCapacity() || 0)) {
- return "A lightning setup fee will be charged if paid over lightning.";
+ function handleSatsInput(e: InputEvent) {
+ const { value } = e.target as HTMLInputElement;
+ const sane = satsInputSanitizer(value);
+ setLocalSats(sane);
+ setLocalFiat(satsToUsd(state.price, Number(sane) || 0, false));
}
- return undefined;
- };
-
- function handleCharacterInput(character: string) {
- const isFiatMode = mode() === "fiat";
- const inputSanitizer = isFiatMode ? fiatInputSanitizer : satsInputSanitizer;
- const localValue = isFiatMode ? localFiat : localSats;
-
- let sane;
-
- if (character === "DEL") {
- sane = inputSanitizer(localValue().slice(0, -1));
- } else {
- if (localValue() === "0") {
- sane = inputSanitizer(character);
- } else {
- sane = inputSanitizer(localValue() + character);
- }
+ function handleFiatInput(e: InputEvent) {
+ const { value } = e.target as HTMLInputElement;
+ const sane = fiatInputSanitizer(value);
+ setLocalFiat(sane);
+ setLocalSats(
+ usdToSats(state.price, parseFloat(sane || "0") || 0, false)
+ );
}
- if (isFiatMode) {
- setLocalFiat(sane);
- setLocalSats(usdToSats(state.price, parseFloat(sane || "0") || 0, false));
- } else {
- setLocalSats(sane);
- setLocalFiat(satsToUsd(state.price, Number(sane) || 0, false));
+ function toggle() {
+ setMode((m) => (m === "sats" ? "fiat" : "sats"));
+ focus();
}
- // After a button press make sure we re-focus the input
- focus();
- }
+ onMount(() => {
+ focus();
+ });
- function setFixedAmount(amount: string) {
- if (mode() === "fiat") {
- setLocalFiat(amount);
- setLocalSats(usdToSats(state.price, parseFloat(amount || "0") || 0, false));
- } else {
- setLocalSats(amount);
- setLocalFiat(satsToUsd(state.price, Number(amount) || 0, false));
+ function focus() {
+ // Make sure we actually have the inputs mounted before we try to focus them
+ if (isOpen() && satsInputRef && fiatInputRef) {
+ if (mode() === "sats") {
+ satsInputRef.focus();
+ } else {
+ fiatInputRef.focus();
+ }
+ }
}
- }
- // What we're all here for in the first place: returning a value
- function handleSubmit(e: SubmitEvent | MouseEvent) {
- e.preventDefault();
- props.setAmountSats(BigInt(localSats()));
- setIsOpen(false);
- }
-
- function handleSatsInput(e: InputEvent) {
- const { value } = e.target as HTMLInputElement;
- const sane = satsInputSanitizer(value);
- setLocalSats(sane);
- setLocalFiat(satsToUsd(state.price, Number(sane) || 0, false));
- }
-
- function handleFiatInput(e: InputEvent) {
- const { value } = e.target as HTMLInputElement;
- const sane = fiatInputSanitizer(value);
- setLocalFiat(sane);
- setLocalSats(usdToSats(state.price, parseFloat(sane || "0") || 0, false));
- }
-
- function toggle() {
- setMode((m) => (m === "sats" ? "fiat" : "sats"));
- focus();
- }
-
- onMount(() => {
- focus();
- });
-
- function focus() {
- // Make sure we actually have the inputs mounted before we try to focus them
- if (isOpen() && satsInputRef && fiatInputRef) {
- if (mode() === "sats") {
- satsInputRef.focus();
- } else {
- fiatInputRef.focus();
- }
- }
- }
-
- return (
-
- }
- >
-