web/satellite: use stripe payment element
This change uses the recommended stripe payment element to collect card information instead of the legacy card element currently in use. Issue: #6436 Change-Id: If931d47430940e0932c845b6eee3e0e23c294fbb
This commit is contained in:
parent
67f32bd519
commit
8f59535f95
@ -119,6 +119,27 @@ export class PaymentsHttpApi implements PaymentsApi {
|
||||
return new ProjectUsagePriceModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add payment method.
|
||||
* @param pmID - stripe payment method id of the credit card
|
||||
* @throws Error
|
||||
*/
|
||||
public async addCardByPaymentMethodID(pmID: string): Promise<void> {
|
||||
const path = `${this.ROOT_PATH}/payment-methods`;
|
||||
const response = await this.client.post(path, pmID);
|
||||
|
||||
if (response.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
throw new APIError({
|
||||
status: response.status,
|
||||
message: result.error || 'Can not add payment method',
|
||||
requestID: response.headers.get('x-request-id'),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add credit card.
|
||||
*
|
||||
@ -474,12 +495,12 @@ export class PaymentsHttpApi implements PaymentsApi {
|
||||
/**
|
||||
* Purchases the pricing package associated with the user's partner.
|
||||
*
|
||||
* @param token - the Stripe token used to add a credit card as a payment method
|
||||
* @param pmID - the Stripe payment method id of the credit card
|
||||
* @throws Error
|
||||
*/
|
||||
public async purchasePricingPackage(token: string): Promise<void> {
|
||||
const path = `${this.ROOT_PATH}/purchase-package`;
|
||||
const response = await this.client.post(path, token);
|
||||
public async purchasePricingPackage(pmID: string): Promise<void> {
|
||||
const path = `${this.ROOT_PATH}/purchase-package?pmID=true`;
|
||||
const response = await this.client.post(path, pmID);
|
||||
|
||||
if (response.ok) {
|
||||
return;
|
||||
|
@ -27,7 +27,7 @@
|
||||
@remove="removePaymentMethodHandler"
|
||||
/>
|
||||
</div>
|
||||
<div class="payments-area__container__new-payments">
|
||||
<div class="payments-area__container__new-payments" :class="{ 'white-background': isAddingPayment }">
|
||||
<div v-if="!isAddingPayment" class="payments-area__container__new-payments__text-area">
|
||||
<span>+ </span>
|
||||
<span
|
||||
@ -41,10 +41,10 @@
|
||||
</div>
|
||||
<div class="payments-area__create-header">Credit Card</div>
|
||||
<div class="payments-area__create-subheader">Add Card Info</div>
|
||||
<StripeCardInput
|
||||
<StripeCardElement
|
||||
ref="stripeCardInput"
|
||||
class="add-card-area__stripe stripe_input"
|
||||
:on-stripe-response-callback="addCard"
|
||||
@pm-created="addCard"
|
||||
/>
|
||||
<VButton
|
||||
class="add-card-button"
|
||||
@ -202,12 +202,12 @@ import { useLoading } from '@/composables/useLoading';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import VLoader from '@/components/common/VLoader.vue';
|
||||
import CreditCardContainer from '@/components/account/billing/billingTabs/CreditCardContainer.vue';
|
||||
import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue';
|
||||
import SortingHeader from '@/components/account/billing/billingTabs/SortingHeader.vue';
|
||||
import AddTokenCard from '@/components/account/billing/paymentMethods/AddTokenCard.vue';
|
||||
import AddTokenCardNative from '@/components/account/billing/paymentMethods/AddTokenCardNative.vue';
|
||||
import TokenTransactionItem from '@/components/account/billing/paymentMethods/TokenTransactionItem.vue';
|
||||
import VTable from '@/components/common/VTable.vue';
|
||||
import StripeCardElement from '@/components/account/billing/paymentMethods/StripeCardElement.vue';
|
||||
|
||||
import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
|
||||
import AmericanExpressIcon from '@/../static/images/payments/cardIcons/smallamericanexpress.svg';
|
||||
@ -381,12 +381,13 @@ function closeAddPayment(): void {
|
||||
isAddingPayment.value = false;
|
||||
}
|
||||
|
||||
async function addCard(token: string): Promise<void> {
|
||||
async function addCard(pmID: string): Promise<void> {
|
||||
try {
|
||||
await billingStore.addCreditCard(token);
|
||||
await billingStore.addCardByPaymentMethodID(pmID);
|
||||
// We fetch User one more time to update their Paid Tier status.
|
||||
await usersStore.getUser();
|
||||
} catch (error) {
|
||||
isLoading.value = false;
|
||||
notify.notifyError(error, AnalyticsErrorEventSource.BILLING_PAYMENT_METHODS_TAB);
|
||||
return;
|
||||
}
|
||||
@ -770,7 +771,7 @@ $align: center;
|
||||
|
||||
&__new-payments {
|
||||
width: 348px;
|
||||
height: 203px;
|
||||
min-height: 203px;
|
||||
padding: 24px;
|
||||
box-sizing: border-box;
|
||||
border: 2px dashed var(--c-grey-5);
|
||||
@ -779,6 +780,10 @@ $align: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.white-background {
|
||||
background: var(--c-white);
|
||||
}
|
||||
|
||||
&__text-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -0,0 +1,185 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<form id="payment-form">
|
||||
<div class="form-row">
|
||||
<div id="payment-element">
|
||||
<!-- A Stripe Element will be inserted here. -->
|
||||
</div>
|
||||
<div id="card-errors" role="alert" />
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { loadStripe } from '@stripe/stripe-js/pure';
|
||||
import { Stripe, StripeElements, StripePaymentElement } from '@stripe/stripe-js';
|
||||
import { StripeElementsOptionsMode } from '@stripe/stripe-js/types/stripe-js/elements-group';
|
||||
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
import { useLoading } from '@/composables/useLoading';
|
||||
import { useBillingStore } from '@/store/modules/billingStore';
|
||||
|
||||
const configStore = useConfigStore();
|
||||
const billingStore = useBillingStore();
|
||||
const notify = useNotify();
|
||||
const { withLoading, isLoading } = useLoading();
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
isDarkTheme?: boolean
|
||||
}>(), {
|
||||
isDarkTheme: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'pmCreated', pmID: string): void
|
||||
}>();
|
||||
|
||||
/**
|
||||
* Stripe elements is used to create 'Add Card' form.
|
||||
*/
|
||||
const paymentElement = ref<StripePaymentElement>();
|
||||
/**
|
||||
* Stripe library.
|
||||
*/
|
||||
const stripe = ref<Stripe | null>(null);
|
||||
const elements = ref<StripeElements | null>(null);
|
||||
|
||||
/**
|
||||
* Stripe initialization.
|
||||
*/
|
||||
async function initStripe(): Promise<void> {
|
||||
const stripePublicKey = configStore.state.config.stripePublicKey;
|
||||
|
||||
try {
|
||||
stripe.value = await loadStripe(stripePublicKey);
|
||||
} catch (error) {
|
||||
notify.error(error.message, AnalyticsErrorEventSource.BILLING_STRIPE_CARD_INPUT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stripe.value) {
|
||||
notify.error('Unable to initialize stripe', AnalyticsErrorEventSource.BILLING_STRIPE_CARD_INPUT);
|
||||
return;
|
||||
}
|
||||
|
||||
const options: StripeElementsOptionsMode = {
|
||||
mode: 'setup',
|
||||
currency: 'usd',
|
||||
paymentMethodCreation: 'manual',
|
||||
paymentMethodTypes: ['card'],
|
||||
appearance: {
|
||||
theme: props.isDarkTheme ? 'night' : 'stripe',
|
||||
labels: 'floating',
|
||||
},
|
||||
};
|
||||
elements.value = stripe.value?.elements(options);
|
||||
|
||||
if (!elements.value) {
|
||||
notify.error('Unable to instantiate elements', AnalyticsErrorEventSource.BILLING_STRIPE_CARD_INPUT);
|
||||
return;
|
||||
}
|
||||
|
||||
paymentElement.value = elements.value.create('payment');
|
||||
if (!paymentElement.value) {
|
||||
notify.error('Unable to create card element', AnalyticsErrorEventSource.BILLING_STRIPE_CARD_INPUT);
|
||||
return;
|
||||
}
|
||||
|
||||
paymentElement.value?.mount('#payment-element');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires stripe event after all inputs are filled.
|
||||
*/
|
||||
function onSubmit(): void {
|
||||
|
||||
const displayError: HTMLElement = document.getElementById('card-errors') as HTMLElement;
|
||||
|
||||
withLoading(async () => {
|
||||
if (!(stripe.value && elements.value && paymentElement.value)) {
|
||||
notify.error('Stripe is not initialized', AnalyticsErrorEventSource.BILLING_STRIPE_CARD_INPUT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger form validation
|
||||
const res = await elements.value.submit();
|
||||
if (res.error) {
|
||||
displayError.textContent = res.error.message ?? '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the PaymentMethod using the details collected by the Payment Element
|
||||
const { error, paymentMethod } = await stripe.value.createPaymentMethod({
|
||||
elements: elements.value,
|
||||
});
|
||||
if (error) {
|
||||
displayError.textContent = error.message ?? '';
|
||||
return;
|
||||
}
|
||||
|
||||
if (paymentMethod.card?.funding === 'prepaid') {
|
||||
displayError.textContent = 'Prepaid cards are not supported';
|
||||
return;
|
||||
}
|
||||
|
||||
emit('pmCreated', paymentMethod.id);
|
||||
});
|
||||
}
|
||||
|
||||
watch(() => props.isDarkTheme, isDarkTheme => {
|
||||
elements.value?.update({
|
||||
appearance: {
|
||||
theme: isDarkTheme ? 'night' : 'stripe',
|
||||
labels: 'floating',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Stripe library loading and initialization.
|
||||
*/
|
||||
onMounted(() => {
|
||||
initStripe();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
onSubmit,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.StripeElement {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding-bottom: 14px;
|
||||
border-radius: 4px;
|
||||
transition: box-shadow 150ms ease;
|
||||
}
|
||||
|
||||
.StripeElement--focus {
|
||||
box-shadow: 0 1px 3px 0 #cfd7df;
|
||||
}
|
||||
|
||||
.StripeElement--invalid {
|
||||
border-color: #fa755a;
|
||||
}
|
||||
|
||||
.StripeElement--webkit-autofill {
|
||||
background-color: #fefde5 !important;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#card-errors {
|
||||
text-align: left;
|
||||
font-family: 'font-medium', sans-serif;
|
||||
color: var(--c-red-2);
|
||||
}
|
||||
</style>
|
@ -26,10 +26,10 @@
|
||||
<div class="content__bottom">
|
||||
<div v-if="!isFree" class="content__bottom__card-area">
|
||||
<p class="content__bottom__card-area__label">Add Card Info</p>
|
||||
<StripeCardInput
|
||||
<StripeCardElement
|
||||
ref="stripeCardInput"
|
||||
class="content__bottom__card-area__input"
|
||||
:on-stripe-response-callback="onCardAdded"
|
||||
@pm-created="onCardAdded"
|
||||
/>
|
||||
</div>
|
||||
<VButton
|
||||
@ -89,9 +89,9 @@ import { useBillingStore } from '@/store/modules/billingStore';
|
||||
import { useAppStore } from '@/store/modules/appStore';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
|
||||
import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import VModal from '@/components/common/VModal.vue';
|
||||
import StripeCardElement from '@/components/account/billing/paymentMethods/StripeCardElement.vue';
|
||||
|
||||
import CheckIcon from '@/../static/images/common/check.svg';
|
||||
import CircleCheck from '@/../static/images/onboardingTour/circleCheck.svg';
|
||||
@ -111,7 +111,7 @@ const notify = useNotify();
|
||||
const isLoading = ref<boolean>(false);
|
||||
const isSuccess = ref<boolean>(false);
|
||||
|
||||
const stripeCardInput = ref<(typeof StripeCardInput & StripeForm) | null>(null);
|
||||
const stripeCardInput = ref<StripeForm | null>(null);
|
||||
|
||||
/**
|
||||
* Returns the pricing plan selected from the onboarding tour.
|
||||
@ -165,16 +165,16 @@ function onActivateClick(): void {
|
||||
/**
|
||||
* Adds card after Stripe confirmation.
|
||||
*/
|
||||
async function onCardAdded(token: string): Promise<void> {
|
||||
async function onCardAdded(pmID: string): Promise<void> {
|
||||
if (!plan.value) return;
|
||||
|
||||
let action = billingStore.addCreditCard;
|
||||
let action = billingStore.addCardByPaymentMethodID;
|
||||
if (plan.value.type === PricingPlanType.PARTNER) {
|
||||
action = billingStore.purchasePricingPackage;
|
||||
}
|
||||
|
||||
try {
|
||||
await action(token);
|
||||
await action(pmID);
|
||||
isSuccess.value = true;
|
||||
|
||||
// Fetch user to update paid tier status
|
||||
|
@ -8,9 +8,9 @@
|
||||
By saving your card information, you allow Storj to charge your card for future payments in accordance with
|
||||
the terms.
|
||||
</p>
|
||||
<StripeCardInput
|
||||
<StripeCardElement
|
||||
ref="stripeCardInput"
|
||||
:on-stripe-response-callback="addCardToDB"
|
||||
@pm-created="addCardToDB"
|
||||
/>
|
||||
<VButton
|
||||
class="button"
|
||||
@ -42,8 +42,8 @@ import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
|
||||
|
||||
import UpgradeAccountWrapper from '@/components/modals/upgradeAccountFlow/UpgradeAccountWrapper.vue';
|
||||
import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import StripeCardElement from '@/components/account/billing/paymentMethods/StripeCardElement.vue';
|
||||
|
||||
interface StripeForm {
|
||||
onSubmit(): Promise<void>;
|
||||
@ -62,7 +62,7 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const stripeCardInput = ref<typeof StripeCardInput & StripeForm | null>(null);
|
||||
const stripeCardInput = ref<StripeForm | null>(null);
|
||||
|
||||
/**
|
||||
* Provides card information to Stripe.
|
||||
@ -83,11 +83,11 @@ async function onSaveCardClick(): Promise<void> {
|
||||
/**
|
||||
* Adds card after Stripe confirmation.
|
||||
*
|
||||
* @param token from Stripe
|
||||
* @param pmID from Stripe
|
||||
*/
|
||||
async function addCardToDB(token: string): Promise<void> {
|
||||
async function addCardToDB(pmID: string): Promise<void> {
|
||||
try {
|
||||
await billingStore.addCreditCard(token);
|
||||
await billingStore.addCardByPaymentMethodID(pmID);
|
||||
notify.success('Card successfully added');
|
||||
// We fetch User one more time to update their Paid Tier status.
|
||||
await usersStore.getUser();
|
||||
|
@ -72,6 +72,10 @@ export const useBillingStore = defineStore('billing', () => {
|
||||
await api.addCreditCard(token);
|
||||
}
|
||||
|
||||
async function addCardByPaymentMethodID(pmID: string): Promise<void> {
|
||||
await api.addCardByPaymentMethodID(pmID);
|
||||
}
|
||||
|
||||
function toggleCardSelection(id: string): void {
|
||||
state.creditCards = state.creditCards.map(card => {
|
||||
if (card.id === id) {
|
||||
@ -183,8 +187,8 @@ export const useBillingStore = defineStore('billing', () => {
|
||||
state.coupon = await api.getCoupon();
|
||||
}
|
||||
|
||||
async function purchasePricingPackage(token: string): Promise<void> {
|
||||
await api.purchasePricingPackage(token);
|
||||
async function purchasePricingPackage(pmID: string): Promise<void> {
|
||||
await api.purchasePricingPackage(pmID);
|
||||
}
|
||||
|
||||
function clear(): void {
|
||||
@ -209,6 +213,7 @@ export const useBillingStore = defineStore('billing', () => {
|
||||
setupAccount,
|
||||
getCreditCards,
|
||||
addCreditCard,
|
||||
addCardByPaymentMethodID,
|
||||
toggleCardSelection,
|
||||
clearCardsSelection,
|
||||
makeCardDefault,
|
||||
|
@ -49,6 +49,13 @@ export interface PaymentsApi {
|
||||
*/
|
||||
addCreditCard(token: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Add payment method.
|
||||
* @param pmID - stripe payment method id of the credit card
|
||||
* @throws Error
|
||||
*/
|
||||
addCardByPaymentMethodID(pmID: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Detach credit card from payment account.
|
||||
* @param cardId
|
||||
@ -128,10 +135,10 @@ export interface PaymentsApi {
|
||||
/**
|
||||
* Purchases the pricing package associated with the user's partner.
|
||||
*
|
||||
* @param token - the Stripe token used to add a credit card as a payment method
|
||||
* @param pmID - the Stripe payment method id of the credit card
|
||||
* @throws Error
|
||||
*/
|
||||
purchasePricingPackage(token: string): Promise<void>;
|
||||
purchasePricingPackage(pmID: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns whether there is a pricing package configured for the user's partner.
|
||||
|
@ -7,10 +7,10 @@
|
||||
<v-btn v-if="!isCardInputShown" variant="outlined" color="default" size="small" class="mr-2" @click="isCardInputShown = true">+ Add New Card</v-btn>
|
||||
|
||||
<template v-else>
|
||||
<StripeCardInput
|
||||
<StripeCardElement
|
||||
ref="stripeCardInput"
|
||||
class="mb-4"
|
||||
:on-stripe-response-callback="addCardToDB"
|
||||
:is-dark-theme="theme.global.current.value.dark"
|
||||
@pm-created="addCardToDB"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@ -26,7 +26,6 @@
|
||||
<v-btn
|
||||
variant="outlined" color="default" size="small" class="mr-2"
|
||||
:disabled="isLoading"
|
||||
:loading="isLoading"
|
||||
@click="isCardInputShown = false"
|
||||
>
|
||||
Cancel
|
||||
@ -37,8 +36,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { VBtn, VCard, VCardText, VCardActions } from 'vuetify/components';
|
||||
import { VBtn, VCard, VCardText } from 'vuetify/components';
|
||||
import { ref } from 'vue';
|
||||
import { useTheme } from 'vuetify';
|
||||
|
||||
import { useUsersStore } from '@/store/modules/usersStore';
|
||||
import { useLoading } from '@/composables/useLoading';
|
||||
@ -46,7 +46,7 @@ import { useNotify } from '@/utils/hooks';
|
||||
import { useBillingStore } from '@/store/modules/billingStore';
|
||||
import { AnalyticsErrorEventSource } from '@/utils/constants/analyticsEventNames';
|
||||
|
||||
import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue';
|
||||
import StripeCardElement from '@/components/account/billing/paymentMethods/StripeCardElement.vue';
|
||||
|
||||
interface StripeForm {
|
||||
onSubmit(): Promise<void>;
|
||||
@ -55,9 +55,10 @@ interface StripeForm {
|
||||
const usersStore = useUsersStore();
|
||||
const notify = useNotify();
|
||||
const billingStore = useBillingStore();
|
||||
const theme = useTheme();
|
||||
const { isLoading } = useLoading();
|
||||
|
||||
const stripeCardInput = ref<typeof StripeCardInput & StripeForm | null>(null);
|
||||
const stripeCardInput = ref<StripeForm | null>(null);
|
||||
|
||||
const isCardInputShown = ref(false);
|
||||
|
||||
@ -79,12 +80,12 @@ async function onSaveCardClick(): Promise<void> {
|
||||
/**
|
||||
* Adds card after Stripe confirmation.
|
||||
*
|
||||
* @param token from Stripe
|
||||
* @param pmID - payment method ID from Stripe
|
||||
*/
|
||||
async function addCardToDB(token: string): Promise<void> {
|
||||
async function addCardToDB(pmID: string): Promise<void> {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
await billingStore.addCreditCard(token);
|
||||
await billingStore.addCardByPaymentMethodID(pmID);
|
||||
notify.success('Card successfully added');
|
||||
isCardInputShown.value = false;
|
||||
isLoading.value = false;
|
||||
|
@ -10,9 +10,10 @@
|
||||
<v-divider />
|
||||
|
||||
<div class="py-4">
|
||||
<StripeCardInput
|
||||
<StripeCardElement
|
||||
ref="stripeCardInput"
|
||||
:on-stripe-response-callback="addCardToDB"
|
||||
:is-dark-theme="theme.global.current.value.dark"
|
||||
@pm-created="addCardToDB"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -51,6 +52,7 @@
|
||||
import { ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { VDivider, VBtn, VIcon, VCol, VRow } from 'vuetify/components';
|
||||
import { useTheme } from 'vuetify';
|
||||
|
||||
import { AnalyticsErrorEventSource, AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { RouteConfig } from '@/types/router';
|
||||
@ -60,7 +62,7 @@ import { useUsersStore } from '@/store/modules/usersStore';
|
||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
|
||||
|
||||
import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue';
|
||||
import StripeCardElement from '@/components/account/billing/paymentMethods/StripeCardElement.vue';
|
||||
|
||||
interface StripeForm {
|
||||
onSubmit(): Promise<void>;
|
||||
@ -71,6 +73,7 @@ const usersStore = useUsersStore();
|
||||
const billingStore = useBillingStore();
|
||||
const projectsStore = useProjectsStore();
|
||||
const notify = useNotify();
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
@ -80,7 +83,7 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const stripeCardInput = ref<typeof StripeCardInput & StripeForm | null>(null);
|
||||
const stripeCardInput = ref<StripeForm | null>(null);
|
||||
|
||||
/**
|
||||
* Provides card information to Stripe.
|
||||
@ -101,12 +104,12 @@ async function onSaveCardClick(): Promise<void> {
|
||||
/**
|
||||
* Adds card after Stripe confirmation.
|
||||
*
|
||||
* @param token from Stripe
|
||||
* @param pmID - payment method ID from Stripe
|
||||
*/
|
||||
async function addCardToDB(token: string): Promise<void> {
|
||||
async function addCardToDB(pmID: string): Promise<void> {
|
||||
loading.value = true;
|
||||
try {
|
||||
await billingStore.addCreditCard(token);
|
||||
await billingStore.addCardByPaymentMethodID(pmID);
|
||||
notify.success('Card successfully added');
|
||||
// We fetch User one more time to update their Paid Tier status.
|
||||
await usersStore.getUser();
|
||||
|
@ -33,10 +33,10 @@
|
||||
|
||||
<div v-if="!isFree" class="py-4">
|
||||
<p class="text-caption">Add Card Info</p>
|
||||
<StripeCardInput
|
||||
<StripeCardElement
|
||||
ref="stripeCardInput"
|
||||
class="content__bottom__card-area__input"
|
||||
:on-stripe-response-callback="onCardAdded"
|
||||
:is-dark-theme="theme.global.current.value.dark"
|
||||
@pm-created="onCardAdded"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -110,6 +110,7 @@
|
||||
import { computed, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { VBtn, VCol, VIcon, VRow } from 'vuetify/components';
|
||||
import { useTheme } from 'vuetify';
|
||||
|
||||
import { PricingPlanInfo, PricingPlanType } from '@/types/common';
|
||||
import { useNotify } from '@/utils/hooks';
|
||||
@ -117,7 +118,7 @@ import { useUsersStore } from '@/store/modules/usersStore';
|
||||
import { useBillingStore } from '@/store/modules/billingStore';
|
||||
import { useConfigStore } from '@/store/modules/configStore';
|
||||
|
||||
import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue';
|
||||
import StripeCardElement from '@/components/account/billing/paymentMethods/StripeCardElement.vue';
|
||||
|
||||
interface StripeForm {
|
||||
onSubmit(): Promise<void>;
|
||||
@ -128,11 +129,12 @@ const billingStore = useBillingStore();
|
||||
const usersStore = useUsersStore();
|
||||
const router = useRouter();
|
||||
const notify = useNotify();
|
||||
const theme = useTheme();
|
||||
|
||||
const isLoading = ref<boolean>(false);
|
||||
const isSuccess = ref<boolean>(false);
|
||||
|
||||
const stripeCardInput = ref<(typeof StripeCardInput & StripeForm) | null>(null);
|
||||
const stripeCardInput = ref<StripeForm | null>(null);
|
||||
|
||||
const props = defineProps<{
|
||||
plan: PricingPlanInfo;
|
||||
@ -174,14 +176,14 @@ async function onActivateClick() {
|
||||
/**
|
||||
* Adds card after Stripe confirmation.
|
||||
*/
|
||||
async function onCardAdded(token: string): Promise<void> {
|
||||
let action = billingStore.addCreditCard;
|
||||
async function onCardAdded(pmID: string): Promise<void> {
|
||||
let action = billingStore.addCardByPaymentMethodID;
|
||||
if (props.plan.type === PricingPlanType.PARTNER) {
|
||||
action = billingStore.purchasePricingPackage;
|
||||
}
|
||||
|
||||
try {
|
||||
await action(token);
|
||||
await action(pmID);
|
||||
isSuccess.value = true;
|
||||
|
||||
// Fetch user to update paid tier status
|
||||
|
@ -166,15 +166,15 @@
|
||||
|
||||
<v-window-item>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="4">
|
||||
<v-col cols="12" md="4" sm="6">
|
||||
<StorjTokenCardComponent @historyClicked="goToTransactionsTab" />
|
||||
</v-col>
|
||||
|
||||
<v-col v-for="(card, i) in creditCards" :key="i" cols="12" sm="4">
|
||||
<v-col v-for="(card, i) in creditCards" :key="i" cols="12" md="4" sm="6">
|
||||
<CreditCardComponent :card="card" />
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="4">
|
||||
<v-col cols="12" md="4" sm="6">
|
||||
<AddCreditCardComponent />
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
Loading…
Reference in New Issue
Block a user