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:
parent
cd8e9bd044
commit
fe890ff535
@ -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>
|
@ -3,6 +3,12 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-container>
|
<v-container>
|
||||||
|
<low-token-balance-banner
|
||||||
|
v-if="isLowBalance"
|
||||||
|
:cta-label="tab !== 1 ? 'Deposit' : ''"
|
||||||
|
@click="tab = 1"
|
||||||
|
/>
|
||||||
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
<PageTitleComponent title="Account Billing" />
|
<PageTitleComponent title="Account Billing" />
|
||||||
@ -228,13 +234,15 @@ import {
|
|||||||
import { useLoading } from '@/composables/useLoading';
|
import { useLoading } from '@/composables/useLoading';
|
||||||
import { useNotify } from '@/utils/hooks';
|
import { useNotify } from '@/utils/hooks';
|
||||||
import { useBillingStore } from '@/store/modules/billingStore';
|
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 { centsToDollars } from '@/utils/strings';
|
||||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||||
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
|
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
|
||||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||||
import { useConfigStore } from '@/store/modules/configStore';
|
import { useConfigStore } from '@/store/modules/configStore';
|
||||||
import { Download } from '@/utils/download';
|
import { Download } from '@/utils/download';
|
||||||
|
import { useLowTokenBalance } from '@/composables/useLowTokenBalance';
|
||||||
|
import { Project } from '@/types/projects';
|
||||||
|
|
||||||
import PageTitleComponent from '@poc/components/PageTitleComponent.vue';
|
import PageTitleComponent from '@poc/components/PageTitleComponent.vue';
|
||||||
import CreditCardComponent from '@poc/components/CreditCardComponent.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 StorjTokenCardComponent from '@poc/components/StorjTokenCardComponent.vue';
|
||||||
import TokenTransactionsTableComponent from '@poc/components/TokenTransactionsTableComponent.vue';
|
import TokenTransactionsTableComponent from '@poc/components/TokenTransactionsTableComponent.vue';
|
||||||
import ApplyCouponCodeDialog from '@poc/components/dialogs/ApplyCouponCodeDialog.vue';
|
import ApplyCouponCodeDialog from '@poc/components/dialogs/ApplyCouponCodeDialog.vue';
|
||||||
|
import LowTokenBalanceBanner from '@poc/components/LowTokenBalanceBanner.vue';
|
||||||
|
|
||||||
const tab = ref(0);
|
const tab = ref(0);
|
||||||
const billingStore = useBillingStore();
|
const billingStore = useBillingStore();
|
||||||
@ -252,6 +261,7 @@ const configStore = useConfigStore();
|
|||||||
|
|
||||||
const { isLoading, withLoading } = useLoading();
|
const { isLoading, withLoading } = useLoading();
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
|
const isLowBalance = useLowTokenBalance();
|
||||||
|
|
||||||
const isRollupLoading = ref(true);
|
const isRollupLoading = ref(true);
|
||||||
const isAddCouponDialogShown = ref<boolean>(false);
|
const isAddCouponDialogShown = ref<boolean>(false);
|
||||||
@ -341,14 +351,20 @@ function goToTransactionsTab() {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
withLoading(async () => {
|
withLoading(async () => {
|
||||||
try {
|
const promises: Promise<void | Project[] | AccountBalance | CreditCard[]>[] = [
|
||||||
await Promise.all([
|
|
||||||
billingStore.getBalance(),
|
billingStore.getBalance(),
|
||||||
billingStore.getCoupon(),
|
billingStore.getCoupon(),
|
||||||
billingStore.getCreditCards(),
|
billingStore.getCreditCards(),
|
||||||
projectsStore.getProjects(),
|
projectsStore.getProjects(),
|
||||||
billingStore.getProjectUsagePriceModel(),
|
billingStore.getProjectUsagePriceModel(),
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
if (configStore.state.config.nativeTokenPaymentsEnabled) {
|
||||||
|
promises.push(billingStore.getNativePaymentsHistory());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Promise.all(promises);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notify.notifyError(error, AnalyticsErrorEventSource.BILLING_AREA);
|
notify.notifyError(error, AnalyticsErrorEventSource.BILLING_AREA);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-container>
|
<v-container>
|
||||||
|
<low-token-balance-banner
|
||||||
|
v-if="isLowBalance && billingEnabled"
|
||||||
|
cta-label="Go to billing"
|
||||||
|
@click="redirectToBilling"
|
||||||
|
/>
|
||||||
<limit-warning-banners v-if="billingEnabled" />
|
<limit-warning-banners v-if="billingEnabled" />
|
||||||
<v-row v-if="promptForPassphrase && !bucketWasCreated" class="my-0">
|
<v-row v-if="promptForPassphrase && !bucketWasCreated" class="my-0">
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
@ -192,7 +197,18 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
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 { ComponentPublicInstance } from '@vue/runtime-core';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
@ -212,6 +228,9 @@ import { LocalData } from '@/utils/localData';
|
|||||||
import { ProjectMembersPage } from '@/types/projectMembers';
|
import { ProjectMembersPage } from '@/types/projectMembers';
|
||||||
import { AccessGrantsPage } from '@/types/accessGrants';
|
import { AccessGrantsPage } from '@/types/accessGrants';
|
||||||
import { useConfigStore } from '@/store/modules/configStore';
|
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 PageTitleComponent from '@poc/components/PageTitleComponent.vue';
|
||||||
import PageSubtitleComponent from '@poc/components/PageSubtitleComponent.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 IconCloud from '@poc/components/icons/IconCloud.vue';
|
||||||
import IconArrowDown from '@poc/components/icons/IconArrowDown.vue';
|
import IconArrowDown from '@poc/components/icons/IconArrowDown.vue';
|
||||||
import LimitWarningBanners from '@poc/components/LimitWarningBanners.vue';
|
import LimitWarningBanners from '@poc/components/LimitWarningBanners.vue';
|
||||||
|
import LowTokenBalanceBanner from '@poc/components/LowTokenBalanceBanner.vue';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const usersStore = useUsersStore();
|
const usersStore = useUsersStore();
|
||||||
@ -238,6 +258,7 @@ const configStore = useConfigStore();
|
|||||||
|
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const isLowBalance = useLowTokenBalance();
|
||||||
|
|
||||||
const bucketWasCreated = !!LocalData.getBucketWasCreatedStatus();
|
const bucketWasCreated = !!LocalData.getBucketWasCreatedStatus();
|
||||||
|
|
||||||
@ -494,7 +515,14 @@ function onCouponCTAClicked(): void {
|
|||||||
return;
|
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();
|
const past = new Date();
|
||||||
past.setDate(past.getDate() - 30);
|
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.getDailyProjectData({ since: past, before: now }),
|
||||||
projectsStore.getProjectLimits(projectID),
|
projectsStore.getProjectLimits(projectID),
|
||||||
pmStore.getProjectMembers(FIRST_PAGE, projectID),
|
pmStore.getProjectMembers(FIRST_PAGE, projectID),
|
||||||
@ -524,10 +552,16 @@ onMounted(async (): Promise<void> => {
|
|||||||
promises = [
|
promises = [
|
||||||
...promises,
|
...promises,
|
||||||
billingStore.getProjectUsageAndChargesCurrentRollup(),
|
billingStore.getProjectUsageAndChargesCurrentRollup(),
|
||||||
|
billingStore.getBalance(),
|
||||||
|
billingStore.getCreditCards(),
|
||||||
billingStore.getCoupon(),
|
billingStore.getCoupon(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configStore.state.config.nativeTokenPaymentsEnabled) {
|
||||||
|
promises.push(billingStore.getNativePaymentsHistory());
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-container>
|
<v-container>
|
||||||
|
<low-token-balance-banner
|
||||||
|
v-if="isLowBalance && billingEnabled"
|
||||||
|
cta-label="Go to billing"
|
||||||
|
@click="redirectToBilling"
|
||||||
|
/>
|
||||||
<PageTitleComponent title="My Projects" />
|
<PageTitleComponent title="My Projects" />
|
||||||
<!-- <PageSubtitleComponent subtitle="Projects are where you and your team can upload and manage data, view usage statistics and billing."/> -->
|
<!-- <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,
|
VBtnToggle,
|
||||||
VProgressCircular,
|
VProgressCircular,
|
||||||
} from 'vuetify/components';
|
} from 'vuetify/components';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { ProjectItemModel } from '@poc/types/projects';
|
import { ProjectItemModel } from '@poc/types/projects';
|
||||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||||
import { useUsersStore } from '@/store/modules/usersStore';
|
import { useUsersStore } from '@/store/modules/usersStore';
|
||||||
import { ProjectRole } from '@/types/projectMembers';
|
import { ProjectRole } from '@/types/projectMembers';
|
||||||
import { useAppStore } from '@/store/modules/appStore';
|
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 ProjectCard from '@poc/components/ProjectCard.vue';
|
||||||
import PageTitleComponent from '@poc/components/PageTitleComponent.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 AddTeamMemberDialog from '@poc/components/dialogs/AddTeamMemberDialog.vue';
|
||||||
import IconCardView from '@poc/components/icons/IconCardView.vue';
|
import IconCardView from '@poc/components/icons/IconCardView.vue';
|
||||||
import IconTableView from '@poc/components/icons/IconTableView.vue';
|
import IconTableView from '@poc/components/icons/IconTableView.vue';
|
||||||
|
import LowTokenBalanceBanner from '@poc/components/LowTokenBalanceBanner.vue';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const projectsStore = useProjectsStore();
|
const projectsStore = useProjectsStore();
|
||||||
const usersStore = useUsersStore();
|
const usersStore = useUsersStore();
|
||||||
|
const configStore = useConfigStore();
|
||||||
|
const billingStore = useBillingStore();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const isLowBalance = useLowTokenBalance();
|
||||||
|
|
||||||
const isLoading = ref<boolean>(true);
|
const isLoading = ref<boolean>(true);
|
||||||
|
|
||||||
const joiningItem = ref<ProjectItemModel | null>(null);
|
const joiningItem = ref<ProjectItemModel | null>(null);
|
||||||
const isJoinProjectDialogShown = ref<boolean>(false);
|
const isJoinProjectDialogShown = ref<boolean>(false);
|
||||||
const isCreateProjectDialogShown = ref<boolean>(false);
|
const isCreateProjectDialogShown = ref<boolean>(false);
|
||||||
const addMemberProjectId = ref<string>('');
|
const addMemberProjectId = ref<string>('');
|
||||||
const isAddMemberDialogShown = ref<boolean>(false);
|
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.
|
* Returns whether to use the table view.
|
||||||
*/
|
*/
|
||||||
@ -176,6 +196,13 @@ const items = computed((): ProjectItemModel[] => {
|
|||||||
return projects;
|
return projects;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirects to Billing Page tab.
|
||||||
|
*/
|
||||||
|
function redirectToBilling(): void {
|
||||||
|
router.push({ name: RouteName.Billing });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the Join Project modal.
|
* Displays the Join Project modal.
|
||||||
*/
|
*/
|
||||||
@ -198,5 +225,13 @@ onMounted(async (): Promise<void> => {
|
|||||||
await projectsStore.getUserInvitations().catch(_ => {});
|
await projectsStore.getUserInvitations().catch(_ => {});
|
||||||
|
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
|
|
||||||
|
if (configStore.state.config.nativeTokenPaymentsEnabled && configStore.state.config.billingFeaturesEnabled) {
|
||||||
|
Promise.all([
|
||||||
|
billingStore.getBalance(),
|
||||||
|
billingStore.getCreditCards(),
|
||||||
|
billingStore.getNativePaymentsHistory(),
|
||||||
|
]).catch(_ => {});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user