DigitalConsumer.FixMyGlass/src/layouts/payment-method/payment-method.vue
2023-10-19 17:07:03 -04:00

411 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="taxedLineItems"
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 = [];
combinedLineItems.push(lineItems.glassParts ?? []);
combinedLineItems.push(lineItems.supportingItems ?? []);
combinedLineItems.push(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
);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.cartItems = combinedLineItems; // TOBEREMOVED BY AJC IN CSR-1384
vm.setCmsContent(resultMap.cmsContent);
vm.availableLineItems = pricedAvailableLineItems;
vm.taxedLineItems = taxedLineItems;
vm.lineItems = lineItems;
});
},
data() {
return {
cartItems: [], // TOBEREMOVED BY AJC IN CSR-1384
lineItems: [],
taxedLineItems: [], // temporary, for use by cart.vue
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() {
await this.dispatchStoreAction(
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
this.paymentMethod,
false
);
await this.dispatchStoreAction(storeActions.SAVE_VAPS, this.lineItems.vaps, false);
await this.dispatchStoreAction(storeActions.SAVE_PROMOS, this.lineItems.promos, false);
switch (this.paymentMethod) {
case paymentMethods.CREDIT_CARD:
this.piaSetup(this.paymentMethod);
break;
case paymentMethods.PAYPAL:
this.piaSetup(this.paymentMethod);
break;
case paymentMethods.AFTERPAY:
this.piaSetup(this.paymentMethod);
break;
default:
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
this.dispatchStoreAction(this.storeActions.SAVE_WORK_ORDER_FLAG, true, 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);
// 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>