BlueWallet/components/TransactionsNavigationHeader.tsx

360 lines
11 KiB
TypeScript
Raw Normal View History

2024-05-20 10:54:13 +01:00
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2024-06-17 10:56:06 -04:00
import Clipboard from '@react-native-clipboard/clipboard';
2024-05-20 10:54:13 +01:00
import { I18nManager, Image, LayoutAnimation, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
2023-04-01 20:16:00 -04:00
import LinearGradient from 'react-native-linear-gradient';
2024-05-27 23:00:28 +01:00
import { LightningCustodianWallet, LightningLdkWallet, MultisigHDWallet } from '../class';
2023-04-01 20:16:00 -04:00
import WalletGradient from '../class/wallet-gradient';
2024-05-20 10:54:13 +01:00
import { TWallet } from '../class/wallets/types';
2024-03-31 12:33:25 -04:00
import loc, { formatBalance, formatBalanceWithoutSuffix } from '../loc';
2024-05-20 10:54:13 +01:00
import { BitcoinUnit } from '../models/bitcoinUnits';
import { FiatUnit } from '../models/fiatUnit';
2024-03-31 12:33:25 -04:00
import { BlurredBalanceView } from './BlurredBalanceView';
2024-05-31 13:18:01 -04:00
import { useSettings } from '../hooks/context/useSettings';
2024-05-26 22:03:35 -04:00
import { ToolTipMenuProps } from './types';
2024-06-17 10:56:06 -04:00
import ToolTipMenu from './TooltipMenu';
2023-04-01 20:16:00 -04:00
interface TransactionsNavigationHeaderProps {
2024-03-15 23:05:15 +03:00
wallet: TWallet;
2023-04-01 20:16:00 -04:00
onWalletUnitChange?: (wallet: any) => void;
navigation: {
navigate: (route: string, params?: any) => void;
goBack: () => void;
};
2024-04-29 11:51:02 -04:00
onManageFundsPressed?: (id?: string) => void;
2024-03-31 12:58:23 -04:00
onWalletBalanceVisibilityChange?: (isShouldBeVisible: boolean) => void;
2023-04-01 20:16:00 -04:00
actionKeys: {
CopyToClipboard: 'copyToClipboard';
WalletBalanceVisibility: 'walletBalanceVisibility';
Refill: 'refill';
RefillWithExternalWallet: 'qrcode';
};
}
const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps> = ({
wallet: initialWallet,
onWalletUnitChange,
navigation,
onManageFundsPressed,
2024-03-31 12:58:23 -04:00
onWalletBalanceVisibilityChange,
2023-04-01 20:16:00 -04:00
}) => {
const [wallet, setWallet] = useState(initialWallet);
const [allowOnchainAddress, setAllowOnchainAddress] = useState(false);
2024-04-17 21:05:48 -04:00
const { preferredFiatCurrency } = useSettings();
2023-04-01 20:16:00 -04:00
2024-05-26 22:03:35 -04:00
const menuRef = useRef<ToolTipMenuProps>(null);
2023-04-01 20:16:00 -04:00
const verifyIfWalletAllowsOnchainAddress = useCallback(() => {
if (wallet.type === LightningCustodianWallet.type) {
wallet
.allowOnchainAddress()
.then((value: boolean) => setAllowOnchainAddress(value))
2023-12-25 17:22:49 -04:00
.catch((e: Error) => {
2023-04-01 20:16:00 -04:00
console.log('This Lndhub wallet does not have an onchain address API.');
setAllowOnchainAddress(false);
});
}
}, [wallet]);
useEffect(() => {
setWallet(initialWallet);
}, [initialWallet]);
2023-04-01 20:16:00 -04:00
useEffect(() => {
verifyIfWalletAllowsOnchainAddress();
}, [wallet, verifyIfWalletAllowsOnchainAddress]);
2024-06-17 15:29:54 -04:00
const handleCopyPress = useCallback(() => {
2024-01-28 11:11:08 -04:00
const value = formatBalance(wallet.getBalance(), wallet.getPreferredBalanceUnit());
if (value) {
Clipboard.setString(value);
}
2024-06-17 15:29:54 -04:00
}, [wallet]);
2023-04-01 20:16:00 -04:00
2024-06-17 15:29:54 -04:00
const handleBalanceVisibility = useCallback(() => {
2024-03-31 12:58:23 -04:00
onWalletBalanceVisibilityChange?.(!wallet.hideBalance);
2024-06-17 15:29:54 -04:00
}, [onWalletBalanceVisibilityChange, wallet.hideBalance]);
2023-04-01 20:16:00 -04:00
2024-03-15 23:05:15 +03:00
const updateWalletWithNewUnit = (w: TWallet, newPreferredUnit: BitcoinUnit) => {
w.preferredBalanceUnit = newPreferredUnit;
return w;
2023-04-01 20:16:00 -04:00
};
const changeWalletBalanceUnit = () => {
2024-05-26 22:03:35 -04:00
if (menuRef.current?.dismissMenu) {
menuRef.current.dismissMenu();
}
2023-04-01 20:16:00 -04:00
let newWalletPreferredUnit = wallet.getPreferredBalanceUnit();
if (newWalletPreferredUnit === BitcoinUnit.BTC) {
newWalletPreferredUnit = BitcoinUnit.SATS;
} else if (newWalletPreferredUnit === BitcoinUnit.SATS) {
newWalletPreferredUnit = BitcoinUnit.LOCAL_CURRENCY;
} else {
newWalletPreferredUnit = BitcoinUnit.BTC;
}
2024-03-31 12:33:25 -04:00
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
2023-04-01 20:16:00 -04:00
const updatedWallet = updateWalletWithNewUnit(wallet, newWalletPreferredUnit);
setWallet(updatedWallet);
onWalletUnitChange?.(updatedWallet);
};
2024-06-17 15:38:01 -04:00
const handleManageFundsPressed = useCallback(
(actionKeyID?: string) => {
if (onManageFundsPressed) {
onManageFundsPressed(actionKeyID);
}
},
[onManageFundsPressed],
);
2023-04-01 20:16:00 -04:00
2024-06-17 15:29:54 -04:00
const onPressMenuItem = useCallback(
(id: string) => {
if (id === 'walletBalanceVisibility') {
handleBalanceVisibility();
} else if (id === 'copyToClipboard') {
handleCopyPress();
}
},
[handleBalanceVisibility, handleCopyPress],
);
2023-04-01 20:16:00 -04:00
const toolTipActions = useMemo(() => {
return [
{
id: actionKeys.Refill,
text: loc.lnd.refill,
icon: actionIcons.Refill,
},
{
id: actionKeys.RefillWithExternalWallet,
text: loc.lnd.refill_external,
icon: actionIcons.RefillWithExternalWallet,
},
];
}, []);
2023-04-01 20:16:00 -04:00
const balance = useMemo(() => {
2023-04-03 14:54:15 -04:00
const hideBalance = wallet.hideBalance;
const balanceUnit = wallet.getPreferredBalanceUnit();
2024-03-31 12:33:25 -04:00
const balanceFormatted =
balanceUnit === BitcoinUnit.LOCAL_CURRENCY
? formatBalance(wallet.getBalance(), balanceUnit, true)
: formatBalanceWithoutSuffix(wallet.getBalance(), balanceUnit, true);
return !hideBalance && balanceFormatted;
2023-04-03 14:54:15 -04:00
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [wallet.hideBalance, wallet.getPreferredBalanceUnit()]);
2023-04-01 20:16:00 -04:00
const toolTipWalletBalanceActions = useMemo(() => {
return wallet.hideBalance
? [
{
id: 'walletBalanceVisibility',
text: loc.transactions.details_balance_show,
icon: {
iconValue: 'eye',
},
},
]
: [
{
id: 'walletBalanceVisibility',
text: loc.transactions.details_balance_hide,
icon: {
iconValue: 'eye.slash',
},
},
{
id: 'copyToClipboard',
text: loc.transactions.details_copy,
icon: {
iconValue: 'doc.on.doc',
},
},
];
}, [wallet.hideBalance]);
2023-04-01 20:16:00 -04:00
return (
<LinearGradient
colors={WalletGradient.gradientsFor(wallet.type)}
style={styles.lineaderGradient}
{...WalletGradient.linearGradientProps(wallet.type)}
>
<Image
source={(() => {
switch (wallet.type) {
case LightningLdkWallet.type:
case LightningCustodianWallet.type:
return I18nManager.isRTL ? require('../img/lnd-shape-rtl.png') : require('../img/lnd-shape.png');
case MultisigHDWallet.type:
return I18nManager.isRTL ? require('../img/vault-shape-rtl.png') : require('../img/vault-shape.png');
default:
return I18nManager.isRTL ? require('../img/btc-shape-rtl.png') : require('../img/btc-shape.png');
}
})()}
style={styles.chainIcon}
/>
<Text testID="WalletLabel" numberOfLines={1} style={styles.walletLabel} selectable>
2023-04-01 20:16:00 -04:00
{wallet.getLabel()}
</Text>
2024-03-31 12:33:25 -04:00
<View style={styles.walletBalanceAndUnitContainer}>
<ToolTipMenu
isMenuPrimaryAction
isButton
enableAndroidRipple={false}
buttonStyle={styles.walletBalance}
onPressMenuItem={onPressMenuItem}
actions={toolTipWalletBalanceActions}
2024-03-31 12:33:25 -04:00
>
<View style={styles.walletBalance}>
{wallet.hideBalance ? (
<BlurredBalanceView />
) : (
2024-04-04 10:06:15 -04:00
<View>
2024-03-31 12:33:25 -04:00
<Text
testID="WalletBalance"
// @ts-ignore: Ugh
key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi
numberOfLines={1}
2024-04-18 13:53:17 -04:00
minimumFontScale={0.5}
2024-03-31 12:33:25 -04:00
adjustsFontSizeToFit
style={styles.walletBalanceText}
>
{balance}
</Text>
2024-04-04 10:06:15 -04:00
</View>
2024-03-31 12:33:25 -04:00
)}
</View>
</ToolTipMenu>
<TouchableOpacity style={styles.walletPreferredUnitView} onPress={changeWalletBalanceUnit}>
<Text style={styles.walletPreferredUnitText}>
{wallet.getPreferredBalanceUnit() === BitcoinUnit.LOCAL_CURRENCY
? preferredFiatCurrency?.endPointKey ?? FiatUnit.USD
: wallet.getPreferredBalanceUnit()}
</Text>
</TouchableOpacity>
</View>
2023-04-01 20:16:00 -04:00
{wallet.type === LightningCustodianWallet.type && allowOnchainAddress && (
<ToolTipMenu
isMenuPrimaryAction
isButton
onPressMenuItem={handleManageFundsPressed}
actions={toolTipActions}
2023-04-01 20:16:00 -04:00
buttonStyle={styles.manageFundsButton}
>
<Text style={styles.manageFundsButtonText}>{loc.lnd.title}</Text>
</ToolTipMenu>
)}
2023-04-21 09:30:39 -05:00
{wallet.type === LightningLdkWallet.type && (
<TouchableOpacity
style={styles.manageFundsButton}
accessibilityRole="button"
accessibilityLabel={loc.lnd.title}
2024-04-29 11:51:02 -04:00
onPress={() => handleManageFundsPressed()}
>
<Text style={styles.manageFundsButtonText}>{loc.lnd.title}</Text>
2023-04-21 09:30:39 -05:00
</TouchableOpacity>
)}
2023-04-01 20:16:00 -04:00
{wallet.type === MultisigHDWallet.type && (
2024-04-29 11:51:02 -04:00
<TouchableOpacity style={styles.manageFundsButton} accessibilityRole="button" onPress={() => handleManageFundsPressed()}>
<Text style={styles.manageFundsButtonText}>{loc.multisig.manage_keys}</Text>
2023-04-01 20:16:00 -04:00
</TouchableOpacity>
)}
</LinearGradient>
);
};
const styles = StyleSheet.create({
lineaderGradient: {
padding: 15,
minHeight: 140,
justifyContent: 'center',
},
chainIcon: {
width: 99,
height: 94,
position: 'absolute',
bottom: 0,
right: 0,
},
walletLabel: {
backgroundColor: 'transparent',
fontSize: 19,
color: '#fff',
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
2024-03-31 12:33:25 -04:00
marginBottom: 10,
2023-04-01 20:16:00 -04:00
},
walletBalance: {
2024-03-31 12:33:25 -04:00
flexShrink: 1,
marginRight: 6,
2023-04-01 20:16:00 -04:00
},
manageFundsButton: {
marginTop: 14,
marginBottom: 10,
backgroundColor: 'rgba(255,255,255,0.2)',
borderRadius: 9,
minHeight: 39,
alignSelf: 'flex-start',
justifyContent: 'center',
alignItems: 'center',
},
manageFundsButtonText: {
fontWeight: '500',
fontSize: 14,
color: '#FFFFFF',
padding: 12,
},
2024-03-31 12:33:25 -04:00
walletBalanceAndUnitContainer: {
flexDirection: 'row',
alignItems: 'center',
paddingRight: 10, // Ensure there's some padding to the right
},
walletBalanceText: {
color: '#fff',
fontWeight: 'bold',
fontSize: 36,
flexShrink: 1, // Allow the text to shrink if there's not enough space
},
walletPreferredUnitView: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(255, 255, 255, 0.25)',
borderRadius: 8,
minHeight: 35,
minWidth: 65,
},
walletPreferredUnitText: {
color: '#fff',
fontWeight: '600',
},
2023-04-01 20:16:00 -04:00
});
export const actionKeys = {
CopyToClipboard: 'copyToClipboard',
WalletBalanceVisibility: 'walletBalanceVisibility',
Refill: 'refill',
2024-04-29 11:44:20 -04:00
RefillWithExternalWallet: 'refillWithExternalWallet',
2023-04-01 20:16:00 -04:00
};
export const actionIcons = {
Eye: {
iconValue: 'eye',
},
EyeSlash: {
iconValue: 'eye.slash',
},
Clipboard: {
iconValue: 'doc.on.doc',
},
Refill: {
iconValue: 'goforward.plus',
},
RefillWithExternalWallet: {
iconValue: 'qrcode',
},
};
export default TransactionsNavigationHeader;