jcloud/dashboard/src2/views/billing/BillingSummary.vue

243 lines
6.6 KiB
Vue

<template>
<div class="space-y-5">
<Card title="Billing Summary">
<div v-if="!$resources.upcomingInvoice.loading">
<div class="grid grid-cols-2 gap-4 mb-4">
<div class="border rounded-md p-4">
<div class="text-base mb-2">Current Billing Amount</div>
<div class="text-2xl font-medium">
{{ upcomingInvoice ? upcomingInvoice.formatted.total : '0.00' }}
</div>
</div>
<div class="border rounded-md p-4">
<div class="flex justify-between text-base">
<div>Total Unpaid Amount</div>
<Button
@click="
$account.team.billing_address
? (showPrepaidCreditsDialog = true)
: (showAddressDialog = true)
"
theme="gray"
iconLeft="credit-card"
>Pay</Button
>
</div>
<div class="text-2xl font-medium">
{{
($account.team.currency == 'CNY' ? '¥' : '$') +
' ' +
Math.ceil($resources.unpaidAmountDue.data)
}}
</div>
</div>
<div class="border rounded-md p-4">
<div class="flex justify-between text-base">
<div>Account Balance</div>
<Button
@click="
$account.team.billing_address
? (showPrepaidCreditsDialog = true)
: (showAddressDialog = true)
"
theme="gray"
iconLeft="plus"
>Add</Button
>
</div>
<div class="text-2xl font-medium">
{{ availableCredits }}
</div>
</div>
<div class="border rounded-md p-4">
<div class="flex justify-between text-base">
<div>Payment Mode</div>
<Button @click="showChangeModeDialog = true" theme="gray"
>Change</Button
>
</div>
<div class="text-2xl font-medium">
{{ $account.team.payment_mode || 'Not set' }}
</div>
</div>
</div>
<a
href="https://jingrow.com/payment-options"
target="_blank"
class="text-sm text-gray-700 underline"
>
Alternative Payment Options
</a>
<ErrorMessage
:message="$resources.upcomingInvoice.error"
class="mt-3"
/>
</div>
<div class="py-20 text-center" v-if="loading">
<Button :loading="true" loadingText="Loading" />
</div>
<ChangePaymentModeDialog v-model="showChangeModeDialog" />
<UpdateBillingDetails
v-if="showAddressDialog"
v-model="showAddressDialog"
@updated="
showAddressDialog = false;
showPrepaidCreditsDialog = true;
$resources.billingDetails.reload();
"
/>
<PrepaidCreditsDialog
v-if="showPrepaidCreditsDialog"
v-model:show="showPrepaidCreditsDialog"
:minimumAmount="Math.ceil(minimumAmount)"
@success="
() => {
$resources.upcomingInvoice.reload();
showPrepaidCreditsDialog = false;
}
"
/>
</Card>
<UpcomingInvoiceSummary
:invoice-pg="upcomingInvoice"
v-if="upcomingInvoice?.items.length"
/>
</div>
</template>
<script>
import PlanIcon from '@/components/PlanIcon.vue';
import UpcomingInvoiceSummary from './UpcomingInvoiceSummary.vue';
import { defineAsyncComponent } from 'vue';
import InvoiceUsageTable from '@/components/InvoiceUsageTable.vue';
export default {
name: 'BillingSummary',
components: {
InvoiceUsageTable,
PlanIcon,
UpcomingInvoiceSummary,
PrepaidCreditsDialog: defineAsyncComponent(() =>
import('@/components/PrepaidCreditsDialog.vue')
),
ChangePaymentModeDialog: defineAsyncComponent(() =>
import('@/components/ChangePaymentModeDialog.vue')
),
UpdateBillingDetails: defineAsyncComponent(() =>
import('@/components/UpdateBillingDetails.vue')
)
},
resources: {
upcomingInvoice: { url: 'jcloud.api.billing.upcoming_invoice', auto: true },
unpaidAmountDue() {
return {
url: 'jcloud.api.billing.total_unpaid_amount',
auto: true
};
},
billingDetails: 'jcloud.api.billing.details'
},
data() {
return {
showPrepaidCreditsDialog: false,
showChangeModeDialog: false,
showAddressDialog: false
};
},
mounted() {
this.$socket.on('balance_updated', () =>
this.$resources.upcomingInvoice.reload()
);
},
unmounted() {
this.$socket.off('balance_updated');
},
computed: {
cardBrand() {
return {
'master-card': defineAsyncComponent(() =>
import('@/components/icons/cards/MasterCard.vue')
),
visa: defineAsyncComponent(() =>
import('@/components/icons/cards/Visa.vue')
),
amex: defineAsyncComponent(() =>
import('@/components/icons/cards/Amex.vue')
),
jcb: defineAsyncComponent(() =>
import('@/components/icons/cards/JCB.vue')
),
generic: defineAsyncComponent(() =>
import('@/components/icons/cards/Generic.vue')
),
'union-pay': defineAsyncComponent(() =>
import('@/components/icons/cards/UnionPay.vue')
)
};
},
minimumAmount() {
const unpaidAmount = this.$resources.unpaidAmountDue.data;
const minimumDefault = $account.team.currency == 'CNY' ? 0.01 : 0.01;
return unpaidAmount && unpaidAmount > minimumDefault
? unpaidAmount
: minimumDefault;
},
upcomingInvoice() {
return this.$resources.upcomingInvoice.data?.upcoming_invoice;
},
availableCredits() {
return this.$resources.upcomingInvoice.data?.available_credits;
},
paymentDate() {
if (!this.upcomingInvoice) {
return '';
}
let endDate = this.$date(this.upcomingInvoice.period_end);
return endDate.toLocaleString({
month: 'short',
day: 'numeric',
year: 'numeric'
});
},
paymentModeDescription() {
let payment_mode = this.$account.team.payment_mode;
let balance = this.$account.balance;
if (payment_mode === 'Card') {
if (!this.upcomingInvoice || balance <= 0) {
return `Your card will be charged on ${this.paymentDate}.`;
} else if (balance >= this.upcomingInvoice.total) {
return `Your account balance will be charged on ${this.paymentDate}.`;
} else if (balance > 0) {
return `Your account balance will be charged and then the remaining balance will be charged from your card on ${this.paymentDate}.`;
} else {
return `Your card will be charged on ${this.paymentDate}.`;
}
}
if (payment_mode === 'Prepaid Credits') {
return `You will be charged from your account balance on ${this.paymentDate}.`;
}
return '';
},
loading() {
return this.$resources.upcomingInvoice.loading;
}
},
methods: {
dateShort(date) {
return this.$date(date).toLocaleString({
month: 'short',
day: 'numeric',
year: 'numeric'
});
}
}
};
</script>