web/satellite: Paid Tier add payment modal implemented
Added new PaidTier-related modal where user can add CC or STORJ Tokens. Becomes visible on CTA click on Paid Tier banner at the top. Change-Id: I51015e95d396e21d5c1a1728b8f753798626c09e
This commit is contained in:
parent
4d418c13c3
commit
bbd3efaeed
@ -23,7 +23,6 @@ import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
import AddCouponCodeInput from '@/components/common/AddCouponCodeInput.vue';
|
||||
import HeaderlessInput from '@/components/common/HeaderlessInput.vue';
|
||||
import ValidationMessage from '@/components/common/ValidationMessage.vue';
|
||||
|
||||
import CloseIcon from '@/../static/images/common/closeCross.svg';
|
||||
import CheckIcon from '@/../static/images/common/success-check.svg';
|
||||
|
@ -0,0 +1,576 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="pm-area">
|
||||
<div v-if="isAddModal" class="pm-area__add-modal">
|
||||
<h1 class="pm-area__add-modal__title">Add a Payment Method</h1>
|
||||
<div class="pm-area__add-modal__header">
|
||||
<h2 class="pm-area__add-modal__header__sub-title">Payment Method</h2>
|
||||
<div class="pm-area__add-modal__header__choices">
|
||||
<p class="pm-area__add-modal__header__choices__var" :class="{active: !isAddCard}" @click.stop="setIsAddToken">
|
||||
STORJ Token
|
||||
</p>
|
||||
<p class="pm-area__add-modal__header__choices__var left-margin" :class="{active: isAddCard}" @click.stop="setIsAddCard">
|
||||
Card
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isAddCard" class="pm-area__add-modal__card">
|
||||
<StripeCardInput
|
||||
class="pm-area__add-modal__card__stripe"
|
||||
ref="stripeCardInput"
|
||||
:on-stripe-response-callback="addCardToDB"
|
||||
/>
|
||||
<VButton
|
||||
width="100%"
|
||||
height="48px"
|
||||
label="Add Credit Card"
|
||||
:on-press="onAddCardClick"
|
||||
/>
|
||||
<p class="pm-area__add-modal__card__info">Get more storage and bandwidth by adding your credit card.</p>
|
||||
<div class="pm-area__add-modal__card__info-bullet">
|
||||
<CheckMarkIcon/>
|
||||
<p class="pm-area__add-modal__card__info-bullet__label">3 projects</p>
|
||||
</div>
|
||||
<div class="pm-area__add-modal__card__info-bullet">
|
||||
<CheckMarkIcon/>
|
||||
<p class="pm-area__add-modal__card__info-bullet__label">25TB storage per project.</p>
|
||||
</div>
|
||||
<div class="pm-area__add-modal__card__info-bullet">
|
||||
<CheckMarkIcon/>
|
||||
<p class="pm-area__add-modal__card__info-bullet__label">100TB egress bandwidth per project.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="pm-area__add-modal__tokens">
|
||||
<p class="pm-area__add-modal__tokens__banner">
|
||||
Deposit STORJ Token to your account and recieve a 10% bonus, or $10 for every $100.
|
||||
</p>
|
||||
<TokenDepositSelection
|
||||
class="pm-area__add-modal__tokens__selection"
|
||||
@onChangeTokenValue="onChangeTokenValue"
|
||||
:payment-options="paymentOptions"
|
||||
/>
|
||||
<VButton
|
||||
width="100%"
|
||||
height="48px"
|
||||
label="Continue to Coin Payments"
|
||||
:on-press="onAddSTORJClick"
|
||||
/>
|
||||
<div v-if="coinPaymentsCheckoutLink" class="pm-area__add-modal__tokens__checkout-container">
|
||||
<a
|
||||
class="pm-area__add-modal__tokens__checkout-container__link"
|
||||
:href="coinPaymentsCheckoutLink"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Checkout
|
||||
</a>
|
||||
</div>
|
||||
<p class="pm-area__add-modal__tokens__note">
|
||||
<b class="pm-area__add-modal__tokens__note__bold">Please Note:</b>
|
||||
Your first deposit of $50 or more in STORJ Token is applied to your account after Coin Payments
|
||||
verifies payment
|
||||
</p>
|
||||
<p class="pm-area__add-modal__tokens__info">
|
||||
After depositing STORJ Tokens, please contact
|
||||
<a
|
||||
class="pm-area__add-modal__tokens__info__link"
|
||||
:href="limitsIncreaseRequestURL"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Support
|
||||
</a>
|
||||
to assist you for accessing your higher limits!
|
||||
</p>
|
||||
</div>
|
||||
<div class="pm-area__add-modal__security">
|
||||
<LockImage/>
|
||||
<p class="pm-area__add-modal__security__info">
|
||||
Your information is secured with 128-bit SSL & AES-256 encryption.
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="isLoading" class="pm-area__add-modal__blur">
|
||||
<VLoader
|
||||
class="pm-area__add-modal__blur__loader"
|
||||
width="30px"
|
||||
height="30px"
|
||||
/>
|
||||
</div>
|
||||
<div class="close-cross-container" @click="onClose">
|
||||
<CloseCrossIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="pm-area__success-modal">
|
||||
<BigCheckMarkIcon class="pm-area__success-modal__icon"/>
|
||||
<h2 class="pm-area__success-modal__title">Congratulations!</h2>
|
||||
<h2 class="pm-area__success-modal__title">You’ve just upgraded your account.</h2>
|
||||
<p class="pm-area__success-modal__info">
|
||||
Now you can have up to 75TB of total storage and 300TB of egress bandwidth per month. If you need more,
|
||||
please
|
||||
<a
|
||||
class="pm-area__success-modal__info__link"
|
||||
:href="limitsIncreaseRequestURL"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
contact us
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
<div class="close-cross-container" @click="onClose">
|
||||
<CloseCrossIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue';
|
||||
import TokenDepositSelection from '@/components/account/billing/paymentMethods/TokenDepositSelection.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
|
||||
import LockImage from '@/../static/images/account/billing/lock.svg';
|
||||
import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
|
||||
import CheckMarkIcon from '@/../static/images/common/greenRoundCheckmark.svg';
|
||||
import BigCheckMarkIcon from '@/../static/images/common/greenRoundCheckmarkBig.svg';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { USER_ACTIONS } from '@/store/modules/users';
|
||||
import { PaymentAmountOption } from '@/types/payments';
|
||||
import { MetaUtils } from '@/utils/meta';
|
||||
|
||||
interface StripeForm {
|
||||
onSubmit(): Promise<void>;
|
||||
}
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
StripeCardInput,
|
||||
VButton,
|
||||
CheckMarkIcon,
|
||||
LockImage,
|
||||
TokenDepositSelection,
|
||||
VLoader,
|
||||
CloseCrossIcon,
|
||||
BigCheckMarkIcon,
|
||||
},
|
||||
})
|
||||
export default class AddPaymentMethodModal extends Vue {
|
||||
@Prop({default: () => false})
|
||||
public readonly onClose: () => void;
|
||||
|
||||
private readonly DEFAULT_TOKEN_DEPOSIT_VALUE = 50; // in dollars.
|
||||
private readonly MAX_TOKEN_AMOUNT = 1000000; // in dollars.
|
||||
private tokenDepositValue: number = this.DEFAULT_TOKEN_DEPOSIT_VALUE;
|
||||
|
||||
public isAddModal: boolean = true;
|
||||
public isAddCard: boolean = true;
|
||||
public isLoading: boolean = false;
|
||||
public coinPaymentsCheckoutLink: string = '';
|
||||
|
||||
public $refs!: {
|
||||
stripeCardInput: StripeCardInput & StripeForm;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set of default payment options.
|
||||
*/
|
||||
public readonly paymentOptions: PaymentAmountOption[] = [
|
||||
new PaymentAmountOption(50, `USD $50`),
|
||||
new PaymentAmountOption(100, `USD $100`),
|
||||
new PaymentAmountOption(200, `USD $200`),
|
||||
new PaymentAmountOption(500, `USD $500`),
|
||||
new PaymentAmountOption(1000, `USD $1000`),
|
||||
];
|
||||
|
||||
/**
|
||||
* Provides card information to Stripe.
|
||||
*/
|
||||
public async onAddCardClick(): Promise<void> {
|
||||
if (this.isLoading) return;
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
await this.$refs.stripeCardInput.onSubmit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds card after Stripe confirmation.
|
||||
*
|
||||
* @param token from Stripe
|
||||
*/
|
||||
public async addCardToDB(token: string) {
|
||||
try {
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.ADD_CREDIT_CARD, token);
|
||||
|
||||
await this.$notify.success('Card successfully added');
|
||||
|
||||
// We fetch User one more time to update their Paid Tier status.
|
||||
await this.$store.dispatch(USER_ACTIONS.GET);
|
||||
|
||||
if (this.$route.name === RouteConfig.Billing.name) {
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_CREDIT_CARDS);
|
||||
}
|
||||
|
||||
if (this.$route.name === RouteConfig.ProjectDashboard.name) {
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.$store.getters.selectedProject.id);
|
||||
}
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
}
|
||||
|
||||
this.isLoading = false;
|
||||
this.isAddModal = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* onAddSTORJClick checks if amount is valid.
|
||||
* If so processes token payment and returns state to default.
|
||||
*/
|
||||
public async onAddSTORJClick(): Promise<void> {
|
||||
if (this.isLoading) return;
|
||||
|
||||
if (this.tokenDepositValue >= this.MAX_TOKEN_AMOUNT || this.tokenDepositValue === 0) {
|
||||
await this.$notify.error('Deposit amount must be more than $0 and less than $1000000');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
try {
|
||||
const tokenResponse = await this.$store.dispatch(PAYMENTS_ACTIONS.MAKE_TOKEN_DEPOSIT, this.tokenDepositValue * 100);
|
||||
await this.$notify.success(`Successfully created new deposit transaction! \nAddress:${tokenResponse.address} \nAmount:${tokenResponse.amount}`);
|
||||
const depositWindow = window.open(tokenResponse.link, '_blank');
|
||||
if (depositWindow) {
|
||||
depositWindow.focus();
|
||||
}
|
||||
|
||||
this.coinPaymentsCheckoutLink = tokenResponse.link;
|
||||
|
||||
if (this.$route.name === RouteConfig.Billing.name) {
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PAYMENTS_HISTORY);
|
||||
}
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
}
|
||||
|
||||
this.tokenDepositValue = this.DEFAULT_TOKEN_DEPOSIT_VALUE;
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets modal state to add STORJ tokens.
|
||||
*/
|
||||
public setIsAddToken(): void {
|
||||
this.isAddCard = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets modal state to add credit card.
|
||||
*/
|
||||
public setIsAddCard(): void {
|
||||
this.isAddCard = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event for changing token deposit value.
|
||||
*/
|
||||
public onChangeTokenValue(value: number): void {
|
||||
this.tokenDepositValue = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns project limits increase request url from config.
|
||||
*/
|
||||
public get limitsIncreaseRequestURL(): string {
|
||||
return MetaUtils.getMetaContent('project-limits-increase-request-url');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pm-area {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
background: rgba(27, 37, 51, 0.75);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
|
||||
&__add-modal {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
width: 660px;
|
||||
position: relative;
|
||||
padding: 45px;
|
||||
|
||||
&__title {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 24px;
|
||||
line-height: 29px;
|
||||
color: #1b2533;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 30px;
|
||||
|
||||
&__sub-title {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&__choices {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&__var {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
color: #a9b5c1;
|
||||
padding: 0 10px 5px 10px;
|
||||
cursor: pointer;
|
||||
border-bottom: 3px solid #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__card {
|
||||
padding-bottom: 20px;
|
||||
|
||||
&__stripe {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
&__info {
|
||||
margin: 50px 0 30px 0;
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&__info-bullet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
&__label {
|
||||
margin-left: 12px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
letter-spacing: 0.473506px;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__tokens {
|
||||
padding-bottom: 30px;
|
||||
|
||||
&__banner {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #384761;
|
||||
padding: 20px 30px;
|
||||
background: #edf4fe;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__selection {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__checkout-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 25px;
|
||||
|
||||
&__link {
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
color: #2683ff;
|
||||
}
|
||||
}
|
||||
|
||||
&__note {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #7b8eab;
|
||||
margin: 25px 0;
|
||||
|
||||
&__bold {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
color: #000;
|
||||
|
||||
&__link {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
text-decoration: underline !important;
|
||||
text-underline-position: under;
|
||||
|
||||
&:visited {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__security {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #cef0e3;
|
||||
padding: 15px 0;
|
||||
border-radius: 0 0 8px 8px;
|
||||
|
||||
&__info {
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
line-height: 18px;
|
||||
color: #1a9666;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&__blur {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-radius: 8px;
|
||||
z-index: 1;
|
||||
background-color: rgba(245, 246, 250, 0.5);
|
||||
|
||||
&__loader {
|
||||
position: absolute;
|
||||
top: 45px;
|
||||
left: calc(-50% + 55px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__success-modal {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
width: 660px;
|
||||
position: relative;
|
||||
padding: 45px 45px 80px 45px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&__icon {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 28px;
|
||||
line-height: 42px;
|
||||
text-align: center;
|
||||
color: #000;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
&__info {
|
||||
margin-top: 40px;
|
||||
font-size: 16px;
|
||||
line-height: 28px;
|
||||
text-align: center;
|
||||
color: #000;
|
||||
max-width: 380px;
|
||||
|
||||
&__link {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
text-decoration: underline !important;
|
||||
text-underline-position: under;
|
||||
|
||||
&:visited {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.close-cross-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 30px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover .close-cross-svg-path {
|
||||
fill: #2683ff;
|
||||
}
|
||||
}
|
||||
|
||||
.left-margin {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #0068dc;
|
||||
border-color: #0068dc;
|
||||
}
|
||||
|
||||
/deep/ .selected-container {
|
||||
width: calc(100% - 2px);
|
||||
}
|
||||
|
||||
/deep/ .custom-input {
|
||||
width: calc(100% - 68px);
|
||||
}
|
||||
|
||||
/deep/ .options-container,
|
||||
/deep/ .payment-selection-blur {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (max-height: 700px) {
|
||||
|
||||
.pm-area {
|
||||
padding: 200px 0 20px 0;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -19,13 +19,13 @@
|
||||
</p>
|
||||
<p class="pt-bar__functional">
|
||||
Upload up to 75TB.
|
||||
<b class="pt-bar__info__bold upgrade">Upgrade now.</b>
|
||||
<b class="pt-bar__info__bold upgrade" @click.stop="openAddPMModal">Upgrade now.</b>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
|
||||
@ -40,6 +40,9 @@ import { Size } from '@/utils/bytesSize';
|
||||
},
|
||||
})
|
||||
export default class PaidTierBar extends Vue {
|
||||
@Prop({default: () => false})
|
||||
public readonly openAddPMModal: () => void;
|
||||
|
||||
/**
|
||||
* Mounted lifecycle hook after initial render.
|
||||
* Fetches total limits.
|
||||
|
@ -8,6 +8,7 @@
|
||||
<TokenDepositSelection
|
||||
class="add-storj-area__selection-container__form"
|
||||
@onChangeTokenValue="onChangeTokenValue"
|
||||
:payment-options="paymentOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="add-storj-area__submit-area">
|
||||
@ -36,6 +37,7 @@ import TokenDepositSelection from '@/components/account/billing/paymentMethods/T
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PaymentAmountOption } from '@/types/payments';
|
||||
|
||||
const {
|
||||
MAKE_TOKEN_DEPOSIT,
|
||||
@ -57,8 +59,19 @@ export default class AddStorjForm extends Vue {
|
||||
public readonly isLoading: boolean;
|
||||
|
||||
/**
|
||||
* onConfirmAddSTORJ checks if amount is valid and if so process token.
|
||||
* payment and return state to default
|
||||
* Set of default payment options.
|
||||
*/
|
||||
public paymentOptions: PaymentAmountOption[] = [
|
||||
new PaymentAmountOption(10, `USD $10`),
|
||||
new PaymentAmountOption(20, `USD $20`),
|
||||
new PaymentAmountOption(50, `USD $50`),
|
||||
new PaymentAmountOption(100, `USD $100`),
|
||||
new PaymentAmountOption(1000, `USD $1000`),
|
||||
];
|
||||
|
||||
/**
|
||||
* onConfirmAddSTORJ checks if amount is valid.
|
||||
* If so processes token payment and returns state to default.
|
||||
*/
|
||||
public async onConfirmAddSTORJ(): Promise<void> {
|
||||
this.$emit('toggleIsLoading');
|
||||
|
@ -430,6 +430,6 @@ export default class PaymentMethods extends Vue {
|
||||
}
|
||||
|
||||
.pm-loader {
|
||||
margin-top: 40px;
|
||||
margin-top: 60px;
|
||||
}
|
||||
</style>
|
||||
|
@ -31,13 +31,12 @@ import {PaymentsHistoryItemType} from "@/types/payments";
|
||||
</label>
|
||||
<div
|
||||
class="options-container"
|
||||
:class="{ 'top-expand': isExpandingTop }"
|
||||
v-if="isSelectionShown"
|
||||
v-click-outside="close"
|
||||
>
|
||||
<div
|
||||
class="options-container__item"
|
||||
v-for="option in options"
|
||||
v-for="option in paymentOptions"
|
||||
:key="option.label"
|
||||
@click.prevent.stop="select(option)"
|
||||
>
|
||||
@ -62,46 +61,34 @@ import {PaymentsHistoryItemType} from "@/types/payments";
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { PaymentAmountOption, PaymentsHistoryItem } from '@/types/payments';
|
||||
import { PaymentAmountOption } from '@/types/payments';
|
||||
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
|
||||
@Component
|
||||
export default class TokenDepositSelection extends Vue {
|
||||
/**
|
||||
* Set of default payment options.
|
||||
*/
|
||||
public paymentOptions: PaymentAmountOption[] = [
|
||||
new PaymentAmountOption(10, `USD $10`),
|
||||
new PaymentAmountOption(20, `USD $20`),
|
||||
new PaymentAmountOption(50, `USD $50`),
|
||||
new PaymentAmountOption(100, `USD $100`),
|
||||
new PaymentAmountOption(1000, `USD $1000`),
|
||||
];
|
||||
|
||||
/**
|
||||
* Set of payment options for the first ever transaction.
|
||||
*/
|
||||
public initialPaymentOptions: PaymentAmountOption[] = [
|
||||
new PaymentAmountOption(10, `USD $10`),
|
||||
new PaymentAmountOption(20, `USD $20`),
|
||||
new PaymentAmountOption(50, `USD $50`),
|
||||
new PaymentAmountOption(100, `USD $100`),
|
||||
new PaymentAmountOption(200, `USD $200`),
|
||||
];
|
||||
@Prop({default: () => []})
|
||||
public readonly paymentOptions: PaymentAmountOption[];
|
||||
|
||||
/**
|
||||
* current selected payment option from default ones.
|
||||
*/
|
||||
public current: PaymentAmountOption = this.paymentOptions[0];
|
||||
public current: PaymentAmountOption;
|
||||
public customAmount: string = '';
|
||||
/**
|
||||
* Indicates if custom amount selection state is active.
|
||||
*/
|
||||
public isCustomAmount = false;
|
||||
|
||||
/**
|
||||
* Lifecycle hook before initial render.
|
||||
* Sets initial deposit amount.
|
||||
*/
|
||||
public beforeMount(): void {
|
||||
this.current = this.paymentOptions[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if concrete payment option is currently selected.
|
||||
*/
|
||||
@ -109,28 +96,6 @@ export default class TokenDepositSelection extends Vue {
|
||||
return (option.value === this.current.value) && !this.isCustomAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if dropdown expands top.
|
||||
*/
|
||||
public get isExpandingTop(): boolean {
|
||||
const hasNoTransactionsOrDepositBonuses: boolean =
|
||||
!this.$store.state.paymentsModule.paymentsHistory.some((item: PaymentsHistoryItem) => item.isTransactionOrDeposit(),
|
||||
);
|
||||
|
||||
return hasNoTransactionsOrDepositBonuses && !this.isOnboardingTour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns payment options depending on user having his own project.
|
||||
*/
|
||||
public get options(): PaymentAmountOption[] {
|
||||
if (this.$store.getters.projectsCount === 0 && this.noCreditCards) {
|
||||
return this.initialPaymentOptions;
|
||||
}
|
||||
|
||||
return this.paymentOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* isSelectionShown flag that indicate is token amount selection shown.
|
||||
*/
|
||||
@ -187,20 +152,6 @@ export default class TokenDepositSelection extends Vue {
|
||||
this.$emit('onChangeTokenValue', option.value);
|
||||
this.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if user has no credit cards.
|
||||
*/
|
||||
private get noCreditCards(): boolean {
|
||||
return this.$store.state.paymentsModule.creditCards.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if app state is in onboarding tour state.
|
||||
*/
|
||||
private get isOnboardingTour(): boolean {
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -357,9 +308,4 @@ export default class TokenDepositSelection extends Vue {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.top-expand {
|
||||
top: -290px;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
</style>
|
||||
|
@ -61,9 +61,11 @@ export default class ProjectDashboard extends Vue {
|
||||
const FIRST_PAGE = 1;
|
||||
|
||||
try {
|
||||
if (!this.isPaidTierStatus) {
|
||||
await this.$store.commit(PAYMENTS_MUTATIONS.TOGGLE_PAID_TIER_BANNER_TO_LOADING);
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.GET_TOTAL_LIMITS);
|
||||
await this.$store.commit(PAYMENTS_MUTATIONS.TOGGLE_PAID_TIER_BANNER_TO_LOADED);
|
||||
}
|
||||
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, FIRST_PAGE);
|
||||
|
||||
@ -92,6 +94,13 @@ export default class ProjectDashboard extends Vue {
|
||||
public get projectLimitsIncreaseRequestURL(): string {
|
||||
return MetaUtils.getMetaContent('project-limits-increase-request-url');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns user's paid tier status from store.
|
||||
*/
|
||||
private get isPaidTierStatus(): boolean {
|
||||
return this.$store.state.usersModule.paidTier;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -137,6 +137,11 @@ export const router = new Router({
|
||||
},
|
||||
component: DashboardArea,
|
||||
children: [
|
||||
{
|
||||
path: RouteConfig.Root.path,
|
||||
name: 'default',
|
||||
component: ProjectDashboard,
|
||||
},
|
||||
{
|
||||
path: RouteConfig.Account.path,
|
||||
name: RouteConfig.Account.name,
|
||||
@ -396,6 +401,12 @@ router.beforeEach(async (to, from, next) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (to.name === 'default') {
|
||||
next(RouteConfig.ProjectDashboard.path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
|
@ -29,6 +29,7 @@ export const PAYMENTS_MUTATIONS = {
|
||||
SET_PRICE_SUMMARY_FOR_SELECTED_PROJECT: 'SET_PRICE_SUMMARY_FOR_SELECTED_PROJECT',
|
||||
TOGGLE_PAID_TIER_BANNER_TO_LOADING: 'TOGGLE_PAID_TIER_BANNER_TO_LOADING',
|
||||
TOGGLE_PAID_TIER_BANNER_TO_LOADED: 'TOGGLE_PAID_TIER_BANNER_TO_LOADED',
|
||||
TOGGLE_IS_ADD_PM_MODAL_SHOWN: 'TOGGLE_IS_ADD_PM_MODAL_SHOWN',
|
||||
};
|
||||
|
||||
export const PAYMENTS_ACTIONS = {
|
||||
@ -61,6 +62,7 @@ const {
|
||||
SET_PRICE_SUMMARY_FOR_SELECTED_PROJECT,
|
||||
TOGGLE_PAID_TIER_BANNER_TO_LOADING,
|
||||
TOGGLE_PAID_TIER_BANNER_TO_LOADED,
|
||||
TOGGLE_IS_ADD_PM_MODAL_SHOWN,
|
||||
} = PAYMENTS_MUTATIONS;
|
||||
|
||||
const {
|
||||
@ -92,6 +94,7 @@ export class PaymentsState {
|
||||
public startDate: Date = new Date();
|
||||
public endDate: Date = new Date();
|
||||
public isPaidTierBarLoading: boolean = true;
|
||||
public isAddPMModalShown: boolean = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,6 +179,9 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState>
|
||||
[TOGGLE_PAID_TIER_BANNER_TO_LOADED](state: PaymentsState): void {
|
||||
state.isPaidTierBarLoading = false;
|
||||
},
|
||||
[TOGGLE_IS_ADD_PM_MODAL_SHOWN](state: PaymentsState): void {
|
||||
state.isAddPMModalShown = !state.isAddPMModalShown;
|
||||
},
|
||||
[CLEAR](state: PaymentsState) {
|
||||
state.balance = new AccountBalance();
|
||||
state.paymentsHistory = [];
|
||||
|
@ -15,7 +15,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="!isLoading" class="dashboard__wrap">
|
||||
<PaidTierBar v-if="!isPaidTierStatus && !isOnboardingTour"/>
|
||||
<PaidTierBar v-if="!isPaidTierStatus && !isOnboardingTour" :open-add-p-m-modal="togglePMModal"/>
|
||||
<DashboardHeader/>
|
||||
<div class="dashboard__wrap__main-area">
|
||||
<NavigationArea class="regular-navigation"/>
|
||||
@ -24,12 +24,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AddPaymentMethodModal v-if="isAddPMModal" :on-close="togglePMModal"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import AddPaymentMethodModal from '@/components/account/billing/paidTier/AddPaymentMethodModal.vue';
|
||||
import PaidTierBar from '@/components/account/billing/paidTier/PaidTierBar.vue';
|
||||
import DashboardHeader from '@/components/header/HeaderArea.vue';
|
||||
import NavigationArea from '@/components/navigation/NavigationArea.vue';
|
||||
@ -39,7 +41,7 @@ import LoaderImage from '@/../static/images/common/loader.svg';
|
||||
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
|
||||
import { RouteConfig } from '@/router';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PAYMENTS_ACTIONS, PAYMENTS_MUTATIONS } from '@/store/modules/payments';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { USER_ACTIONS } from '@/store/modules/users';
|
||||
import { Project } from '@/types/projects';
|
||||
@ -59,6 +61,7 @@ const {
|
||||
DashboardHeader,
|
||||
LoaderImage,
|
||||
PaidTierBar,
|
||||
AddPaymentMethodModal,
|
||||
},
|
||||
})
|
||||
export default class DashboardArea extends Vue {
|
||||
@ -126,6 +129,20 @@ export default class DashboardArea extends Vue {
|
||||
await this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens add payment method modal.
|
||||
*/
|
||||
public togglePMModal(): void {
|
||||
this.$store.commit(PAYMENTS_MUTATIONS.TOGGLE_IS_ADD_PM_MODAL_SHOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if add payment method modal is shown.
|
||||
*/
|
||||
public get isAddPMModal(): boolean {
|
||||
return this.$store.state.paymentsModule.isAddPMModalShown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns user's paid tier status from store.
|
||||
*/
|
||||
|
@ -0,0 +1,5 @@
|
||||
<svg width="23" height="21" viewBox="0 0 23 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<ellipse cx="10.4954" cy="10.3125" rx="10" ry="10" fill="#00D459"/>
|
||||
<path d="M5.19919 11.0717C4.70867 10.5812 4.70867 9.78595 5.19919 9.29544C5.6897 8.80493 6.48498 8.80493 6.97549 9.29544L9.936 12.2559C10.4265 12.7465 10.4265 13.5417 9.936 14.0323C9.44549 14.5228 8.65021 14.5228 8.1597 14.0323L5.19919 11.0717Z" fill="white"/>
|
||||
<path d="M9.936 14.0323C9.44549 14.5228 8.65021 14.5228 8.1597 14.0323C7.66918 13.5417 7.66918 12.7465 8.1597 12.2559L13.4886 6.92704C13.9791 6.43652 14.7744 6.43652 15.2649 6.92703C15.7554 7.41755 15.7554 8.21283 15.2649 8.70334L9.936 14.0323Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 705 B |
@ -0,0 +1,5 @@
|
||||
<svg width="62" height="58" viewBox="0 0 58 58" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<ellipse cx="29.7271" cy="29" rx="29" ry="29" fill="#00D459"/>
|
||||
<path d="M14.3686 31.1928C12.9461 29.7703 12.9461 27.464 14.3686 26.0415C15.7911 24.6191 18.0974 24.6191 19.5199 26.0415L28.1054 34.627C29.5279 36.0495 29.5279 38.3558 28.1054 39.7783C26.6829 41.2008 24.3766 41.2008 22.9541 39.7783L14.3686 31.1928Z" fill="white"/>
|
||||
<path d="M28.1054 39.7783C26.6829 41.2008 24.3766 41.2008 22.9541 39.7783C21.5316 38.3558 21.5316 36.0495 22.9541 34.627L38.4079 19.1732C39.8304 17.7507 42.1367 17.7507 43.5592 19.1732C44.9817 20.5957 44.9817 22.902 43.5592 24.3245L28.1054 39.7783Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 708 B |
@ -29,7 +29,7 @@ exports[`AddStorjForm renders correctly after continue To Coin Payments click 1`
|
||||
<div class="add-storj-area">
|
||||
<div class="add-storj-area__selection-container">
|
||||
<p class="add-storj-area__selection-container__label">Deposit STORJ Tokens via Coin Payments</p>
|
||||
<tokendepositselection-stub class="add-storj-area__selection-container__form"></tokendepositselection-stub>
|
||||
<tokendepositselection-stub paymentoptions="[object Object],[object Object],[object Object],[object Object],[object Object]" class="add-storj-area__selection-container__form"></tokendepositselection-stub>
|
||||
</div>
|
||||
<div class="add-storj-area__submit-area"><img src="@/../static/images/account/billing/loading.gif" alt="loading gif" class="loading-image">
|
||||
<vbutton-stub label="Continue to Coin Payments" width="251px" height="48px" isdisabled="true" onpress="function () { [native code] }" class="confirm-add-storj-button"></vbutton-stub>
|
||||
|
@ -14,6 +14,7 @@ exports[`Dashboard renders correctly when data is loaded 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -24,5 +25,6 @@ exports[`Dashboard renders correctly when data is loading 1`] = `
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
||||
|
Loading…
Reference in New Issue
Block a user