Skip to content

Commit

Permalink
satellite/{web,console}: enable/disable billing features depending on…
Browse files Browse the repository at this point in the history
… config value

Added client side logic to disable billing features depending on config value.
Disabled billing endpoints if billing is disabled.

Issue:
storj/storj-private#464

Change-Id: I6e70dc5e2372953b613ddab9f19cb94f008935ce
  • Loading branch information
VitaliiShpital authored and Storj Robot committed Oct 18, 2023
1 parent bce022e commit 6ae28e2
Show file tree
Hide file tree
Showing 14 changed files with 191 additions and 100 deletions.
48 changes: 25 additions & 23 deletions satellite/console/consoleweb/server.go
Expand Up @@ -336,29 +336,31 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, oidc
abRouter.Handle("/hit/{action}", http.HandlerFunc(abController.SendHit)).Methods(http.MethodPost, http.MethodOptions)
}

paymentController := consoleapi.NewPayments(logger, service, accountFreezeService, packagePlans)
paymentsRouter := router.PathPrefix("/api/v0/payments").Subrouter()
paymentsRouter.Use(server.withCORS)
paymentsRouter.Use(server.withAuth)
paymentsRouter.Handle("/cards", server.userIDRateLimiter.Limit(http.HandlerFunc(paymentController.AddCreditCard))).Methods(http.MethodPost, http.MethodOptions)
paymentsRouter.HandleFunc("/cards", paymentController.MakeCreditCardDefault).Methods(http.MethodPatch, http.MethodOptions)
paymentsRouter.HandleFunc("/cards", paymentController.ListCreditCards).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/cards/{cardId}", paymentController.RemoveCreditCard).Methods(http.MethodDelete, http.MethodOptions)
paymentsRouter.HandleFunc("/account/charges", paymentController.ProjectsCharges).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/account/balance", paymentController.AccountBalance).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/account", paymentController.SetupAccount).Methods(http.MethodPost, http.MethodOptions)
paymentsRouter.HandleFunc("/wallet", paymentController.GetWallet).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/wallet", paymentController.ClaimWallet).Methods(http.MethodPost, http.MethodOptions)
paymentsRouter.HandleFunc("/wallet/payments", paymentController.WalletPayments).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/wallet/payments-with-confirmations", paymentController.WalletPaymentsWithConfirmations).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/billing-history", paymentController.BillingHistory).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/invoice-history", paymentController.InvoiceHistory).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.Handle("/coupon/apply", server.userIDRateLimiter.Limit(http.HandlerFunc(paymentController.ApplyCouponCode))).Methods(http.MethodPatch, http.MethodOptions)
paymentsRouter.HandleFunc("/coupon", paymentController.GetCoupon).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/pricing", paymentController.GetProjectUsagePriceModel).Methods(http.MethodGet, http.MethodOptions)
if config.PricingPackagesEnabled {
paymentsRouter.HandleFunc("/purchase-package", paymentController.PurchasePackage).Methods(http.MethodPost, http.MethodOptions)
paymentsRouter.HandleFunc("/package-available", paymentController.PackageAvailable).Methods(http.MethodGet, http.MethodOptions)
if config.BillingFeaturesEnabled {
paymentController := consoleapi.NewPayments(logger, service, accountFreezeService, packagePlans)
paymentsRouter := router.PathPrefix("/api/v0/payments").Subrouter()
paymentsRouter.Use(server.withCORS)
paymentsRouter.Use(server.withAuth)
paymentsRouter.Handle("/cards", server.userIDRateLimiter.Limit(http.HandlerFunc(paymentController.AddCreditCard))).Methods(http.MethodPost, http.MethodOptions)
paymentsRouter.HandleFunc("/cards", paymentController.MakeCreditCardDefault).Methods(http.MethodPatch, http.MethodOptions)
paymentsRouter.HandleFunc("/cards", paymentController.ListCreditCards).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/cards/{cardId}", paymentController.RemoveCreditCard).Methods(http.MethodDelete, http.MethodOptions)
paymentsRouter.HandleFunc("/account/charges", paymentController.ProjectsCharges).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/account/balance", paymentController.AccountBalance).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/account", paymentController.SetupAccount).Methods(http.MethodPost, http.MethodOptions)
paymentsRouter.HandleFunc("/wallet", paymentController.GetWallet).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/wallet", paymentController.ClaimWallet).Methods(http.MethodPost, http.MethodOptions)
paymentsRouter.HandleFunc("/wallet/payments", paymentController.WalletPayments).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/wallet/payments-with-confirmations", paymentController.WalletPaymentsWithConfirmations).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/billing-history", paymentController.BillingHistory).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/invoice-history", paymentController.InvoiceHistory).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.Handle("/coupon/apply", server.userIDRateLimiter.Limit(http.HandlerFunc(paymentController.ApplyCouponCode))).Methods(http.MethodPatch, http.MethodOptions)
paymentsRouter.HandleFunc("/coupon", paymentController.GetCoupon).Methods(http.MethodGet, http.MethodOptions)
paymentsRouter.HandleFunc("/pricing", paymentController.GetProjectUsagePriceModel).Methods(http.MethodGet, http.MethodOptions)
if config.PricingPackagesEnabled {
paymentsRouter.HandleFunc("/purchase-package", paymentController.PurchasePackage).Methods(http.MethodPost, http.MethodOptions)
paymentsRouter.HandleFunc("/package-available", paymentController.PackageAvailable).Methods(http.MethodGet, http.MethodOptions)
}
}

