New Payments Buttons (#11045)

* start implementing separate amazon button component

* wio

* switch amazon to new flow

* adjust amazon pay button size

* design buttons and add them to the settings page

* abstract css

* fixes and buy gems modal

* group plans css

* new buttons for gifts, fix padding in settings

* gift modal styles

* final style fixes
This commit is contained in:
Matteo Pagliazzi
2019-03-11 18:23:47 +01:00
committed by GitHub
parent ee20b1eea8
commit 6bccd2a866
15 changed files with 288 additions and 252 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -36,3 +36,4 @@
@import './animals'; @import './animals';
@import './iconalert'; @import './iconalert';
@import './tiers'; @import './tiers';
@import './payments';

View File

@@ -0,0 +1,40 @@
.payments-column {
display: flex;
flex-direction: column;
width: 296px;
justify-content: center;
&.payments-disabled {
opacity: 0.64;
.btn, .btn:hover, .btn:active {
box-shadow: none;
}
}
.payment-item {
margin-bottom: 12px;
display: flex;
&.payment-button {
display: flex;
justify-content: center;
align-items: center;
.credit-card-icon {
width: 21.3px;
height: 16px;
margin-right: 8.7px;
}
&.paypal-checkout {
background: #009cde;
img {
width: 157px;
height: 21px;
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="16" viewBox="0 0 22 16">
<path fill="#FFF" fill-rule="nonzero" d="M0 13.872V5.333h21.333v8.539c0 1.176-.747 2.128-1.67 2.128H1.67C.747 16 0 15.047 0 13.872zM19.664 0c.922 0 1.67.918 1.67 2.053v.614H0v-.614C0 .918.747 0 1.67 0h17.994z"/>
</svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@@ -22,11 +22,11 @@
button.btn.btn-primary.btn-lg.btn-block(@click="createGroup()", :disabled="!newGroupIsReady") {{ $t('createGroupPlan') }} button.btn.btn-primary.btn-lg.btn-block(@click="createGroup()", :disabled="!newGroupIsReady") {{ $t('createGroupPlan') }}
.col-12(v-if='activePage === PAGES.PAY') .col-12(v-if='activePage === PAGES.PAY')
h2 {{ $t('choosePaymentMethod') }} h2 {{ $t('choosePaymentMethod') }}
.payment-providers .payments-column
.box.payment-button(@click='pay(PAYMENTS.STRIPE)') button.purchase.btn.btn-primary.payment-button.payment-item(@click='pay(PAYMENTS.STRIPE)')
.svg-icon.credit-card-icon(v-html="icons.creditCard") .svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
.box.payment-button.amazon(@click='pay(PAYMENTS.AMAZON)') | {{ $t('card') }}
.svg-icon.amazon-pay-icon(v-html="icons.amazonpay") amazon-button.payment-item(:amazon-data="pay(PAYMENTS.AMAZON)")
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -65,40 +65,29 @@
opacity: 0.7; opacity: 0.7;
} }
.amazon-pay-icon {
width: 150px;
}
.credit-card-icon {
width: 150px;
color: #4e4a57;
}
.btn-block { .btn-block {
margin-bottom: 1em; margin-bottom: 1em;
} }
.payment-button.amazon {
margin-bottom: 2em;
}
</style> </style>
<script> <script>
import * as Analytics from 'client/libs/analytics'; import * as Analytics from 'client/libs/analytics';
import { mapState } from 'client/libs/store'; import { mapState } from 'client/libs/store';
import paymentsMixin from '../../mixins/payments'; import paymentsMixin from '../../mixins/payments';
import amazonButton from 'client/components/payments/amazonButton';
import amazonpay from 'assets/svg/amazonpay.svg'; import creditCardIcon from 'assets/svg/credit-card-icon.svg';
import creditCard from 'assets/svg/credit-card.svg';
export default { export default {
mixins: [paymentsMixin], mixins: [paymentsMixin],
components: {
amazonButton,
},
data () { data () {
return { return {
amazonPayments: {}, amazonPayments: {},
icons: Object.freeze({ icons: Object.freeze({
amazonpay, creditCardIcon,
creditCard,
}), }),
PAGES: { PAGES: {
CREATE_GROUP: 'create-group', CREATE_GROUP: 'create-group',
@@ -159,7 +148,7 @@ export default {
this.showStripe(paymentData); this.showStripe(paymentData);
} else if (this.paymentMethod === this.PAYMENTS.AMAZON) { } else if (this.paymentMethod === this.PAYMENTS.AMAZON) {
paymentData.type = 'subscription'; paymentData.type = 'subscription';
this.amazonPaymentsInit(paymentData); return paymentData;
} }
}, },
}, },

View File

@@ -48,14 +48,11 @@ div
.box.payment-providers .box.payment-providers
h3 Choose your payment method h3 Choose your payment method
.box.payment-button(@click='pay(PAYMENTS.STRIPE)') .payments-column
div button.purchase.btn.btn-primary.payment-button.payment-item(@click='pay(PAYMENTS.STRIPE)')
.svg-icon.credit-card-icon(v-html="icons.group") .svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
p.credit-card Credit Card | {{ $t('card') }}
p Powered by Stripe amazon-button.payment-item(:amazon-data="pay(PAYMENTS.AMAZON)")
.box.payment-button(@click='pay(PAYMENTS.AMAZON)')
.svg-icon.amazon-pay-icon(v-html="icons.amazonpay")
.container.col-6.offset-3.create-option(v-if='!upgradingGroup._id') .container.col-6.offset-3.create-option(v-if='!upgradingGroup._id')
.row .row
h1.col-12.text-center.purple-header Create your Group today! h1.col-12.text-center.purple-header Create your Group today!
@@ -99,13 +96,13 @@ div
.form-group .form-group
button.btn.btn-primary.btn-lg.btn-block(@click="createGroup()", :disabled="!newGroupIsReady") {{ $t('createGroupPlan') }} button.btn.btn-primary.btn-lg.btn-block(@click="createGroup()", :disabled="!newGroupIsReady") {{ $t('createGroupPlan') }}
.col-12(v-if='activePage === PAGES.PAY') .col-12(v-if='activePage === PAGES.PAY')
.payment-providers .text-center
h3 Choose your payment method h3 Choose your payment method
.box.payment-button(@click='pay(PAYMENTS.STRIPE)') .payments-column.mx-auto
p Credit Card button.purchase.btn.btn-primary.payment-button.payment-item(@click='pay(PAYMENTS.STRIPE)')
p Powered by Stripe .svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
.box.payment-button(@click='pay(PAYMENTS.AMAZON)') | {{ $t('card') }}
| Amazon Pay amazon-button.payment-item(:amazon-data="pay(PAYMENTS.AMAZON)")
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -130,12 +127,6 @@ div
color: #fff; color: #fff;
} }
.payment-button {
display: block;
margin: 0 auto;
margin-bottom: 1em;
}
.plus .svg-icon{ .plus .svg-icon{
width: 24px; width: 24px;
} }
@@ -143,26 +134,6 @@ div
.payment-providers { .payment-providers {
width: 350px; width: 350px;
} }
.credit-card {
font-size: 20px;
font-weight: bold;
margin-bottom: 0;
margin-top: .5em;
display: inline-block;
}
.credit-card-icon {
width: 25px;
display: inline-block;
margin-right: .5em;
}
.amazon-pay-icon {
width: 150px;
margin: 0 auto;
margin-top: .5em;
}
} }
.header { .header {
@@ -316,35 +287,25 @@ div
vertical-align: bottom; vertical-align: bottom;
} }
} }
.payment-button {
width: 200px;
height: 80px;
margin-bottom: .5em;
padding: .5em;
display: block;
}
.payment-button:hover {
cursor: pointer;
}
</style> </style>
<script> <script>
import paymentsMixin from '../../mixins/payments'; import paymentsMixin from '../../mixins/payments';
import { mapState } from 'client/libs/store'; import { mapState } from 'client/libs/store';
import group from 'assets/svg/group.svg';
import amazonpay from 'assets/svg/amazonpay.svg';
import positiveIcon from 'assets/svg/positive.svg'; import positiveIcon from 'assets/svg/positive.svg';
import creditCardIcon from 'assets/svg/credit-card-icon.svg';
import amazonButton from 'client/components/payments/amazonButton';
export default { export default {
mixins: [paymentsMixin], mixins: [paymentsMixin],
components: {
amazonButton,
},
data () { data () {
return { return {
amazonPayments: {}, amazonPayments: {},
icons: Object.freeze({ icons: Object.freeze({
group, creditCardIcon,
amazonpay,
positiveIcon, positiveIcon,
}), }),
PAGES: { PAGES: {
@@ -413,7 +374,7 @@ export default {
this.showStripe(paymentData); this.showStripe(paymentData);
} else if (this.paymentMethod === this.PAYMENTS.AMAZON) { } else if (this.paymentMethod === this.PAYMENTS.AMAZON) {
paymentData.type = 'subscription'; paymentData.type = 'subscription';
this.amazonPaymentsInit(paymentData); return paymentData;
} }
}, },
}, },

View File

@@ -0,0 +1,102 @@
<template lang="pug">
.amazon-pay-button(:id="buttonId")
</template>
<script>
import axios from 'axios';
import { mapState } from 'client/libs/store';
import uuid from 'uuid';
import paymentsMixin from 'client/mixins/payments';
const AMAZON_PAYMENTS = process.env.AMAZON_PAYMENTS; // eslint-disable-line
export default {
mixins: [paymentsMixin],
data () {
return { // @TODO what needed here? can be moved to mixin?
amazonPayments: {
modal: null,
type: null,
gift: null,
loggedIn: false,
paymentSelected: false,
billingAgreementId: '',
recurringConsent: false,
orderReferenceId: null,
subscription: null,
coupon: null,
},
isAmazonSetup: false,
amazonButtonEnabled: false,
groupToCreate: null, // creating new group
group: null, // upgrading existing group
buttonId: null,
};
},
props: {
amazonData: Object,
},
computed: {
...mapState({user: 'user.data'}),
...mapState(['isAmazonReady']),
amazonPaymentsCanCheckout () {
if (this.amazonPayments.type === 'single') {
return this.amazonPayments.paymentSelected === true;
} else if (this.amazonPayments.type === 'subscription') {
return this.amazonPayments.paymentSelected && this.amazonPayments.recurringConsent;
}
return false;
},
},
beforeMount () {
this.buttonId = `AmazonPayButton-${uuid.v4()}`;
},
mounted () {
this.amazonPaymentsInit(this.amazonData); // TOOD clone
if (this.isAmazonReady) return this.setupAmazon();
this.$store.watch(state => state.isAmazonReady, (isAmazonReady) => {
if (isAmazonReady) return this.setupAmazon();
});
},
methods: {
setupAmazon () {
if (this.isAmazonSetup) return false;
this.isAmazonSetup = true;
this.showButton();
},
showButton () {
window.OffAmazonPayments.Button( // eslint-disable-line new-cap
this.buttonId, // ID of the button
AMAZON_PAYMENTS.SELLER_ID,
{
type: 'PwA',
color: 'Gold',
size: 'large',
agreementType: 'BillingAgreement',
onSignIn: async (contract) => { // @TODO send to modal
this.amazonPayments.billingAgreementId = contract.getAmazonBillingAgreementId();
this.$set(this.amazonPayments, 'loggedIn', true);
this.$root.$emit('habitica::pay-with-amazon', this.amazonPayments);
},
authorization: () => {
window.amazon.Login.authorize({
scope: 'payments:widget',
popup: true,
}, function amazonSuccess (response) {
if (response.error) return alert(response.error);
const url = '/amazon/verifyAccessToken';
axios.post(url, response).catch((e) => {
alert(e.message);
});
});
},
onError: this.amazonOnError, // @TODO port here
});
},
},
};
</script>

View File

@@ -1,7 +1,6 @@
<template lang="pug"> <template lang="pug">
b-modal#amazon-payment(title="Amazon", :hide-footer="true", size='md') b-modal#amazon-payment(title="Amazon", :hide-footer="true", size='md')
h2.text-center Continue with Amazon h2.text-center Continue with Amazon
#AmazonPayButton
#AmazonPayWallet(v-if="amazonPayments.loggedIn", style="width: 400px; height: 228px;") #AmazonPayWallet(v-if="amazonPayments.loggedIn", style="width: 400px; height: 228px;")
template(v-if="amazonPayments.loggedIn && amazonPayments.type === 'subscription'") template(v-if="amazonPayments.loggedIn && amazonPayments.type === 'subscription'")
br br
@@ -19,7 +18,7 @@
margin-bottom: 12px; margin-bottom: 12px;
} }
#AmazonPayButton, #AmazonPayWallet, #AmazonPayRecurring { #AmazonPayWallet, #AmazonPayRecurring {
margin: 0 auto; margin: 0 auto;
} }
@@ -54,7 +53,6 @@ export default {
subscription: null, subscription: null,
coupon: null, coupon: null,
}, },
OffAmazonPayments: {},
isAmazonSetup: false, isAmazonSetup: false,
amazonButtonEnabled: false, amazonButtonEnabled: false,
groupToCreate: null, // creating new group groupToCreate: null, // creating new group
@@ -74,12 +72,6 @@ export default {
}, },
}, },
mounted () { mounted () {
if (this.isAmazonReady) return this.setupAmazon();
this.$store.watch(state => state.isAmazonReady, (isAmazonReady) => {
if (isAmazonReady) return this.setupAmazon();
});
this.$root.$on('habitica::pay-with-amazon', (amazonPaymentsData) => { this.$root.$on('habitica::pay-with-amazon', (amazonPaymentsData) => {
if (!amazonPaymentsData) return; if (!amazonPaymentsData) return;
@@ -90,67 +82,30 @@ export default {
this.amazonPayments = Object.assign({}, amazonPayments, amazonPaymentsData); this.amazonPayments = Object.assign({}, amazonPayments, amazonPaymentsData);
this.$root.$emit('bv::show::modal', 'amazon-payment'); this.$root.$emit('bv::show::modal', 'amazon-payment');
this.$nextTick(async () => {
if (this.amazonPayments.type === 'subscription') {
this.amazonInitWidgets();
} else {
let url = '/amazon/createOrderReferenceId';
let response = await axios.post(url, {
billingAgreementId: this.amazonPayments.billingAgreementId,
});
if (response.status <= 400) {
this.amazonPayments.orderReferenceId = response.data.data.orderReferenceId;
this.amazonInitWidgets();
} else {
alert(response.message);
}
}
});
}); });
}, },
destroyed () { destroyed () {
this.$root.$off('habitica::pay-with-amazon'); this.$root.$off('habitica::pay-with-amazon');
}, },
methods: { methods: {
setupAmazon () {
if (this.isAmazonSetup) return false;
this.isAmazonSetup = true;
this.OffAmazonPayments = window.OffAmazonPayments;
this.showButton();
},
showButton () {
// @TODO: prevent modal close form clicking outside
let amazonButton = this.OffAmazonPayments.Button( // eslint-disable-line
'AmazonPayButton',
AMAZON_PAYMENTS.SELLER_ID,
{
type: 'PwA',
color: 'Gold',
size: 'small',
agreementType: 'BillingAgreement',
onSignIn: async (contract) => {
this.amazonPayments.billingAgreementId = contract.getAmazonBillingAgreementId();
this.$set(this.amazonPayments, 'loggedIn', true);
if (this.amazonPayments.type === 'subscription') {
this.amazonInitWidgets();
} else {
let url = '/amazon/createOrderReferenceId';
let response = await axios.post(url, {
billingAgreementId: this.amazonPayments.billingAgreementId,
});
if (response.status <= 400) {
this.amazonPayments.orderReferenceId = response.data.data.orderReferenceId;
this.amazonInitWidgets();
return;
}
alert(response.message);
}
},
authorization: () => {
window.amazon.Login.authorize({
scope: 'payments:widget',
popup: true,
}, function amazonSuccess (response) {
if (response.error) return alert(response.error);
let url = '/amazon/verifyAccessToken';
axios.post(url, response)
.catch((e) => {
alert(e.message);
});
});
},
onError: this.amazonOnError,
});
},
amazonInitWidgets () { amazonInitWidgets () {
let walletParams = { let walletParams = {
sellerId: AMAZON_PAYMENTS.SELLER_ID, // @TODO: Import sellerId: AMAZON_PAYMENTS.SELLER_ID, // @TODO: Import
@@ -167,15 +122,14 @@ export default {
walletParams.onReady = (billingAgreement) => { walletParams.onReady = (billingAgreement) => {
this.amazonPayments.billingAgreementId = billingAgreement.getAmazonBillingAgreementId(); this.amazonPayments.billingAgreementId = billingAgreement.getAmazonBillingAgreementId();
new this.OffAmazonPayments.Widgets.Consent({ new window.OffAmazonPayments.Widgets.Consent({
sellerId: AMAZON_PAYMENTS.SELLER_ID, sellerId: AMAZON_PAYMENTS.SELLER_ID,
amazonBillingAgreementId: this.amazonPayments.billingAgreementId, amazonBillingAgreementId: this.amazonPayments.billingAgreementId,
design: { design: {
designMode: 'responsive', designMode: 'responsive',
}, },
onReady: (consent) => { onReady: (consent) => {
let getConsent = consent.getConsentStatus; this.$set(this.amazonPayments, 'recurringConsent', consent.getConsentStatus ? Boolean(consent.getConsentStatus()) : false);
this.$set(this.amazonPayments, 'recurringConsent', getConsent ? Boolean(getConsent()) : false);
this.$set(this, 'amazonButtonEnabled', true); this.$set(this, 'amazonButtonEnabled', true);
}, },
onConsent: (consent) => { onConsent: (consent) => {
@@ -189,7 +143,7 @@ export default {
walletParams.amazonOrderReferenceId = this.amazonPayments.orderReferenceId; walletParams.amazonOrderReferenceId = this.amazonPayments.orderReferenceId;
} }
new this.OffAmazonPayments.Widgets.Wallet(walletParams).bind('AmazonPayWallet'); new window.OffAmazonPayments.Widgets.Wallet(walletParams).bind('AmazonPayWallet');
}, },
storePaymentStatusAndReload (url) { storePaymentStatusAndReload (url) {
let paymentType; let paymentType;
@@ -305,30 +259,6 @@ export default {
amazonOnPaymentSelect () { amazonOnPaymentSelect () {
this.$set(this.amazonPayments, 'paymentSelected', true); this.$set(this.amazonPayments, 'paymentSelected', true);
}, },
amazonOnError (error) {
alert(error.getErrorMessage());
this.reset();
},
reset () {
// @TODO: Ensure we are using all of these
// some vars are set in the payments mixin. We should try to edit in one place
this.amazonPayments.modal = null;
this.amazonPayments.type = null;
this.amazonPayments.loggedIn = false;
// Gift
this.amazonPayments.gift = null;
this.amazonPayments.giftReceiver = null;
this.amazonPayments.billingAgreementId = null;
this.amazonPayments.orderReferenceId = null;
this.amazonPayments.paymentSelected = false;
this.amazonPayments.recurringConsent = false;
this.amazonPayments.subscription = null;
this.amazonPayments.coupon = null;
this.amazonPayments.groupToCreate = null;
this.amazonPayments.group = null;
},
}, },
}; };
</script> </script>

View File

@@ -44,16 +44,13 @@
button.btn.btn-primary(@click='gemAmount === 20 ? gemAmount = 0 : gemAmount = 20') {{gemAmount === 20 ? $t('selected') : '$5.00'}} button.btn.btn-primary(@click='gemAmount === 20 ? gemAmount = 0 : gemAmount = 20') {{gemAmount === 20 ? $t('selected') : '$5.00'}}
.row.text-center .row.text-center
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }} h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
.card-deck .payments-column
.card.text-center.payment-method(@click='showStripe({})') button.purchase.btn.btn-primary.payment-button.payment-item(@click='showStripe()')
.card-body .svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"') | {{ $t('card') }}
.card.text-center.payment-method button.btn.payment-item.paypal-checkout.payment-button(@click="openPaypal(paypalCheckoutLink, 'gems')")
a.card-body.paypal(@click="openPaypal(paypalCheckoutLink, 'gems')") img(src='~assets/images/paypal-checkout.png', srcset="~assets/images/paypal-checkout@3x.png 3x ~assets/images/paypal-checkout@2x.png 2x", :alt="$t('paypal')")
img(src='~assets/images/paypal.png') amazon-button.payment-item(:amazon-data="{type: 'single'}")
.card.text-center.payment-method(@click="amazonPaymentsInit({type: 'single'})")
.card-body.amazon
img(src='~assets/images/amazon-payments.png')
.row.text-center .row.text-center
.svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"') .svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"')
.row.text-center.text-outtro .row.text-center.text-outtro
@@ -127,16 +124,14 @@
h2.mx-auto.text-payment(v-once) {{ $t('choosePaymentMethod') }} h2.mx-auto.text-payment(v-once) {{ $t('choosePaymentMethod') }}
.row.text-center .row.text-center
a.mx-auto(v-once) {{ $t('haveCouponCode') }} a.mx-auto(v-once) {{ $t('haveCouponCode') }}
.card-deck(v-if='subscriptionPlan') .payments-column(v-if='subscriptionPlan')
.card.text-center.payment-method button.purchase.btn.btn-primary.payment-button.payment-item(@click='showStripe({subscription: subscriptionPlan})')
.card-body(@click='showStripe({subscription: subscriptionPlan})') .svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"') | {{ $t('card') }}
.card.text-center.payment-method button.btn.payment-item.paypal-checkout.payment-button(@click="openPaypal(paypalSubscriptionLink, 'subscription')")
a.card-body.paypal(@click="openPaypal(paypalSubscriptionLink, 'subscription')") img(src='~assets/images/paypal-checkout.png', srcset="~assets/images/paypal-checkout@3x.png 3x ~assets/images/paypal-checkout@2x.png 2x", :alt="$t('paypal')")
img(src='~assets/images/paypal.png') amazon-button.payment-item(:amazon-data="{type: 'subscription', subscription: subscriptionPlan}")
.card.text-center.payment-method
.card-body.amazon(@click="amazonPaymentsInit({type: 'subscription', subscription: subscriptionPlan})")
img(src='~assets/images/amazon-payments.png')
.row.text-center .row.text-center
.svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"') .svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"')
.row.text-center.text-outtro .row.text-center.text-outtro
@@ -162,6 +157,11 @@
<style lang="scss" scoped> <style lang="scss" scoped>
@import '~client/assets/scss/colors.scss'; @import '~client/assets/scss/colors.scss';
.payments-column {
margin: 0 auto;
}
a.mx-auto { a.mx-auto {
color: #2995cd; color: #2995cd;
} }
@@ -174,10 +174,6 @@
font-size: 16px; font-size: 16px;
} }
.amazon {
padding-top: 1.8em;
}
.benefits { .benefits {
font-size: 14px; font-size: 14px;
} }
@@ -194,19 +190,6 @@
justify-content: center; justify-content: center;
} }
.card {
margin: 1em;
border-radius: 2px;
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
}
.card.active {
border-color: #24cc8f;
button {
background-color: #24cc8f;
}
}
.divider { .divider {
width: 80%; width: 80%;
height: 1px; height: 1px;
@@ -272,18 +255,6 @@
cursor: pointer; cursor: pointer;
} }
.payment-method {
background-color: #e1e0e3;
}
.payment-method:hover {
cursor: pointer;
}
.paypal {
padding-top: 1.3em;
}
.spacer { .spacer {
height: 4em; height: 4em;
} }
@@ -328,7 +299,6 @@
color: #4e4a57; color: #4e4a57;
font-size: 24px; font-size: 24px;
margin: 1em; margin: 1em;
opacity: 0.64;
} }
</style> </style>
@@ -339,7 +309,7 @@
import paymentsMixin from 'client/mixins/payments'; import paymentsMixin from 'client/mixins/payments';
import checkIcon from 'assets/svg/check.svg'; import checkIcon from 'assets/svg/check.svg';
import creditCard from 'assets/svg/credit-card.svg'; import creditCardIcon from 'assets/svg/credit-card-icon.svg';
import heart from 'assets/svg/health.svg'; import heart from 'assets/svg/health.svg';
import logo from 'assets/svg/habitica-logo.svg'; import logo from 'assets/svg/habitica-logo.svg';
@@ -348,10 +318,13 @@
import fortyTwoGems from 'assets/svg/42-gems.svg'; import fortyTwoGems from 'assets/svg/42-gems.svg';
import eightyFourGems from 'assets/svg/84-gems.svg'; import eightyFourGems from 'assets/svg/84-gems.svg';
import amazonButton from 'client/components/payments/amazonButton';
export default { export default {
mixins: [paymentsMixin], mixins: [paymentsMixin],
components: { components: {
planGemLimits, planGemLimits,
amazonButton,
}, },
computed: { computed: {
...mapState({user: 'user.data'}), ...mapState({user: 'user.data'}),
@@ -373,7 +346,7 @@
icons: Object.freeze({ icons: Object.freeze({
logo, logo,
check: checkIcon, check: checkIcon,
creditCard, creditCardIcon,
fourGems, fourGems,
heart, heart,
twentyOneGems, twentyOneGems,
@@ -383,7 +356,6 @@
gemAmount: 0, gemAmount: 0,
subscriptionPlan: '', subscriptionPlan: '',
selectedPage: 'subscribe', selectedPage: 'subscribe',
amazonPayments: {},
planGemLimits, planGemLimits,
}; };
}, },

View File

@@ -1,6 +1,6 @@
<template lang="pug"> <template lang="pug">
b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide()') b-modal#send-gems(:title="title", :hide-footer="true", size='md', @hide='onHide()')
.modal-body(v-if='userReceivingGems') div(v-if='userReceivingGems')
.panel.panel-default( .panel.panel-default(
:class="gift.type === 'gems' ? 'panel-primary' : 'transparent'", :class="gift.type === 'gems' ? 'panel-primary' : 'transparent'",
@click='gift.type = "gems"' @click='gift.type = "gems"'
@@ -32,7 +32,7 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
h3.panel-heading {{ $t('subscription') }} h3.panel-heading {{ $t('subscription') }}
.panel-body .panel-body
.row .row
.col-md-4 .col-md-12
.form-group .form-group
.radio(v-for='block in subscriptionBlocks', v-if="block.target !== 'group' && block.canSubscribe === true") .radio(v-for='block in subscriptionBlocks', v-if="block.target !== 'group' && block.canSubscribe === true")
label label
@@ -48,11 +48,13 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
@click="sendGift()", @click="sendGift()",
:disabled="sendingInProgress" :disabled="sendingInProgress"
) {{ $t("send") }} ) {{ $t("send") }}
template(v-else) .payments-column.mx-auto(v-else, :class="{'payments-disabled': !gift.subscription.key}")
button.btn.btn-primary(@click='showStripe({gift, uuid: userReceivingGems._id, receiverName})') {{ $t('card') }} button.purchase.btn.btn-primary.payment-button.payment-item(@click='showStripe({gift, uuid: userReceivingGems._id, receiverName})', :disabled="!gift.subscription.key")
button.btn.btn-warning(@click='openPaypalGift({gift: gift, giftedTo: userReceivingGems._id, receiverName})') PayPal .svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
button.btn.btn-success(@click="amazonPaymentsInit({type: 'single', gift, giftedTo: userReceivingGems._id, receiverName})") Amazon Payments | {{ $t('card') }}
button.btn.btn-secondary(@click='close()') {{$t('cancel')}} button.btn.payment-item.paypal-checkout.payment-button(@click="openPaypalGift({gift: gift, giftedTo: userReceivingGems._id, receiverName})", :disabled="!gift.subscription.key")
img(src='~assets/images/paypal-checkout.png', srcset="~assets/images/paypal-checkout@3x.png 3x ~assets/images/paypal-checkout@2x.png 2x", :alt="$t('paypal')")
amazon-button.payment-item.mb-0(:amazon-data="{type: 'single', gift, giftedTo: userReceivingGems._id, receiverName}")
</template> </template>
<style lang="scss"> <style lang="scss">
@@ -78,6 +80,12 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
} }
</style> </style>
<style lang="scss" scoped>
input[type="radio"] {
margin-right: 4px;
}
</style>
<script> <script>
import toArray from 'lodash/toArray'; import toArray from 'lodash/toArray';
import omitBy from 'lodash/omitBy'; import omitBy from 'lodash/omitBy';
@@ -86,12 +94,17 @@ import { mapState } from 'client/libs/store';
import planGemLimits from '../../../common/script/libs/planGemLimits'; import planGemLimits from '../../../common/script/libs/planGemLimits';
import paymentsMixin from 'client/mixins/payments'; import paymentsMixin from 'client/mixins/payments';
import notificationsMixin from 'client/mixins/notifications'; import notificationsMixin from 'client/mixins/notifications';
import amazonButton from 'client/components/payments/amazonButton';
import creditCardIcon from 'assets/svg/credit-card-icon.svg';
// @TODO: EMAILS.TECH_ASSISTANCE_EMAIL, load from config // @TODO: EMAILS.TECH_ASSISTANCE_EMAIL, load from config
const TECH_ASSISTANCE_EMAIL = 'admin@habitica.com'; const TECH_ASSISTANCE_EMAIL = 'admin@habitica.com';
export default { export default {
mixins: [paymentsMixin, notificationsMixin], mixins: [paymentsMixin, notificationsMixin],
components: {
amazonButton,
},
data () { data () {
return { return {
planGemLimits, planGemLimits,
@@ -110,6 +123,9 @@ export default {
}, },
sendingInProgress: false, sendingInProgress: false,
userReceivingGems: null, userReceivingGems: null,
icons: Object.freeze({
creditCardIcon,
}),
}; };
}, },
computed: { computed: {

View File

@@ -73,15 +73,13 @@
.subscribe-pay(v-if='!hasSubscription || hasCanceledSubscription') .subscribe-pay(v-if='!hasSubscription || hasCanceledSubscription')
h3 {{ $t('subscribeUsing') }} h3 {{ $t('subscribeUsing') }}
.row.text-center .payments-column
.col-md-4 button.purchase.btn.btn-primary.payment-button.payment-item(@click='showStripe({subscription:subscription.key, coupon:subscription.coupon})', :disabled='!subscription.key')
button.purchase.btn.btn-primary(@click='showStripe({subscription:subscription.key, coupon:subscription.coupon})', :disabled='!subscription.key') {{ $t('card') }} .svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
.col-md-4 | {{ $t('card') }}
a.purchase(@click="openPaypal(paypalPurchaseLink, 'subscription')", :disabled='!subscription.key') button.btn.payment-item.paypal-checkout.payment-button(@click="openPaypal(paypalPurchaseLink, 'subscription')", :disabled='!subscription.key')
img(src='https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png', :alt="$t('paypal')") img(src='~assets/images/paypal-checkout.png', srcset="~assets/images/paypal-checkout@3x.png 3x ~assets/images/paypal-checkout@2x.png 2x", :alt="$t('paypal')")
.col-md-4 amazon-button.payment-item(:amazon-data="{type: 'subscription', subscription: this.subscription.key, coupon: this.subscription.coupon}")
a.btn.btn-secondary.purchase(@click="payWithAmazon()")
img(src='https://payments.amazon.com/gp/cba/button', :alt="$t('amazonPayments')")
.row .row
.col-6 .col-6
h2(v-once) {{ $t('giftSubscription') }} h2(v-once) {{ $t('giftSubscription') }}
@@ -92,7 +90,7 @@
h4(v-once) {{ $t('giftSubscriptionText4') }} h4(v-once) {{ $t('giftSubscriptionText4') }}
</template> </template>
<style scoped> <style scoped lang="scss">
.badge.badge-success { .badge.badge-success {
color: #fff; color: #fff;
} }
@@ -115,8 +113,14 @@ import planGemLimits from '../../../common/script/libs/planGemLimits';
import paymentsMixin from '../../mixins/payments'; import paymentsMixin from '../../mixins/payments';
import notificationsMixin from '../../mixins/notifications'; import notificationsMixin from '../../mixins/notifications';
import amazonButton from 'client/components/payments/amazonButton';
import creditCardIcon from 'assets/svg/credit-card-icon.svg';
export default { export default {
mixins: [paymentsMixin, notificationsMixin], mixins: [paymentsMixin, notificationsMixin],
components: {
amazonButton,
},
data () { data () {
return { return {
loading: false, loading: false,
@@ -137,6 +141,9 @@ export default {
PAYPAL: 'Paypal', PAYPAL: 'Paypal',
GIFT: 'Gift', GIFT: 'Gift',
}, },
icons: Object.freeze({
creditCardIcon,
}),
}; };
}, },
computed: { computed: {
@@ -240,13 +247,6 @@ export default {
}, },
}, },
methods: { methods: {
payWithAmazon () {
this.amazonPaymentsInit({
type: 'subscription',
subscription: this.subscription.key,
coupon: this.subscription.coupon,
});
},
async applyCoupon (coupon) { async applyCoupon (coupon) {
const response = await axios.post(`/api/v4/coupons/validate/${coupon}`); const response = await axios.post(`/api/v4/coupons/validate/${coupon}`);

View File

@@ -251,8 +251,30 @@ export default {
this.amazonPayments.gift = data.gift; this.amazonPayments.gift = data.gift;
this.amazonPayments.type = data.type; this.amazonPayments.type = data.type;
},
amazonOnError (error) {
alert(error.getErrorMessage());
this.reset();
},
reset () {
// @TODO: Ensure we are using all of these
// some vars are set in the payments mixin. We should try to edit in one place
this.amazonPayments.modal = null;
this.amazonPayments.type = null;
this.amazonPayments.loggedIn = false;
this.$root.$emit('habitica::pay-with-amazon', this.amazonPayments); // Gift
this.amazonPayments.gift = null;
this.amazonPayments.giftReceiver = null;
this.amazonPayments.billingAgreementId = null;
this.amazonPayments.orderReferenceId = null;
this.amazonPayments.paymentSelected = false;
this.amazonPayments.recurringConsent = false;
this.amazonPayments.subscription = null;
this.amazonPayments.coupon = null;
this.amazonPayments.groupToCreate = null;
this.amazonPayments.group = null;
}, },
async cancelSubscription (config) { async cancelSubscription (config) {
if (config && config.group && !confirm(this.$t('confirmCancelGroupPlan'))) return; if (config && config.group && !confirm(this.$t('confirmCancelGroupPlan'))) return;

View File

@@ -112,7 +112,7 @@
"donationDesc": "20 Gems, Donation to Habitica", "donationDesc": "20 Gems, Donation to Habitica",
"payWithCard": "Pay with Card", "payWithCard": "Pay with Card",
"payNote": "Note: PayPal sometimes takes a long time to clear. We recommend paying with card.", "payNote": "Note: PayPal sometimes takes a long time to clear. We recommend paying with card.",
"card": "Credit Card (using Stripe)", "card": "Credit Card",
"amazonInstructions": "Click the button to pay using Amazon Payments", "amazonInstructions": "Click the button to pay using Amazon Payments",
"paymentMethods": "Purchase using", "paymentMethods": "Purchase using",
"paymentSuccessful": "Your payment was successful!", "paymentSuccessful": "Your payment was successful!",