mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2025-12-18 23:04:25 +01:00
amount input switchable to usd
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { For, ParentComponent, Show, createMemo, createResource, createSignal } from "solid-js";
|
import { For, ParentComponent, Show, createResource, createSignal, onMount } from "solid-js";
|
||||||
import { Button } from "~/components/layout";
|
import { Button } from "~/components/layout";
|
||||||
import { useMegaStore } from "~/state/megaStore";
|
import { useMegaStore } from "~/state/megaStore";
|
||||||
import { satsToUsd } from "~/utils/conversions";
|
import { satsToUsd, usdToSats } from "~/utils/conversions";
|
||||||
import { Dialog } from "@kobalte/core";
|
import { Dialog } from "@kobalte/core";
|
||||||
import close from "~/assets/icons/close.svg";
|
import close from "~/assets/icons/close.svg";
|
||||||
import pencil from "~/assets/icons/pencil.svg";
|
import pencil from "~/assets/icons/pencil.svg";
|
||||||
@@ -12,12 +12,43 @@ 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 = [
|
const FIXED_AMOUNTS_SATS = [
|
||||||
{ label: "10k", amount: "10000" },
|
{ label: "10k", amount: "10000" },
|
||||||
{ label: "100k", amount: "100000" },
|
{ label: "100k", amount: "100000" },
|
||||||
{ label: "1m", amount: "1000000" }
|
{ label: "1m", amount: "1000000" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const FIXED_AMOUNTS_USD = [
|
||||||
|
{ 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.");
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
return noLeadingZero;
|
||||||
|
}
|
||||||
|
|
||||||
function SingleDigitButton(props: {
|
function SingleDigitButton(props: {
|
||||||
character: string;
|
character: string;
|
||||||
onClick: (c: string) => void;
|
onClick: (c: string) => void;
|
||||||
@@ -27,7 +58,6 @@ function SingleDigitButton(props: {
|
|||||||
// Skip the "." if it's fiat
|
// Skip the "." if it's fiat
|
||||||
<Show when={props.fiat || !(props.character === ".")} fallback={<div />}>
|
<Show when={props.fiat || !(props.character === ".")} fallback={<div />}>
|
||||||
<button
|
<button
|
||||||
disabled={props.character === "."}
|
|
||||||
class="disabled:opacity-50 p-2 rounded-lg md:hover:bg-white/10 active:bg-m-blue text-white text-4xl font-semi font-mono"
|
class="disabled:opacity-50 p-2 rounded-lg md:hover:bg-white/10 active:bg-m-blue text-white text-4xl font-semi font-mono"
|
||||||
onClick={() => props.onClick(props.character)}
|
onClick={() => props.onClick(props.character)}
|
||||||
>
|
>
|
||||||
@@ -37,18 +67,65 @@ function SingleDigitButton(props: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function BigScalingText(props: { text: string; fiat: boolean }) {
|
||||||
|
const chars = () => props.text.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<h1
|
||||||
|
class="font-light text-center transition-transform ease-out duration-300 text-4xl"
|
||||||
|
classList={{
|
||||||
|
"scale-90": chars() > 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} <span class="text-xl">{props.fiat ? "USD" : "SATS"}</span>
|
||||||
|
</h1>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SmallSubtleAmount(props: { text: string; fiat: boolean }) {
|
||||||
|
return (
|
||||||
|
<h2 class="text-xl font-light text-neutral-400">
|
||||||
|
≈ {props.text} <span class="text-sm">{props.fiat ? "USD" : "SATS"}</span>
|
||||||
|
</h2>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toDisplayHandleNaN(input: string, _fiat: boolean): string {
|
||||||
|
const parsed = Number(input);
|
||||||
|
if (isNaN(parsed)) {
|
||||||
|
return "0";
|
||||||
|
} else {
|
||||||
|
return parsed.toLocaleString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const AmountEditable: ParentComponent<{
|
export const AmountEditable: ParentComponent<{
|
||||||
initialAmountSats: string;
|
initialAmountSats: string;
|
||||||
initialOpen: boolean;
|
initialOpen: boolean;
|
||||||
setAmountSats: (s: bigint) => void;
|
setAmountSats: (s: bigint) => void;
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
const [isOpen, setIsOpen] = createSignal(props.initialOpen);
|
const [isOpen, setIsOpen] = createSignal(props.initialOpen);
|
||||||
const [store, _actions] = useMegaStore();
|
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 [displayAmount, setDisplayAmount] = createSignal(props.initialAmountSats || "0");
|
const displaySats = () => toDisplayHandleNaN(localSats(), false);
|
||||||
|
const displayFiat = () => `$${toDisplayHandleNaN(localFiat(), true)}`;
|
||||||
|
|
||||||
|
let satsInputRef!: HTMLInputElement;
|
||||||
|
let fiatInputRef!: HTMLInputElement;
|
||||||
|
|
||||||
const [inboundCapacity] = createResource(async () => {
|
const [inboundCapacity] = createResource(async () => {
|
||||||
const channels = await store.mutiny_wallet?.list_channels();
|
const channels = await state.mutiny_wallet?.list_channels();
|
||||||
let inbound = 0;
|
let inbound = 0;
|
||||||
|
|
||||||
for (const channel of channels) {
|
for (const channel of channels) {
|
||||||
@@ -59,7 +136,7 @@ export const AmountEditable: ParentComponent<{
|
|||||||
});
|
});
|
||||||
|
|
||||||
const warningText = () => {
|
const warningText = () => {
|
||||||
if ((store.balance?.lightning || 0n) === 0n) {
|
if ((state.balance?.lightning || 0n) === 0n) {
|
||||||
const network = state.mutiny_wallet?.get_network() as Network;
|
const network = state.mutiny_wallet?.get_network() as Network;
|
||||||
if (network === "bitcoin") {
|
if (network === "bitcoin") {
|
||||||
return "Your first lightning receive needs to be 50,000 sats or greater.";
|
return "Your first lightning receive needs to be 50,000 sats or greater.";
|
||||||
@@ -68,7 +145,7 @@ export const AmountEditable: ParentComponent<{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsed = Number(displayAmount());
|
const parsed = Number(localSats());
|
||||||
if (isNaN(parsed)) {
|
if (isNaN(parsed)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -80,119 +157,91 @@ export const AmountEditable: ParentComponent<{
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
let inputRef!: HTMLInputElement;
|
|
||||||
|
|
||||||
function handleCharacterInput(character: string) {
|
function handleCharacterInput(character: string) {
|
||||||
|
const isFiatMode = mode() === "fiat";
|
||||||
|
const inputSanitizer = isFiatMode ? fiatInputSanitizer : satsInputSanitizer;
|
||||||
|
const localValue = isFiatMode ? localFiat : localSats;
|
||||||
|
const inputRef = isFiatMode ? fiatInputRef : satsInputRef;
|
||||||
|
|
||||||
|
let sane;
|
||||||
|
|
||||||
if (character === "DEL") {
|
if (character === "DEL") {
|
||||||
setDisplayAmount(displayAmount().slice(0, -1));
|
sane = inputSanitizer(localValue().slice(0, -1));
|
||||||
} else {
|
} else {
|
||||||
if (displayAmount() === "0") {
|
if (localValue() === "0") {
|
||||||
setDisplayAmount(character);
|
sane = inputSanitizer(character);
|
||||||
} else {
|
} else {
|
||||||
setDisplayAmount(displayAmount() + character);
|
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
|
// After a button press make sure we re-focus the input
|
||||||
inputRef.focus();
|
inputRef.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// making a "controlled" input is a known hard problem
|
function setFixedAmount(amount: string) {
|
||||||
// https://github.com/solidjs/solid/discussions/416
|
if (mode() === "fiat") {
|
||||||
function handleHiddenInput(
|
setLocalFiat(amount);
|
||||||
e: Event & {
|
setLocalSats(usdToSats(state.price, parseFloat(amount || "0") || 0, false));
|
||||||
currentTarget: HTMLInputElement;
|
|
||||||
target: HTMLInputElement;
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
// if the input is empty, set the display amount to 0
|
|
||||||
if (e.target.value === "") {
|
|
||||||
setDisplayAmount("0");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the input starts with one or more 0s, remove them, unless the input is just 0
|
|
||||||
if (e.target.value.startsWith("0") && e.target.value !== "0") {
|
|
||||||
setDisplayAmount(e.target.value.replace(/^0+/, ""));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there's already a decimal point, don't allow another one
|
|
||||||
if (e.target.value.includes(".") && e.target.value.endsWith(".")) {
|
|
||||||
setDisplayAmount(e.target.value.slice(0, -1));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setDisplayAmount(e.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// I tried to do this with cooler math but I think it gets confused between decimal and percent
|
|
||||||
const scale = createMemo(() => {
|
|
||||||
const chars = displayAmount().length;
|
|
||||||
|
|
||||||
if (chars > 9) {
|
|
||||||
return "scale-90";
|
|
||||||
} else if (chars > 8) {
|
|
||||||
return "scale-95";
|
|
||||||
} else if (chars > 7) {
|
|
||||||
return "scale-100";
|
|
||||||
} else if (chars > 6) {
|
|
||||||
return "scale-105";
|
|
||||||
} else if (chars > 5) {
|
|
||||||
return "scale-110";
|
|
||||||
} else if (chars > 4) {
|
|
||||||
return "scale-125";
|
|
||||||
} else {
|
} else {
|
||||||
return "scale-150";
|
setLocalSats(amount);
|
||||||
|
setLocalFiat(satsToUsd(state.price, Number(amount) || 0, false));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
const prettyPrint = createMemo(() => {
|
|
||||||
const parsed = Number(displayAmount());
|
|
||||||
if (isNaN(parsed)) {
|
|
||||||
return displayAmount();
|
|
||||||
} else {
|
|
||||||
return parsed.toLocaleString();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Fiat conversion
|
|
||||||
const [state, _] = useMegaStore();
|
|
||||||
|
|
||||||
const amountInUsd = () => satsToUsd(state.price, Number(displayAmount()) || 0, true);
|
|
||||||
|
|
||||||
// What we're all here for in the first place: returning a value
|
// What we're all here for in the first place: returning a value
|
||||||
function handleSubmit(e: SubmitEvent | MouseEvent) {
|
function handleSubmit(e: SubmitEvent | MouseEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
props.setAmountSats(BigInt(localSats()));
|
||||||
// validate it's a number
|
|
||||||
console.log("handling submit...");
|
|
||||||
console.log(displayAmount());
|
|
||||||
const number = Number(displayAmount());
|
|
||||||
if (isNaN(number) || number < 0) {
|
|
||||||
setDisplayAmount("0");
|
|
||||||
inputRef.focus();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
const bign = BigInt(displayAmount());
|
|
||||||
props.setAmountSats(bign);
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsOpen(false);
|
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"));
|
||||||
|
if (mode() === "sats") {
|
||||||
|
satsInputRef.focus();
|
||||||
|
} else {
|
||||||
|
fiatInputRef.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
satsInputRef.focus();
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog.Root open={isOpen()}>
|
<Dialog.Root open={isOpen()}>
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
class="px-4 py-2 rounded-xl border-2 border-m-blue flex gap-2 items-center"
|
class="px-4 py-2 rounded-xl border-2 border-m-blue flex gap-2 items-center"
|
||||||
>
|
>
|
||||||
{/* <Amount amountSats={Number(displayAmount())} showFiat /><span>✏️</span> */}
|
|
||||||
<Show
|
<Show
|
||||||
when={displayAmount() !== "0"}
|
when={localSats() !== "0"}
|
||||||
fallback={<div class="inline-block font-semibold">Set amount</div>}
|
fallback={<div class="inline-block font-semibold">Set amount</div>}
|
||||||
>
|
>
|
||||||
<InlineAmount amount={displayAmount()} />
|
<InlineAmount amount={localSats()} />
|
||||||
</Show>
|
</Show>
|
||||||
<img src={pencil} alt="Edit" />
|
<img src={pencil} alt="Edit" />
|
||||||
{/* {props.children} */}
|
{/* {props.children} */}
|
||||||
@@ -210,36 +259,51 @@ export const AmountEditable: ParentComponent<{
|
|||||||
<img src={close} alt="Close" />
|
<img src={close} alt="Close" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<form onSubmit={handleSubmit}>
|
{/* <form onSubmit={handleSubmit} class="text-black"> */}
|
||||||
|
<form onSubmit={handleSubmit} class="opacity-0 absolute -z-10">
|
||||||
<input
|
<input
|
||||||
ref={(el) => (inputRef = el)}
|
ref={(el) => (satsInputRef = el)}
|
||||||
autofocus
|
disabled={mode() === "fiat"}
|
||||||
inputmode="none"
|
|
||||||
type="text"
|
type="text"
|
||||||
class="opacity-0 absolute -z-10"
|
value={localSats()}
|
||||||
value={displayAmount()}
|
onInput={handleSatsInput}
|
||||||
onInput={(e) => handleHiddenInput(e)}
|
inputMode="none"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
ref={(el) => (fiatInputRef = el)}
|
||||||
|
disabled={mode() === "sats"}
|
||||||
|
type="text"
|
||||||
|
value={localFiat()}
|
||||||
|
onInput={handleFiatInput}
|
||||||
|
inputMode="none"
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="flex flex-col flex-1 justify-around gap-2 max-w-[400px] mx-auto w-full">
|
<div class="flex flex-col flex-1 justify-around gap-2 max-w-[400px] mx-auto w-full">
|
||||||
<div class="w-full p-4 flex flex-col gap-4 items-center justify-center">
|
<div class="p-4 flex flex-col gap-4 items-center justify-center" onClick={toggle}>
|
||||||
<h1
|
<BigScalingText
|
||||||
class={`font-light text-center transition-transform ease-out duration-300 text-4xl ${scale()}`}
|
text={mode() === "fiat" ? displayFiat() : displaySats()}
|
||||||
>
|
fiat={mode() === "fiat"}
|
||||||
{prettyPrint()} <span class="text-xl">SATS</span>
|
/>
|
||||||
</h1>
|
<SmallSubtleAmount
|
||||||
<h2 class="text-xl font-light text-white/70">
|
text={mode() === "fiat" ? displaySats() : displayFiat()}
|
||||||
≈ {amountInUsd()} <span class="text-sm">USD</span>
|
fiat={mode() !== "fiat"}
|
||||||
</h2>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Show when={warningText()}>
|
<Show when={warningText()}>
|
||||||
<InfoBox accent="green">{warningText()}</InfoBox>
|
<InfoBox accent="green">{warningText()}</InfoBox>
|
||||||
</Show>
|
</Show>
|
||||||
<div class="flex justify-center gap-4 my-2">
|
<div class="flex justify-center gap-4 my-2">
|
||||||
<For each={FIXED_AMOUNTS}>
|
<For each={mode() === "fiat" ? FIXED_AMOUNTS_USD : FIXED_AMOUNTS_SATS}>
|
||||||
{(amount) => (
|
{(amount) => (
|
||||||
<button
|
<button
|
||||||
onClick={() => setDisplayAmount(amount.amount)}
|
onClick={() => { setFixedAmount(amount.amount)
|
||||||
|
if (mode() === "fiat") {
|
||||||
|
fiatInputRef.focus();
|
||||||
|
} else {
|
||||||
|
satsInputRef.focus();
|
||||||
|
}
|
||||||
|
}}
|
||||||
class="py-2 px-4 rounded-lg bg-white/10"
|
class="py-2 px-4 rounded-lg bg-white/10"
|
||||||
>
|
>
|
||||||
{amount.label}
|
{amount.label}
|
||||||
@@ -251,7 +315,7 @@ export const AmountEditable: ParentComponent<{
|
|||||||
<For each={CHARACTERS}>
|
<For each={CHARACTERS}>
|
||||||
{(character) => (
|
{(character) => (
|
||||||
<SingleDigitButton
|
<SingleDigitButton
|
||||||
fiat={false}
|
fiat={mode() === "fiat"}
|
||||||
character={character}
|
character={character}
|
||||||
onClick={handleCharacterInput}
|
onClick={handleCharacterInput}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,27 +2,32 @@ import { MutinyWallet } from "@mutinywallet/mutiny-wasm";
|
|||||||
|
|
||||||
export function satsToUsd(amount: number | undefined, price: number, formatted: boolean): string {
|
export function satsToUsd(amount: number | undefined, price: number, formatted: boolean): string {
|
||||||
if (typeof amount !== "number" || isNaN(amount)) {
|
if (typeof amount !== "number" || isNaN(amount)) {
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const btc = MutinyWallet.convert_sats_to_btc(BigInt(Math.floor(amount)));
|
const btc = MutinyWallet.convert_sats_to_btc(BigInt(Math.floor(amount)));
|
||||||
const usd = btc * price;
|
const usd = btc * price;
|
||||||
|
|
||||||
if (formatted) {
|
if (formatted) {
|
||||||
return usd.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
|
return usd.toLocaleString("en-US", { style: "currency", currency: "USD" });
|
||||||
|
} else {
|
||||||
|
// Some float fighting shenaningans
|
||||||
|
const roundedUsd = Math.round(usd);
|
||||||
|
if (roundedUsd * 100 === Math.round(usd * 100)) {
|
||||||
|
return usd.toFixed(0);
|
||||||
} else {
|
} else {
|
||||||
return usd.toFixed(2);
|
return usd.toFixed(2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usdToSats(amount: number | undefined, price: number, formatted: boolean): string {
|
export function usdToSats(amount: number | undefined, price: number, formatted: boolean): string {
|
||||||
if (typeof amount !== "number" || isNaN(amount)) {
|
if (typeof amount !== "number" || isNaN(amount)) {
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const btc = price / amount;
|
const btc = price / amount;
|
||||||
@@ -34,6 +39,6 @@ export function usdToSats(amount: number | undefined, price: number, formatted:
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user