Skip to content

Commit 3d613d9

Browse files
authored
refactor: migrate ChoosePassword to design system components and Tailwind CSS (MetaMask#27616)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This PR migrates the `ChoosePassword` view and its `FoxRiveLoaderAnimation` sub-component away from legacy StyleSheet.create()-based styling toward the `MetaMask design system and Tailwind CSS`. Jira Link: https://consensyssoftware.atlassian.net/browse/TO-602 ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: migrate ChoosePassword to design system components and Tailwind CSS ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: ChoosePassword screen — visual and functional parity after style migration Scenario: New wallet creation with SRP backup Given the app is freshly installed and onboarding is in progress When the user reaches the "Create Password" screen Then the screen renders with title, password field, confirm field, checkbox, and button And the "Create Password" button is disabled When the user types a password ≥ 8 characters And types the same value in the confirm password field And checks the "I understand" checkbox Then the "Create Password" button becomes enabled When the user taps "Create Password" Then the Fox Rive loading animation appears and the form is hidden And after completion the user is navigated to the Manual Backup step Scenario: Password mismatch validation Given the user is on the "Create Password" screen When the user types different values in each password field Then a mismatch error is displayed and the button stays disabled Scenario: Password too short Given the user is on the "Create Password" screen When the user types fewer than 8 characters Then the helper text "Must be at least 8 characters" is always visible Scenario: OAuth (social login) flow Given the user arrived via a social login Then the button is enabled without checking the checkbox And on submit the user is navigated to the Onboarding Success screen Scenario: Dark-mode theme correctness Given the device is in dark mode When the user opens the "Create Password" screen Then all text, backgrounds, and icons use correct design system colour tokens And no hardcoded colours are visible ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/79e2215f-8874-46eb-b332-840ac271a75d https://github.com/user-attachments/assets/70708f0b-5417-4b65-bbbe-4d765c71a379 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > UI refactor of the password creation/onboarding flow that changes component primitives, accessibility identifiers, and loading/form rendering, which can cause visual or E2E regressions despite largely preserving business logic. > > **Overview** > Migrates the `ChoosePassword` screen and `FoxRiveLoaderAnimation` from legacy `StyleSheet` + internal component-library primitives to **design-system React Native components** (`Box`, `Text`, `TextField`, `Button`, `Checkbox`, `Icon`) styled via **Tailwind** (`useTailwind`), deleting the old `*.styles.ts` files. > > Adjusts a few UI behaviors and identifiers (e.g., confirm-password eye toggle disabled when empty, adds `accessibilityLabel`s for password fields, updates icon color tokens) and updates snapshots/unit tests accordingly, including refactored `ChoosePassword` tests and Detox page object selectors to use labels on Android. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 7ddefaf. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 9385d8c commit 3d613d9

10 files changed

Lines changed: 1322 additions & 1976 deletions

File tree

app/components/Views/ChoosePassword/ChoosePassword.styles.ts

Lines changed: 0 additions & 105 deletions
This file was deleted.

app/components/Views/ChoosePassword/FoxRiveLoaderAnimation/FoxRiveLoaderAnimation.tsx

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import React, { useEffect, useMemo, useRef } from 'react';
2-
import { View, ActivityIndicator } from 'react-native';
2+
import { ActivityIndicator } from 'react-native';
33
import Rive, { Fit, Alignment, RiveRef } from 'rive-react-native';
44
import { useTheme } from '../../../../util/theme';
5-
import createStyles from './index.styles';
6-
5+
import { useTailwind } from '@metamask/design-system-twrnc-preset';
6+
import {
7+
Box,
8+
BoxAlignItems,
9+
BoxJustifyContent,
10+
} from '@metamask/design-system-react-native';
711
import onboardingRiveFile from '../../../../animations/fox_loading.riv';
812
import { getScreenDimensions } from '../../../../util/onboarding';
913
import { isE2E } from '../../../../util/test/utils';
@@ -13,12 +17,26 @@ interface FoxRiveLoaderAnimationProps {}
1317
const FoxRiveLoaderAnimation: React.FC<FoxRiveLoaderAnimationProps> = () => {
1418
const riveRef = useRef<RiveRef>(null);
1519
const { colors } = useTheme();
20+
const tw = useTailwind();
21+
const { screenWidth, animationHeight } = getScreenDimensions();
22+
23+
const animationWrapperStyle = useMemo(
24+
() => ({ width: screenWidth, height: animationHeight }),
25+
[screenWidth, animationHeight],
26+
);
1627

17-
const screenDimensions = getScreenDimensions();
28+
const riveAnimationStyle = useMemo(
29+
() => ({
30+
...tw.style('self-center bg-background-default'),
31+
width: screenWidth * 0.4,
32+
height: animationHeight,
33+
}),
34+
[screenWidth, animationHeight, tw],
35+
);
1836

19-
const styles = useMemo(
20-
() => createStyles(colors, screenDimensions),
21-
[colors, screenDimensions],
37+
const textWrapperStyle = useMemo(
38+
() => ({ width: screenWidth }),
39+
[screenWidth],
2240
);
2341

2442
useEffect(() => {
@@ -32,21 +50,35 @@ const FoxRiveLoaderAnimation: React.FC<FoxRiveLoaderAnimationProps> = () => {
3250
}, [riveRef]);
3351

3452
return (
35-
<View testID="fox-rive-loader-animation" style={styles.animationContainer}>
36-
<View style={styles.animationWrapper}>
53+
<Box
54+
testID="fox-rive-loader-animation"
55+
alignItems={BoxAlignItems.Center}
56+
justifyContent={BoxJustifyContent.Start}
57+
twClassName="flex-1 bg-background-default pt-[30px]"
58+
>
59+
<Box
60+
alignItems={BoxAlignItems.Center}
61+
justifyContent={BoxJustifyContent.Center}
62+
twClassName="bg-background-default"
63+
style={animationWrapperStyle}
64+
>
3765
<Rive
3866
ref={riveRef}
3967
source={onboardingRiveFile}
40-
style={styles.riveAnimation}
68+
style={riveAnimationStyle}
4169
autoplay
4270
fit={Fit.Contain}
4371
alignment={Alignment.Center}
4472
/>
45-
</View>
46-
<View style={styles.textWrapper}>
73+
</Box>
74+
<Box
75+
justifyContent={BoxJustifyContent.End}
76+
twClassName="px-5"
77+
style={textWrapperStyle}
78+
>
4779
<ActivityIndicator size="large" color={colors.text.default} />
48-
</View>
49-
</View>
80+
</Box>
81+
</Box>
5082
);
5183
};
5284

app/components/Views/ChoosePassword/FoxRiveLoaderAnimation/__snapshots__/index.test.tsx.snap

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,36 @@
33
exports[`FoxRiveLoaderAnimation displays Rive animation and ActivityIndicator 1`] = `
44
<View
55
style={
6-
{
7-
"testID": "animation-container",
8-
}
6+
[
7+
{
8+
"alignItems": "center",
9+
"backgroundColor": "#ffffff",
10+
"display": "flex",
11+
"flexBasis": "0%",
12+
"flexGrow": 1,
13+
"flexShrink": 1,
14+
"justifyContent": "flex-start",
15+
"paddingTop": 30,
16+
},
17+
undefined,
18+
]
919
}
1020
testID="fox-rive-loader-animation"
1121
>
1222
<View
1323
style={
14-
{
15-
"testID": "animation-wrapper",
16-
}
24+
[
25+
{
26+
"alignItems": "center",
27+
"backgroundColor": "#ffffff",
28+
"display": "flex",
29+
"justifyContent": "center",
30+
},
31+
{
32+
"height": 406,
33+
"width": 375,
34+
},
35+
]
1736
}
1837
>
1938
<RiveView
@@ -22,16 +41,27 @@ exports[`FoxRiveLoaderAnimation displays Rive animation and ActivityIndicator 1`
2241
source="mock-rive-file"
2342
style={
2443
{
25-
"testID": "rive-animation",
44+
"alignSelf": "center",
45+
"backgroundColor": "#ffffff",
46+
"height": 406,
47+
"width": 150,
2648
}
2749
}
2850
/>
2951
</View>
3052
<View
3153
style={
32-
{
33-
"testID": "text-wrapper",
34-
}
54+
[
55+
{
56+
"display": "flex",
57+
"justifyContent": "flex-end",
58+
"paddingLeft": 20,
59+
"paddingRight": 20,
60+
},
61+
{
62+
"width": 375,
63+
},
64+
]
3565
}
3666
>
3767
<ActivityIndicator

app/components/Views/ChoosePassword/FoxRiveLoaderAnimation/index.styles.ts

Lines changed: 0 additions & 67 deletions
This file was deleted.

app/components/Views/ChoosePassword/FoxRiveLoaderAnimation/index.test.tsx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,6 @@ jest.mock('../../../../util/device', () => ({
5656
default: mockDevice,
5757
}));
5858

59-
// Mock styles
60-
jest.mock('./index.styles', () =>
61-
jest.fn(() => ({
62-
animationContainer: { testID: 'animation-container' },
63-
animationWrapper: { testID: 'animation-wrapper' },
64-
textWrapper: { testID: 'text-wrapper' },
65-
riveAnimation: { testID: 'rive-animation' },
66-
})),
67-
);
68-
6959
import FoxRiveLoaderAnimation from './FoxRiveLoaderAnimation';
7060

7161
describe('FoxRiveLoaderAnimation', () => {

0 commit comments

Comments
 (0)