409 lines
15 KiB
Vue
409 lines
15 KiB
Vue
<template>
|
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
|
<loadingModal notFullScreen ref="loadingModal" />
|
|
<div class="container-fluid page-container-grouped-styles">
|
|
<div class="row">
|
|
<div class="col">
|
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
|
</div>
|
|
</div>
|
|
<div class="row justify-content-center">
|
|
<div class="col-md-6 col-xl-4">
|
|
<vehicleBanner
|
|
cmsWidgetName="VehicleBannerWidget"
|
|
:displayGenericVehicleImage="false" />
|
|
|
|
<funnelSubHeader
|
|
class="mb-5 mt-4"
|
|
cmsWidgetName="FunnelSubHeaderWidget"
|
|
leftAlignHeader />
|
|
|
|
<p v-if="isPiaDisabled" class="fw-normal no-pia-disclaimer">
|
|
<span>{{ noPiaDisclaimer }}</span>
|
|
</p>
|
|
|
|
<hr />
|
|
|
|
<cart
|
|
:damage="damageInfo"
|
|
:availableLineItems="availableLineItems"
|
|
:lineItems="lineItems"
|
|
servicePackageOptionsCmsName="ServicePackageTitle"
|
|
@cart-remove="cartRemove" />
|
|
|
|
<div>
|
|
<alert
|
|
ref="piaErrorAlert"
|
|
class="my-4"
|
|
v-if="displayPiaAlert"
|
|
cmsWidgetName="PIAErrorAlertWidget"
|
|
alertClass="alert-danger"
|
|
v-bind:isDismissible="false" />
|
|
</div>
|
|
|
|
<add-vaps-modal-buttons
|
|
:cartItems="cartItems"
|
|
:availableLineItems="availableLineItems"
|
|
vapsTilesCmsName="VapsProductTiles"
|
|
v-on="{ 'buttonEvent.openModal': openModal }" />
|
|
|
|
<contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" />
|
|
<paymentMethodQuestion
|
|
v-if="!isPiaDisabled"
|
|
v-model="paymentMethodInternalModel"
|
|
validationRules="option-required" />
|
|
|
|
<navbar
|
|
cmsWidgetName="FunnelFooterWidget"
|
|
ref="navbar"
|
|
:isForwardActionDisabled="!meta.valid"
|
|
:isBackButtonHidden="shouldHideBackButton"
|
|
@back-clicked="backButtonAction"
|
|
@ForwardClicked="forwardButtonAction" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Form>
|
|
</template>
|
|
|
|
<script>
|
|
// Components
|
|
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
|
import navbar from "@/fmg-components/nav-bar/nav-bar";
|
|
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
|
import paymentMethodQuestion from "@/layouts/payment-method/payment-method-question/payment-method-question";
|
|
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
|
import cart from "@/fmg-components/cart/cart";
|
|
import addVapsModalButtons from "@/fmg-components/add-vaps-modal-buttons/add-vaps-modal-buttons";
|
|
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
|
|
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
|
import alert from "@/ux-components/alert/alert";
|
|
|
|
import baseMixin from "@/mixins/base-mixin.js";
|
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
|
import { storeActions } from "@/constants/store-actions";
|
|
import store from "@/store";
|
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
|
import { paymentMethods } from "@/constants/payment-method-constants";
|
|
import { experimentSettings } from "@/constants/experiments";
|
|
|
|
import { Form } from "vee-validate";
|
|
import { defineRule } from "vee-validate";
|
|
import { required } from "@/helpers/validation-rules";
|
|
import { errorMessages } from "@/constants/error-messages";
|
|
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
|
|
|
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
|
|
|
export default {
|
|
name: "paymentMethod",
|
|
async beforeRouteEnter(to, from, next) {
|
|
// Call APIs
|
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
|
const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.GET_WIPERS,
|
|
null,
|
|
"payment-method"
|
|
);
|
|
|
|
const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.GET_RAIN_DEFENSE,
|
|
null,
|
|
"payment-method"
|
|
);
|
|
|
|
const supportingItemsPromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.GET_SUPPORTING_ITEMS,
|
|
null,
|
|
"payment-method"
|
|
);
|
|
|
|
const promiseResultMap = [
|
|
{
|
|
resultKey: "cmsContent",
|
|
promise: cmsContentPromise,
|
|
},
|
|
{
|
|
resultKey: "wipers",
|
|
promise: wipersPromise,
|
|
},
|
|
{
|
|
resultKey: "rainDefense",
|
|
promise: rainDefensePromise,
|
|
},
|
|
{
|
|
resultKey: "supportingItems",
|
|
promise: supportingItemsPromise,
|
|
},
|
|
];
|
|
|
|
const resultMap = await settleAllPromises(promiseResultMap);
|
|
|
|
const glassParts = store.getters.order.lineItems.glassParts ?? [];
|
|
|
|
const availableLineItems = [
|
|
resultMap.rainDefense,
|
|
...resultMap.supportingItems,
|
|
...resultMap.wipers,
|
|
...glassParts,
|
|
];
|
|
|
|
const pricedAvailableLineItems = await baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
|
|
{
|
|
availableLineItems: availableLineItems,
|
|
},
|
|
"payment-method",
|
|
false
|
|
);
|
|
|
|
const lineItems = store.getters.order.lineItems;
|
|
|
|
const combinedLineItems = [...glassParts, ...lineItems.supportingItems, ...lineItems.vaps];
|
|
|
|
const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
|
|
{
|
|
billToAccountNumber: "87291",
|
|
providerNumber: store.getters.order.serviceLocation.provider.providerNumber,
|
|
appointmentType: store.getters.order.serviceLocation.appointmentType,
|
|
serviceLocationState: store.getters.order.serviceLocation.state,
|
|
serviceLocationZipCode: store.getters.order.serviceLocation.zipCode,
|
|
pricedLineItems: combinedLineItems,
|
|
},
|
|
"payment-method",
|
|
false
|
|
);
|
|
|
|
const cartItems = [...glassParts, ...lineItems.supportingItems, ...lineItems.vaps]; // TOBEREMOVED BY AJC IN CSR-1384
|
|
|
|
// Call the "next" function to complete the transition to this page.
|
|
next((vm) => {
|
|
vm.cartItems = cartItems; // TOBEREMOVED BY AJC IN CSR-1384
|
|
|
|
vm.setCmsContent(resultMap.cmsContent);
|
|
vm.availableLineItems = pricedAvailableLineItems;
|
|
vm.lineItems = taxedLineItems;
|
|
});
|
|
},
|
|
data() {
|
|
return {
|
|
cartItems: [], // TOBEREMOVED BY AJC IN CSR-1384
|
|
|
|
lineItems: [],
|
|
availableLineItems: [],
|
|
paymentMethodInternalModel: this.getPaymentMethodFromStore(),
|
|
displayPiaAlert: this.getPiaAlert(),
|
|
};
|
|
},
|
|
methods: {
|
|
arePagePrerequisitesValid() {
|
|
// Line Items
|
|
const packageReqs = !!store.getters.order.lineItems.supportingItems;
|
|
|
|
// 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 &&
|
|
(!isMobile || schedule.endTime) &&
|
|
schedule.jobMaxMinutes &&
|
|
schedule.jobMinMinutes
|
|
);
|
|
|
|
// Customer
|
|
const customer = store.getters.order.customer;
|
|
const customerReqs = !!(
|
|
customer.firstName &&
|
|
customer.lastName &&
|
|
customer.phoneNumber &&
|
|
customer.emailAddress
|
|
);
|
|
|
|
return (
|
|
packageReqs && serviceLocationReqs && isInsuranceSet && scheduleReqs && customerReqs
|
|
);
|
|
},
|
|
openModal(modalName) {
|
|
this.$refs[modalName].openModal();
|
|
},
|
|
getPiaAlert() {
|
|
return store.getters.order.payment.piaErrorCode ? true : false;
|
|
},
|
|
getPaymentMethodFromStore() {
|
|
const isPia = store.getters.order.payment.isPia;
|
|
|
|
if (isPia === null || isPia === undefined) {
|
|
return null;
|
|
}
|
|
|
|
if (isPia) {
|
|
return store.getters.order.payment.piaType;
|
|
} else {
|
|
return paymentMethods.LATER;
|
|
}
|
|
},
|
|
vapsItemsSelectedAction(vapsItemsSelected) {
|
|
this.cartItems = vapsItemsSelected;
|
|
},
|
|
// TODO (as part of CSR-1384) enable adding to the cart
|
|
// vapsItemsSelectedAction(vapsItemsSelected) {
|
|
// this.cartItems = vapsItemsSelected;
|
|
// },
|
|
cartRemove(item) {
|
|
const matchedIndices = [];
|
|
this.cartItems.forEach((cartItem, i) => {
|
|
if (cartItem.partType === item.partType) {
|
|
// console.log("adding this to matchedIndices: ", i);
|
|
matchedIndices.push(i);
|
|
}
|
|
});
|
|
this.cartItems = this.cartItems.filter((cartItem, index) => {
|
|
return cartItem.partType !== item.partType;
|
|
});
|
|
},
|
|
backButtonAction() {
|
|
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
|
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
|
},
|
|
async forwardButtonAction() {
|
|
switch (this.paymentMethod) {
|
|
case paymentMethods.CREDIT_CARD:
|
|
this.piaSetup("cc");
|
|
break;
|
|
case paymentMethods.PAYPAL:
|
|
this.piaSetup("pp");
|
|
break;
|
|
case paymentMethods.AFTERPAY:
|
|
this.piaSetup("ap");
|
|
break;
|
|
default:
|
|
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
|
this.dispatchStoreAction(this.storeActions.SAVE_WORK_ORDER_FLAG, true, false);
|
|
this.dispatchStoreAction(
|
|
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
|
this.paymentMethod,
|
|
false
|
|
);
|
|
await submitWorkOrder({ pageNameToLog: "payment-method" });
|
|
this.$router.navigateWithoutSaving(
|
|
this.navigationScenarios.CLICKED_FORWARD,
|
|
this.$route
|
|
);
|
|
}
|
|
},
|
|
|
|
async piaSetup(payNowType) {
|
|
this.$refs.loadingModal.showModal();
|
|
|
|
// since we're leaving the site for pia, clear any save session promises that we will not be able to resolve when we return
|
|
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
|
await this.dispatchStoreAction(
|
|
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
|
payNowType,
|
|
false
|
|
);
|
|
|
|
// make sure pia error codes are reset
|
|
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
|
|
|
// if we don't have a work order in delete substatus, set the flag and submit
|
|
if (!store.getters.order.workOrderNumber) {
|
|
this.dispatchStoreAction(storeActions.SAVE_PIA_WORK_ORDER, true);
|
|
await submitWorkOrder({ pageNameToLog: "payment-method" });
|
|
this.dispatchStoreAction(storeActions.SAVE_PIA_WORK_ORDER, false);
|
|
}
|
|
|
|
this.$router.navigateWithoutSaving(
|
|
this.navigationScenarios.CLICKED_PAY_NOW,
|
|
this.$route
|
|
);
|
|
},
|
|
},
|
|
computed: {
|
|
damageInfo() {
|
|
return this.$store.getters.damage;
|
|
},
|
|
noPiaDisclaimer() {
|
|
return this.getCmsContent("NoPiaDisclaimerWidget", "Text");
|
|
},
|
|
customCtaCopy() {
|
|
switch (this.paymentMethod) {
|
|
case paymentMethods.CREDIT_CARD:
|
|
return "Continue to checkout";
|
|
case paymentMethods.PAYPAL:
|
|
return "Continue to Paypal";
|
|
case paymentMethods.AFTERPAY:
|
|
return "Continue to Afterpay";
|
|
default:
|
|
return null;
|
|
}
|
|
},
|
|
isPiaDisabled() {
|
|
const piaExperience =
|
|
this.getSettingValue(experimentSettings.PIA_EXPERIENCE) === "PIA Optional";
|
|
const enablePIA =
|
|
this.getSettingValue(experimentSettings.SUBMIT_ORDER_ENABLE_PIA) === "true";
|
|
|
|
return false;
|
|
//return !(piaExperience && enablePIA);
|
|
},
|
|
paymentMethod() {
|
|
if (this.isPiaDisabled) {
|
|
return paymentMethods.LATER;
|
|
}
|
|
|
|
return this.paymentMethodInternalModel;
|
|
},
|
|
},
|
|
watch: {
|
|
customCtaCopy(newValue) {
|
|
this.$refs.navbar.updateButtonText(newValue);
|
|
},
|
|
},
|
|
components: {
|
|
funnelHeader,
|
|
navbar,
|
|
funnelSubHeader,
|
|
Form,
|
|
loadingModal,
|
|
cart,
|
|
alert,
|
|
addVapsModalButtons,
|
|
contentGroupModal,
|
|
paymentMethodQuestion,
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.no-pia-disclaimer {
|
|
color: $gray-550;
|
|
margin: 0;
|
|
}
|
|
</style>
|