web/satellite: info bars for accounts with no paywall
WHAT: info bars for accounts with no paywall implemented, USR-976 WHY: we should notify users with no paywall that available coupon value is running low or coupon is used Change-Id: I1a84afce890515b3aaedf1f0b8d359499af05471
This commit is contained in:
parent
db57d76ee9
commit
e5012fcb3d
@ -269,7 +269,7 @@ export class PaymentsHttpApi implements PaymentsApi {
|
|||||||
throw new ErrorUnauthorized();
|
throw new ErrorUnauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('can not process coin payment');
|
throw new Error('can not get paywall status');
|
||||||
}
|
}
|
||||||
|
|
||||||
return await response.json();
|
return await response.json();
|
||||||
|
@ -180,11 +180,3 @@ a {
|
|||||||
height: calc(100vh - 70px);
|
height: calc(100vh - 70px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-height: 700px) {
|
|
||||||
|
|
||||||
.navigation-area {
|
|
||||||
padding: 20px 0;
|
|
||||||
height: calc(100vh - 40px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (C) 2020 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template src="./noPaywallInfoBar.html"/>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import { RouteConfig } from '@/router';
|
||||||
|
import { PaymentsHistoryItem, PaymentsHistoryItemType } from '@/types/payments';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class NoPaywallInfoBar extends Vue {
|
||||||
|
private readonly ONE_QUARTER = 25; // in percents.
|
||||||
|
public readonly billingPath: string = RouteConfig.Account.with(RouteConfig.Billing).path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if default message is shown.
|
||||||
|
*/
|
||||||
|
public get isDefaultMessage(): boolean {
|
||||||
|
return this.promotionalCoupon.remainingAmountPercentage() > this.ONE_QUARTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if warning message is shown.
|
||||||
|
*/
|
||||||
|
public get isWarningMessage(): boolean {
|
||||||
|
const remaining = this.promotionalCoupon.remainingAmountPercentage();
|
||||||
|
|
||||||
|
return remaining > 0 && remaining <= this.ONE_QUARTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if error message is shown.
|
||||||
|
*/
|
||||||
|
public get isErrorMessage(): boolean {
|
||||||
|
return this.promotionalCoupon.remainingAmountPercentage() === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns promotional coupon.
|
||||||
|
*/
|
||||||
|
private get promotionalCoupon(): PaymentsHistoryItem {
|
||||||
|
const coupons: PaymentsHistoryItem[] = this.$store.state.paymentsModule.paymentsHistory.filter((item: PaymentsHistoryItem) => {
|
||||||
|
return item.type === PaymentsHistoryItemType.Coupon;
|
||||||
|
});
|
||||||
|
|
||||||
|
return coupons[coupons.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss" src="./noPaywallInfoBar.scss"/>
|
@ -0,0 +1,18 @@
|
|||||||
|
<!--Copyright (C) 2020 Storj Labs, Inc.-->
|
||||||
|
<!--See LICENSE for copying information.-->
|
||||||
|
|
||||||
|
<div class="no-paywall-bar" :class="{ blue: isDefaultMessage, orange: isWarningMessage, red: isErrorMessage }">
|
||||||
|
<p class="no-paywall-bar__message" v-if="isDefaultMessage">
|
||||||
|
<b class="no-paywall-bar__message__bold">Try Storj with 50 GB Free.</b>
|
||||||
|
<span>Add a payment method to keep experiencing Storj after your trial.</span>
|
||||||
|
</p>
|
||||||
|
<p class="no-paywall-bar__message" v-if="isWarningMessage">
|
||||||
|
<b class="no-paywall-bar__message__bold">Your 50 GB trial is running out soon!</b>
|
||||||
|
<span>Add a payment method to keep experiencing Storj.</span>
|
||||||
|
</p>
|
||||||
|
<p class="no-paywall-bar__message" v-if="isErrorMessage">
|
||||||
|
<b class="no-paywall-bar__message__bold">Your 50 GB trial has run out!</b>
|
||||||
|
<span>Add a payment method to keep experiencing Storj.</span>
|
||||||
|
</p>
|
||||||
|
<router-link class="no-paywall-bar__link" :to="billingPath">Add a Payment Method -></router-link>
|
||||||
|
</div>
|
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (C) 2020 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
.no-paywall-bar {
|
||||||
|
width: calc(100% - 60px);
|
||||||
|
padding: 0 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-family: 'font_regular', sans-serif;
|
||||||
|
|
||||||
|
&__message,
|
||||||
|
&__link {
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 12px;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&__bold {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
font-family: 'font_medium', sans-serif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blue {
|
||||||
|
background-color: #2582ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orange {
|
||||||
|
background-color: #e67c00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red {
|
||||||
|
background-color: #e43e3e;
|
||||||
|
}
|
@ -65,7 +65,6 @@ import CloseImage from '@/../static/images/onboardingTour/close.svg';
|
|||||||
|
|
||||||
import { RouteConfig } from '@/router';
|
import { RouteConfig } from '@/router';
|
||||||
import { TourState } from '@/utils/constants/onboardingTourEnums';
|
import { TourState } from '@/utils/constants/onboardingTourEnums';
|
||||||
import { MetaUtils } from '@/utils/meta';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@ -123,7 +122,7 @@ export default class OnboardingTourArea extends Vue {
|
|||||||
* Indicates if paywall is enabled.
|
* Indicates if paywall is enabled.
|
||||||
*/
|
*/
|
||||||
public get isPaywallEnabled(): boolean {
|
public get isPaywallEnabled(): boolean {
|
||||||
return this.$store.state.paymentsModule.paywallEnabled;
|
return this.$store.state.paymentsModule.isPaywallEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +88,7 @@ export class PaymentsState {
|
|||||||
public priceSummary: number = 0;
|
public priceSummary: number = 0;
|
||||||
public startDate: Date = new Date();
|
public startDate: Date = new Date();
|
||||||
public endDate: Date = new Date();
|
public endDate: Date = new Date();
|
||||||
public paywallEnabled: boolean = true;
|
public isPaywallEnabled: boolean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -154,7 +154,7 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState>
|
|||||||
state.priceSummary = usageItemSummaries.reduce((accumulator, current) => accumulator + current);
|
state.priceSummary = usageItemSummaries.reduce((accumulator, current) => accumulator + current);
|
||||||
},
|
},
|
||||||
[SET_PAYWALL_ENABLED_STATUS](state: PaymentsState, paywallEnabledStatus: boolean): void {
|
[SET_PAYWALL_ENABLED_STATUS](state: PaymentsState, paywallEnabledStatus: boolean): void {
|
||||||
state.paywallEnabled = paywallEnabledStatus;
|
state.isPaywallEnabled = paywallEnabledStatus;
|
||||||
},
|
},
|
||||||
[CLEAR](state: PaymentsState) {
|
[CLEAR](state: PaymentsState) {
|
||||||
state.balance = new AccountBalance();
|
state.balance = new AccountBalance();
|
||||||
@ -164,7 +164,7 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState>
|
|||||||
state.creditCards = [];
|
state.creditCards = [];
|
||||||
state.startDate = new Date();
|
state.startDate = new Date();
|
||||||
state.endDate = new Date();
|
state.endDate = new Date();
|
||||||
state.paywallEnabled = true;
|
state.isPaywallEnabled = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -110,7 +110,9 @@ export class PaymentAmountOption {
|
|||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BillingHistoryItem holds all public information about billing history line.
|
/**
|
||||||
|
* PaymentsHistoryItem holds all public information about payments history line.
|
||||||
|
*/
|
||||||
export class PaymentsHistoryItem {
|
export class PaymentsHistoryItem {
|
||||||
public constructor(
|
public constructor(
|
||||||
public readonly id: string = '',
|
public readonly id: string = '',
|
||||||
@ -137,6 +139,17 @@ export class PaymentsHistoryItem {
|
|||||||
return this.status.charAt(0).toUpperCase() + this.status.substring(1);
|
return this.status.charAt(0).toUpperCase() + this.status.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RemainingAmountPercentage will return remaining amount of item in percentage.
|
||||||
|
*/
|
||||||
|
public remainingAmountPercentage(): number {
|
||||||
|
if (this.amount === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.remaining / this.amount * 100;
|
||||||
|
}
|
||||||
|
|
||||||
private amountDollars(amount): number {
|
private amountDollars(amount): number {
|
||||||
return amount / 100;
|
return amount / 100;
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,12 @@
|
|||||||
<div v-if="isLoading" class="loading-overlay active">
|
<div v-if="isLoading" class="loading-overlay active">
|
||||||
<img class="loading-image" src="@/../static/images/register/Loading.gif" alt="Company logo loading gif">
|
<img class="loading-image" src="@/../static/images/register/Loading.gif" alt="Company logo loading gif">
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="dashboard-container__wrap">
|
<NoPaywallInfoBar v-if="isNoPaywallInfoBarShown && !isLoading"/>
|
||||||
|
<div v-if="!isLoading" class="dashboard-container__wrap">
|
||||||
<NavigationArea class="regular-navigation"/>
|
<NavigationArea class="regular-navigation"/>
|
||||||
<div class="dashboard-container__wrap__column">
|
<div class="dashboard-container__wrap__column">
|
||||||
<DashboardHeader/>
|
<DashboardHeader/>
|
||||||
<div class="dashboard-container__main-area">
|
<div class="dashboard-container__main-area" :class="{ extended: isNoPaywallInfoBarShown }">
|
||||||
<div class="dashboard-container__main-area__bar-area">
|
<div class="dashboard-container__main-area__bar-area">
|
||||||
<VInfoBar
|
<VInfoBar
|
||||||
v-if="isInfoBarShown"
|
v-if="isInfoBarShown"
|
||||||
@ -38,6 +39,7 @@ import { Component, Vue } from 'vue-property-decorator';
|
|||||||
import VInfoBar from '@/components/common/VInfoBar.vue';
|
import VInfoBar from '@/components/common/VInfoBar.vue';
|
||||||
import DashboardHeader from '@/components/header/HeaderArea.vue';
|
import DashboardHeader from '@/components/header/HeaderArea.vue';
|
||||||
import NavigationArea from '@/components/navigation/NavigationArea.vue';
|
import NavigationArea from '@/components/navigation/NavigationArea.vue';
|
||||||
|
import NoPaywallInfoBar from '@/components/noPaywallInfoBar/NoPaywallInfoBar.vue';
|
||||||
|
|
||||||
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
|
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
|
||||||
import { RouteConfig } from '@/router';
|
import { RouteConfig } from '@/router';
|
||||||
@ -72,6 +74,7 @@ const {
|
|||||||
NavigationArea,
|
NavigationArea,
|
||||||
DashboardHeader,
|
DashboardHeader,
|
||||||
VInfoBar,
|
VInfoBar,
|
||||||
|
NoPaywallInfoBar,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class DashboardArea extends Vue {
|
export default class DashboardArea extends Vue {
|
||||||
@ -203,6 +206,17 @@ export default class DashboardArea extends Vue {
|
|||||||
await this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADED);
|
await this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if no paywall info bar is shown.
|
||||||
|
*/
|
||||||
|
public get isNoPaywallInfoBarShown(): boolean {
|
||||||
|
const isOnboardingTour: boolean = this.$route.name === RouteConfig.OnboardingTour.name;
|
||||||
|
|
||||||
|
return !this.isPaywallEnabled && !isOnboardingTour &&
|
||||||
|
this.$store.state.paymentsModule.balance.coins === 0 &&
|
||||||
|
this.$store.state.paymentsModule.creditCards.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if info bar is shown.
|
* Indicates if info bar is shown.
|
||||||
*/
|
*/
|
||||||
@ -252,6 +266,13 @@ export default class DashboardArea extends Vue {
|
|||||||
public get isLoading(): boolean {
|
public get isLoading(): boolean {
|
||||||
return this.$store.state.appStateModule.appState.fetchState === AppState.LOADING;
|
return this.$store.state.appStateModule.appState.fetchState === AppState.LOADING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if paywall is enabled.
|
||||||
|
*/
|
||||||
|
private get isPaywallEnabled(): boolean {
|
||||||
|
return this.$store.state.paymentsModule.isPaywallEnabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -294,6 +315,10 @@ export default class DashboardArea extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extended {
|
||||||
|
height: calc(100vh - 90px);
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1280px) {
|
@media screen and (max-width: 1280px) {
|
||||||
|
|
||||||
.regular-navigation {
|
.regular-navigation {
|
||||||
|
@ -45,6 +45,8 @@ class NotificatorPlugin {
|
|||||||
const notificationsPlugin = new NotificatorPlugin();
|
const notificationsPlugin = new NotificatorPlugin();
|
||||||
localVue.use(notificationsPlugin);
|
localVue.use(notificationsPlugin);
|
||||||
|
|
||||||
|
const ANIMATION_COMPLETE_TIME = 600;
|
||||||
|
|
||||||
describe('PaymentMethods', () => {
|
describe('PaymentMethods', () => {
|
||||||
it('renders correctly without card', () => {
|
it('renders correctly without card', () => {
|
||||||
const wrapper = mount(PaymentMethods, {
|
const wrapper = mount(PaymentMethods, {
|
||||||
@ -72,8 +74,8 @@ describe('PaymentMethods', () => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
done();
|
done();
|
||||||
}, 500);
|
}, ANIMATION_COMPLETE_TIME);
|
||||||
}, 500);
|
}, ANIMATION_COMPLETE_TIME);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -94,8 +96,8 @@ describe('PaymentMethods', () => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
done();
|
done();
|
||||||
}, 500);
|
}, ANIMATION_COMPLETE_TIME);
|
||||||
}, 500);
|
}, ANIMATION_COMPLETE_TIME);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
64
web/satellite/tests/unit/views/NoPaywallInfoBar.spec.ts
Normal file
64
web/satellite/tests/unit/views/NoPaywallInfoBar.spec.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (C) 2019 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
import Vuex from 'vuex';
|
||||||
|
|
||||||
|
import NoPaywallInfoBar from '@/components/noPaywallInfoBar/NoPaywallInfoBar.vue';
|
||||||
|
|
||||||
|
import { router } from '@/router';
|
||||||
|
import { makePaymentsModule, PAYMENTS_MUTATIONS } from '@/store/modules/payments';
|
||||||
|
import { PaymentsHistoryItem, PaymentsHistoryItemType, ProjectUsageAndCharges } from '@/types/payments';
|
||||||
|
import { createLocalVue, mount } from '@vue/test-utils';
|
||||||
|
|
||||||
|
import { PaymentsMock } from '../mock/api/payments';
|
||||||
|
|
||||||
|
const localVue = createLocalVue();
|
||||||
|
const paymentsModule = makePaymentsModule(new PaymentsMock());
|
||||||
|
const { SET_PAYMENTS_HISTORY } = PAYMENTS_MUTATIONS;
|
||||||
|
const store = new Vuex.Store({
|
||||||
|
modules: {
|
||||||
|
paymentsModule,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
localVue.use(Vuex);
|
||||||
|
|
||||||
|
describe('NoPaywallInfoBar.vue', () => {
|
||||||
|
it('renders correctly with less than 75% usage', () => {
|
||||||
|
const coupon: PaymentsHistoryItem = new PaymentsHistoryItem('id', 'coupon', 300, 300, 'test', '', new Date(), new Date(), PaymentsHistoryItemType.Coupon, 275);
|
||||||
|
store.commit(SET_PAYMENTS_HISTORY, [coupon]);
|
||||||
|
|
||||||
|
const wrapper = mount(NoPaywallInfoBar, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
router,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders correctly with more than 75% usage', () => {
|
||||||
|
const coupon: PaymentsHistoryItem = new PaymentsHistoryItem('id', 'coupon', 300, 300, 'test', '', new Date(), new Date(), PaymentsHistoryItemType.Coupon, 75);
|
||||||
|
store.commit(SET_PAYMENTS_HISTORY, [coupon]);
|
||||||
|
|
||||||
|
const wrapper = mount(NoPaywallInfoBar, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
router,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders correctly with used coupon', () => {
|
||||||
|
const coupon: PaymentsHistoryItem = new PaymentsHistoryItem('id', 'coupon', 300, 300, 'test', '', new Date(), new Date(), PaymentsHistoryItemType.Coupon, 0);
|
||||||
|
store.commit(SET_PAYMENTS_HISTORY, [coupon]);
|
||||||
|
|
||||||
|
const wrapper = mount(NoPaywallInfoBar, {
|
||||||
|
store,
|
||||||
|
localVue,
|
||||||
|
router,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
exports[`Dashboard renders correctly when data is loaded 1`] = `
|
exports[`Dashboard renders correctly when data is loaded 1`] = `
|
||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
<div class="dashboard-container__wrap">
|
<div class="dashboard-container__wrap">
|
||||||
<navigationarea-stub class="regular-navigation"></navigationarea-stub>
|
<navigationarea-stub class="regular-navigation"></navigationarea-stub>
|
||||||
<div class="dashboard-container__wrap__column">
|
<div class="dashboard-container__wrap__column">
|
||||||
@ -22,5 +24,7 @@ exports[`Dashboard renders correctly when data is loaded 1`] = `
|
|||||||
exports[`Dashboard renders correctly when data is loading 1`] = `
|
exports[`Dashboard renders correctly when data is loading 1`] = `
|
||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<div class="loading-overlay active"><img src="@/../static/images/register/Loading.gif" alt="Company logo loading gif" class="loading-image"></div>
|
<div class="loading-overlay active"><img src="@/../static/images/register/Loading.gif" alt="Company logo loading gif" class="loading-image"></div>
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`NoPaywallInfoBar.vue renders correctly with less than 75% usage 1`] = `
|
||||||
|
<div class="no-paywall-bar blue">
|
||||||
|
<p class="no-paywall-bar__message"><b class="no-paywall-bar__message__bold">Try Storj with 50 GB Free.</b> <span>Add a payment method to keep experiencing Storj after your trial.</span></p>
|
||||||
|
<!---->
|
||||||
|
<!----> <a href="/account/billing" class="no-paywall-bar__link">Add a Payment Method -></a>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`NoPaywallInfoBar.vue renders correctly with more than 75% usage 1`] = `
|
||||||
|
<div class="no-paywall-bar orange">
|
||||||
|
<!---->
|
||||||
|
<p class="no-paywall-bar__message"><b class="no-paywall-bar__message__bold">Your 50 GB trial is running out soon!</b> <span>Add a payment method to keep experiencing Storj.</span></p>
|
||||||
|
<!----> <a href="/account/billing" class="no-paywall-bar__link">Add a Payment Method -></a>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`NoPaywallInfoBar.vue renders correctly with used coupon 1`] = `
|
||||||
|
<div class="no-paywall-bar red">
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
<p class="no-paywall-bar__message"><b class="no-paywall-bar__message__bold">Your 50 GB trial has run out!</b> <span>Add a payment method to keep experiencing Storj.</span></p> <a href="/account/billing" class="no-paywall-bar__link">Add a Payment Method -></a>
|
||||||
|
</div>
|
||||||
|
`;
|
Loading…
Reference in New Issue
Block a user