Files
habitica/website/client/src/components/payments/amazonModal.vue
T
Natalie L ce18e614be Gifting modal design - amazonModal.vue update (#14131)
* update selectUserModal.vue

* more updates to selectUserModal.vue, typo fix in subscriber.json

* remove exact sizing for selectUserModal.vue

* update to size for selectUserModal.vue

* added sendGiftModal.vue file

* updates to selectUser & sendGift modals

* making the modals go & position cursor

* working working working

* added a return to method

* avatar display & placeholder profile.name and username

* subscription-options added

* added menu row & started on gem options

* Added selectPage function, have not tested.

* updated habitica-images

* state changes

* bringing in gem counter

* arranging elements

* state changes, gem input boxes

* styling sendGiftModal.vue

* more sendGiftModal.vue styling and new close.svg icon

* more styling!

* and more styling of send own gems part of page

* images update

* more styling of own gems & some attempts to adjust :class on the menu

* styling styling styling

* replace +/- svg, styling

* styling, mostly

* new SVGs

* stylin'

* reverting svg changes

* no more stylin'

* finally got the +/- icons to show up...but they're the wrong color

* solved svg icon color problem! :)

* habitica-images

* working on sendGift part of button

* trying to make it do math, failing

* more attempts at math

* +/- buttons work on gem pages & cost calculation on buyGems

* trying to get hover colors working on +/- svgs

* formatted dollar amount as currency

* css/html for subscription-options & payments-buttons simplified

* swag at payments-buttons parameter (not tested)

* send gems from own balance works!

* working on starting page

* increment gem amount limited to maxGems and not < 0

* uncommented onHide()

* got bg color on sub options to work! yay!

* payment buttons!

* making g1g1 look good

* position modal on page properly & code clean-up

* Changes as requested!

* small color update

* fixed ternary function

* chore(html): indentation and comments

* fix(fn): correct catch for under-0

* chore(json): whitespace

* update gem styling; add linebreak to notifications.vue bc linter

* updating subscriptionOptions

* snackbar css fix

* reverting commit e16c12f

* removing merge conflict markers

* just a little comment

* fixed some navigation, clear input field on selectPage, cleaned up code; another try at subscriptionOption.vue

* merge upstream/develop

* update selectPage() to disable Gems menu items when on 'ownGems' or 'buyGems' states

* working on subscriptionOptions.vue logic

* fix(script): changed props & added updateSubscriptionData()

* fix(script): forgot to call updateSubscriptionData()

* fix(scripts): corrected :userReceivingGift on sendGiftModal.vue

* fix(scripts): correct props userReceivingGift to an Object

* fix(scripts): corrected v-if & revised props

* fix(style/html/whitespace): updated css for close.svg and added missing </div>

* style(radio-buttons): updated focus states and added hover states

* style(radio-buttons): refined focus and hover states

* fix(function): changed buyGemsLink to buyGems; still working on menu

* style(radio buttons): ensured consistent display of radio buttons through-out site; still struggling with hover states

* style(radio buttons): updated focus/active/hover to match design & removed unnecessary code

* fix: set default subscription option to 1 month

* fix(function): add default amounts to gem states when modal selected from user profile

* fix(build): use develop package json

* fix: SCSS commenting & abstracted setGemsDefault()

* fix(packages): revert to develop

* fix: remove unnecessary console.log statement

* fix(payments): storePaymentStatusAndReload() modified

Co-authored-by: SabreCat <sabe@habitica.com>
2022-07-21 14:06:50 -05:00

291 lines
9.4 KiB
Vue

