Skip to content

Commit b670447

Browse files
committed
added button to start onboarding tour from settings
1 parent fde47fb commit b670447

File tree

4 files changed

+62
-35
lines changed

4 files changed

+62
-35
lines changed

src/App.vue

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
<template>
22
<div id="app" :class="{'value-masked': amountsHidden}">
33
<!-- (?) This could be moved to Groundfloor.vue -->
4-
<!-- TODO Remove '|| true' -->
5-
<transition v-if="!!$route.params.doOnboardingTour || true" name="delay">
6-
<Tour />
4+
<transition v-if="!!$route.params.tourName" name="delay">
5+
<Tour :tourName="$route.params.tourName" />
76
</transition>
87

98
<main :class="routeClass" ref="$main">
@@ -45,13 +44,6 @@ import { useSwipes } from './composables/useSwipes';
4544
4645
export default defineComponent({
4746
name: 'app',
48-
props: {
49-
doOnboardingTour: {
50-
// It has to be a string since it is a value encapsulated in Location.params which is Dictionary<string>.
51-
type: String,
52-
default: '',
53-
},
54-
},
5547
setup(props, context) {
5648
provideRouter(router);
5749

src/components/Tour.vue

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<div>
33
<v-tour
44
class="tour"
5-
name="onboarding-tour"
5+
name="nimiq-tour"
66
:steps="Object.values(steps).map((s) => s.tooltip)"
77
>
88
<template slot-scope="tour">
@@ -94,7 +94,7 @@ import {
9494
} from '@vue/composition-api';
9595
import Vue from 'vue';
9696
import VueTour from 'vue-tour';
97-
import { TourStep, TourStepIndex, useFakeTx, useOnboardingTourSteps } from '../composables/useTour';
97+
import { TourName, TourStep, TourStepIndex, TourSteps, useFakeTx, useTour } from '../composables/useTour';
9898
import { useWindowSize } from '../composables/useWindowSize';
9999
import CaretRightIcon from './icons/CaretRightIcon.vue';
100100
@@ -104,6 +104,13 @@ require('vue-tour/dist/vue-tour.css');
104104
105105
export default defineComponent({
106106
name: 'tour',
107+
props: {
108+
tourName: {
109+
type: String,
110+
required: true,
111+
validator: (tour: TourName) => (['onboarding', 'network'] as TourName[]).indexOf(tour) !== -1,
112+
},
113+
},
107114
setup(props, context) {
108115
// TODO Use isMobile
109116
const { width } = useWindowSize();
@@ -112,38 +119,47 @@ export default defineComponent({
112119
const disconnected = computed(
113120
() => $network.consensus !== 'established',
114121
);
115-
const loading = ref(false);
116122
117123
let tour: VueTour.Tour | null = null;
124+
const steps: TourSteps<any> = useTour(props.tourName as TourName, context) || {};
118125
119-
// TODO This will be a prop
120-
const steps = useOnboardingTourSteps(context);
121-
122-
const currentStep: Ref<TourStepIndex> = ref(6);
123-
const nSteps = Object.keys(steps).length; // TODO Might be a ref/computed instead
124-
const disableNextStep = ref(currentStep.value >= nSteps - 1 || !!steps[currentStep.value].ui.disabledNextStep);
126+
// Initial state
127+
const loading = ref(true);
128+
const currentStep: Ref<TourStepIndex> = ref(0);
129+
const nSteps: Ref<number> = ref(0);
130+
const disableNextStep = ref(true);
125131
126132
onMounted(() => {
127-
tour = context.root.$tours['onboarding-tour'];
133+
tourSetup();
134+
135+
// REMOVE ME
136+
const { removeTransactions } = useTransactionsStore();
137+
removeTransactions([useFakeTx()]);
138+
});
128139
140+
async function tourSetup() {
141+
// Update state
142+
nSteps.value = Object.keys(steps).length;
143+
disableNextStep.value = currentStep.value >= nSteps.value - 1
144+
|| !!steps[currentStep.value].ui.disabledNextStep;
129145
_addAttributes(steps[currentStep.value].ui, currentStep.value);
130146
// eslint-disable-next-line no-unused-expressions
131147
steps[currentStep.value].lifecycle?.onMountedStep?.(goToNextStep);
132148
133-
tour!.start(`${currentStep.value}`);
149+
await sleep(500);
134150
135-
// REMOVE ME
136-
const { removeTransactions } = useTransactionsStore();
137-
removeTransactions([useFakeTx()]);
138-
});
151+
tour = context.root.$tours['nimiq-tour'];
152+
tour!.start(`${currentStep.value}`);
153+
loading.value = false;
154+
}
139155
140156
function goToPrevStep() {
141157
if (currentStep.value <= 0) return;
142158
_moveToFutureStep(currentStep.value, currentStep.value - 1);
143159
}
144160
145161
function goToNextStep() {
146-
if (currentStep.value + 1 >= nSteps) return;
162+
if (currentStep.value + 1 >= nSteps.value) return;
147163
_moveToFutureStep(currentStep.value, currentStep.value + 1);
148164
}
149165
@@ -191,7 +207,7 @@ export default defineComponent({
191207
192208
// onMountedStep
193209
loading.value = false;
194-
disableNextStep.value = futureStepIndex >= nSteps - 1 || !!futureUI.disabledNextStep;
210+
disableNextStep.value = futureStepIndex >= nSteps.value - 1 || !!futureUI.disabledNextStep;
195211
196212
// eslint-disable-next-line no-unused-expressions
197213
futureLifecycle?.onMountedStep?.(goToNextStep);

src/components/layouts/Settings.vue

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@
8787
</label>
8888
</div>
8989

90+
<div class="setting">
91+
<div class="description">
92+
<label class="nq-h2" for="product-tour">{{ $t('Product Tour') }}</label>
93+
<p class="nq-text">
94+
{{ $t('Go through the product again') }}
95+
</p>
96+
</div>
97+
98+
<router-link :to="{ name: 'root', params: { tourName: 'onboarding' } }">
99+
<button class="nq-button-pill light-blue">{{ $t('Start Tour') }}</button>
100+
</router-link>
101+
</div>
102+
90103
<!-- <div class="setting">
91104
<div class="description">
92105
<label class="nq-h2" for="theme">{{ $t('Interface Theme') }}</label>

src/composables/useTour.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Transaction, useTransactionsStore } from '@/stores/Transactions';
22
import { SetupContext } from '@vue/composition-api';
33
import { useAddressStore } from '../stores/Address';
44

5+
export type TourName = 'onboarding' | 'network'
56
type OnboardingTourPages = '/' | '/transactions' | '/?sidebar=true'
67

78
enum MobileOnboardingTourStep {
@@ -59,8 +60,8 @@ export interface TourStep {
5960
};
6061
}
6162

62-
export type TourSteps = {
63-
[x in TourStepIndex]: TourStep;
63+
export type TourSteps<T extends number> = {
64+
[x in T]: TourStep;
6465
};
6566

6667
// TODO Remove me
@@ -92,7 +93,7 @@ export function useFakeTx(): Transaction {
9293
state: 'confirmed',
9394
};
9495
}
95-
export function useOnboardingTourSteps({ root }: SetupContext): TourSteps {
96+
function getOnboardingTourSteps({ root }: SetupContext): TourSteps<MobileOnboardingTourStep> {
9697
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
9798

9899
const closeAccountOptionsModal = async () => {
@@ -112,7 +113,7 @@ export function useOnboardingTourSteps({ root }: SetupContext): TourSteps {
112113
await sleep(500); // TODO Check this random value
113114
};
114115

115-
const steps: TourSteps = {
116+
const steps: TourSteps<MobileOnboardingTourStep> = {
116117
[MobileOnboardingTourStep.FIRST_ADDRESS]: {
117118
page: '/',
118119
tooltip: {
@@ -359,8 +360,7 @@ export function useOnboardingTourSteps({ root }: SetupContext): TourSteps {
359360
steps[MobileOnboardingTourStep.TRANSACTIONS_LIST].lifecycle = {
360361
...steps[MobileOnboardingTourStep.TRANSACTIONS_LIST].lifecycle,
361362

362-
// TODO Maybe it could be possible without async/await
363-
onMountedStep: async () => new Promise((resolve) => {
363+
onMountedStep: () => {
364364
root.$watch(() => useTransactionsStore().state.transactions, (txs) => {
365365
if (Object.values(txs).length > 0) {
366366
// Once the user has at least one transaction, tooltip in step TRANSACTIONS_LIST is modified
@@ -373,9 +373,15 @@ export function useOnboardingTourSteps({ root }: SetupContext): TourSteps {
373373
};
374374
steps[MobileOnboardingTourStep.TRANSACTIONS_LIST].ui.disabledNextStep = false;
375375
}
376-
resolve();
377376
});
378-
}),
377+
},
379378
};
380379
return steps;
381380
}
381+
export function useTour(tour: TourName, context: SetupContext)
382+
: TourSteps<MobileOnboardingTourStep> | TourSteps<NetworkTourStep> | undefined {
383+
if (tour === 'onboarding') {
384+
return getOnboardingTourSteps(context);
385+
}
386+
return undefined;
387+
}

0 commit comments

Comments
 (0)