import { For, Show, createMemo, createSignal } from 'solid-js'; import { Button } from '~/components/layout'; import { useMegaStore } from '~/state/megaStore'; import { satsToUsd } from '~/utils/conversions'; import { Amount } from './Amount'; import { Dialog } from '@kobalte/core'; import close from "~/assets/icons/close.svg"; const CHARACTERS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "0", "DEL"]; const FIXED_AMOUNTS = [{ label: "10k", amount: "10000" }, { label: "100k", amount: "100000" }, { label: "1m", amount: "1000000" }] function SingleDigitButton(props: { character: string, onClick: (c: string) => void, fiat: boolean }) { return ( // Skip the "." if it's fiat }> props.onClick(props.character)} > {props.character} ); } export function AmountEditable(props: { initialAmountSats: string, setAmountSats: (s: bigint) => void }) { const [isOpen, setIsOpen] = createSignal(false); const [displayAmount, setDisplayAmount] = createSignal(props.initialAmountSats || "0"); let inputRef!: HTMLInputElement; function handleCharacterInput(character: string) { if (character === "DEL") { setDisplayAmount(displayAmount().slice(0, -1)); } else { if (displayAmount() === "0") { setDisplayAmount(character); } else { setDisplayAmount(displayAmount() + character); } } // After a button press make sure we re-focus the input inputRef.focus() } // making a "controlled" input is a known hard problem // https://github.com/solidjs/solid/discussions/416 function handleHiddenInput(e: Event & { 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 { return "scale-150" } }) 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 function handleSubmit(e: SubmitEvent | MouseEvent) { e.preventDefault() // 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); } const DIALOG_POSITIONER = "fixed inset-0 safe-top safe-bottom z-50" const DIALOG_CONTENT = "h-full safe-bottom flex flex-col justify-between p-4 backdrop-blur-xl bg-neutral-800/70" return ( setIsOpen(true)} class="p-4 rounded-xl border-2 border-m-blue"> {/* */} setIsOpen(false)}> {/* TODO: figure out how to submit on enter */} setIsOpen(false)} class="hover:bg-white/10 rounded-lg active:bg-m-blue"> inputRef = el} autofocus inputmode='none' type="text" class="opacity-0 absolute -z-10" value={displayAmount()} onInput={(e) => handleHiddenInput(e)} /> {prettyPrint()} SATS ≈ {amountInUsd()} USD {(amount) => ( setDisplayAmount(amount.amount)} class="py-2 px-4 rounded-lg bg-white/10">{amount.label} )} {(character) => ( )} Set Amount ); }