<template>
<b-modal
id="amazon-payment"
title="Amazon"
size="md"
:hide-footer="true"
@hide="reset()"
>
<h2 class="text-center">
Continue with Amazon
</h2>
<div
v-if="amazonPayments.loggedIn"
id="AmazonPayWallet"
style="width: 400px; height: 228px;"
></div>
<template v-if="amazonPayments.loggedIn && amazonPayments.type === 'subscription'">
<br>
<p v-html="$t('amazonPaymentsRecurring')"></p>
<div
id="AmazonPayRecurring"
style="width: 400px; height: 140px;"
></div>
</template>
<div class="modal-footer">
<div class="text-center">
<button
v-if="amazonPaymentsCanCheckout"
class="btn btn-primary"
:disabled="!amazonButtonEnabled"
@click="amazonCheckOut()"
>
{{ $t('checkout') }}
</button>
</div>
</div>
</b-modal>
</template>
<style scoped>
#AmazonPayButton {
width: 150px;
margin-bottom: 12px;
}
#AmazonPayWallet, #AmazonPayRecurring {
margin: 0 auto;
}
#AmazonPayRecurring {
height: 200px;
width: 500px;
}
</style>
<script>
import axios from 'axios';
import pick from 'lodash/pick';
import { mapState } from '@/libs/store';
import { CONSTANTS, setLocalSetting } from '@/libs/userlocalManager';
import paymentsMixin from '@/mixins/payments';
const habiticaUrl = `${window.location.protocol}//${window.location.host}`;
export default {
mixins: [paymentsMixin],
data () {
return {
amazonPayments: {
modal: null,
type: null,
gemsBlock: 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
};
},
computed: {
...mapState({ user: 'user.data' }),
...mapState(['isAmazonReady']),
amazonPaymentsCanCheckout () {
if (this.amazonPayments.type === 'single') {
return this.amazonPayments.paymentSelected === true;
} if (this.amazonPayments.type === 'subscription') {
return this.amazonPayments.paymentSelected && this.amazonPayments.recurringConsent;
}
return false;
},
},
mounted () {
this.$root.$on('habitica::pay-with-amazon', amazonPaymentsData => {
if (!amazonPaymentsData) return;
const amazonPayments = {
type: 'single',
loggedIn: false,
};
this.amazonPayments = { ...amazonPayments, ...amazonPaymentsData };
this.$root.$emit('bv::show::modal', 'amazon-payment');
this.$nextTick(async () => {
if (this.amazonPayments.type === 'subscription') {
this.amazonInitWidgets();
} else {
const url = '/amazon/createOrderReferenceId';
const response = await axios.post(url, {
billingAgreementId: this.amazonPayments.billingAgreementId,
});
if (response.status <= 400) {
this.amazonPayments.orderReferenceId = response.data.data.orderReferenceId;
this.amazonInitWidgets();
} else {
window.alert(response.message); // eslint-disable-line no-alert
}
}
});
});
},
beforeDestroy () {
this.$root.$off('habitica::pay-with-amazon');
},
methods: {
amazonInitWidgets () {
const walletParams = {
sellerId: process.env.AMAZON_PAYMENTS_SELLER_ID, // @TODO: Import
design: {
designMode: 'responsive',
},
onPaymentSelect: this.amazonOnPaymentSelect,
onError: this.amazonOnError,
};
if (this.amazonPayments.type === 'subscription') {
walletParams.agreementType = 'BillingAgreement';
walletParams.billingAgreementId = this.amazonPayments.billingAgreementId;
walletParams.onReady = billingAgreement => {
this.amazonPayments.billingAgreementId = billingAgreement.getAmazonBillingAgreementId();
new window.OffAmazonPayments.Widgets.Consent({
sellerId: process.env.AMAZON_PAYMENTS_SELLER_ID,
amazonBillingAgreementId: this.amazonPayments.billingAgreementId,
design: {
designMode: 'responsive',
},
onReady: consent => {
this.$set(this.amazonPayments, 'recurringConsent', consent.getConsentStatus ? Boolean(consent.getConsentStatus()) : false);
this.$set(this, 'amazonButtonEnabled', true);
},
onConsent: consent => {
this.$set(this.amazonPayments, 'recurringConsent', Boolean(consent.getConsentStatus()));
},
onError: this.amazonOnError,
}).bind('AmazonPayRecurring');
};
} else {
this.$set(this, 'amazonButtonEnabled', true);
walletParams.amazonOrderReferenceId = this.amazonPayments.orderReferenceId;
}
new window.OffAmazonPayments.Widgets.Wallet(walletParams).bind('AmazonPayWallet');
},
storePaymentStatusAndReload (url) {
let paymentType;
if (this.amazonPayments.type === 'single' && !this.amazonPayments.gift) paymentType = 'gems';
if (this.amazonPayments.type === 'subscription') paymentType = 'subscription';
if (this.amazonPayments.groupId || this.amazonPayments.groupToCreate) paymentType = 'groupPlan';
if (this.amazonPayments.type === 'single' && this.amazonPayments.gift && this.amazonPayments.giftReceiver) {
paymentType = this.amazonPayments.gift.type === 'gems' ? 'gift-gems' : 'gift-subscription';
}
const appState = {
paymentMethod: 'amazon',
paymentCompleted: true,
paymentType,
};
if (paymentType === 'subscription') {
appState.subscriptionKey = this.amazonPayments.subscription;
} else if (paymentType === 'groupPlan') {
appState.subscriptionKey = this.amazonPayments.subscription;
if (this.amazonPayments.groupToCreate) {
appState.newGroup = true;
appState.group = pick(this.amazonPayments.groupToCreate, ['_id', 'memberCount', 'name']);
} else {
appState.newGroup = false;
appState.group = pick(this.amazonPayments.group, ['_id', 'memberCount', 'name']);
}
} else if (paymentType && paymentType.indexOf('gift-') === 0) {
appState.gift = this.amazonPayments.gift;
appState.giftReceiver = this.amazonPayments.giftReceiver;
} else if (paymentType === 'gems') {
appState.gemsBlock = this.amazonPayments.gemsBlock;
}
setLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE, JSON.stringify(appState));
if (url) {
window.location.assign(url);
} else {
window.location.reload(true);
}
},
async amazonCheckOut () {
this.amazonButtonEnabled = false;
// @TODO: Create factory functions
// @TODO: A gift should not read the same as buying gems for yourself.
if (this.amazonPayments.type === 'single') {
const url = '/amazon/checkout';
const data = {
orderReferenceId: this.amazonPayments.orderReferenceId,
gift: this.amazonPayments.gift,
};
if (this.amazonPayments.gemsBlock) {
data.gemsBlock = this.amazonPayments.gemsBlock.key;
}
try {
await axios.post(url, data);
this.$set(this, 'amazonButtonEnabled', true);
this.storePaymentStatusAndReload();
} catch (e) {
console.error(e); // eslint-disable-line no-console
this.$set(this, 'amazonButtonEnabled', true);
this.reset();
}
} else if (this.amazonPayments.type === 'subscription') {
let url = '/amazon/subscribe';
if (this.amazonPayments.groupToCreate) {
url = '/api/v4/groups/create-plan';
}
try {
const response = await axios.post(url, {
billingAgreementId: this.amazonPayments.billingAgreementId,
subscription: this.amazonPayments.subscription,
coupon: this.amazonPayments.coupon,
groupId: this.amazonPayments.groupId,
groupToCreate: this.amazonPayments.groupToCreate,
paymentType: 'Amazon',
});
const newGroup = response.data.data;
if (newGroup && newGroup._id) {
// Handle new user signup
if (!this.$store.state.isUserLoggedIn) {
this.storePaymentStatusAndReload(`${habiticaUrl}/group-plans/${newGroup._id}/task-information?showGroupOverview=true`);
return;
}
this.user.guilds.push(newGroup._id);
this.storePaymentStatusAndReload(`${habiticaUrl}/group-plans/${newGroup._id}/task-information`);
return;
}
if (this.amazonPayments.groupId) {
this.storePaymentStatusAndReload(`${habiticaUrl}/group-plans/${this.amazonPayments.groupId}/task-information`);
return;
}
this.storePaymentStatusAndReload();
} catch (e) {
this.$set(this, 'amazonButtonEnabled', true);
this.$root.$emit('bv::hide::modal', 'amazon-payment');
// @TODO: do we need this? this.amazonPaymentsreset();
}
}
},
amazonOnPaymentSelect () {
this.$set(this.amazonPayments, 'paymentSelected', true);
},
},
};
</script>