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

feat: make tour provider tour steps dynamic #1428

Merged
Show file tree
Hide file tree
Changes from 7 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
14 changes: 2 additions & 12 deletions packages/legacy/core/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ import { animatedComponents } from './animated-components'
import ErrorModal from './components/modals/ErrorModal'
import NetInfo from './components/network/NetInfo'
import toastConfig from './components/toast/ToastConfig'
import { credentialOfferTourSteps } from './components/tour/CredentialOfferTourSteps'
import { credentialsTourSteps } from './components/tour/CredentialsTourSteps'
import { homeTourSteps } from './components/tour/HomeTourSteps'
import { proofRequestTourSteps } from './components/tour/ProofRequestTourSteps'
import { Container, ContainerProvider } from './container-api'
import { ActivityProvider } from './contexts/activity'
import { AnimatedComponentsProvider } from './contexts/animated-components'
Expand All @@ -25,6 +21,7 @@ import { initLanguages, initStoredLanguage, translationResources } from './local
import RootStack from './navigators/RootStack'
import { theme } from './theme'
import { OpenIDCredentialRecordProvider } from './modules/openid/context/OpenIDCredentialRecordProvider'
import { tours } from './constants'

const App = (system: Container): React.FC => {
initLanguages(translationResources)
Expand Down Expand Up @@ -58,14 +55,7 @@ const App = (system: Container): React.FC => {
/>
<NetInfo />
<ErrorModal />
<TourProvider
homeTourSteps={homeTourSteps}
credentialsTourSteps={credentialsTourSteps}
credentialOfferTourSteps={credentialOfferTourSteps}
proofRequestTourSteps={proofRequestTourSteps}
overlayColor={'gray'}
overlayOpacity={0.7}
>
<TourProvider tours={tours} overlayColor={'gray'} overlayOpacity={0.7}>
<RootStack />
</TourProvider>
<Toast topOffset={15} config={toastConfig} />
Expand Down
19 changes: 19 additions & 0 deletions packages/legacy/core/App/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { Tours } from 'contexts/tour/tour-context'
import { PINValidationRules } from './types/security'
import { homeTourSteps } from './components/tour/HomeTourSteps'
import { credentialsTourSteps } from './components/tour/CredentialsTourSteps'
import { credentialOfferTourSteps } from './components/tour/CredentialOfferTourSteps'
import { proofRequestTourSteps } from './components/tour/ProofRequestTourSteps'

const lengthOfHiddenAttributes = 10
const unicodeForBulletCharacter = '\u2022'
Expand Down Expand Up @@ -63,6 +68,20 @@ export const attemptLockoutThresholdRules = {

export const defaultAutoLockTime = 5

export const tours: Tours = {
homeTourSteps,
credentialsTourSteps,
credentialOfferTourSteps,
proofRequestTourSteps,
}

export const TourIDKeys = {
homeTourSteps: 'homeTourSteps',
credentialsTourSteps: 'credentialsTourSteps',
credentialOfferTourSteps: 'credentialOfferTourSteps',
proofRequestTourSteps: 'proofRequestTourSteps',
} as const

export const walletId = 'walletId'

export const minPINLength = 6
Expand Down
28 changes: 9 additions & 19 deletions packages/legacy/core/App/contexts/tour/tour-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { createContext, ReactElement, useContext } from 'react'
import { LayoutRectangle } from 'react-native'

import { TourID } from '../../types/tour'
import { TourIDKeys } from '../../constants'

export type Tours = {
[key: TourID]: TourStep[]
}

export interface RenderProps {
/**
Expand Down Expand Up @@ -112,21 +117,9 @@ export interface TourCtx extends Tour {
*/
spot: LayoutRectangle
/**
* The list of steps for the home tour.
*/
homeTourSteps: TourStep[]
/**
* Same as above for the credential list screen
*/
credentialsTourSteps: TourStep[]
/**
* Same as above for the credential offer screen
*/
credentialOfferTourSteps: TourStep[]
/**
* Same as above for the proof request screen
* A dictionnary where the key is...
*/
proofRequestTourSteps: TourStep[]
tours: Tours
}

export const ORIGIN_SPOT: LayoutRectangle = {
Expand All @@ -137,17 +130,14 @@ export const ORIGIN_SPOT: LayoutRectangle = {
}

export const TourContext = createContext<TourCtx>({
currentTour: TourID.HomeTour,
currentTour: TourIDKeys.homeTourSteps,
currentStep: undefined,
changeSpot: () => undefined,
next: () => undefined,
previous: () => undefined,
spot: ORIGIN_SPOT,
start: () => undefined,
homeTourSteps: [],
credentialsTourSteps: [],
credentialOfferTourSteps: [],
proofRequestTourSteps: [],
tours: {},
stop: () => undefined,
})

Expand Down
102 changes: 23 additions & 79 deletions packages/legacy/core/App/contexts/tour/tour-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,17 @@ import { TourOverlay } from '../../components/tour/TourOverlay'
import { ChildFn, TourID } from '../../types/tour'
import { isChildFunction } from '../../utils/helpers'

import { BackdropPressBehavior, OSConfig, Tour, TourContext, TourCtx, TourStep, ORIGIN_SPOT } from './tour-context'
import {
BackdropPressBehavior,
OSConfig,
Tour,
TourContext,
TourCtx,
TourStep,
ORIGIN_SPOT,
Tours,
} from './tour-context'
import { TourIDKeys } from '../../constants'

export interface TourProviderProps {
children: React.ReactNode | ChildFn<Tour>
Expand Down Expand Up @@ -45,19 +55,7 @@ export interface TourProviderProps {
/**
* The list of steps for the home tour.
*/
homeTourSteps: TourStep[]
/**
* Same as above for the credential list screen
*/
credentialsTourSteps: TourStep[]
/**
* Same as above for the credential offer screen
*/
credentialOfferTourSteps: TourStep[]
/**
* Same as above for the proof request screen
*/
proofRequestTourSteps: TourStep[]
tours: Tours
}

const TourProviderComponent = (props: TourProviderProps, ref: Ref<Tour>) => {
Expand All @@ -66,29 +64,21 @@ const TourProviderComponent = (props: TourProviderProps, ref: Ref<Tour>) => {
onBackdropPress,
overlayColor = 'black',
overlayOpacity = 0.45,
homeTourSteps,
credentialsTourSteps,
credentialOfferTourSteps,
proofRequestTourSteps,
tours,
nativeDriver = false,
} = props

const [currentTour, setCurrentTour] = useState<TourID>(TourID.HomeTour)
const [currentTour, setCurrentTour] = useState<TourID>(TourIDKeys.homeTourSteps)
const [currentStep, setCurrentStep] = useState<number>()
const [spot, setSpot] = useState(ORIGIN_SPOT)

const renderStep = useCallback(
(index: number): void | Promise<void> => {
if (
(currentTour === TourID.HomeTour && homeTourSteps[index] !== undefined) ||
(currentTour === TourID.CredentialsTour && credentialsTourSteps[index] !== undefined) ||
(currentTour === TourID.CredentialOfferTour && credentialOfferTourSteps[index] !== undefined) ||
(currentTour === TourID.ProofRequestTour && proofRequestTourSteps[index] !== undefined)
) {
if (tours[currentTour]?.[index] !== undefined) {
setCurrentStep(index)
}
},
[currentTour, homeTourSteps, credentialsTourSteps, credentialOfferTourSteps, proofRequestTourSteps]
[currentTour, tours]
)

const changeSpot = useCallback((newSpot: LayoutRectangle): void => {
Expand All @@ -109,50 +99,20 @@ const TourProviderComponent = (props: TourProviderProps, ref: Ref<Tour>) => {
}, [])

const next = useCallback((): void => {
let steps = homeTourSteps
if (currentTour === TourID.CredentialsTour) {
steps = credentialsTourSteps
} else if (currentTour === TourID.CredentialOfferTour) {
steps = credentialOfferTourSteps
} else if (currentTour === TourID.ProofRequestTour) {
steps = proofRequestTourSteps
if (currentTour && currentStep !== undefined && tours[currentTour]) {
currentStep === tours[currentTour].length - 1 ? stop() : renderStep(currentStep + 1)
}
}, [stop, renderStep, currentStep, currentTour, tours])

if (currentStep !== undefined) {
currentStep === steps.length - 1 ? stop() : renderStep(currentStep + 1)
}
}, [
stop,
renderStep,
currentStep,
currentTour,
homeTourSteps,
credentialsTourSteps,
credentialOfferTourSteps,
proofRequestTourSteps,
])

// works the same regardless of which tour is on
const previous = useCallback((): void => {
if (currentStep !== undefined && currentStep > 0) {
renderStep(currentStep - 1)
}
}, [renderStep, currentStep])

const tourStep = useMemo((): TourStep => {
let stepToRender = undefined
let steps = homeTourSteps
if (currentTour === TourID.CredentialsTour) {
steps = credentialsTourSteps
} else if (currentTour === TourID.CredentialOfferTour) {
steps = credentialOfferTourSteps
} else if (currentTour === TourID.ProofRequestTour) {
steps = proofRequestTourSteps
}

stepToRender = currentStep !== undefined ? steps[currentStep] : undefined
return stepToRender ?? { Render: () => <></> }
}, [homeTourSteps, currentTour, credentialsTourSteps, credentialOfferTourSteps, proofRequestTourSteps, currentStep])
return tours[currentTour]?.[currentStep ?? 0] ?? { Render: () => <></> }
}, [currentTour, currentStep, tours])

const tour = useMemo(
(): TourCtx => ({
Expand All @@ -164,25 +124,9 @@ const TourProviderComponent = (props: TourProviderProps, ref: Ref<Tour>) => {
spot,
start,
stop,
homeTourSteps,
credentialsTourSteps,
credentialOfferTourSteps,
proofRequestTourSteps,
tours,
}),
[
changeSpot,
currentTour,
currentStep,
next,
previous,
spot,
start,
stop,
homeTourSteps,
credentialsTourSteps,
credentialOfferTourSteps,
proofRequestTourSteps,
]
[changeSpot, currentTour, currentStep, next, previous, spot, start, stop, tours]
)

useImperativeHandle(ref, () => ({
Expand Down
12 changes: 10 additions & 2 deletions packages/legacy/core/App/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import * as types from './types'
import Scan from './screens/Scan'
import Onboarding from './screens/Onboarding'
import { DefaultScreenOptionsDictionary, useDefaultStackOptions } from './navigators/defaultStackOptions'
import { PINRules, walletTimeout } from './constants'
import { PINRules, walletTimeout, tours, TourIDKeys } from './constants'
import { CredentialListFooterProps } from './types/credential-list-footer'
import { OpenIDCredentialRecordProvider } from './modules/openid/context/OpenIDCredentialRecordProvider'
import { defaultConfig, defaultHistoryEventsLogger } from './container-impl'
Expand Down Expand Up @@ -83,7 +83,13 @@ export { BifoldError } from './types/error'
export { EventTypes } from './constants'
export { migrateToAskar } from './utils/migration'
export { createLinkSecretIfRequired, getAgentModules } from './utils/agent'
export { removeExistingInvitationIfRequired, connectFromScanOrDeepLink, formatTime, useCredentialConnectionLabel, getConnectionName } from './utils/helpers'
export {
removeExistingInvitationIfRequired,
connectFromScanOrDeepLink,
formatTime,
useCredentialConnectionLabel,
getConnectionName,
} from './utils/helpers'
export { isValidAnonCredsCredential, getCredentialIdentifiers } from './utils/credential'
export { buildFieldsFromAnonCredsCredential } from './utils/oca'

Expand Down Expand Up @@ -195,6 +201,8 @@ export {
BulletPoint,
PINRules,
walletTimeout,
tours,
TourIDKeys,
DefaultScreenOptionsDictionary,
DefaultScreenLayoutOptions,
}
Expand Down
11 changes: 5 additions & 6 deletions packages/legacy/core/App/navigators/TabStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ import { SafeAreaView } from 'react-native-safe-area-context'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'

import { AttachTourStep } from '../components/tour/AttachTourStep'
import { EventTypes } from '../constants'
import { EventTypes, TourIDKeys } from '../constants'
import { TOKENS, useServices } from '../container-api'
import { useNetwork } from '../contexts/network'
import { DispatchAction } from '../contexts/reducers/store'
import { useStore } from '../contexts/store'
import { useTheme } from '../contexts/theme'
import { BifoldError } from '../types/error'
import { Screens, Stacks, TabStackParams, TabStacks } from '../types/navigators'
import { TourID } from '../types/tour'
import { connectFromScanOrDeepLink } from '../utils/helpers'
import { testIdWithKey } from '../utils/testable'

Expand Down Expand Up @@ -128,7 +127,7 @@ const TabStack: React.FC = () => {
options={{
tabBarIconStyle: styles.tabBarIcon,
tabBarIcon: ({ color, focused }) => (
<AttachTourStep tourID={TourID.HomeTour} index={1}>
<AttachTourStep tourID={TourIDKeys.homeTourSteps} index={1}>
<View style={{ ...TabTheme.tabBarContainerStyle, justifyContent: showLabels ? 'flex-end' : 'center' }}>
<Icon name={focused ? 'message-text' : 'message-text-outline'} color={color} size={30} />

Expand Down Expand Up @@ -168,7 +167,7 @@ const TabStack: React.FC = () => {
width: 90,
}}
>
<AttachTourStep tourID={TourID.HomeTour} index={0} fill>
<AttachTourStep tourID={TourIDKeys.homeTourSteps} index={0} fill>
<View
style={{
position: 'absolute',
Expand All @@ -179,7 +178,7 @@ const TabStack: React.FC = () => {
margin: 'auto',
}}
>
<AttachTourStep tourID={TourID.CredentialsTour} index={0} fill>
<AttachTourStep tourID={TourIDKeys.homeTourSteps} index={0} fill>
<View
style={{
flexGrow: 1,
Expand Down Expand Up @@ -238,7 +237,7 @@ const TabStack: React.FC = () => {
options={{
tabBarIconStyle: styles.tabBarIcon,
tabBarIcon: ({ color, focused }) => (
<AttachTourStep tourID={TourID.HomeTour} index={2}>
<AttachTourStep tourID={TourIDKeys.homeTourSteps} index={2}>
<View style={{ ...TabTheme.tabBarContainerStyle, justifyContent: showLabels ? 'flex-end' : 'center' }}>
<Icon name={focused ? 'wallet' : 'wallet-outline'} color={color} size={30} />
{showLabels && (
Expand Down
Loading