web/satellite: added ability to restart onboarding tour

Added an info icon which toggles a bubble where user can click a button to restrat onboarding tour

Change-Id: I8b02a1506684377c2887cc9d9c93b5450f1bfd4d
This commit is contained in:
Vitalii Shpital 2021-08-20 15:04:16 +03:00
parent ce6ae1b17a
commit a7e151e970
8 changed files with 112 additions and 84 deletions

View File

@ -5,10 +5,20 @@
<div class="info" @mouseenter="toggleVisibility" @mouseleave="toggleVisibility">
<slot />
<div v-if="isVisible" class="info__box">
<div v-if="buttonLabel" class="info__box__click-mock" />
<div class="info__box__arrow" />
<div class="info__box__message">
<h1 v-if="title" class="info__box__message__title">{{ title }}</h1>
<p class="info__box__message__regular-text">{{ text }}</p>
<p class="info__box__message__bold-text">{{ boldText }}</p>
<VButton
v-if="buttonLabel"
class="info__box__message__button"
:label="buttonLabel"
height="42px"
border-radius="52px"
:on-press="onClick"
/>
</div>
</div>
</div>
@ -17,15 +27,38 @@
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
import VButton from '@/components/common/VButton.vue';
@Component({
components: {
VButton,
}
})
export default class VInfo extends Vue {
@Prop({default: ''})
private readonly title: string;
@Prop({default: ''})
private readonly text: string;
@Prop({default: ''})
private readonly boldText: string;
@Prop({default: ''})
private readonly buttonLabel: string;
@Prop({default: () => false})
private readonly onButtonClick: () => unknown;
public isVisible = false;
/**
* Holds on button click logic.
*/
public onClick(): void {
this.onButtonClick();
this.toggleVisibility();
}
/**
* Toggles bubble visibility.
*/
public toggleVisibility(): void {
this.isVisible = !this.isVisible;
}
@ -47,6 +80,11 @@ export default class VInfo extends Vue {
filter: drop-shadow(0 0 34px #0a1b2c47);
z-index: 1;
&__click-mock {
height: 24px;
background: transparent;
}
&__arrow {
background-color: white;
width: 40px;
@ -62,6 +100,14 @@ export default class VInfo extends Vue {
padding: 24px;
border-radius: 20px;
&__title {
font-family: 'font_bold', sans-serif;
font-size: 14px;
line-height: 32px;
color: #000;
margin-bottom: 10px;
}
&__bold-text,
&__regular-text {
color: #586c86;
@ -74,6 +120,10 @@ export default class VInfo extends Vue {
&__regular-text {
font-family: 'font_regular', sans-serif;
}
&__button {
margin-top: 20px;
}
}
}
}

View File

@ -24,6 +24,16 @@
<SettingsSelection class="settings-selection" />
</div>
<div class="header-container__right-area">
<VInfo
v-if="!isOnboardingTour"
class="header-container__right-area__info"
title="Need some help?"
text="You can always start the onboarding tour and go through all the steps to get you started again."
button-label="START TOUR"
:on-button-click="onStartTourButtonClick"
>
<InfoIcon />
</VInfo>
<div class="header-container__right-area__satellite-area">
<div class="header-container__right-area__satellite-area__checkmark">
<CheckmarkIcon />
@ -47,8 +57,10 @@ import ProjectSelection from '@/components/header/projectsDropdown/ProjectSelect
import ResourcesSelection from '@/components/header/resourcesDropdown/ResourcesSelection.vue';
import SettingsSelection from '@/components/header/settingsDropdown/SettingsSelection.vue';
import NavigationArea from '@/components/navigation/NavigationArea.vue';
import VInfo from '@/components/common/VInfo.vue';
import LogoIcon from '@/../static/images/logo.svg';
import InfoIcon from '@/../static/images/header/info.svg';
import CheckmarkIcon from '@/../static/images/header/checkmark.svg';
import NavigationCloseIcon from '@/../static/images/header/navigationClose.svg';
import NavigationMenuIcon from '@/../static/images/header/navigationMenu.svg';
@ -61,9 +73,11 @@ import AccountButton from './accountDropdown/AccountButton.vue';
components: {
AccountButton,
NavigationArea,
VInfo,
NavigationMenuIcon,
NavigationCloseIcon,
LogoIcon,
InfoIcon,
CheckmarkIcon,
ProjectSelection,
ResourcesSelection,
@ -90,6 +104,13 @@ export default class HeaderArea extends Vue {
location.reload();
}
/**
* Redirects to onboarding tour.
*/
public async onStartTourButtonClick(): Promise<void> {
await this.$router.push(RouteConfig.OnboardingTour.path)
}
/**
* Indicates if current route is onboarding tour.
*/
@ -148,6 +169,11 @@ export default class HeaderArea extends Vue {
display: flex;
align-items: center;
&__info {
max-height: 24px;
margin-right: 17px;
}
&__satellite-area {
height: 36px;
background: #f6f6fa;
@ -205,6 +231,19 @@ export default class HeaderArea extends Vue {
margin-right: 35px;
}
::v-deep .info__box {
top: calc(100% - 24px);
&__message {
min-width: 335px;
&__regular-text {
font-size: 12px;
line-height: 21px;
}
}
}
@media screen and (min-width: 1281px) {
.adapted-navigation,

View File

@ -10,27 +10,8 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { RouteConfig } from '@/router';
@Component
export default class OnboardingTourArea extends Vue {
/**
* Lifecycle hook after initial render.
* Sets area to needed state.
*/
public mounted(): void {
if (this.userHasProject) {
this.$router.push(RouteConfig.ProjectDashboard.path).catch(() => {return; });
}
}
/**
* Indicates if user has at least one project.
*/
private get userHasProject(): boolean {
return this.$store.state.projectsModule.projects.length > 0;
}
}
export default class OnboardingTourArea extends Vue {}
</script>
<style scoped lang="scss">

View File

@ -51,7 +51,6 @@ import WelcomeRight from '@/../static/images/onboardingTour/welcome-right.svg';
import { AnalyticsHttpApi } from '@/api/analytics';
import { RouteConfig } from '@/router';
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
@Component({
@ -67,19 +66,9 @@ export default class OverviewStep extends Vue {
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
/**
* Lifecycle hook after initial render.
* Sets area to needed state.
*/
public mounted(): void {
if (this.userHasProject) {
this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant).path).catch(() => {return; });
}
}
/**
* Holds button click logic.
* Creates untitled project and redirects to next step (creating access grant).
* Redirects to next step (creating access grant).
*/
public async onUplinkCLIClick(): Promise<void> {
if (this.isLoading) return;
@ -87,21 +76,13 @@ export default class OverviewStep extends Vue {
this.isLoading = true;
await this.analytics.linkEventTriggered(AnalyticsEvent.PATH_SELECTED, 'CLI');
await this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant).with(RouteConfig.AccessGrantName).path);
try {
await this.$store.dispatch(PROJECTS_ACTIONS.CREATE_DEFAULT_PROJECT);
this.isLoading = false;
await this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant).with(RouteConfig.AccessGrantName).path);
} catch (error) {
await this.$notify.error(error.message);
this.isLoading = false;
}
this.isLoading = false;
}
/**
* Creates untitled project and redirects to objects page.
* Redirects to objects page.
*/
public async onUploadInBrowserClick(): Promise<void> {
if (this.isLoading) return;
@ -109,45 +90,17 @@ export default class OverviewStep extends Vue {
this.isLoading = true;
await this.analytics.linkEventTriggered(AnalyticsEvent.PATH_SELECTED, 'Continue in Browser');
await this.$router.push(RouteConfig.Objects.path).catch(() => {return; });
try {
await this.$store.dispatch(PROJECTS_ACTIONS.CREATE_DEFAULT_PROJECT);
this.isLoading = false;
await this.$router.push(RouteConfig.Objects.path).catch(() => {return; });
} catch (error) {
await this.$notify.error(error.message);
this.isLoading = false;
}
this.isLoading = false;
}
/**
* Holds button click logic.
* Creates untitled project and redirects to project dashboard.
* Redirects to project dashboard.
*/
public async onSkipClick(): Promise<void> {
if (this.isLoading) return;
this.isLoading = true;
try {
await this.$store.dispatch(PROJECTS_ACTIONS.CREATE_DEFAULT_PROJECT);
this.isLoading = false;
await this.$router.push(RouteConfig.ProjectDashboard.path);
} catch (error) {
await this.$notify.error(error.message);
this.isLoading = false;
}
}
/**
* Indicates if user has at least one project.
*/
private get userHasProject(): boolean {
return this.$store.state.projectsModule.projects.length > 0;
await this.$router.push(RouteConfig.ProjectDashboard.path);
}
}
</script>

View File

@ -132,10 +132,10 @@ export default class DashboardArea extends Vue {
}
if (!projects.length) {
await this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADED);
try {
await this.$store.dispatch(PROJECTS_ACTIONS.CREATE_DEFAULT_PROJECT);
await this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.OverviewStep).path);
await this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADED);
} catch (error) {
return;
}

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 16V12" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 8H12.01" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 524 B

View File

@ -4,7 +4,7 @@ exports[`Team HeaderArea renders correctly 1`] = `
<div class="team-header-container">
<div class="team-header-container__title-area">
<h1 class="team-header-container__title-area__title">Project Members</h1>
<vinfo-stub text="" boldtext="The only project role currently available is Admin, which gives full access to the project." class="team-header-container__title-area__info-button">
<vinfo-stub title="" text="" boldtext="The only project role currently available is Admin, which gives full access to the project." buttonlabel="" class="team-header-container__title-area__info-button">
<infoicon-stub class="team-header-container__title-area__info-button__image"></infoicon-stub>
</vinfo-stub>
</div>
@ -27,7 +27,7 @@ exports[`Team HeaderArea renders correctly with 1 selected user and delete click
<div class="team-header-container">
<div class="team-header-container__title-area">
<h1 class="team-header-container__title-area__title">Project Members</h1>
<vinfo-stub text="" boldtext="The only project role currently available is Admin, which gives full access to the project." class="team-header-container__title-area__info-button">
<vinfo-stub title="" text="" boldtext="The only project role currently available is Admin, which gives full access to the project." buttonlabel="" class="team-header-container__title-area__info-button">
<infoicon-stub class="team-header-container__title-area__info-button__image"></infoicon-stub>
</vinfo-stub>
</div>
@ -53,7 +53,7 @@ exports[`Team HeaderArea renders correctly with 2 selected users and delete clic
<div class="team-header-container">
<div class="team-header-container__title-area">
<h1 class="team-header-container__title-area__title">Project Members</h1>
<vinfo-stub text="" boldtext="The only project role currently available is Admin, which gives full access to the project." class="team-header-container__title-area__info-button">
<vinfo-stub title="" text="" boldtext="The only project role currently available is Admin, which gives full access to the project." buttonlabel="" class="team-header-container__title-area__info-button">
<infoicon-stub class="team-header-container__title-area__info-button__image"></infoicon-stub>
</vinfo-stub>
</div>
@ -79,7 +79,7 @@ exports[`Team HeaderArea renders correctly with opened Add team member popup 1`]
<div class="team-header-container">
<div class="team-header-container__title-area">
<h1 class="team-header-container__title-area__title">Project Members</h1>
<vinfo-stub text="" boldtext="The only project role currently available is Admin, which gives full access to the project." class="team-header-container__title-area__info-button">
<vinfo-stub title="" text="" boldtext="The only project role currently available is Admin, which gives full access to the project." buttonlabel="" class="team-header-container__title-area__info-button">
<infoicon-stub class="team-header-container__title-area__info-button__image"></infoicon-stub>
</vinfo-stub>
</div>
@ -102,7 +102,7 @@ exports[`Team HeaderArea renders correctly with selected users 1`] = `
<div class="team-header-container">
<div class="team-header-container__title-area">
<h1 class="team-header-container__title-area__title">Project Members</h1>
<vinfo-stub text="" boldtext="The only project role currently available is Admin, which gives full access to the project." class="team-header-container__title-area__info-button">
<vinfo-stub title="" text="" boldtext="The only project role currently available is Admin, which gives full access to the project." buttonlabel="" class="team-header-container__title-area__info-button">
<infoicon-stub class="team-header-container__title-area__info-button__image"></infoicon-stub>
</vinfo-stub>
</div>

View File

@ -5,7 +5,7 @@ exports[`Dashboard renders correctly when data is loaded 1`] = `
<!---->
<!---->
<div class="dashboard__wrap">
<!---->
<paidtierbar-stub openaddpmmodal="function () { [native code] }"></paidtierbar-stub>
<!---->
<dashboardheader-stub></dashboardheader-stub>
<div class="dashboard__wrap__main-area">