mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-28 02:50:39 +00:00
Payment setting frontend part 2 - payment setup front/backend
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
<template>
|
||||
<PageTab>
|
||||
<!--Global payment settings-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="dollar">
|
||||
{{ $t('Subscription Payments') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Subscription Payments')" :description="$t('User can subscribe to fixed or metered plan')" :is-last="! allowedPayments">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowedPayments', allowedPayments)" v-model="allowedPayments" :state="allowedPayments" />
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_payments', allowedPayments)" v-model="allowedPayments" :state="allowedPayments" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<AppInputText v-if="allowedPayments" :title="$t('Subscription Type')" :is-last="true">
|
||||
@@ -20,14 +21,14 @@
|
||||
{{ $t('Stripe') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Stripe Service')" :description="$t('Allow your users pay by their credit card')" :is-last="! stripe.allowStripe">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'payments_active', stripe.allowStripe)" v-model="stripe.allowStripe" :state="stripe.allowStripe" />
|
||||
<AppInputSwitch :title="$t('Allow Stripe Service')" :description="$t('Allow your users pay by their credit card')" :is-last="! stripe.allowedService">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_stripe', stripe.allowedService)" v-model="stripe.allowedService" :state="stripe.allowedService" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Stripe credentials are set up-->
|
||||
<div v-if="stripe.allowStripe">
|
||||
<div v-if="stripe.allowedService">
|
||||
<div v-if="stripe.isConfigured">
|
||||
<AppInputText :title="$t('Payment Description')" :description="$t('The description showed below user payment method selection.')">
|
||||
<AppInputText @input="$updateText('/admin/settings', 'stripe_payment_description', stripe.paymentDescription)" :title="$t('Payment Description')" :description="$t('The description showed below user payment method selection.')">
|
||||
<textarea rows="2" @input="$updateText('/admin/settings', 'stripe_payment_description', stripe.paymentDescription, true)" v-model="stripe.paymentDescription" :placeholder="$t('Describe in short which methods user can pay with this payment method...')" type="text" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
|
||||
@@ -42,7 +43,14 @@
|
||||
</div>
|
||||
|
||||
<!--Set up Stripe credentials-->
|
||||
<ValidationObserver v-if="! stripe.isConfigured || stripe.isVisibleCredentialsForm" @submit.prevent="stripeCredentialsSubmit" ref="stripeCredentials" v-slot="{ invalid }" tag="form" class="p-5 border rounded-xl">
|
||||
<ValidationObserver
|
||||
v-if="! stripe.isConfigured || stripe.isVisibleCredentialsForm"
|
||||
@submit.prevent="storeCredentials('stripe')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="p-5 border rounded-xl"
|
||||
>
|
||||
<FormLabel icon="shield">
|
||||
{{ $t('Configure Your Stripe Credentials') }}
|
||||
</FormLabel>
|
||||
@@ -122,13 +130,33 @@
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
allowedPayments: false,
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
allowedPayments: true,
|
||||
stripe: {
|
||||
allowStripe: true,
|
||||
isConfigured: true,
|
||||
allowedService: true,
|
||||
isConfigured: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
paymentDescription: undefined,
|
||||
credentials: {
|
||||
key: 'test',
|
||||
secret: 'test',
|
||||
}
|
||||
},
|
||||
paystack: {
|
||||
allowedService: true,
|
||||
isConfigured: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
paymentDescription: undefined,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
}
|
||||
},
|
||||
paypal: {
|
||||
allowedService: true,
|
||||
isConfigured: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
paymentDescription: undefined,
|
||||
credentials: {
|
||||
@@ -139,58 +167,88 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async stripeCredentialsSubmit() {
|
||||
async storeCredentials(service) {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.stripeCredentials.validate();
|
||||
const isValid = await this.$refs.credentialsForm.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
let credentials = {
|
||||
stripe: {
|
||||
service: 'stripe',
|
||||
key: this.stripe.credentials.key,
|
||||
secret: this.stripe.credentials.secret,
|
||||
},
|
||||
paystack: {
|
||||
service: 'paystack',
|
||||
key: this.paystack.credentials.key,
|
||||
secret: this.paystack.credentials.secret,
|
||||
},
|
||||
paypal: {
|
||||
service: 'paypal',
|
||||
key: this.paypal.credentials.key,
|
||||
secret: this.paypal.credentials.secret,
|
||||
},
|
||||
}
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/admin/settings/stripe', this.stripeCredentials)
|
||||
.post('/api/admin/settings/payment-service', credentials[service])
|
||||
.then(() => {
|
||||
|
||||
// Store Stripe Public
|
||||
this.$store.commit('SET_STRIPE_PUBLIC_KEY', this.stripeCredentials.key)
|
||||
// Update Credentials
|
||||
let commitKey = {
|
||||
stripe: 'SET_STRIPE_CREDENTIALS',
|
||||
paystack: 'SET_PAYSTACK_CREDENTIALS',
|
||||
paypal: 'SET_PAYPAL_CREDENTIALS',
|
||||
}[service]
|
||||
|
||||
// Commit credentials
|
||||
this.$store.commit(commitKey, credentials[service])
|
||||
|
||||
this[service].allowedService = true
|
||||
this[service].isConfigured = true
|
||||
this[service].isVisibleCredentialsForm = false
|
||||
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.stripe_set'),
|
||||
message: this.$t('toaster.credentials_set', {service: service}),
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status = 401) {
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
.finally(() => this.isLoading = false)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
axios.get('/api/admin/settings', {
|
||||
params: {
|
||||
column: 'payments_active|payments_configured'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.isLoading = false
|
||||
this.stripe.paymentDescription = this.config.stripe_payment_description
|
||||
this.paystack.paymentDescription = this.config.paystack_payment_description
|
||||
this.paypal.paymentDescription = this.config.paypal_payment_description
|
||||
|
||||
this.payments = {
|
||||
configured: parseInt(response.data.payments_configured),
|
||||
status: parseInt(response.data.payments_active),
|
||||
}
|
||||
})
|
||||
this.stripe.allowedService = this.config.isStripe
|
||||
this.paystack.allowedService = this.config.isPaystack
|
||||
this.paypal.allowedService = this.config.isPayPal
|
||||
|
||||
if (this.config.stripe_public_key)
|
||||
this.stripe.isConfigured = true
|
||||
|
||||
if (this.config.paystack_public_key)
|
||||
this.paystack.isConfigured = true
|
||||
|
||||
if (this.config.paypal_client_id)
|
||||
this.paypal.isConfigured = true
|
||||
|
||||
this.allowedPayments = this.config.allowed_payments
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,820 +0,0 @@
|
||||
<template>
|
||||
<div id="single-page">
|
||||
<div id="page-content" class="large-width center-page" v-show="! isLoading">
|
||||
<MobileHeader :title="$t($router.currentRoute.meta.title)" />
|
||||
<div class="content-page">
|
||||
<div class="plan-title">
|
||||
<credit-card-icon size="42" class="title-icon text-theme" />
|
||||
<h1>{{ $t('page_upgrade_account.title') }}</h1>
|
||||
<h2>{{ $t('page_upgrade_account.desription') }}</h2>
|
||||
</div>
|
||||
<div class="order">
|
||||
<div class="steps">
|
||||
|
||||
<div class="payment-card">
|
||||
<FormLabel>{{ $t('page_upgrade_account.section_card') }}</FormLabel>
|
||||
|
||||
<!-- Pay by new credit card -->
|
||||
<div class="register-card" v-show="! defaultPaymentMethod || payByNewCard">
|
||||
<InfoBox v-if="config.isDemo || config.isDev">
|
||||
<p>For test your payment please use <b class="text-theme">4242 4242 4242 4242</b> or <b class="text-theme">5555 5555 5555 4444</b> as a card number, <b class="text-theme">11/22</b>
|
||||
as the expiration date and <b class="text-theme">123</b> as CVC number and ZIP <b class="text-theme">12345</b>.</p>
|
||||
</InfoBox>
|
||||
|
||||
<div ref="stripeCard" class="stripe-card" :class="{'is-error': isError }"></div>
|
||||
|
||||
<div class="card-error-message" v-if="isError">
|
||||
<span>{{ errorMessage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--User registered payment card-->
|
||||
<div class="registered-cards" v-if="defaultPaymentMethod && ! payByNewCard">
|
||||
|
||||
<div class="credit-card" :class="{'is-error': isError}">
|
||||
<div class="card-number">
|
||||
<img class="credit-card-icon"
|
||||
:src="$getCreditCardBrand(defaultPaymentMethod.data.attributes.brand)"
|
||||
:alt="defaultPaymentMethod.data.attributes.brand">
|
||||
<div class="credit-card-numbers">
|
||||
•••• {{ defaultPaymentMethod.data.attributes.last4 }}
|
||||
</div>
|
||||
<ColorLabel color="purple">{{ $t('global.default') }}</ColorLabel>
|
||||
</div>
|
||||
<div class="expiration-date">
|
||||
<span>{{ defaultPaymentMethod.data.attributes.exp_month }} / {{ defaultPaymentMethod.data.attributes.exp_year }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Change payment-->
|
||||
<div class="change-payment" v-if="! isError">
|
||||
<span>
|
||||
{{ $t('page_upgrade_account.change_payment.you_can') }}
|
||||
</span>
|
||||
|
||||
<router-link v-if="PaymentMethods.data.length > 0" :to="{name: 'PaymentMethods'}">
|
||||
{{ $t('page_upgrade_account.change_payment.change_payment') }}
|
||||
</router-link>
|
||||
|
||||
<span v-if="PaymentMethods.data.length > 0">
|
||||
{{ $t('global.or') }}
|
||||
</span>
|
||||
|
||||
<a @click="payByNewCardForm">
|
||||
{{ $t('page_upgrade_account.change_payment.pay_by_new_card') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!--Card error-->
|
||||
<div class="card-error-message" v-if="isError">
|
||||
<span>{{ errorMessage }}</span>
|
||||
<span @click="payByNewCardForm" class="link">
|
||||
{{ $t('page_upgrade_account.errors.pay_by_another_card') }}
|
||||
</span>
|
||||
<span>
|
||||
{{ $t('global.or') }}
|
||||
</span>
|
||||
<router-link :to="{name: 'PaymentMethods'}" class="link">
|
||||
{{ $t('page_upgrade_account.change_payment.change_payment') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="billing" v-if="billing">
|
||||
<FormLabel>{{ $t('page_upgrade_account.section_billing') }}</FormLabel>
|
||||
|
||||
<ValidationObserver ref="order" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<div class="form block-form">
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>{{ $t('user_settings.name') }}:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
|
||||
rules="required"
|
||||
name="billing_name" v-slot="{ errors }">
|
||||
<input v-model="billing.name"
|
||||
:placeholder="$t('user_settings.name_plac')"
|
||||
type="text"
|
||||
:class="{'border-red': errors[0]}"
|
||||
class="focus-border-theme"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>{{ $t('user_settings.address') }}:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
|
||||
rules="required"
|
||||
name="billing_address" v-slot="{ errors }">
|
||||
<input v-model="billing.address"
|
||||
:placeholder="$t('user_settings.address_plac')"
|
||||
type="text"
|
||||
:class="{'border-red': errors[0]}"
|
||||
class="focus-border-theme"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="wrapper-inline">
|
||||
<div class="block-wrapper">
|
||||
<label>{{ $t('user_settings.city') }}:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
|
||||
rules="required" name="billing_city"
|
||||
v-slot="{ errors }">
|
||||
<input v-model="billing.city"
|
||||
:placeholder="$t('user_settings.city_plac')"
|
||||
type="text"
|
||||
:class="{'border-red': errors[0]}"
|
||||
class="focus-border-theme"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>{{ $t('user_settings.postal_code') }}:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
|
||||
rules="required" name="billing_postal_code"
|
||||
v-slot="{ errors }">
|
||||
<input v-model="billing.postal_code"
|
||||
:placeholder="$t('user_settings.postal_code_plac')"
|
||||
type="text"
|
||||
:class="{'border-red': errors[0]}"
|
||||
class="focus-border-theme"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>{{ $t('user_settings.country') }}:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
|
||||
rules="required"
|
||||
name="billing_country" v-slot="{ errors }">
|
||||
<SelectInput v-model="billing.country"
|
||||
:default="billing.country"
|
||||
:options="countries"
|
||||
:placeholder="$t('user_settings.country_plac')"
|
||||
:isError="errors[0]" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>{{ $t('user_settings.state') }}:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
|
||||
rules="required"
|
||||
name="billing_state" v-slot="{ errors }">
|
||||
<input v-model="billing.state"
|
||||
:placeholder="$t('user_settings.state_plac')"
|
||||
type="text"
|
||||
:class="{'border-red': errors[0]}"
|
||||
class="focus-border-theme"
|
||||
/>
|
||||
<small class="input-help">
|
||||
State, county, province, or region.
|
||||
</small>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>{{ $t('user_settings.phone_number') }}:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
|
||||
rules="required"
|
||||
name="billing_phone_number" v-slot="{ errors }">
|
||||
<input v-model="billing.phone_number"
|
||||
:placeholder="$t('user_settings.phone_number_plac')"
|
||||
type="text"
|
||||
:class="{'border-red': errors[0]}"
|
||||
class="focus-border-theme"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
</div>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary">
|
||||
<FormLabel>{{ $t('page_upgrade_account.section_summary') }}</FormLabel>
|
||||
<div class="summary-list" :class="{'is-error': isError}" v-if="requestedPlan">
|
||||
<div class="row">
|
||||
<div class="cell">
|
||||
<b>{{ requestedPlan.data.attributes.name }}</b>
|
||||
<small>{{ $t('page_upgrade_account.summary.period') }}</small>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<b>{{ requestedPlan.data.attributes.price }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="taxRates">
|
||||
<div class="cell">
|
||||
<b>{{ $t('page_upgrade_account.summary.vat') }} - ({{ userTaxRates.country }} {{ userTaxRates.percentage }}%)</b>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<b>{{ userTaxRates.plan_price_formatted }}</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Show total when tax rates is not specified-->
|
||||
<div class="row" v-if="! taxRates">
|
||||
<div class="cell">
|
||||
<b>{{ $t('global.total') }}</b>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<b>{{ requestedPlan.data.attributes.price }}</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Show total when is tax rates-->
|
||||
<div class="row" v-if="taxRates">
|
||||
<div class="cell">
|
||||
<b>{{ $t('page_upgrade_account.summary.total_with_vat') }}</b>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<b>{{ userTaxRates.plan_price_formatted }}</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ButtonBase :disabled="isSubmitted" :loading="isSubmitted" @click.native="submitOrder"
|
||||
type="submit" button-style="theme-solid" class="next-submit">
|
||||
{{ $t('page_upgrade_account.summary.submit_button') }}
|
||||
</ButtonBase>
|
||||
<p class="error-message" v-if="isError">{{ errorMessage }}</p>
|
||||
<small class="disclaimer">
|
||||
{{ $t('page_upgrade_account.summary.submit_disclaimer', {app: config.app_name}) }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loader" v-if="isLoading">
|
||||
<Spinner></Spinner>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import PlanPricingTables from '/resources/js/components/Others/PlanPricingTables'
|
||||
import SelectInput from '/resources/js/components/Others/Forms/SelectInput'
|
||||
import FormLabel from '/resources/js/components/Others/Forms/FormLabel'
|
||||
import MobileHeader from '/resources/js/components/Mobile/MobileHeader'
|
||||
import ButtonBase from '/resources/js/components/FilesView/ButtonBase'
|
||||
import InfoBox from '/resources/js/components/Others/Forms/InfoBox'
|
||||
import ColorLabel from '/resources/js/components/Others/ColorLabel'
|
||||
import PageHeader from '/resources/js/components/Others/PageHeader'
|
||||
import Spinner from '/resources/js/components/FilesView/Spinner'
|
||||
import {CreditCardIcon} from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import {events} from '/resources/js/bus'
|
||||
import axios from 'axios'
|
||||
|
||||
let [stripe, card] = [undefined, undefined];
|
||||
|
||||
export default {
|
||||
name: 'UpgradePlan',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
PlanPricingTables,
|
||||
CreditCardIcon,
|
||||
MobileHeader,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
PageHeader,
|
||||
ColorLabel,
|
||||
FormLabel,
|
||||
required,
|
||||
Spinner,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['requestedPlan', 'config', 'countries']),
|
||||
billing() {
|
||||
return this.$store.getters.user.data.relationships.settings.data.attributes
|
||||
},
|
||||
taxRates() {
|
||||
return this.requestedPlan.data.attributes.tax_rates.find(taxRate => {
|
||||
return taxRate.country === this.billing.country
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
complete: false,
|
||||
stripeOptions: {
|
||||
hidePostalCode: false
|
||||
},
|
||||
isLoading: true,
|
||||
isSubmitted: false,
|
||||
PaymentMethods: undefined,
|
||||
defaultPaymentMethod: undefined,
|
||||
|
||||
errorMessage: undefined,
|
||||
isError: false,
|
||||
|
||||
payByNewCard: false,
|
||||
|
||||
clientSecret: undefined
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initStripe() {
|
||||
stripe = Stripe(this.config.stripe_public_key)
|
||||
|
||||
let elements = stripe.elements();
|
||||
|
||||
card = elements.create('card');
|
||||
|
||||
card.mount(this.$refs.stripeCard);
|
||||
},
|
||||
payByNewCardForm() {
|
||||
this.payByNewCard = true
|
||||
this.isError = false
|
||||
},
|
||||
successOrder() {
|
||||
// Update user data
|
||||
this.$store.dispatch('getAppData')
|
||||
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.account_upgraded'),
|
||||
})
|
||||
|
||||
// Go to User page
|
||||
this.$router.push({name: 'Subscription'})
|
||||
},
|
||||
errorOrder(error) {
|
||||
|
||||
// Redirect user to confirmation payment page
|
||||
if (error.response.status === 402) {
|
||||
window.location.href = error.response.data.message;
|
||||
}
|
||||
|
||||
// Show user error message
|
||||
if (error.response.status === 400) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
// Show server error
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
}
|
||||
},
|
||||
async submitOrder() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.order.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Remove error
|
||||
this.isError = false
|
||||
|
||||
// Start loading
|
||||
this.isSubmitted = true
|
||||
|
||||
// If user don't have credit card, register new
|
||||
if (!this.defaultPaymentMethod || this.payByNewCard) {
|
||||
|
||||
const {setupIntent, error} = await stripe.confirmCardSetup(this.clientSecret, {
|
||||
payment_method: {
|
||||
card: card,
|
||||
}
|
||||
})
|
||||
|
||||
if (error) {
|
||||
|
||||
// Set error on
|
||||
this.isError = true
|
||||
|
||||
// End button spinner
|
||||
this.isSubmitted = false
|
||||
|
||||
// Show error message
|
||||
this.errorMessage = error.message
|
||||
|
||||
} else {
|
||||
|
||||
axios
|
||||
.post('/api/user/subscription/upgrade', {
|
||||
billing: {
|
||||
billing_address: this.billing.address,
|
||||
billing_city: this.billing.city,
|
||||
billing_country: this.billing.country,
|
||||
billing_name: this.billing.name,
|
||||
billing_phone_number: this.billing.phone_number,
|
||||
billing_postal_code: this.billing.postal_code,
|
||||
billing_state: this.billing.state,
|
||||
},
|
||||
plan: this.requestedPlan,
|
||||
payment: {
|
||||
type: 'stripe',
|
||||
meta: {
|
||||
pm: setupIntent.payment_method,
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
this.successOrder()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.errorOrder(error)
|
||||
})
|
||||
.finally(() => {
|
||||
this.isSubmitted = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// if user has credit card
|
||||
if (this.defaultPaymentMethod && !this.payByNewCard) {
|
||||
|
||||
axios
|
||||
.post('/api/user/subscription/upgrade', {
|
||||
billing: {
|
||||
billing_address: this.billing.address,
|
||||
billing_city: this.billing.city,
|
||||
billing_country: this.billing.country,
|
||||
billing_name: this.billing.name,
|
||||
billing_phone_number: this.billing.phone_number,
|
||||
billing_postal_code: this.billing.postal_code,
|
||||
billing_state: this.billing.state,
|
||||
},
|
||||
plan: this.requestedPlan,
|
||||
payment: {
|
||||
type: 'stripe',
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
this.successOrder()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.errorOrder(error)
|
||||
})
|
||||
.finally(() => {
|
||||
this.isSubmitted = false
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted: function () {
|
||||
if (!this.requestedPlan) {
|
||||
this.$router.push({name: 'UpgradePlan'})
|
||||
} else {
|
||||
this.initStripe()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
// Get setup intent for stripe
|
||||
axios.get('/api/user/subscription/setup-intent')
|
||||
.then(response => {
|
||||
this.clientSecret = response.data.client_secret
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
|
||||
axios.get('/api/user/subscription/payment-cards')
|
||||
.then(response => {
|
||||
|
||||
this.defaultPaymentMethod = response.data.default
|
||||
this.PaymentMethods = response.data.others
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '/resources/sass/vuefilemanager/_variables';
|
||||
@import '/resources/sass/vuefilemanager/_mixins';
|
||||
@import '/resources/sass/vuefilemanager/_forms';
|
||||
|
||||
.change-payment {
|
||||
padding-top: 10px;
|
||||
|
||||
span {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
span, a {
|
||||
color: $text-muted;
|
||||
@include font-size(14);
|
||||
}
|
||||
}
|
||||
|
||||
.card-error-message {
|
||||
padding-top: 10px;
|
||||
|
||||
span, a {
|
||||
@include font-size(14);
|
||||
font-weight: 600;
|
||||
color: $danger;
|
||||
}
|
||||
|
||||
.link, a {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.registered-cards {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.register-card {
|
||||
margin-bottom: 55px;
|
||||
}
|
||||
|
||||
.credit-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 15px;
|
||||
background: $light_background;
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
|
||||
&.is-error {
|
||||
box-shadow: 0 0 7px rgba($danger, 0.3);
|
||||
border: 2px solid $danger;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.card-number {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.credit-card-numbers {
|
||||
vertical-align: middle;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.credit-card-icon {
|
||||
vertical-align: middle;
|
||||
max-height: 20px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.stripe-card {
|
||||
box-sizing: border-box;
|
||||
padding: 13px 20px;
|
||||
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background-color: white;
|
||||
|
||||
box-shadow: 0 1px 3px 0 #e6ebf1;
|
||||
-webkit-transition: box-shadow 150ms ease;
|
||||
transition: box-shadow 150ms ease;
|
||||
|
||||
&.is-error {
|
||||
box-shadow: 0 0 7px rgba($danger, 0.3);
|
||||
border: 2px solid $danger;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&.StripeElement--focus {
|
||||
box-shadow: 0 1px 3px 0 #cfd7df;
|
||||
}
|
||||
|
||||
&.StripeElement--invalid {
|
||||
border-color: #fa755a;
|
||||
}
|
||||
|
||||
&.StripeElement--webkit-autofill {
|
||||
background-color: #fefde5 !important;
|
||||
}
|
||||
|
||||
iframe .InputContainer .InputElement {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.summary-list {
|
||||
box-shadow: 0 7px 20px 5px hsla(220, 36%, 16%, 0.06);
|
||||
border-radius: 8px;
|
||||
position: sticky;
|
||||
padding: 25px;
|
||||
top: 30px;
|
||||
|
||||
&.is-error {
|
||||
border: 2px solid $danger;
|
||||
box-shadow: 0 7px 20px 5px rgba($danger, 0.06);
|
||||
}
|
||||
|
||||
.error-message {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.next-submit {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
@include font-size(12);
|
||||
line-height: 1.6;
|
||||
display: block;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 15px 0;
|
||||
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
border-top: 1px solid $light_mode_border;
|
||||
padding-bottom: 0;
|
||||
|
||||
b {
|
||||
font-weight: 800;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell {
|
||||
b {
|
||||
display: block;
|
||||
@include font-size(18);
|
||||
}
|
||||
|
||||
small {
|
||||
color: $text-muted;
|
||||
@include font-size(12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.order {
|
||||
display: flex;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.steps {
|
||||
flex: 0 0 65%;
|
||||
padding-right: 30px;
|
||||
|
||||
.form {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.summary {
|
||||
flex: 0 0 34%;
|
||||
}
|
||||
}
|
||||
|
||||
.plan-title {
|
||||
text-align: center;
|
||||
max-width: 600px;
|
||||
margin: 0 auto 80px;
|
||||
|
||||
path, line, polyline, rect, circle {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@include font-size(38);
|
||||
font-weight: 800;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@include font-size(20);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
|
||||
.plan-title {
|
||||
|
||||
h1 {
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: $dark_mode_text_secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.credit-card {
|
||||
background: $dark_mode_foreground;
|
||||
|
||||
span, .credit-card-numbers {
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
}
|
||||
|
||||
.change-payment {
|
||||
|
||||
span {
|
||||
color: $dark_mode_text_secondary;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $theme;
|
||||
}
|
||||
}
|
||||
|
||||
.summary-list {
|
||||
background: $dark_mode_foreground;
|
||||
|
||||
.disclaimer {
|
||||
color: $dark_mode_text_secondary;
|
||||
}
|
||||
|
||||
.row {
|
||||
|
||||
&:last-of-type {
|
||||
border-top: 1px solid $dark_mode_border_color;
|
||||
|
||||
b {
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell {
|
||||
b {
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
|
||||
small {
|
||||
color: $dark_mode_text_secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stripe-card {
|
||||
border: 1px solid transparent;
|
||||
//background-color: $dark_mode_foreground;
|
||||
box-shadow: none;
|
||||
|
||||
&.StripeElement--webkit-autofill {
|
||||
background-color: $dark_mode_foreground !important;
|
||||
}
|
||||
|
||||
&.StripeElement--focus {
|
||||
box-shadow: none;
|
||||
border-color: $theme;
|
||||
box-shadow: 0 1px 5px rgba($theme, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 960px) {
|
||||
.order {
|
||||
display: block;
|
||||
|
||||
.steps {
|
||||
margin-bottom: 70px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,110 +0,0 @@
|
||||
<template>
|
||||
<div id="single-page">
|
||||
<div id="page-content" class="large-width center-page" v-show="! isLoading">
|
||||
<MobileHeader :title="$t($router.currentRoute.meta.title)"/>
|
||||
<div class="content-page">
|
||||
|
||||
<!--Page Title-->
|
||||
<div class="plan-title">
|
||||
<cloud-icon size="42" class="title-icon text-theme" />
|
||||
<h1>{{ $t('page_pricing_tables.title') }}</h1>
|
||||
<h2>{{ $t('page_pricing_tables.description') }}</h2>
|
||||
</div>
|
||||
|
||||
<!--Pricing Tables-->
|
||||
<PlanPricingTables @load="onLoadPricingTables" @selected-plan="onSelectTable"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loader" v-if="isLoading">
|
||||
<Spinner></Spinner>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PlanPricingTables from '/resources/js/components/Others/PlanPricingTables'
|
||||
import MobileHeader from '/resources/js/components/Mobile/MobileHeader'
|
||||
import PageHeader from '/resources/js/components/Others/PageHeader'
|
||||
import Spinner from '/resources/js/components/FilesView/Spinner'
|
||||
import { CloudIcon } from 'vue-feather-icons'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'UpgradePlan',
|
||||
components: {
|
||||
PlanPricingTables,
|
||||
MobileHeader,
|
||||
PageHeader,
|
||||
CloudIcon,
|
||||
Spinner,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onLoadPricingTables(state) {
|
||||
this.isLoading = state
|
||||
},
|
||||
onSelectTable(plan) {
|
||||
this.$store.commit('STORE_REQUESTED_PLAN', plan)
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
let StripeElementsScript = document.createElement('script')
|
||||
|
||||
StripeElementsScript.setAttribute('src', 'https://js.stripe.com/v3/')
|
||||
document.head.appendChild(StripeElementsScript)
|
||||
},
|
||||
mounted() {
|
||||
// Reload user data
|
||||
this.$store.dispatch('getAppData')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '/resources/sass/vuefilemanager/_variables';
|
||||
@import '/resources/sass/vuefilemanager/_mixins';
|
||||
@import '/resources/sass/vuefilemanager/_forms';
|
||||
|
||||
.plan-title {
|
||||
text-align: center;
|
||||
max-width: 600px;
|
||||
margin: 0 auto 80px;
|
||||
|
||||
path, line, polyline, rect, circle {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@include font-size(38);
|
||||
font-weight: 800;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@include font-size(20);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 960px) {
|
||||
|
||||
}
|
||||
|
||||
.dark {
|
||||
.plan-title {
|
||||
|
||||
h1 {
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: $dark_mode_text_secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user