From fe8aefe577088aef347328a4e1ab184a05b02f79 Mon Sep 17 00:00:00 2001 From: Graeme Houston Date: Fri, 31 Jan 2025 15:35:54 +0000 Subject: [PATCH 1/5] fix: (BadgeTile) fix issues surrounding specific badge not earned --- .../organisms/BadgeTile/BadgeTile.stories.tsx | 28 +++++++++++++++++++ .../BadgeTile/badge-tile-date-earned.tsx | 26 +++++++++++------ .../BadgeTile/badge-tile-description.tsx | 10 +++++-- .../organisms/BadgeTile/badge-tile-media.tsx | 12 ++++++-- .../organisms/BadgeTile/badge-tile-title.tsx | 12 ++++++-- 5 files changed, 71 insertions(+), 17 deletions(-) diff --git a/lib/components/organisms/BadgeTile/BadgeTile.stories.tsx b/lib/components/organisms/BadgeTile/BadgeTile.stories.tsx index d0905a1..7cf6f24 100644 --- a/lib/components/organisms/BadgeTile/BadgeTile.stories.tsx +++ b/lib/components/organisms/BadgeTile/BadgeTile.stories.tsx @@ -171,3 +171,31 @@ SpecificBadgeAwardedOnce.args = { }, }, }; + +export const SpecificBadgeNotEarnedNoEmpty = Template.bind({}); +SpecificBadgeNotEarnedNoEmpty.args = { + tile: { + id: 'specific-badge-not-earned-no-empty', + type: TileType.Badge, + active: true, + createdAt: '2024-08-06T08:53:24.307Z', + updatedAt: '2024-08-06T08:53:24.307Z', + tileHeight: TileHeight.Full, + priority: 0, + configuration: { + type: BadgeTileType.Specific, + badgeId: '900a2477-95c4-4c42-ae2d-3795e7f0f5f2', + internalName: 'Top Spender', + name: 'Top Spender', + description: 'Spent £100 on 5 Separate transactions', + artworkUrl: 'https://ucarecdn.com/3d3731b2-faec-4779-9cd8-3691631d280c/', + priority: 0, + status: 'ACTIVE', + createdAt: '2024-08-06T08:53:24.307Z', + updatedAt: '2024-08-06T08:53:24.307Z', + awardedDatePrefix: 'Awarded', + badgeNotEarnedMessage: 'Complete 5 top-ups to earn this', + count: 0, + }, + }, +}; diff --git a/lib/components/organisms/BadgeTile/badge-tile-date-earned.tsx b/lib/components/organisms/BadgeTile/badge-tile-date-earned.tsx index 3875a64..3b3914c 100644 --- a/lib/components/organisms/BadgeTile/badge-tile-date-earned.tsx +++ b/lib/components/organisms/BadgeTile/badge-tile-date-earned.tsx @@ -14,10 +14,24 @@ export const BadgeTileDateEarned = (): JSX.Element | null => { const styles = useBadgeTileStyles(); const tile = useTileContext(); const { configuration } = tile as { configuration: BadgeTileConfig }; - const { type, count, awardedDatePrefix, createdAt, badgeNotEarnedMessage } = + const { count, awardedDatePrefix, createdAt, badgeNotEarnedMessage, type } = configuration; const { theme } = useWllSdk(); + // Don't show for Latest type with count=0 + if (type === BadgeTileType.Latest && count === 0) { + return null; + } + + // For Specific type, only show if count > 0 or badgeNotEarnedMessage exists + if ( + type === BadgeTileType.Specific && + count === 0 && + !badgeNotEarnedMessage + ) { + return null; + } + const backgroundColor = getStateColor( theme.alphaDerivedPrimary[20], type, @@ -26,10 +40,6 @@ export const BadgeTileDateEarned = (): JSX.Element | null => { const containerStyle = [styles.dateEarnedContainer, { backgroundColor }]; const textColor = getReadableTextColor(backgroundColor); - if (type === BadgeTileType.Latest && count === 0) { - return null; - } - const displayText = count === 0 ? badgeNotEarnedMessage @@ -40,8 +50,6 @@ export const BadgeTileDateEarned = (): JSX.Element | null => { ? 'Badge not yet earned' : `Badge earned on ${new Date(createdAt).toLocaleDateString()}`; - if (!displayText) return null; - return ( { > diff --git a/lib/components/organisms/BadgeTile/badge-tile-description.tsx b/lib/components/organisms/BadgeTile/badge-tile-description.tsx index 828ae6a..fec996d 100644 --- a/lib/components/organisms/BadgeTile/badge-tile-description.tsx +++ b/lib/components/organisms/BadgeTile/badge-tile-description.tsx @@ -1,15 +1,19 @@ import React from 'react'; import { View } from 'react-native'; -import { BadgeTileConfig } from '../../../types/tile'; +import { BadgeTileConfig, BadgeTileType } from '../../../types/tile'; import { Text } from '../../atoms'; import { useTileContext } from '../../atoms/BaseTile'; export const BadgeTileDescription = (): JSX.Element | null => { const tile = useTileContext(); const { configuration } = tile as { configuration: BadgeTileConfig }; - const { count, description } = configuration; + const { count, description, type } = configuration; - if (count === 0 || !description) return null; + if (!description) return null; + + // For Latest type, hide description when count = 0 + // For Specific type, always show description + if (count === 0 && type !== BadgeTileType.Specific) return null; return ( { const styles = useBadgeTileStyles(); const tile = useTileContext(); const { configuration } = tile as { configuration: BadgeTileConfig }; - const { count, name, emptyBadgeMessage } = configuration; + const { count, name, emptyBadgeMessage, type } = configuration; + + const displayText = + type === BadgeTileType.Specific + ? name + : count === 0 + ? emptyBadgeMessage + : name; - const displayText = count === 0 ? emptyBadgeMessage : name; if (!displayText) return null; return ( From 9f44c8896b8916e5e0952114ec03d88c7705d7e8 Mon Sep 17 00:00:00 2001 From: Graeme Houston Date: Fri, 31 Jan 2025 15:44:40 +0000 Subject: [PATCH 2/5] docs: (BadgeTile) update docs to reflect recnt changes --- docs/components/badge-tile.md | 49 +++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/docs/components/badge-tile.md b/docs/components/badge-tile.md index 6f131dc..7f16922 100644 --- a/docs/components/badge-tile.md +++ b/docs/components/badge-tile.md @@ -1,6 +1,6 @@ # Badge Tile -Displays achievement badges with support for latest earned, specific badges, and multiple achievement states. +Displays achievement badges with support for latest earned and specific badges. > ⚠️ **Important**: This component only supports full height tiles (`tileHeight: 'FULL'`). Half-height tiles are not supported. @@ -13,14 +13,13 @@ const tile = { type: 'BADGE', tileHeight: 'FULL', configuration: { - type: 'SPECIFIC', + type: 'SPECIFIC', // or 'LATEST_EARNED' name: 'Top Spender', description: 'Spent £100 on 5 Separate transactions', artworkUrl: 'https://example.com/badge.png', count: 1, awardedDatePrefix: 'Awarded', - badgeNotEarnedMessage: 'Badge not earned yet', - emptyBadgeMessage: "You haven't earned any badges yet" + badgeNotEarnedMessage: 'Badge not earned yet' // Optional, controls earned/not earned chip visibility } } @@ -37,28 +36,40 @@ function MyComponent() { ## Configuration Object -| Property | Type | Description | -|----------|------|-------------| -| type | 'SPECIFIC' \| 'LATEST_EARNED' | Badge display type | -| name | string | Badge name | -| description | string | Badge description | -| artworkUrl | string | Badge image URL | -| count | number | Times achieved (0 = locked) | -| awardedDatePrefix | string | Text before award date | -| badgeNotEarnedMessage | string | Message for unearned badges | -| emptyBadgeMessage | string | Message when no badges earned | +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| type | 'SPECIFIC' \| 'LATEST_EARNED' | Yes | Badge display type. Use 'SPECIFIC' for a particular badge, 'LATEST_EARNED' for most recent achievement | +| name | string | Yes | Badge name | +| description | string | No | Badge description | +| artworkUrl | string | Yes | Badge image URL | +| count | number | Yes | Times achieved (0 = not earned) | +| awardedDatePrefix | string | No | Text before award date | +| badgeNotEarnedMessage | string | No | Message shown in status chip when badge is not earned. If not provided, no chip will be shown for unearned badges | + +## Display Types + +### SPECIFIC +- Shows a particular badge regardless of earned state +- Always shows description if provided +- Shows earned/not earned chip if badgeNotEarnedMessage is provided + +### LATEST_EARNED +- Used to display the most recent achievement +- Hides description when not earned (count = 0) +- Shows earned/not earned chip if badgeNotEarnedMessage is provided ## States -- **Not Earned**: Shows lock icon (count: 0) +- **Not Earned**: Shows badge with count: 0 + - If `badgeNotEarnedMessage` is provided, shows status chip with that message + - For LATEST_EARNED type, hides description - **Earned Once**: Shows badge with award date - **Multiple Earned**: Shows badge with count (e.g., "3x") -- **Latest Badge**: Special display for most recent achievement ## Composition - `BadgeTile.Media` - Badge artwork container - `BadgeTile.Status` - Lock icon or achievement count -- `BadgeTile.Title` - Badge name or empty state message -- `BadgeTile.Description` - Badge description -- `BadgeTile.DateEarned` - Award date or status message \ No newline at end of file +- `BadgeTile.Title` - Badge name +- `BadgeTile.Description` - Badge description (hidden for unearned LATEST_EARNED badges) +- `BadgeTile.DateEarned` - Award date or not earned message (if provided) \ No newline at end of file From 61e0ce7e88b4fb49da63042eaf60eb2695456406 Mon Sep 17 00:00:00 2001 From: Graeme Houston Date: Fri, 31 Jan 2025 15:50:25 +0000 Subject: [PATCH 3/5] test: update snapshots --- lib/components/molecules/Grid/__snapshots__/Grid.spec.tsx.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/molecules/Grid/__snapshots__/Grid.spec.tsx.snap b/lib/components/molecules/Grid/__snapshots__/Grid.spec.tsx.snap index 83c19dd..90c9e7d 100644 --- a/lib/components/molecules/Grid/__snapshots__/Grid.spec.tsx.snap +++ b/lib/components/molecules/Grid/__snapshots__/Grid.spec.tsx.snap @@ -87,7 +87,7 @@ exports[` matches snapshot 1`] = ` style="background-color: rgba(57, 46, 215, 0.2);" >
From 725118592e2f03b063d1d629b39c39d5cea62a38 Mon Sep 17 00:00:00 2001 From: Graeme Houston Date: Fri, 31 Jan 2025 15:57:36 +0000 Subject: [PATCH 4/5] test: (BadgeTile) update test cases --- .../organisms/BadgeTile/BadgeTile.spec.tsx | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/lib/components/organisms/BadgeTile/BadgeTile.spec.tsx b/lib/components/organisms/BadgeTile/BadgeTile.spec.tsx index 1d55a27..c86c520 100644 --- a/lib/components/organisms/BadgeTile/BadgeTile.spec.tsx +++ b/lib/components/organisms/BadgeTile/BadgeTile.spec.tsx @@ -96,11 +96,39 @@ describe('', () => { }, }; render(); + expect( + screen.getByText(specificBadge.configuration.name) + ).toBeInTheDocument(); + expect( + screen.getByText(specificBadge.configuration.description) + ).toBeInTheDocument(); expect( screen.getByText(specificBadge.configuration.badgeNotEarnedMessage) ).toBeInTheDocument(); }); + it('does not show earned/not earned chip when badgeNotEarnedMessage is not provided', () => { + const specificBadge = { + ...BadgeTileMock, + configuration: { + ...BadgeTileMock.configuration, + type: BadgeTileType.Specific, + count: 0, + badgeNotEarnedMessage: undefined, + }, + }; + render(); + expect( + screen.getByText(specificBadge.configuration.name) + ).toBeInTheDocument(); + expect( + screen.getByText(specificBadge.configuration.description) + ).toBeInTheDocument(); + expect( + screen.queryByTestId('badge-tile-date-earned') + ).not.toBeInTheDocument(); + }); + it('renders specific badge type correctly when earned once', () => { const specificBadge = { ...BadgeTileMock, @@ -157,25 +185,30 @@ describe('', () => { describe('Badge Media', () => { it('renders badge artwork when provided', () => { render(); - expect(screen.getByTestId('badge-tile-media')).toBeInTheDocument(); + const media = screen.getByTestId('badge-tile-media'); + expect(media).toBeInTheDocument(); + const progressiveImage = media.querySelector('[src]'); + expect(progressiveImage).toHaveAttribute( + 'src', + BadgeTileMock.configuration.artworkUrl + ); }); - it('renders empty badge artwork when no badges earned', () => { - const emptyBadge = { + it('always uses main artworkUrl regardless of earned state', () => { + const unearned = { ...BadgeTileMock, configuration: { ...BadgeTileMock.configuration, count: 0, }, }; - render(); + render(); const media = screen.getByTestId('badge-tile-media'); expect(media).toBeInTheDocument(); - const progressiveImage = media.querySelector('[src]'); expect(progressiveImage).toHaveAttribute( 'src', - emptyBadge.configuration.emptyBadgeArtworkUrl + unearned.configuration.artworkUrl ); }); }); From 2d73d8ca486eeba5710dc8aad0a1ddf77f8ed771 Mon Sep 17 00:00:00 2001 From: Graeme Houston Date: Fri, 31 Jan 2025 16:55:58 +0000 Subject: [PATCH 5/5] fix: make Latest badge description visibility explicit --- lib/components/organisms/BadgeTile/badge-tile-description.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/organisms/BadgeTile/badge-tile-description.tsx b/lib/components/organisms/BadgeTile/badge-tile-description.tsx index fec996d..8480143 100644 --- a/lib/components/organisms/BadgeTile/badge-tile-description.tsx +++ b/lib/components/organisms/BadgeTile/badge-tile-description.tsx @@ -13,7 +13,7 @@ export const BadgeTileDescription = (): JSX.Element | null => { // For Latest type, hide description when count = 0 // For Specific type, always show description - if (count === 0 && type !== BadgeTileType.Specific) return null; + if (count === 0 && type === BadgeTileType.Latest) return null; return (