Skip to content

Commit

Permalink
web/satellite/v2: add partner upgrade banner to project dashboard
Browse files Browse the repository at this point in the history
This change adds a banner that prompt eligible users to upgrade their
account with their corresponding partner. Also, some minor changes to
the upgrade dialog are made, particularly the success notice of the
pricing plan step.

Issue: storj/storj-private#559

Change-Id: I580e13dbd3ea7c676e96dfa68768c184ec536400
  • Loading branch information
wilfred-asomanii authored and Storj Robot committed Jan 26, 2024
1 parent 8258809 commit 2c9c698
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 15 deletions.
2 changes: 2 additions & 0 deletions web/satellite/src/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export class PricingPlanInfo {
public activationPriceHTML: string | null = null,
// Info for the pricing plan modal (post-activation)
public successSubtitle: string = '',
public bannerTitle: string = '',
public bannerText: string = '',
) {}
}

Expand Down
3 changes: 2 additions & 1 deletion web/satellite/src/types/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export class UserSettings {
public onboardingEnd = false,
public passphrasePrompt = true,
public onboardingStep: string | null = null,
public noticeDismissal: NoticeDismissal = { fileGuide: false, serverSideEncryption: false },
public noticeDismissal: NoticeDismissal = { fileGuide: false, serverSideEncryption: false, partnerUpgradeBanner: false },
) { }

