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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

fc-santos
Copy link
Contributor

@fc-santos fc-santos commented Feb 4, 2025

Summary of Changes

This PR makes the tour steps more dynamic. The base tours still exist (homeTourSteps, credentialsTourSteps, etc), but a wallet will be able to add other tours if needed it.

Breaking change: The TourProvider will accept a tours prop instead of the homeTourSteps, credentialsTourSteps.

Here is the type definition of Tours:

type TourID = `${string}TourSteps` 

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

/* 
const tours: Tours = {
   homeTourSteps: myWalletHomeTourSteps,
  credentialsTourSteps: myWalletCredentialsTourSteps,
  ....,
  // Let's say a wallet has another screen where they want an app tour
  someScreenTourSteps: myWalletScreenTourSteps
}
*/

Screenshots, videos, or gifs

N/A

Breaking change guide

The Tour Provider will be defined as following in App.tsx:

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 tours: Tours = {
  homeTourSteps,
  credentialsTourSteps,
  credentialOfferTourSteps,
  proofRequestTourSteps
}

<TourProvider tours={tours} overlayColor={'gray'} overlayOpacity={0.7}>
      <RootStack />
</TourProvider>

And to use the AttachTourStep component:

Example in TabStack.tsx
<AttachTourStep tourID={TourIDKeys.homeTourSteps} index={1}></AttachTourStep>

Related Issues

Replace this text with issue #'s that are relevant to this PR. If there are none, simply enter N/A

Pull Request Checklist

Tick all boxes below to demonstrate that you have completed the respective task. If the item does not apply to your this PR check it anyway to make it apparent that there's nothing to do.

  • All commits contain a DCO Signed-off-by line (we use the DCO GitHub app to enforce this)
  • If applicable, screenshots, gifs, or video are included for UI changes
  • If applicable, breaking changes are described above along with how to address them
  • Updated documentation as needed for changed code and new or modified features
  • Added sufficient tests so that overall code coverage is not reduced

If you have any questions to any of the points above, just submit and ask! This checklist is here to help you, not to deter you from contributing!

Pro Tip 🤓

  • Read our contribution guide at least once; it will save you a few review cycles!
  • Your PR will likely not be reviewed until all the above boxes are checked and all automated checks have passed

@fc-santos fc-santos requested a review from a team as a code owner February 4, 2025 21:08
@fc-santos
Copy link
Contributor Author

@bryce-mcmath, I see you're the person who worked in the TourProvider implementation. If you could take a lot at this, it'd be greatly appreciated. To explain a little bit more why I have done this, in Quebec, we have other screens where we would like to have the tour guide, but the current implementation won't allow this. This PR will allows us to add a guided tour for the Activities screen and the More screen here:

image

Signed-off-by: fc-santos <[email protected]>
@bryce-mcmath
Copy link
Contributor

@bryce-mcmath, I see you're the person who worked in the TourProvider implementation. If you could take a lot at this, it'd be greatly appreciated. To explain a little bit more why I have done this, in Quebec, we have other screens where we would like to have the tour guide, but the current implementation won't allow this. This PR will allows us to add a guided tour for the Activities screen and the More screen

@fc-santos I'm still reading through it, but so far I love it, nice work! It's much more extensible this way (and I'm glad someone was able to understand the code for this feature.)

This is a small thing, but could we follow the SonarCloud optional chaining suggestion? The other two SonarCloud issues are fine as is, but the optional chaining one is a good and easy change I think.

Copy link
Contributor

@bryce-mcmath bryce-mcmath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly small things related to constants. There are some great improvements here though, good work so far

packages/legacy/core/App/constants.ts Outdated Show resolved Hide resolved
@@ -137,17 +132,14 @@ export const ORIGIN_SPOT: LayoutRectangle = {
}

export const TourContext = createContext<TourCtx>({
currentTour: TourID.HomeTour,
currentTour: 'homeTourSteps',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use constants for these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

nativeDriver = false,
} = props

const [currentTour, setCurrentTour] = useState<TourID>(TourID.HomeTour)
const [currentTour, setCurrentTour] = useState<TourID>('homeTourSteps')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

(currentTour === TourID.CredentialOfferTour && credentialOfferTourSteps[index] !== undefined) ||
(currentTour === TourID.ProofRequestTour && proofRequestTourSteps[index] !== undefined)
) {
if (currentTour && tours[currentTour] && tours[currentTour][index] !== undefined) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice simplification! We could also add the suggested optional chaining here too to clean it up even further

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

Comment on lines 113 to 117
if (currentTour && currentStep !== undefined && tours[currentTour]) {
return tours[currentTour][currentStep] ?? { Render: () => <></> }
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think with this refactoring we could simplify it further to just one conditional and won't need both returns (won't need two { Render: () => ... })

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@@ -203,7 +202,7 @@ const ProofRequest: React.FC<ProofRequestProps> = ({ navigation, proofId }) => {
const shouldShowTour = enableToursConfig && store.tours.enableTours && !store.tours.seenProofRequestTour

if (shouldShowTour && screenIsFocused) {
start(TourID.ProofRequestTour)
start('proofRequestTourSteps')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"

CredentialOfferTour,
ProofRequestTour,
}
export type TourID = `${string}TourSteps`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this an extensible type so that we can use it for constants throughout Bifold as well as extensions (like the Quebec or BC apps?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean by making an extensible type. Could you please explain ? Thanks!

P.S: All other comments should have been resolved, if you can review it again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking something like this:

// in Bifold
export enum BifoldTourIds {
    HomeTour = "homeTourSteps",
    ProofRequestTour = "proofRequestTourSteps"
    ...
}
// in Quebec Wallet
enum QuebecTourIds {
    QuebecSpecificATour = "quebecSpecificATourSteps",
    QuebecSpecificBTour = "quebecSpecificBTourSteps"
    ...
}

// in Quebec Wallet
type TourIds = BifoldTourIds | QuebecTourIds

// in Quebec Wallet when you want to start a tour for a screen that's unique to Quebec
start(TourIds.QuebecTourA)

// in Quebec Wallet when you want to start a tour for a Bifold screen that Quebec is injecting their own custom version
start(TourIds.HomeTour)

And we could then use those TourIds where you are using TourIDKeys now (I'm not picky about the naming as long as it's clear. Whether we use as const or enum doesn't really matter to me either but we should export some kind of BifoldTourIds that we can extend so we can use that constant / enum everywhere in both Bifold and Quebec Wallet (or any other Bifold based wallet.) No plain strings like tourID={'homeTourSteps'}

>
<AttachTourStep index={0} tourID={TourID.HomeTour}>
<TourProvider tours={tours} overlayColor={'gray'} overlayOpacity={0.7}>
<AttachTourStep index={0} tourID={'homeTourSteps'}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use constant as mentioned above

<TourBox
title={'Title'}
leftText={'Left'}
rightText={'Right'}
onLeft={previous}
onRight={next}
currentTour={TourID.HomeTour}
currentTour={'homeTourSteps'}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"

<TourOverlay
color={'grey'}
currentStep={0}
currentTour={TourID.HomeTour}
currentTour={'homeTourSteps'}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"

Signed-off-by: fc-santos <[email protected]>
Signed-off-by: fc-santos <[email protected]>
Signed-off-by: fc-santos <[email protected]>
Copy link

sonarqubecloud bot commented Feb 7, 2025

Copy link
Contributor

@bryce-mcmath bryce-mcmath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good improvements, added a comment above explaining the small change requested. Wasn't very clear the first time, sorry about that

#1428 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants