v1.7 beta.1

This commit is contained in:
carodej
2020-07-16 10:26:41 +02:00
parent 6b36480097
commit eeada5468b
36 changed files with 923 additions and 42 deletions

View File

@@ -0,0 +1,223 @@
<template>
<PageTab>
<PageTabGroup>
<div class="form block-form">
<FormLabel>{{ $t('user_payments.add_card') }}</FormLabel>
<!-- Register new credit card -->
<div class="register-card">
<InfoBox v-show="config.isDemo">
<p>For test your payment please use <b>4242 4242 4242 4242</b> or <b>5555 5555 5555 4444</b> as a card number, <b>11/22</b>
as the expiration date and <b>123</b> as CVC number and ZIP <b>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>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">{{ $t('user_add_card.default_title') }}:</label>
<small class="input-help">{{ $t('user_add_card.default_description') }}</small>
</div>
<SwitchInput v-model="defaultPaymentMethod" class="switch" :state="defaultPaymentMethod"/>
</div>
</div>
</div>
<ButtonBase @click.native="registerCard" :disabled="isSubmitted" :loading="isSubmitted" button-style="theme" type="submit">
{{ $t('user_payments.add_card') }}
</ButtonBase>
</div>
</PageTabGroup>
</PageTab>
</template>
<script>
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import FormLabel from '@/components/Others/Forms/FormLabel'
import ButtonBase from '@/components/FilesView/ButtonBase'
import PageTab from '@/components/Others/Layout/PageTab'
import InfoBox from '@/components/Others/Forms/InfoBox'
import {mapGetters} from 'vuex'
import {events} from "@/bus"
import axios from 'axios'
let [stripe, card] = [undefined, undefined];
export default {
name: 'CreatePaymentMethod',
components: {
PageTabGroup,
SwitchInput,
ButtonBase,
FormLabel,
PageTab,
InfoBox,
},
computed: {
...mapGetters(['config']),
},
data() {
return {
errorMessage: undefined,
isError: false,
stripeOptions: {
hidePostalCode: false
},
isSubmitted: false,
defaultPaymentMethod: true,
clientSecret: undefined
}
},
methods: {
async registerCard() {
// Start loading
this.isSubmitted = true
const {setupIntent, error} = await stripe.confirmCardSetup(this.clientSecret, {
payment_method: {
card: card,
}
})
if (setupIntent) {
axios
.post('/api/user/payment-cards', {
token: setupIntent.payment_method,
default: this.defaultPaymentMethod,
})
.then(() => {
// Show toaster
events.$emit('toaster', {
type: 'success',
message: this.$t('toaster.card_new_add'),
})
// Go to payment methods page
this.$router.push({name: 'PaymentMethods'})
})
.catch(() => {
events.$emit('alert:open', {
title: this.$t('popup_error.title'),
message: this.$t('popup_error.message'),
})
})
.finally(() => {
this.isSubmitted = false
})
}
if (error) {
// Set error on
this.isError = true
// End button spinner
this.isSubmitted = false
// Show error message
this.errorMessage = error.message
}
},
initStripe() {
stripe = Stripe(this.config.stripe_public_key)
let elements = stripe.elements();
card = elements.create('card');
card.mount(this.$refs.stripeCard);
},
},
mounted() {
let StripeElementsScript = document.createElement('script')
StripeElementsScript.setAttribute('src', 'https://js.stripe.com/v3/')
document.head.appendChild(StripeElementsScript)
// Get setup intent for stripe
axios.get('/api/stripe/setup-intent')
.then(response => {
this.clientSecret = response.data.client_secret
this.initStripe()
})
},
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
@import '@assets/vue-file-manager/_forms';
.register-card {
margin-bottom: 25px;
}
.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;
}
}
.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;
}
}
}
</style>

View File

@@ -2,7 +2,14 @@
<PageTab :is-loading="isLoading">
<PageTabGroup v-if="PaymentMethods && PaymentMethods.length > 0">
<FormLabel>{{ $t('user_payments.title') }}</FormLabel>
<DatatableWrapper :paginator="true" :columns="columns" :data="PaymentMethods" class="table">
<div class="page-actions">
<router-link :to="{name: 'CreatePaymentMethod'}">
<MobileActionButton icon="credit-card">
{{ $t('user_payments.add_card') }}
</MobileActionButton>
</router-link>
</div>
<DatatableWrapper :paginator="false" :columns="columns" :data="PaymentMethods" class="table">
<template scope="{ row }">
<tr :class="{'is-deleting': row.data.attributes.card_id === deletingID}">
<td style="width: 300px">
@@ -29,8 +36,12 @@
</td>
<td>
<div class="action-icons">
<credit-card-icon size="15" class="icon icon-card" :title="$t('user_payments.set_as_default')" @click="setDefaultCard(row.data.attributes)" v-if="row.data.id !== defaultPaymentCard.data.id"></credit-card-icon>
<trash2-icon size="15" class="icon icon-trash" :title="$t('user_payments.delete_card')" @click="deleteCard(row.data.attributes)"></trash2-icon>
<label class="icon-wrapper" :title="$t('user_payments.set_as_default')">
<credit-card-icon size="15" class="icon icon-card" @click="setDefaultCard(row.data.attributes)" v-if="row.data.id !== defaultPaymentCard.data.id"></credit-card-icon>
</label>
<label class="icon-wrapper" :title="$t('user_payments.delete_card')">
<trash2-icon size="15" class="icon icon-trash" @click="deleteCard(row.data.attributes)"></trash2-icon>
</label>
</div>
</td>
</tr>
@@ -38,12 +49,13 @@
</DatatableWrapper>
</PageTabGroup>
<InfoBox v-else>
<p>{{ $t('user_payments.empty') }}</p>
<p>{{ $t('user_payments.empty') }} <router-link v-if="user.data.attributes.stripe_customer" :to="{name: 'CreatePaymentMethod'}">Add new payment method.</router-link> </p>
</InfoBox>
</PageTab>
</template>
<script>
import MobileActionButton from '@/components/FilesView/MobileActionButton'
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import {CreditCardIcon, Trash2Icon} from "vue-feather-icons"
@@ -51,12 +63,14 @@
import PageTab from '@/components/Others/Layout/PageTab'
import ColorLabel from '@/components/Others/ColorLabel'
import InfoBox from '@/components/Others/Forms/InfoBox'
import { mapGetters } from 'vuex'
import {events} from "@/bus"
import axios from 'axios'
export default {
name: 'UserPaymentMethods',
components: {
MobileActionButton,
DatatableWrapper,
CreditCardIcon,
PageTabGroup,
@@ -66,6 +80,9 @@
InfoBox,
PageTab,
},
computed: {
...mapGetters(['user']),
},
data() {
return {
defaultPaymentCard: undefined,
@@ -250,6 +267,11 @@
}
}
.page-actions {
margin-top: 45px;
margin-bottom: 10px;
}
@media only screen and (max-width: 960px) {