Skip to content

Commit 11db647

Browse files
chore: Aligned Transactions/Activity tab with the rest of trade lane (MetaMask#21236)
## **Description** This PR updates the Activity/Transactions page UI to align with the latest design system standards and improve consistency across the app. **What is the reason for the change?** The Activity page's filter buttons (used in Transfers and Perps tabs) were using outdated styling and inconsistent component patterns. The buttons didn't follow the current design system guidelines and used a mix of StyleSheet-based styling and old component-library components. **What is the improvement/solution?** - Migrated Activity page to use MetaMask Design System React Native (MMDS) components (`Box`, `Text`) instead of component-library equivalents - Updated all filter buttons (All/Purchased/Sold in Transfers tab, and Trades/Orders/Funding in Perps tab) to use consistent styling: - Height: 40px (previously 32px) - Horizontal padding: 16px - Border radius: 12px (previously 20px) - Gap between buttons: 12px (previously 8px) - Text: Body MD variant with Medium font weight - Selected state: `bg-icon-default` background with `text-icon-inverse` text - Unselected state: `bg-background-muted` background with `text-default` text - Replaced `TouchableOpacity` with `Pressable` for better interaction handling - Converted styling to use Tailwind CSS via `useTailwind()` hook instead of StyleSheet - Improved accessibility with proper pressed states ## **Changelog** CHANGELOG entry: Updated Activity page filter buttons to use design system components with consistent styling ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Updated Activity page filter buttons Scenario: user views and interacts with Transfers filter buttons Given user is on the Activity tab When user taps on the "Transfers" tab Then user should see "All", "Purchased", and "Sold" filter buttons And filter buttons should have 40px height with rounded corners And the "All" button should be selected by default with dark background When user taps on "Purchased" button Then "Purchased" button should become selected with dark background And "All" button should become unselected with light background Scenario: user views and interacts with Perps filter buttons Given user is on the Activity tab And Perps feature is enabled When user taps on the "Perps" tab Then user should see "Trades", "Orders", and "Funding" filter buttons And filter buttons should have 40px height with rounded corners And the "Trades" button should be selected by default When user taps on "Orders" button Then "Orders" button should become selected with dark background And transactions list should update to show orders Scenario: user views button pressed state Given user is on any Activity tab with filter buttons When user presses and holds a filter button Then button should show a pressed state with reduced opacity When user releases the button Then button should return to its normal state ``` ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/ad772865-a079-40dd-a3bf-d9f5776c443e ### **After** https://github.com/user-attachments/assets/87fb66ab-9611-4142-b568-a6d551e897a3 https://github.com/user-attachments/assets/0b110dae-1adc-47cf-92f3-865a7e8d1f37 ## **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** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] 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] > Replaces Activity/Transactions UI with design-system Header/Tabs, standardizes filter/tab styling and behavior, adds dynamic tab management, and updates related styles, tests, and e2e selectors. > > - **ActivityView (major)**: > - Replace legacy header/tab system with `HeaderBase` and `TabsList`; use `Box` and Tailwind utilities. > - Add dynamic tab ordering/visibility (Transactions, Orders, Perps, Predict) with feature flags; expose `goToTabIndex`. > - Move network filter button into Transactions tab and align styles. > - **Tabs**: > - Update `TabsList` to use `React.Children.toArray` + filter valid elements; improve key/label extraction; add swipe navigation; expose testIDs. > - **Perps Transactions**: > - Switch to design-system `Text` variants; Tailwind spacing for filter bar; tweak paddings and section header; minor empty-state padding. > - **Transactions/Multichain/Unified views**: > - Normalize empty/loading containers (full-width, `paddingVertical: 40`, bg); simplify styles creation in Multichain view. > - `TransactionElement`: restructure `ListItem` layout; wrap import-time row in `View`; small style cleanups. > - **Tests**: > - Overhaul ActivityView tests to mock new `TabsList`, validate tab presence/order and navigation; snapshot updates. > - Update e2e selectors/page objects (add `activity-view-tabs` IDs; swipe tabs bar; select tab by label). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5246c91. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 4eff695 commit 11db647

15 files changed

Lines changed: 748 additions & 1234 deletions

File tree

app/component-library/components-temp/Tabs/TabsList/TabsList.tsx

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,24 @@ const TabsList = forwardRef<TabsListRef, TabsListProps>(
3535

3636
const tabs: TabItem[] = useMemo(
3737
() =>
38-
React.Children.map(children, (child, index) => {
39-
if (React.isValidElement(child)) {
40-
const props = child.props as {
38+
React.Children.toArray(children)
39+
.filter((child) => React.isValidElement(child))
40+
.map((child, index) => {
41+
const props = (child as React.ReactElement).props as {
4142
tabLabel?: string;
4243
isDisabled?: boolean;
4344
};
4445
const tabLabel = props.tabLabel || `Tab ${index + 1}`;
4546
const isDisabled = props.isDisabled || false;
4647
return {
47-
key: child.key?.toString() || `tab-${index}`,
48+
key:
49+
(child as React.ReactElement).key?.toString() || `tab-${index}`,
4850
label: tabLabel,
4951
content: child,
5052
isDisabled,
5153
isLoaded: false,
5254
};
53-
}
54-
return {
55-
key: `tab-${index}`,
56-
label: `Tab ${index + 1}`,
57-
content: child,
58-
isDisabled: false,
59-
isLoaded: false,
60-
};
61-
}) || [],
55+
}),
6256
[children],
6357
);
6458

app/component-library/components-temp/Tabs/TabsList/__snapshots__/TabsList.test.tsx.snap

Lines changed: 0 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -146,109 +146,6 @@ exports[`TabsList Edge Cases handles non-React element children with default val
146146
</Text>
147147
</View>
148148
</View>
149-
<View
150-
onLayout={[Function]}
151-
style={
152-
{
153-
"flexShrink": 0,
154-
}
155-
}
156-
>
157-
<View
158-
accessibilityState={
159-
{
160-
"busy": undefined,
161-
"checked": undefined,
162-
"disabled": false,
163-
"expanded": undefined,
164-
"selected": undefined,
165-
}
166-
}
167-
accessibilityValue={
168-
{
169-
"max": undefined,
170-
"min": undefined,
171-
"now": undefined,
172-
"text": undefined,
173-
}
174-
}
175-
accessible={true}
176-
collapsable={false}
177-
focusable={true}
178-
onBlur={[Function]}
179-
onClick={[Function]}
180-
onFocus={[Function]}
181-
onResponderGrant={[Function]}
182-
onResponderMove={[Function]}
183-
onResponderRelease={[Function]}
184-
onResponderTerminate={[Function]}
185-
onResponderTerminationRequest={[Function]}
186-
onStartShouldSetResponder={[Function]}
187-
style={
188-
{
189-
"alignItems": "center",
190-
"flexDirection": "row",
191-
"justifyContent": "center",
192-
"paddingBottom": 4,
193-
"paddingLeft": 0,
194-
"paddingRight": 0,
195-
"paddingTop": 4,
196-
"position": "relative",
197-
}
198-
}
199-
testID="undefined-tab-1"
200-
>
201-
<Text
202-
accessibilityRole="text"
203-
numberOfLines={1}
204-
style={
205-
[
206-
{
207-
"color": "#121314",
208-
"fontFamily": "Geist Bold",
209-
"fontSize": 16,
210-
"fontWeight": 400,
211-
"letterSpacing": 0,
212-
"lineHeight": 24,
213-
},
214-
{
215-
"opacity": 0,
216-
},
217-
]
218-
}
219-
>
220-
Tab 2
221-
</Text>
222-
<Text
223-
accessibilityRole="text"
224-
numberOfLines={1}
225-
style={
226-
[
227-
{
228-
"color": "#686e7d",
229-
"fontFamily": "Geist Regular",
230-
"fontSize": 16,
231-
"fontWeight": 400,
232-
"letterSpacing": 0,
233-
"lineHeight": 24,
234-
},
235-
{
236-
"alignItems": "center",
237-
"bottom": 0,
238-
"display": "flex",
239-
"justifyContent": "center",
240-
"left": 0,
241-
"position": "absolute",
242-
"right": 0,
243-
"top": 0,
244-
},
245-
]
246-
}
247-
>
248-
Tab 2
249-
</Text>
250-
</View>
251-
</View>
252149
</View>
253150
</View>
254151
<View

app/components/UI/Perps/Views/PerpsTransactionsView/PerpsTransactionsView.styles.ts

Lines changed: 6 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,47 +8,21 @@ export const styleSheet = (params: { theme: Theme }) => {
88
container: {
99
flex: 1,
1010
},
11-
filterTabText: {
12-
color: colors.text.alternative,
13-
},
1411
filterContainer: {
12+
paddingVertical: 8,
1513
paddingHorizontal: 16,
16-
paddingVertical: 12,
1714
backgroundColor: colors.background.default,
1815
},
19-
filterScrollView: {
20-
flexGrow: 0,
21-
},
22-
filterTabContainer: {
23-
gap: 8,
24-
},
25-
filterTabActive: {
26-
backgroundColor: colors.background.defaultPressed,
27-
},
28-
transactionList: {
29-
flex: 1,
30-
minHeight: 1, // Prevents FlashList layout issues
31-
},
3216
tabDescription: {
3317
paddingHorizontal: 16,
3418
paddingTop: 8,
3519
},
36-
sectionHeader: {
37-
paddingTop: 12,
38-
paddingHorizontal: 16,
39-
backgroundColor: colors.background.default,
40-
},
41-
sectionHeaderText: {
42-
fontSize: 16,
43-
fontWeight: '600' as const,
44-
color: colors.text.alternative,
45-
},
4620
transactionItem: {
4721
flexDirection: 'row' as const,
4822
alignItems: 'center' as const,
4923
paddingVertical: 16,
5024
paddingHorizontal: 16,
51-
minHeight: 72, // Consistent height for FlashList
25+
minHeight: 72,
5226
},
5327
tokenIconContainer: {
5428
width: 36,
@@ -104,12 +78,11 @@ export const styleSheet = (params: { theme: Theme }) => {
10478
flex: 1,
10579
justifyContent: 'center' as const,
10680
alignItems: 'center' as const,
107-
paddingVertical: 48,
81+
paddingVertical: 40,
10882
},
109-
fillTag: {
110-
flexDirection: 'row' as const,
111-
alignItems: 'center' as const,
112-
gap: 10,
83+
sectionHeader: {
84+
paddingVertical: 12,
85+
paddingHorizontal: 16,
11386
},
11487
};
11588
};

app/components/UI/Perps/Views/PerpsTransactionsView/PerpsTransactionsView.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@ import React, {
1010
import { RefreshControl, ScrollView, View } from 'react-native';
1111
import { useSelector } from 'react-redux';
1212
import { strings } from '../../../../../../locales/i18n';
13-
import Text, {
13+
import {
14+
Text,
1415
TextVariant,
15-
} from '../../../../../component-library/components/Texts/Text';
16+
TextColor,
17+
ButtonSize,
18+
} from '@metamask/design-system-react-native';
1619
import { useStyles } from '../../../../../component-library/hooks';
20+
import { TabEmptyState } from '../../../../../component-library/components-temp/TabEmptyState';
21+
import ButtonFilter from '../../../../../component-library/components-temp/ButtonFilter';
1722
import Routes from '../../../../../constants/navigation/Routes';
1823
import { PerpsNavigationParamList } from '../../types/navigation';
1924
import { selectSelectedInternalAccountFormattedAddress } from '../../../../../selectors/accountsController';
@@ -36,12 +41,11 @@ import { formatDateSection } from '../../utils/formatUtils';
3641
import { styleSheet } from './PerpsTransactionsView.styles';
3742
import { usePerpsMeasurement } from '../../hooks/usePerpsMeasurement';
3843
import { TraceName } from '../../../../../util/trace';
39-
import ButtonFilter from '../../../../../component-library/components-temp/ButtonFilter';
40-
import { ButtonSize } from '@metamask/design-system-react-native';
41-
import { TabEmptyState } from '../../../../../component-library/components-temp/TabEmptyState';
44+
import { useTailwind } from '@metamask/design-system-twrnc-preset';
4245

4346
const PerpsTransactionsView: React.FC<PerpsTransactionsViewProps> = () => {
4447
const { styles } = useStyles(styleSheet, {});
48+
const tw = useTailwind();
4549
const navigation = useNavigation<NavigationProp<PerpsNavigationParamList>>();
4650

4751
// Transaction data is now computed from hooks instead of stored in state
@@ -266,7 +270,7 @@ const PerpsTransactionsView: React.FC<PerpsTransactionsViewProps> = () => {
266270
if (item.fill) {
267271
return (
268272
<Text
269-
variant={TextVariant.BodySM}
273+
variant={TextVariant.BodySm}
270274
style={item.fill.isPositive ? styles.profitAmount : styles.lossAmount}
271275
>
272276
{item.fill.amount}
@@ -285,7 +289,7 @@ const PerpsTransactionsView: React.FC<PerpsTransactionsViewProps> = () => {
285289
}
286290

287291
return (
288-
<Text variant={TextVariant.BodySM} style={statusStyle}>
292+
<Text variant={TextVariant.BodySm} style={statusStyle}>
289293
{item.order.text}
290294
</Text>
291295
);
@@ -294,7 +298,7 @@ const PerpsTransactionsView: React.FC<PerpsTransactionsViewProps> = () => {
294298
if (item.fundingAmount) {
295299
return (
296300
<Text
297-
variant={TextVariant.BodySM}
301+
variant={TextVariant.BodySm}
298302
style={
299303
item.fundingAmount.isPositive
300304
? styles.profitAmount
@@ -314,7 +318,7 @@ const PerpsTransactionsView: React.FC<PerpsTransactionsViewProps> = () => {
314318
if (item.type === 'header') {
315319
return (
316320
<View style={styles.sectionHeader}>
317-
<Text style={styles.sectionHeaderText}>{item.title}</Text>
321+
<Text color={TextColor.TextAlternative}>{item.title}</Text>
318322
</View>
319323
);
320324
}
@@ -382,7 +386,7 @@ const PerpsTransactionsView: React.FC<PerpsTransactionsViewProps> = () => {
382386
<ScrollView
383387
horizontal
384388
showsHorizontalScrollIndicator={false}
385-
style={styles.filterScrollView}
389+
contentContainerStyle={tw.style('flex-row gap-3')}
386390
pointerEvents="auto"
387391
scrollEnabled={false}
388392
>
@@ -392,7 +396,7 @@ const PerpsTransactionsView: React.FC<PerpsTransactionsViewProps> = () => {
392396

393397
{filterTabDescription && (
394398
<View style={styles.tabDescription}>
395-
<Text variant={TextVariant.BodySM}>{filterTabDescription}</Text>
399+
<Text variant={TextVariant.BodySm}>{filterTabDescription}</Text>
396400
</View>
397401
)}
398402

@@ -406,7 +410,7 @@ const PerpsTransactionsView: React.FC<PerpsTransactionsViewProps> = () => {
406410
<View style={styles.filterContainer} pointerEvents="box-none">
407411
<ScrollView
408412
horizontal
409-
contentContainerStyle={styles.filterTabContainer}
413+
contentContainerStyle={tw.style('flex-row gap-3')}
410414
showsHorizontalScrollIndicator={false}
411415
pointerEvents="auto"
412416
scrollEnabled
@@ -417,7 +421,7 @@ const PerpsTransactionsView: React.FC<PerpsTransactionsViewProps> = () => {
417421

418422
{filterTabDescription && (
419423
<View style={styles.tabDescription}>
420-
<Text variant={TextVariant.BodySM}>{filterTabDescription}</Text>
424+
<Text variant={TextVariant.BodySm}>{filterTabDescription}</Text>
421425
</View>
422426
)}
423427

0 commit comments

Comments
 (0)