DigitalConsumer.ISS/src/layouts/service-packages/service-packages.vue
2026-02-10 11:55:30 -05:00

258 lines
8.7 KiB
Vue

<template>
<Form
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="fade-on-route-transition service-packages">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="iss-heritage-container-width">
<div class="service-packages-container">
<siteSubHeader
class="subheader mt-4"
justification="center"
cmsWidgetName="SiteSubHeaderWidget"
issContainingPage="service-packages" />
<servicePackageQuestion
ref="servicePackage"
cmsWidgetName="ServicePackage"
groupName="ServicePackageQuestion"
:availableLineItems="availableLineItems"
:validationRules="rules.optionRequired"
isRequired
@vapsItemsSelected="vapsItemsSelectedAction"
@link-event="openModalAction" />
<div class="d-flex justify-content-center mt-8 mb-4">
<buttonMain
ref="buttonMain"
class="continue-button"
variant="navigation"
:buttonText="'Continue'"
@clickEvent="forwardButtonAction" />
</div>
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
:isForwardButtonHidden="true"
@backClicked="navigateBack" />
</div>
<p
class="caption disclaimer"
v-html="PriceDisclaimerText"></p>
</div>
<loadingModal
ref="loadingModal"
:textSlides="loadingText" />
<contentGroupModal
ref="RainDefenseModal"
cmsWidgetName="RainDefenseModal" />
<contentGroupModal
ref="FrontWiperModal"
cmsWidgetName="FrontWiperModal" />
<contentGroupModal
ref="RearWiperModal"
cmsWidgetName="RearWiperModal" />
<contentGroupModal
ref="RecalModal"
cssModalHeadlineClass="text-center"
cmsWidgetName="RecalModal" />
</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 contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
import settleAllPromises from '@/helpers/layout-helper';
import { useMainStore } from '@/store';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { Form } from 'vee-validate';
import allGlassPartsAndItemsHavePrices from '@/layouts/service-packages/service-package-helper/service-package-helper';
import globalRules from '@/constants/global-rules';
import servicePackageQuestion from '@/layouts/service-packages/service-package-question/service-package-question.vue';
import issPageValues from '@/router/router-constants/issPage-values';
import bailoutMessage from '@/constants/bailoutMessage';
import buttonMain from '@/ux-components/button-main/button-main.vue';
const store = useMainStore();
export default {
name: 'service-packages',
components: {
siteHeader,
siteFooter,
siteSubHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
servicePackageQuestion,
loadingModal,
contentGroupModal,
buttonMain
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const wipersPromise = await store.getWipers();
const rainDefensePromise = await store.getRainDefense();
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
},
{
resultKey: 'wipers',
promise: wipersPromise
},
{
resultKey: 'rainDefense',
promise: rainDefensePromise
}
];
const resultMap = await settleAllPromises(promiseResultMap);
const { feeItems } = store.order.lineItems;
const availableLineItems = [];
if (resultMap?.rainDefense) {
availableLineItems.push(resultMap.rainDefense);
}
if (resultMap?.wipers?.length > 0) {
availableLineItems.push(...resultMap.wipers);
}
if (feeItems?.length > 0) {
availableLineItems.push(...feeItems);
}
let hasBailedOut = false;
const pricedItems = await store.getCombinedQuote(availableLineItems)
.catch((err) => {
useMainStore().setBailout(bailoutMessage.pricingResponseError(
availableLineItems.map((li) => li.partNumber),
{ code: err.code, message: err.message, data: err.data }
));
hasBailedOut = true;
next(`/?issPage=${issPageValues.BAILOUT_PAGE}`);
});
// Call the "next" function to complete the transition to this page.
if (!hasBailedOut) {
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.setData(pricedItems);
});
}
},
data() {
return {
selectedVaps: [],
availableLineItems: [],
loadingText: [
'Finding shops near you',
'Looking for dates',
'Searching for times',
'Nearly there',
'Finishing up'
],
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
};
},
computed: {
PriceDisclaimerText() {
return this.getCmsContent('PriceDisclaimerWidget', 'Text');
}
},
methods: {
openModalAction(modalName) {
this.$refs[modalName.args].openModal();
},
arePagePrerequisitesValid() {
return (
store.order.serviceLocation.zipCode
&& store.order.serviceLocation.zipCodeCtu
&& (store.order.damage.isRepair
|| (store.order.lineItems?.glassParts != null
&& store.order.lineItems.glassParts.length > 0))
);
},
setData(pricedVaps) {
this.availableLineItems = pricedVaps;
useMainStore().order.availableVaps = pricedVaps;
},
vapsItemsSelectedAction(vapsItemsSelected) {
this.selectedVaps = vapsItemsSelected;
},
forwardButtonAction() {
const parts = {
vaps: this.selectedVaps
};
if (!allGlassPartsAndItemsHavePrices(parts)) {
window.console.error('One or more items have no price assigned!');
}
store.updateVaps(this.selectedVaps);
const scenario = store.isMobileAppointment
? this.navigationScenarios.CLICKED_FORWARD_MOBILE
: this.navigationScenarios.CLICKED_FORWARD_INSHOP;
this.$router.navigate(
scenario,
this.$route
);
}
}
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.service-packages-container {
@media (min-width: 992px) {
width: 85%; // REVISIT
}
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
display: block;
margin: 0 auto;
:deep(.subheader-primary) {
display: block;
}
:deep(.subheader-secondary) {
display: block;
text-align: center;
margin-top: 0.75rem;
padding: 0px;
}
}
}
.disclaimer {
margin: 0.5rem 0 1.5rem 0;
padding-left: 3rem;
:deep(.external-text) {
text-decoration: none;
}
}
.service-packages {
:deep(strong) {
font-weight: 400;
}
}
.continue-button {
width: 60%
}
</style>