bucketsController := consoleapi.NewBuckets(logger, service)
Expand Down
13 changes: 10 additions & 3 deletions web/satellite/src/components/modals/CreateProjectPromptModal.vue
Expand Up @@ -9,7 +9,7 @@
<ProjectIcon />
<h1 class="modal__header__title">Get more projects</h1>
</div>
<p v-if="!isPaidTier" class="modal__info">
<p v-if="!isPaidTier && billingEnabled" class="modal__info">
Upgrade to Pro Account to create more projects and gain access to higher limits.
</p>
<p v-else class="modal__info">
Expand Down Expand Up @@ -45,6 +45,7 @@ import { computed } from 'vue';
import { MODALS } from '@/utils/constants/appStatePopUps';
import { useAppStore } from '@/store/modules/appStore';
import { useUsersStore } from '@/store/modules/usersStore';
import { useConfigStore } from '@/store/modules/configStore';
import VButton from '@/components/common/VButton.vue';
import VModal from '@/components/common/VModal.vue';
Expand All @@ -53,14 +54,20 @@ import ProjectIcon from '@/../static/images/common/blueBox.svg';
const appStore = useAppStore();
const userStore = useUsersStore();
const configStore = useConfigStore();
const isPaidTier = computed<boolean>(() => userStore.state.user.paidTier);
/**
* Indicates if billing features are enabled.
*/
const billingEnabled = computed<boolean>(() => configStore.state.config.billingFeaturesEnabled);
/**
* Returns button text label depending on if the user is in the free or paid tier.
*/
const buttonLabel = computed<string>(() => {
return isPaidTier.value ? 'Request -->' : 'Upgrade -->';
return !isPaidTier.value && billingEnabled.value ? 'Upgrade -->' : 'Request -->';
});
/**
Expand All @@ -69,7 +76,7 @@ const buttonLabel = computed<string>(() => {
* Redirects to upgrade modal or opens new tab to request increase project limits .
*/
function onClick(): void {
if (!isPaidTier.value) {
if (!isPaidTier.value && billingEnabled.value) {
appStore.updateActiveModal(MODALS.upgradeAccount);
} else {
appStore.removeActiveModal();
Expand Down
33 changes: 22 additions & 11 deletions web/satellite/src/components/navigation/AccountArea.vue
Expand Up @@ -8,8 +8,10 @@
<AccountIcon class="account-area__wrap__left__icon" />
<p class="account-area__wrap__left__label">My Account</p>
<p class="account-area__wrap__left__label-small">Account</p>
<TierBadgePro v-if="user.paidTier" class="account-area__wrap__left__tier-badge" />
<TierBadgeFree v-else class="account-area__wrap__left__tier-badge" />
<template v-if="billingEnabled">
<TierBadgePro v-if="isPaidTier" class="account-area__wrap__left__tier-badge" />
<TierBadgeFree v-else class="account-area__wrap__left__tier-badge" />
</template>
</div>
<ArrowImage class="account-area__wrap__arrow" />
</div>
Expand All @@ -31,11 +33,11 @@
</a>
</div>
</div>
<div v-if="!user.paidTier" tabindex="0" class="account-area__dropdown__item" @click="onUpgrade" @keyup.enter="onUpgrade">
<div v-if="!isPaidTier && billingEnabled" tabindex="0" class="account-area__dropdown__item" @click="onUpgrade" @keyup.enter="onUpgrade">
<UpgradeIcon />
<p class="account-area__dropdown__item__label">Upgrade</p>
</div>
<div tabindex="0" class="account-area__dropdown__item" @click="navigateToBilling" @keyup.enter="navigateToBilling">
<div v-if="billingEnabled" tabindex="0" class="account-area__dropdown__item" @click="navigateToBilling" @keyup.enter="navigateToBilling">
<BillingIcon />
<p class="account-area__dropdown__item__label">Billing</p>
</div>
Expand All @@ -55,7 +57,6 @@
import { computed, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { User } from '@/types/users';
import { RouteConfig } from '@/types/router';
import { AuthHttpApi } from '@/api/auth';
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
Expand Down Expand Up @@ -108,6 +109,11 @@ const dropdownYPos = ref<number>(0);
const dropdownXPos = ref<number>(0);
const accountArea = ref<HTMLDivElement>();
/**
* Indicates if billing features are enabled.
*/
const billingEnabled = computed<boolean>(() => configStore.state.config.billingFeaturesEnabled);
/**
* Returns bottom and left position of dropdown.
*/
Expand All @@ -130,10 +136,10 @@ const satellite = computed((): string => {
});
/**
* Returns user entity from store.
* Indicates if user is in paid tier.
*/
const user = computed((): User => {
return usersStore.state.user;
const isPaidTier = computed((): boolean => {
return usersStore.state.user.paidTier;
});
/**
Expand All @@ -142,6 +148,8 @@ const user = computed((): User => {
function onUpgrade(): void {
closeDropdown();
if (!billingEnabled.value) return;
appStore.updateActiveModal(MODALS.upgradeAccount);
}
Expand Down Expand Up @@ -204,12 +212,15 @@ function toggleDropdown(): void {
}
const DROPDOWN_HEIGHT = 224; // pixels
const SIXTEEN_PIXELS = 16;
const FIFTY_THREE_PIXELS = 53; // height of a single child element.
const TWENTY_PIXELS = 20;
const SEVENTY_PIXELS = 70;
const accountContainer = accountArea.value.getBoundingClientRect();
dropdownYPos.value = accountContainer.bottom - DROPDOWN_HEIGHT - (usersStore.state.user.paidTier ? SIXTEEN_PIXELS : SEVENTY_PIXELS);
if (billingEnabled.value) {
dropdownYPos.value = accountContainer.bottom - DROPDOWN_HEIGHT - (isPaidTier.value ? 0 : FIFTY_THREE_PIXELS);
} else {
dropdownYPos.value = accountContainer.bottom - DROPDOWN_HEIGHT + FIFTY_THREE_PIXELS;
}
dropdownXPos.value = accountContainer.right - TWENTY_PIXELS;
appStore.toggleActiveDropdown(APP_STATE_DROPDOWNS.ACCOUNT);
Expand Down
26 changes: 18 additions & 8 deletions web/satellite/src/components/navigation/MobileNavigation.vue
Expand Up @@ -157,8 +157,10 @@
<AccountIcon class="account-area__wrap__left__icon" />
<p class="account-area__wrap__left__label">My Account</p>
<p class="account-area__wrap__left__label-small">Account</p>
<TierBadgePro v-if="user.paidTier" class="account-area__wrap__left__tier-badge" />
<TierBadgeFree v-else class="account-area__wrap__left__tier-badge" />
<template v-if="billingEnabled">
<TierBadgePro v-if="user.paidTier" class="account-area__wrap__left__tier-badge" />
<TierBadgeFree v-else class="account-area__wrap__left__tier-badge" />
</template>
</div>
<ArrowIcon class="account-area__wrap__arrow" />
</div>
Expand All @@ -180,11 +182,11 @@
</a>
</div>
</div>
<div v-if="!user.paidTier" tabindex="0" class="account-area__dropdown__item" @click="onUpgrade" @keyup.enter="onUpgrade">
<div v-if="!user.paidTier && billingEnabled" tabindex="0" class="account-area__dropdown__item" @click="onUpgrade" @keyup.enter="onUpgrade">
<UpgradeIcon />
<p class="account-area__dropdown__item__label">Upgrade</p>
</div>
<div class="account-area__dropdown__item" @click="navigateToBilling">
<div v-if="billingEnabled" class="account-area__dropdown__item" @click="navigateToBilling">
<BillingIcon />
<p class="account-area__dropdown__item__label">Billing</p>
</div>
Expand Down Expand Up @@ -294,7 +296,12 @@ const isAccountDropdownShown = ref<boolean>(false);
const isOpened = ref<boolean>(false);
const isLoading = ref<boolean>(false);
/*
/**
* Indicates if billing features are enabled.
*/
const billingEnabled = computed<boolean>(() => configStore.state.config.billingFeaturesEnabled);
/**
* Whether the user is the owner of the selected project.
*/
const isProjectOwner = computed((): boolean => {
Expand Down Expand Up @@ -525,6 +532,9 @@ function onCreateLinkClick(): void {
*/
function onUpgrade(): void {
isOpened.value = false;
if (!billingEnabled.value) return;
appStore.updateActiveModal(MODALS.upgradeAccount);
}
Expand Down Expand Up @@ -893,7 +903,7 @@ async function onLogout(): Promise<void> {
&__wrap {
box-sizing: border-box;
padding: 16px 32px;
padding: 16px 32px 16px 36px;
height: 48px;
width: 100%;
display: flex;
Expand Down Expand Up @@ -930,7 +940,7 @@ async function onLogout(): Promise<void> {
&__header {
background: var(--c-grey-1);
padding: 16px 32px;
padding: 16px 32px 16px 36px;
border: 1px solid var(--c-grey-2);
display: flex;
align-items: center;
Expand Down Expand Up @@ -964,7 +974,7 @@ async function onLogout(): Promise<void> {
&__item {
display: flex;
align-items: center;
padding: 16px 32px;
padding: 16px 32px 16px 36px;
background: var(--c-grey-1);
&__label {
Expand Down
Expand Up @@ -73,10 +73,11 @@ function closePicker(): void {

<style scoped lang="scss">
.range-selection {
background-color: #fff;
background-color: var(--c-white);
cursor: pointer;
font-family: 'font_regular', sans-serif;
position: relative;
border-radius: 8px;
&__toggle-container {
display: flex;
Expand Down
14 changes: 12 additions & 2 deletions web/satellite/src/components/project/dashboard/LimitsArea.vue
Expand Up @@ -46,7 +46,7 @@
'https://supportdcs.storj.io/hc/en-us/requests/new?ticket_form_id=360000683212'"
/>
<LimitCard
v-if="coupon && isFreeTierCoupon"
v-if="coupon && isFreeTierCoupon && billingEnabled"
:icon="CheckmarkIcon"
title="Free Tier"
color="#091c45"
Expand All @@ -62,7 +62,7 @@
link="https://docs.storj.io/dcs/pricing#free-tier"
/>
<LimitCard
v-if="coupon && !isFreeTierCoupon"
v-if="coupon && !isFreeTierCoupon && billingEnabled"
:icon="CheckmarkIcon"
title="Coupon"
color="#091c45"
Expand Down Expand Up @@ -95,6 +95,7 @@ import { Coupon, ProjectCharges } from '@/types/payments';
import { centsToDollars } from '@/utils/strings';
import { MODALS } from '@/utils/constants/appStatePopUps';
import { RouteConfig } from '@/types/router';
import { useConfigStore } from '@/store/modules/configStore';
import LimitCard from '@/components/project/dashboard/LimitCard.vue';
Expand All @@ -107,6 +108,8 @@ const appStore = useAppStore();
const usersStore = useUsersStore();
const projectsStore = useProjectsStore();
const billingStore = useBillingStore();
const configStore = useConfigStore();
const router = useRouter();
const props = defineProps<{
Expand All @@ -116,6 +119,11 @@ const props = defineProps<{
const EIGHTY_PERCENT = 80;
const HUNDRED_PERCENT = 100;
/**
* Indicates if billing features are enabled.
*/
const billingEnabled = computed<boolean>(() => configStore.state.config.billingFeaturesEnabled);
/**
* Returns coupon from store.
*/
Expand Down Expand Up @@ -305,6 +313,8 @@ function usageAction(limit: LimitToChange): void {
* Starts upgrade account flow.
*/
function startUpgradeFlow(): void {
if (!billingEnabled.value) return;
appStore.updateActiveModal(MODALS.upgradeAccount);
}
Expand Down

0 comments on commit 6ae28e2

Please sign in to comment.