mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-25 02:10:39 +00:00
frontend & backend update
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<PageTabGroup v-if="paymentCards && paymentCards.length > 0">
|
||||
<DatatableWrapper :paginator="true" :columns="columns" :data="paymentCards" class="table">
|
||||
<template scope="{ row }">
|
||||
<tr :class="{'is-deleting': row.data.attributes.card_id === deletingID}">
|
||||
<td style="width: 300px">
|
||||
<span class="cell-item">
|
||||
<div class="credit-card">
|
||||
<img class="credit-card-icon" :src="$getCreditCardBrand(row.data.attributes.brand)"
|
||||
:alt="row.data.attributes.brand">
|
||||
<div class="credit-card-numbers">
|
||||
•••• {{ row.data.attributes.last4 }}
|
||||
</div>
|
||||
<ColorLabel v-if="row.data.id === defaultPaymentCard.data.id" color="purple">Default</ColorLabel>
|
||||
</div>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="cell-item">
|
||||
<ColorLabel :color="getCardStatusColor(row.data.attributes.status)">{{ getCardStatus(row.data.attributes.status) }}</ColorLabel>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="cell-item">
|
||||
{{ row.data.attributes.exp_month }} / {{ row.data.attributes.exp_year }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-icons">
|
||||
<credit-card-icon size="15" class="icon icon-card" title="Set as default card" @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="Delete card" @click="deleteCard(row.data.attributes)"></trash2-icon>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</PageTabGroup>
|
||||
<PageTabGroup v-else>
|
||||
You don't have any payment cards yet.
|
||||
</PageTabGroup>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
|
||||
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
|
||||
import PageTab from '@/components/Others/Layout/PageTab'
|
||||
import ColorLabel from '@/components/Others/ColorLabel'
|
||||
import {CreditCardIcon, Trash2Icon} from "vue-feather-icons"
|
||||
import {events} from "@/bus"
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'UserPaymentCards',
|
||||
components: {
|
||||
DatatableWrapper,
|
||||
PageTabGroup,
|
||||
Trash2Icon,
|
||||
ColorLabel,
|
||||
CreditCardIcon,
|
||||
PageTab,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultPaymentCard: undefined,
|
||||
paymentCards: undefined,
|
||||
deletingID: undefined,
|
||||
columns: [
|
||||
{
|
||||
label: 'Card Number',
|
||||
field: 'data.attributes.total',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: 'Status',
|
||||
field: 'data.attributes.status',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: 'Expiration Date',
|
||||
field: 'data.attributes.total',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
field: 'data.action',
|
||||
sortable: false
|
||||
},
|
||||
],
|
||||
isLoading: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCardStatusColor(status) {
|
||||
switch (status) {
|
||||
case 'active':
|
||||
return 'green'
|
||||
break
|
||||
case 'card_declined':
|
||||
return 'yellow'
|
||||
break
|
||||
case 'expired':
|
||||
return 'red'
|
||||
break
|
||||
}
|
||||
},
|
||||
getCardStatus(status) {
|
||||
switch (status) {
|
||||
case 'active':
|
||||
return 'Active'
|
||||
break
|
||||
case 'card_declined':
|
||||
return 'Rejected'
|
||||
break
|
||||
case 'expired':
|
||||
return 'Expired'
|
||||
break
|
||||
}
|
||||
},
|
||||
setDefaultCard(card) {
|
||||
events.$emit('confirm:open', {
|
||||
title: 'Set as default card?',
|
||||
message: 'Your card will be set as default and will be always charged for the next billings.',
|
||||
buttonColor: 'theme-solid',
|
||||
action: {
|
||||
id: card.card_id,
|
||||
operation: 'set-as-default-credit-card'
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteCard(card) {
|
||||
events.$emit('confirm:open', {
|
||||
title: 'Are you sure?',
|
||||
message: 'This event is irreversible and your payment card will be delete forever',
|
||||
action: {
|
||||
id: card.card_id,
|
||||
operation: 'delete-credit-card'
|
||||
}
|
||||
})
|
||||
},
|
||||
fetchPaymentCards() {
|
||||
axios.get('/api/user/payments')
|
||||
.then(response => {
|
||||
|
||||
this.defaultPaymentCard = response.data.default
|
||||
|
||||
this.paymentCards = response.data.others.data
|
||||
this.paymentCards.push(response.data.default)
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
// Get payments card
|
||||
this.fetchPaymentCards()
|
||||
|
||||
// Delete credit card
|
||||
events.$on('action:confirmed', data => {
|
||||
|
||||
if (data.operation === 'delete-credit-card') {
|
||||
|
||||
this.deletingID = data.id
|
||||
|
||||
axios.delete('/api/user/payment-cards/' + data.id)
|
||||
.then(() => {
|
||||
|
||||
// Get payments card
|
||||
this.fetchPaymentCards()
|
||||
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: 'Your card was successfully deleted.',
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
})
|
||||
}
|
||||
|
||||
if (data.operation === 'set-as-default-credit-card') {
|
||||
|
||||
axios.patch('/api/user/payment-cards/' + data.id, {
|
||||
default: 1
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
// Get payments card
|
||||
this.fetchPaymentCards()
|
||||
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: 'Your card was successfully set as default.',
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@assets/vue-file-manager/_variables';
|
||||
@import '@assets/vue-file-manager/_mixins';
|
||||
@import '@assets/vue-file-manager/_forms';
|
||||
|
||||
.is-deleting {
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
.credit-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.credit-card-numbers {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.credit-card-icon {
|
||||
max-height: 20px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 960px) {
|
||||
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,34 +1,44 @@
|
||||
<template>
|
||||
<PageTab>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<PageTabGroup v-if="subscription">
|
||||
|
||||
<!--Info about active subscription-->
|
||||
<div v-if="! subscription.canceled" class="state active">
|
||||
<div v-if="! subscription.data.attributes.canceled" class="state active">
|
||||
<ListInfo class="list-info">
|
||||
<ListInfoItem class="list-item" title="Plan" :content="subscription.name + ' - ' + subscription.capacity_formatted"/>
|
||||
<ListInfoItem class="list-item" title="Plan" :content="subscription.data.attributes.name + ' - ' + subscription.data.attributes.capacity_formatted"/>
|
||||
<ListInfoItem class="list-item" title="Billed" content="Monthly"/>
|
||||
<ListInfoItem class="list-item" title="Status" :content="status"/>
|
||||
<ListInfoItem class="list-item" title="Created At" :content="subscription.created_at"/>
|
||||
<ListInfoItem class="list-item" title="Renews At" :content="subscription.ends_at"/>
|
||||
<ListInfoItem class="list-item" title="Created At" :content="subscription.data.attributes.created_at"/>
|
||||
<ListInfoItem class="list-item" title="Renews At" :content="subscription.data.attributes.ends_at"/>
|
||||
</ListInfo>
|
||||
<div class="cancel-plan">
|
||||
<div class="plan-action">
|
||||
<ButtonBase
|
||||
:disabled="isDeleting"
|
||||
@click.native="cancelSubscription"
|
||||
:button-style="cancelButtonStyle"
|
||||
class="cancel-button">
|
||||
class="confirm-button">
|
||||
{{ cancelButtonText }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Info about canceled subscription-->
|
||||
<div v-if="subscription.canceled" class="state canceled">
|
||||
<div v-if="subscription.data.attributes.canceled" class="state canceled">
|
||||
<ListInfo class="list-info">
|
||||
<ListInfoItem class="list-item" title="Plan" :content="subscription.name"/>
|
||||
<ListInfoItem class="list-item" title="Plan" :content="subscription.data.attributes.name"/>
|
||||
<ListInfoItem class="list-item" title="Status" :content="status"/>
|
||||
<ListInfoItem class="list-item" title="Canceled At" :content="subscription.canceled_at"/>
|
||||
<ListInfoItem class="list-item" title="Ends At" :content="subscription.ends_at"/>
|
||||
<ListInfoItem class="list-item" title="Canceled At" :content="subscription.data.attributes.canceled_at"/>
|
||||
<ListInfoItem class="list-item" title="Ends At" :content="subscription.data.attributes.ends_at"/>
|
||||
</ListInfo>
|
||||
<div class="plan-action">
|
||||
<ButtonBase
|
||||
:disabled="isResuming"
|
||||
@click.native="resumeSubscription"
|
||||
:button-style="resumeButtonStyle"
|
||||
class="confirm-button">
|
||||
{{ resumeButtonText }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</div>
|
||||
</PageTabGroup>
|
||||
<PageTabGroup v-else>
|
||||
@@ -65,26 +75,31 @@
|
||||
return this.isConfirmedCancel ? this.$t('popup_share_edit.confirm') : 'Cancel Plan'
|
||||
},
|
||||
cancelButtonStyle() {
|
||||
return this.isConfirmedCancel ? 'danger-solid' : 'danger'
|
||||
return this.isConfirmedCancel ? 'danger-solid' : 'secondary'
|
||||
},
|
||||
subscription() {
|
||||
return this.$store.getters.user.relationships.subscription
|
||||
? this.$store.getters.user.relationships.subscription.data.attributes
|
||||
: undefined
|
||||
resumeButtonText() {
|
||||
return this.isConfirmedResume ? this.$t('popup_share_edit.confirm') : 'Resume Plan'
|
||||
},
|
||||
resumeButtonStyle() {
|
||||
return this.isConfirmedResume ? 'theme-solid' : 'secondary'
|
||||
},
|
||||
status() {
|
||||
if (this.subscription.canceled) {
|
||||
if (this.subscription.data.attributes.canceled) {
|
||||
return 'Canceled'
|
||||
}
|
||||
if (this.subscription.active) {
|
||||
if (this.subscription.data.attributes.active) {
|
||||
return 'Active'
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
subscription: undefined,
|
||||
isConfirmedCancel: false,
|
||||
isConfirmedResume: false,
|
||||
isDeleting: false,
|
||||
isResuming: false,
|
||||
isLoading: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -98,6 +113,7 @@
|
||||
|
||||
// Start deleting spinner button
|
||||
this.isDeleting = true
|
||||
this.isLoading = true
|
||||
|
||||
// Send delete request
|
||||
axios
|
||||
@@ -105,7 +121,9 @@
|
||||
.then(() => {
|
||||
|
||||
// Update user data
|
||||
this.$store.dispatch('getAppData')
|
||||
this.$store.dispatch('getAppData').then(() => {
|
||||
this.fetchSubscriptionDetail()
|
||||
})
|
||||
|
||||
// End deleting spinner button
|
||||
this.isDeleting = false
|
||||
@@ -122,9 +140,61 @@
|
||||
|
||||
// End deleting spinner button
|
||||
this.isDeleting = false
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
resumeSubscription() {
|
||||
|
||||
// Set confirm button
|
||||
if (! this.isConfirmedResume) {
|
||||
|
||||
this.isConfirmedResume = true
|
||||
} else {
|
||||
|
||||
// Start deleting spinner button
|
||||
this.isResuming = true
|
||||
this.isLoading = true
|
||||
|
||||
// Send delete request
|
||||
axios
|
||||
.post('/api/subscription/resume')
|
||||
.then(() => {
|
||||
|
||||
// Update user data
|
||||
this.$store.dispatch('getAppData').then(() => {
|
||||
this.fetchSubscriptionDetail()
|
||||
})
|
||||
|
||||
// End deleting spinner button
|
||||
this.isResuming = false
|
||||
|
||||
events.$emit('alert:open', {
|
||||
emoji: '👍',
|
||||
title: 'Subscription Was Resumed',
|
||||
message: 'Your subscription was re-activated, and they will be billed on the original billing cycle.',
|
||||
buttonStyle: 'theme',
|
||||
button: 'That\'s awesome!'
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
// End deleting spinner button
|
||||
this.isResuming = false
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
fetchSubscriptionDetail() {
|
||||
axios.get('/api/user/subscription')
|
||||
.then(response => {
|
||||
this.subscription = response.data
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchSubscriptionDetail()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -133,7 +203,7 @@
|
||||
@import '@assets/vue-file-manager/_variables';
|
||||
@import '@assets/vue-file-manager/_mixins';
|
||||
|
||||
.cancel-plan {
|
||||
.plan-action {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user