1- import React , { ReactElement , useState } from 'react' ;
1+ import React , { ReactElement , useEffect , useState } from 'react' ;
22import { StyleProp , StyleSheet , View , ViewStyle } from 'react-native' ;
33
44import { useCurrency } from '../../hooks/displayValues' ;
@@ -9,6 +9,8 @@ import { fiatToBitcoinUnit } from '../../utils/conversion';
99import { getDisplayValues } from '../../utils/displayValues' ;
1010import BaseWidget from './BaseWidget' ;
1111
12+ const MAX_BITCOIN = 2_100_000_000_000_000 ; // Maximum bitcoin amount in sats
13+
1214const CalculatorWidget = ( {
1315 isEditing = false ,
1416 style,
@@ -30,16 +32,58 @@ const CalculatorWidget = ({
3032 return dv . fiatValue . toString ( ) ;
3133 } ) ;
3234
35+ // biome-ignore lint/correctness/useExhaustiveDependencies: update fiat amount when currency changes
36+ useEffect ( ( ) => {
37+ updateFiatAmount ( bitcoinAmount ) ;
38+ } , [ fiatTicker ] ) ;
39+
3340 const updateFiatAmount = ( bitcoin : string ) => {
34- const amount = Number ( bitcoin ) ;
35- const dv = getDisplayValues ( { satoshis : amount , shouldRoundUpFiat : true } ) ;
41+ // Remove leading zeros for positive numbers
42+ const sanitizedBitcoin = bitcoin . replace ( / ^ 0 + (? = \d ) / , '' ) ;
43+ const amount = Number ( sanitizedBitcoin ) ;
44+ // Cap the amount at maximum bitcoin
45+ const cappedAmount = Math . min ( amount , MAX_BITCOIN ) ;
46+ const dv = getDisplayValues ( {
47+ satoshis : cappedAmount ,
48+ shouldRoundUpFiat : true ,
49+ } ) ;
3650 setFiatAmount ( dv . fiatValue . toString ( ) ) ;
51+ // Update bitcoin amount if it was capped
52+ if ( cappedAmount !== amount ) {
53+ setBitcoinAmount ( cappedAmount . toString ( ) ) ;
54+ }
3755 } ;
3856
3957 const updateBitcoinAmount = ( fiat : string ) => {
40- const amount = Number ( fiat . replace ( ',' , '.' ) ) ;
58+ // Remove leading zeros and handle decimal separator
59+ const sanitizedFiat = fiat . replace ( / ^ 0 + (? = \d ) / , '' ) ;
60+ // Only convert to number if it's not just a decimal point
61+ const amount = sanitizedFiat === '.' ? 0 : Number ( sanitizedFiat ) ;
4162 const sats = fiatToBitcoinUnit ( { amount } ) ;
42- setBitcoinAmount ( sats . toString ( ) ) ;
63+ // Cap the amount at maximum bitcoin
64+ const cappedSats = Math . min ( sats , MAX_BITCOIN ) ;
65+ setBitcoinAmount ( cappedSats . toString ( ) ) ;
66+ // Update fiat amount if bitcoin was capped
67+ if ( cappedSats !== sats ) {
68+ const dv = getDisplayValues ( {
69+ satoshis : cappedSats ,
70+ shouldRoundUpFiat : true ,
71+ } ) ;
72+ setFiatAmount ( dv . fiatValue . toString ( ) ) ;
73+ }
74+ } ;
75+
76+ const formatNumberWithSeparators = ( value : string ) : string => {
77+ const endsWithDecimal = value . endsWith ( '.' ) ;
78+ const cleanNumber = value . replace ( / [ ^ \d . ] / g, '' ) ;
79+ const [ integer , decimal ] = cleanNumber . split ( '.' ) ;
80+ const formattedInteger = integer . replace ( / \B (? = ( \d { 3 } ) + (? ! \d ) ) / g, ' ' ) ;
81+
82+ if ( decimal !== undefined ) {
83+ return `${ formattedInteger } .${ decimal } ` ;
84+ }
85+
86+ return endsWithDecimal ? `${ formattedInteger } .` : formattedInteger ;
4387 } ;
4488
4589 return (
@@ -56,13 +100,16 @@ const CalculatorWidget = ({
56100 < View style = { styles . amount } >
57101 < TextInput
58102 style = { styles . input }
59- value = { bitcoinAmount }
103+ value = { formatNumberWithSeparators ( bitcoinAmount ) }
60104 placeholder = "0"
61105 keyboardType = "number-pad"
62106 returnKeyType = "done"
63107 onChangeText = { ( text ) => {
64- setBitcoinAmount ( text ) ;
65- updateFiatAmount ( text ) ;
108+ // Remove any spaces before processing
109+ const rawText = text . replace ( / \s / g, '' ) ;
110+ const sanitizedText = rawText . replace ( / ^ 0 + (? = \d ) / , '' ) ;
111+ setBitcoinAmount ( sanitizedText ) ;
112+ updateFiatAmount ( sanitizedText ) ;
66113 } }
67114 />
68115 </ View >
@@ -75,13 +122,36 @@ const CalculatorWidget = ({
75122 < View style = { styles . amount } >
76123 < TextInput
77124 style = { styles . input }
78- value = { fiatAmount }
125+ value = { formatNumberWithSeparators ( fiatAmount ) }
79126 placeholder = "0"
80127 keyboardType = "decimal-pad"
81128 returnKeyType = "done"
82129 onChangeText = { ( text ) => {
83- setFiatAmount ( text ) ;
84- updateBitcoinAmount ( text ) ;
130+ // Process the input text
131+ const processedText = text
132+ . replace ( ',' , '.' ) // Convert comma to dot
133+ . replace ( / \s / g, '' ) ; // Remove spaces
134+
135+ // Split and clean the number parts
136+ const [ integer , decimal ] = processedText . split ( '.' ) ;
137+ const cleanInteger = integer . replace ( / ^ 0 + (? = \d ) / , '' ) || '0' ;
138+
139+ // Construct the final number
140+ const finalText =
141+ decimal !== undefined
142+ ? `${ cleanInteger } .${ decimal . slice ( 0 , 2 ) } `
143+ : cleanInteger ;
144+
145+ // Update state if valid
146+ if (
147+ finalText === '' ||
148+ finalText === '.' ||
149+ finalText === '0.' ||
150+ / ^ \d * \. ? \d { 0 , 2 } $ / . test ( finalText )
151+ ) {
152+ setFiatAmount ( finalText ) ;
153+ updateBitcoinAmount ( finalText ) ;
154+ }
85155 } }
86156 />
87157 </ View >
0 commit comments