web/satellite: added create project prompt modal for free tier users

Added new modal when free tier user tries to create new project.
This modal prompts to upgrade account.

Change-Id: I0e787e35b099387a08186c7df7fc080092d2366c
This commit is contained in:
Vitalii 2022-04-13 19:07:16 +03:00 committed by Vitalii Shpital
parent 95ae739d9c
commit aba7de6c32
8 changed files with 176 additions and 4 deletions

View File

@ -60,9 +60,9 @@ func TestNavigation(t *testing.T) {
page.MustElement("[aria-roledescription=project-selection]").MustClick()
page.MustElementR("p", "Create new").MustClick()
waitVueTick(page)
createProjectTitle := page.MustElement("[aria-roledescription=title]").MustText()
require.Contains(t, createProjectTitle, "Create a Project")
page.MustNavigateBack()
createProjectPromptTitle := page.MustElement("[aria-roledescription=modal-title]").MustText()
require.Contains(t, createProjectPromptTitle, "Get more projects\nwhen you upgrade")
page.MustElement(".close-cross-container").MustClick()
// project dashboard route
page.MustElementR("p", "Dashboard").MustClick()

View File

@ -0,0 +1,136 @@
// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="prompt">
<div class="prompt__modal">
<img
class="prompt__modal__icon"
src="@/../static/images/account/billing/paidTier/prompt.png"
alt="Prompt Image"
>
<h1 class="prompt__modal__title" aria-roledescription="modal-title">
Get more projects<br>when you upgrade
</h1>
<p class="prompt__modal__info">
Upgrade your Free Account to create<br>more projects and gain access to higher limits.
</p>
<VButton
width="256px"
height="56px"
border-radius="8px"
label="Upgrade to Pro Account ->"
:on-press="onClick"
/>
<div class="close-cross-container" @click="onClose">
<CloseCrossIcon />
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { APP_STATE_MUTATIONS } from "@/store/mutationConstants";
import { PAYMENTS_MUTATIONS } from "@/store/modules/payments";
import VButton from '@/components/common/VButton.vue';
import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
// @vue/component
@Component({
components: {
VButton,
CloseCrossIcon,
},
})
export default class CreateProjectPromptModal extends Vue {
@Prop({default: () => false})
public readonly onClose: () => void;
/**
* Holds on button click logic.
* Closes this modal and opens upgrade account modal.
*/
public onClick(): void {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_PROJECT_PROMPT_POPUP);
this.$store.commit(PAYMENTS_MUTATIONS.TOGGLE_IS_ADD_PM_MODAL_SHOWN);
}
}
</script>
<style scoped lang="scss">
.prompt {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: 1000;
background: rgb(27 37 51 / 75%);
display: flex;
align-items: center;
justify-content: center;
font-family: 'font_regular', sans-serif;
&__modal {
display: flex;
align-items: center;
flex-direction: column;
background: #fff;
border-radius: 20px;
box-shadow: 0 0 32px rgb(0 0 0 / 4%);
width: 600px;
position: relative;
padding: 50px 0 65px;
&__icon {
max-height: 154px;
max-width: 118px;
}
&__title {
font-family: 'font_bold', sans-serif;
font-size: 28px;
line-height: 34px;
color: #1b2533;
margin-top: 40px;
text-align: center;
}
&__info {
font-family: 'font_regular', sans-serif;
font-size: 16px;
line-height: 21px;
text-align: center;
color: #354049;
margin: 15px 0 45px;
}
}
}
.close-cross-container {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
right: 30px;
top: 30px;
height: 24px;
width: 24px;
cursor: pointer;
&:hover .close-cross-svg-path {
fill: #2683ff;
}
}
@media screen and (max-height: 900px) {
.prompt {
padding: 150px 0 20px;
overflow-y: scroll;
}
}
</style>

View File

