DigitalConsumer.ISS/src/layouts/payment-method/payment-method.vue
2024-05-07 16:28:31 -04:00

343 lines
13 KiB
Vue

<template>
<Form
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader
class="mb-5 mt-4 px-3"
cmsWidgetName="SiteSubHeaderWidget"
subHeaderClasses="mt-2" />
<div class="main-content-container">
<hr class="my-0" />
<reviewDropdown ref="reviewDropdown" />
<hr class="my-0" />
<cartDropdown
:showAsPaid="false"
:readOnly="false"
:showDropdownHeader="true"
:isInitiallyExpanded="false"
recyclingModalCmsWidgetName="RecycleModal"
servicePackageTitleWidgetName="ServicePackageTitle" />
<hr class="mt-0 mb-5" />
<alert
v-if="displayPayInAdvanceAlert"
name="payInAdvanceErrorAlert"
class="my-4"
cmsWidgetName="PayInAdvanceErrorAlertWidget"
alertClass="alert-danger"
:isDismissible="false" />
<paymentMethodQuestion
v-if="!isPayInAdvanceDisabled"
v-model="paymentMethodInternalModel"
cmsWidgetName="PaymentMethodWidget"
:validationRules="rules.optionRequired" />
<alert
v-if="isPayInAdvanceDisabled"
:isDismissible="false"
alertClass="alert-info"
cmsWidgetName="NoPayInAdvanceDisclaimerWidget"
:shouldScrollToOnMount="false" />
<siteFooter
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
:isStackedVertically="true"
@backClicked="navigateBack"
@ForwardClicked="forwardButtonAction" />
</div>
</div>
</div>
</div>
</Form>
</template>
<script>
// Components
import baseFormMixin from '@/mixins/base-form-mixin';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import reviewDropdown from '@/layouts/payment-method/review-dropdown/review-dropdown.vue';
import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
import paymentMethodQuestion from '@/layouts/payment-method/payment-method-question/payment-method-question.vue';
import alert from '@/ux-components/alert/alert.vue';
// Supporting Items
import settleAllPromises from '@/helpers/layout-helper';
import { useMainStore } from '@/store';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { paymentMethods } from '@/constants/payment-method-constants';
import queryStrings from '@/constants/query-strings';
import globalRules from '@/constants/global-rules';
import { Form } from 'vee-validate';
import issPageValues from '@/router/router-constants/issPage-values';
import bailoutMessage from '@/constants/bailoutMessage';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import VehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import { submitWorkOrder } from '@/helpers/order-helper.js';
import { experimentSettings } from '@/constants/experiments';
export default {
name: 'payment-method',
components: {
// eslint-disable-next-line vue/no-reserved-component-names
Form,
siteHeader,
siteSubHeader,
siteFooter,
reviewDropdown,
cartDropdown,
paymentMethodQuestion,
alert,
VehicleBanner
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const reviewDropdownPromise = reviewDropdown.methods.loadInitialData();
const wipersPromise = useMainStore().getWipers();
const rainDefensePromise = useMainStore().getRainDefense();
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
},
{
resultKey: 'reviewDropdownData',
promise: reviewDropdownPromise
},
{
resultKey: 'wipers',
promise: wipersPromise
},
{
resultKey: 'rainDefense',
promise: rainDefensePromise
}
];
const resultMap = await settleAllPromises(promiseResultMap);
await useMainStore().setPriceAndSalesTaxForOrderLineItems();
const unpricedVaps = [...resultMap.wipers, resultMap.rainDefense];
let hasBailedOut = false;
const pricedVaps = await useMainStore()
.getPriceOrderItems(unpricedVaps)
.catch((err) => {
useMainStore().setBailout(bailoutMessage.pricingResponseError(
unpricedVaps.map((li) => li.partNumber),
{ code: err.code, message: err.message, data: err.data }
));
hasBailedOut = true;
next(`/?issPage=${issPageValues.BAILOUT_PAGE}`);
});
if (!hasBailedOut) {
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.updateFooterButtonText(vm.customCallToActionButtonCopy);
vm.$refs.reviewDropdown.initializeComponent(resultMap.reviewDropdownData);
vm.storeAvailableVaps(pricedVaps ?? []);
});
}
},
data() {
return {
paymentMethodInternalModel: this.getPaymentMethodFromStore(),
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
};
},
computed: {
customCallToActionButtonCopy() {
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;
}
},
displayPayInAdvanceAlert() {
return this.$route.query[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT];
},
isPayInAdvanceDisabled() {
const piaExperience = this.getSettingValue(experimentSettings.ISS_DISPLAY_PAY_IN_ADVANCE);
const isEnabled = piaExperience === 'true';
return !isEnabled || useMainStore().isUnverified;
},
paymentMethod() {
return this.paymentMethodInternalModel;
}
},
watch: {
customCallToActionButtonCopy(newValue) {
this.updateFooterButtonText(newValue);
}
},
methods: {
arePagePrerequisitesValid() {
// Vehicle
const { vehicle } = useMainStore().order;
const vehicleReqs = !!(
vehicle.year
&& vehicle.make
&& vehicle.model
&& vehicle.style
);
// Damage
const { isRepair, numberOfChips, glassToReplace } =
useMainStore().order.damage;
const damageReqs = !!(
(isRepair && numberOfChips)
|| (!isRepair && glassToReplace?.length)
);
// Service Package
const { lineItems } = useMainStore().order;
const packageReqs = !!(
(isRepair || lineItems.glassParts)
&& lineItems.supportingItems
);
// Service Location
const { serviceLocation } = useMainStore().order;
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
|| serviceLocation.appointmentType
=== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP;
const serviceLocationReqs =
(isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs);
// Schedule
const { date, startTime, endTime, jobMaxMinutes, jobMinMinutes } =
useMainStore().order.schedule;
const scheduleReqs = !!(
date
&& startTime
&& endTime
&& jobMaxMinutes
&& jobMinMinutes
);
// Customer
const { firstName, lastName, emailAddress } =
useMainStore().order.customer;
const customerReqs = !!(firstName && lastName && emailAddress);
// Contact Info
const { contactInfo } = useMainStore().order;
const contactInfoReqs = !!(
contactInfo.firstName
&& contactInfo.lastName
&& contactInfo.servicePhone
&& contactInfo.emailAddress
);
return (
vehicleReqs
&& damageReqs
&& packageReqs
&& serviceLocationReqs
&& scheduleReqs
&& customerReqs
&& contactInfoReqs
);
},
getPaymentMethodFromStore() {
const { payInAdvanceType } = useMainStore().order.payment;
const isPayInAdvance =
useMainStore().order.payment.isPayInAdvance
&& !!payInAdvanceType;
return isPayInAdvance
? payInAdvanceType
: paymentMethods.PAY_AT_TIME_OF_SERVICE;
},
updateFooterButtonText(newValue) {
this.$refs.siteFooter.updateButtonText(newValue);
},
async forwardButtonAction() {
await useMainStore().savePaymentMethodChoice(this.paymentMethod);
if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
try {
await submitWorkOrder({
pageNameToLog: 'payment-method',
submitAfterSave: true
});
useMainStore().resetSubmittedOrder();
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
} catch (error) {
console.error(`error: response from submit work order:${error.message}`);
}
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_PAY_NOW,
this.$route
);
}
},
storeAvailableVaps(vaps) {
useMainStore().order.availableVaps = vaps;
}
}
};
</script>
<style lang="scss" scoped>
$page-side-padding: 1.5rem;
.main-content-container {
padding: 0;
}
.page-container-grouped-styles {
overflow: auto;
}
</style>