Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: various fixes #2457

Merged
merged 7 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions __tests__/todos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('Todos selector', () => {
let s: RootState;

beforeAll(async () => {
let res = await createNewWallet();
const res = await createNewWallet();
if (res.isErr()) {
throw res.error;
}
Expand Down Expand Up @@ -67,7 +67,7 @@ describe('Todos selector', () => {

it('should not return backupSeedPhraseTodo if backup is verified', () => {
const state = cloneDeep(s);
state.settings.backupVerified = true;
state.user.backupVerified = true;

expect(todosFullSelector(state)).not.toEqual(
expect.arrayContaining([backupSeedPhraseTodo]),
Expand Down
1 change: 1 addition & 0 deletions e2e/slashtags.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ d('Profile and Contacts', () => {
await expect(element(by.text('WEBSITE'))).toExist();
await expect(element(by.text(satoshi.website))).toExist();
await element(by.id('NavigationBack')).tap();
await element(by.id('NavigationBack')).tap();

if (device.getPlatform() === 'ios') {
// FIXME: this bottom sheet should not appear
Expand Down
9 changes: 4 additions & 5 deletions src/assets/tos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const BUI = ({ children }: Props): ReactElement => {
const TOS = (): ReactElement => (
<View style={s.root}>
<P>
<B>Effective date: June 7, 2024</B>
<B>Effective date: February 4, 2025</B>
</P>
<P>
<B>
Expand Down Expand Up @@ -113,10 +113,9 @@ const TOS = (): ReactElement => (
</P>
<P>
<B>
FUNDS TRANSFERRED USING CAVEMAN JUST-IN-TIME CHANNELS BY THIRD PARTIES
MAY NOT BE DELIVERED TO YOU BY THE THIRD PARTY. YOU ARE REFERRED TO
CLAUSE 9.3 OF THE TERMS AS TO SYNONYM’S LIABILITY FOR THIRD PARTY
SERVICES.
FUNDS TRANSFERRED USING JUST-IN-TIME CHANNELS BY THIRD PARTIES MAY NOT
BE DELIVERED TO YOU BY THE THIRD PARTY. YOU ARE REFERRED TO CLAUSE 9.3
OF THE TERMS AS TO SYNONYM’S LIABILITY FOR THIRD PARTY SERVICES.
</B>
</P>
<P>
Expand Down
92 changes: 81 additions & 11 deletions src/components/widgets/CalculatorWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactElement, useState } from 'react';
import React, { ReactElement, useEffect, useState } from 'react';
import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';

import { useCurrency } from '../../hooks/displayValues';
Expand All @@ -9,6 +9,8 @@ import { fiatToBitcoinUnit } from '../../utils/conversion';
import { getDisplayValues } from '../../utils/displayValues';
import BaseWidget from './BaseWidget';

const MAX_BITCOIN = 2_100_000_000_000_000; // Maximum bitcoin amount in sats

const CalculatorWidget = ({
isEditing = false,
style,
Expand All @@ -30,16 +32,58 @@ const CalculatorWidget = ({
return dv.fiatValue.toString();
});

// biome-ignore lint/correctness/useExhaustiveDependencies: update fiat amount when currency changes
useEffect(() => {
updateFiatAmount(bitcoinAmount);
}, [fiatTicker]);

const updateFiatAmount = (bitcoin: string) => {
const amount = Number(bitcoin);
const dv = getDisplayValues({ satoshis: amount, shouldRoundUpFiat: true });
// Remove leading zeros for positive numbers
const sanitizedBitcoin = bitcoin.replace(/^0+(?=\d)/, '');
const amount = Number(sanitizedBitcoin);
// Cap the amount at maximum bitcoin
const cappedAmount = Math.min(amount, MAX_BITCOIN);
const dv = getDisplayValues({
satoshis: cappedAmount,
shouldRoundUpFiat: true,
});
setFiatAmount(dv.fiatValue.toString());
// Update bitcoin amount if it was capped
if (cappedAmount !== amount) {
setBitcoinAmount(cappedAmount.toString());
}
};

const updateBitcoinAmount = (fiat: string) => {
const amount = Number(fiat.replace(',', '.'));
// Remove leading zeros and handle decimal separator
const sanitizedFiat = fiat.replace(/^0+(?=\d)/, '');
// Only convert to number if it's not just a decimal point
const amount = sanitizedFiat === '.' ? 0 : Number(sanitizedFiat);
const sats = fiatToBitcoinUnit({ amount });
setBitcoinAmount(sats.toString());
// Cap the amount at maximum bitcoin
const cappedSats = Math.min(sats, MAX_BITCOIN);
setBitcoinAmount(cappedSats.toString());
// Update fiat amount if bitcoin was capped
if (cappedSats !== sats) {
const dv = getDisplayValues({
satoshis: cappedSats,
shouldRoundUpFiat: true,
});
setFiatAmount(dv.fiatValue.toString());
}
};

const formatNumberWithSeparators = (value: string): string => {
const endsWithDecimal = value.endsWith('.');
const cleanNumber = value.replace(/[^\d.]/g, '');
const [integer, decimal] = cleanNumber.split('.');
const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ' ');

if (decimal !== undefined) {
return `${formattedInteger}.${decimal}`;
}

return endsWithDecimal ? `${formattedInteger}.` : formattedInteger;
};

return (
Expand All @@ -56,13 +100,16 @@ const CalculatorWidget = ({
<View style={styles.amount}>
<TextInput
style={styles.input}
value={bitcoinAmount}
value={formatNumberWithSeparators(bitcoinAmount)}
placeholder="0"
keyboardType="number-pad"
returnKeyType="done"
onChangeText={(text) => {
setBitcoinAmount(text);
updateFiatAmount(text);
// Remove any spaces before processing
const rawText = text.replace(/\s/g, '');
const sanitizedText = rawText.replace(/^0+(?=\d)/, '');
setBitcoinAmount(sanitizedText);
updateFiatAmount(sanitizedText);
}}
/>
</View>
Expand All @@ -75,13 +122,36 @@ const CalculatorWidget = ({
<View style={styles.amount}>
<TextInput
style={styles.input}
value={fiatAmount}
value={formatNumberWithSeparators(fiatAmount)}
placeholder="0"
keyboardType="decimal-pad"
returnKeyType="done"
onChangeText={(text) => {
setFiatAmount(text);
updateBitcoinAmount(text);
// Process the input text
const processedText = text
.replace(',', '.') // Convert comma to dot
.replace(/\s/g, ''); // Remove spaces

// Split and clean the number parts
const [integer, decimal] = processedText.split('.');
const cleanInteger = integer.replace(/^0+(?=\d)/, '') || '0';

// Construct the final number
const finalText =
decimal !== undefined
? `${cleanInteger}.${decimal.slice(0, 2)}`
: cleanInteger;

// Update state if valid
if (
finalText === '' ||
finalText === '.' ||
finalText === '0.' ||
/^\d*\.?\d{0,2}$/.test(finalText)
) {
setFiatAmount(finalText);
updateBitcoinAmount(finalText);
}
}}
/>
</View>
Expand Down
2 changes: 1 addition & 1 deletion src/components/widgets/WeatherWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const WeatherWidget = ({
</BodySSB>
</View>
<View style={styles.columnRight}>
<BodyMSB numberOfLines={1}>{nextBlockFee} bitcoin/vB</BodyMSB>
<BodyMSB numberOfLines={1}>{nextBlockFee} ₿/vByte</BodyMSB>
</View>
</View>
)}
Expand Down
16 changes: 1 addition & 15 deletions src/screens/Activity/ActivityListShort.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import Button from '../../components/buttons/Button';
import { useAppSelector } from '../../hooks/redux';
import type { RootNavigationProp } from '../../navigation/types';
import { activityItemsSelector } from '../../store/reselect/activity';
import { EActivityType, IActivityItem } from '../../store/types/activity';
import { IActivityItem } from '../../store/types/activity';
import { showBottomSheet } from '../../store/utils/ui';
import { Caption13Up } from '../../styles/text';
import { groupActivityItems } from '../../utils/activity';
Expand All @@ -31,13 +31,6 @@ const ActivityListShort = (): ReactElement => {
return groupActivityItems(sliced);
}, [items]);

const droppedItems = useMemo(() => {
const dropped = items.filter((item) => {
return item.activityType === EActivityType.onchain && !item.exists;
});
return dropped;
}, [items]);

const renderItem = useCallback(
({
item,
Expand Down Expand Up @@ -76,13 +69,6 @@ const ActivityListShort = (): ReactElement => {
<View style={styles.content}>
<Caption13Up style={styles.title} color="secondary">
{t('activity')}

{droppedItems.length !== 0 && (
<Caption13Up color="red">
{' '}
({droppedItems.length} {t('activity_removed')})
</Caption13Up>
)}
</Caption13Up>

{groupedItems.length === 0 ? (
Expand Down
5 changes: 1 addition & 4 deletions src/screens/Contacts/Contact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,7 @@ const Contact = ({
return (
<View style={styles.root}>
<SafeAreaInset type="top" />
<NavigationHeader
title={t('contact')}
onBackPress={(): void => navigation.navigate('Contacts')}
/>
<NavigationHeader title={t('contact')} />
<View style={styles.content}>
<ProfileCard
url={url}
Expand Down
3 changes: 1 addition & 2 deletions src/screens/Onboarding/RestoreFromSeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ import VerticalShadow from '../../components/VerticalShadow';
import Button from '../../components/buttons/Button';
import { useAppDispatch } from '../../hooks/redux';
import { OnboardingStackScreenProps } from '../../navigation/types';
import { verifyBackup } from '../../store/slices/settings';
import { updateUser } from '../../store/slices/user';
import { updateUser, verifyBackup } from '../../store/slices/user';
import {
ScrollView,
TextInput,
Expand Down
2 changes: 1 addition & 1 deletion src/screens/Settings/Backup/BackupPrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
} from '../../../hooks/bottomSheet';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
import { useBalance } from '../../../hooks/wallet';
import { backupVerifiedSelector } from '../../../store/reselect/settings';
import { viewControllersSelector } from '../../../store/reselect/ui';
import { backupVerifiedSelector } from '../../../store/reselect/user';
import { ignoreBackupTimestampSelector } from '../../../store/reselect/user';
import { closeSheet } from '../../../store/slices/ui';
import { ignoreBackup } from '../../../store/slices/user';
Expand Down
2 changes: 1 addition & 1 deletion src/screens/Settings/Backup/Success.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import SafeAreaInset from '../../../components/SafeAreaInset';
import Button from '../../../components/buttons/Button';
import { useAppDispatch } from '../../../hooks/redux';
import { BackupScreenProps } from '../../../navigation/types';
import { verifyBackup } from '../../../store/slices/settings';
import { verifyBackup } from '../../../store/slices/user';
import { BodyM, BodyMB } from '../../../styles/text';

const imageSrc = require('../../../assets/illustrations/check.png');
Expand Down
18 changes: 10 additions & 8 deletions src/screens/Widgets/Widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,16 @@ const Widget = ({
{renderWidget()}

<View style={styles.buttonsContainer}>
<Button
style={styles.button}
text={t('common:delete')}
size="large"
variant="secondary"
testID="WidgetDelete"
onPress={onDelete}
/>
{savedWidget && (
<Button
style={styles.button}
text={t('common:delete')}
size="large"
variant="secondary"
testID="WidgetDelete"
onPress={onDelete}
/>
)}
<Button
style={styles.button}
text={t('save')}
Expand Down
2 changes: 1 addition & 1 deletion src/screens/Widgets/WidgetEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const WidgetEdit = ({
{
key: 'showNextBlockFee' as const,
title: t('weather.next_block'),
value: `${nextBlockFee} bitcoin/vB`,
value: `${nextBlockFee} ₿/vByte`,
},
];

Expand Down
4 changes: 0 additions & 4 deletions src/store/reselect/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ export const settingsSelector = (state: RootState): TSettings => state.settings;
const customElectrumPeersState = (state: RootState): TCustomElectrumPeers => {
return state.settings.customElectrumPeers;
};

export const backupVerifiedSelector = (state: RootState): boolean => {
return state.settings.backupVerified;
};
export const selectedCurrencySelector = (state: RootState): string => {
return state.settings.selectedCurrency;
};
Expand Down
7 changes: 5 additions & 2 deletions src/store/reselect/todos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ import { ITodo, TTodosState } from '../types/todos';
import { ETransferType, TTransferToSavings } from '../types/wallet';
import { blocktankPaidOrdersFullSelector } from './blocktank';
import { closedChannelsSelector, openChannelsSelector } from './lightning';
import { backupVerifiedSelector, pinSelector } from './settings';
import { pinSelector } from './settings';
import { onboardingProfileStepSelector } from './slashtags';
import { startCoopCloseTimestampSelector } from './user';
import {
backupVerifiedSelector,
startCoopCloseTimestampSelector,
} from './user';
import { createShallowEqualSelector } from './utils';
import { pendingTransfersSelector } from './wallet';

Expand Down
3 changes: 3 additions & 0 deletions src/store/reselect/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { TUser } from '../slices/user';

const userState = (state: RootState): TUser => state.user;

export const backupVerifiedSelector = (state: RootState): boolean => {
return state.user.backupVerified;
};
export const isGeoBlockedSelector = createSelector(
[userState],
(user): boolean => user.isGeoBlocked ?? false,
Expand Down
1 change: 0 additions & 1 deletion src/store/shapes/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ const defaultReceivePreference = [
];

export const initialSettingsState: TSettings = {
backupVerified: false,
enableAutoReadClipboard: false,
enableSendAmountWarning: false,
enableSwipeToHideBalance: true,
Expand Down
5 changes: 0 additions & 5 deletions src/store/slices/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
import { EDenomination, EUnit } from '../types/wallet';

export type TSettings = {
backupVerified: boolean;
enableAutoReadClipboard: boolean;
enableSendAmountWarning: boolean;
enableSwipeToHideBalance: boolean;
Expand Down Expand Up @@ -88,9 +87,6 @@ export const settingsSlice = createSlice({
addOrangeTicket: (state, action: PayloadAction<string>) => {
state.orangeTickets.push(action.payload);
},
verifyBackup: (state) => {
state.backupVerified = true;
},
resetSettingsState: () => initialSettingsState,
},
});
Expand All @@ -103,7 +99,6 @@ export const {
addTreasureChest,
updateTreasureChest,
addOrangeTicket,
verifyBackup,
resetSettingsState,
} = actions;

Expand Down
Loading