Merge pull request #6584 from BlueWallet/tooltipreff

REF: ToolTipMenu to TSX
This commit is contained in:
GLaDOS 2024-05-19 03:04:08 +00:00 committed by GitHub
commit 72439f36c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 348 additions and 355 deletions

View file

@ -7,6 +7,7 @@ import loc from '../loc';
import Clipboard from '@react-native-clipboard/clipboard';
import { useTheme } from './themes';
import { ActionIcons } from '../typings/ActionIcons';
import { Action } from './types';
interface QRCodeComponentProps {
value: string;
@ -18,22 +19,6 @@ interface QRCodeComponentProps {
onError?: () => void;
}
interface ActionType {
Share: 'share';
Copy: 'copy';
}
interface Action {
id: string;
text: string;
icon: ActionIcons;
}
const actionKeys: ActionType = {
Share: 'share',
Copy: 'copy',
};
const actionIcons: { [key: string]: ActionIcons } = {
Share: {
iconType: 'SYSTEM',
@ -45,6 +30,22 @@ const actionIcons: { [key: string]: ActionIcons } = {
},
};
const actionKeys = {
Share: 'share',
Copy: 'copy',
};
const menuActions: Action[] =
Platform.OS === 'ios' || Platform.OS === 'macos'
? [
{
id: actionKeys.Copy,
text: loc.transactions.details_copy,
icon: actionIcons.Copy,
},
]
: [{ id: actionKeys.Share, text: loc.receive.details_share, icon: actionIcons.Share }];
const QRCodeComponent: React.FC<QRCodeComponentProps> = ({
value = '',
isLogoRendered = true,
@ -75,23 +76,6 @@ const QRCodeComponent: React.FC<QRCodeComponentProps> = ({
}
};
const menuActions = (): Action[] => {
const actions: Action[] = [];
if (Platform.OS === 'ios' || Platform.OS === 'macos') {
actions.push({
id: actionKeys.Copy,
text: loc.transactions.details_copy,
icon: actionIcons.Copy,
});
}
actions.push({
id: actionKeys.Share,
text: loc.receive.details_share,
icon: actionIcons.Share,
});
return actions;
};
const renderQRCode = (
<QRCode
value={value}
@ -115,7 +99,7 @@ const QRCodeComponent: React.FC<QRCodeComponentProps> = ({
accessibilityLabel={loc.receive.qrcode_for_the_address}
>
{isMenuAvailable ? (
<ToolTipMenu actions={menuActions()} onPressMenuItem={onPressMenuItem}>
<ToolTipMenu actions={menuActions} onPressMenuItem={onPressMenuItem}>
{renderQRCode}
</ToolTipMenu>
) : (

View file

@ -1,9 +1,10 @@
import React, { ReactNode } from 'react';
import { StyleProp, ViewStyle } from 'react-native';
import ToolTipMenu from './TooltipMenu';
import loc from '../loc';
import { ActionIcons } from '../typings/ActionIcons';
import * as fs from '../blue_modules/fs';
import { Action } from './types';
import ToolTipMenu from './TooltipMenu';
interface SaveFileButtonProps {
fileName: string;
@ -11,7 +12,7 @@ interface SaveFileButtonProps {
children?: ReactNode;
style?: StyleProp<ViewStyle>;
afterOnPress?: () => void;
beforeOnPress?: () => Promise<void>; // Changed this line
beforeOnPress?: () => Promise<void>;
onMenuWillHide?: () => void;
onMenuWillShow?: () => void;
}
@ -26,30 +27,24 @@ const SaveFileButton: React.FC<SaveFileButtonProps> = ({
onMenuWillHide,
onMenuWillShow,
}) => {
const actions = [
{ id: 'save', text: loc._.save, icon: actionIcons.Save },
{ id: 'share', text: loc.receive.details_share, icon: actionIcons.Share },
];
const handlePressMenuItem = async (actionId: string) => {
if (beforeOnPress) {
await beforeOnPress(); // Now properly awaiting a function that returns a promise
await beforeOnPress();
}
const action = actions.find(a => a.id === actionId);
if (action?.id === 'save') {
await fs.writeFileAndExport(fileName, fileContent, false).finally(() => {
afterOnPress?.(); // Safely call afterOnPress if it exists
afterOnPress?.();
});
} else if (action?.id === 'share') {
await fs.writeFileAndExport(fileName, fileContent, true).finally(() => {
afterOnPress?.(); // Safely call afterOnPress if it exists
afterOnPress?.();
});
}
};
return (
// @ts-ignore: Tooltip must be refactored to use TSX}
<ToolTipMenu
onMenuWillHide={onMenuWillHide}
onMenuWillShow={onMenuWillShow}
@ -57,7 +52,7 @@ const SaveFileButton: React.FC<SaveFileButtonProps> = ({
isMenuPrimaryAction
actions={actions}
onPressMenuItem={handlePressMenuItem}
buttonStyle={style}
buttonStyle={style as ViewStyle} // Type assertion to match ViewStyle
>
{children}
</ToolTipMenu>
@ -76,3 +71,7 @@ const actionIcons: { [key: string]: ActionIcons } = {
iconValue: 'square.and.arrow.down',
},
};
const actions: Action[] = [
{ id: 'save', text: loc._.save, icon: actionIcons.Save },
{ id: 'share', text: loc.receive.details_share, icon: actionIcons.Share },
];

View file

@ -1,64 +0,0 @@
import React, { useRef, useEffect, forwardRef } from 'react';
import PropTypes from 'prop-types';
import { Pressable } from 'react-native';
import showPopupMenu from '../blue_modules/showPopupMenu';
const BaseToolTipMenu = (props, ref) => {
const menuRef = useRef();
const disabled = props.disabled ?? false;
const isMenuPrimaryAction = props.isMenuPrimaryAction ?? false;
const enableAndroidRipple = props.enableAndroidRipple ?? true;
const buttonStyle = props.buttonStyle ?? {};
const handleToolTipSelection = selection => {
props.onPressMenuItem(selection.id);
};
useEffect(() => {
if (ref && ref.current) {
ref.current.dismissMenu = dismissMenu;
}
}, [ref]);
const dismissMenu = () => {
console.log('dismissMenu Not implemented');
};
const showMenu = () => {
const menu = [];
for (const actions of props.actions) {
if (Array.isArray(actions)) {
for (const actionToMap of actions) {
menu.push({ id: actionToMap.id, label: actionToMap.text });
}
} else {
menu.push({ id: actions.id, label: actions.text });
}
}
showPopupMenu(menu, handleToolTipSelection, menuRef.current);
};
return (
<Pressable
{...(enableAndroidRipple ? { android_ripple: { color: 'lightgrey' } } : {})}
ref={menuRef}
disabled={disabled}
style={buttonStyle}
{...(isMenuPrimaryAction ? { onPress: showMenu } : { onPress: props.onPress, onLongPress: showMenu })}
>
{props.children}
</Pressable>
);
};
const ToolTipMenu = forwardRef(BaseToolTipMenu);
export default ToolTipMenu;
ToolTipMenu.propTypes = {
actions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
children: PropTypes.node,
onPressMenuItem: PropTypes.func.isRequired,
isMenuPrimaryAction: PropTypes.bool,
onPress: PropTypes.func,
disabled: PropTypes.bool,
};

View file

@ -0,0 +1,76 @@
import React, { useRef, useEffect, forwardRef, Ref, useMemo, useCallback } from 'react';
import { Pressable, View } from 'react-native';
import showPopupMenu, { OnPopupMenuItemSelect, PopupMenuItem } from '../blue_modules/showPopupMenu.android';
import { ToolTipMenuProps } from './types';
const dismissMenu = () => {
console.log('dismissMenu Not implemented');
};
const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref<{ dismissMenu?: () => void }>) => {
const menuRef = useRef<View>(null);
const {
actions,
children,
onPressMenuItem,
isMenuPrimaryAction = false,
buttonStyle = {},
enableAndroidRipple = true,
disabled = false,
onPress,
...restProps
} = props;
const handleToolTipSelection = useCallback<OnPopupMenuItemSelect>(
(selection: PopupMenuItem) => {
if (selection.id) {
onPressMenuItem(selection.id);
}
},
[onPressMenuItem],
);
useEffect(() => {
// @ts-ignore: fix later
if (ref && ref.current) {
// @ts-ignore: fix later
ref.current.dismissMenu = dismissMenu;
}
}, [ref]);
const menuItems = useMemo(() => {
const menu: { id: string; label: string }[] = [];
actions.forEach(action => {
if (Array.isArray(action)) {
action.forEach(actionToMap => {
menu.push({ id: actionToMap.id.toString(), label: actionToMap.text });
});
} else {
menu.push({ id: action.id.toString(), label: action.text });
}
});
return menu;
}, [actions]);
const showMenu = useCallback(() => {
if (menuRef.current) {
showPopupMenu(menuItems, handleToolTipSelection, menuRef.current);
}
}, [menuItems, handleToolTipSelection]);
return (
<Pressable
{...(enableAndroidRipple ? { android_ripple: { color: 'lightgrey' } } : {})}
ref={menuRef}
disabled={disabled}
style={buttonStyle}
{...(isMenuPrimaryAction ? { onPress: showMenu } : { onPress, onLongPress: showMenu })}
{...restProps}
>
{children}
</Pressable>
);
};
const ToolTipMenu = forwardRef(BaseToolTipMenu);
export default ToolTipMenu;

View file

@ -1,140 +0,0 @@
import React, { forwardRef } from 'react';
import { ContextMenuView, ContextMenuButton } from 'react-native-ios-context-menu';
import PropTypes from 'prop-types';
import { TouchableOpacity } from 'react-native';
const BaseToolTipMenu = (props, ref) => {
const menuItemMapped = ({ action, menuOptions }) => {
const item = {
actionKey: action.id.toString(),
actionTitle: action.text,
icon: action.icon,
menuOptions,
menuTitle: action.menuTitle,
};
item.menuState = action.menuStateOn ? 'on' : 'off';
if (action.disabled) {
item.menuAttributes = ['disabled'];
}
return item;
};
const menuItems = props.actions.map(action => {
if (Array.isArray(action)) {
const mapped = [];
for (const actionToMap of action) {
mapped.push(menuItemMapped({ action: actionToMap }));
}
const submenu = {
menuOptions: ['displayInline'],
menuItems: mapped,
menuTitle: '',
};
return submenu;
} else {
return menuItemMapped({ action });
}
});
const menuTitle = props.title ?? '';
const isButton = !!props.isButton;
const isMenuPrimaryAction = props.isMenuPrimaryAction ? props.isMenuPrimaryAction : false;
const renderPreview = props.renderPreview ?? undefined;
const disabled = props.disabled ?? false;
const onPress = props.onPress ?? undefined;
const onMenuWillShow = props.onMenuWillShow ?? undefined;
const onMenuWillHide = props.onMenuWillHide ?? undefined;
const buttonStyle = props.buttonStyle;
return isButton ? (
<TouchableOpacity onPress={onPress} disabled={disabled} accessibilityRole="button" style={buttonStyle}>
<ContextMenuButton
ref={ref}
onMenuWillShow={onMenuWillShow}
onMenuWillHide={onMenuWillHide}
useActionSheetFallback={false}
onPressMenuItem={({ nativeEvent }) => {
props.onPressMenuItem(nativeEvent.actionKey);
}}
isMenuPrimaryAction={isMenuPrimaryAction}
menuConfig={{
menuTitle,
menuItems,
}}
>
{props.children}
</ContextMenuButton>
</TouchableOpacity>
) : props.onPress ? (
<ContextMenuView
ref={ref}
lazyPreview
shouldEnableAggressiveCleanup
shouldCleanupOnComponentWillUnmountForMenuPreview
internalCleanupMode="automatic"
onPressMenuItem={({ nativeEvent }) => {
props.onPressMenuItem(nativeEvent.actionKey);
}}
useActionSheetFallback={false}
menuConfig={{
menuTitle,
menuItems,
}}
{...(renderPreview
? {
previewConfig: {
previewType: 'CUSTOM',
backgroundColor: 'white',
},
renderPreview,
}
: {})}
>
<TouchableOpacity accessibilityRole="button" onPress={props.onPress}>
{props.children}
</TouchableOpacity>
</ContextMenuView>
) : (
<ContextMenuView
ref={ref}
internalCleanupMode="viewController"
onPressMenuItem={({ nativeEvent }) => {
props.onPressMenuItem(nativeEvent.actionKey);
}}
lazyPreview
shouldEnableAggressiveCleanup
useActionSheetFallback={false}
menuConfig={{
menuTitle,
menuItems,
}}
{...(renderPreview
? {
previewConfig: {
previewType: 'CUSTOM',
backgroundColor: 'white',
},
renderPreview,
}
: {})}
>
{props.children}
</ContextMenuView>
);
};
const ToolTipMenu = forwardRef(BaseToolTipMenu);
export default ToolTipMenu;
ToolTipMenu.propTypes = {
actions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
title: PropTypes.string,
children: PropTypes.node,
onPressMenuItem: PropTypes.func.isRequired,
isMenuPrimaryAction: PropTypes.bool,
isButton: PropTypes.bool,
renderPreview: PropTypes.func,
onPress: PropTypes.func,
previewValue: PropTypes.string,
disabled: PropTypes.bool,
};

View file

@ -0,0 +1,122 @@
import React, { forwardRef, Ref, useMemo, useCallback } from 'react';
import { ContextMenuView, ContextMenuButton, RenderItem } from 'react-native-ios-context-menu';
import { TouchableOpacity } from 'react-native';
import { ToolTipMenuProps, Action } from './types';
const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref<any>) => {
const {
title = '',
isButton = false,
isMenuPrimaryAction = false,
renderPreview,
disabled = false,
onPress,
onMenuWillShow,
onMenuWillHide,
buttonStyle,
onPressMenuItem,
} = props;
const menuItemMapped = useCallback(({ action, menuOptions }: { action: Action; menuOptions?: string[] }) => {
const item: any = {
actionKey: action.id.toString(),
actionTitle: action.text,
icon: action.icon,
menuOptions,
menuTitle: action.menuTitle,
};
item.menuState = action.menuStateOn ? 'on' : 'off';
if (action.disabled) {
item.menuAttributes = ['disabled'];
}
return item;
}, []);
const menuItems = useMemo(
() =>
props.actions.map(action => {
if (Array.isArray(action)) {
const mapped = action.map(actionToMap => menuItemMapped({ action: actionToMap }));
return {
menuOptions: ['displayInline'],
menuItems: mapped,
menuTitle: '',
};
} else {
return menuItemMapped({ action });
}
}),
[props.actions, menuItemMapped],
);
const handlePressMenuItem = useCallback(
({ nativeEvent }: { nativeEvent: { actionKey: string } }) => {
onPressMenuItem(nativeEvent.actionKey);
},
[onPressMenuItem],
);
const renderContextMenuButton = () => (
<ContextMenuButton
ref={ref}
onMenuWillShow={onMenuWillShow}
onMenuWillHide={onMenuWillHide}
useActionSheetFallback={false}
onPressMenuItem={handlePressMenuItem}
isMenuPrimaryAction={isMenuPrimaryAction}
menuConfig={{
menuTitle: title,
menuItems,
}}
>
{props.children}
</ContextMenuButton>
);
const renderContextMenuView = () => (
<ContextMenuView
ref={ref}
lazyPreview
shouldEnableAggressiveCleanup
internalCleanupMode="automatic"
onPressMenuItem={handlePressMenuItem}
useActionSheetFallback={false}
menuConfig={{
menuTitle: title,
menuItems,
}}
{...(renderPreview
? {
previewConfig: {
previewType: 'CUSTOM',
backgroundColor: 'white',
},
renderPreview: renderPreview as RenderItem,
}
: {})}
>
{onPress ? (
<TouchableOpacity accessibilityRole="button" onPress={onPress}>
{props.children}
</TouchableOpacity>
) : (
props.children
)}
</ContextMenuView>
);
return isMenuPrimaryAction && onPress ? (
<TouchableOpacity onPress={onPress} disabled={disabled} accessibilityRole="button" style={buttonStyle}>
{renderContextMenuButton()}
</TouchableOpacity>
) : isButton ? (
renderContextMenuButton()
) : (
renderContextMenuView()
);
};
const ToolTipMenu = forwardRef(BaseToolTipMenu);
export default ToolTipMenu;

View file

@ -1,9 +0,0 @@
import { forwardRef } from 'react';
const BaseToolTipMenu = (props, _ref) => {
return props.children;
};
const ToolTipMenu = forwardRef(BaseToolTipMenu);
export default ToolTipMenu;

View file

@ -0,0 +1,11 @@
import { forwardRef, Ref } from 'react';
import { ToolTipMenuProps } from './types';
const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref<any>) => {
console.debug('ToolTipMenu.tsx ref:', ref);
return props.children;
};
const ToolTipMenu = forwardRef(BaseToolTipMenu);
export default ToolTipMenu;

View file

@ -20,6 +20,7 @@ import { useTheme } from './themes';
import ListItem from './ListItem';
import { useSettings } from './Context/SettingsContext';
import { LightningTransaction, Transaction } from '../class/wallets/types';
import { Action } from './types';
interface TransactionListItemProps {
itemPriceUnit: BitcoinUnit;
@ -287,9 +288,9 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
handleOnViewOnBlockExplorer,
],
);
const toolTipActions = useMemo((): Action[] | Action[][] => {
const actions: (Action | Action[])[] = [];
const toolTipActions = useMemo(() => {
const actions = [];
if (rowTitle !== loc.lnd.expired) {
actions.push({
id: actionKeys.CopyAmount,
@ -305,6 +306,7 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
icon: actionIcons.Clipboard,
});
}
if (item.hash) {
actions.push(
{
@ -337,10 +339,9 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
]);
}
return actions;
return actions as Action[] | Action[][];
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [item.hash, subtitle, rowTitle, subtitleNumberOfLines, txMetadata]);
return (
<View style={styles.container}>
<ToolTipMenu ref={menuRef} actions={toolTipActions} onPressMenuItem={onToolTipPress} onPress={onPress}>

View file

@ -1,8 +1,7 @@
import React, { useRef } from 'react';
import React, { useMemo, useRef } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { useNavigation } from '@react-navigation/native';
import { ListItem } from 'react-native-elements';
import PropTypes from 'prop-types';
import { AddressTypeBadge } from './AddressTypeBadge';
import loc, { formatBalance } from '../../loc';
import TooltipMenu from '../TooltipMenu';
@ -16,6 +15,7 @@ import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/h
import QRCodeComponent from '../QRCodeComponent';
import confirm from '../../helpers/confirm';
import { useBiometrics } from '../../hooks/useBiometrics';
import { Action } from '../types';
interface AddressItemProps {
// todo: fix `any` after addresses.js is converted to the church of holy typescript
@ -80,6 +80,8 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
});
};
const menuActions = useMemo(() => getAvailableActions({ allowSignVerifyMessage }), [allowSignVerifyMessage]);
const balance = formatBalance(item.balance, balanceUnit, true);
const handleCopyPress = () => {
@ -130,39 +132,6 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
}
};
const getAvailableActions = () => {
const actions = [
{
id: AddressItem.actionKeys.CopyToClipboard,
text: loc.transactions.details_copy,
icon: AddressItem.actionIcons.Clipboard,
},
{
id: AddressItem.actionKeys.Share,
text: loc.receive.details_share,
icon: AddressItem.actionIcons.Share,
},
];
if (allowSignVerifyMessage) {
actions.push({
id: AddressItem.actionKeys.SignVerify,
text: loc.addresses.sign_title,
icon: AddressItem.actionIcons.Signature,
});
}
if (allowSignVerifyMessage) {
actions.push({
id: AddressItem.actionKeys.ExportPrivateKey,
text: loc.addresses.copy_private_key,
icon: AddressItem.actionIcons.ExportPrivateKey,
});
}
return actions;
};
const renderPreview = () => {
return <QRCodeComponent value={item.address} isMenuAvailable={false} />;
};
@ -172,7 +141,7 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
<TooltipMenu
title={item.address}
ref={menuRef}
actions={getAvailableActions()}
actions={menuActions}
onPressMenuItem={onToolTipPress}
renderPreview={renderPreview}
onPress={navigateToReceive}
@ -247,15 +216,37 @@ const styles = StyleSheet.create({
},
});
AddressItem.propTypes = {
item: PropTypes.shape({
key: PropTypes.string,
index: PropTypes.number,
address: PropTypes.string,
isInternal: PropTypes.bool,
transactions: PropTypes.number,
balance: PropTypes.number,
}),
balanceUnit: PropTypes.string,
const getAvailableActions = ({ allowSignVerifyMessage }: { allowSignVerifyMessage: boolean }): Action[] | Action[][] => {
const actions = [
{
id: AddressItem.actionKeys.CopyToClipboard,
text: loc.transactions.details_copy,
icon: AddressItem.actionIcons.Clipboard,
},
{
id: AddressItem.actionKeys.Share,
text: loc.receive.details_share,
icon: AddressItem.actionIcons.Share,
},
];
if (allowSignVerifyMessage) {
actions.push({
id: AddressItem.actionKeys.SignVerify,
text: loc.addresses.sign_title,
icon: AddressItem.actionIcons.Signature,
});
}
if (allowSignVerifyMessage) {
actions.push({
id: AddressItem.actionKeys.ExportPrivateKey,
text: loc.addresses.copy_private_key,
icon: AddressItem.actionIcons.ExportPrivateKey,
});
}
return actions;
};
export { AddressItem };

30
components/types.ts Normal file
View file

@ -0,0 +1,30 @@
import { ViewStyle } from 'react-native';
export interface Action {
id: string | number;
text: string;
icon: {
iconType: string;
iconValue: string;
};
menuTitle?: string;
menuStateOn?: boolean;
disabled?: boolean;
}
export interface ToolTipMenuProps {
actions: Action[] | Action[][];
children: React.ReactNode;
enableAndroidRipple?: boolean;
onPressMenuItem: (id: string) => void;
title?: string;
isMenuPrimaryAction?: boolean;
isButton?: boolean;
renderPreview?: () => React.ReactNode;
onPress?: () => void;
previewValue?: string;
disabled?: boolean;
buttonStyle?: ViewStyle;
onMenuWillShow?: () => void;
onMenuWillHide?: () => void;
}

View file

@ -47,7 +47,7 @@ export const useExtendedNavigation = (): NavigationProp<ParamListBase> => {
const isAuthenticated = await unlockWithBiometrics();
if (isAuthenticated) {
proceedWithNavigation();
return; // Ensure the function exits if this path is taken
return;
} else {
console.error('Biometric authentication failed');
// Decide if navigation should proceed or not after failed authentication

View file

@ -23,6 +23,22 @@ interface TransactionDetailsProps {
navigation: NativeStackNavigationProp<any>;
}
const actionKeys = {
CopyToClipboard: 'copyToClipboard',
GoToWallet: 'goToWallet',
};
const actionIcons = {
Clipboard: {
iconType: 'SYSTEM',
iconValue: 'doc.on.doc',
},
GoToWallet: {
iconType: 'SYSTEM',
iconValue: 'wallet.pass',
},
};
function onlyUnique(value: any, index: number, self: any[]) {
return self.indexOf(value) === index;
}
@ -37,6 +53,14 @@ function arrDiff(a1: any[], a2: any[]) {
return ret;
}
const toolTipMenuActions = [
{
id: actionKeys.CopyToClipboard,
text: loc.transactions.copy_link,
icon: actionIcons.Clipboard,
},
];
const TransactionDetails = () => {
const { setOptions, navigate } = useNavigation();
const { hash, walletID } = useRoute<TransactionDetailsProps['route']>().params;
@ -162,9 +186,7 @@ const TransactionDetails = () => {
};
const handleCopyPress = (stringToCopy: string) => {
Clipboard.setString(
stringToCopy !== TransactionDetails.actionKeys.CopyToClipboard ? stringToCopy : `https://mempool.space/tx/${tx?.hash}`,
);
Clipboard.setString(stringToCopy !== actionKeys.CopyToClipboard ? stringToCopy : `https://mempool.space/tx/${tx?.hash}`);
};
if (isLoading || !tx) {
@ -189,9 +211,9 @@ const TransactionDetails = () => {
};
const onPressMenuItem = (key: string) => {
if (key === TransactionDetails.actionKeys.CopyToClipboard) {
if (key === actionKeys.CopyToClipboard) {
handleCopyPress(key);
} else if (key === TransactionDetails.actionKeys.GoToWallet) {
} else if (key === actionKeys.GoToWallet) {
const wallet = weOwnAddress(key);
if (wallet) {
navigateToWallet(wallet);
@ -205,16 +227,16 @@ const TransactionDetails = () => {
for (const [index, address] of array.entries()) {
const actions = [];
actions.push({
id: TransactionDetails.actionKeys.CopyToClipboard,
id: actionKeys.CopyToClipboard,
text: loc.transactions.details_copy,
icon: TransactionDetails.actionIcons.Clipboard,
icon: actionIcons.Clipboard,
});
const isWeOwnAddress = weOwnAddress(address);
if (isWeOwnAddress) {
actions.push({
id: TransactionDetails.actionKeys.GoToWallet,
id: actionKeys.GoToWallet,
text: loc.formatString(loc.transactions.view_wallet, { walletLabel: isWeOwnAddress.getLabel() }),
icon: TransactionDetails.actionIcons.GoToWallet,
icon: actionIcons.GoToWallet,
});
}
@ -320,16 +342,10 @@ const TransactionDetails = () => {
)}
<ToolTipMenu
isButton
actions={[
{
id: TransactionDetails.actionKeys.CopyToClipboard,
text: loc.transactions.copy_link,
icon: TransactionDetails.actionIcons.Clipboard,
},
]}
actions={toolTipMenuActions}
onPressMenuItem={handleCopyPress}
onPress={handleOnOpenTransactionOnBlockExplorerTapped}
buttonStyle={[styles.greyButton, stylesHooks.greyButton]}
buttonStyle={StyleSheet.flatten([styles.greyButton, stylesHooks.greyButton])}
>
<Text style={[styles.Link, stylesHooks.Link]}>{loc.transactions.details_show_in_block_explorer}</Text>
</ToolTipMenu>
@ -338,22 +354,6 @@ const TransactionDetails = () => {
);
};
TransactionDetails.actionKeys = {
CopyToClipboard: 'copyToClipboard',
GoToWallet: 'goToWallet',
};
TransactionDetails.actionIcons = {
Clipboard: {
iconType: 'SYSTEM',
iconValue: 'doc.on.doc',
},
GoToWallet: {
iconType: 'SYSTEM',
iconValue: 'wallet.pass',
},
};
const styles = StyleSheet.create({
scroll: {
flex: 1,

View file

@ -21,25 +21,19 @@ import { satoshiToLocalCurrency } from '../../blue_modules/currency';
import { BlueLoading } from '../../BlueComponents';
import { PaymentCodeStackParamList } from '../../navigation/PaymentCodeStack';
import presentAlert from '../../components/Alert';
import { Action } from '../../components/types';
interface DataSection {
title: string;
data: string[];
}
interface IActionKey {
id: Actions;
text: string;
icon: any;
}
enum Actions {
pay,
rename,
copyToClipboard,
}
const actionKeys: IActionKey[] = [
const actionKeys: Action[] = [
{
id: Actions.pay,
text: loc.bip47.pay_this_contact,
@ -97,9 +91,7 @@ export default function PaymentCodesList() {
setData(newData);
}, [walletID, wallets, reload]);
const toolTipActions = useMemo(() => {
return actionKeys;
}, []);
const toolTipActions = useMemo(() => actionKeys, []);
const shortenContactName = (name: string): string => {
if (name.length < 20) return name;

View file

@ -206,6 +206,6 @@ jest.mock('react-native-keychain', () => mockKeychain);
jest.mock('react-native-tcp-socket', () => mockKeychain);
jest.mock('../components/TooltipMenu.ios.js', () => require('../components/TooltipMenu.js'));
jest.mock('../components/TooltipMenu.ios.tsx', () => require('../components/TooltipMenu.tsx'));
global.alert = () => {};