DigitalConsumer.FixMyGlass/src/layouts/payment/payment.vue
Scott Kiener 77c007c444 CASH-462 | Rename and restructure submittedOrder
Rename to submittedState
Add an applicationUser attribute
2025-04-03 13:19:44 -04:00

842 lines
35 KiB
Vue

<template>
<Form>
<loadingModal notFullScreen ref="loadingModal" />
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-md-6">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4 p-0">
<div>
<alert
ref="piaCCErrorAlert"
class="my-4"
v-if="shouldDisplayPiaCCAlert"
cmsWidgetName="PIACCErrorAlertWidget"
alertClass="alert-danger"
@textLinkClicked="paymentFailedPayLater"
v-bind:isDismissible="false" />
</div>
<div>
<alert
ref="piaAPErrorAlert"
class="my-4"
v-if="shouldDisplayPiaAPAlert"
cmsWidgetName="PIAAPErrorAlertWidget"
alertClass="alert-danger"
@textLinkClicked="paymentFailedPayLater"
v-bind:isDismissible="false" />
</div>
<div id="card-container">
<iframe
v-resize
ref="paymentFrame"
class="hop-iframe payment-iframe"
name="card-frame"
id="card-frame"
seamless
scrolling="no"
allow="payment *; microphone *; geolocation *;"></iframe>
</div>
<hr />
<cart
ref="cart"
:damage="damageInfo"
:availableVaps="availableVaps"
:allowItemRemoval="false"
v-model="lineItems"
servicePackageOptionsCmsName="ServicePackageTitle"
recyclingModalCmsWidgetName="RecycleModal"
:isInsurance="isInsurance"
:insuranceDeductible="currentDeductible"
:insuranceCompanyName="insuranceCompanyName"
:showInsuranceCoverageAs="showInsuranceCoverageAs"
:isItac="isItac"
:isNoComp="isNoComp"
:isExpandedOnLoad="true" />
<hr class="mb-5" />
<navbar
cmsWidgetName="FunnelFooterWidget"
isForwardActionDisabled="true"
:isBackButtonHidden="shouldHideBackButton"
isSubmitHidden="true"
@back-clicked="backButtonAction" />
</div>
</div>
<div v-if="shouldBlockInteraction" class="ui-block" @click="supressClick"></div>
</div>
</Form>
<form
ref="hopForm"
id="card-data"
:target="isPaypal ? '_top' : 'card-frame'"
method="POST"
:action="checkoutUrl">
<input type="hidden" name="paymentType" :value="paymentType" />
<input type="hidden" name="sgSessionId" :value="authToken" />
<input type="hidden" name="sgAuthToken" :value="authToken" />
<input type="hidden" name="sgSignaturePublic" :value="authSignature" />
<input type="hidden" name="sgSignatureStartDate" :value="authSignatureStart" />
<input type="hidden" name="referralSeqNum" :value="referralSequenceNumber" />
<input type="hidden" name="sge_commerce_indicator_isinternet" value="true" />
<input type="hidden" name="sghopsource" value="Safelite.com" />
<input type="hidden" name="sgHtmlStyle" value="ResourceSafeliteHtml" />
<input type="hidden" name="sgErrorMessagesEmbedded" value="true" />
<input type="hidden" name="sgNoKeystrokeProcessing" value="false" />
<input type="hidden" name="maskCharacter" value="*" />
<input type="hidden" name="styleSheetCode" :value="dynamicCSSUrl" />
<input type="hidden" name="styleSheetCode2" :value="dynamicHopCSSUrl" />
<input type="hidden" name="sgReceiptResponseURL" :value="piaResponseUrl" />
<input type="hidden" name="sgDeclineResponseURL" :value="piaResponseUrl" />
<input type="hidden" name="sgErrorResponseURL" :value="piaResponseUrl" />
<input type="hidden" name="sgheaderline1" :value="getHeaderLine1" />
<input type="hidden" name="sgHeader1subtitle" value="" />
<input type="hidden" name="sgheaderline2" :value="getHeaderLine2" />
<input type="hidden" name="sgheaderline3" value="" />
<input type="hidden" name="sgheaderline4" value="" />
<input type="hidden" name="sgheaderline5" value="*Required information" />
<input type="hidden" name="billTo_firstName" :value="firstName" />
<input type="hidden" name="billTo_firstNameShow" value="true" />
<input type="hidden" name="sghopmiddleInitialShow" value="false" />
<input type="hidden" name="billTo_lastName" :value="lastName" />
<input type="hidden" name="billTo_lastNameShow" value="true" />
<input type="hidden" name="billTo_street1" value="" />
<input type="hidden" name="billTo_street2" value="" />
<input type="hidden" name="billTo_city" value="" />
<input type="hidden" name="billTo_state" value="" />
<input type="hidden" name="billTo_postalCode" value="" />
<input type="hidden" name="billTo_postalCodeShow" value="true" />
<input type="hidden" name="billTo_postalCodeEnable" value="true" />
<input type="hidden" name="sgLabelPostalCode" value="Billing ZIP" />
<input type="hidden" name="sgtotalamount" :value="displayAmount" />
<input type="hidden" name="totalAmountDecimal" :value="totalAmount" />
<input type="hidden" name="lineItems" :value="piaLineItems" />
<input type="hidden" name="sgdiscountstrikethruamount" value="" />
<input type="hidden" name="callerDisplayText" value="" />
<input
type="hidden"
name="sgtermsofusedisplaytext"
value="By selecting submit, I agree to Safelite's" />
<input
type="hidden"
name="sgtermsofuseurl"
value="http://www.safelite.com/terms-of-service/" />
<input type="hidden" name="sgtermsofuselinkdisplaytext" value="Terms of service" />
<input type="hidden" name="sgtermsofcancelrefunddisplaytext" value="and" />
<input
type="hidden"
name="sgtermsofcancelrefundlinkdisplaytext"
value="cancellation and refund policy" />
<input
type="hidden"
name="sgtermsofcancelrefundurl"
value="http://www.safelite.com/cancellation-refund-policy" />
<input
type="hidden"
name="sgErrorMessageCardVerification"
value="Credit card could not be processed" />
<input
type="hidden"
name="sgErrorMessageTimeOut"
value="For your security, this transaction has been timed out." />
<input type="hidden" name="sgLabelCardNumber" value="" />
<input type="hidden" name="sgLabelAddressLine1" :value="address1" />
<input type="hidden" name="sgLabelAddressLine2" :value="address2" />
<input type="hidden" name="sgLabelCity" :value="city" />
<input type="hidden" name="sgLabelState" :value="state" />
<input type="hidden" name="sgCtu" :value="ctu" />
<input type="hidden" name="sgWorkOrder" :value="workOrderNumber" />
<input type="hidden" name="sgEmailAddress" :value="emailAddress" />
<input type="hidden" name="paypalInvoiceNumber" :value="invoiceNumber" />
<input type="hidden" name="paypalSuccessUrl" :value="piaResponseUrl" />
<input type="hidden" name="paypalCancelUrl" :value="piaCancelUrl" />
<input type="hidden" name="sgCCDeclineURL" :value="piaErrorUrl" />
<input type="hidden" name="sgCCTimeoutURL" :value="piaCancelUrl" />
<input type="hidden" name="sgTransactionType" value="authorization" />
<input type="hidden" name="amount" :value="totalAmount" />
<input type="hidden" name="ctu" :value="ctu" />
<input type="hidden" name="orderNumber" :value="workOrderNumber" />
<input type="hidden" name="billTo_email" :value="emailAddress" />
<input type="hidden" name="useDecisionManager" value="True" />
<input type="hidden" name="correlationId" :value="referralCorrelationId" />
<input type="hidden" name="sgErrorMessageCard_CVN" value="Please enter a valid CVV" />
<input type="hidden" name="ship_to_address_line1" :value="address1" />
<input type="hidden" name="ship_to_address_line2" :value="address2" />
<input type="hidden" name="ship_to_address_city" :value="city" />
<input type="hidden" name="ship_to_address_state" :value="state" />
<input type="hidden" name="ship_to_address_country" value="US" />
<input type="hidden" name="ship_to_address_postal_code" :value="zipCode" />
<input type="hidden" name="ship_to_phone" :value="phoneNumber" />
<input type="hidden" name="calling_application" value="NextGen" />
<input type="hidden" name="parentdomainname" :value="parentNomainName" />
</form>
</template>
<script>
// Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import navbar from "@/fmg-components/nav-bar/nav-bar";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import cart from "@/fmg-components/cart/cart";
import alert from "@/ux-components/alert/alert";
import { storeActions } from "@/constants/store-actions";
import store from "@/store";
import { externalUrls } from "@/router/router-constants/externalUrl-values";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { applicationConfig } from "@/constants/application-config";
import { paymentMethods } from "@/constants/payment-method-constants";
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
import baseMixin from "@/mixins/base-mixin.js";
import { mapTaxedLineItemsToStoreFormat } from "../../store";
import {
revalidatePromosAndValidateQueryStringPromo,
getAddableVapsFromAvailableLineItems,
getVapsThatNeedToBeAddedToSatisfyPromos,
} from "@/helpers/promotions-helper";
import { queryStrings } from "@/constants/query-strings";
import { getQuerystringParameter } from "@/helpers/querystring-helper";
import { deepClone } from "@/helpers/object-helper";
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
import iframeResize from "../../../node_modules/iframe-resizer/js/iframeResizer.js";
import { routerParams } from "@/router/router-constants/router-params";
import { coverageStatus } from "@/constants/insurance";
import { getBoolFromString } from "@/helpers/boolean-helper.js";
import {
getDisplayAmountDue,
getAmountDue,
getSubTotal,
getSalesTax,
} from "@/helpers/pricing-helper.js";
export default {
name: "payment",
data() {
return {
checkoutUrl: externalUrls.SAFELITE_HOP,
piaResponseUrl: applicationConfig.PIA_RESPONSE_URL,
piaCancelUrl: applicationConfig.PIA_CANCEL_URL,
piaErrorUrl: applicationConfig.PIA_ERROR_URL,
paymentType: this.getPaymentType(),
authToken: "",
authSignature: "",
authSignatureStart: "",
referralSequenceNumber: store.getters.order.referralSequenceNumber,
emailAddress: store.getters.order.customer.emailAddress,
address1: this.getAddress1(),
address2: this.getAddress2(),
city: this.getCity(),
state: this.getState(),
zipCode: this.getZipCode(),
firstName: store.getters.order.customer.firstName,
lastName: store.getters.order.customer.lastName,
phoneNumber: store.getters.order.customer.phoneNumber,
ctu: store.getters.order.serviceLocation.zipCodeCtu,
referralCorrelationId: store.getters.order.referralCorrelationId,
workOrderNumber: this.getWOrkOrderNumber(),
invoiceNumber: this.getInvoiceNumber(),
totalAmount: this.getAmountDue(),
displayAmount: this.getDisplayAmountDue(),
piaLineItems: "",
lineItems: [],
availableVaps: [],
shouldBlockInteraction: false,
};
},
directives: {
resize: {
mounted: function (el) {
el.addEventListener("load", () => {
iframeResize({ checkOrigin: false }, el);
});
},
unmounted: function (el) {
el.iFrameResizer.removeListeners();
},
},
},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
const signaturePromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_SIGNATURE,
null,
"payment"
);
const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_WIPERS,
{
serviceZipCode: store.getters.order.serviceLocation.zipCode,
carId: store.getters.vehicle.carId,
},
"payment"
);
const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_RAIN_DEFENSE,
null,
"payment"
);
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "signature",
promise: signaturePromise,
},
{
resultKey: "wipers",
promise: wipersPromise,
},
{
resultKey: "rainDefense",
promise: rainDefensePromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
const lineItemsFromStore = deepClone(store.getters.order.lineItems);
const glassParts = lineItemsFromStore.glassParts ?? [];
const supportingItems = lineItemsFromStore.supportingItems ?? [];
const lineItemsToTax = [
resultMap.rainDefense,
...supportingItems,
...resultMap.wipers,
...glassParts,
];
const availableVaps = [resultMap.rainDefense, ...resultMap.wipers];
const pricedLineItemsToTax = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
availableLineItems: lineItemsToTax,
},
"payment",
false
);
// Promo logic
const promoCodeFromQueryString = getQuerystringParameter(queryStrings.PROMO);
const { validatePromoResponse, revalidatePromoResponse } =
await revalidatePromosAndValidateQueryStringPromo(
promoCodeFromQueryString,
pricedLineItemsToTax,
"payment"
);
const newValidatedPromos = validatePromoResponse?.orderPromos ?? [];
newValidatedPromos.push(
...(revalidatePromoResponse ? revalidatePromoResponse.promoLineItems : [])
);
pricedLineItemsToTax.push(...newValidatedPromos);
// End of promo logic
const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
billToAccountNumber: store.getters.payment.billToAccountNumber,
providerNumber: store.getters.order.serviceLocation.provider.providerNumber,
appointmentType: store.getters.order.serviceLocation.appointmentType,
serviceLocationCity: store.getters.order.serviceLocation.city,
serviceLocationState: store.getters.order.serviceLocation.state,
serviceLocationZipCode: store.getters.order.serviceLocation.zipCode,
pricedLineItems: pricedLineItemsToTax,
},
"payment",
false
);
// Match all line items to the line items as they are in the store
// and rebuild the original structure.
const lineItems = mapTaxedLineItemsToStoreFormat(taxedLineItems, lineItemsFromStore);
const taxedVaps = mapTaxedLineItemsToStoreFormat(taxedLineItems, availableVaps);
// Add items that were not in the store yet but added via query string promo validation
//newValidatedPromos contains both validated and revalidated promos.
lineItems.promos = Array.from(newValidatedPromos);
const vapsToAddToCart = getVapsThatNeedToBeAddedToSatisfyPromos(
newValidatedPromos,
taxedVaps,
lineItems
);
lineItems.vaps = lineItems.vaps ?? [];
lineItems.vaps.push(...vapsToAddToCart);
// Call the "next" function to complete the transition to this page.
next(async (vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.availableVaps = taxedVaps;
vm.lineItems = lineItems;
vm.$nextTick(() => {
if (vm.$refs.cart) {
const cartItems = vm.$refs.cart.cartItems;
vm.getPiaLineItems(cartItems);
}
vm.fetchSignatureInfo(resultMap.signature);
vm.setIFrameListener();
});
});
},
computed: {
parentNomainName() {
return window.location.hostname;
},
dynamicCSSUrl() {
const { protocol, hostname, port } = window.location;
return `${protocol}//${hostname}:${port}/fmg/css/site-2020Styling.css`;
},
dynamicHopCSSUrl() {
const { protocol, hostname, port } = window.location;
return `${protocol}//${hostname}:${port}/fmg/css/hop-styling.css`;
},
getHeaderLine1() {
if (!this.isPaypal) {
return this.getCmsContent("PIAHeaderLine1", "Text");
}
return "";
},
getHeaderLine2() {
if (!this.isPaypal) {
return this.getCmsContent("PIAHeaderLine2", "Text");
}
return "";
},
damageInfo() {
return this.$store.getters.damage;
},
isInsurance() {
return this.$store.getters.payment.isInsurance;
},
isNoComp() {
return this.$store.getters.policy.isNoComp;
},
isItac() {
return this.$store.getters.policy.isItac;
},
hasVapsInCart() {
if (this.lineItems?.vaps?.length > 0) {
return true;
}
return false;
},
showInsuranceCoverageAs() {
if (!this.isInsurance) return null;
if (this.isNoComp || this.isItac) {
return coverageStatus.NOCOMP;
} else {
return this.$store.getters.payment.insuranceCoverage.coverageStatus;
}
},
currentDeductible() {
return this.$store.getters.policy.currentDeductible;
},
insuranceCompanyName() {
return this.$store.getters.policy.insuranceCompanyName;
},
isPaypal() {
if (this.paymentType == "pp") {
return true;
}
return false;
},
shouldDisplayPiaCCAlert() {
return this.shouldDisplayPiaAlert(paymentMethods.CREDIT_CARD);
},
shouldDisplayPiaAPAlert() {
return this.shouldDisplayPiaAlert(paymentMethods.AFTERPAY);
},
},
methods: {
arePagePrerequisitesValid() {
// Service Location
const serviceLocation = store.getters.order.serviceLocation;
const mobileReqs = !!(
serviceLocation.address &&
serviceLocation.city &&
serviceLocation.state &&
serviceLocation.zipCode
);
const providerLocation = serviceLocation.provider.address;
const dropOffInshopReqs = !!(
providerLocation.streetAddress &&
providerLocation.city &&
providerLocation.state &&
providerLocation.zipCode
);
const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE;
const serviceLocationReqs =
(isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs);
// Insurance
const isInsuranceSet = store.getters.order.payment.isInsurance !== null;
// Schedule
const schedule = store.getters.order.schedule;
const scheduleReqs = !!(
schedule.date &&
schedule.startTime &&
schedule.endTime &&
schedule.jobMaxMinutes &&
schedule.jobMinMinutes
);
// Customer
const customer = store.getters.order.customer;
const customerReqs = !!(
customer.firstName &&
customer.lastName &&
customer.phoneNumber &&
customer.emailAddress
);
const paymentMethodReqs =
store.getters.order.payment.isPia !== null &&
(store.getters.order.payment.isPia || !!store.getters.order.payment.piaType);
const preReqResult =
serviceLocationReqs &&
isInsuranceSet &&
scheduleReqs &&
customerReqs &&
paymentMethodReqs;
// prettier-ignore
{
if (store.getters.applicationUser.loggingOption || !preReqResult) {
console.log("------------- payment.vue pagePrereqs start -----------------");
console.log(new Date() + "mobileReqs:" + mobileReqs);
console.log(new Date() + "serviceLocation.address:" + serviceLocation.address);
console.log(new Date() + "serviceLocation.city:" + serviceLocation.city);
console.log(new Date() + "serviceLocation.state:" + serviceLocation.state);
console.log(new Date() + "serviceLocation.zipCode:" + serviceLocation.zipCode);
console.log("");
console.log(new Date() + "dropOffInshopReqs:" + dropOffInshopReqs);
console.log(new Date() + "serviceLocationReqs:" + serviceLocationReqs);
console.log(new Date() + "providerLocation.streetAddress:" + providerLocation.streetAddress);
console.log(new Date() + "providerLocation.city:" + providerLocation.city);
console.log(new Date() + "providerLocation.state:" + providerLocation.state);
console.log(new Date() + "providerLocation.zipCode:" + providerLocation.zipCode);
console.log("");
console.log(new Date() + "isInsuranceSet:" + isInsuranceSet);
console.log("");
console.log(new Date() + "scheduleReqs:" + scheduleReqs);
console.log(new Date() + "schedule.date:" + schedule.date);
console.log(new Date() + "schedule.startTime:" + schedule.startTime);
console.log(new Date() + "schedule.endTime:" + schedule.endTime);
console.log(new Date() + "schedule.jobMaxMinutes:" + schedule.jobMaxMinutes);
console.log(new Date() + "schedule.jobMinMinutes:" + schedule.jobMinMinutes);
console.log("");
console.log(new Date() + "customerReqs:" + customerReqs);
console.log(new Date() + "customer.firstName:" + customer.firstName);
console.log(new Date() + "customer.lastName:" + customer.lastName);
console.log(new Date() + "customer.phoneNumber:" + customer.phoneNumber);
console.log(new Date() + "customer.emailAddress:" + customer.emailAddress);
console.log("");
console.log(new Date() + "paymentMethodReqs:" + paymentMethodReqs);
console.log(new Date() + "store.getters.order.payment.isPia:" + store.getters.order.payment.isPia);
console.log(new Date() + "store.getters.order.payment.piaType:" + store.getters.order.payment.piaType);
console.log("------------- payment.vue pagePrereqs end -------------------");
}
}
return preReqResult;
},
getWOrkOrderNumber() {
if (store.getters.order.workOrderNumber) {
const items = store.getters.order.workOrderNumber.split("-");
return items[1];
}
this.backButtonAction();
},
getInvoiceNumber() {
if (store.getters.order.workOrderNumber) {
return store.getters.order.workOrderNumber.replace("-", "");
}
this.backButtonAction();
},
getAddress1() {
return store.getters.order.serviceLocation.address
? store.getters.order.serviceLocation.address
: store.getters.order.serviceLocation.provider.address.streetAddress;
},
getAddress2() {
return store.getters.order.serviceLocation.address2
? store.getters.order.serviceLocation.address2
: null;
},
getCity() {
return store.getters.order.serviceLocation.city
? store.getters.order.serviceLocation.city
: store.getters.order.serviceLocation.provider.address.city;
},
getState() {
return store.getters.order.serviceLocation.state
? store.getters.order.serviceLocation.state
: store.getters.order.serviceLocation.provider.address.state;
},
getZipCode() {
return store.getters.order.serviceLocation.zipCode
? store.getters.order.serviceLocation.zipCode
: store.getters.order.serviceLocation.provider.address.zipCode;
},
getPaymentType() {
switch (store.getters.order.payment.piaType) {
case paymentMethods.AFTERPAY:
return "ap";
case paymentMethods.CREDIT_CARD:
return "cc";
case paymentMethods.PAYPAL:
return "pp";
default:
return store.getters.payment.piaType;
}
},
getPiaLineItems(cartItems) {
const glassParts = store.getters.order.lineItems.glassParts;
let lineItems = [];
if (glassParts === null) {
lineItems = ["Labor|0|1", "Repair supplies|0|1"];
} else {
lineItems = ["Parts and labor|0|1"];
}
cartItems.forEach((item) => {
if (item.name !== null && item.category != "promos") {
const total = (item.salesTax + item.subTotal).toFixed(2);
if (total > 0) {
lineItems.push(
`${item.name}|${(item.salesTax + item.subTotal).toFixed(2)}|1`
);
}
}
});
this.piaLineItems = lineItems.join("||");
},
getAmountDue() {
return getAmountDue(store.getters.order.lineItems);
},
getDisplayAmountDue() {
return getDisplayAmountDue(store.getters.order.lineItems);
},
async paymentFailedPayLater() {
this.$refs.loadingModal.isModalVisible = true;
await this.dispatchStoreAction(
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
paymentMethods.LATER,
false
);
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
try {
await submitWorkOrder({
pageNameToLog: "payment",
submitAfterSave: true,
});
await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_STATE);
window.location = applicationConfig.CONFIRMATION_URL;
} catch (error) {
console.log("error: response from submit work order(payment pg):" + error.message);
this.$router.navigateWithoutSaving(
this.navigationScenarios.PIA_ERROR,
this.$route,
{},
{ [routerParams.DISPLAY_PIA_ALERT]: true }
);
this.$refs.loadingModal.isModalVisible = false;
return;
}
},
backButtonAction() {
// The only way I could figure out how to get navigation to work on a page with the iframe.
// This is also how a cancel from Paypal would work. Just a redirect to the payment-method page.
// The normal navigation sort of works but the page does not render. The "next" callback function does not get
// invoked in payment-method's beforeroute enter. I also spotted an error in vue-router.esm-bundler.js when this
// happens but was unable to ignore it with a try catch. The navigation guard error is:
// Error: Redirected from "/?fmgPage=payment-method" to "{ params: {isSavingNation: "false"}, query: "fmgPage: "payment-method"}"
// I don't know if the navigation guard thinks the to and from are the same page.
// Also tried overriding with a $router.push
window.location = applicationConfig.PIA_CANCEL_URL;
//this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
},
submitHopForm() {
this.$nextTick(() => {
this.$refs.hopForm.submit();
const iframe = this.$refs.paymentFrame;
if (iframe) {
iframe.onload = () => {
if (iframe.contentWindow) {
if (baseMixin.methods.showApplePay()) {
iframe.contentWindow.postMessage("hybrid-with-applepay", "*");
console.log(new Date() + ": Sent applepay: new hop with applepay");
} else {
iframe.contentWindow.postMessage("hybrid", "*");
console.log(new Date() + ": Sent hybrid: new hop no applepay");
}
if (this.paymentType == "cc" || this.paymentType == "PayNow") {
iframe.contentWindow.postMessage("CreditCardChosen", "*");
console.log(new Date() + ": Sent creditcard");
} else if (this.paymentType == "ap") {
iframe.contentWindow.postMessage("afterpay", "*");
console.log(new Date() + ": Sent afterpay");
}
}
};
}
});
},
async fetchSignatureInfo(signatureInfo) {
if (this.isPaypal) {
this.$refs.loadingModal.showModal();
}
this.authToken = signatureInfo.token;
this.authSignature = signatureInfo.signature;
this.authSignatureStart = signatureInfo.startDate;
this.submitHopForm();
},
handleIFrameContentWindowMessage(event) {
if (typeof event.data === "string") {
if (event.data.indexOf("afterpayClosed") > -1) {
this.backButtonAction();
}
if (event.data.indexOf("creditCardSubmit") > -1) {
console.log(new Date() + ": Payment method credit card selected");
this.updatePaymentMethod(paymentMethods.CREDIT_CARD);
this.setUIBlock(true);
}
if (event.data.indexOf("afterpayPaymentReceived") > -1) {
console.log(new Date() + ": Payment method afterpay selected");
this.updatePaymentMethod(paymentMethods.AFTERPAY);
}
if (event.data.indexOf("applepayOpened") > -1) {
console.log(new Date() + ": Payment method applepay selected");
this.updatePaymentMethod(paymentMethods.APPLE_PAY);
}
if (event.data.indexOf("showLoaderForPaypal") > -1) {
console.log(new Date() + ": Payment method paypal selected");
this.updatePaymentMethod(paymentMethods.PAYPAL);
}
}
},
updatePaymentMethod(paymentMethod) {
// if the payment method is not set yet, then set it based on what HOP sends us
if (
store.getters.order.payment.piaType == paymentMethods.PAY_NOW ||
store.getters.order.payment.piaType == paymentMethods.NONE
) {
console.log(new Date() + " UPDATE PaymentMethod from HOP:" + paymentMethod);
this.dispatchStoreAction(
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
paymentMethod,
false
);
}
},
setIFrameListener() {
window.addEventListener("message", (event) =>
this.handleIFrameContentWindowMessage(event)
);
},
setUIBlock(val) {
this.shouldBlockInteraction = val;
},
supressClick(event) {
if (this.shouldBlockInteraction) {
event.stopPropagation();
}
},
shouldDisplayPiaAlert(payMethod) {
return (
this.$route.query[queryStrings.DISPLAY_PIA_ALERT] === payMethod ||
getBoolFromString(window.history.state.displayPiaAlert)
);
},
},
components: {
funnelHeader,
navbar,
loadingModal,
cart,
alert,
},
};
</script>
<style lang="scss">
.hop-iframe {
position: relative;
min-height: 650px;
width: 100%;
border: 0 none;
}
#pageLoadingModal {
background-color: red;
}
.ui-block {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 9999;
}
</style>