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-32057) feat(ShareAppModal): A/B test design share app modal #7063

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { BicolorIdCardWithMagnifyingGlass } from 'ui/svg/icons/BicolorIdCardWith
import { BicolorPhonePending } from 'ui/svg/icons/BicolorPhonePending'
import { BicolorProfileDeletion } from 'ui/svg/icons/BicolorProfileDeletion'
import { BicolorSadFace } from 'ui/svg/icons/BicolorSadFace'
import { BicolorShareChat } from 'ui/svg/icons/BicolorShareChat'
import { BicolorSharePhones } from 'ui/svg/icons/BicolorSharePhones'
import { BicolorTicketBooked } from 'ui/svg/icons/BicolorTicketBooked'
import { BicolorUserFavorite } from 'ui/svg/icons/BicolorUserFavorite'
import { CalendarIllustration } from 'ui/svg/icons/CalendarIllustration'
Expand Down Expand Up @@ -52,6 +54,8 @@ export const BicolorIllustrations = {
BicolorUserError,
BicolorUserFavorite,
BicolorUserIdentification,
BicolorSharePhones,
BicolorShareChat,
}

export const UniqueColorIllustrations = {
Expand Down
140 changes: 140 additions & 0 deletions src/features/share/api/useShareAppModalViewmodel.native.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import * as shareApp from 'features/share/helpers/shareApp'
import { ShareAppModalType } from 'features/share/types'
import { analytics } from 'libs/analytics/__mocks__/provider'
import { DEFAULT_REMOTE_CONFIG } from 'libs/firebase/remoteConfig/remoteConfig.constants'
import { CustomRemoteConfig } from 'libs/firebase/remoteConfig/remoteConfig.types'
import * as useRemoteConfigContext from 'libs/firebase/remoteConfig/RemoteConfigProvider'
import { renderHook } from 'tests/utils'

import {
ShareAppModalSelectorViewmodelParams,
useShareAppModalViewmodel,
} from './useShareAppModalViewmodel'

const useRemoteConfigContextSpy = jest.spyOn(useRemoteConfigContext, 'useRemoteConfigContext')
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter')

const mockShareApp = jest.spyOn(shareApp, 'shareApp')
mockShareApp.mockImplementation(jest.fn())

const useShareAppModalSelectorViewmodelTest = ({
hideModal = jest.fn(),
type: type = ShareAppModalType.BENEFICIARY,
showModal = jest.fn(),
setType = jest.fn(),
}: Partial<ShareAppModalSelectorViewmodelParams> = {}) => {
const hook = renderHook(() =>
// eslint-disable-next-line react-hooks/rules-of-hooks
useShareAppModalViewmodel({
type,
hideModal,
showModal,
setType,
})
)

return hook.result.current
}

const givenRemoteConfigShareAppModalVersion = (
version: CustomRemoteConfig['shareAppModalVersion']
) => {
useRemoteConfigContextSpy.mockReturnValue({
...DEFAULT_REMOTE_CONFIG,
shareAppModalVersion: version,
})
}

describe('useShareAppModalViewmodel', () => {
describe('version', () => {
test.each`
expectedVersion
${'default'}
${'version_1'}
`('get version $expectedVersion from remote config', async ({ expectedVersion }) => {
givenRemoteConfigShareAppModalVersion(expectedVersion)
const { version } = useShareAppModalSelectorViewmodelTest()

expect(version).toEqual(expectedVersion)
})
})

describe('close', () => {
test('close modal on close', async () => {
const hideModal = jest.fn()

const { close } = useShareAppModalSelectorViewmodelTest({ hideModal })

close()

expect(hideModal).toHaveBeenCalledWith()
})

test.each`
type
${ShareAppModalType.BENEFICIARY}
${ShareAppModalType.NOT_ELIGIBLE}
`('log dismiss share app on close with type $type', async ({ type }) => {
const { close } = useShareAppModalSelectorViewmodelTest({ type })

close()

expect(analytics.logDismissShareApp).toHaveBeenCalledWith(type)
})
})

describe('share', () => {
test('close modal on share', async () => {
const hideModal = jest.fn()

const { share } = useShareAppModalSelectorViewmodelTest({ hideModal })

await share()

expect(hideModal).toHaveBeenCalledWith()
})

test.each`
type
${ShareAppModalType.BENEFICIARY}
${ShareAppModalType.NOT_ELIGIBLE}
`('log share app on share with type $type', async ({ type }) => {
const { share } = useShareAppModalSelectorViewmodelTest({ type })

await share()

expect(analytics.logShareApp).toHaveBeenCalledWith({ type })
})
})

describe('show', () => {
test.each`
type
${ShareAppModalType.BENEFICIARY}
${ShareAppModalType.NOT_ELIGIBLE}
`('show modal on show with type $type', async ({ type }) => {
const showModal = jest.fn()
const setType = jest.fn()
const { show } = useShareAppModalSelectorViewmodelTest({ showModal, setType })

show(type)

expect(setType).toHaveBeenCalledWith(type)
expect(showModal).toHaveBeenCalledWith()
})

test.each`
type
${ShareAppModalType.BENEFICIARY}
${ShareAppModalType.NOT_ELIGIBLE}
`('send analytics on show with $type', ({ type }) => {
const { show } = useShareAppModalSelectorViewmodelTest()

show(type)

expect(analytics.logShowShareAppModal).toHaveBeenCalledWith({
type,
})
})
})
})
49 changes: 49 additions & 0 deletions src/features/share/api/useShareAppModalViewmodel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useCallback } from 'react'

