Browse Source

Payment and Bills page (#40)

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement payment and bills page

Merge branch 'feat/ui-layout' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: change config to accept env files

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: make a stripe element component

Merge branch 'master' into feat/ui-layout

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement manage ssh key page

feat: set password page

feat: implement change password page

fix: change design

feat: implement my account page

feat: implement animation control for launching bubble screen

fix: navigating to network page

feat: implement Launching bubble page

feat: integrate launch bubble api

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement MFA in login

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement adding ssh key

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

fix: showing default values

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement selector placeholders and default values

Merge branch 'feat/ui-layout' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

fix: getting user information after setting payment method

Merge branch 'master' into feat/ui-layout

feat: implement setting payment plan in payment page

feat: populate options for advanced settings modal

fix: remove showing advanced settings modal when loading the page

feat: implement Advanced Settings Modal layout

feat: implement modal and selector components

feat: implement launch bubble screen

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement add stripe card

feat: implement login process

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement payment page

feat: implement mail verification screen

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: prevent registration when the configs.allowRegistration is set to false

fix: weird routing

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: implement actual pages

Merge branch 'master' of git.bubblev.org:bubblev/bubble-web into feat/ui-layout

feat: api integration for register page

Co-authored-by: Tyler <everdev0923@gmail.com>
Co-authored-by: jonathan <jonathan@noreply.git.bubblev.org>
Reviewed-on: https://git.bubblev.org/bubblev/bubble-web/pulls/40
pull/46/head
Tyler Chen 4 years ago
committed by jonathan
parent
commit
83324cee67
2 changed files with 403 additions and 0 deletions
  1. +399
    -0
      src/_pages/main/account/PaymentMethods.vue
  2. +4
    -0
      src/_router/index.js

+ 399
- 0
src/_pages/main/account/PaymentMethods.vue View File

@@ -0,0 +1,399 @@
<!-- Copyright (c) 2020 Bubble, Inc. All rights reserved. For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ -->
<template>
<div class="wrapper">
<h1 class="text-center white-text form-title">
{{ messages.title_account_payment_methods }}
</h1>

<form class="bubble-form">
<h5>{{ messages.title_account_payment_methods }}</h5>

<div v-if="payMethods">
<table border="1">
<thead>
<tr>
<td>{{ messages.label_account_payment_method_type }}</td>
<td>{{ messages.label_account_payment_method_info }}</td>
<td>{{ messages.label_account_payment_method_added }}</td>
<td>{{ messages.label_account_payment_method_current }}</td>
<td></td>
<td v-if="payMethods.length > 1">
{{ messages.label_account_payment_method_set }}
</td>
<td v-if="payMethods.length > 1">
{{ messages.label_account_payment_method_remove }}
</td>
</tr>
</thead>
<tbody>
<tr v-for="(pm, key) in payMethods" :key="key">
<td>{{ messages['payment_method_' + pm.paymentMethodType] }}</td>
<td nowrap="nowrap">
<small>{{ pm.maskedPaymentInfo }}</small>
</td>
<td>
{{
messages.label_account_payment_method_added_format.parseDateMessage(
pm.ctime,
messages
)
}}
</td>

<td v-if="pm.planNames && pm.planNames.length > 0">
<div v-for="(name, key) in pm.planNames" :key="key">
{{ name }}
</div>
</td>
<td v-else></td>

<td
v-if="
accountPlans &&
accountPlans.length > 0 &&
payMethods.length > 1
"
>
<div v-for="(ap, key) in accountPlans" :key="key">
<Button
style="white-space:nowrap"
v-if="ap.paymentMethod !== pm.uuid"
@click="setPayMethodForPlan(ap.uuid, pm.uuid)"
>
{{ ap.name }}
</Button>
</div>
</td>
<td v-else-if="payMethods.length > 1"></td>

<td v-if="pm.deletable">
<Button v-if="pm.deletable" @click="deletePayMethod(pm.uuid)">
{{ messages.button_label_account_payment_delete }}
</Button>
</td>
<td v-else></td>
</tr>
</tbody>
</table>
</div>

<hr />

<label htmlFor="paymentMethod">
<b>{{ messages.label_account_payment_add }}</b>
</label>

<stripe-element ref="stripeElement" />

<div
v-if="submitted && errors.has('purchase')"
class="invalid-feedback d-block"
>
{{ errors.first('purchase') }}
</div>
<div
v-if="submitted && errors.has('paymentMethod')"
class="invalid-feedback d-block"
>
{{ errors.first('paymentMethod') }}
</div>
<div
v-if="submitted && errors.has('paymentMethodInfo')"
class="invalid-feedback d-block"
>
{{ errors.first('paymentMethodInfo') }}
</div>
<div
v-if="submitted && errors.has('paymentMethodType')"
class="invalid-feedback d-block"
>
{{ errors.first('paymentMethodType') }}
</div>
<div
v-if="submitted && errors.has('paymentMethodService')"
class="invalid-feedback d-block"
>
{{ errors.first('paymentMethodService') }}
</div>
<div
v-if="submitted && errors.has('paymentInfo')"
class="invalid-feedback d-block"
>
{{ errors.first('paymentInfo') }}
</div>
<div
v-if="submitted && errors.has('plan')"
class="invalid-feedback d-block"
>
{{ errors.first('plan') }}
</div>

<Button
block
color="default"
class="bubble-form-submit"
@click="authorizeCard"
v-if="
paymentStatus.addingPaymentMethod || !paymentStatus.addedPaymentMethod
"
:disabled="paymentStatus.addingPaymentMethod"
>
{{ messages.button_label_add_card }}
</Button>

<hr />
<div v-if="promos && promos.length > 0">
<h5>{{ messages.title_account_promotions }}</h5>

<table border="1">
<thead>
<tr>
<td>{{ messages.label_account_payment_method_info }}</td>
<td>{{ messages.label_account_payment_method_added }}</td>
</tr>
</thead>
<tbody>
<tr v-for="(pm, key) in promos" :key="key">
<td>{{ messages['label_promotion_' + pm.maskedPaymentInfo] }}</td>
<td>
{{
messages.label_account_payment_method_added_format.parseDateMessage(
pm.ctime,
messages
)
}}
</td>
</tr>
</tbody>
</table>
</div>

<hr />
<div v-if="usedPromos && usedPromos.length > 0">
<h5>{{ messages.title_account_promotions_used }}</h5>

<table border="1">
<thead>
<tr>
<td>{{ messages.label_account_payment_method_info }}</td>
<td>{{ messages.label_account_payment_method_added }}</td>
<td>{{ messages.label_account_promotion_used }}</td>
</tr>
</thead>
<tbody>
<tr v-for="(pm, key) in usedPromos" :key="key">
<td>{{ messages['label_promotion_' + pm.maskedPaymentInfo] }}</td>
<td>
{{
messages.label_account_payment_method_added_format.parseDateMessage(
pm.ctime,
messages
)
}}
</td>
<td>
{{
messages.label_account_payment_method_used_format.parseDateMessage(
pm.deleted,
messages
)
}}
</td>
</tr>
</tbody>
</table>
</div>
</form>
</div>
</template>

<style lang="scss" scoped>
@import '../../../_scss/components/form';

.bubble-form {
width: 600px;
}
</style>

<script>
import { mapState, mapActions, mapGetters } from 'vuex';
import { util } from '~/_helpers';

import { Button, StripeElement } from '~/_components/shared';

export default {
components: {
Button,
StripeElement,
},
data() {
return {
me: null,
userId: null,
linkPrefix: null,
currentUser: util.currentUser(),
payMethods: null,
promos: null,
usedPromos: null,
selectedPaymentMethod: null,
newPaymentMethod: {
paymentMethodType: null,
paymentInfo: null,
},
submitted: false,
};
},
computed: {
...mapState('system', ['messages']),
...mapState('paymentMethods', [
'paymentMethods',
'accountPaymentMethods',
'paymentMethod',
'paymentStatus',
]),
...mapState('accountPlans', ['accountPlans']),
},
methods: {
...mapActions('paymentMethods', [
'getAllPaymentMethods',
'getAllAccountPaymentMethods',
'setPaymentMethod',
'deleteAccountPaymentMethod',
'setAccountPaymentMethodForPlan',
'addAccountPaymentMethod',
]),
...mapActions('accountPlans', ['getAllAccountPlans']),
...mapGetters('paymentMethods', ['loading']),
...mapActions('account', ['checkSession']),

deletePayMethod(pmId) {
this.deleteAccountPaymentMethod({
userId: this.userId,
pmId: pmId,
messages: this.messages,
errors: this.errors,
});
},
setPayMethodForPlan(planId, pmId) {
this.setAccountPaymentMethodForPlan({
userId: this.userId,
planId: planId,
pmId: pmId,
messages: this.messages,
errors: this.errors,
});
},

authorizeCard(e) {
util.setSkipRegistration();

this.errors.clear();

this.$refs.stripeElement.verifyCard().then((result) => {
if (result.error) {
this.$snotify.error(result.error.message);
} else {
this.submitted = true;
this.addAccountPaymentMethod({
userId: this.user && this.user.uuid ? this.user.uuid : null,
paymentMethod: {
paymentMethodType: 'credit',
paymentInfo: result.token.id,
preferredPlan: this.bubblePlan,
},
messages: this.messages,
errors: this.errors,
}).then(() => {
this.checkSession({
messages: this.messages,
errors: this.errors,
});
});
}
});
return false;
},
},

watch: {
paymentMethods() {
this.$refs.stripeElement.setUpStripe(
this.paymentMethods[0].driverConfig.publicApiKey
);
},
accountPaymentMethods(pms) {
if (pms) {
const payMethods = [];
const promos = [];
const usedPromos = [];
for (let i = 0; i < pms.length; i++) {
const pm = pms[i];
if (pm.promotion) {
if (typeof pm.deleted !== 'undefined' && pm.deleted !== null) {
usedPromos.push(pm);
} else {
promos.push(pm);
}
} else {
if (typeof pm.deleted === 'undefined' || pm.deleted === null) {
payMethods.push(pm);
}
}
}
this.payMethods = payMethods;
this.promos = promos;
this.usedPromos = usedPromos;
}
},
paymentMethod(pm) {
if (pm) {
this.selectedPaymentMethod = pm;
this.newPaymentMethod.paymentMethodType = pm.paymentMethodType;
this.newPaymentMethod.paymentInfo = null;
}
},
paymentStatus(status) {
if (
status &&
(status.addedPaymentMethod === true ||
status.updatedPaymentMethod === true ||
status.deletedPaymentMethod === true)
) {
this.selectedPaymentMethod = null;
if (status.updatedPaymentMethod === true) {
this.getAllAccountPlans({
userId: this.userId,
messages: this.messages,
errors: this.errors,
});
}
this.getAllAccountPaymentMethods({
userId: this.userId,
messages: this.messages,
errors: this.errors,
});
}
},
},

created() {
this.me = this.$route.path.startsWith('/me/');
if (util.validateAccount(this)) {
this.getAllAccountPaymentMethods({
userId: this.userId,
messages: this.messages,
errors: this.errors,
});
this.getAllPaymentMethods({
messages: this.messages,
errors: this.errors,
});
this.getAllAccountPlans({
userId: this.userId,
messages: this.messages,
errors: this.errors,
});
}
},
};
</script>

+ 4
- 0
src/_router/index.js View File

@@ -104,6 +104,10 @@ export const router = new Router({
path: 'me/keys',
component: () => import('~/_pages/main/account/ManageSSH'),
},
{
path: 'me/payment',
component: () => import('~/_pages/main/account/PaymentMethods'),
},
],
},
{


Loading…
Cancel
Save