Skip to content
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
9 changes: 8 additions & 1 deletion app/component-library/components/Toast/Toast.context.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/* eslint-disable react/prop-types */

// Third party dependencies.
import React, { useRef } from 'react';
import React, { useRef, useEffect } from 'react';

// Internal dependencies.
import { ToastRef, ToastContextParams } from './Toast.types';
import ToastService from '../../../core/ToastService';

export const ToastContext = React.createContext<ToastContextParams>({
toastRef: undefined,
Expand All @@ -14,6 +15,12 @@ export const ToastContextWrapper: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const toastRef = useRef<ToastRef | null>(null);

useEffect(() => {
// Register the ref with ToastService when the component is mounted
ToastService.toastRef = toastRef;
}, [toastRef]);

return (
<ToastContext.Provider value={{ toastRef }}>
{children}
Expand Down
5 changes: 4 additions & 1 deletion app/components/UI/AccountRightButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,7 @@ const AccountRightButton = ({
);
};

export default AccountRightButton;
const AccountRightButtonMemoized = React.memo(AccountRightButton);
AccountRightButtonMemoized.displayName = 'AccountRightButton';

export default AccountRightButtonMemoized;
107 changes: 69 additions & 38 deletions app/components/UI/BrowserBottomBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useCallback, useMemo } from 'react';
import { Platform, ImageSourcePropType } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useTailwind } from '@metamask/design-system-twrnc-preset';
Expand Down Expand Up @@ -76,6 +76,8 @@ interface BrowserBottomBarProps {
icon?: ImageSourcePropType;
}

const MemoizedButtonIcon = React.memo(ButtonIcon);

/**
* Browser bottom bar that contains icons for navigation,
* bookmark management, and tab operations
Expand Down Expand Up @@ -103,34 +105,42 @@ const BrowserBottomBar: React.FC<BrowserBottomBarProps> = ({
const bookmarks = useSelector((state: RootState) => state.bookmarks);
const tabCount = useSelector(selectBrowserTabCount);

const trackNavigationEvent = (navigationOption: string): void => {
trackEvent(
createEventBuilder(MetaMetricsEvents.BROWSER_NAVIGATION)
.addProperties({
option_chosen: navigationOption,
os: Platform.OS,
})
.build(),
);
};
const maskedActiveUrl = useMemo(
() => getMaskedUrl(activeUrl, sessionENSNames),
[activeUrl, getMaskedUrl, sessionENSNames],
);

const trackNavigationEvent = useCallback(
(navigationOption: string): void => {
trackEvent(
createEventBuilder(MetaMetricsEvents.BROWSER_NAVIGATION)
.addProperties({
option_chosen: navigationOption,
os: Platform.OS,
})
.build(),
);
},
[trackEvent, createEventBuilder],
);

/**
* Check if current URL is bookmarked
*/
const isBookmark = (): boolean => {
const maskedUrl = getMaskedUrl(activeUrl, sessionENSNames);
return bookmarks.some(({ url }: { url: string }) => url === maskedUrl);
};
const isBookmarked = useMemo(
() => bookmarks.some(({ url }: { url: string }) => url === maskedActiveUrl),
[bookmarks, maskedActiveUrl],
);

/**
* Navigate to AddBookmarkView modal
*/
const navigateToAddBookmark = () => {
const navigateToAddBookmark = useCallback(() => {
navigation.push('AddBookmarkView', {
screen: 'AddBookmark',
params: {
title: title || '',
url: getMaskedUrl(activeUrl, sessionENSNames),
url: maskedActiveUrl,
onAddBookmark: async ({
name,
url: urlToAdd,
Expand Down Expand Up @@ -180,55 +190,76 @@ const BrowserBottomBar: React.FC<BrowserBottomBarProps> = ({
trackEvent(
createEventBuilder(MetaMetricsEvents.DAPP_ADD_TO_FAVORITE).build(),
);
};
}, [
navigation,
title,
activeUrl,
maskedActiveUrl,
getMaskedUrl,
sessionENSNames,
dispatch,
icon,
favicon,
trackEvent,
createEventBuilder,
]);

/**
* Check if bookmark button should be disabled
*/
const isBookmarkDisabled = !activeUrl || activeUrl.trim() === '';
const isBookmarkDisabled = useMemo(
() => !activeUrl || activeUrl.trim() === '',
[activeUrl],
);

/**
* Handle bookmark button press - add or remove bookmark
*/
const handleBookmarkPress = () => {
const handleBookmarkPress = useCallback(() => {
// Don't allow bookmarking empty URLs
if (isBookmarkDisabled) return;

if (isBookmark()) {
const maskedUrl = getMaskedUrl(activeUrl, sessionENSNames);
if (isBookmarked) {
const bookmarkToRemove = bookmarks.find(
({ url }: { url: string }) => url === maskedUrl,
({ url }: { url: string }) => url === maskedActiveUrl,
);
if (bookmarkToRemove) {
dispatch(removeBookmark(bookmarkToRemove));
}
} else {
navigateToAddBookmark();
}
};
}, [
isBookmarkDisabled,
isBookmarked,
maskedActiveUrl,
bookmarks,
dispatch,
navigateToAddBookmark,
]);

const onBackPress = (): void => {
const onBackPress = useCallback((): void => {
if (goBack) {
goBack();
trackNavigationEvent('Go Back');
}
};
}, [goBack, trackNavigationEvent]);

const onForwardPress = (): void => {
const onForwardPress = useCallback((): void => {
if (goForward) {
goForward();
trackNavigationEvent('Go Forward');
}
};
}, [goForward, trackNavigationEvent]);

const onReloadPress = (): void => {
const onReloadPress = useCallback((): void => {
if (reload) {
reload();
trackEvent(createEventBuilder(MetaMetricsEvents.BROWSER_RELOAD).build());
}
};
}, [reload, trackEvent, createEventBuilder]);

const onNewTabPress = (): void => {
const onNewTabPress = useCallback((): void => {
if (openNewTab) {
openNewTab();
trackEvent(
Expand All @@ -240,7 +271,7 @@ const BrowserBottomBar: React.FC<BrowserBottomBarProps> = ({
.build(),
);
}
};
}, [openNewTab, trackEvent, createEventBuilder, tabCount]);

return (
<Box
Expand All @@ -259,7 +290,7 @@ const BrowserBottomBar: React.FC<BrowserBottomBarProps> = ({
twClassName="gap-4"
>
{/* Back Button */}
<ButtonIcon
<MemoizedButtonIcon
iconName={IconName.ArrowLeft}
size={ButtonIconSize.Lg}
onPress={onBackPress}
Expand All @@ -268,7 +299,7 @@ const BrowserBottomBar: React.FC<BrowserBottomBarProps> = ({
/>

{/* Forward Button */}
<ButtonIcon
<MemoizedButtonIcon
iconName={IconName.ArrowRight}
size={ButtonIconSize.Lg}
onPress={onForwardPress}
Expand All @@ -277,7 +308,7 @@ const BrowserBottomBar: React.FC<BrowserBottomBarProps> = ({
/>

{/* Reload Button */}
<ButtonIcon
<MemoizedButtonIcon
iconName={IconName.Refresh}
size={ButtonIconSize.Lg}
onPress={onReloadPress}
Expand All @@ -291,16 +322,16 @@ const BrowserBottomBar: React.FC<BrowserBottomBarProps> = ({
twClassName="gap-4"
>
{/* Bookmark Button */}
<ButtonIcon
iconName={isBookmark() ? IconName.StarFilled : IconName.Star}
<MemoizedButtonIcon
iconName={isBookmarked ? IconName.StarFilled : IconName.Star}
size={ButtonIconSize.Lg}
onPress={handleBookmarkPress}
isDisabled={isBookmarkDisabled}
testID={BrowserViewSelectorsIDs.BOOKMARK_BUTTON}
/>

{/* New Tab Button */}
<ButtonIcon
<MemoizedButtonIcon
iconName={IconName.Add}
size={ButtonIconSize.Lg}
onPress={onNewTabPress}
Expand Down
53 changes: 32 additions & 21 deletions app/components/UI/BrowserUrlBar/BrowserUrlBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,42 +196,52 @@ const BrowserUrlBar = forwardRef<BrowserUrlBarRef, BrowserUrlBarProps>(
return iconName;
}, [connectionType]);

const onBlurInput = () => {
const onBlurInput = useCallback(() => {
if (!shouldTriggerBlurCallbackRef.current) {
shouldTriggerBlurCallbackRef.current = true;
return;
}
unfocusInput();
onBlur();
};
}, [unfocusInput, onBlur]);

const onFocusInput = () => {
const onFocusInput = useCallback(() => {
setIsUrlBarFocused(true);
onFocus();
};
}, [setIsUrlBarFocused, onFocus]);

const onChangeTextInput = (text: string) => {
inputRef?.current?.setNativeProps({ text });
onChangeText(text);
};
const onPressUrlText = useCallback(() => {
inputRef?.current?.focus();
}, []);

const onSubmitEditingInput = ({
nativeEvent: { text },
}: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => {
const trimmedText = text.trim();
inputValueRef.current = trimmedText;
onSubmitEditing(trimmedText);
};
const onChangeTextInput = useCallback(
(text: string) => {
inputRef?.current?.setNativeProps({ text });
onChangeText(text);
},
[onChangeText],
);

const onSubmitEditingInput = useCallback(
({
nativeEvent: { text },
}: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => {
const trimmedText = text.trim();
inputValueRef.current = trimmedText;
onSubmitEditing(trimmedText);
},
[onSubmitEditing],
);

/**
* Clears the input value and calls the onChangeText callback
*/
const onClearInput = () => {
const onClearInput = useCallback(() => {
const clearedText = '';
inputRef?.current?.clear();
inputValueRef.current = clearedText;
onChangeText(clearedText);
};
}, [onChangeText]);

return (
<View style={styles.browserUrlBarWrapper}>
Expand Down Expand Up @@ -263,9 +273,7 @@ const BrowserUrlBar = forwardRef<BrowserUrlBarRef, BrowserUrlBarProps>(
onBlur={onBlurInput}
onFocus={onFocusInput}
/>
<TouchableWithoutFeedback
onPress={() => inputRef?.current?.focus()}
>
<TouchableWithoutFeedback onPress={onPressUrlText}>
<Text
style={styles.urlBarText}
numberOfLines={1}
Expand Down Expand Up @@ -307,4 +315,7 @@ const BrowserUrlBar = forwardRef<BrowserUrlBarRef, BrowserUrlBarProps>(
},
);

export default BrowserUrlBar;
const BrowserUrlBarMemoized = React.memo(BrowserUrlBar);
BrowserUrlBarMemoized.displayName = 'BrowserUrlBar';

export default BrowserUrlBarMemoized;
7 changes: 5 additions & 2 deletions app/components/UI/UrlAutocomplete/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ const UrlAutocomplete = forwardRef<
const [searchQuery, setSearchQuery] = useState('');

const resultsRef = useRef<View | null>(null);
const { styles } = useStyles(styleSheet, {});
const { styles } = useStyles(styleSheet);

// Empty state: show Recents and Favorites from browser history/bookmarks
const emptyStateResults: ResultsWithCategory[] = useMemo(() => {
Expand Down Expand Up @@ -621,4 +621,7 @@ const UrlAutocomplete = forwardRef<
);
});

export default UrlAutocomplete;
const UrlAutocompleteMemoized = React.memo(UrlAutocomplete);
UrlAutocompleteMemoized.displayName = 'UrlAutocomplete';

export default UrlAutocompleteMemoized;
7 changes: 5 additions & 2 deletions app/components/Views/Browser/Browser.components.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
// 1. if tabs.length > 4, show the max browser tabs modal
// 2. if tabs.length <= 4, create a new tab

import React from 'react';
import { Browser } from './index';
import React, { ComponentType } from 'react';
import { BrowserPure as BrowserComponent } from './index';
import { BrowserComponentProps } from './Browser.types';
import Routes from '../../../constants/navigation/Routes';
import renderWithProvider from '../../../util/test/renderWithProvider';
import { backgroundState } from '../../../util/test/initial-root-state';
Expand All @@ -20,6 +21,8 @@ import { captureScreen } from 'react-native-view-shot';
import Logger from '../../../util/Logger';
import BrowserTab from '../BrowserTab/BrowserTab';

const Browser = BrowserComponent as ComponentType<BrowserComponentProps>;

jest.useFakeTimers();

jest.mock('../../hooks/useAccounts', () => ({
Expand Down
Loading
Loading