@ -64,7 +64,9 @@ import { OBJECTS_ACTIONS } from "@/store/modules/objects";
import { PAYMENTS_ACTIONS } from "@/store/modules/payments";
import { ACCESS_GRANTS_ACTIONS } from "@/store/modules/accessGrants";
import { BUCKET_ACTIONS } from "@/store/modules/buckets";
import { APP_STATE_MUTATIONS } from "@/store/mutationConstants";
import { Project } from "@/types/projects";
import { User } from "@/types/users";
import ProjectIcon from '@/../static/images/navigation/project.svg';
import ArrowImage from '@/../static/images/navigation/arrowExpandRight.svg';
@ -223,7 +225,15 @@ export default class NewProjectSelection extends Vue {
public onCreateLinkClick(): void {
if (this.$route.name !== RouteConfig.CreateProject.name) {
this.analytics.linkEventTriggered(AnalyticsEvent.PATH_SELECTED, "Create New Project");
this.$router.push(RouteConfig.CreateProject.path);
const user: User = this.$store.getters.user;
const ownProjectsCount: number = this.$store.getters.projectsCount;
if (!user.paidTier && user.projectLimit === ownProjectsCount) {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_PROJECT_PROMPT_POPUP);
} else {
this.$router.push(RouteConfig.CreateProject.path);
}
}
this.closeDropdown();

View File

@ -30,6 +30,7 @@ class ViewsState {
public isPaymentSelectionShown = false,
public isUploadCancelPopupVisible = false,
public isSuccessfulPasswordResetShown = false,
public isCreateProjectPromptModalShown = false,
public onbAGStepBackRoute = "",
public onbAPIKeyStepBackRoute = "",
@ -117,6 +118,9 @@ export const appStateModule = {
[APP_STATE_MUTATIONS.TOGGLE_UPLOAD_CANCEL_POPUP](state: State): void {
state.appState.isUploadCancelPopupVisible = !state.appState.isUploadCancelPopupVisible;
},
[APP_STATE_MUTATIONS.TOGGLE_CREATE_PROJECT_PROMPT_POPUP](state: State): void {
state.appState.isCreateProjectPromptModalShown = !state.appState.isCreateProjectPromptModalShown;
},
[APP_STATE_MUTATIONS.SHOW_SET_DEFAULT_PAYMENT_METHOD_POPUP](state: State, id: string): void {
state.appState.setDefaultPaymentMethodID = id;
},

View File

@ -29,6 +29,7 @@ export const APP_STATE_MUTATIONS = {
TOGGLE_EDIT_PROFILE_POPUP: 'TOGGLE_EDIT_PROFILE_POPUP',
TOGGLE_CHANGE_PASSWORD_POPUP: 'TOGGLE_CHANGE_PASSWORD_POPUP',
TOGGLE_UPLOAD_CANCEL_POPUP: 'TOGGLE_UPLOAD_CANCEL_POPUP',
TOGGLE_CREATE_PROJECT_PROMPT_POPUP: 'TOGGLE_CREATE_PROJECT_PROMPT_POPUP',
SHOW_DELETE_PAYMENT_METHOD_POPUP: 'SHOW_DELETE_PAYMENT_METHOD_POPUP',
SHOW_SET_DEFAULT_PAYMENT_METHOD_POPUP: 'SHOW_SET_DEFAULT_PAYMENT_METHOD_POPUP',
CLOSE_ALL: 'CLOSE_ALL',

View File

@ -49,6 +49,8 @@
</div>
</template>
</div>
<!-- TODO: put all the modals to one single wrapper component and move out all the logic from here -->
<CreateProjectPromptModal v-if="isCreateProjectPromptModal" :on-close="toggleCreateProjectPromptModal" />
<AddPaymentMethodModal v-if="isAddPMModal" :on-close="togglePMModal" />
<MFARecoveryCodesPopup v-if="isMFACodesPopup" :toggle-modal="toggleMFACodesPopup" />
</div>
@ -58,6 +60,7 @@
import { Component, Vue } from 'vue-property-decorator';
import AddPaymentMethodModal from '@/components/account/billing/paidTier/AddPaymentMethodModal.vue';
import CreateProjectPromptModal from "@/components/account/billing/paidTier/CreateProjectPromptModal.vue";
import PaidTierBar from '@/components/infoBars/PaidTierBar.vue';
import MFARecoveryCodeBar from '@/components/infoBars/MFARecoveryCodeBar.vue';
import BetaSatBar from '@/components/infoBars/BetaSatBar.vue';
@ -79,6 +82,7 @@ import { CouponType } from '@/types/coupons';
import { CreditCard } from '@/types/payments';
import { Project } from '@/types/projects';
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
import { APP_STATE_MUTATIONS } from "@/store/mutationConstants";
import { AppState } from '@/utils/constants/appStateEnum';
import { LocalData } from '@/utils/localData';
import { User } from "@/types/users";
@ -93,6 +97,7 @@ const {
// @vue/component
@Component({
components: {
CreateProjectPromptModal,
NavigationArea,
NewNavigationArea,
DashboardHeader,
@ -206,6 +211,13 @@ export default class DashboardArea extends Vue {
this.$store.commit(PAYMENTS_MUTATIONS.TOGGLE_IS_ADD_PM_MODAL_SHOWN);
}
/**
* Toggles create project prompt modal.
*/
public toggleCreateProjectPromptModal(): void {
this.$store.commit(APP_STATE_MUTATIONS.TOGGLE_CREATE_PROJECT_PROMPT_POPUP);
}
/**
* Toggles MFA recovery codes popup visibility.
*/
@ -269,6 +281,13 @@ export default class DashboardArea extends Vue {
return this.$store.state.paymentsModule.isAddPMModalShown;
}
/**
* Indicates if create project prompt modal is shown.
*/
public get isCreateProjectPromptModal(): boolean {
return this.$store.state.appStateModule.appState.isCreateProjectPromptModalShown;
}
/**
* Returns credit cards from store.
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -16,6 +16,7 @@ exports[`Dashboard renders correctly when data is loaded 1`] = `
</div>
<!---->
<!---->
<!---->
</div>
`;
@ -27,5 +28,6 @@ exports[`Dashboard renders correctly when data is loading 1`] = `
<!---->
<!---->
<!---->
<!---->
</div>
`;