Skip to content

Commit

Permalink
feat(points): Implement empty state for points history bottom sheet (#…
Browse files Browse the repository at this point in the history
…5361)

### Description

Implements the empty state for the points history bottom sheet. See
designs
[here](https://www.figma.com/file/rXBDplfMHHqYmuu6EkgMEo/Gamification-experiments?type=design&node-id=1486-5899&mode=design&t=gVtyIzOM0LmxJaDy-4).

### Test plan

Units and manual tested. See video below



https://github.com/valora-inc/wallet/assets/569401/b9ed634a-4784-4c6a-a7db-fdbeaf9eb395



### Related issues

- Fixes #[issue number here]

### Backwards compatibility

Yes

### Network scalability

If a new NetworkId and/or Network are added in the future, the changes
in this PR will:

- [x] Continue to work without code changes, OR trigger a compilation
error (guaranteeing we find it when a new network is added)
  • Loading branch information
jophish committed Apr 30, 2024
1 parent e72fc01 commit 15e0dbf
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 9 deletions.
5 changes: 5 additions & 0 deletions locales/base/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2273,6 +2273,11 @@
"title": "Unable to load points activity",
"subtitle": "Oops, something went wrong when trying to load your points activity feed. Please try again.",
"tryAgain": "Try again"
},
"empty": {
"title": "No points activity yet",
"subtitle": "It looks like you haven't earned any points yet. Use {{appName}} to start earning points!",
"gotIt": "Got it"
}
},
"loading": {
Expand Down
1 change: 1 addition & 0 deletions src/analytics/Events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -672,4 +672,5 @@ export enum PointsEvents {
points_screen_activity_press = 'points_screen_activity_press',
points_screen_activity_try_again_press = 'points_screen_activity_try_again_press',
points_screen_activity_fetch_more = 'points_screen_activity_fetch_more',
points_screen_activity_learn_more_press = 'points_screen_activity_learn_more_press',
}
1 change: 1 addition & 0 deletions src/analytics/Properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1563,6 +1563,7 @@ interface PointsEventsProperties {
[PointsEvents.points_screen_activity_press]: undefined
[PointsEvents.points_screen_activity_try_again_press]: undefined
[PointsEvents.points_screen_activity_fetch_more]: undefined
[PointsEvents.points_screen_activity_learn_more_press]: undefined
}

export type AnalyticsPropertiesList = AppEventsProperties &
Expand Down
1 change: 1 addition & 0 deletions src/analytics/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ export const eventDocs: Record<AnalyticsEventType, string> = {
[PointsEvents.points_screen_activity_press]: `when the Activity button is pressed from Points home screen`,
[PointsEvents.points_screen_activity_try_again_press]: `when the Try Again button is pressed after an error while fetching Points activity`,
[PointsEvents.points_screen_activity_fetch_more]: `when the user requests to fetch more Points history`,
[PointsEvents.points_screen_activity_learn_more_press]: `when the Learn button is pressed when a user has no points history`,

// Events related to WalletConnect pairing (technical: opening up the communication channel via QR code or deeplink)
[WalletConnectEvents.wc_pairing_start]: `when WC pairing is started (no UI at this point)`,
Expand Down
15 changes: 15 additions & 0 deletions src/points/PointsHistoryBottomSheet.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,19 @@ describe(PointsHistoryBottomSheet, () => {
)
expect(dispatch).toHaveBeenCalledWith(getHistoryStarted({ getNextPage: false }))
})

it('shows empty screen if no info after fetch', async () => {
const tree = renderScreen({ points: { getHistoryStatus: 'idle', pointsHistory: [] } })
expect(tree.getByTestId('PointsHistoryBottomSheet/Empty')).toBeTruthy()
})

it('closes bottom sheet if got it is pressed', async () => {
const { getByText } = renderScreen({ points: { getHistoryStatus: 'idle', pointsHistory: [] } })
fireEvent.press(getByText('points.history.empty.gotIt'))
await waitFor(() =>
expect(ValoraAnalytics.track).toHaveBeenCalledWith(
PointsEvents.points_screen_activity_learn_more_press
)
)
})
})
40 changes: 31 additions & 9 deletions src/points/PointsHistoryBottomSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ function PointsHistoryBottomSheet({ forwardedRef }: Props) {
)
}

const onPressLearnMore = () => {
ValoraAnalytics.track(PointsEvents.points_screen_activity_learn_more_press)
forwardedRef.current?.close()
}

const Loading =
pointsHistoryStatus === 'loading' ? (
<ActivityIndicator
Expand All @@ -99,7 +104,7 @@ function PointsHistoryBottomSheet({ forwardedRef }: Props) {

const EmptyOrError =
pointsHistoryStatus === 'error' ? (
<View testID={'PointsHistoryBottomSheet/Error'} style={styles.errorContainer}>
<View testID={'PointsHistoryBottomSheet/Error'} style={styles.emptyContainer}>
<View style={styles.messageContainer}>
<Attention size={48} color={Colors.black} />
<Text style={styles.messageTitle}>{t('points.history.error.title')}</Text>
Expand All @@ -115,8 +120,23 @@ function PointsHistoryBottomSheet({ forwardedRef }: Props) {
/>
</View>
) : (
<View testID={'PointsHistoryBottomSheet/Empty'}></View>
) // TODO: Render empty/no history state
<View testID={'PointsHistoryBottomSheet/Empty'} style={styles.emptyContainer}>
<View style={styles.messageContainer}>
<Text style={styles.messageTitle}>{t('points.history.empty.title')}</Text>
<Text style={styles.messageSubtitle}>{t('points.history.empty.subtitle')}</Text>
</View>
<Button
testID={'PointsHistoryBottomSheet/GotIt'}
onPress={onPressLearnMore}
text={t('points.history.empty.gotIt')}
type={BtnTypes.GRAY_WITH_BORDER}
size={BtnSizes.FULL}
style={{ width: '100%' }}
/>
</View>
)

const isEmpty = pointsHistoryStatus !== 'loading' && !pointsHistory.length

// TODO: Figure out what to render when error occurs on subsequent page fetch

Expand All @@ -126,11 +146,12 @@ function PointsHistoryBottomSheet({ forwardedRef }: Props) {

return (
<BottomSheetBase snapPoints={['80%']} forwardedRef={forwardedRef}>
{pointsHistoryStatus !== 'error' && (
<Text style={styles.contentHeader}>{t('points.history.title')}</Text>
)}
{!isEmpty && <Text style={styles.contentHeader}>{t('points.history.title')}</Text>}
<BottomSheetSectionList
contentContainerStyle={{ paddingBottom: Math.max(insets.bottom, Spacing.Thick24) }}
contentContainerStyle={{
paddingBottom: Math.max(insets.bottom, Spacing.Thick24),
flex: isEmpty ? 1 : 0,
}}
renderItem={renderItem}
renderSectionHeader={(item) => (
<SectionHead text={item.section.title} style={styles.sectionHead} />
Expand All @@ -141,16 +162,17 @@ function PointsHistoryBottomSheet({ forwardedRef }: Props) {
testID="PointsHistoryList"
onEndReached={onFetchMoreHistory}
ListFooterComponent={Loading}
ListEmptyComponent={EmptyOrError}
ListEmptyComponent={isEmpty ? EmptyOrError : null}
onEndReachedThreshold={0.5}
/>
</BottomSheetBase>
)
}

const styles = StyleSheet.create({
errorContainer: {
emptyContainer: {
flex: 1,
padding: Spacing.Thick24,
},
messageContainer: {
flex: 1,
Expand Down

0 comments on commit 15e0dbf

Please sign in to comment.