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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- fix(bridge): prevent quote polling when "quote expired" modal is open ([#15602](https://github.com/MetaMask/metamask-mobile/issues/15602))
- fix(browser): fix browser PermissionsSummary origin spoofing when browser redirects issue ([#13394](https://github.com/MetaMask/metamask-mobile/pull/13394))

### Changed
- feat: update minimum version modal UI ([#15567](https://github.com/MetaMask/metamask-mobile/pull/15567))

### Added

- feat(bridge): improve bridge screen layout and user experience ([#15425](https://github.com/MetaMask/metamask-mobile/pull/15425))
Expand Down
59 changes: 58 additions & 1 deletion app/components/UI/UpdateNeeded/UpdateNeeded.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,70 @@
import { renderScreen } from '../../..//util/test/renderWithProvider';
import { UpdateNeeded } from './';
import { fireEvent } from '@testing-library/react-native';
import { MM_APP_STORE_LINK, MM_PLAY_STORE_LINK } from '../../../constants/urls';
import { Platform } from 'react-native';

const mockCanOpenURL = jest.fn(() => Promise.resolve(true));
const mockOpenURL = jest.fn(() => Promise.resolve());
const mockAddEventListener = jest.fn();
const mockRemoveEventListener = jest.fn();

jest.mock('react-native/Libraries/Linking/Linking', () => ({
openURL: mockOpenURL,
canOpenURL: mockCanOpenURL,
addEventListener: mockAddEventListener,
removeEventListener: mockRemoveEventListener,
}));

describe('UpdateNeeded', () => {
it('should render correctly', () => {
it('should render snapshot correctly', () => {
const { toJSON } = renderScreen(
UpdateNeeded,
{ name: 'UpdateNeeded' },
{ state: {} },
);
expect(toJSON()).toMatchSnapshot();
});
it('should render correctly', () => {
const { getByText, getByTestId } = renderScreen(
UpdateNeeded,
{ name: 'UpdateNeeded' },
{ state: {} },
);
const title = getByText('Get the newest features')
expect(title).toBeDefined();

const description = getByText('We’ve made your wallet safer, smoother, and added some new features. Update now to stay protected and use our latest improvements.');
expect(description).toBeDefined();

const closeButton = getByTestId('update-needed-modal-close-button');
expect(closeButton).toBeDefined();

const primaryButton = getByText('Update to latest version');
expect(primaryButton).toBeDefined();
});
it('should open iOS App Store on primary button press', () => {
Platform.OS = 'ios';
const { getByText } = renderScreen(
UpdateNeeded,
{ name: 'UpdateNeeded' },
{ state: {} },
);
const primaryButton = getByText('Update to latest version');
fireEvent.press(primaryButton);
expect(mockCanOpenURL).toHaveBeenCalled();
expect(mockCanOpenURL).toHaveBeenCalledWith(MM_APP_STORE_LINK);
});
it('should open Google Play Store on primary button press', () => {
Platform.OS = 'android';
const { getByText } = renderScreen(
UpdateNeeded,
{ name: 'UpdateNeeded' },
{ state: {} },
);
const primaryButton = getByText('Update to latest version');
fireEvent.press(primaryButton);
expect(mockCanOpenURL).toHaveBeenCalled();
expect(mockCanOpenURL).toHaveBeenCalledWith(MM_PLAY_STORE_LINK);
});
});
45 changes: 33 additions & 12 deletions app/components/UI/UpdateNeeded/UpdateNeeded.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ import { useTheme } from '../../../util/theme';
import ReusableModal, { ReusableModalRef } from '../ReusableModal';
import Logger from '../../../util/Logger';
import Button, {
ButtonSize,
ButtonVariants,
ButtonWidthTypes,
} from '../../../component-library/components/Buttons/Button';
import ButtonIcon, {
} from '../../../component-library/components/Buttons/ButtonIcon';
import HeaderBase from '../../../component-library/components/HeaderBase';
import {
IconColor,
IconName,
} from '../../../component-library/components/Icons/Icon';
import { MM_APP_STORE_LINK, MM_PLAY_STORE_LINK } from '../../../constants/urls';
import { MetaMetricsEvents } from '../../../core/Analytics';

Expand All @@ -23,7 +29,8 @@ import generateDeviceAnalyticsMetaData from '../../../util/metrics';
import { useMetrics } from '../../../components/hooks/useMetrics';

/* eslint-disable import/no-commonjs, @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports */
const onboardingDeviceImage = require('../../../images/swaps_onboard_device.png');
const foxLogo = require('../../../images/branding/fox.png');
const metamaskName = require('../../../images/branding/metamask-name.png');

export const createUpdateNeededNavDetails = createNavigationDetails(
Routes.MODAL.ROOT_MODAL_FLOW,
Expand Down Expand Up @@ -91,11 +98,32 @@ const UpdateNeeded = () => {

return (
<ReusableModal ref={modalRef} style={styles.screen}>
<HeaderBase
style={styles.header}
includesTopInset
endAccessory={
<ButtonIcon
onPress={triggerClose}
iconName={IconName.Close}
iconColor={IconColor.Default}
testID="update-needed-modal-close-button"
/>}
>
<Image
style={styles.headerLogo}
source={metamaskName}
resizeMode='contain'
/>
</HeaderBase>
<ScrollView contentContainerStyle={styles.content}>
<View style={styles.images}>
<Image source={onboardingDeviceImage} />
<Image source={foxLogo}
style={styles.foxImage}
resizeMethod='auto'
resizeMode='contain'
/>
</View>
<Text variant={TextVariant.DisplayMD} style={styles.title}>
<Text variant={TextVariant.HeadingLG} style={styles.title}>
{strings('update_needed.title')}
</Text>
<Text variant={TextVariant.BodyMD} style={styles.description}>
Expand All @@ -110,15 +138,8 @@ const UpdateNeeded = () => {
onPress={onUpdatePressed}
style={styles.actionButton}
/>
<Button
variant={ButtonVariants.Link}
width={ButtonWidthTypes.Full}
label={strings('update_needed.secondary_action')}
size={ButtonSize.Md}
onPress={triggerClose}
/>
</View>
</ReusableModal>
</ReusableModal >
);
};

Expand Down
147 changes: 106 additions & 41 deletions app/components/UI/UpdateNeeded/__snapshots__/UpdateNeeded.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`UpdateNeeded should render correctly 1`] = `
exports[`UpdateNeeded should render snapshot correctly 1`] = `
<View
style={
{
Expand Down Expand Up @@ -383,6 +383,98 @@ exports[`UpdateNeeded should render correctly 1`] = `
}
}
/>
<View
style={
[
{
"alignItems": "center",
"backgroundColor": "#ffffff",
"flexDirection": "row",
},
{
"marginTop": 0,
},
]
}
testID="header"
>
<View
style={
{
"width": undefined,
}
}
>
<View
onLayout={[Function]}
/>
</View>
<View
style={
{
"alignItems": "center",
"flex": 1,
"marginHorizontal": 16,
}
}
>
<Image
resizeMode="contain"
source={1}
style={
{
"height": 32,
"width": 67,
}
}
/>
</View>
<View
style={
{
"width": undefined,
}
}
>
<View
onLayout={[Function]}
>
<TouchableOpacity
accessible={true}
activeOpacity={1}
disabled={false}
onPress={[Function]}
onPressIn={[Function]}
onPressOut={[Function]}
style={
{
"alignItems": "center",
"borderRadius": 8,
"height": 24,
"justifyContent": "center",
"opacity": 1,
"width": 24,
}
}
testID="update-needed-modal-close-button"
>
<SvgMock
color="#121314"
fill="currentColor"
height={16}
name="Close"
style={
{
"height": 16,
"width": 16,
}
}
width={16}
/>
</TouchableOpacity>
</View>
</View>
</View>
<RCTScrollView
collapsable={false}
contentContainerStyle={
Expand All @@ -400,11 +492,20 @@ exports[`UpdateNeeded should render correctly 1`] = `
style={
{
"alignItems": "center",
"marginBottom": 40,
}
}
>
<Image
resizeMethod="auto"
resizeMode="contain"
source={1}
style={
{
"height": 140,
"width": 140,
}
}
/>
</View>
<Text
Expand All @@ -413,16 +514,16 @@ exports[`UpdateNeeded should render correctly 1`] = `
{
"color": "#121314",
"fontFamily": "CentraNo1-Bold",
"fontSize": 32,
"fontSize": 24,
"fontWeight": "700",
"letterSpacing": 0,
"lineHeight": 40,
"lineHeight": 32,
"paddingBottom": 16,
"textAlign": "center",
}
}
>
Updates needed
Get the newest features
</Text>
<Text
accessibilityRole="text"
Expand All @@ -438,7 +539,7 @@ exports[`UpdateNeeded should render correctly 1`] = `
}
}
>
We've increased security for your wallet! Please take a moment to protect yourself and update to the latest version.
Weve made your wallet safer, smoother, and added some new features. Update now to stay protected and use our latest improvements.
</Text>
</View>
</RCTScrollView>
Expand Down Expand Up @@ -488,42 +589,6 @@ exports[`UpdateNeeded should render correctly 1`] = `
Update to latest version
</Text>
</TouchableOpacity>
<TouchableOpacity
accessibilityRole="button"
accessible={true}
activeOpacity={1}
onPress={[Function]}
onPressIn={[Function]}
onPressOut={[Function]}
style={
{
"alignItems": "center",
"alignSelf": "stretch",
"backgroundColor": "transparent",
"borderRadius": 12,
"flexDirection": "row",
"height": 40,
"justifyContent": "center",
"paddingHorizontal": 16,
}
}
>
<Text
accessibilityRole="text"
style={
{
"color": "#4459ff",
"fontFamily": "CentraNo1-Medium",
"fontSize": 16,
"fontWeight": "500",
"letterSpacing": 0,
"lineHeight": 24,
}
}
>
Remind me later
</Text>
</TouchableOpacity>
</View>
</View>
</View>
Expand Down
12 changes: 12 additions & 0 deletions app/components/UI/UpdateNeeded/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ export const createStyles = (colors: any) =>
alignItems: 'center',
backgroundColor: colors.background.default,
},
header: {
alignItems: 'center',
},
headerLogo: {
width: 67,
height: 32,
},
content: {
justifyContent: 'center',
paddingHorizontal: 16,
Expand All @@ -27,6 +34,7 @@ export const createStyles = (colors: any) =>
},
images: {
alignItems: 'center',
marginBottom: 40,
},
actionButtonWrapper: {
width: '100%',
Expand All @@ -37,4 +45,8 @@ export const createStyles = (colors: any) =>
marginVertical: 10,
padding: 8,
},
foxImage: {
width: 140,
height: 140,
},
});
Loading
Loading