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

feat: multi rpc modal #11685

Merged
merged 7 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
16 changes: 15 additions & 1 deletion app/actions/security/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export enum ActionType {
SET_AUTOMATIC_SECURITY_CHECKS_MODAL_OPEN = 'SET_AUTOMATIC_SECURITY_CHECKS_MODAL_OPEN',
SET_DATA_COLLECTION_FOR_MARKETING = 'SET_DATA_COLLECTION_FOR_MARKETING',
SET_NFT_AUTO_DETECTION_MODAL_OPEN = 'SET_NFT_AUTO_DETECTION_MODAL_OPEN',
SET_MULTI_RPC_MIGRATION_MODAL_OPEN = 'SET_MULTI_RPC_MIGRATION_MODAL_OPEN',
}

export interface AllowLoginWithRememberMeUpdated
Expand Down Expand Up @@ -35,6 +36,11 @@ export interface SetNftAutoDetectionModalOpen
open: boolean;
}

export interface SetMultiRpcMigrationModalOpen
extends ReduxAction<ActionType.SET_MULTI_RPC_MIGRATION_MODAL_OPEN> {
open: boolean;
}

export interface SetDataCollectionForMarketing
extends ReduxAction<ActionType.SET_DATA_COLLECTION_FOR_MARKETING> {
enabled: boolean;
Expand All @@ -46,7 +52,8 @@ export type Action =
| UserSelectedAutomaticSecurityChecksOptions
| SetAutomaticSecurityChecksModalOpen
| SetDataCollectionForMarketing
| SetNftAutoDetectionModalOpen;
| SetNftAutoDetectionModalOpen
| SetMultiRpcMigrationModalOpen;

export const setAllowLoginWithRememberMe = (
enabled: boolean,
Expand Down Expand Up @@ -82,6 +89,13 @@ export const setNftAutoDetectionModalOpen = (
open,
});

export const setMultiRpcMigrationModalOpen = (
open: boolean,
): SetMultiRpcMigrationModalOpen => ({
type: ActionType.SET_MULTI_RPC_MIGRATION_MODAL_OPEN,
open,
});

export const setDataCollectionForMarketing = (enabled: boolean) => ({
type: ActionType.SET_DATA_COLLECTION_FOR_MARKETING,
enabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const CellSelectWithMenu = ({
tagLabel,
isSelected = false,
children,
withAvatar = true,
...props
}: CellSelectWithMenuProps) => {
const { styles } = useStyles(styleSheet, { style });
Expand All @@ -46,12 +47,15 @@ const CellSelectWithMenu = ({
>
<View style={styles.cellBase}>
{/* DEV Note: Account Avatar should be replaced with Avatar with Badge whenever available */}
<Avatar
style={styles.avatar}
testID={CellModalSelectorsIDs.BASE_AVATAR}
size={DEFAULT_CELLBASE_AVATAR_SIZE}
{...avatarProps}
/>
{withAvatar ? (
<Avatar
style={styles.avatar}
testID={CellModalSelectorsIDs.BASE_AVATAR}
size={DEFAULT_CELLBASE_AVATAR_SIZE}
{...avatarProps}
/>
) : null}

<View style={styles.cellBaseInfo}>
<Text
numberOfLines={1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ exports[`CellSelectWithMenu should render with default settings correctly 1`] =
"opacity": 1,
"padding": 16,
"position": "relative",
"width": "95%",
"width": "90%",
"zIndex": 1,
}
}
Expand Down Expand Up @@ -287,7 +287,13 @@ exports[`CellSelectWithMenu should render with default settings correctly 1`] =
</View>
</View>
</TouchableOpacity>
<View>
<View
style={
{
"paddingHorizontal": 20,
}
}
>
<TouchableOpacity
accessibilityRole="button"
accessible={true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const styleSheet = (params: {
position: 'relative',
opacity: isDisabled ? 0.5 : 1,
padding: 16,
width: '95%',
width: '90%',
salimtb marked this conversation as resolved.
Show resolved Hide resolved
zIndex: 1,
} as ViewStyle,
style,
Expand Down Expand Up @@ -86,6 +86,9 @@ const styleSheet = (params: {
paddingLeft: 8,
paddingTop: 32,
},
buttonIcon: {
paddingHorizontal: 20,
},
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,22 @@ import {
IconColor,
IconName,
} from '../../../component-library/components/Icons/Icon';
import Button, {
ButtonSize,
ButtonVariants,
ButtonWidthTypes,
} from '../../../component-library/components/Buttons/Button';
import { TextVariant } from '../../../component-library/components/Texts/Text';

const ListItemMultiSelectButton: React.FC<ListItemMultiSelectButtonProps> = ({
style,
isSelected = false,
isDisabled = false,
children,
gap = DEFAULT_LISTITEMMULTISELECT_GAP,
showButtonIcon = true,
buttonIcon = IconName.MoreVertical,
textButton = null,
...props
}) => {
const { styles } = useStyles(styleSheet, {
Expand Down Expand Up @@ -55,15 +63,29 @@ const ListItemMultiSelectButton: React.FC<ListItemMultiSelectButtonProps> = ({
</View>
)}
</TouchableOpacity>
<View>
<ButtonIcon
iconName={buttonIcon}
iconColor={IconColor.Default}
testID={BUTTON_TEST_ID}
onPress={props.onButtonClick}
accessibilityRole="button"
/>
</View>
{showButtonIcon ? (
<View style={styles.buttonIcon}>
<ButtonIcon
iconName={buttonIcon}
iconColor={IconColor.Default}
testID={BUTTON_TEST_ID}
onPress={props.onButtonClick}
accessibilityRole="button"
/>
</View>
) : null}
{textButton ? (
<View>
<Button
variant={ButtonVariants.Link}
onPress={props.onButtonClick as () => void}
labelTextVariant={TextVariant.BodyMD}
size={ButtonSize.Lg}
width={ButtonWidthTypes.Auto}
label={textButton}
/>
</View>
) : null}
</View>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ export interface ListItemMultiSelectButtonProps
* Optional button onClick rpc modal function
*/
onTextClick?: (() => void) | undefined;

/**
* Optional property to add avatar
*/
withAvatar?: boolean;

/**
* Optional property to show icon
*/
showButtonIcon?: boolean;
/**
* Optional property to show text button
*/
textButton?: string | null;
salimtb marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ exports[`ListItemMultiSelectButton should render correctly with default props 1`
"opacity": 1,
"padding": 16,
"position": "relative",
"width": "95%",
"width": "90%",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not use percentage width

"zIndex": 1,
}
}
Expand Down Expand Up @@ -52,7 +52,13 @@ exports[`ListItemMultiSelectButton should render correctly with default props 1`
</View>
</View>
</TouchableOpacity>
<View>
<View
style={
{
"paddingHorizontal": 20,
}
}
>
<TouchableOpacity
accessibilityRole="button"
accessible={true}
Expand Down
10 changes: 8 additions & 2 deletions app/components/Nav/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
import OptionsSheet from '../../UI/SelectOptionSheet/OptionsSheet';
import FoxLoader from '../../../components/UI/FoxLoader';
import { AppStateEventProcessor } from '../../../core/AppStateEventListener';
import MultiRpcModal from '../../../components/Views/MultiRpcModal/MultiRpcModal';

const clearStackNavigatorOptions = {
headerShown: false,
Expand Down Expand Up @@ -396,7 +397,6 @@
});
}, [handleDeeplink]);


useEffect(() => {
if (navigator) {
// Initialize deep link manager
Expand Down Expand Up @@ -546,7 +546,7 @@
}
};

const DetectedTokensFlow = () => (

Check warning on line 549 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator
mode={'modal'}
screenOptions={clearStackNavigatorOptions}
Expand All @@ -560,7 +560,7 @@
</Stack.Navigator>
);

const RootModalFlow = () => (

Check warning on line 563 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator mode={'modal'} screenOptions={clearStackNavigatorOptions}>
<Stack.Screen
name={Routes.MODAL.WALLET_ACTIONS}
Expand Down Expand Up @@ -687,11 +687,17 @@
name={Routes.MODAL.NFT_AUTO_DETECTION_MODAL}
component={NFTAutoDetectionModal}
/>
{isNetworkUiRedesignEnabled() ? (
<Stack.Screen
name={Routes.MODAL.MULTI_RPC_MIGRATION_MODAL}
component={MultiRpcModal}
/>
) : null}

<Stack.Screen
name={Routes.SHEET.SHOW_TOKEN_ID}
component={ShowTokenIdSheet}
/>

<Stack.Screen
name={Routes.SHEET.ORIGIN_SPAM_MODAL}
component={OriginSpamModal}
Expand All @@ -703,7 +709,7 @@
</Stack.Navigator>
);

const ImportPrivateKeyView = () => (

Check warning on line 712 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator
screenOptions={{
headerShown: false,
Expand All @@ -724,7 +730,7 @@
</Stack.Navigator>
);

const ConnectQRHardwareFlow = () => (

Check warning on line 733 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator
screenOptions={{
headerShown: false,
Expand All @@ -734,7 +740,7 @@
</Stack.Navigator>
);

const LedgerConnectFlow = () => (

Check warning on line 743 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator
screenOptions={{
headerShown: false,
Expand All @@ -748,7 +754,7 @@
</Stack.Navigator>
);

const ConnectHardwareWalletFlow = () => (

Check warning on line 757 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator name="ConnectHardwareWallet">
<Stack.Screen
name={Routes.HW.SELECT_DEVICE}
Expand All @@ -758,14 +764,14 @@
</Stack.Navigator>
);

const EditAccountNameFlow = () => (

Check warning on line 767 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator>
<Stack.Screen name="EditAccountName" component={EditAccountName} />
</Stack.Navigator>
);

// eslint-disable-next-line react/prop-types
const AddNetworkFlow = ({ route }) => (

Check warning on line 774 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator>
<Stack.Screen
name="AddNetwork"
Expand Down
39 changes: 39 additions & 0 deletions app/components/Nav/Main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import { useMinimumVersions } from '../../hooks/MinimumVersions';
import navigateTermsOfUse from '../../../util/termsOfUse/termsOfUse';
import {
selectChainId,
selectNetworkConfigurations,
selectProviderConfig,
selectProviderType,
} from '../../../selectors/networkController';
Expand All @@ -80,6 +81,7 @@ import {
startIncomingTransactionPolling,
stopIncomingTransactionPolling,
} from '../../../util/transaction-controller';
import isNetworkUiRedesignEnabled from '../../../util/networks/isNetworkUiRedesignEnabled';

const Stack = createStackNavigator();

Expand Down Expand Up @@ -232,8 +234,10 @@ const Main = (props) => {
* Current network
*/
const providerConfig = useSelector(selectProviderConfig);
const networkConfigurations = useSelector(selectNetworkConfigurations);
const networkName = useSelector(selectNetworkName);
const previousProviderConfig = useRef(undefined);
const previousNetworkConfigurations = useRef(undefined);
const { toastRef } = useContext(ToastContext);
const networkImage = useSelector(selectNetworkImageSource);

Expand All @@ -259,6 +263,41 @@ const Main = (props) => {
previousProviderConfig.current = providerConfig;
}, [providerConfig, networkName, networkImage, toastRef]);

// Show add network confirmation.
useEffect(() => {
if (!isNetworkUiRedesignEnabled()) return;

// Memoized values to avoid recalculations
const currentNetworkValues = Object.values(networkConfigurations);
const previousNetworkValues = Object.values(
previousNetworkConfigurations.current ?? {},
);

if (
salimtb marked this conversation as resolved.
Show resolved Hide resolved
previousNetworkValues.length &&
currentNetworkValues.length !== previousNetworkValues.length
) {
// Find the newly added network
const newNetwork = currentNetworkValues.find(
(network) => !previousNetworkValues.includes(network),
);

toastRef?.current?.showToast({
variant: ToastVariants.Plain,
labelOptions: [
{
label: `${newNetwork?.name ?? strings('asset_details.network')} `,
isBold: true,
},
{ label: strings('toast.network_added') },
],
networkImageSource: networkImage,
});
}

previousNetworkConfigurations.current = networkConfigurations;
}, [networkConfigurations, networkName, networkImage, toastRef]);

useEffect(() => {
if (locale.current !== I18n.locale) {
locale.current = I18n.locale;
Expand Down
1 change: 1 addition & 0 deletions app/components/UI/AssetIcon/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const mockInitialState = {
selectedAddress: '0x76cf1CdD1fcC252442b50D6e97207228aA4aefC3',
useTokenDetection: true,
useNftDetection: false,
showMultiRpcModal: false,
displayNftMedia: true,
useSafeChainsListValidation: false,
isMultiAccountBalancesEnabled: true,
Expand Down
30 changes: 30 additions & 0 deletions app/components/Views/MultiRpcModal/MultiRpcModal.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export const SAMPLE_NETWORK_CONFIGURATIONS = {
'0x1': {
blockExplorerUrls: [],
chainId: '0x1',
defaultRpcEndpointIndex: 0,
name: 'Mainnet',
nativeCurrency: 'ETH',
rpcEndpoints: [
{
networkClientId: 'mainnet',
type: 'infura',
url: 'https://mainnet.infura.io/v3/{infuraProjectId}',
},
],
},
'0x5': {
blockExplorerUrls: [],
chainId: '0x5',
defaultRpcEndpointIndex: 0,
name: 'Goerli',
nativeCurrency: 'GoerliETH',
rpcEndpoints: [
{
networkClientId: 'goerli',
type: 'infura',
url: 'https://goerli.infura.io/v3/{infuraProjectId}',
},
],
},
};
Loading
Loading