import { shareApp } from 'features/share/helpers/shareApp'
import { ShareAppModalType } from 'features/share/types'
import { analytics } from 'libs/analytics'
import { useRemoteConfigContext } from 'libs/firebase/remoteConfig/RemoteConfigProvider'

export type ShareAppModalSelectorViewmodelParams = {
type: ShareAppModalType
hideModal: () => void
setType: (type: ShareAppModalType) => void
showModal: () => void
}

export const useShareAppModalViewmodel = ({
hideModal,
type,
showModal,
setType,
}: ShareAppModalSelectorViewmodelParams) => {
const { shareAppModalVersion: version } = useRemoteConfigContext()

const close = useCallback(() => {
analytics.logDismissShareApp(type)
hideModal()
}, [hideModal, type])

const share = useCallback(async () => {
analytics.logShareApp({ type: type })
await shareApp(ShareAppModalType.BENEFICIARY ? 'beneficiary_modal' : 'uneligible_modal')
hideModal()
}, [hideModal, type])

const show = useCallback(
(_type: ShareAppModalType) => {
analytics.logShowShareAppModal({ type: _type })
setType(_type)
showModal()
},
[setType, showModal]
)

return {
version,
share,
close,
show,
}
}
25 changes: 25 additions & 0 deletions src/features/share/components/ShareAppModalSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { FC } from 'react'

import { ShareAppModal } from 'features/share/pages/ShareAppModal'
import { ShareAppModalVersionA } from 'features/share/pages/ShareAppModalVersionA'
import { ShareAppModalVersionB } from 'features/share/pages/ShareAppModalVersionB'
import { CustomRemoteConfig } from 'libs/firebase/remoteConfig/remoteConfig.types'

type SelectorProps = {
visible: boolean
close: () => void
share: () => void
version: CustomRemoteConfig['shareAppModalVersion']
}

export const ShareAppModalSelector: FC<SelectorProps> = ({ visible, close, share, version }) => {
if (version === 'A') {
return <ShareAppModalVersionA visible={visible} close={close} share={share} />
}

if (version === 'B') {
return <ShareAppModalVersionB visible={visible} close={close} share={share} />
}

return <ShareAppModal visible={visible} close={close} share={share} />
}
60 changes: 0 additions & 60 deletions src/features/share/context/ShareAppWrapper.native.test.tsx

This file was deleted.

29 changes: 14 additions & 15 deletions src/features/share/context/ShareAppWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { memo, useCallback, useContext, useMemo, useState } from 'react'
import React, { memo, useContext, useMemo, useState } from 'react'

import { ShareAppModal } from 'features/share/pages/ShareAppModal'
import { ShareAppModalType } from 'features/share/types'
import { analytics } from 'libs/analytics'
import { useModal } from 'ui/components/modals/useModal'

import { useShareAppModalViewmodel } from '../api/useShareAppModalViewmodel'
import { ShareAppModalSelector } from '../components/ShareAppModalSelector'

interface ShareAppContextValue {
showShareAppModal: (modalType: ShareAppModalType) => void
}
Expand All @@ -18,29 +19,27 @@ export const ShareAppWrapper = memo(function ShareAppWrapper({
}: {
children: React.JSX.Element
}) {
const { showModal, ...shareAppModalProps } = useModal(false)
const { showModal, visible, hideModal } = useModal(false)
const [modalType, setModalType] = useState(ShareAppModalType.NOT_ELIGIBLE)

const showShareAppModal = useCallback(
(modalType: ShareAppModalType) => {
analytics.logShowShareAppModal({ type: modalType })
setModalType(modalType)
showModal()
},
[showModal]
)
const { close, share, show, version } = useShareAppModalViewmodel({
hideModal,
showModal,
setType: setModalType,
type: modalType,
})

const value = useMemo(
() => ({
showShareAppModal,
showShareAppModal: show,
}),
[showShareAppModal]
[show]
)

return (
<ShareAppContext.Provider value={value}>
{children}
<ShareAppModal modalType={modalType} {...shareAppModalProps} />
<ShareAppModalSelector visible={visible} close={close} share={share} version={version} />
</ShareAppContext.Provider>
)
})
Expand Down
Loading
Loading