Skip to content

Commit

Permalink
allow user to save back up words from tour
Browse files Browse the repository at this point in the history
- it will go automatically to next step
  • Loading branch information
onmax committed Feb 11, 2022
1 parent 7d2bc2b commit 0d1fb52
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 41 deletions.
60 changes: 30 additions & 30 deletions src/components/Tour.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template>
<div class="tour">
<v-tour
name="nimiq-tour"
:steps="steps.map((s) => s.tooltip)"
:options="tourOptions"
name="nimiq-tour"
:steps="vTourSteps"
:options="tourOptions"
>
<template v-slot="tour">
<transition name="fade">
Expand Down Expand Up @@ -92,7 +92,7 @@
{{ tour.steps[tour.currentStep].button.text }}
</button>
<button
v-else-if="isLargeScreen && !isLoading"
v-else-if="isLargeScreen && !disableNextStep && !isLoading"
class="right"
@click="goToNextStep()"
tabindex="0"
Expand Down Expand Up @@ -212,20 +212,13 @@ export default defineComponent({
useKeyboardNavigation: false, // handled by us
};
// `getTour` function returns an object like:
// { "1": { /** First step */}, "10": { /** Step */}, "2": { /** Second step */}, ... }
// where the key is the step index and the value is the step object that we need to sort
// and store it as an array
let unsortedStepds = getTour(
accountStore.tour?.name, context, { isSmallScreen, isMediumScreen, isLargeScreen });
let steps = Object.keys(unsortedStepds)
.sort((a, b) => (a as unknown as number) - (b as unknown as number))
.map((key) => unsortedStepds[key as unknown as TourStepIndex]);
// Initial state
const steps: Ref<ITourStep[]> = ref([]);
setTourAsArray();
const isLoading = ref(true);
const currentStep: Ref<TourStepIndex> = ref(0);
const nSteps: Ref<number> = ref(Object.keys(steps).length);
const currentStep: Ref<TourStepIndex> = ref(4);
const nSteps: Ref<number> = ref(steps.value.length);
const disableNextStep = ref(true);
const showTour = ref(false);
Expand Down Expand Up @@ -256,7 +249,7 @@ export default defineComponent({
await context.root.$nextTick(); // to ensure DOM is ready
const step = steps[currentStep.value];
const step = steps.value[currentStep.value];
if (!step) return;
// Update state
Expand Down Expand Up @@ -316,7 +309,7 @@ export default defineComponent({
// execute _toggleDisabledButtons but it is kind of random the amount of time
// it takes to render the button. I don't know how to fix it. Waiting 500ms works.
await sleep(500);
_toggleDisabledButtons(steps[currentStep.value]?.ui.disabledButtons, true);
_toggleDisabledButtons(steps.value[currentStep.value]?.ui.disabledButtons, true);
});
function goToPrevStep() {
Expand All @@ -335,8 +328,8 @@ export default defineComponent({
newStepIndex: TourStepIndex,
goingForward: boolean,
) {
const { path: currentPath } = steps[currentStepIndex]!;
const { path: newPath, ui: newUI, lifecycle: newLifecycle } = steps[newStepIndex]!;
const { path: currentPath } = steps.value[currentStepIndex]!;
const { path: newPath, ui: newUI, lifecycle: newLifecycle } = steps.value[newStepIndex]!;
tour!.stop();
await sleep(500); // ensures animation ends
Expand All @@ -353,6 +346,7 @@ export default defineComponent({
await context.root.$nextTick();
}
_toggleDisabledButtons(steps.value[currentStepIndex].ui.disabledButtons, false);
_updateUI(newUI, newStepIndex);
await context.root.$nextTick();
Expand Down Expand Up @@ -407,7 +401,7 @@ export default defineComponent({
const tourInteractableElements = ['.tour', '.tour-manager', '.tooltip'];
// This are the elements that are allowed to be clicked only in current step
const stepInteractableElements = steps[currentStep.value]?.ui.explicitInteractableElements || [];
const stepInteractableElements = steps.value[currentStep.value]?.ui.explicitInteractableElements || [];
const interactableElements = tourInteractableElements.concat(stepInteractableElements)
.map((s) => $(s)).filter((e) => !!e) as HTMLElement[];
Expand Down Expand Up @@ -504,8 +498,6 @@ export default defineComponent({
$$(`[data-explicit-interactable="${stepIndex}"]`).forEach((el) => {
el.removeAttribute('data-explicit-interactable');
});
_toggleDisabledButtons(steps[stepIndex].ui.disabledButtons, false);
}
// nofifyManager - if true will notify the manager that the tour has ended
Expand Down Expand Up @@ -582,11 +574,7 @@ export default defineComponent({
async function _screenTypeChanged() {
tour!.stop();
unsortedStepds = getTour(
accountStore.tour?.name, context, { isSmallScreen, isMediumScreen, isLargeScreen });
steps = Object.keys(unsortedStepds)
.sort((a, b) => (a as unknown as number) - (b as unknown as number))
.map((key) => unsortedStepds[key as unknown as TourStepIndex]);
setTourAsArray();
// end tour sofly and start it again
await endTour(false, true);
Expand Down Expand Up @@ -614,6 +602,10 @@ export default defineComponent({
});
}
function setTourAsArray() {
steps.value = getTour(accountStore.tour?.name, context, { isSmallScreen, isMediumScreen, isLargeScreen });
}
return {
isSmallScreen,
isMediumScreen,
Expand All @@ -622,7 +614,7 @@ export default defineComponent({
// tour
tourOptions,
steps,
vTourSteps: computed(() => steps.value.map((s) => s.tooltip)),
showTour,
// control bar
Expand All @@ -635,6 +627,10 @@ export default defineComponent({
goToPrevStep,
goToNextStep,
endTour,
// We need to expose this function so that we can call it from the steps.
// In particular /lib/tour/onboarding/06_0_BackupAlertStep.ts
setTourAsArray,
};
},
components: {
Expand Down Expand Up @@ -812,10 +808,14 @@ export default defineComponent({
font-size: 14px;
border: 1px solid transparent;
&:focus {
&.right:focus {
border: 1px solid #ffffff55;
}
&.left:focus {
opacity: 1;
}
&.left {
display: flex;
align-items: center;
Expand Down
14 changes: 13 additions & 1 deletion src/lib/tour/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,19 @@ export function getTour(tour: TourName | undefined, context: SetupContext, scree
default:
}

return Object.values(steps).filter((step) => Boolean(step)) as ITourStep[];
// At this moment we have something like this:
// {
// "1": { /** First step object */},
// "10": { /** This is not the first step object!! */},
// "2": { /** Second step object */},
// ...
// }
// where the key is the step index and the value is the step object that we need to sort
// and store it as an array
return Object.entries(steps)
.filter(([, s]) => Boolean(s)) // Remove undefined steps
.sort(([a], [b]) => parseInt(a, 10) - parseInt(b, 10)) // Sort by key
.map(([, s]) => s) as ITourStep[]; // Just return only the step
}

// Finds the component instance given its name in the Vue tree
Expand Down
2 changes: 1 addition & 1 deletion src/lib/tour/onboarding/03_FirstTransactionStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export function getFirstTransactionStep({ isSmallScreen, txsLen }: IOnboardingGe
: '.vue-recycle-scroller__item-view:nth-child(2)'}`;
},
content: getOnboardingTexts(OnboardingTourStep.FIRST_TRANSACTION)[
txsLen.value === 1 ? 'default' : 'alternative'],
txsLen.value <= 1 ? 'default' : 'alternative'],
params: {
get placement() {
return isSmallScreen.value ? 'bottom-start' : 'left';
Expand Down
29 changes: 25 additions & 4 deletions src/lib/tour/onboarding/06_0_BackupAlertStep.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { defaultTooltipModifiers, ITourOrigin, IWalletHTMLElements } from '..';
import { IOnboardingGetStepFnArgs, OnboardingTourStep, ITourStep } from '../types';
import { useAccountStore } from '@/stores/Account';
import { watch } from '@vue/composition-api';
import { defaultTooltipModifiers, ITourOrigin, IWalletHTMLElements, searchComponentByName } from '..';
import { IOnboardingGetStepFnArgs, ITourStep, OnboardingTourStep } from '../types';
import { getOnboardingTexts } from './OnboardingTourTexts';

export function getBackupAlertStep(
{ isSmallScreen, startedFrom, toggleHighlightButton }: IOnboardingGetStepFnArgs): ITourStep {
{ isSmallScreen, startedFrom, toggleHighlightButton, root }: IOnboardingGetStepFnArgs): ITourStep {
const ui: ITourStep['ui'] = {
fadedElements: [
IWalletHTMLElements.SIDEBAR_TESTNET,
Expand Down Expand Up @@ -75,9 +77,28 @@ export function getBackupAlertStep(
ui,
lifecycle: {
mounted: () => {
const unwatch = watch(useAccountStore().activeAccountInfo, async (newVal) => {
if (newVal?.wordsExported) {
// If user clicks "save recover words" and completes the process, we
// no longer need to show the user this step, therefore, we execute
// setTourAsArray again, and go to the next step which in reality will have
// same index
const nimiqTourInstance = searchComponentByName(root, 'nimiq-tour') as any;
if (!nimiqTourInstance) return;

nimiqTourInstance.setTourAsArray();
nimiqTourInstance.currentStep -= 1;

setTimeout(() => nimiqTourInstance.goToNextStep(), 500);
}
});

// hightlight 'Revover words' button
toggleHighlightButton(IWalletHTMLElements.BUTTON_ADDRESS_BACKUP_ALERT, true, 'orange');
return () => toggleHighlightButton(IWalletHTMLElements.BUTTON_ADDRESS_BACKUP_ALERT, false, 'orange');
return () => {
unwatch();
toggleHighlightButton(IWalletHTMLElements.BUTTON_ADDRESS_BACKUP_ALERT, false, 'orange');
};
},
},
} as ITourStep;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/tour/onboarding/OnboardingTourTexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const texts: ITourStepTexts<OnboardingTourStep> = {
alternative: [$t('This is where all your transactions will appear.')],
},
[OnboardingTourStep.FIRST_TRANSACTION]: {
// If user has 0 or 1 tx
// If user has 1 tx
default: [
$t('Here’s your first transaction with your first NIM.'),
$t('Every NIM address comes with an avatar. They help to make sure you got the right one.'),
Expand Down
8 changes: 4 additions & 4 deletions src/lib/tour/onboarding/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export function getOnboardingTourSteps({ root }: SetupContext, screenTypes: Scre

const { state, activeAccountInfo } = useAccountStore();
const { startedFrom } = (state.tour as { startedFrom: ITourOrigin });
const { type: accountType, wordsExported } = activeAccountInfo.value || {};
const accountIsSecured = accountType === AccountType.BIP39 && !!wordsExported;
const accountIsSecured = computed(() =>
activeAccountInfo.value?.type === AccountType.BIP39 && activeAccountInfo.value?.wordsExported);

const args: IOnboardingGetStepFnArgs = {
sleep,
Expand All @@ -53,7 +53,7 @@ export function getOnboardingTourSteps({ root }: SetupContext, screenTypes: Scre
[OnboardingTourStep.WALLET_BALANCE]: getWalletBalanceStep(args),
get [OnboardingTourStep.BACKUP_ALERT]() {
// if the user has already backed up their account, skip this step
return !accountIsSecured ? getBackupAlertStep(args) : undefined;
return !accountIsSecured.value ? getBackupAlertStep(args) : undefined;
},
get [OnboardingTourStep.MENU_ICON]() {
// show only this step if it is a new user and is not in a large screen
Expand All @@ -63,7 +63,7 @@ export function getOnboardingTourSteps({ root }: SetupContext, screenTypes: Scre
[OnboardingTourStep.ACCOUNT_OPTIONS]: getAccountOptionsStep(args),
get [OnboardingTourStep.BACKUP_OPTION_FROM_OPTIONS]() {
// if the user has already backed up their account, remind the user that he can backup anytime
if (!accountIsSecured) return undefined;
if (!accountIsSecured.value) return undefined;
return (screenTypes.isLargeScreen.value)
? getBackupOptionLargeScreenStep()
: getBackupOptionNotLargeScreenStep(args);
Expand Down

0 comments on commit 0d1fb52

Please sign in to comment.