REF: Reuse AddressInput component

This commit is contained in:
Marcos Rodriguez Velez 2025-02-13 18:38:37 -04:00
parent d68b806b60
commit 1c15ae0a0c
6 changed files with 23 additions and 160 deletions

View file

@ -11,9 +11,7 @@ interface AddressInputProps {
address?: string;
placeholder?: string;
onChangeText: (text: string) => void;
onBarScanned: (ret: { data?: any }) => void;
scanButtonTapped?: () => void;
launchedBy?: string;
editable?: boolean;
inputAccessoryViewID?: string;
onFocus?: () => void;
@ -43,9 +41,7 @@ const AddressInput = ({
testID = 'AddressInput',
placeholder = loc.send.details_address,
onChangeText,
onBarScanned,
scanButtonTapped = () => {},
launchedBy,
editable = true,
inputAccessoryViewID,
onFocus = () => {},
@ -108,15 +104,7 @@ const AddressInput = ({
keyboardType={keyboardType}
{...(skipValidation ? { onBlur } : { onBlur: onBlurEditing })}
/>
{editable ? (
<AddressInputScanButton
isLoading={isLoading}
launchedBy={launchedBy}
scanButtonTapped={scanButtonTapped}
onBarScanned={onBarScanned}
onChangeText={onChangeText}
/>
) : null}
{editable ? <AddressInputScanButton isLoading={isLoading} scanButtonTapped={scanButtonTapped} onChangeText={onChangeText} /> : null}
</View>
);
};

View file

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo } from 'react';
import React, { useCallback, useMemo } from 'react';
import { Image, Keyboard, Platform, StyleSheet, Text } from 'react-native';
import Clipboard from '@react-native-clipboard/clipboard';
import ToolTipMenu from './TooltipMenu';
@ -9,33 +9,19 @@ import { useTheme } from './themes';
import RNQRGenerator from 'rn-qr-generator';
import { CommonToolTipActions } from '../typings/CommonToolTipActions';
import { useSettings } from '../hooks/context/useSettings';
import { useRoute } from '@react-navigation/native';
import { useExtendedNavigation } from '../hooks/useExtendedNavigation';
interface AddressInputScanButtonProps {
isLoading: boolean;
launchedBy?: string;
scanButtonTapped: () => void;
onBarScanned: (ret: { data?: any }) => void;
onChangeText: (text: string) => void;
}
interface RouteParams {
onBarScanned?: any;
}
export const AddressInputScanButton = ({
isLoading,
launchedBy,
scanButtonTapped,
onBarScanned,
onChangeText,
}: AddressInputScanButtonProps) => {
export const AddressInputScanButton = ({ isLoading, scanButtonTapped, onChangeText }: AddressInputScanButtonProps) => {
const { colors } = useTheme();
const { isClipboardGetContentEnabled } = useSettings();
const navigation = useExtendedNavigation();
const params = useRoute().params as RouteParams;
const stylesHook = StyleSheet.create({
scan: {
backgroundColor: colors.scanLabel,
@ -67,17 +53,8 @@ export const AddressInputScanButton = ({
return availableActions;
}, [isClipboardGetContentEnabled]);
useEffect(() => {
const data = params.onBarScanned;
if (data) {
onBarScanned({ data });
navigation.setParams({ onBarScanned: undefined });
}
});
const onMenuItemPressed = useCallback(
async (action: string) => {
if (onBarScanned === undefined) throw new Error('onBarScanned is required');
switch (action) {
case CommonToolTipActions.ScanQR.id:
scanButtonTapped();
@ -147,7 +124,7 @@ export const AddressInputScanButton = ({
}
Keyboard.dismiss();
},
[navigation, onBarScanned, onChangeText, scanButtonTapped],
[navigation, onChangeText, scanButtonTapped],
);
const buttonStyle = useMemo(() => [styles.scan, stylesHook.scan], [stylesHook.scan]);

View file

@ -81,7 +81,6 @@ const SendDetails = () => {
const selectedDataProcessor = useRef<ToolTipAction | undefined>();
const setParams = navigation.setParams;
const route = useRoute<RouteProps>();
const name = route.name;
const feeUnit = route.params?.feeUnit ?? BitcoinUnit.BTC;
const amountUnit = route.params?.amountUnit ?? BitcoinUnit.BTC;
const frozenBalance = route.params?.frozenBalance ?? 0;
@ -1312,11 +1311,9 @@ const SendDetails = () => {
setIsLoading(false);
setParams({ payjoinUrl: pjUrl });
}}
onBarScanned={processAddressData}
address={item.address}
isLoading={isLoading}
inputAccessoryViewID={DismissKeyboardInputAccessoryViewID}
launchedBy={name}
editable={isEditable}
style={styles.addressInput}
/>

View file

@ -416,10 +416,6 @@ const ElectrumSettings: React.FC = () => {
}
};
const importScan = async () => {
navigation.navigate('ScanQRCode');
};
useEffect(() => {
const data = params.onBarScanned;
if (data) {
@ -494,7 +490,6 @@ const ElectrumSettings: React.FC = () => {
address={host}
onChangeText={text => setHost(text.trim())}
editable={!isLoading}
onBarScanned={importScan}
keyboardType="default"
skipValidation
onBlur={() => setIsAndroidAddressKeyboardVisible(false)}

View file

@ -1,9 +1,9 @@
import React, { useCallback, useEffect, useState } from 'react';
import { RouteProp, useRoute } from '@react-navigation/native';
import { Alert, I18nManager, Linking, ScrollView, StyleSheet, TextInput, View } from 'react-native';
import { Alert, I18nManager, Linking, ScrollView, StyleSheet } from 'react-native';
import { Button as ButtonRNElements } from '@rneui/themed';
import DefaultPreference from 'react-native-default-preference';
import { BlueButtonLink, BlueCard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import { BlueCard, BlueLoading, BlueSpacing40, BlueText } from '../../BlueComponents';
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet';
import presentAlert, { AlertType } from '../../components/Alert';
@ -15,24 +15,9 @@ import { GROUP_IO_BLUEWALLET } from '../../blue_modules/currency';
import { clearLNDHub, getLNDHub, setLNDHub } from '../../helpers/lndHub';
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import AddressInput from '../../components/AddressInput';
const styles = StyleSheet.create({
uri: {
flexDirection: 'row',
borderWidth: 1,
borderBottomWidth: 0.5,
minHeight: 44,
height: 44,
alignItems: 'center',
borderRadius: 4,
},
uriText: {
flex: 1,
color: '#81868e',
marginHorizontal: 8,
minHeight: 36,
height: 36,
},
buttonStyle: {
backgroundColor: 'transparent',
flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
@ -46,14 +31,7 @@ const LightningSettings: React.FC = () => {
const [isLoading, setIsLoading] = useState(true);
const [URI, setURI] = useState<string>();
const { colors } = useTheme();
const { navigate, setParams } = useExtendedNavigation();
const styleHook = StyleSheet.create({
uri: {
borderColor: colors.formBorder,
borderBottomColor: colors.formBorder,
backgroundColor: colors.inputBackgroundColor,
},
});
const { setParams } = useExtendedNavigation();
useEffect(() => {
const fetchURI = async () => {
@ -123,12 +101,6 @@ const LightningSettings: React.FC = () => {
setIsLoading(false);
}, [URI]);
const importScan = () => {
navigate('ScanQRCode', {
showFileImportButton: true,
});
};
useEffect(() => {
const data = params?.onBarScanned;
if (data) {
@ -158,25 +130,15 @@ const LightningSettings: React.FC = () => {
/>
<BlueCard>
<View style={[styles.uri, styleHook.uri]}>
<TextInput
value={URI}
placeholder={loc.formatString(loc.settings.lndhub_uri, { example: 'https://10.20.30.40:3000' })}
onChangeText={setLndhubURI}
numberOfLines={1}
style={styles.uriText}
placeholderTextColor="#81868e"
editable={!isLoading}
textContentType="URL"
autoCapitalize="none"
autoCorrect={false}
underlineColorAndroid="transparent"
testID="URIInput"
/>
</View>
<BlueSpacing20 />
<BlueButtonLink title={loc.wallets.import_scan_qr} testID="ImportScan" onPress={importScan} />
<BlueSpacing20 />
<AddressInput
isLoading={isLoading}
address={URI}
placeholder={loc.formatString(loc.settings.lndhub_uri, { example: 'https://10.20.30.40:3000' })}
onChangeText={setLndhubURI}
testID="URIInput"
editable={!isLoading}
/>
<BlueSpacing40 />
{isLoading ? <BlueLoading /> : <Button testID="Save" onPress={save} title={loc.settings.save} />}
</BlueCard>
</ScrollView>

View file

@ -13,22 +13,17 @@ import {
} from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { useTheme } from '../../components/themes';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import loc, { formatBalanceWithoutSuffix } from '../../loc';
import loc from '../../loc';
import { useStorage } from '../../hooks/context/useStorage';
import useDebounce from '../../hooks/useDebounce';
import { TTXMetadata } from '../../class';
import { ExtendedTransaction, LightningTransaction, Transaction, TWallet } from '../../class/wallets/types';
import useBounceAnimation from '../../hooks/useBounceAnimation';
import { unlockWithBiometrics, useBiometrics } from '../../hooks/useBiometrics';
import presentAlert from '../../components/Alert';
import prompt from '../../helpers/prompt';
import HeaderRightButton from '../../components/HeaderRightButton';
import { useSettings } from '../../hooks/context/useSettings';
import DragList, { DragListRenderItemInfo } from 'react-native-draglist';
import { BitcoinUnit } from '../../models/bitcoinUnits';
const ManageWalletsListItem = lazy(() => import('../../components/ManageWalletsListItem'));
@ -199,7 +194,6 @@ const ManageWallets: React.FC = () => {
const walletsRef = useRef<TWallet[]>(deepCopyWallets(storedWallets)); // Create a deep copy of wallets for the DraggableFlatList
const { navigate, setOptions, goBack } = useExtendedNavigation();
const [state, dispatch] = useReducer(reducer, initialState);
const { isBiometricUseCapableAndEnabled } = useBiometrics();
const navigation = useNavigation();
const debouncedSearchQuery = useDebounce(state.searchQuery, 300);
const bounceAnim = useBounceAnimation(state.searchQuery);
@ -365,64 +359,14 @@ const ManageWallets: React.FC = () => {
[bounceAnim],
);
const presentWalletHasBalanceAlert = useCallback(async (wallet: TWallet) => {
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
try {
const balance = formatBalanceWithoutSuffix(wallet.getBalance(), BitcoinUnit.SATS, true);
const walletBalanceConfirmation = await prompt(
loc.wallets.details_delete_wallet,
loc.formatString(loc.wallets.details_del_wb_q, { balance }),
true,
'numeric',
true,
loc.wallets.details_delete,
);
const cleanedConfirmation = (walletBalanceConfirmation || '').replace(/[^0-9]/g, '');
if (Number(cleanedConfirmation) === wallet.getBalance()) {
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
dispatch({ type: REMOVE_WALLET, payload: wallet.getID() });
} else {
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
presentAlert({ message: loc.wallets.details_del_wb_err });
}
} catch (_) {}
}, []);
const handleDeleteWallet = useCallback(
async (wallet: TWallet) => {
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
presentAlert({
title: loc.wallets.details_delete_wallet,
message: loc.wallets.details_are_you_sure,
buttons: [
{
text: loc.wallets.details_yes_delete,
onPress: async () => {
const isBiometricsEnabled = await isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled && !(await unlockWithBiometrics())) {
return;
}
if (wallet.getBalance && wallet.getBalance() > 0 && wallet.allowSend && wallet.allowSend()) {
presentWalletHasBalanceAlert(wallet);
} else {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
dispatch({ type: REMOVE_WALLET, payload: wallet.getID() });
}
const deleted = await handleWalletDeletion(wallet.getID(), true);
if (deleted) {
goBack();
}
},
style: 'destructive',
},
{ text: loc._.cancel, onPress: () => {}, style: 'cancel' },
],
options: { cancelable: false },
});
const deletionSucceeded = await handleWalletDeletion(wallet.getID());
if (deletionSucceeded) {
dispatch({ type: REMOVE_WALLET, payload: wallet.getID() });
}
},
[isBiometricUseCapableAndEnabled, handleWalletDeletion, presentWalletHasBalanceAlert, goBack],
[handleWalletDeletion],
);
const handleToggleHideBalance = useCallback(