Skip to content

Commit

Permalink
BTC amount formatting: remove commas and add spaces
Browse files Browse the repository at this point in the history
  • Loading branch information
kaloudis committed Nov 12, 2024
1 parent 4d38b72 commit 47e0307
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 14 deletions.
8 changes: 8 additions & 0 deletions components/Amount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ function AmountDisplay({
{negative ? '-' : ''}
{amount === 'N/A' && fiatRatesLoading ? (
<LoadingIndicator size={20} />
) : unit === 'BTC' ? (
stores.fiatStore.formatBitcoinWithSpaces(
amount
)
) : (
amount.toString()
)}
Expand Down Expand Up @@ -216,6 +220,10 @@ function AmountDisplay({
{negative ? '-' : ''}
{amount === 'N/A' && fiatRatesLoading ? (
<LoadingIndicator size={20} />
) : unit === 'BTC' ? (
stores.fiatStore.formatBitcoinWithSpaces(
amount
)
) : (
amount.toString()
)}
Expand Down
21 changes: 21 additions & 0 deletions stores/FiatStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ export default class FiatStore {
@observable public numberWithCommas = (x: string | number) =>
x?.toString()?.replace(/\B(?=(\d{3})+(?!\d))/g, ',') || '0';

@observable public formatBitcoinWithSpaces = (x: string | number) => {
// Convert to string to handle decimal parts
const [integerPart, decimalPart] = x.toString().split('.');

const integerFormatted = this.numberWithCommas(integerPart);

// // If no decimal part, return the integer part as is
if (x.toString().includes('.') && !decimalPart) {
return `${integerFormatted}.`;
} else if (!decimalPart) {
return integerFormatted;
}

// Handle the first two characters, then group the rest in threes
const firstTwo = decimalPart.slice(0, 2);
const rest = decimalPart.slice(2).replace(/(\d{3})(?=\d)/g, '$1 ');

// Combine integer part, first two characters, and formatted rest
return `${integerFormatted}.${firstTwo} ${rest}`.trim();
};

@observable public numberWithDecimals = (x: string | number) =>
this.numberWithCommas(x).replace(/[,.]/g, (y: string) =>
y === ',' ? '.' : ','
Expand Down
4 changes: 2 additions & 2 deletions utils/UnitsUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ describe('UnitsUtils', () => {
describe('getDecimalPlaceholder', () => {
it('Returns string and count properly', () => {
expect(getDecimalPlaceholder('1231.2', 'BTC')).toEqual({
string: '0000000',
string: '0 000 000',
count: 7
});
expect(getDecimalPlaceholder('1231.', 'BTC')).toEqual({
string: '00000000',
string: '00 000 000',
count: 8
});

Expand Down
17 changes: 14 additions & 3 deletions utils/UnitsUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const getDecimalPlaceholder = (amount: string, units: string) => {
const occupiedPlaces: number =
(amount.split('.')[1] && amount.split('.')[1].length) || 0;
const [_, decimalPart] = amount.split('.');
const occupiedPlaces: number = (decimalPart && decimalPart.length) || 0;
let placeholderCount = 0;

if (units === 'sats') {
Expand All @@ -12,7 +12,18 @@ const getDecimalPlaceholder = (amount: string, units: string) => {
}

return {
string: amount.includes('.') ? '0'.repeat(placeholderCount) : null,
string: amount.includes('.')
? units === 'BTC'
? '00 000 000'.slice(
occupiedPlaces +
(decimalPart.length > 5
? 2
: decimalPart.length > 2
? 1
: 0)
)
: '0'.repeat(placeholderCount)
: null,
count: amount.includes('.') ? placeholderCount : 0
};
};
Expand Down
37 changes: 28 additions & 9 deletions views/Wallet/KeypadPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ interface KeypadPaneState {
lspNotConfigured: boolean;
}

const MAX_LENGTH = 10;

@inject(
'ChannelsStore',
'FiatStore',
Expand Down Expand Up @@ -99,17 +97,34 @@ export default class KeypadPane extends React.PureComponent<
return this.startShake();
}
if (units === 'BTC') {
if (amount.split('.')[1] && amount.split('.')[1].length == 8)
const [integerPart, decimalPart] = amount.split('.');
// deny if trying to add more than 8 figures of Bitcoin
if (
!decimalPart &&
integerPart &&
integerPart.length == 8 &&
!amount.includes('.') &&
value !== '.'
)
return this.startShake();
// deny if trying to add more than 8 decimal places of satoshis
if (decimalPart && decimalPart.length == 8)
return this.startShake();
}

if (amount.length >= MAX_LENGTH) {
newAmount = amount;
const proposedNewAmountStr = `${amount}${value}`;
const proposedNewAmount = new BigNumber(proposedNewAmountStr);

// deny if exceeding BTC 21 million capacity
if (units === 'BTC' && proposedNewAmount.gt(21000000))
return this.startShake();
} else if (amount === '0') {
if (units === 'sats' && proposedNewAmount.gt(2100000000000000.0))
return this.startShake();

if (amount === '0') {
newAmount = value;
} else {
newAmount = `${amount}${value}`;
newAmount = proposedNewAmountStr;
}

let needInbound = false;
Expand Down Expand Up @@ -197,8 +212,10 @@ export default class KeypadPane extends React.PureComponent<
return needInbound ? 40 : 50;
case 8:
return needInbound ? 35 : 45;
default:
case 9:
return needInbound ? 25 : 35;
default:
return needInbound ? 20 : 30;
}
};

Expand Down Expand Up @@ -326,7 +343,9 @@ export default class KeypadPane extends React.PureComponent<
fontFamily: 'PPNeueMontreal-Medium'
}}
>
{FiatStore?.numberWithCommas(amount)}
{units === 'BTC'
? FiatStore?.formatBitcoinWithSpaces(amount)
: FiatStore?.numberWithCommas(amount)}
<Text style={{ color: themeColor('secondaryText') }}>
{getDecimalPlaceholder(amount, units).string}
</Text>
Expand Down

0 comments on commit 47e0307

Please sign in to comment.