public get sessionDuration(): Duration | null {
Expand All @@ -210,6 +210,7 @@ export class UserSettings {
export interface NoticeDismissal {
fileGuide: boolean
serverSideEncryption: boolean
partnerUpgradeBanner: boolean
}

export interface SetUserSettingsData {
Expand Down
35 changes: 35 additions & 0 deletions web/satellite/vuetify-poc/src/components/NextStepsContainer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (C) 2024 Storj Labs, Inc.
// See LICENSE for copying information.

<template>
<div v-if="!hideContainer">
<h5 class="text-h5 font-weight-bold">Welcome {{ user.fullName }}!</h5>
<p class="my-3">Your next steps</p>

<partner-upgrade-notice-banner v-model="partnerBannerVisible" />
</div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { User } from '@/types/users';
import { useUsersStore } from '@/store/modules/usersStore';
import PartnerUpgradeNoticeBanner from '@poc/components/PartnerUpgradeNoticeBanner.vue';
const usersStore = useUsersStore();
const partnerBannerVisible = ref(true);
const hideContainer = ref(false);
const user = computed<User>(() => usersStore.state.user);
// hide container when no content is visible.
watch(partnerBannerVisible, (value) => {
if (!value) {
// hide container when no content is visible
hideContainer.value = true;
}
});
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright (C) 2024 Storj Labs, Inc.
// See LICENSE for copying information.

<template>
<v-alert
v-if="!isLoading && planInfo"
:model-value="model"
:title="planInfo.bannerTitle"
closable
variant="tonal"
type="success"
rounded="lg"
class="mt-2 mb-4"
@click:close="dismiss"
>
<template #prepend />
<template #text>
<p>
{{ planInfo.bannerText }}
</p>
<v-btn
class="mt-2"
color="success"
@click="toggleUpgradeDialog"
>
Learn More
</v-btn>
</template>
</v-alert>

<upgrade-account-dialog
ref="upgradeDialog"
v-model="isUpgradeDialogShown"
/>
</template>

<script setup lang="ts">
import { VAlert, VBtn } from 'vuetify/components';
import { computed, onBeforeMount, ref, watch } from 'vue';
import { User } from '@/types/users';
import { PricingPlanInfo } from '@/types/common';
import { useUsersStore } from '@/store/modules/usersStore';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import { useNotify } from '@/utils/hooks';
import { useConfigStore } from '@/store/modules/configStore';
import { PaymentsHttpApi } from '@/api/payments';
import { useLoading } from '@/composables/useLoading';
import UpgradeAccountDialog from '@poc/components/dialogs/upgradeAccountFlow/UpgradeAccountDialog.vue';
const payments: PaymentsHttpApi = new PaymentsHttpApi();
const configStore = useConfigStore();
const usersStore = useUsersStore();
const { isLoading, withLoading } = useLoading();
const notify = useNotify();
const isUpgradeDialogShown = ref<boolean>(false);
const planInfo = ref<PricingPlanInfo>();
const upgradeDialog = ref<{ setSecondStep: ()=>void }>();
const props = defineProps<{
modelValue: boolean,
}>();
const model = computed<boolean>({
get: () => props.modelValue,
set: value => emit('update:modelValue', value),
});
const emit = defineEmits<{
(event: 'update:modelValue', value: boolean): void,
}>();
async function dismiss() {
model.value = false;
try {
const noticeDismissal = { ...usersStore.state.settings.noticeDismissal };
noticeDismissal.partnerUpgradeBanner = true;
await usersStore.updateSettings({ noticeDismissal });
} catch (error) {
notify.notifyError(error, AnalyticsErrorEventSource.PROJECT_DASHBOARD_PAGE);
}
}
function toggleUpgradeDialog() {
// go to the second step, which in this case
// will be the pricing plan selection step.
upgradeDialog.value?.setSecondStep();
isUpgradeDialogShown.value = true;
}
onBeforeMount(() => {
withLoading(async () => {
if (!configStore.state.config.billingFeaturesEnabled
|| !configStore.state.config.pricingPackagesEnabled
|| usersStore.noticeDismissal.partnerUpgradeBanner) {
model.value = false;
return;
}
const user: User = usersStore.state.user;
if (user.paidTier || !user.partner) {
model.value = false;
return;
}
try {
model.value = await payments.pricingPackageAvailable();
} catch (error) {
notify.notifyError(error, AnalyticsErrorEventSource.PROJECT_DASHBOARD_PAGE);
model.value = false;
return;
}
let config;
try {
config = (await import('@/components/account/billing/pricingPlans/pricingPlanConfig.json')).default;
} catch {
model.value = false;
return;
}
planInfo.value = config[user.partner] as PricingPlanInfo;
if (!planInfo.value) {
model.value = false;
return;
}
model.value = true;
});
});
watch(() => [usersStore.state.user.paidTier, isUpgradeDialogShown.value], (value) => {
if (value[0] && !value[1]) {
// throttle the banner dismissal for the dialog close animation.
setTimeout(() => model.value = false, 500);
}
});
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ onBeforeMount(async () => {
];
}
const user: User = usersStore.state.user;
if (user.paidTier || !user.partner) {
isLoading.value = false;
return;
}
let config;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,24 @@

<p class="text-center mb-4">Your plan has been successfully activated.</p>

<v-row align="center" justify="space-between" class="ma-0 mb-4 pa-2 border-sm rounded-lg">
<v-col cols="auto">
<v-icon color="success" :icon="mdiCheckOutline" />
</v-col>
<v-col cols="auto">
<span class="text-body-1 font-weight-bold">
<v-alert
class="mb-4"
type="success"
variant="tonal"
>
<template #prepend>
<v-icon :icon="mdiCheckOutline" />
</template>
<template #text>
<p class="font-weight-bold">
{{ plan.title }}
<span v-if="plan.activationSubtitle" class="font-weight-regular"> / {{ plan.successSubtitle }}</span>
</span>
</v-col>
<v-col cols="auto">
<span style="color: var(--c-green-5);">Activated</span>
</v-col>
</v-row>
</p>
<p v-if="plan.activationSubtitle">{{ plan.activationSubtitle }}</p>
</template>
<template #append>
<span>Activated</span>
</template>
</v-alert>

<v-btn
color="success"
Expand All @@ -115,7 +119,7 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import { VBtn, VCol, VIcon, VRow } from 'vuetify/components';
import { VAlert, VBtn, VCol, VIcon, VRow } from 'vuetify/components';
import { useTheme } from 'vuetify';
import { mdiCheckOutline, mdiLock } from '@mdi/js';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,4 +240,6 @@ watch(content, (value) => {
return;
}
});
defineExpose({ setSecondStep });
</script>
3 changes: 3 additions & 0 deletions web/satellite/vuetify-poc/src/views/Dashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
</v-col>
</v-row>

<next-steps-container />

<v-row align="center" justify="space-between">
<v-col cols="12" md="auto">
<PageTitleComponent title="Project Dashboard" />
Expand Down Expand Up @@ -302,6 +304,7 @@ import LimitWarningBanners from '@poc/components/LimitWarningBanners.vue';
import LowTokenBalanceBanner from '@poc/components/LowTokenBalanceBanner.vue';
import IconUpgrade from '@poc/components/icons/IconUpgrade.vue';
import IconCirclePlus from '@poc/components/icons/IconCirclePlus.vue';
import NextStepsContainer from '@poc/components/NextStepsContainer.vue';
const appStore = useAppStore();
const usersStore = useUsersStore();
Expand Down

0 comments on commit 2c9c698

Please sign in to comment.