317 lines
12 KiB
Vue
317 lines
12 KiB
Vue
<template>
|
|
<Form
|
|
ref="theForm"
|
|
v-slot="{ meta }"
|
|
@submit="onSubmit"
|
|
@invalidSubmit="onInvalidSubmit">
|
|
<div class="fade-on-route-transition">
|
|
<div class="justify-content-center">
|
|
<siteHeader
|
|
ref="siteHeader"
|
|
cmsWidgetName="SiteHeaderWidget" />
|
|
</div>
|
|
<div class="iss-heritage-container-width">
|
|
<div class="payment-method-container iss-heritage-content-container-width">
|
|
<siteSubHeader
|
|
class="mb-5 mt-4 px-3"
|
|
cmsWidgetName="SiteSubHeaderWidget"
|
|
secondaryTextClasses="text-center"
|
|
subHeaderClasses="mt-4" />
|
|
<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="paymentMethod"
|
|
:cmsWidgetName="paymentMethodWidgetName"
|
|
: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 { saveSession, submitWorkOrder } from '@/helpers/order-helper.js';
|
|
import { experimentSettings } from '@/constants/experiments';
|
|
import submitType from '@/constants/submit-type';
|
|
import routerParams from '@/router/router-constants/router-params';
|
|
import { supportsApplePay } from '@/helpers/browser-helper';
|
|
|
|
export default {
|
|
name: 'payment-method',
|
|
components: {
|
|
// eslint-disable-next-line vue/no-reserved-component-names
|
|
Form,
|
|
siteHeader,
|
|
siteSubHeader,
|
|
siteFooter,
|
|
reviewDropdown,
|
|
cartDropdown,
|
|
paymentMethodQuestion,
|
|
alert
|
|
},
|
|
mixins: [baseFormMixin],
|
|
async beforeRouteEnter(to, from, next) {
|
|
// Call APIs
|
|
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
|
|
|
const promiseResultMap = [
|
|
{
|
|
resultKey: 'cmsContent',
|
|
promise: cmsContentPromise
|
|
}
|
|
];
|
|
|
|
const resultMap = await settleAllPromises(promiseResultMap);
|
|
|
|
await useMainStore().setPriceAndSalesTaxForOrderLineItems();
|
|
|
|
next((vm) => {
|
|
vm.setCmsContent(resultMap.cmsContent);
|
|
vm.initializeComponent();
|
|
vm.updateFooterButtonText(vm.customCallToActionButtonCopy);
|
|
});
|
|
},
|
|
data() {
|
|
return {
|
|
paymentMethod: null,
|
|
widget: {
|
|
paymentMethod: 'PaymentMethodWidget',
|
|
paymentMethodApplePay: 'PaymentMethodWidgetApplePay'
|
|
},
|
|
rules: {
|
|
optionRequired: globalRules.OPTION_REQUIRED
|
|
}
|
|
};
|
|
},
|
|
computed: {
|
|
customCallToActionButtonCopy() {
|
|
switch (this.paymentMethod) {
|
|
case paymentMethods.PayNow:
|
|
return 'Continue to checkout';
|
|
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';
|
|
const isDeductibleTotalEqualToZero = useMainStore().order.currentDeductible === 0;
|
|
|
|
return !isEnabled || useMainStore().isUnverified || (useMainStore().isDeductible && isDeductibleTotalEqualToZero);
|
|
},
|
|
paymentMethodWidgetName() {
|
|
return supportsApplePay() ? this.widget.paymentMethodApplePay : this.widget.paymentMethod;
|
|
}
|
|
},
|
|
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);
|
|
},
|
|
initializeComponent() {
|
|
this.paymentMethod = this.getPaymentMethodFromStore();
|
|
},
|
|
getPaymentMethodFromStore() {
|
|
if (this.isPayInAdvanceDisabled) {
|
|
return paymentMethods.PAY_AT_TIME_OF_SERVICE;
|
|
}
|
|
|
|
return useMainStore().order.payment.paymentMethod;
|
|
},
|
|
updateFooterButtonText(newValue) {
|
|
this.$refs.siteFooter.updateButtonText(newValue);
|
|
},
|
|
async forwardButtonAction() {
|
|
useMainStore().savePaymentMethodChoice(this.paymentMethod);
|
|
if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
|
|
try {
|
|
await submitWorkOrder({ submitType: submitType.SAFELITE });
|
|
this.$router.navigate(
|
|
this.navigationScenarios.CLICKED_FORWARD,
|
|
this.$route
|
|
);
|
|
} catch (error) {
|
|
useMainStore().setBailout(bailoutMessage.saveSessionError(error.data));
|
|
this.$router.navigate(
|
|
this.navigationScenarios.SAVE_SESSION_FAILED,
|
|
this.$route,
|
|
{ issPage: issPageValues.PAYMENT_METHOD }
|
|
);
|
|
console.error(`error: response from submit work order:${error.message}`);
|
|
}
|
|
} else {
|
|
await saveSession({
|
|
createWorkOrderNumberForPIA: true,
|
|
shouldAwaitSaveSessionQueue: true
|
|
});
|
|
|
|
this.$router.navigate(
|
|
this.navigationScenarios.CLICKED_PAY_NOW,
|
|
this.$route,
|
|
{},
|
|
{ [routerParams.SKIP_SAVE_SESSION]: true }
|
|
);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
$page-side-padding: 1.5rem;
|
|
.iss-heritage-container-width {
|
|
.payment-method-container {
|
|
position: relative;
|
|
min-height: 1px;
|
|
padding-left: .9375rem;
|
|
padding-right: .9375rem;
|
|
}
|
|
}
|
|
|
|
.main-content-container {
|
|
padding: 0;
|
|
}
|
|
|
|
.page-container-grouped-styles {
|
|
overflow: auto;
|
|
}
|
|
</style>
|