Last active
June 25, 2022 07:05
-
-
Save JohnRandom/2fb3053fd32c5716e4cdca0a3a8459f9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { push, replace, setOnboardingStep } from 'actions'; | |
let step = null; | |
let finalStep = 'STEP_C'; | |
const steps = { | |
STEP_A: { url: '/feature_1', nextStep: 'STEP_B' }, | |
STEP_B: { url: '/feature_2', nextStep: 'STEP_C' }, | |
STEP_C: { url: '/feature_3', nextStep: 'STEP_D' }, | |
// ... and so on ... | |
}; | |
const milestones = [ | |
'SAVE_USER_PROFILE_SUCCESS', | |
'SAVE_PAYMENT_OPTIONS_SUCCESS', | |
'CONFIRM_SHOPPING_BASKET_SELECTION', | |
// ... and so on ... | |
]; | |
const exclusiveUrls = [ | |
'/onboarding/route/1', | |
'/onboarding/route/2', | |
'/onboarding/route/3', | |
// ... and so on ... | |
]; | |
const middleware = store => next => action => { | |
// Make sure call this at the beginning, so that state | |
// changes already happened when we have to redirect. | |
const nextAction = next(action); | |
// These actions are always being handled, even if the user | |
// iss currently not being on-boarded. | |
switch (action.type) { | |
case 'SET_ONBOARDING_STEP': | |
step = action.payload; | |
const { url } = steps[step]; | |
// Make sure we "replace" instead of "push" when we have an on-boarding | |
// exclusive URL. | |
const redirectMethod = exclusiveUrls.indexOf(url) >= 0 ? replace : push; | |
store.dispatch( redirectMethod(url) ); | |
break; | |
case 'ADD_ONBOARDING_MILESTONE': | |
milestones.push(action.payload); | |
break; | |
case 'REMOVE_ONBOARDING_MILESTONE': | |
const idx = milestones.indexOf(action.payload); | |
if (idx >= 0) milestones.splice(idx, 1); | |
break; | |
case 'INSERT_ONBOARDING_STEP': | |
const { stepBefore, step, stepLabel } = action.payload; | |
steps[stepBefore].nextStep = stepLabel; | |
steps[stepLabel] = step; | |
break; | |
case 'REMOVE_ONBOARDING_STEP': | |
const { stepLabel, newNextStep } = action.payload; | |
// Rewrite all pointers to the deleted step with the new next step label. | |
Object.keys(steps).forEach((label) => { | |
if (steps[label].nextStep === stepLabel) steps[label].nextStep = newNextStep; | |
}); | |
delete steps[stepLabel]; | |
break; | |
case 'SET_FINAL_ONBOARDIND_STEP': | |
finalStep = action.payload; | |
break; | |
case 'LOGOUT': | |
step = null; | |
break; | |
} | |
// This are the actions being handled when the user is currently | |
// not being onboarded. | |
if (step === finalStep || step === null) { | |
// Handle all LOCATION_CHANGE action from react-router-redux. | |
if (action.type === '@@router/LOCATION_CHANGE';) { | |
// Make sure the user is redirected away from on-boarding exclusive URLs. | |
if (exclusiveUrls.indexOf(action.payload.pathname) >= 0) { | |
store.dispatch( push('/somewhere/else') ); | |
} | |
} | |
// If we're already on the last step, we don't need to steer the flow anymore, | |
// so we can safely return. | |
return nextAction; | |
} | |
// These are the actions being handled, when the user is currently | |
// being on-boarded. | |
// If the user completed an on-boarding milestone, | |
// advance the flow to the next step. | |
if (milestones.indexOf(action.type) >= 0) { | |
const { nextStep } = states[step]; | |
store.dispatch( setRegistrationStep(nextStep) ); | |
} | |
// If we see a routing event during on-boarding, make sure that it only | |
// goes to routes allowed during on-boarding. | |
if (action.type === '@@router/LOCATION_CHANGE') { | |
const expectedUrl = steps[step].url; | |
const isOnCorrectUrl = action.payload.pathname === expectedUrl; | |
if (!isOnCorrectUrl) dispatch( push(expectedUrl) ); | |
} | |
return nextAction; | |
}; | |
export default middleware; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment