web/satellite: extend low token balance banner use-case
Updated condition on when this banner should be shown. Also, added this banner to project dashboard and billing pages. Issue: https://github.com/storj/storj/issues/6356 https://github.com/storj/storj/issues/6368 Change-Id: I2f8f587a3c75508df0a9a6e84e1684b3c3904aa7
This commit is contained in:
parent
4cbdc0342a
commit
40e43826a9
@ -53,6 +53,7 @@ type FrontendConfig struct {
|
||||
BillingFeaturesEnabled bool `json:"billingFeaturesEnabled"`
|
||||
UnregisteredInviteEmailsEnabled bool `json:"unregisteredInviteEmailsEnabled"`
|
||||
FreeTierInvitesEnabled bool `json:"freeTierInvitesEnabled"`
|
||||
UserBalanceForUpgrade int64 `json:"userBalanceForUpgrade"`
|
||||
}
|
||||
|
||||
// Satellites is a configuration value that contains a list of satellite names and addresses.
|
||||
|
@ -753,6 +753,7 @@ func (server *Server) frontendConfigHandler(w http.ResponseWriter, r *http.Reque
|
||||
BillingFeaturesEnabled: server.config.BillingFeaturesEnabled,
|
||||
UnregisteredInviteEmailsEnabled: server.config.UnregisteredInviteEmailsEnabled,
|
||||
FreeTierInvitesEnabled: server.config.FreeTierInvitesEnabled,
|
||||
UserBalanceForUpgrade: server.config.UserBalanceForUpgrade,
|
||||
}
|
||||
|
||||
err := json.NewEncoder(w).Encode(&cfg)
|
||||
|
@ -2,60 +2,80 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="account-billing-area">
|
||||
<div class="account-billing-area__header__div">
|
||||
<div class="account-billing-area__title">
|
||||
<h1 class="account-billing-area__title__text">Billing</h1>
|
||||
<div ref="content" class="account-billing-area">
|
||||
<div class="account-billing-area__wrap">
|
||||
<div class="account-billing-area__wrap__title">
|
||||
<h1 class="account-billing-area__wrap__title__text">Billing</h1>
|
||||
</div>
|
||||
<div class="account-billing-area__header">
|
||||
<v-banner
|
||||
v-if="isLowBalance && content"
|
||||
class="account-billing-area__wrap__low-balance"
|
||||
message="Your STORJ Token balance is low. Deposit more STORJ tokens or add a credit card to avoid interruptions in service."
|
||||
link-text="Deposit tokens"
|
||||
severity="warning"
|
||||
:dashboard-ref="content"
|
||||
:on-link-click="onAddTokensClick"
|
||||
/>
|
||||
<div class="account-billing-area__wrap__header">
|
||||
<div
|
||||
:class="`account-billing-area__header__tab first-header-tab ${routeHas('overview') ? 'selected-tab' : ''}`"
|
||||
:class="`account-billing-area__wrap__header__tab first-header-tab ${routeHas('overview') ? 'selected-tab' : ''}`"
|
||||
@click="routeToOverview"
|
||||
>
|
||||
<p>Overview</p>
|
||||
</div>
|
||||
<div
|
||||
:class="`account-billing-area__header__tab ${routeHas('methods') ? 'selected-tab' : ''}`"
|
||||
:class="`account-billing-area__wrap__header__tab ${routeHas('methods') ? 'selected-tab' : ''}`"
|
||||
@click="routeToPaymentMethods"
|
||||
>
|
||||
<p>Payment Methods</p>
|
||||
</div>
|
||||
<div
|
||||
:class="`account-billing-area__header__tab ${routeHas('history') ? 'selected-tab' : ''}`"
|
||||
:class="`account-billing-area__wrap__header__tab ${routeHas('history') ? 'selected-tab' : ''}`"
|
||||
@click="routeToBillingHistory"
|
||||
>
|
||||
<p>Billing History</p>
|
||||
</div>
|
||||
<div
|
||||
:class="`account-billing-area__header__tab last-header-tab ${routeHas('coupons') ? 'selected-tab' : ''}`"
|
||||
:class="`account-billing-area__wrap__header__tab last-header-tab ${routeHas('coupons') ? 'selected-tab' : ''}`"
|
||||
@click="routeToCoupons"
|
||||
>
|
||||
<p>Coupons</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="account-billing-area__divider" />
|
||||
<div class="account-billing-area__wrap__divider" />
|
||||
</div>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { RouteConfig } from '@/types/router';
|
||||
import { APP_STATE_DROPDOWNS } from '@/utils/constants/appStatePopUps';
|
||||
import { APP_STATE_DROPDOWNS, MODALS } from '@/utils/constants/appStatePopUps';
|
||||
import { NavigationLink } from '@/types/navigation';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
|
||||
import { useBillingStore } from '@/store/modules/billingStore';
|
||||
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
import { useLowTokenBalance } from '@/composables/useLowTokenBalance';
|
||||
|
||||
import VBanner from '@/components/common/VBanner.vue';
|
||||
|
||||
const analyticsStore = useAnalyticsStore();
|
||||
const appStore = useAppStore();
|
||||
const billingStore = useBillingStore();
|
||||
const configStore = useConfigStore();
|
||||
|
||||
const notify = useNotify();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const isLowBalance = useLowTokenBalance();
|
||||
|
||||
const content = ref<HTMLElement | null>(null);
|
||||
|
||||
/**
|
||||
* Indicates if free credits dropdown shown.
|
||||
@ -89,6 +109,15 @@ const baseAccountRoute = computed((): NavigationLink => {
|
||||
return RouteConfig.Account;
|
||||
});
|
||||
|
||||
/**
|
||||
* Holds on add tokens button click logic.
|
||||
* Triggers Add funds popup.
|
||||
*/
|
||||
function onAddTokensClick(): void {
|
||||
analyticsStore.eventTriggered(AnalyticsEvent.ADD_FUNDS_CLICKED);
|
||||
appStore.updateActiveModal(MODALS.addTokenFunds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether current route name contains term.
|
||||
*/
|
||||
@ -139,93 +168,33 @@ function routeToCoupons(): void {
|
||||
router.push(couponsPath);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (!configStore.state.config.nativeTokenPaymentsEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await Promise.all([
|
||||
billingStore.getBalance(),
|
||||
billingStore.getCreditCards(),
|
||||
billingStore.getNativePaymentsHistory(),
|
||||
]);
|
||||
} catch (error) {
|
||||
notify.notifyError(error, AnalyticsErrorEventSource.BILLING_AREA);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.label-header {
|
||||
display: none;
|
||||
}
|
||||
.selected-tab {
|
||||
border-bottom: 5px solid black;
|
||||
}
|
||||
|
||||
.credit-history {
|
||||
.account-billing-area {
|
||||
padding-bottom: 40px;
|
||||
|
||||
&__coupon-modal-wrapper {
|
||||
background: #1b2533c7 75%;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
&__coupon-modal {
|
||||
width: 741px;
|
||||
height: 298px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
margin: 15% auto;
|
||||
position: relative;
|
||||
|
||||
&__header-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__header {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
line-height: 148.31%;
|
||||
margin: 30px 0 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&__input-wrapper {
|
||||
position: relative;
|
||||
width: 85%;
|
||||
margin: 0 auto;
|
||||
|
||||
.headerless-input::placeholder {
|
||||
color: #384b65;
|
||||
opacity: 0.4;
|
||||
position: relative;
|
||||
left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&__claim-button {
|
||||
position: absolute;
|
||||
bottom: 11px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
&__apply-button {
|
||||
width: 85%;
|
||||
height: 44px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
bottom: 50px;
|
||||
background: #93a1af;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
position: absolute;
|
||||
top: 90px;
|
||||
z-index: 1;
|
||||
left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.selected-tab {
|
||||
border-bottom: 5px solid black;
|
||||
}
|
||||
|
||||
.account-billing-area {
|
||||
padding-bottom: 40px;
|
||||
&__wrap {
|
||||
|
||||
&__title {
|
||||
padding-top: 20px;
|
||||
@ -235,9 +204,8 @@ function routeToCoupons(): void {
|
||||
}
|
||||
}
|
||||
|
||||
&__divider {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #dadfe7;
|
||||
&__low-balance {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
&__header {
|
||||
@ -277,107 +245,37 @@ function routeToCoupons(): void {
|
||||
}
|
||||
}
|
||||
|
||||
&__title-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 20px 0;
|
||||
|
||||
&__balance-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
|
||||
&__tokens-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
color: #768394;
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
|
||||
&__label {
|
||||
margin-right: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
&__free-credits {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
cursor: default;
|
||||
margin-right: 50px;
|
||||
color: #768394;
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
|
||||
&__label {
|
||||
margin-right: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__notification-container {
|
||||
margin-top: 20px;
|
||||
|
||||
&__negative-balance,
|
||||
&__low-balance {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
|
||||
&__text {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
margin: 0 17px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 19px;
|
||||
}
|
||||
}
|
||||
|
||||
&__negative-balance {
|
||||
background-color: #ffd4d2;
|
||||
}
|
||||
|
||||
&__low-balance {
|
||||
background-color: #fcf8e3;
|
||||
}
|
||||
&__divider {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #dadfe7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-position {
|
||||
margin: 30px 0 20px;
|
||||
}
|
||||
@media only screen and (width <= 625px) {
|
||||
|
||||
.icon {
|
||||
min-width: 14px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.account-billing-area {
|
||||
|
||||
@media only screen and (width <= 625px) {
|
||||
|
||||
.account-billing-area__header__div {
|
||||
&__wrap {
|
||||
margin-right: -24px;
|
||||
margin-left: -24px;
|
||||
}
|
||||
|
||||
.account-billing-area__title {
|
||||
margin-left: 24px;
|
||||
}
|
||||
&__title {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
.first-header-tab {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
.last-header-tab {
|
||||
margin-right: 24px;
|
||||
&__low-balance {
|
||||
margin: 25px 24px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.first-header-tab {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
.last-header-tab {
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -6,9 +6,9 @@
|
||||
<template #content>
|
||||
<div class="add-tokens">
|
||||
<p class="add-tokens__info">
|
||||
Send more than $10 in STORJ Tokens to the following deposit address to upgrade to a Pro account.
|
||||
Your account will be upgraded after your transaction receives {{ neededConfirmations }} confirmations.
|
||||
If your account is not automatically upgraded, please fill out this
|
||||
Send more than {{ amountForUpgrade }} in STORJ Tokens to the following deposit address to upgrade to
|
||||
a Pro account. Your account will be upgraded after your transaction receives {{ neededConfirmations }}
|
||||
confirmations. If your account is not automatically upgraded, please fill out this
|
||||
<a
|
||||
class="add-tokens__info__link"
|
||||
href="https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000683212"
|
||||
@ -72,6 +72,7 @@ import { useConfigStore } from '@/store/modules/configStore';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { PaymentStatus, PaymentWithConfirmations, Wallet } from '@/types/payments';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { centsToDollars, microDollarsToCents } from '@/utils/strings';
|
||||
|
||||
import UpgradeAccountWrapper from '@/components/modals/upgradeAccountFlow/UpgradeAccountWrapper.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
@ -94,6 +95,12 @@ const canvas = ref<HTMLCanvasElement>();
|
||||
const intervalID = ref<NodeJS.Timer>();
|
||||
const viewState = ref<ViewState>(ViewState.Default);
|
||||
|
||||
const amountForUpgrade = computed<string>(() => {
|
||||
const balanceForUpgrade = configStore.state.config.userBalanceForUpgrade;
|
||||
|
||||
return centsToDollars(microDollarsToCents(balanceForUpgrade));
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns wallet from store.
|
||||
*/
|
||||
|
@ -24,11 +24,9 @@
|
||||
import { onBeforeMount, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { PricingPlanInfo, PricingPlanType } from '@/types/common';
|
||||
import { User } from '@/types/users';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { useUsersStore } from '@/store/modules/usersStore';
|
||||
|
||||
import UpgradeAccountWrapper from '@/components/modals/upgradeAccountFlow/UpgradeAccountWrapper.vue';
|
||||
|
@ -5,7 +5,7 @@
|
||||
<UpgradeAccountWrapper title="Upgrade to Pro">
|
||||
<template #content>
|
||||
<p class="options-info">
|
||||
Add a credit card to activate your Pro Account, or deposit more than $10 in STORJ tokens to upgrade
|
||||
Add a credit card to activate your Pro Account, or deposit more than {{ amountForUpgrade }} in STORJ tokens to upgrade
|
||||
and get 10% bonus on your STORJ tokens deposit.
|
||||
</p>
|
||||
<div class="options-buttons">
|
||||
@ -36,13 +36,19 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { useUsersStore } from '@/store/modules/usersStore';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
import { centsToDollars, microDollarsToCents } from '@/utils/strings';
|
||||
|
||||
import UpgradeAccountWrapper from '@/components/modals/upgradeAccountFlow/UpgradeAccountWrapper.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
const usersStore = useUsersStore();
|
||||
const configStore = useConfigStore();
|
||||
|
||||
const notify = useNotify();
|
||||
|
||||
const props = defineProps<{
|
||||
@ -50,6 +56,12 @@ const props = defineProps<{
|
||||
onAddCard: () => void;
|
||||
onAddTokens: () => Promise<void>;
|
||||
}>();
|
||||
|
||||
const amountForUpgrade = computed<string>(() => {
|
||||
const balanceForUpgrade = configStore.state.config.userBalanceForUpgrade;
|
||||
|
||||
return centsToDollars(microDollarsToCents(balanceForUpgrade));
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
@ -2,7 +2,16 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="project-dashboard">
|
||||
<div ref="content" class="project-dashboard">
|
||||
<v-banner
|
||||
v-if="isLowBalance && content && billingEnabled"
|
||||
class="project-dashboard__low-balance"
|
||||
message="Your STORJ Token balance is low. Deposit more STORJ tokens or add a credit card to avoid interruptions in service."
|
||||
link-text="Go to billing"
|
||||
severity="warning"
|
||||
:dashboard-ref="content"
|
||||
:on-link-click="redirectToBillingOverview"
|
||||
/>
|
||||
<div class="project-dashboard__heading">
|
||||
<h1 class="project-dashboard__heading__title" aria-roledescription="title">{{ selectedProject.name }}</h1>
|
||||
<project-ownership-tag :role="(selectedProject.ownerId === user.id) ? ProjectRole.Owner : ProjectRole.Member" />
|
||||
@ -196,6 +205,8 @@ import { ProjectMembersPage, ProjectRole } from '@/types/projectMembers';
|
||||
import { AccessGrantsPage } from '@/types/accessGrants';
|
||||
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
|
||||
import { useCreateProjectClickHandler } from '@/composables/useCreateProjectClickHandler';
|
||||
import { AccountBalance, CreditCard } from '@/types/payments';
|
||||
import { useLowTokenBalance } from '@/composables/useLowTokenBalance';
|
||||
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
import InfoContainer from '@/components/project/dashboard/InfoContainer.vue';
|
||||
@ -209,6 +220,7 @@ import BucketsTable from '@/components/objects/BucketsTable.vue';
|
||||
import EncryptionBanner from '@/components/objects/EncryptionBanner.vue';
|
||||
import ProjectOwnershipTag from '@/components/project/ProjectOwnershipTag.vue';
|
||||
import LimitsArea from '@/components/project/dashboard/LimitsArea.vue';
|
||||
import VBanner from '@/components/common/VBanner.vue';
|
||||
|
||||
import NewProjectIcon from '@/../static/images/project/newProject.svg';
|
||||
import InfoIcon from '@/../static/images/project/infoIcon.svg';
|
||||
@ -228,11 +240,13 @@ const pmStore = useProjectMembersStore();
|
||||
const agStore = useAccessGrantsStore();
|
||||
|
||||
const { handleCreateProjectClick } = useCreateProjectClickHandler();
|
||||
const isLowBalance = useLowTokenBalance();
|
||||
const notify = useNotify();
|
||||
const router = useRouter();
|
||||
|
||||
const now = new Date().toLocaleDateString('en-US');
|
||||
|
||||
const content = ref<HTMLElement | null>(null);
|
||||
const isDataFetching = ref<boolean>(true);
|
||||
const areBucketsFetching = ref<boolean>(true);
|
||||
const isServerSideEncryptionBannerHidden = ref<boolean>(true);
|
||||
@ -373,6 +387,13 @@ const bucketsCount = computed((): number => {
|
||||
return bucketsStore.state.page.totalCount;
|
||||
});
|
||||
|
||||
/**
|
||||
* Redirects to Billing Page Overview tab.
|
||||
*/
|
||||
function redirectToBillingOverview(): void {
|
||||
router.push(RouteConfig.Account.with(RouteConfig.Billing.with(RouteConfig.BillingOverview)).path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides server-side encryption banner.
|
||||
*/
|
||||
@ -481,13 +502,21 @@ onMounted(async (): Promise<void> => {
|
||||
appStore.toggleHasJustLoggedIn();
|
||||
}
|
||||
|
||||
const promises: Promise<void | ProjectMembersPage | AccessGrantsPage>[] = [
|
||||
let promises: Promise<void | ProjectMembersPage | AccessGrantsPage | AccountBalance | CreditCard[]>[] = [
|
||||
projectsStore.getDailyProjectData({ since: past, before: now }),
|
||||
pmStore.getProjectMembers(FIRST_PAGE, projectID),
|
||||
agStore.getAccessGrants(FIRST_PAGE, projectID),
|
||||
];
|
||||
|
||||
if (billingEnabled.value) promises.push(billingStore.getCoupon());
|
||||
if (billingEnabled.value) {
|
||||
promises = [
|
||||
...promises,
|
||||
billingStore.getBalance(),
|
||||
billingStore.getCreditCards(),
|
||||
billingStore.getNativePaymentsHistory(),
|
||||
billingStore.getCoupon(),
|
||||
];
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
} catch (error) {
|
||||
@ -530,6 +559,10 @@ onBeforeUnmount((): void => {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
padding-bottom: 55px;
|
||||
|
||||
&__low-balance {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&__heading {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
26
web/satellite/src/composables/useLowTokenBalance.ts
Normal file
26
web/satellite/src/composables/useLowTokenBalance.ts
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2023 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { microDollarsToCents } from '@/utils/strings';
|
||||
import { useBillingStore } from '@/store/modules/billingStore';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
import { useUsersStore } from '@/store/modules/usersStore';
|
||||
|
||||
export function useLowTokenBalance() {
|
||||
const userStore = useUsersStore();
|
||||
const configStore = useConfigStore();
|
||||
const billingStore = useBillingStore();
|
||||
|
||||
return computed<boolean>(() => {
|
||||
const notEnoughBalance = billingStore.state.nativePaymentsHistory.length > 0 &&
|
||||
billingStore.state.balance.sum < microDollarsToCents(configStore.state.config.userBalanceForUpgrade);
|
||||
|
||||
return (
|
||||
userStore.state.user.paidTier && !billingStore.state.creditCards.length && notEnoughBalance
|
||||
) || (
|
||||
billingStore.state.creditCards.length > 0 && billingStore.state.balance.sum > 0 && notEnoughBalance
|
||||
);
|
||||
});
|
||||
}
|
@ -50,6 +50,7 @@ export class FrontendConfig {
|
||||
billingFeaturesEnabled: boolean;
|
||||
unregisteredInviteEmailsEnabled: boolean;
|
||||
freeTierInvitesEnabled: boolean;
|
||||
userBalanceForUpgrade: number;
|
||||
}
|
||||
|
||||
export class MultiCaptchaConfig {
|
||||
|
@ -89,6 +89,14 @@ export function centsToDollars(cents: number) {
|
||||
return formatPrice(decimalShift(cents.toString(), 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* microDollarsToCents converts micro dollars to cents.
|
||||
* @param microDollars - the micro dollars value
|
||||
*/
|
||||
export function microDollarsToCents(microDollars: number): number {
|
||||
return microDollars / 10000;
|
||||
}
|
||||
|
||||
/**
|
||||
* bytesToBase10String Converts bytes to base-10 types.
|
||||
* @param amountInBytes
|
||||
|
@ -51,19 +51,20 @@ import { useUsersStore } from '@/store/modules/usersStore';
|
||||
import { MODALS } from '@/utils/constants/appStatePopUps';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { RouteConfig } from '@/types/router';
|
||||
import { useBillingStore } from '@/store/modules/billingStore';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
import { useLowTokenBalance } from '@/composables/useLowTokenBalance';
|
||||
|
||||
import VBanner from '@/components/common/VBanner.vue';
|
||||
import UpgradeNotification from '@/components/notifications/UpgradeNotification.vue';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const billingStore = useBillingStore();
|
||||
const usersStore = useUsersStore();
|
||||
const appStore = useAppStore();
|
||||
const configStore = useConfigStore();
|
||||
|
||||
const isLowBalance = useLowTokenBalance();
|
||||
|
||||
const props = defineProps<{
|
||||
parentRef: HTMLElement;
|
||||
}>();
|
||||
@ -87,15 +88,6 @@ const isAccountWarned = computed((): boolean => {
|
||||
return usersStore.state.user.freezeStatus.warned;
|
||||
});
|
||||
|
||||
/**
|
||||
* Indicates if low STORJ token balance banner is shown.
|
||||
*/
|
||||
const isLowBalance = computed((): boolean => {
|
||||
return !billingStore.state.creditCards.length &&
|
||||
billingStore.state.nativePaymentsHistory.length > 0 &&
|
||||
billingStore.state.balance.sum < billingStore.state.projectCharges.getPrice();
|
||||
});
|
||||
|
||||
/* whether the paid tier banner should be shown */
|
||||
const isPaidTierBannerShown = computed((): boolean => {
|
||||
return !usersStore.state.user.paidTier
|
||||
|
@ -158,7 +158,6 @@ onMounted(async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
billingStore.getBalance(),
|
||||
billingStore.getProjectUsageAndChargesCurrentRollup(),
|
||||
billingStore.getCreditCards(),
|
||||
billingStore.getNativePaymentsHistory(),
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user