Skip to content

Commit 4fdbac9

Browse files
authored
chore: spacing fix in Whats happening carousel card (#30186)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Fixes the spacing in the Whats happening carousel card. Before: <img width="300" height="146" alt="Screenshot 2026-05-14 at 14 58 30" src="https://github.com/user-attachments/assets/6ccd762c-e8e4-4dfe-88be-e5ed9e55d3b7" /> After: <img width="297" height="141" alt="Screenshot 2026-05-14 at 14 57 57" src="https://github.com/user-attachments/assets/2ba0855a-f055-4b48-b450-a9d16eee98d4" /> ## **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: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] 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). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] 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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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] > **Low Risk** > Low risk UI-only change that standardizes carousel card/skeleton heights; no business logic, data, or security behavior is modified. > > **Overview** > Adjusts the `WhatsHappening` carousel to use a shared Tailwind height class (`h-[230px]`) so real cards, loading skeletons, and the `ViewMoreCard` stay visually aligned. > > Adds an optional `twHeightClassName` prop to `WhatsHappeningCard` and `WhatsHappeningCardSkeleton`, wires it through from `WhatsHappeningSection`, and includes a small unit test for the skeleton component. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a03dda5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 12790c0 commit 4fdbac9

4 files changed

Lines changed: 59 additions & 5 deletions

File tree

app/components/UI/WhatsHappening/WhatsHappeningSection.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { MetaMetricsEvents } from '../../../core/Analytics/MetaMetrics.events';
3737
import { getWhatsHappeningEventProps } from './eventProperties';
3838

3939
const CARD_WIDTH = 280;
40+
const CARD_HEIGHT_CLASS = 'h-[230px]';
4041
const GAP = 12;
4142

4243
const SNAP_OFFSETS = Array.from(
@@ -162,7 +163,12 @@ const WhatsHappeningSection = forwardRef<
162163
testID={WhatsHappeningSelectorsIDs.CAROUSEL}
163164
>
164165
{isLoading ? (
165-
SKELETON_KEYS.map((key) => <WhatsHappeningCardSkeleton key={key} />)
166+
SKELETON_KEYS.map((key) => (
167+
<WhatsHappeningCardSkeleton
168+
key={key}
169+
twHeightClassName={CARD_HEIGHT_CLASS}
170+
/>
171+
))
166172
) : (
167173
<>
168174
{items.map((item: WhatsHappeningItem, index: number) => (
@@ -172,11 +178,12 @@ const WhatsHappeningSection = forwardRef<
172178
cardIndex={index}
173179
source={source}
174180
onPress={() => handleCardPress(index)}
181+
twHeightClassName={CARD_HEIGHT_CLASS}
175182
/>
176183
))}
177184
<ViewMoreCard
178185
onPress={handleViewAll}
179-
twClassName="w-[180px] h-[254px]"
186+
twClassName={`w-[180px] ${CARD_HEIGHT_CLASS}`}
180187
textVariant={TextVariant.BodyLg}
181188
/>
182189
</>

app/components/UI/WhatsHappening/components/WhatsHappeningCard.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ interface WhatsHappeningCardProps {
3232
cardIndex: number;
3333
source: WhatsHappeningSourceValue;
3434
onPress?: (item: WhatsHappeningItem) => void;
35+
/** Tailwind height class so the carousel can keep all cards visually aligned. */
36+
twHeightClassName?: string;
3537
}
3638

3739
const MAX_VISIBLE_ASSET_ICONS = 3;
@@ -41,6 +43,7 @@ const WhatsHappeningCard: React.FC<WhatsHappeningCardProps> = ({
4143
cardIndex,
4244
source,
4345
onPress,
46+
twHeightClassName = '',
4447
}) => {
4548
const tw = useTailwind();
4649
const formattedDate = useMemo(
@@ -90,7 +93,7 @@ const WhatsHappeningCard: React.FC<WhatsHappeningCardProps> = ({
9093
onPress={handlePress}
9194
activeOpacity={0.7}
9295
style={tw.style(
93-
'w-[280px] h-[254px] rounded-2xl bg-background-muted overflow-hidden p-4 justify-between gap-3',
96+
`w-[280px] ${twHeightClassName} rounded-2xl bg-background-muted overflow-hidden p-4 justify-between gap-3`,
9497
)}
9598
>
9699
<Box gap={3}>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react';
2+
import { screen } from '@testing-library/react-native';
3+
import renderWithProvider from '../../../../util/test/renderWithProvider';
4+
import WhatsHappeningCardSkeleton from './WhatsHappeningCardSkeleton';
5+
6+
jest.mock('./whatsHappeningSkeletonShared', () => ({
7+
WhatsHappeningSkeletonShimmer: ({
8+
children,
9+
}: {
10+
children: React.ReactNode;
11+
}) => children,
12+
WhatsHappeningSkeletonLineStack: () => null,
13+
}));
14+
15+
describe('WhatsHappeningCardSkeleton', () => {
16+
it('renders without crashing', () => {
17+
renderWithProvider(<WhatsHappeningCardSkeleton />);
18+
expect(screen.toJSON()).not.toBeNull();
19+
});
20+
21+
it('applies the twHeightClassName when provided', () => {
22+
renderWithProvider(
23+
<WhatsHappeningCardSkeleton twHeightClassName="h-[230px]" />,
24+
);
25+
expect(screen.toJSON()).not.toBeNull();
26+
});
27+
28+
it('renders correctly without twHeightClassName (default empty string)', () => {
29+
const { toJSON: withoutProp } = renderWithProvider(
30+
<WhatsHappeningCardSkeleton />,
31+
);
32+
const { toJSON: withEmptyProp } = renderWithProvider(
33+
<WhatsHappeningCardSkeleton twHeightClassName="" />,
34+
);
35+
expect(withoutProp()).toEqual(withEmptyProp());
36+
});
37+
});

app/components/UI/WhatsHappening/components/WhatsHappeningCardSkeleton.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@ import {
66
WhatsHappeningSkeletonShimmer,
77
} from './whatsHappeningSkeletonShared';
88

9-
const WhatsHappeningCardSkeleton: React.FC = () => {
9+
interface WhatsHappeningCardSkeletonProps {
10+
/** Tailwind height class so skeletons match real cards in the carousel. */
11+
twHeightClassName?: string;
12+
}
13+
14+
const WhatsHappeningCardSkeleton: React.FC<WhatsHappeningCardSkeletonProps> = ({
15+
twHeightClassName = '',
16+
}) => {
1017
const tw = useTailwind();
1118

1219
return (
1320
<View
1421
style={tw.style(
15-
'w-[280px] rounded-2xl bg-background-muted overflow-hidden',
22+
`w-[280px] ${twHeightClassName} rounded-2xl bg-background-muted overflow-hidden`,
1623
)}
1724
>
1825
<WhatsHappeningSkeletonShimmer>

0 commit comments

Comments
 (0)