import React, { useMemo } from "react"; import { Box, Text } from "ink"; import TextInput from "./TextInput.js"; import { useSatoshisConversion } from "../hooks/useSatoshisConversion.js"; interface VariableInputFieldProps { variable: { id: string; name: string; type: string; hint?: string; value: string; }; index: number; isFocused: boolean; onChange: (index: number, value: string) => void; onSubmit: () => void; borderColor: string; focusColor: string; } const SATOSHIS_PER_BCH = 100_000_000n; /** * Returns true when the variable is an integer satoshis field. */ function isSatoshisVariable(variable: VariableInputFieldProps["variable"]): boolean { return ( variable.type === "integer" && variable.hint?.toLowerCase().includes("satoshi") === true ); } /** * Parse a strict integer string into bigint. */ function parseSatoshis(value: string): bigint | null { const trimmed = value.trim(); if (!/^[-]?\d+$/.test(trimmed)) { return null; } try { return BigInt(trimmed); } catch { return null; } } /** * Format satoshis as BCH with fixed 8 decimals, preserving bigint precision. */ function formatBchFromSatoshis(satoshis: bigint): string { const sign = satoshis < 0n ? "-" : ""; const absolute = satoshis < 0n ? satoshis * -1n : satoshis; const whole = absolute / SATOSHIS_PER_BCH; const fractional = absolute % SATOSHIS_PER_BCH; return `${sign}${whole.toString()}.${fractional.toString().padStart(8, "0")} BCH`; } export function VariableInputField({ variable, index, isFocused, onChange, onSubmit, borderColor, focusColor, }: VariableInputFieldProps): React.ReactElement { const { currencyCode, formattedFiatPerBchRate, formatSatoshisToFiat } = useSatoshisConversion("USD"); const satoshisValue = useMemo( () => parseSatoshis(variable.value), [variable.value], ); const formattedBch = useMemo(() => { if (satoshisValue === null) { return null; } return formatBchFromSatoshis(satoshisValue); }, [satoshisValue]); const formattedFiat = useMemo(() => { if (satoshisValue === null) { return null; } return formatSatoshisToFiat(satoshisValue); }, [satoshisValue, formatSatoshisToFiat]); const shouldShowSatoshisConversion = isSatoshisVariable(variable); return ( {variable.name} {variable.hint && ( ({variable.hint}) )} onChange(index, value)} onSubmit={onSubmit} focus={isFocused} placeholder={`Enter ${variable.name}...`} /> {/* TODO: this may need to be conditional. Need to play around with other templates though */} {variable.hint} {shouldShowSatoshisConversion && ( {formattedBch ? ( <> {formattedBch} {formattedFiat ? `Approx. ${currencyCode}: ${formattedFiat}` : `Approx. ${currencyCode}: waiting for live rate...`} {formattedFiatPerBchRate && ( 1 BCH = {formattedFiatPerBchRate} )} ) : ( Enter a whole satoshi amount to preview BCH/{currencyCode} conversion. )} )} ); }