Skip to content

Commit

Permalink
added store state for tour
Browse files Browse the repository at this point in the history
  • Loading branch information
onmax committed Jan 20, 2022
1 parent b670447 commit d0ee499
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 59 deletions.
13 changes: 10 additions & 3 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div id="app" :class="{'value-masked': amountsHidden}">
<!-- (?) This could be moved to Groundfloor.vue -->
<transition v-if="!!$route.params.tourName" name="delay">
<Tour :tourName="$route.params.tourName" />
<transition v-if="showTour" name="delay">
<Tour/>
</transition>

<main :class="routeClass" ref="$main">
Expand Down Expand Up @@ -77,7 +77,13 @@ export default defineComponent({
}
});
const { accountInfos } = useAccountStore();
const { accountInfos, state: accountState, removeTour } = useAccountStore();
if (!['root', 'transactions'].includes(context.root.$route.name as string)
&& accountState.tour?.name === 'onboarding') {
removeTour();
}
const showTour = computed(() => !!accountState.tour);
// Convert result of computation to boolean, to not trigger rerender when number of accounts changes above 0.
const hasAccounts = computed(() => Boolean(Object.keys(accountInfos.value).length));
Expand Down Expand Up @@ -170,6 +176,7 @@ export default defineComponent({
});
return {
showTour,
routeClass,
hasAccounts,
amountsHidden,
Expand Down
133 changes: 93 additions & 40 deletions src/components/Tour.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<template>
<div>
<div class="tour">
<v-tour
class="tour"
name="nimiq-tour"
:steps="Object.values(steps).map((s) => s.tooltip)"
>
Expand All @@ -20,34 +19,37 @@
:is-last="tour.isLast"
:labels="tour.labels"
>
<div class="content" slot="content">
<div slot="content" class="content">
<p
v-for="(content, i) in tour.steps[tour.currentStep].content"
:key="i"
v-html="content"
v-html="$t(content)"
></p>
<!-- TODO REMOVE ME -->
<div class="remove_me" v-if="currentStep === 1" @click="simulate()">
Simulate Receive NIM
</div>
</div>
<div slot="actions">
<template v-if="!isMobile">
<button @click="tour.previousStep">
{{ $t("Previous step") }}
</button>
<button @click="tour.goToNextStep">
{{ $t("Next step") }}
</button>
</template>
<div slot="actions" class="actions">
<button @click="tour.previousStep" v-if="!isMobile">
{{ $t("Previous step") }}
</button>
<button class="right" @click="alert"
v-if="tour.steps[tour.currentStep].button">
{{ $t(tour.steps[tour.currentStep].button.text) }}
</button>
<button class="right" @click="tour.goToNextStep"
v-else-if="!isMobile">
{{ $t("Next step") }}
</button>
</div>
</v-step>
</transition>
</template>
</v-tour>
<transition name="fade">
<div class="tour-control-bar">
<button disabled>
<button @click="endTour()">
{{ $t("End Tour") }}
</button>
<span class="progress">
Expand Down Expand Up @@ -82,6 +84,7 @@
</template>

<script lang="ts">
import { useAccountStore } from '@/stores/Account';
import { useNetworkStore } from '@/stores/Network';
import { useTransactionsStore } from '@/stores/Transactions';
import { CircleSpinner } from '@nimiq/vue-components';
Expand All @@ -91,10 +94,11 @@ import {
onMounted,
Ref,
ref,
watch,
} from '@vue/composition-api';
import Vue from 'vue';
import VueTour from 'vue-tour';
import { TourName, TourStep, TourStepIndex, TourSteps, useFakeTx, useTour } from '../composables/useTour';
import { TourStep, TourStepIndex, TourSteps, useFakeTx, useTour } from '../composables/useTour';
import { useWindowSize } from '../composables/useWindowSize';
import CaretRightIcon from './icons/CaretRightIcon.vue';
Expand All @@ -104,13 +108,6 @@ require('vue-tour/dist/vue-tour.css');
export default defineComponent({
name: 'tour',
props: {
tourName: {
type: String,
required: true,
validator: (tour: TourName) => (['onboarding', 'network'] as TourName[]).indexOf(tour) !== -1,
},
},
setup(props, context) {
// TODO Use isMobile
const { width } = useWindowSize();
Expand All @@ -120,12 +117,14 @@ export default defineComponent({
() => $network.consensus !== 'established',
);
const { state: tourStore, removeTour } = useAccountStore();
let tour: VueTour.Tour | null = null;
const steps: TourSteps<any> = useTour(props.tourName as TourName, context) || {};
const steps: TourSteps<any> = useTour(tourStore.tour, context) || {};
// Initial state
const loading = ref(true);
const currentStep: Ref<TourStepIndex> = ref(0);
const currentStep: Ref<TourStepIndex> = ref(8);
const nSteps: Ref<number> = ref(0);
const disableNextStep = ref(true);
Expand All @@ -142,17 +141,36 @@ export default defineComponent({
nSteps.value = Object.keys(steps).length;
disableNextStep.value = currentStep.value >= nSteps.value - 1
|| !!steps[currentStep.value].ui.disabledNextStep;
_addAttributes(steps[currentStep.value].ui, currentStep.value);
// eslint-disable-next-line no-unused-expressions
steps[currentStep.value].lifecycle?.onMountedStep?.(goToNextStep);
if (context.root.$route.path !== steps[currentStep.value].path) {
context.root.$router.push(steps[currentStep.value].path);
}
await sleep(500);
tour = context.root.$tours['nimiq-tour'];
tour!.start(`${currentStep.value}`);
loading.value = false;
}
// Dont allow user to interact with the page while it is loading
// But allow to end it
watch([loading, disconnected], () => {
const app = document.querySelector('#app main') as HTMLDivElement;
if (loading.value || disconnected.value) {
// eslint-disable-next-line no-unused-expressions
app?.setAttribute('data-non-interactable', '');
} else {
// eslint-disable-next-line no-unused-expressions
app?.removeAttribute('data-non-interactable');
}
});
function goToPrevStep() {
if (currentStep.value <= 0) return;
_moveToFutureStep(currentStep.value, currentStep.value - 1);
Expand All @@ -171,8 +189,8 @@ export default defineComponent({
) {
const goingForward = futureStepIndex > currentStepIndex;
const { page: currentPage, lifecycle: currentLifecycle } = steps[currentStepIndex];
const { page: futurePage, ui: futureUI, lifecycle: futureLifecycle } = steps[futureStepIndex];
const { path: currentPage, lifecycle: currentLifecycle } = steps[currentStepIndex];
const { path: futurePage, ui: futureUI, lifecycle: futureLifecycle } = steps[futureStepIndex];
loading.value = true;
tour!.stop();
Expand All @@ -183,10 +201,14 @@ export default defineComponent({
await currentLifecycle.prepareDOMPrevPage();
} else if (goingForward && currentLifecycle && currentLifecycle.prepareDOMNextPage) {
await currentLifecycle.prepareDOMNextPage();
} else if (futurePage !== currentPage && currentPage.startsWith(context.root.$route.path)) {
// Default prepare DOM
context.root.$router.push(futurePage);
await context.root.$nextTick();
} else if (futurePage !== currentPage) {
try {
// Default prepare DOM
context.root.$router.push(futurePage);
await context.root.$nextTick();
} catch {
// Ignore error
}
}
_addAttributes(futureUI, futureStepIndex);
Expand Down Expand Up @@ -243,6 +265,16 @@ export default defineComponent({
});
}
function endTour() {
_removeAttributes(currentStep.value);
// If user finalizes tour while it is loading, allow then interaction
const app = document.querySelector('#app main') as HTMLDivElement;
app.removeAttribute('data-non-interactable');
removeTour();
}
// TODO REMOVE ME - Simulate tx
function simulate() {
const { addTransactions } = useTransactionsStore();
Expand All @@ -263,6 +295,7 @@ export default defineComponent({
// actions
goToPrevStep,
goToNextStep,
endTour,
// TODO REMOVE ME
simulate,
Expand Down Expand Up @@ -294,6 +327,20 @@ export default defineComponent({
.tour {
position: relative;
button {
width: min-content;
white-space: nowrap;
font-size: 16px;
padding: 0.8rem 1.6rem;
text-align: center;
background: #ffffff33; // TODO Maybe move this to a CSS variable (?)
color: var(--nimiq-white);
border: none;
outline: var(--nimiq-);
border-radius: 9999px;
}
.tooltip-step {
background: radial-gradient(
100% 100% at 100% 100%,
Expand Down Expand Up @@ -323,6 +370,21 @@ export default defineComponent({
}
}
}
.actions {
margin-top: 2rem;
display: flex;
button {
font-weight: 700;
font-size: 14px;
&.right {
margin-left: auto;
}
}
}
}
}
Expand All @@ -348,17 +410,8 @@ export default defineComponent({
);
button {
width: min-content;
white-space: nowrap;
padding: 1.4rem 1.6rem 1rem 1.6rem;
font-size: 16px;
text-align: center;
background: #ffffff33; // TODO Maybe move this to a CSS variable (?)
color: var(--nimiq-white);
border: none;
outline: var(--nimiq-);
border-radius: 9999px;
font-weight: 700;
&:disabled {
opacity: 0.5;
Expand Down
14 changes: 11 additions & 3 deletions src/components/layouts/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@
</p>
</div>

<router-link :to="{ name: 'root', params: { tourName: 'onboarding' } }">
<button class="nq-button-pill light-blue">{{ $t('Start Tour') }}</button>
</router-link>
<button class="nq-button-pill light-blue" @click="goToOnboardingTour()">
{{ $t('Start Tour') }}
</button>
</div>

<!-- <div class="setting">
Expand Down Expand Up @@ -275,6 +275,7 @@ import { CircleSpinner } from '@nimiq/vue-components';
// @ts-expect-error missing types for this package
import { Portal } from '@linusborg/vue-simple-portal';
import { useAccountStore } from '@/stores/Account';
import MenuIcon from '../icons/MenuIcon.vue';
import CrossCloseButton from '../CrossCloseButton.vue';
import CountryFlag from '../CountryFlag.vue';
Expand Down Expand Up @@ -372,6 +373,12 @@ export default defineComponent({
reader.readAsText(file);
}
function goToOnboardingTour() {
const { setTour } = useAccountStore();
setTour('onboarding');
context.root.$router.push('/');
}
async function onTrialPassword(el: HTMLInputElement) {
let hash: string;
try {
Expand Down Expand Up @@ -434,6 +441,7 @@ export default defineComponent({
...settings,
$fileInput,
loadFile,
goToOnboardingTour,
showVestingSetting,
onTrialPassword,
applyWalletUpdate,
Expand Down
Loading

0 comments on commit d0ee499

Please sign in to comment.