Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(PC-32910) feat(Achievements): add achievements tracker #7313

Merged
merged 2 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/features/navigation/RootNavigator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ export type RootStackParamList = {
ThematicHeaders: undefined
MarketingBlocks: undefined
MovieCalendar: undefined
Achievements: undefined
Achievements: { from: 'profile' | 'success' }
} & AccessibilityRootStackParamList &
CulturalSurveyRootStackParamList &
TutorialRootStackParamList &
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const BadgeBanner: React.FC = () => {
<InternalTouchableLink
navigateTo={{
screen: 'Achievements',
params: { from: 'profile' },
}}>
<GenericBanner LeftIcon={<BicolorTrophy size={theme.icons.sizes.standard} />}>
<Typo.ButtonText>Mes badges</Typo.ButtonText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const AchievementSuccessModal = ({ visible, hideModal, ids }: Props) => {
<InternalTouchableLink
as={ButtonPrimary}
wording="Accéder à mes succès"
navigateTo={{ screen: 'Achievements' }}
navigateTo={{ screen: 'Achievements', params: { from: 'success' } }}
onBeforeNavigate={() => {
hideModal()
}}
Expand Down
13 changes: 11 additions & 2 deletions src/features/profile/pages/Achievements/Achievements.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, { FC } from 'react'
import { useRoute } from '@react-navigation/native'
import React, { FC, useEffect } from 'react'
import { View } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import { useTheme } from 'styled-components'
import styled from 'styled-components/native'

import { UseRouteType } from 'features/navigation/RootNavigator/types'
import { Badge } from 'features/profile/components/Achievements/Badge'
import {
achievementCategoryDisplayNames,
Expand All @@ -28,12 +30,19 @@ const emptyBadge = {
}

export const Achievements = () => {
const {
params: { from },
} = useRoute<UseRouteType<'Achievements'>>()
const { uniqueColors } = useTheme()
const categories = useAchievements({
const { categories, track } = useAchievements({
achievements: mockAchievements,
completedAchievements: mockCompletedAchievements,
})

useEffect(() => {
track(from)
}, [from, track])

return (
<SecondaryPageWithBlurHeader title="">
<ViewGap gap={4}>
Expand Down
116 changes: 80 additions & 36 deletions src/features/profile/pages/Achievements/useAchievements.native.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
UseAchivementsProps,
useAchievements,
} from 'features/profile/pages/Achievements/useAchievements'
import { analytics } from 'libs/analytics/__mocks__/provider'
import { renderHook } from 'tests/utils'
import { BicolorTrophy, Trophy } from 'ui/svg/icons/Trophy'

Expand Down Expand Up @@ -57,17 +58,17 @@ const testUseAchievements = ({

describe('useAchievements', () => {
it('should return empty array when there are no achievements', () => {
const badges = testUseAchievements()
const { categories } = testUseAchievements()

expect(badges).toEqual([])
expect(categories).toEqual([])
})

it('should return achievements grouped by category', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, testAchievement as unknown as Achievement],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
badges: [
Expand All @@ -88,11 +89,11 @@ describe('useAchievements', () => {
})

it('achievement is NOT completed when user has not already completed it', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
badges: [
Expand All @@ -110,12 +111,12 @@ describe('useAchievements', () => {
})

it('achievement is completed when user has already completed it', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [userCompletedArtLessonBooking, userCompletedBookBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
badges: [
Expand All @@ -133,12 +134,12 @@ describe('useAchievements', () => {
})

it('achievement name is "Badge non débloqué" when achievement is not completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
badges: [
Expand All @@ -156,12 +157,12 @@ describe('useAchievements', () => {
})

it('achievement completed name is the achievement name', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [userCompletedArtLessonBooking, userCompletedBookBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
badges: [
Expand All @@ -179,12 +180,12 @@ describe('useAchievements', () => {
})

it('achivements are sorted by name', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [userCompletedArtLessonBooking, userCompletedBookBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
badges: [
Expand All @@ -200,12 +201,12 @@ describe('useAchievements', () => {
})

it('achievement completed is sorted before achievement not completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstBookBooking, firstArtLessonBooking],
completedAchievements: [userCompletedArtLessonBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
badges: [
Expand All @@ -223,12 +224,12 @@ describe('useAchievements', () => {
describe('Category Achievements completion', () => {
describe('Remaining achievements to complete', () => {
it('should return "0 badge restant" when all achievements of category are completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [userCompletedArtLessonBooking, userCompletedBookBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
remainingAchievementsText: '0 badge restant',
Expand All @@ -237,12 +238,12 @@ describe('useAchievements', () => {
})

it('should return "1 badge restants" when 1 achievement are not completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [userCompletedArtLessonBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
remainingAchievementsText: '1 badge restant',
Expand All @@ -251,11 +252,11 @@ describe('useAchievements', () => {
})

it('should return "2 badges restants" when 2 achievement are not completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
remainingAchievementsText: '2 badges restant',
Expand All @@ -266,12 +267,12 @@ describe('useAchievements', () => {

describe('Achievements progression', () => {
it('should be 1 when all achievements are completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking],
completedAchievements: [userCompletedArtLessonBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
progress: 1,
Expand All @@ -280,11 +281,11 @@ describe('useAchievements', () => {
})

it('should be 0 when no achievements are completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
progress: 0,
Expand All @@ -293,12 +294,12 @@ describe('useAchievements', () => {
})

it('should be 0.5 when 1 achievement of 2 are completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [userCompletedArtLessonBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
progress: 0.5,
Expand All @@ -307,7 +308,7 @@ describe('useAchievements', () => {
})

it('should be 0.75 when 3 achievement of 4 are completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [
firstArtLessonBooking,
firstBookBooking,
Expand All @@ -321,7 +322,7 @@ describe('useAchievements', () => {
],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
progress: 0.75,
Expand All @@ -331,11 +332,11 @@ describe('useAchievements', () => {

describe('text', () => {
it('should return 0/2 when no achievements are completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
progressText: '0/2',
Expand All @@ -344,12 +345,12 @@ describe('useAchievements', () => {
})

it('should return 2/2 when all achievements are completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [userCompletedArtLessonBooking, userCompletedBookBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
progressText: '2/2',
Expand All @@ -358,12 +359,12 @@ describe('useAchievements', () => {
})

it('should return 1/2 when 1 achievement of 2 are completed', () => {
const badges = testUseAchievements({
const { categories } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [userCompletedArtLessonBooking],
})

expect(badges).toEqual([
expect(categories).toEqual([
expect.objectContaining({
id: CombinedAchievementCategory.FIRST_BOOKINGS,
progressText: '1/2',
Expand All @@ -373,4 +374,47 @@ describe('useAchievements', () => {
})
})
})

describe('Tracking', () => {
describe('From', () => {
it.each`
from
${'profile'}
${'success'}
`('send DisplayAchievements event with from $from when track from $from', ({ from }) => {
const { track } = testUseAchievements()

track(from)

expect(analytics.logDisplayAchievements).toHaveBeenCalledWith(
expect.objectContaining({ from })
)
})
})
})

describe('Number unlocked', () => {
it('send 0 when no achievements are completed', () => {
const { track } = testUseAchievements()

track('profile')

expect(analytics.logDisplayAchievements).toHaveBeenCalledWith(
expect.objectContaining({ numberUnlocked: 0 })
)
})

it('send 2 when 2 achievement are completed', () => {
const { track } = testUseAchievements({
achievements: [firstArtLessonBooking, firstBookBooking],
completedAchievements: [userCompletedArtLessonBooking, userCompletedBookBooking],
})

track('profile')

expect(analytics.logDisplayAchievements).toHaveBeenCalledWith(
expect.objectContaining({ numberUnlocked: 2 })
)
})
})
})
Loading