web/satellite/vuetify-poc: add low token balance banner

Added low token balance banner to vuetify app with the same logic as in main app.

Issue:
https://github.com/storj/storj/issues/6460

Change-Id: Ifa9af8e2179ec3a6601b5053575990b86cc8f0b5
This commit is contained in:
Vitalii 2023-11-06 15:49:08 +02:00
parent cd8e9bd044
commit fe890ff535
4 changed files with 132 additions and 12 deletions

View File

@ -0,0 +1,35 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<v-alert
closable
variant="tonal"
type="warning"
rounded="lg"
class="mt-2 mb-4"
border
>
<template #default>
<v-row class="ma-0 flex-nowrap justify-space-between align-center">
<p>
Your STORJ Token balance is low. Deposit more STORJ tokens or make sure you have a credit card
on file to avoid interruptions in service.
</p>
<p class="ml-2 text-cursor-pointer text-no-wrap text-decoration-underline" @click="() => emits('click')">{{ ctaLabel }}</p>
</v-row>
</template>
</v-alert>
</template>
<script setup lang="ts">
import { VAlert, VRow } from 'vuetify/components';
const props = defineProps<{
ctaLabel: string
}>();
const emits = defineEmits<{
click: [],
}>();
</script>

View File

@ -3,6 +3,12 @@
<template>
<v-container>
<low-token-balance-banner
v-if="isLowBalance"
:cta-label="tab !== 1 ? 'Deposit' : ''"
@click="tab = 1"
/>
<v-row>
<v-col>
<PageTitleComponent title="Account Billing" />
@ -228,13 +234,15 @@ import {
import { useLoading } from '@/composables/useLoading';
import { useNotify } from '@/utils/hooks';
import { useBillingStore } from '@/store/modules/billingStore';
import { Coupon, CouponDuration, CreditCard } from '@/types/payments';
import { AccountBalance, Coupon, CouponDuration, CreditCard } from '@/types/payments';
import { centsToDollars } from '@/utils/strings';
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { useConfigStore } from '@/store/modules/configStore';
import { Download } from '@/utils/download';
import { useLowTokenBalance } from '@/composables/useLowTokenBalance';
import { Project } from '@/types/projects';
import PageTitleComponent from '@poc/components/PageTitleComponent.vue';
import CreditCardComponent from '@poc/components/CreditCardComponent.vue';
@ -244,6 +252,7 @@ import UsageAndChargesComponent from '@poc/components/billing/UsageAndChargesCom
import StorjTokenCardComponent from '@poc/components/StorjTokenCardComponent.vue';
import TokenTransactionsTableComponent from '@poc/components/TokenTransactionsTableComponent.vue';
import ApplyCouponCodeDialog from '@poc/components/dialogs/ApplyCouponCodeDialog.vue';
import LowTokenBalanceBanner from '@poc/components/LowTokenBalanceBanner.vue';
const tab = ref(0);
const billingStore = useBillingStore();
@ -252,6 +261,7 @@ const configStore = useConfigStore();
const { isLoading, withLoading } = useLoading();
const notify = useNotify();
const isLowBalance = useLowTokenBalance();
const isRollupLoading = ref(true);
const isAddCouponDialogShown = ref<boolean>(false);
@ -341,14 +351,20 @@ function goToTransactionsTab() {
onMounted(async () => {
withLoading(async () => {
const promises: Promise<void | Project[] | AccountBalance | CreditCard[]>[] = [
billingStore.getBalance(),
billingStore.getCoupon(),
billingStore.getCreditCards(),
projectsStore.getProjects(),
billingStore.getProjectUsagePriceModel(),
];
if (configStore.state.config.nativeTokenPaymentsEnabled) {
promises.push(billingStore.getNativePaymentsHistory());
}
try {
await Promise.all([
billingStore.getBalance(),
billingStore.getCoupon(),
billingStore.getCreditCards(),
projectsStore.getProjects(),
billingStore.getProjectUsagePriceModel(),
]);
await Promise.all(promises);
} catch (error) {
notify.notifyError(error, AnalyticsErrorEventSource.BILLING_AREA);
}

View File

@ -3,6 +3,11 @@
<template>
<v-container>
<low-token-balance-banner
v-if="isLowBalance && billingEnabled"
cta-label="Go to billing"
@click="redirectToBilling"
/>
<limit-warning-banners v-if="billingEnabled" />
<v-row v-if="promptForPassphrase && !bucketWasCreated" class="my-0">
<v-col cols="12">
@ -192,7 +197,18 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
import { VBtn, VCard, VCardTitle, VCardText, VCol, VContainer, VRow, VBadge, VIcon, VTooltip } from 'vuetify/components';
import {
VBtn,
VCard,
VCardTitle,
VCardText,
VCol,
VContainer,
VRow,
VBadge,
VIcon,
VTooltip,
} from 'vuetify/components';
import { ComponentPublicInstance } from '@vue/runtime-core';
import { useRouter } from 'vue-router';
@ -212,6 +228,9 @@ import { LocalData } from '@/utils/localData';
import { ProjectMembersPage } from '@/types/projectMembers';
import { AccessGrantsPage } from '@/types/accessGrants';
import { useConfigStore } from '@/store/modules/configStore';
import { useLowTokenBalance } from '@/composables/useLowTokenBalance';
import { RouteName } from '@poc/router';
import { AccountBalance, CreditCard } from '@/types/payments';
import PageTitleComponent from '@poc/components/PageTitleComponent.vue';
import PageSubtitleComponent from '@poc/components/PageSubtitleComponent.vue';
@ -226,6 +245,7 @@ import ManagePassphraseDialog from '@poc/components/dialogs/ManagePassphraseDial
import IconCloud from '@poc/components/icons/IconCloud.vue';
import IconArrowDown from '@poc/components/icons/IconArrowDown.vue';
import LimitWarningBanners from '@poc/components/LimitWarningBanners.vue';
import LowTokenBalanceBanner from '@poc/components/LowTokenBalanceBanner.vue';
const appStore = useAppStore();
const usersStore = useUsersStore();
@ -238,6 +258,7 @@ const configStore = useConfigStore();
const notify = useNotify();
const router = useRouter();
const isLowBalance = useLowTokenBalance();
const bucketWasCreated = !!LocalData.getBucketWasCreatedStatus();
@ -494,7 +515,14 @@ function onCouponCTAClicked(): void {
return;
}
router.push('/account/billing');
redirectToBilling();
}
/**
* Redirects to Billing Page tab.
*/
function redirectToBilling(): void {
router.push({ name: RouteName.Billing });
}
/**
@ -512,7 +540,7 @@ onMounted(async (): Promise<void> => {
const past = new Date();
past.setDate(past.getDate() - 30);
let promises: Promise<void | ProjectMembersPage | AccessGrantsPage>[] = [
let promises: Promise<void | ProjectMembersPage | AccessGrantsPage | AccountBalance | CreditCard[]>[] = [
projectsStore.getDailyProjectData({ since: past, before: now }),
projectsStore.getProjectLimits(projectID),
pmStore.getProjectMembers(FIRST_PAGE, projectID),
@ -524,10 +552,16 @@ onMounted(async (): Promise<void> => {
promises = [
...promises,
billingStore.getProjectUsageAndChargesCurrentRollup(),
billingStore.getBalance(),
billingStore.getCreditCards(),
billingStore.getCoupon(),
];
}
if (configStore.state.config.nativeTokenPaymentsEnabled) {
promises.push(billingStore.getNativePaymentsHistory());
}
try {
await Promise.all(promises);
} catch (error) {

View File

@ -3,6 +3,11 @@
<template>
<v-container>
<low-token-balance-banner
v-if="isLowBalance && billingEnabled"
cta-label="Go to billing"
@click="redirectToBilling"
/>
<PageTitleComponent title="My Projects" />
<!-- <PageSubtitleComponent subtitle="Projects are where you and your team can upload and manage data, view usage statistics and billing."/> -->
@ -105,12 +110,17 @@ import {
VBtnToggle,
VProgressCircular,
} from 'vuetify/components';
import { useRouter } from 'vue-router';
import { ProjectItemModel } from '@poc/types/projects';
import { useProjectsStore } from '@/store/modules/projectsStore';
import { useUsersStore } from '@/store/modules/usersStore';
import { ProjectRole } from '@/types/projectMembers';
import { useAppStore } from '@/store/modules/appStore';
import { useLowTokenBalance } from '@/composables/useLowTokenBalance';
import { useConfigStore } from '@/store/modules/configStore';
import { useBillingStore } from '@/store/modules/billingStore';
import { RouteName } from '@poc/router';
import ProjectCard from '@poc/components/ProjectCard.vue';
import PageTitleComponent from '@poc/components/PageTitleComponent.vue';
@ -120,19 +130,29 @@ import CreateProjectDialog from '@poc/components/dialogs/CreateProjectDialog.vue
import AddTeamMemberDialog from '@poc/components/dialogs/AddTeamMemberDialog.vue';
import IconCardView from '@poc/components/icons/IconCardView.vue';
import IconTableView from '@poc/components/icons/IconTableView.vue';
import LowTokenBalanceBanner from '@poc/components/LowTokenBalanceBanner.vue';
const appStore = useAppStore();
const projectsStore = useProjectsStore();
const usersStore = useUsersStore();
const configStore = useConfigStore();
const billingStore = useBillingStore();
const router = useRouter();
const isLowBalance = useLowTokenBalance();
const isLoading = ref<boolean>(true);
const joiningItem = ref<ProjectItemModel | null>(null);
const isJoinProjectDialogShown = ref<boolean>(false);
const isCreateProjectDialogShown = ref<boolean>(false);
const addMemberProjectId = ref<string>('');
const isAddMemberDialogShown = ref<boolean>(false);
/**
* Indicates if billing features are enabled.
*/
const billingEnabled = computed<boolean>(() => configStore.state.config.billingFeaturesEnabled);
/**
* Returns whether to use the table view.
*/
@ -176,6 +196,13 @@ const items = computed((): ProjectItemModel[] => {
return projects;
});
/**
* Redirects to Billing Page tab.
*/
function redirectToBilling(): void {
router.push({ name: RouteName.Billing });
}
/**
* Displays the Join Project modal.
*/
@ -198,5 +225,13 @@ onMounted(async (): Promise<void> => {
await projectsStore.getUserInvitations().catch(_ => {});
isLoading.value = false;
if (configStore.state.config.nativeTokenPaymentsEnabled && configStore.state.config.billingFeaturesEnabled) {
Promise.all([
billingStore.getBalance(),
billingStore.getCreditCards(),
billingStore.getNativePaymentsHistory(),
]).catch(_ => {});
}
});
</script>