WIP update files with updated ESLint settings.

This commit is contained in:
Bryan Mauger 2024-04-15 09:22:44 -04:00
parent fa3c7711f6
commit 7e5c8fd1b6
17 changed files with 3204 additions and 3369 deletions

2
package-lock.json generated
View file

@ -37,7 +37,7 @@
"@vue/vue3-jest": "^27.0.0-alpha.1",
"axios-mock-adapter": "^1.21.5",
"babel-jest": "^27.0.6",
"eslint": "8.45.0",
"eslint": "^8.45.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-import-resolver-alias": "1.1.2",
"eslint-plugin-import": "2.26.0",

View file

@ -44,7 +44,7 @@
"@vue/vue3-jest": "^27.0.0-alpha.1",
"axios-mock-adapter": "^1.21.5",
"babel-jest": "^27.0.6",
"eslint": "8.45.0",
"eslint": "^8.45.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-import-resolver-alias": "1.1.2",
"eslint-plugin-import": "2.26.0",
@ -61,4 +61,4 @@
"vitest": "^0.33.0",
"volar-service-vetur": "latest"
}
}
}

View file

@ -3,19 +3,19 @@
<img :src="footerImageURL" />
</div>
</template>
<script>
export default {
name: "footer-image",
props: {
cmsWidgetName: String,
<script>
export default {
name: 'footer-image',
props: {
cmsWidgetName: String
},
computed: {
computed: {
footerImageURL() {
return this.getCmsContent(this.cmsWidgetName, 'FooterImageURL');
},
},
};
</script>
}
}
};
</script>
<style lang="scss" scoped>
.footerImage {

View file

@ -1,47 +1,50 @@
<template>
<div>
<footer
id="infoBox"
class="footer container-fluid g-5 my-5 px-0">
<div
class="row d-flex vw-100 mx-0"
:class="[
isStackedVertically
? 'flex-column align-items-stretch'
: 'flex-row-reverse align-items-center'
]">
<div
id="stacked"
class="col button-col d-flex px-0">
<buttonMain
v-if="!isForwardButtonHidden"
ref="buttonMain"
isPrimary
:buttonText="buttonText"
loaderColor="white"
:class="(disableForwardAction || isForwardActionDisabled) && 'form-test-invalid'"
:aria-disabled="isForwardActionDisabled"
:isDisabled="isForwardActionDisabled"
data-bs-target="#footerModal"
data-bs-dismiss="modal"
data-test-id="site-footer-main-button"
@clickEvent="buttonClick" />
</div>
<div
v-if="!isBackButtonHidden"
class="col-auto link-col py-1 px-0 text-break">
<textLink
linkType="navigation"
:text="backLink"
href="javascript:void(0)"
data-bs-target="#footerModal"
data-bs-dismiss="modal"
data-test-id="site-footer-back-button"
@clickEvent="linkClick" />
</div>
</div>
</footer>
</div>
<div>
<footer
id="infoBox"
class="footer container-fluid g-5 my-5 px-0">
<div
class="row d-flex vw-100 mx-0"
:class="[
isStackedVertically
? 'flex-column align-items-stretch'
: 'flex-row-reverse align-items-center',
]">
<div
id="stacked"
class="col button-col d-flex px-0">
<buttonMain
v-if="!isForwardButtonHidden"
ref="buttonMain"
isPrimary
:buttonText="buttonText"
loaderColor="white"
:class="
(disableForwardAction || isForwardActionDisabled) &&
'form-test-invalid'
"
:aria-disabled="isForwardActionDisabled"
:isDisabled="isForwardActionDisabled"
data-bs-target="#footerModal"
data-bs-dismiss="modal"
data-test-id="site-footer-main-button"
@clickEvent="buttonClick" />
</div>
<div
v-if="!isBackButtonHidden"
class="col-auto link-col py-1 px-0 text-break">
<textLink
linkType="navigation"
:text="backLink"
href="javascript:void(0)"
data-bs-target="#footerModal"
data-bs-dismiss="modal"
data-test-id="site-footer-back-button"
@clickEvent="linkClick" />
</div>
</div>
</footer>
</div>
</template>
<script>
@ -53,7 +56,7 @@ export default {
name: 'site-footer',
components: {
textLink,
buttonMain,
buttonMain
},
props: {
isForwardActionDisabled: Boolean,
@ -80,18 +83,20 @@ export default {
: this.getCmsContent(this.cmsWidgetName, 'ForwardButtonText');
},
footerImageURL() {
//return this.getCmsContent(this.cmsWidgetName, 'FooterImageURL');
// return this.getCmsContent(this.cmsWidgetName, 'FooterImageURL');
const output = this.getCmsContent(this.cmsWidgetName, 'FooterImageURL');
console.log("original image", output);
console.log('original image', output);
return output;
},
includeFooterImage() {
const currentPageName = this.getPageNameByQueryString();
return (currentPageName.toLowerCase() === issPageValues.WELCOME_PAGE);
return currentPageName.toLowerCase() === issPageValues.WELCOME_PAGE;
}
},
mounted() {
this.paddingHeight = this.includeFooterImage ? this.getFooterInfoBoxHeight() + 16 : this.getFooterInfoBoxHeight() + 24;
this.paddingHeight = this.includeFooterImage
? this.getFooterInfoBoxHeight() + 16
: this.getFooterInfoBoxHeight() + 24;
this.$nextTick(() => {
window.addEventListener('resize', this.onResize);
});
@ -133,63 +138,60 @@ export default {
<style lang="scss" scoped>
.footer {
display: flex;
overflow: visible;
a {
display: flex;
overflow: visible;
a {
display: flex;
justify-content: center;
}
justify-content: center;
}
.col,
.col-auto,
.col button {
width: 100%;
}
@media only screen and (min-width: 340px) {
.col,
.col-auto,
.col button {
width: 100%;
width: auto;
justify-content: flex-end;
}
@media only screen and (min-width: 340px) {
.col,
.col-auto,
.col button {
width: auto;
justify-content: flex-end;
}
.btn-primary {
width: auto;
}
a {
display: flex;
justify-content: flex-start;
}
.btn-primary {
width: auto;
}
a {
display: flex;
justify-content: flex-start;
}
}
& > .container-fluid {
overflow-x: visible; // needed to fix hidden footer on some iphones
& > .container-fluid {
overflow-x: visible; // needed to fix hidden footer on some iphones
}
div.flex-column {
.btn-primary {
width: 100%;
justify-content: center;
}
div.flex-column {
.btn-primary {
width: 100%;
justify-content: center;
}
div.link-col {
display: flex;
justify-content: center;
margin-top: 1.25rem;
}
div.link-col {
display: flex;
justify-content: center;
margin-top: 1.25rem;
}
}
}
.footerImage
{
text-align: center;
position: sticky;
.footerImage {
text-align: center;
position: sticky;
}
@media only screen and (max-width: 340px) {
.footerImage
{
bottom: 78px;
}
.footerImage {
bottom: 78px;
}
}
#siteFooterImage
{
width: 100%;
#siteFooterImage {
width: 100%;
}
</style>

View file

@ -3,12 +3,13 @@
ref="contact-details-form"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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="widget.siteHeader" />
<siteHeader
ref="siteHeader"
:cmsWidgetName="widget.siteHeader" />
</div>
</div>
<div class="row justify-content-center">
@ -17,8 +18,7 @@
id="sub-header"
ref="siteSubHeader"
class="mt-5"
:cmsWidgetName="widget.siteSubHeader"
/>
:cmsWidgetName="widget.siteSubHeader" />
<textboxQuestion
ref="firstNameQuestion"
v-model="firstName"
@ -26,8 +26,7 @@
inputId="firstName"
:cmsWidgetName="widget.firstNameQuestion"
isRequired
:validationRules="rules.firstName"
/>
:validationRules="rules.firstName" />
<textboxQuestion
ref="lastNameQuestion"
v-model="lastName"
@ -35,8 +34,7 @@
inputId="lastName"
:cmsWidgetName="widget.lastNameQuestion"
isRequired
:validationRules="rules.lastName"
/>
:validationRules="rules.lastName" />
<textboxQuestion
ref="emailQuestion"
v-model="emailAddress"
@ -44,8 +42,7 @@
inputId="emailAddress"
:cmsWidgetName="widget.emailQuestion"
isRequired
:validationRules="rules.emailAddress"
/>
:validationRules="rules.emailAddress" />
<textboxQuestion
ref="phoneNumberQuestion"
v-model="phoneNumber"
@ -54,8 +51,7 @@
:cmsWidgetName="widget.phoneNumberQuestion"
isRequired
:mask="phoneMask"
:validationRules="rules.phoneNumber"
/>
:validationRules="rules.phoneNumber" />
<checkbox
ref="requestTextUpdatesCheckbox"
v-model="requestTextUpdates"
@ -63,8 +59,7 @@
class="mt-3"
checkboxName="requestTextUpdates"
buttonID="requestTextUpdates"
:checkboxLabel="requestTextUpdatesCheckboxText"
/>
:checkboxLabel="requestTextUpdatesCheckboxText" />
<textareaQuestion
ref="notesQuestion"
v-model="notesForTechnician"
@ -74,25 +69,24 @@
:isRequired="false"
:cmsWidgetName="widget.notesQuestion"
maxLength="250"
:inputRows="4"
/>
<p ref="disclaimerText" class="caption dark-gray mt-6">
:inputRows="4" />
<p
ref="disclaimerText"
class="caption dark-gray mt-6">
{{ textUpdateDisclaimerText }} I also agree to Safelite's
<textLink
ref="privacyPolicyLink"
class="normal-line-height"
linkType="text"
text="Privacy Policy"
href="//www.safelite.com/privacy-center"
/>
href="//www.safelite.com/privacy-center" />
and
<textLink
ref="termsOfUseLink"
class="normal-line-height"
linkType="text"
text="Terms of Use"
href="//www.safelite.com/terms-of-use"
/>.
href="//www.safelite.com/terms-of-use" />.
</p>
<siteFooter
ref="siteFooter"
@ -100,8 +94,7 @@
:cmsWidgetName="widget.siteFooter"
:isForwardActionDisabled="!meta.valid"
@forwardClicked="forwardButtonAction"
@backClicked="navigateBack"
/>
@backClicked="navigateBack" />
</div>
</div>
</div>
@ -109,117 +102,117 @@
</template>
<script>
// Components
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 textboxQuestion from "@/digital-components/textbox-question/textbox-question.vue";
import checkbox from "@/ux-components/checkbox/checkbox.vue";
import textareaQuestion from "@/digital-components/textarea-question/textarea-question.vue";
import textLink from "@/ux-components/text-link/text-link.vue";
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 textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
import checkbox from '@/ux-components/checkbox/checkbox.vue';
import textareaQuestion from '@/digital-components/textarea-question/textarea-question.vue';
import textLink from '@/ux-components/text-link/text-link.vue';
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper.js";
import { Form } from "vee-validate";
import BaseFormMixin from "@/mixins/base-form-mixin.js";
import { useMainStore } from "@/store/index.js";
import globalRules from "@/constants/global-rules.js";
import MaskaFormattedMasks from "@/constants/maska-masks";
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper.js';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store/index.js';
import globalRules from '@/constants/global-rules.js';
import MaskaFormattedMasks from '@/constants/maska-masks';
export default {
name: "contact-details",
components: {
siteHeader,
siteSubHeader,
textboxQuestion,
checkbox,
textareaQuestion,
siteFooter,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
textLink,
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContent = await fetchCmsContentForPage(to.query.issPage);
name: 'contact-details',
components: {
siteHeader,
siteSubHeader,
textboxQuestion,
checkbox,
textareaQuestion,
siteFooter,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
textLink
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContent = await fetchCmsContentForPage(to.query.issPage);
next((vm) => {
vm.setCmsContent(cmsContent);
});
},
data() {
const {
firstName,
lastName,
emailAddress,
phoneNumber,
requestTextUpdates,
notesForTechnician,
} = useMainStore().contactInfo;
return {
firstName,
lastName,
emailAddress,
phoneNumber,
requestTextUpdates,
notesForTechnician,
widget: {
siteHeader: "SiteHeaderWidget",
siteSubHeader: "SiteSubHeaderWidget",
firstNameQuestion: "FirstNameQuestionWidget",
lastNameQuestion: "LastNameQuestionWidget",
emailQuestion: "EmailQuestionWidget",
phoneNumberQuestion: "PhoneNumberQuestionWidget",
requestTextUpdates: "TextContentWidget",
notesQuestion: "NotesQuestionWidget",
disclaimer: "TextUpdateDisclaimerWidget",
siteFooter: "SiteFooterWidget",
},
rules: {
firstName: globalRules.FIRST_NAME_REQUIRED,
lastName: globalRules.LAST_NAME_REQUIRED,
emailAddress: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`,
phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`,
},
};
},
computed: {
next((vm) => {
vm.setCmsContent(cmsContent);
});
},
data() {
const {
firstName,
lastName,
emailAddress,
phoneNumber,
requestTextUpdates,
notesForTechnician
} = useMainStore().contactInfo;
return {
firstName,
lastName,
emailAddress,
phoneNumber,
requestTextUpdates,
notesForTechnician,
widget: {
siteHeader: 'SiteHeaderWidget',
siteSubHeader: 'SiteSubHeaderWidget',
firstNameQuestion: 'FirstNameQuestionWidget',
lastNameQuestion: 'LastNameQuestionWidget',
emailQuestion: 'EmailQuestionWidget',
phoneNumberQuestion: 'PhoneNumberQuestionWidget',
requestTextUpdates: 'TextContentWidget',
notesQuestion: 'NotesQuestionWidget',
disclaimer: 'TextUpdateDisclaimerWidget',
siteFooter: 'SiteFooterWidget'
},
rules: {
firstName: globalRules.FIRST_NAME_REQUIRED,
lastName: globalRules.LAST_NAME_REQUIRED,
emailAddress: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`,
phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`
}
};
},
computed: {
/**
* @returns {string} Returns the CMS text associated with the "get text updates" checkbox.
*/
requestTextUpdatesCheckboxText() {
return `${this.getCmsContent(this.widget.requestTextUpdates, "Text")}*`;
requestTextUpdatesCheckboxText() {
return `${this.getCmsContent(this.widget.requestTextUpdates, 'Text')}*`;
},
/**
* @returns {string} Returns the CMS text associated with the "get text updates" checkbox.
*/
textUpdateDisclaimerText() {
return `*${this.getCmsContent(this.widget.disclaimer, 'Text')}`;
},
phoneMask() {
return MaskaFormattedMasks.PHONE_NUMBER;
}
},
/**
* @returns {string} Returns the CMS text associated with the "get text updates" checkbox.
*/
textUpdateDisclaimerText() {
return `*${this.getCmsContent(this.widget.disclaimer, "Text")}`;
},
phoneMask() {
return MaskaFormattedMasks.PHONE_NUMBER;
},
},
methods: {
methods: {
/**
* @summary Steps to perform when forward button clicked.
*/
forwardButtonAction() {
const contactInfo = {
firstName: this.firstName,
lastName: this.lastName,
emailAddress: this.emailAddress,
phoneNumber: this.phoneNumber,
requestTextUpdates: this.requestTextUpdates,
notesForTechnician: this.notesForTechnician,
};
useMainStore().updateContactInfo(contactInfo);
const scenario =
forwardButtonAction() {
const contactInfo = {
firstName: this.firstName,
lastName: this.lastName,
emailAddress: this.emailAddress,
phoneNumber: this.phoneNumber,
requestTextUpdates: this.requestTextUpdates,
notesForTechnician: this.notesForTechnician
};
useMainStore().updateContactInfo(contactInfo);
const scenario =
useMainStore().order.serviceLocation.IsSafeliteProvider === false
? this.navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP
: this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP;
this.$router.navigate(scenario, this.$route);
},
},
? this.navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP
: this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP;
this.$router.navigate(scenario, this.$route);
}
}
};
</script>

View file

@ -3,13 +3,16 @@
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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">
<loadingModal ref="loadingModal" :textSlides="loadingText" />
<siteHeader ref="siteHeader" cmsWidgetName="SiteHeaderWidget" />
<loadingModal
ref="loadingModal"
:textSlides="loadingText" />
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
</div>
<div class="row justify-content-center pt-5">
@ -17,34 +20,28 @@
<h5
ref="siteSubHeader"
class="text-center text-black"
v-html="coverageStatementSubHeader"
></h5>
v-html="coverageStatementSubHeader"></h5>
<div
ref="explanatoryText"
class="body-text text-center mt-2"
v-html="explanatoryText"
></div>
v-html="explanatoryText"></div>
<div
ref="secondaryText"
class="text-center mt-4 mb-1 fw-bold text-black"
v-html="secondaryText"
></div>
v-html="secondaryText"></div>
<div
v-if="verifiedDeductible"
class="d-flex justify-content-center cost"
>
class="d-flex justify-content-center cost">
{{ deductibleForDisplay }}
</div>
<div
v-if="isQuoteDisplayed"
class="d-flex justify-content-center cost mb-0"
>
class="d-flex justify-content-center cost mb-0">
{{ servicePriceForDisplay }}
</div>
<div
v-if="verifiedITAC"
class="d-flex justify-content-center mb-4 deductible-text"
>
class="d-flex justify-content-center mb-4 deductible-text">
{{ deductibleText }}&nbsp;
<span class="text-success fw-bold">{{ deductibleForDisplay }}</span>
</div>
@ -56,14 +53,14 @@
:manualHeadline="verifiedItacAlertHeader"
:manualCopy="verifiedItacAlertBody"
alertClass="alert-success"
:isDismissible="false"
>
:isDismissible="false">
</alert>
<div
class="fw-bold text-black mt-5 mb-2"
v-html="nextStepsHeader"
></div>
<div class="body-text" v-html="nextStepsBody"></div>
v-html="nextStepsHeader"></div>
<div
class="body-text"
v-html="nextStepsBody"></div>
<buttonQuestion
v-if="isQuoteDisplayed"
v-model="selectedProvider"
@ -73,407 +70,393 @@
groupName="ServiceProviderQuestionOption"
buttonTypeString="listButton"
isRequired
:validationRules="rules.selectionRequired"
>
:validationRules="rules.selectionRequired">
</buttonQuestion>
<text-block
v-if="isQuoteDisplayed"
cmsWidgetName="DisclaimerWidget"
typeStyle="caption"
/>
typeStyle="caption" />
<siteFooter
ref="siteFooter"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBackByVehicleQuestions"
@forwardClicked="navigateForward"
/>
@forwardClicked="navigateForward" />
</div>
</div>
</div>
<recalModal ref="RecalModal" cmsWidgetName="RecalModal" />
<recalModal
ref="RecalModal"
cmsWidgetName="RecalModal" />
<contentGroupModal
ref="DeductibleModal"
cmsWidgetName="DeductibleModal"
class="deductible-modal"
/>
class="deductible-modal" />
</Form>
</template>
<script>
// Import Component
import { Form } from "vee-validate";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import siteHeader from "@/iss-components/site-header/site-header.vue";
import recalModal from "@/layouts/coverage-statement/recal-modal/recal-modal.vue";
import alert from "@/ux-components/alert/alert.vue";
import contentGroupModal from "@/iss-components/content-group-modal/content-group-modal.vue";
import buttonQuestion from "@/digital-components/button-question/button-question.vue";
import loadingModal from "@/iss-components/loading-modal/loading-modal.vue";
import textBlock from "@/digital-components/text-block/text-block.vue";
import { Form } from 'vee-validate';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal.vue';
import alert from '@/ux-components/alert/alert.vue';
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
// Import Supporting Files
import {
fetchCmsContentForPage,
setupModalLinks,
processIfStatements,
} from "@/helpers/cms-content-helper.js";
import settleAllPromises from "@/helpers/layout-helper.js";
import { getDamageString } from "@/helpers/damage-helper.js";
import { useMainStore } from "@/store/index.js";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin.js";
import globalRules from "@/constants/global-rules.js";
import baseFormMixin from "@/mixins/base-form-mixin.js";
import navigationScenarios from "@/router/router-constants/navigation-scenarios.js";
import issPageValues from "@/router/router-constants/issPage-values";
import bailoutMessage from "@/constants/bailoutMessage";
import coverageStatuses from "@/constants/coverage-statuses";
import widgetFields from "@/constants/cms-widget-fields.js";
import getPriceOfLineItems from "@/helpers/price-calculator.js";
import { formatAmountInDollars } from "@/helpers/text-helper.js";
fetchCmsContentForPage,
setupModalLinks,
processIfStatements
} from '@/helpers/cms-content-helper.js';
import settleAllPromises from '@/helpers/layout-helper.js';
import { getDamageString } from '@/helpers/damage-helper.js';
import { useMainStore } from '@/store/index.js';
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin.js';
import globalRules from '@/constants/global-rules.js';
import baseFormMixin from '@/mixins/base-form-mixin.js';
import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
import issPageValues from '@/router/router-constants/issPage-values';
import bailoutMessage from '@/constants/bailoutMessage';
import coverageStatuses from '@/constants/coverage-statuses';
import widgetFields from '@/constants/cms-widget-fields.js';
import getPriceOfLineItems from '@/helpers/price-calculator.js';
import { formatAmountInDollars } from '@/helpers/text-helper.js';
const SAFELITE_PROVIDER = "Safelite";
const SAFELITE_PROVIDER = 'Safelite';
export default {
name: "coverage-statement",
components: {
siteFooter,
siteHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
recalModal,
alert,
contentGroupModal,
buttonQuestion,
loadingModal,
textBlock,
},
mixins: [baseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
name: 'coverage-statement',
components: {
siteFooter,
siteHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
recalModal,
alert,
contentGroupModal,
buttonQuestion,
loadingModal,
textBlock
},
mixins: [baseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to?.query?.issPage);
const supportingItemsPromise = await useMainStore().getSupportingItems();
const cmsContentPromise = fetchCmsContentForPage(to?.query?.issPage);
const supportingItemsPromise = await useMainStore().getSupportingItems();
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "supportingItems",
promise: supportingItemsPromise,
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
},
{
resultKey: 'supportingItems',
promise: supportingItemsPromise
}
];
const resultMap = await settleAllPromises(promiseResultMap);
const clonedGlassParts = useMainStore().lineItems.glassParts
? JSON.parse(JSON.stringify(useMainStore().lineItems.glassParts))
: [];
const availableLineItems = [
...(resultMap.supportingItems ?? []),
...(clonedGlassParts ?? []),
];
const resultMap = await settleAllPromises(promiseResultMap);
const clonedGlassParts = useMainStore().lineItems.glassParts
? JSON.parse(JSON.stringify(useMainStore().lineItems.glassParts))
: [];
const availableLineItems = [
...(resultMap.supportingItems ?? []),
...(clonedGlassParts ?? [])
];
let hasBailedOut = false;
let pricingResults = [];
if (
useMainStore().policy.policyLookupSuccessful &&
useMainStore().vehicle.policyVehicleId >= 0
) {
await useMainStore().getFinalDeductible();
pricingResults = await useMainStore()
.getPriceOrderItems(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}`);
});
}
if (!hasBailedOut) {
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.setSupportingItems(resultMap.supportingItems);
// eslint-disable-next-line no-param-reassign
vm.setBaseServiceLineItems(pricingResults);
vm.$refs.loadingModal.showModal();
vm.initializeComponent();
if (!vm.unverified) {
useMainStore().disableKeyFields();
let hasBailedOut = false;
let pricingResults = [];
if (
useMainStore().policy.policyLookupSuccessful
&& useMainStore().vehicle.policyVehicleId >= 0
) {
await useMainStore().getFinalDeductible();
pricingResults = await useMainStore()
.getPriceOrderItems(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}`);
});
}
if (!hasBailedOut) {
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.setSupportingItems(resultMap.supportingItems);
// eslint-disable-next-line no-param-reassign
vm.setBaseServiceLineItems(pricingResults);
vm.$refs.loadingModal.showModal();
vm.initializeComponent();
if (!vm.unverified) {
useMainStore().disableKeyFields();
}
});
}
});
}
},
data() {
const { isRepair } = useMainStore().damage;
const { policyLookupSuccessful, noCoverage } = useMainStore().policy;
return {
isRepair,
policyLookupSuccessful,
isNoComp: noCoverage ?? false,
baseServiceLineItems: [],
selectedProvider: "",
deductibleText: "Your deductible is",
// TODO update when design team gives appropriate text
loadingText: [
"Connecting to your insurance company",
"Nearly there",
"Finishing up",
],
rules: {
selectionRequired: globalRules.OPTION_REQUIRED,
},
supportingItems: null,
widget: {
subheader: "SiteSubHeaderWidget",
verifiedItacAlert: "VerifiedITACAlert",
explanatoryText: "ExplanatoryTextWidget",
nextStep: "NextStepsWidget",
serviceProviderQuestion: "ServiceProviderQuestion",
},
};
},
computed: {
coverageStatementSubHeader() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.subheader,
widgetFields.SUB_HEADER_WIDGET.SUB_HEADER_TEXT
);
},
verifiedItacAlertHeader() {
return this.getCmsContent(
this.widget.verifiedItacAlert,
widgetFields.ALERT_WIDGET.HEADLINE_TEXT
);
data() {
const { isRepair } = useMainStore().damage;
const { policyLookupSuccessful, noCoverage } = useMainStore().policy;
return {
isRepair,
policyLookupSuccessful,
isNoComp: noCoverage ?? false,
baseServiceLineItems: [],
selectedProvider: '',
deductibleText: 'Your deductible is',
// TODO update when design team gives appropriate text
loadingText: [
'Connecting to your insurance company',
'Nearly there',
'Finishing up'
],
rules: {
selectionRequired: globalRules.OPTION_REQUIRED
},
supportingItems: null,
widget: {
subheader: 'SiteSubHeaderWidget',
verifiedItacAlert: 'VerifiedITACAlert',
explanatoryText: 'ExplanatoryTextWidget',
nextStep: 'NextStepsWidget',
serviceProviderQuestion: 'ServiceProviderQuestion'
}
};
},
verifiedItacAlertBody() {
return this.getCmsContent(
this.widget.verifiedItacAlert,
widgetFields.ALERT_WIDGET.BODY_TEXT
)?.replaceAll("{custom:costSavings}", this.itacCostSavingsForDisplay);
computed: {
coverageStatementSubHeader() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.subheader,
widgetFields.SUB_HEADER_WIDGET.SUB_HEADER_TEXT
);
},
verifiedItacAlertHeader() {
return this.getCmsContent(
this.widget.verifiedItacAlert,
widgetFields.ALERT_WIDGET.HEADLINE_TEXT
);
},
verifiedItacAlertBody() {
return this.getCmsContent(
this.widget.verifiedItacAlert,
widgetFields.ALERT_WIDGET.BODY_TEXT
)?.replaceAll('{custom:costSavings}', this.itacCostSavingsForDisplay);
},
secondaryText() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.subheader,
widgetFields.SUB_HEADER_WIDGET.SECONDARY_TEXT
);
},
explanatoryText() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.explanatoryText,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
);
},
nextStepsHeader() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.nextStep,
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT
);
},
nextStepsBody() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.nextStep,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
)?.replaceAll('{custom:damage}', this.damageText);
},
damageText() {
const damageString = getDamageString();
return damageString === 'match' ? '' : damageString;
},
deductibleValue() {
return useMainStore().order.currentDeductible;
},
deductibleForDisplay() {
return formatAmountInDollars(this.deductibleValue);
},
registerClaimSuccessful() {
return useMainStore().payment.insuranceCoverage.isVerified;
},
verifiedNoComp() {
return this.policyLookupSuccessful && this.isNoComp;
},
verifiedITAC() {
return (
this.policyLookupSuccessful
&& !this.isNoComp
&& this.deductibleValue > this.totalServicePrice
);
},
coveredAndServicePriceAboveOrEqualDeductible() {
return (
!this.verifiedNoComp && this.totalServicePrice >= this.deductibleValue
);
},
verifiedDeductible() {
return useMainStore().isClaimRegistrationRequired
? this.registerClaimSuccessful
&& this.coveredAndServicePriceAboveOrEqualDeductible
&& this.deductibleValue !== null
: this.policyLookupSuccessful
&& this.coveredAndServicePriceAboveOrEqualDeductible;
},
unverified() {
return (
!this.verifiedDeductible && !this.verifiedITAC && !this.verifiedNoComp
);
},
isADAS() {
const parts = useMainStore().order.lineItems.glassParts;
return (
parts !== null && !!parts.find((part) => part.requiresRecalibration)
);
},
totalServicePrice() {
return getPriceOfLineItems(this.baseServiceLineItems);
},
servicePriceForDisplay() {
return formatAmountInDollars(this.totalServicePrice);
},
itacCostSavings() {
return this.deductibleValue - this.totalServicePrice;
},
itacCostSavingsForDisplay() {
return formatAmountInDollars(this.itacCostSavings);
},
serviceProviderQuestionText() {
return this.getCmsContent(
this.widget.serviceProviderQuestion,
widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT
);
},
serviceProviderQuestionAnswers() {
return this.getCmsContent(
this.widget.serviceProviderQuestion,
widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
);
},
isQuoteDisplayed() {
return this.verifiedITAC || this.verifiedNoComp;
},
shouldRegisterClaim() {
return (
this.policyLookupSuccessful
&& useMainStore().vehicle.policyVehicleId != null
&& useMainStore().vehicle.policyVehicleId >= 0
&& useMainStore().isClaimRegistrationRequired
&& !useMainStore().isClaimAlreadyRegistered
&& (this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC)
);
}
},
secondaryText() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.subheader,
widgetFields.SUB_HEADER_WIDGET.SECONDARY_TEXT
);
},
explanatoryText() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.explanatoryText,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
);
},
nextStepsHeader() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.nextStep,
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT
);
},
nextStepsBody() {
return this.getTextFromCmsWithCustomIfStatements(
this.widget.nextStep,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
)?.replaceAll("{custom:damage}", this.damageText);
},
damageText() {
const damageString = getDamageString();
return damageString === "match" ? "" : damageString;
},
deductibleValue() {
return useMainStore().order.currentDeductible;
},
deductibleForDisplay() {
return formatAmountInDollars(this.deductibleValue);
},
registerClaimSuccessful() {
return useMainStore().payment.insuranceCoverage.isVerified;
},
verifiedNoComp() {
return this.policyLookupSuccessful && this.isNoComp;
},
verifiedITAC() {
return (
this.policyLookupSuccessful &&
!this.isNoComp &&
this.deductibleValue > this.totalServicePrice
);
},
coveredAndServicePriceAboveOrEqualDeductible() {
return (
!this.verifiedNoComp && this.totalServicePrice >= this.deductibleValue
);
},
verifiedDeductible() {
return useMainStore().isClaimRegistrationRequired
? this.registerClaimSuccessful &&
this.coveredAndServicePriceAboveOrEqualDeductible &&
this.deductibleValue !== null
: this.policyLookupSuccessful &&
this.coveredAndServicePriceAboveOrEqualDeductible;
},
unverified() {
return (
!this.verifiedDeductible && !this.verifiedITAC && !this.verifiedNoComp
);
},
isADAS() {
const parts = useMainStore().order.lineItems.glassParts;
return (
parts !== null && !!parts.find((part) => part.requiresRecalibration)
);
},
totalServicePrice() {
return getPriceOfLineItems(this.baseServiceLineItems);
},
servicePriceForDisplay() {
return formatAmountInDollars(this.totalServicePrice);
},
itacCostSavings() {
return this.deductibleValue - this.totalServicePrice;
},
itacCostSavingsForDisplay() {
return formatAmountInDollars(this.itacCostSavings);
},
serviceProviderQuestionText() {
return this.getCmsContent(
this.widget.serviceProviderQuestion,
widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT
);
},
serviceProviderQuestionAnswers() {
return this.getCmsContent(
this.widget.serviceProviderQuestion,
widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
);
},
isQuoteDisplayed() {
return this.verifiedITAC || this.verifiedNoComp;
},
shouldRegisterClaim() {
return (
this.policyLookupSuccessful &&
useMainStore().vehicle.policyVehicleId != null &&
useMainStore().vehicle.policyVehicleId >= 0 &&
useMainStore().isClaimRegistrationRequired &&
!useMainStore().isClaimAlreadyRegistered &&
(this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC)
);
},
},
watch: {
selectedProvider() {
const buttonText =
watch: {
selectedProvider() {
const buttonText =
this.selectedProvider === SAFELITE_PROVIDER
? "Continue with Safelite"
: "Safelite";
this.$refs.siteFooter.updateButtonText(buttonText);
},
nextStepsBody(newValue, oldValue) {
if (newValue !== oldValue) {
setupModalLinks(this, "RecalModal");
setupModalLinks(this, "DeductibleModal");
}
},
},
mounted() {
setupModalLinks(this);
},
methods: {
arePagePrerequisitesValid() {
return !!useMainStore().vehicle.carId;
},
async initializeComponent() {
useMainStore().updatePolicyITACFlag(this.verifiedITAC);
const coverageStatus =
this.verifiedITAC || this.verifiedNoComp
? coverageStatuses.VERIFIED
: coverageStatuses.PENDING;
useMainStore().updateCoverageStatus(coverageStatus);
if (this.shouldRegisterClaim) {
await useMainStore()
.registerClaim()
?.catch(() => {});
}
this.$refs.loadingModal.hideModal();
},
async navigateForward() {
if (this.unverified || this.verifiedDeductible) {
useMainStore().updateSupportingItems(this.supportingItems);
this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD);
} else if (this.verifiedITAC || this.verifiedNoComp) {
useMainStore().updateIsSafeliteProvider(
this.selectedProvider === SAFELITE_PROVIDER
);
if (this.selectedProvider === SAFELITE_PROVIDER) {
useMainStore().updateSupportingItems(this.supportingItems);
this.navigateWithScenario(
navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE
);
} else {
useMainStore().setBailout(bailoutMessage.RequestCallback());
this.navigateWithScenario(
navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP
);
? 'Continue with Safelite'
: 'Safelite';
this.$refs.siteFooter.updateButtonText(buttonText);
},
nextStepsBody(newValue, oldValue) {
if (newValue !== oldValue) {
setupModalLinks(this, 'RecalModal');
setupModalLinks(this, 'DeductibleModal');
}
}
} else {
useMainStore().setBailout(
bailoutMessage.coverageStatementInvalidState()
);
this.navigateWithScenario(
navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE
);
}
},
navigateWithScenario(scenario) {
this.$router.navigate(scenario, this.$route);
mounted() {
setupModalLinks(this);
},
getTextFromCmsWithCustomIfStatements(widgetName, widgetField) {
const rawText = this.getCmsContent(widgetName, widgetField);
return processIfStatements(
rawText,
"custom",
this.getCustomValueFromString
);
},
getCustomValueFromString(str) {
switch (str) {
case "coverageUnverified":
return this.unverified;
case "verifiedDeductible":
return this.verifiedDeductible;
case "verifiedITAC":
return this.verifiedITAC;
case "verifiedNoComp":
return this.verifiedNoComp;
case "ADASReplace":
return !this.isRepair && this.isADAS;
case "nonADASReplace":
return !this.isRepair && !this.isADAS;
case "nonADASRepair":
return this.isRepair;
case "deductibleOverZero":
return this.verifiedDeductible && this.deductibleValue !== 0; // TODO what if deductible is negative?
case "isDeductibleZero":
return this.verifiedDeductible && this.deductibleValue === 0;
default:
return null;
}
},
setSupportingItems(newSupportingItems) {
this.supportingItems = newSupportingItems;
},
setBaseServiceLineItems(lineItems) {
this.baseServiceLineItems = lineItems;
},
},
methods: {
arePagePrerequisitesValid() {
return !!useMainStore().vehicle.carId;
},
async initializeComponent() {
useMainStore().updatePolicyITACFlag(this.verifiedITAC);
const coverageStatus =
this.verifiedITAC || this.verifiedNoComp
? coverageStatuses.VERIFIED
: coverageStatuses.PENDING;
useMainStore().updateCoverageStatus(coverageStatus);
if (this.shouldRegisterClaim) {
await useMainStore()
.registerClaim()
?.catch(() => {});
}
this.$refs.loadingModal.hideModal();
},
async navigateForward() {
if (this.unverified || this.verifiedDeductible) {
useMainStore().updateSupportingItems(this.supportingItems);
this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD);
} else if (this.verifiedITAC || this.verifiedNoComp) {
useMainStore().updateIsSafeliteProvider(this.selectedProvider === SAFELITE_PROVIDER);
if (this.selectedProvider === SAFELITE_PROVIDER) {
useMainStore().updateSupportingItems(this.supportingItems);
this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE);
} else {
useMainStore().setBailout(bailoutMessage.RequestCallback());
this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP);
}
} else {
useMainStore().setBailout(bailoutMessage.coverageStatementInvalidState());
this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_INVALID_STATE);
}
},
navigateWithScenario(scenario) {
this.$router.navigate(scenario, this.$route);
},
getTextFromCmsWithCustomIfStatements(widgetName, widgetField) {
const rawText = this.getCmsContent(widgetName, widgetField);
return processIfStatements(
rawText,
'custom',
this.getCustomValueFromString
);
},
getCustomValueFromString(str) {
switch (str) {
case 'coverageUnverified':
return this.unverified;
case 'verifiedDeductible':
return this.verifiedDeductible;
case 'verifiedITAC':
return this.verifiedITAC;
case 'verifiedNoComp':
return this.verifiedNoComp;
case 'ADASReplace':
return !this.isRepair && this.isADAS;
case 'nonADASReplace':
return !this.isRepair && !this.isADAS;
case 'nonADASRepair':
return this.isRepair;
case 'deductibleOverZero':
return this.verifiedDeductible && this.deductibleValue !== 0; // TODO what if deductible is negative?
case 'isDeductibleZero':
return this.verifiedDeductible && this.deductibleValue === 0;
default:
return null;
}
},
setSupportingItems(newSupportingItems) {
this.supportingItems = newSupportingItems;
},
setBaseServiceLineItems(lineItems) {
this.baseServiceLineItems = lineItems;
}
}
};
</script>

View file

@ -3,12 +3,13 @@
ref="duplicate-check-form"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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="widget.siteHeader" />
<siteHeader
ref="siteHeader"
:cmsWidgetName="widget.siteHeader" />
</div>
</div>
<div class="row justify-content-center">
@ -17,8 +18,7 @@
id="sub-header"
ref="siteSubHeader"
class="mt-5 duplicate-check-subheader"
:cmsWidgetName="widget.siteSubHeader"
/>
:cmsWidgetName="widget.siteSubHeader" />
<buttonQuestion
ref="buttonQuestion"
v-model="selectedAnswer"
@ -29,16 +29,14 @@
groupName="existingOrNewQuestionOption"
buttonTypeString="listButton"
isRequired
:validationRules="rules.selectionRequired"
/>
:validationRules="rules.selectionRequired" />
<siteFooter
ref="siteFooter"
class="my-5"
:cmsWidgetName="widget.siteFooter"
:isForwardActionDisabled="!meta.valid"
@forwardClicked="forwardButtonAction"
@backClicked="navigateBack"
/>
@backClicked="navigateBack" />
</div>
</div>
</div>
@ -47,166 +45,166 @@
<script>
// Components
import { Form } from "vee-validate";
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 buttonQuestion from "@/digital-components/button-question/button-question.vue";
import { Form } from 'vee-validate';
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 buttonQuestion from '@/digital-components/button-question/button-question.vue';
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper.js";
import BaseFormMixin from "@/mixins/base-form-mixin.js";
import { useMainStore } from "@/store/index.js";
import globalRules from "@/constants/global-rules.js";
import { toTitleCase } from "@/helpers/text-helper.js";
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper.js';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store/index.js';
import globalRules from '@/constants/global-rules.js';
import { toTitleCase } from '@/helpers/text-helper.js';
export default {
name: "duplicate-check",
components: {
siteHeader,
siteSubHeader,
buttonQuestion,
siteFooter,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContent = await fetchCmsContentForPage(to.query.issPage);
name: 'duplicate-check',
components: {
siteHeader,
siteSubHeader,
buttonQuestion,
siteFooter,
// eslint-disable-next-line vue/no-reserved-component-names
Form
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContent = await fetchCmsContentForPage(to.query.issPage);
next((vm) => {
vm.setCmsContent(cmsContent);
});
},
data() {
return {
selectedAnswer: null,
widget: {
siteHeader: "SiteHeaderWidget",
siteSubHeader: "SiteSubHeaderWidget",
existingOrNewQuestion: "ExistingOrNewQuestion",
siteFooter: "SiteFooterWidget",
},
rules: {
selectionRequired: globalRules.OPTION_REQUIRED,
},
};
},
computed: {
questionText() {
return this.getCmsContent(
this.widget.existingOrNewQuestion,
"QuestionText"
);
next((vm) => {
vm.setCmsContent(cmsContent);
});
},
answersFromCms() {
return (
this.getCmsContent(this.widget.existingOrNewQuestion, "Answers") ?? []
);
data() {
return {
selectedAnswer: null,
widget: {
siteHeader: 'SiteHeaderWidget',
siteSubHeader: 'SiteSubHeaderWidget',
existingOrNewQuestion: 'ExistingOrNewQuestion',
siteFooter: 'SiteFooterWidget'
},
rules: {
selectionRequired: globalRules.OPTION_REQUIRED
}
};
},
getNewOrderSelectionName() {
return this.answersFromCms?.[0]?.Name ?? "";
},
duplicateOrders() {
const duplicateOrderText = "Finish Existing Claim";
const orders = useMainStore().applicationUser.duplicateOrders;
return (
orders?.map((o) => {
const vehicle =
computed: {
questionText() {
return this.getCmsContent(
this.widget.existingOrNewQuestion,
'QuestionText'
);
},
answersFromCms() {
return (
this.getCmsContent(this.widget.existingOrNewQuestion, 'Answers') ?? []
);
},
getNewOrderSelectionName() {
return this.answersFromCms?.[0]?.Name ?? '';
},
duplicateOrders() {
const duplicateOrderText = 'Finish Existing Claim';
const orders = useMainStore().applicationUser.duplicateOrders;
return (
orders?.map((o) => {
const vehicle =
!!o.vehicleYear && !!o.vehicleMake && !!o.vehicleModel
? `${o.vehicleYear} ${o.vehicleMake} ${o.vehicleModel}`
: null;
? `${o.vehicleYear} ${o.vehicleMake} ${o.vehicleModel}`
: null;
const dateOfLoss =
const dateOfLoss =
o.responseDate == null
? ""
: new Date(o.responseDate).toLocaleDateString();
const subtext =
? ''
: new Date(o.responseDate).toLocaleDateString();
const subtext =
vehicle && o.responseDate
? `${vehicle}, ${dateOfLoss}`
: (vehicle ?? "").concat(dateOfLoss);
? `${vehicle}, ${dateOfLoss}`
: (vehicle ?? '').concat(dateOfLoss);
return {
Text: duplicateOrderText,
Name: o.referralNumber,
SubText: toTitleCase(subtext),
value: o,
};
}) ?? []
);
return {
Text: duplicateOrderText,
Name: o.referralNumber,
SubText: toTitleCase(subtext),
value: o
};
}) ?? []
);
},
answers() {
return [...this.duplicateOrders, ...this.answersFromCms];
}
},
answers() {
return [...this.duplicateOrders, ...this.answersFromCms];
},
},
methods: {
methods: {
/**
* @summary Steps to perform when forward button clicked.
*/
async forwardButtonAction() {
if (
this.selectedAnswer !== null &&
typeof this.selectedAnswer === "object"
) {
await useMainStore()
.loadSession(this.selectedAnswer)
.catch(() => {})
.finally(() => {
async forwardButtonAction() {
if (
this.selectedAnswer !== null
&& typeof this.selectedAnswer === 'object'
) {
await useMainStore()
.loadSession(this.selectedAnswer)
.catch(() => {})
.finally(() => {
this.navigateForward();
});
return;
}
this.navigateForward();
});
return;
}
},
navigateForward() {
if (!this.mainStore.order.policy.policyLookupSuccessful) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED,
this.$route
);
return;
}
this.navigateForward();
},
navigateForward() {
if (!this.mainStore.order.policy.policyLookupSuccessful) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED,
this.$route
);
return;
}
const policyVehicles = useMainStore().order.policy.vehicles ?? [];
if (!this.mainStore.order.loadedFromDupeCheck) {
if (policyVehicles.length !== 0) {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES,
this.$route
);
}
return;
}
const policyVehicles = useMainStore().order.policy.vehicles ?? [];
if (!this.mainStore.order.loadedFromDupeCheck) {
if (policyVehicles.length !== 0) {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES,
this.$route
);
if (this.mainStore.order.vehicle.vin) {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_POLICY_VEHICLE,
this.$route
);
} else if (policyVehicles.length !== 0) {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_NON_POLICY_VEHICLE,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_NO_POLICY_VEHICLES,
this.$route
);
}
}
return;
}
if (this.mainStore.order.vehicle.vin) {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_POLICY_VEHICLE,
this.$route
);
} else if (policyVehicles.length !== 0) {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_NON_POLICY_VEHICLE,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_NO_POLICY_VEHICLES,
this.$route
);
}
},
},
}
};
</script>

View file

@ -3,35 +3,33 @@
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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 class="mb-2 header" cmsWidgetName="SiteHeaderWidget" />
<siteHeader
class="mb-2 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="select-car-form rounded text-center">
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="displayGeneric"
class="mt-2 mb-4"
/>
<policyVehiclesQuestion
v-model="selectedVehicleVin"
cmsWidgetName="PolicyVehiclesQuestion"
:vehicles="VehiclesForQuestions"
:validationRules="rules.optionRequired"
/>
<siteFooter
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@backClicked="backButtonAction"
/>
<div class="select-car-form rounded text-center">
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="displayGeneric"
class="mt-2 mb-4" />
<policyVehiclesQuestion
v-model="selectedVehicleVin"
cmsWidgetName="PolicyVehiclesQuestion"
:vehicles="VehiclesForQuestions"
:validationRules="rules.optionRequired" />
<siteFooter
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@backClicked="backButtonAction" />
</div>
</div>
</div>
@ -40,250 +38,236 @@
</template>
<script>
// Components
import siteHeader from "@/iss-components/site-header/site-header.vue";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner.vue";
import policyVehiclesQuestion from "@/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.vue";
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import policyVehiclesQuestion from '@/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.vue';
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper.js";
import { Form } from "vee-validate";
import BaseFormMixin from "@/mixins/base-form-mixin.js";
import vehicleSelectionOptions from "@/constants/vehicle-selection-options.js";
import endorsementOptions from "@/constants/endorsement-options.js";
import globalRules from "@/constants/global-rules.js";
import { useMainStore } from "@/store/index.js";
import bailoutMessage from "@/constants/bailoutMessage";
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper.js';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import vehicleSelectionOptions from '@/constants/vehicle-selection-options.js';
import endorsementOptions from '@/constants/endorsement-options.js';
import globalRules from '@/constants/global-rules.js';
import { useMainStore } from '@/store/index.js';
import bailoutMessage from '@/constants/bailoutMessage';
import {
deductibleForSelectedVehicle,
endorsementsForSelectedVehicle,
noCoverageForSelectedVehicle,
repairWaivedForSelectedVehicle,
} from "@/helpers/policy-vehicle-helper";
deductibleForSelectedVehicle,
endorsementsForSelectedVehicle,
noCoverageForSelectedVehicle,
repairWaivedForSelectedVehicle
} from '@/helpers/policy-vehicle-helper';
export default {
name: "policy-vehicles",
components: {
siteHeader,
siteFooter,
vehicleBanner,
policyVehiclesQuestion,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = await fetchCmsContentForPage(to.query.issPage);
next((vm) => {
vm.setCmsContent(cmsContentPromise);
});
},
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
const policyVehicles = useMainStore().order.policy.vehicles;
return {
policyVehicles,
selectedVehicleVin: "",
selectedPolicyVehicle: null,
displayGeneric: true,
policyVinFound: true,
rules: {
optionRequired: globalRules.OPTION_REQUIRED,
},
};
},
computed: {
VehiclesForQuestions() {
// Map API result data, to address-vehicles data structure
const vehicles = this.policyVehicles;
const mappedData =
vehicles?.map((v) => {
const maskSymbol = "X";
const vinStart = maskSymbol.repeat(v.vin.length - 6);
const vinEnd = v.vin.substring(v.vin.length - 6);
return {
vin: v.vin,
vehicle: v,
Text: `${v.vehicleYear} ${v.vehicleMake} ${v.vehicleModel}`,
Name: v.vin,
SubText: `VIN ${vinStart}${vinEnd}`,
};
}) ?? [];
return mappedData;
name: 'policy-vehicles',
components: {
siteHeader,
siteFooter,
vehicleBanner,
policyVehiclesQuestion,
// eslint-disable-next-line vue/no-reserved-component-names
Form
},
noCoverageForSelectedVehicle() {
return noCoverageForSelectedVehicle(this.selectedPolicyVehicle);
},
deductibleForSelectedVehicle() {
return deductibleForSelectedVehicle(this.selectedPolicyVehicle);
},
endorsementsForSelectedVehicle() {
return endorsementsForSelectedVehicle(this.selectedPolicyVehicle);
},
repairWaivedForSelectedVehicle() {
return repairWaivedForSelectedVehicle(this.selectedPolicyVehicle);
},
selectedVehicle() {
const vehicle = this.mainStore.lookupVehicleByVin(
this.selectedVehicleVin
);
return vehicle;
},
},
watch: {
async selectedVehicleVin(value) {
if (value === vehicleSelectionOptions.VEHICLE_NOT_LISTED) {
// clear previously selected vehicle and image
this.mainStore.resetVehicleState();
this.displayGeneric = true;
this.selectedPolicyVehicle = null;
} else {
// get vehicle details from selected VIN
const vehicle = await this.lookupVehicleByVin(value);
// handle error in case vehicle info doesn't come back for selected VIN
if (vehicle?.error === true) {
this.mainStore.resetVehicleState();
this.displayGeneric = true;
this.selectedPolicyVehicle = null;
return;
}
if (vehicle) {
// save selected vehicle to the store
this.mainStore.updateVehicle(vehicle.data);
this.displayGeneric = false;
this.selectedPolicyVehicle = this.policyVehicles.find(
(p) => p.vin === value
);
}
}
},
},
beforeMount() {
if (this.mainStore.order.vehicle.vin) {
this.selectedVehicleVin = this.mainStore.order.vehicle.vin;
} else if (this.policyVehicles?.length === 1) {
this.selectedVehicleVin = this.policyVehicles[0]?.vin;
}
},
methods: {
backButtonAction() {
useMainStore().issConfig.disabledFields.policyNumber = true;
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() {
if (
this.selectedVehicleVin !== vehicleSelectionOptions.VEHICLE_NOT_LISTED
) {
const vehicleLookupResponse = await this.lookupVehicleByVin(
this.selectedVehicleVin
);
const vehicle = this.policyVehicles.find(
(pv) => pv.vin === this.selectedVehicleVin
);
if (vehicleLookupResponse.error) {
if (vehicleLookupResponse.status === 404) {
this.mainStore.resetVehicleState();
useMainStore().updateVehicle({
policyVehicleId: vehicle.id,
carId: "0",
category: "",
year: vehicle.vehicleYear || "",
make: vehicle.vehicleMake || "",
model: vehicle.vehicleModel || "",
style: vehicle.vehicleStyle || "",
vin: vehicle.vin,
noCoverage: this.noCoverageForSelectedVehicle,
deductible: this.deductibleForSelectedVehicle,
repairWaived: this.repairWaivedForSelectedVehicle,
});
this.policyVinFound = false;
return this.navigateForward();
}
this.mainStore.setBailout(
bailoutMessage.vehicleLookupError(
vehicle.vin,
vehicleLookupResponse.data
)
);
return this.navigateForward();
}
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, {
policyVehicleId: vehicle.id,
vin: this.selectedVehicleVin,
noCoverage: this.noCoverageForSelectedVehicle,
deductible: this.deductibleForSelectedVehicle,
repairWaived: this.repairWaivedForSelectedVehicle,
endorsements: this.endorsementsForSelectedVehicle,
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = await fetchCmsContentForPage(to.query.issPage);
next((vm) => {
vm.setCmsContent(cmsContentPromise);
});
useMainStore().updateVehicle(this.vehicleFromLookup);
}
return this.navigateForward();
},
navigateForward() {
if (this.mainStore.isBailout) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route,
{},
{}
);
} else if (
this.selectedVehicleVin === vehicleSelectionOptions.VEHICLE_NOT_LISTED
) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE,
this.$route,
{},
{}
);
} else if (
this.endorsementsForSelectedVehicle?.length > 0 &&
(this.endorsementsForSelectedVehicle?.includes(
endorsementOptions.PARKING_GUARD
) ||
this.endorsementsForSelectedVehicle?.includes(
endorsementOptions.EDUCATOR
))
) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS,
this.$route
);
} else if (!this.policyVinFound) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND,
this.$route,
{},
{}
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE,
this.$route,
{},
{}
);
}
setup() {
const mainStore = useMainStore();
return { mainStore };
},
async lookupVehicleByVin(vin) {
try {
return await useMainStore().lookupVehicleByVin(vin);
} catch (responseError) {
data() {
const policyVehicles = useMainStore().order.policy.vehicles;
return {
error: true,
status: responseError.status,
data: responseError.data,
policyVehicles,
selectedVehicleVin: '',
selectedPolicyVehicle: null,
displayGeneric: true,
policyVinFound: true,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
};
}
},
},
computed: {
VehiclesForQuestions() {
// Map API result data, to address-vehicles data structure
const vehicles = this.policyVehicles;
const mappedData =
vehicles?.map((v) => {
const maskSymbol = 'X';
const vinStart = maskSymbol.repeat(v.vin.length - 6);
const vinEnd = v.vin.substring(v.vin.length - 6);
return {
vin: v.vin,
vehicle: v,
Text: `${v.vehicleYear} ${v.vehicleMake} ${v.vehicleModel}`,
Name: v.vin,
SubText: `VIN ${vinStart}${vinEnd}`
};
}) ?? [];
return mappedData;
},
noCoverageForSelectedVehicle() {
return noCoverageForSelectedVehicle(this.selectedPolicyVehicle);
},
deductibleForSelectedVehicle() {
return deductibleForSelectedVehicle(this.selectedPolicyVehicle);
},
endorsementsForSelectedVehicle() {
return endorsementsForSelectedVehicle(this.selectedPolicyVehicle);
},
repairWaivedForSelectedVehicle() {
return repairWaivedForSelectedVehicle(this.selectedPolicyVehicle);
},
selectedVehicle() {
const vehicle = this.mainStore.lookupVehicleByVin(this.selectedVehicleVin);
return vehicle;
}
},
watch: {
async selectedVehicleVin(value) {
if (value === vehicleSelectionOptions.VEHICLE_NOT_LISTED) {
// clear previously selected vehicle and image
this.mainStore.resetVehicleState();
this.displayGeneric = true;
this.selectedPolicyVehicle = null;
} else {
// get vehicle details from selected VIN
const vehicle = await this.lookupVehicleByVin(value);
// handle error in case vehicle info doesn't come back for selected VIN
if (vehicle?.error === true) {
this.mainStore.resetVehicleState();
this.displayGeneric = true;
this.selectedPolicyVehicle = null;
return;
}
if (vehicle) {
// save selected vehicle to the store
this.mainStore.updateVehicle(vehicle.data);
this.displayGeneric = false;
this.selectedPolicyVehicle = this.policyVehicles.find((p) => p.vin === value);
}
}
}
},
beforeMount() {
if (this.mainStore.order.vehicle.vin) {
this.selectedVehicleVin = this.mainStore.order.vehicle.vin;
} else if (this.policyVehicles?.length === 1) {
this.selectedVehicleVin = this.policyVehicles[0]?.vin;
}
},
methods: {
backButtonAction() {
useMainStore().issConfig.disabledFields.policyNumber = true;
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() {
if (
this.selectedVehicleVin !== vehicleSelectionOptions.VEHICLE_NOT_LISTED
) {
const vehicleLookupResponse = await this.lookupVehicleByVin(this.selectedVehicleVin);
const vehicle = this.policyVehicles.find((pv) => pv.vin === this.selectedVehicleVin);
if (vehicleLookupResponse.error) {
if (vehicleLookupResponse.status === 404) {
this.mainStore.resetVehicleState();
useMainStore().updateVehicle({
policyVehicleId: vehicle.id,
carId: '0',
category: '',
year: vehicle.vehicleYear || '',
make: vehicle.vehicleMake || '',
model: vehicle.vehicleModel || '',
style: vehicle.vehicleStyle || '',
vin: vehicle.vin,
noCoverage: this.noCoverageForSelectedVehicle,
deductible: this.deductibleForSelectedVehicle,
repairWaived: this.repairWaivedForSelectedVehicle
});
this.policyVinFound = false;
return this.navigateForward();
}
this.mainStore.setBailout(bailoutMessage.vehicleLookupError(
vehicle.vin,
vehicleLookupResponse.data
));
return this.navigateForward();
}
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, {
policyVehicleId: vehicle.id,
vin: this.selectedVehicleVin,
noCoverage: this.noCoverageForSelectedVehicle,
deductible: this.deductibleForSelectedVehicle,
repairWaived: this.repairWaivedForSelectedVehicle,
endorsements: this.endorsementsForSelectedVehicle
});
useMainStore().updateVehicle(this.vehicleFromLookup);
}
return this.navigateForward();
},
navigateForward() {
if (this.mainStore.isBailout) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route,
{},
{}
);
} else if (
this.selectedVehicleVin === vehicleSelectionOptions.VEHICLE_NOT_LISTED
) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE,
this.$route,
{},
{}
);
} else if (
this.endorsementsForSelectedVehicle?.length > 0
&& (this.endorsementsForSelectedVehicle?.includes(endorsementOptions.PARKING_GUARD)
|| this.endorsementsForSelectedVehicle?.includes(endorsementOptions.EDUCATOR))
) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_ENDORSEMENTS,
this.$route
);
} else if (!this.policyVinFound) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_CAR_ID_NOT_FOUND,
this.$route,
{},
{}
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE,
this.$route,
{},
{}
);
}
},
async lookupVehicleByVin(vin) {
try {
return await useMainStore().lookupVehicleByVin(vin);
} catch (responseError) {
return {
error: true,
status: responseError.status,
data: responseError.data
};
}
}
}
};
</script>
<style lang="scss" scoped>

View file

@ -1,9 +1,14 @@
<template>
<Form ref="theForm" @submit="onSubmit" @invalidSubmit="onInvalidSubmit">
<Form
ref="theForm"
@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 class="mb-2 header" cmsWidgetName="SiteHeaderWidget" />
<siteHeader
class="mb-2 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
@ -11,8 +16,7 @@
<siteSubHeader
id="sub-header"
cmsWidgetName="SiteSubHeader"
class="mb-5 mt-4"
/>
class="mb-5 mt-4" />
</div>
</div>
<div class="row justify-content-center">
@ -25,219 +29,214 @@
groupName="prefQuestions"
buttonTypeString="providerPrefRadio"
:validationRules="rules.optionRequired"
isRequired
/>
isRequired />
<siteFooter
ref="siteFooter"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="isForwardActionDisabled"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
/>
@forwardClicked="forwardButtonAction" />
</div>
</div>
<recalModal ref="recalModal" cmsWidgetName="RecalModal" />
<recalModal
ref="recalModal"
cmsWidgetName="RecalModal" />
<steeringModal
ref="StateSteeringModal"
cmsWidgetName="StateSteeringModal"
/>
cmsWidgetName="StateSteeringModal" />
<shopPreferenceModal
ref="ShopPreferenceDrawer"
cmsWidgetName="ShopPreferenceDrawer"
:showSteeringLink="showSteeringLink"
@openSteering="openStateSteeringModal"
/>
@openSteering="openStateSteeringModal" />
<tpaRecalModal
ref="TPARecalModal"
cmsWidgetName="TPARecalModal"
:ackError="ackError"
@buttonClick="navigateWithTPAAck"
/>
@buttonClick="navigateWithTPAAck" />
</div>
</Form>
</template>
<script>
// Import Supporting Files
import {
fetchCmsContentForPage,
setupModalLinks,
} from "@/helpers/cms-content-helper";
import settleAllPromises from "@/helpers/layout-helper";
import errorMessages from "@/constants/error-messages";
import buttonQuestion from "@/digital-components/button-question/button-question.vue";
import issPageValues from "@/router/router-constants/issPage-values";
fetchCmsContentForPage,
setupModalLinks
} from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import errorMessages from '@/constants/error-messages';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import issPageValues from '@/router/router-constants/issPage-values';
// Import Component
import baseFormMixin from "@/mixins/base-form-mixin";
import { Form } from "vee-validate";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import siteHeader from "@/iss-components/site-header/site-header.vue";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue";
import recalModal from "@/layouts/coverage-statement/recal-modal/recal-modal.vue";
import steeringModal from "@/layouts/provider-preference/steering-modal/steering-modal.vue";
import shopPreferenceModal from "@/layouts/provider-preference/shop-preference-modal/shop-preference-modal.vue";
import tpaRecalModal from "@/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue";
import globalRules from "@/constants/global-rules";
import bailoutCode from "@/constants/bailoutCode";
import bailoutMessage from "@/constants/bailoutMessage";
import baseFormMixin from '@/mixins/base-form-mixin';
import { Form } from 'vee-validate';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal.vue';
import steeringModal from '@/layouts/provider-preference/steering-modal/steering-modal.vue';
import shopPreferenceModal from '@/layouts/provider-preference/shop-preference-modal/shop-preference-modal.vue';
import tpaRecalModal from '@/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue';
import globalRules from '@/constants/global-rules';
import bailoutCode from '@/constants/bailoutCode';
import bailoutMessage from '@/constants/bailoutMessage';
const options = { SAFELITE: "SafeliteOption", TPA: "TPAOption" };
const options = { SAFELITE: 'SafeliteOption', TPA: 'TPAOption' };
export default {
name: "provider-preference",
name: 'provider-preference',
components: {
siteFooter,
siteHeader,
siteSubHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
buttonQuestion,
recalModal,
steeringModal,
shopPreferenceModal,
tpaRecalModal,
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.showSteeringLink = !!vm.$refs.StateSteeringModal.ModalBodyText;
if (vm.showSteeringLink) {
vm.$refs.StateSteeringModal.openModal();
}
});
},
data() {
return {
selectedProvider: null,
showSteeringLink: false,
tpaAcknowledgement: false,
rules: {
optionRequired: globalRules.OPTION_REQUIRED,
},
};
},
computed: {
isForwardActionDisabled() {
return this.selectedProvider === null;
components: {
siteFooter,
siteHeader,
siteSubHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
buttonQuestion,
recalModal,
steeringModal,
shopPreferenceModal,
tpaRecalModal
},
prefAnswers() {
const cmsAnswersContent = [
{
cmsWidgetName: options.SAFELITE,
},
{
cmsWidgetName: options.TPA,
},
];
// if cms content has not yet loaded, skip
if (
!this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, "HeaderText") ||
this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, "HeaderText") ===
""
) {
return {};
}
const modifiedAnswers = cmsAnswersContent.map((answer) => ({
value: answer.cmsWidgetName,
buttonLabel: this.getHeaderTextFromCms(answer.cmsWidgetName),
buttonLabelSubCopy: this.getSubheaderTextFromCms(answer.cmsWidgetName),
buttonBodyCopy: this.getBodyTextFromCms(answer.cmsWidgetName),
}));
return modifiedAnswers;
},
ackError() {
return errorMessages.ACKNOWLEDGEMENT_REQUIRED;
},
},
mounted() {
setupModalLinks(this);
const pageData = this.mainStore.pageData(issPageValues.PROVIDER_PREFERENCE);
this.selectedProvider = pageData?.selectedProvider
? pageData.selectedProvider
: null;
this.tpaAcknowledgement = pageData?.tpaAcknowledgement
? pageData.tpaAcknowledgement
: false;
},
methods: {
getHeaderTextFromCms(cmsWidgetName) {
const headerText = this.getCmsContent(cmsWidgetName, "HeaderText");
return headerText?.replace(
"{custom:SafeliteLogo}",
"<span class='safeliteLogo'></span>"
);
},
getSubheaderTextFromCms(cmsWidgetName) {
return this.getCmsContent(cmsWidgetName, "SubheaderText");
},
getBodyTextFromCms(cmsWidgetName) {
return this.getCmsContent(cmsWidgetName, "BodyText");
},
arePagePrerequisiteValid() {
return true;
},
navigateForward(scenario) {
this.$router.navigate(scenario, this.$route);
},
navigateWithTPAAck() {
this.mainStore.saveProviderPreferenceData({
selectedProvider: this.selectedProvider,
tpaAcknowledgement: this.tpaAcknowledgement,
});
this.navigateForward(
this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED
);
},
forwardButtonAction() {
if (this.selectedProvider) {
let scenario = null;
switch (this.selectedProvider) {
case options.SAFELITE:
this.mainStore.updateIsSafeliteProvider(true);
scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE;
break;
case options.TPA:
this.mainStore.updateIsSafeliteProvider(false);
if (this.mainStore.issConfig.enableTPAFlow) {
if (this.mainStore.hasRecalibrationPart) {
this.$refs.TPARecalModal.openModal();
this.$refs.siteFooter.removeLoader();
return;
}
scenario =
this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED;
} else {
this.mainStore.setBailout(bailoutMessage.TPANotEnabled());
scenario =
this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED;
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
}
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.showSteeringLink = !!vm.$refs.StateSteeringModal.ModalBodyText;
if (vm.showSteeringLink) {
vm.$refs.StateSteeringModal.openModal();
}
break;
default:
}
this.navigateForward(scenario);
this.mainStore.saveProviderPreferenceData({
selectedProvider: this.selectedProvider,
tpaAcknowledgement: this.tpaAcknowledgement,
});
}
},
openStateSteeringModal() {
this.$refs.StateSteeringModal.openModal();
data() {
return {
selectedProvider: null,
showSteeringLink: false,
tpaAcknowledgement: false,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
};
},
},
computed: {
isForwardActionDisabled() {
return this.selectedProvider === null;
},
prefAnswers() {
const cmsAnswersContent = [
{
cmsWidgetName: options.SAFELITE
},
{
cmsWidgetName: options.TPA
}
];
// if cms content has not yet loaded, skip
if (
!this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText')
|| this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText')
=== ''
) {
return {};
}
const modifiedAnswers = cmsAnswersContent.map((answer) => ({
value: answer.cmsWidgetName,
buttonLabel: this.getHeaderTextFromCms(answer.cmsWidgetName),
buttonLabelSubCopy: this.getSubheaderTextFromCms(answer.cmsWidgetName),
buttonBodyCopy: this.getBodyTextFromCms(answer.cmsWidgetName)
}));
return modifiedAnswers;
},
ackError() {
return errorMessages.ACKNOWLEDGEMENT_REQUIRED;
}
},
mounted() {
setupModalLinks(this);
const pageData = this.mainStore.pageData(issPageValues.PROVIDER_PREFERENCE);
this.selectedProvider = pageData?.selectedProvider
? pageData.selectedProvider
: null;
this.tpaAcknowledgement = pageData?.tpaAcknowledgement
? pageData.tpaAcknowledgement
: false;
},
methods: {
getHeaderTextFromCms(cmsWidgetName) {
const headerText = this.getCmsContent(cmsWidgetName, 'HeaderText');
return headerText?.replace(
'{custom:SafeliteLogo}',
"<span class='safeliteLogo'></span>"
);
},
getSubheaderTextFromCms(cmsWidgetName) {
return this.getCmsContent(cmsWidgetName, 'SubheaderText');
},
getBodyTextFromCms(cmsWidgetName) {
return this.getCmsContent(cmsWidgetName, 'BodyText');
},
arePagePrerequisiteValid() {
return true;
},
navigateForward(scenario) {
this.$router.navigate(scenario, this.$route);
},
navigateWithTPAAck() {
this.mainStore.saveProviderPreferenceData({
selectedProvider: this.selectedProvider,
tpaAcknowledgement: this.tpaAcknowledgement
});
this.navigateForward(this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED);
},
forwardButtonAction() {
if (this.selectedProvider) {
let scenario = null;
switch (this.selectedProvider) {
case options.SAFELITE:
this.mainStore.updateIsSafeliteProvider(true);
scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE;
break;
case options.TPA:
this.mainStore.updateIsSafeliteProvider(false);
if (this.mainStore.issConfig.enableTPAFlow) {
if (this.mainStore.hasRecalibrationPart) {
this.$refs.TPARecalModal.openModal();
this.$refs.siteFooter.removeLoader();
return;
}
scenario =
this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED;
} else {
this.mainStore.setBailout(bailoutMessage.TPANotEnabled());
scenario =
this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED;
}
break;
default:
}
this.navigateForward(scenario);
this.mainStore.saveProviderPreferenceData({
selectedProvider: this.selectedProvider,
tpaAcknowledgement: this.tpaAcknowledgement
});
}
},
openStateSteeringModal() {
this.$refs.StateSteeringModal.openModal();
}
}
};
</script>
<style lang="scss" scoped>

View file

@ -3,12 +3,13 @@
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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 class="mb-2 header" cmsWidgetName="SiteHeaderWidget" />
<siteHeader
class="mb-2 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
@ -16,21 +17,18 @@
<siteSubHeader
cmsWidgetName="ScheduleSubHeaderWidget"
subTextClasses="text-center small sub-text"
class="mt-4"
/>
class="mt-4" />
<template v-if="ChangeShopLink.length">
<textBlock
cmsWidgetName="ChangeShopLink"
justifyText="center"
class="mb-3 text-link-small"
:marginTopSizeOverride="1"
/>
:marginTopSizeOverride="1" />
</template>
<div class="main-content-container">
<locationAlerts
ref="locationAlerts"
cmsWidgetPrefix="LocationAlert-"
/>
cmsWidgetPrefix="LocationAlert-" />
<datePicker
ref="datePicker"
v-model="selectedDate"
@ -39,8 +37,7 @@
class="text-link-small"
:customSelectableDatesCallback="getAvailableDatesMethod"
validationRules="date-required"
@dateClicked="openInshopTimeSlotsModal"
/>
@dateClicked="openInshopTimeSlotsModal" />
<timeSlotModalQuestion
ref="timeSlotModalQuestion"
v-model="selectedTimeSlotInfo"
@ -62,16 +59,14 @@
selectableDatesData.estimatedServiceMinutesMaximum
"
validationRules="time-slot-selection-required"
@timeSlotModalClosed="timeSlotModalClosed"
/>
@timeSlotModalClosed="timeSlotModalClosed" />
<siteFooter
ref="navbar"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
/>
@forwardClicked="forwardButtonAction" />
</div>
</div>
</div>
@ -80,419 +75,407 @@
</template>
<script>
// Components
import siteHeader from "@/iss-components/site-header/site-header.vue";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue";
import locationAlerts from "@/layouts/schedule-page/location-alerts/location-alerts.vue";
import datePicker from "@/digital-components/date-picker/date-picker.vue";
import timeSlotModalQuestion from "@/layouts/schedule-page/time-slot-modal-question/time-slot-modal-question.vue";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import textBlock from "@/digital-components/text-block/text-block.vue";
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import locationAlerts from '@/layouts/schedule-page/location-alerts/location-alerts.vue';
import datePicker from '@/digital-components/date-picker/date-picker.vue';
import timeSlotModalQuestion from '@/layouts/schedule-page/time-slot-modal-question/time-slot-modal-question.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
// Supporting files
import {
AppointmentTypeStrings,
GET_MOBILE_TIME_SLOTS,
GET_SHOP_TIME_SLOTS,
PREMIUM_FEE_PART_TYPE,
} from "@/constants/schedule-constants.js";
AppointmentTypeStrings,
GET_MOBILE_TIME_SLOTS,
GET_SHOP_TIME_SLOTS,
PREMIUM_FEE_PART_TYPE
} from '@/constants/schedule-constants.js';
import {
fetchCmsContentForPage,
splitCopyOnCMSPlaceHolder,
} from "@/helpers/cms-content-helper";
fetchCmsContentForPage,
splitCopyOnCMSPlaceHolder
} from '@/helpers/cms-content-helper';
import {
calcDaysBetweenDates,
convertDateStringToDate,
sumDateString,
} from "@/helpers/date-helper";
import settleAllPromises from "@/helpers/layout-helper";
import { Form, defineRule } from "vee-validate";
import BaseFormMixin from "@/mixins/base-form-mixin.js";
import errorMessages from "@/constants/error-messages";
import { required } from "@/helpers/validation-rules";
import { useMainStore } from "@/store";
calcDaysBetweenDates,
convertDateStringToDate,
sumDateString
} from '@/helpers/date-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { Form, defineRule } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import errorMessages from '@/constants/error-messages';
import { required } from '@/helpers/validation-rules';
import { useMainStore } from '@/store';
// DEFINE VALIDATION RULES
defineRule("date-required", required(errorMessages.DATE_REQUIRED));
defineRule("time-slot-selection-required", (value) => {
if (value?.timeSlot?.routeCode == null) {
return errorMessages.DATE_REQUIRED;
}
return true;
defineRule('date-required', required(errorMessages.DATE_REQUIRED));
defineRule('time-slot-selection-required', (value) => {
if (value?.timeSlot?.routeCode == null) {
return errorMessages.DATE_REQUIRED;
}
return true;
});
// Define constants
const TIME_SLOTS_CALL_DAYS_LIMIT = 34; // needs to be 34 for API limits (35 does not consistently work)
const getAvailableDates = async (
startDateString,
endDateString,
appointmentType,
providerNumber
) => {
const apiEndDateLimit = sumDateString(
startDateString,
TIME_SLOTS_CALL_DAYS_LIMIT
);
const difference = calcDaysBetweenDates(startDateString, endDateString);
const apiCallsCount = Math.ceil(difference / TIME_SLOTS_CALL_DAYS_LIMIT);
const storeActionConfigs = [];
const timeSlotsData = {};
timeSlotsData.days = [];
let apiStartDate = startDateString;
let apiEndDate = endDateString;
endDateString,
appointmentType,
providerNumber
) => {
const apiEndDateLimit = sumDateString(
startDateString,
TIME_SLOTS_CALL_DAYS_LIMIT
);
const difference = calcDaysBetweenDates(startDateString, endDateString);
const apiCallsCount = Math.ceil(difference / TIME_SLOTS_CALL_DAYS_LIMIT);
const storeActionConfigs = [];
const timeSlotsData = {};
timeSlotsData.days = [];
let apiStartDate = startDateString;
let apiEndDate = endDateString;
for (let i = 1; i <= apiCallsCount; i++) {
let storeActionConfig;
for (let i = 1; i <= apiCallsCount; i++) {
let storeActionConfig;
if (i > 1) {
apiStartDate = sumDateString(apiEndDate, 1);
apiEndDate = sumDateString(apiStartDate, TIME_SLOTS_CALL_DAYS_LIMIT);
if (i > 1) {
apiStartDate = sumDateString(apiEndDate, 1);
apiEndDate = sumDateString(apiStartDate, TIME_SLOTS_CALL_DAYS_LIMIT);
if (i === apiCallsCount) {
apiEndDate = endDateString;
}
} else if (apiEndDate > apiEndDateLimit) {
apiEndDate = apiEndDateLimit;
}
if (
appointmentType === AppointmentTypeStrings.MOBILE ||
appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
) {
storeActionConfig = {
storeAction: GET_MOBILE_TIME_SLOTS,
payload: {
startDate: apiStartDate,
endDate: apiEndDate,
},
};
} else {
storeActionConfig = {
storeAction: GET_SHOP_TIME_SLOTS,
payload: {
startDate: apiStartDate,
endDate: apiEndDate,
shopAppointmentType: appointmentType,
providerNumber,
},
};
}
if (apiStartDate < apiEndDate) storeActionConfigs.push(storeActionConfig);
}
const timeSlotsResponsesData = {
days: [],
};
function compareDayStrings(a, b) {
if (a.date < b.date) return -1;
if (a.date > b.date) return 1;
return 0;
}
const makeParallelCalls = async () => {
await Promise.all(
storeActionConfigs.map(async (storeAction) => {
let timeSlotsResponse = null;
if (storeAction.storeAction === GET_SHOP_TIME_SLOTS) {
timeSlotsResponse = await useMainStore().getShopTimeSlots(
storeAction.payload.startDate,
storeAction.payload.endDate,
storeAction.payload.shopAppointmentType,
storeAction.payload.providerNumber
);
} else {
timeSlotsResponse = await useMainStore().getMobileTimeSlots(
storeAction.payload.startDate,
storeAction.payload.endDate
);
if (i === apiCallsCount) {
apiEndDate = endDateString;
}
} else if (apiEndDate > apiEndDateLimit) {
apiEndDate = apiEndDateLimit;
}
timeSlotsResponsesData.estimatedServiceMinutesMinimum =
timeSlotsResponse.data.estimatedServiceMinutesMinimum;
timeSlotsResponsesData.estimatedServiceMinutesMaximum =
timeSlotsResponse.data.estimatedServiceMinutesMaximum;
timeSlotsResponsesData.days = [
...timeSlotsResponsesData.days,
...timeSlotsResponse.data.days,
];
})
);
};
if (
appointmentType === AppointmentTypeStrings.MOBILE
|| appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
) {
storeActionConfig = {
storeAction: GET_MOBILE_TIME_SLOTS,
payload: {
startDate: apiStartDate,
endDate: apiEndDate
}
};
} else {
storeActionConfig = {
storeAction: GET_SHOP_TIME_SLOTS,
payload: {
startDate: apiStartDate,
endDate: apiEndDate,
shopAppointmentType: appointmentType,
providerNumber
}
};
}
if (apiStartDate < apiEndDate) storeActionConfigs.push(storeActionConfig);
}
return makeParallelCalls().then(() => {
const timeSlotsResponsesData = {
days: []
};
function compareDayStrings(a, b) {
if (a.date < b.date) return -1;
if (a.date > b.date) return 1;
return 0;
}
const makeParallelCalls = async () => {
await Promise.all(storeActionConfigs.map(async (storeAction) => {
let timeSlotsResponse = null;
if (storeAction.storeAction === GET_SHOP_TIME_SLOTS) {
timeSlotsResponse = await useMainStore().getShopTimeSlots(
storeAction.payload.startDate,
storeAction.payload.endDate,
storeAction.payload.shopAppointmentType,
storeAction.payload.providerNumber
);
} else {
timeSlotsResponse = await useMainStore().getMobileTimeSlots(
storeAction.payload.startDate,
storeAction.payload.endDate
);
}
timeSlotsResponsesData.estimatedServiceMinutesMinimum =
timeSlotsResponse.data.estimatedServiceMinutesMinimum;
timeSlotsResponsesData.estimatedServiceMinutesMaximum =
timeSlotsResponse.data.estimatedServiceMinutesMaximum;
timeSlotsResponsesData.days = [
...timeSlotsResponsesData.days,
...timeSlotsResponse.data.days
];
}));
};
return makeParallelCalls().then(() => {
// sort days chronologically
timeSlotsResponsesData.days.sort(compareDayStrings);
return timeSlotsResponsesData;
});
timeSlotsResponsesData.days.sort(compareDayStrings);
return timeSlotsResponsesData;
});
};
export default {
name: "schedule-page",
components: {
siteHeader,
siteSubHeader,
locationAlerts,
datePicker,
timeSlotModalQuestion,
siteFooter,
textBlock,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
name: 'schedule-page',
components: {
siteHeader,
siteSubHeader,
locationAlerts,
datePicker,
timeSlotModalQuestion,
siteFooter,
textBlock,
// eslint-disable-next-line vue/no-reserved-component-names
Form
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
let preSelectedDate = await useMainStore().order.schedule.date;
if (!preSelectedDate || preSelectedDate.startTime === null) {
preSelectedDate = null;
}
let preSelectedDate = await useMainStore().order.schedule.date;
if (!preSelectedDate || preSelectedDate.startTime === null) {
preSelectedDate = null;
}
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const datePickerInitialDataPromise =
const datePickerInitialDataPromise =
await datePicker.methods.loadInitialData({
selectableDatesSetting: "custom",
initialViewRowsToShow: 5,
customSelectableDatesCallback: getAvailableDates,
preSelectedDate,
selectableDatesSetting: 'custom',
initialViewRowsToShow: 5,
customSelectableDatesCallback: getAvailableDates,
preSelectedDate
});
const premiumFeePromise = useMainStore().getMobilePremiumFee();
const premiumFeePromise = useMainStore().getMobilePremiumFee();
const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
if (result.data) {
return useMainStore().priceOrderItemsAndSaveServerData(result.data);
}
return result.data;
});
const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
if (result.data) {
return useMainStore().priceOrderItemsAndSaveServerData(result.data);
}
return result.data;
});
const alertReasonsPromise = locationAlerts.methods.loadInitialData(
useMainStore().order.serviceLocation.zipCodeCtu,
useMainStore().order.serviceLocation.provider?.address?.zipCodeCtu
);
const alertReasonsPromise = locationAlerts.methods.loadInitialData(
useMainStore().order.serviceLocation.zipCodeCtu,
useMainStore().order.serviceLocation.provider?.address?.zipCodeCtu
);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "alertReasons",
promise: alertReasonsPromise,
},
{
resultKey: "datePickerInitialData",
promise: datePickerInitialDataPromise,
},
{
resultKey: "premiumFeeWithPrice",
promise: premiumFeeWithPricePromise,
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
},
{
resultKey: 'alertReasons',
promise: alertReasonsPromise
},
{
resultKey: 'datePickerInitialData',
promise: datePickerInitialDataPromise
},
{
resultKey: 'premiumFeeWithPrice',
promise: premiumFeeWithPricePromise
}
];
// use resultMap to populate layout content.
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
vm.setData(
resultMap.datePickerInitialData.initialShopTimeSlotsResponse,
resultMap.premiumFeeWithPrice
);
vm.updateFooterButtonText(vm.selectedTimeSlotInfo);
});
},
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
return {
selectedDate: this.getSelectedDate(),
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
selectableDatesData: [],
mobilePremiumAppointmentFee: null,
};
},
computed: {
ChangeShopLinkText() {
return this.getCmsContent("ChangeShopLink", "Text");
// use resultMap to populate layout content.
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
vm.setData(
resultMap.datePickerInitialData.initialShopTimeSlotsResponse,
resultMap.premiumFeeWithPrice
);
vm.updateFooterButtonText(vm.selectedTimeSlotInfo);
});
},
ChangeShopLink() {
return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
setup() {
const mainStore = useMainStore();
return { mainStore };
},
appointmentType() {
return useMainStore().order.serviceLocation.appointmentType;
},
timeSlotsForSelectedDate() {
if (!this.selectedDate) {
return null;
}
return this.selectableDatesData.days?.find(
(selectableDate) => selectableDate.date === this.selectedDate
);
},
supportingItems() {
return useMainStore().lineItems.supportingItems;
},
},
watch: {
selectedDate(newValue, oldValue) {
// Clear time slot selection if date selected changes
if (newValue !== oldValue) {
this.selectedTimeSlotInfo = {
timeSlot: {
date: null,
routeCode: null,
startTime: null,
endTime: null,
jobMaxMinutes: null,
jobMinMinutes: null,
},
isPremiumAppointment: null,
data() {
return {
selectedDate: this.getSelectedDate(),
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
selectableDatesData: [],
mobilePremiumAppointmentFee: null
};
}
},
selectedTimeSlotInfo(newValue) {
this.updateFooterButtonText(newValue);
},
},
methods: {
splitCopyOnCMSPlaceHolder,
arePagePrerequisitesValid() {
const { serviceLocation } = useMainStore().order;
const serviceLocationPreReqs =
serviceLocation.zipCode &&
serviceLocation.zipCodeCtu &&
serviceLocation.appointmentType &&
(serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE ||
serviceLocation.appointmentType ===
AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP ||
serviceLocation.provider.providerNumber);
const supportingItems = this.supportingItems !== null;
const damageInfo =
useMainStore().order.damage.isRepair ||
(useMainStore().order.lineItems?.glassParts != null &&
useMainStore().order.lineItems.glassParts.length > 0);
computed: {
ChangeShopLinkText() {
return this.getCmsContent('ChangeShopLink', 'Text');
},
ChangeShopLink() {
return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
},
appointmentType() {
return useMainStore().order.serviceLocation.appointmentType;
},
timeSlotsForSelectedDate() {
if (!this.selectedDate) {
return null;
}
return serviceLocationPreReqs && supportingItems && damageInfo;
return this.selectableDatesData.days?.find((selectableDate) => selectableDate.date === this.selectedDate);
},
supportingItems() {
return useMainStore().lineItems.supportingItems;
}
},
setData(initialShopTimeSlotsResponse, premiumFeeWithPriceResponse) {
this.selectableDatesData = initialShopTimeSlotsResponse;
this.mobilePremiumAppointmentFee = premiumFeeWithPriceResponse
? premiumFeeWithPriceResponse[0]
: null;
watch: {
selectedDate(newValue, oldValue) {
// Clear time slot selection if date selected changes
if (newValue !== oldValue) {
this.selectedTimeSlotInfo = {
timeSlot: {
date: null,
routeCode: null,
startTime: null,
endTime: null,
jobMaxMinutes: null,
jobMinMinutes: null
},
isPremiumAppointment: null
};
}
},
selectedTimeSlotInfo(newValue) {
this.updateFooterButtonText(newValue);
}
},
async getAvailableDatesMethod(startDate, endDate) {
const newShopTimeSlots = await getAvailableDates(
startDate,
endDate,
this.appointmentType,
this.mainStore.order.serviceLocation.provider.providerNumber
);
// ADD API CALL RESULTS TO EXISTING DATE DATA
this.selectableDatesData.days = this.selectableDatesData.days.concat(
newShopTimeSlots.days
);
return newShopTimeSlots;
},
getAvailableDates,
getServiceZipCtuCodeFromStore() {
return this.mainStore.order.serviceLocation.zipCodeCtu;
},
openInshopTimeSlotsModal() {
this.$refs.timeSlotModalQuestion.openModal();
},
getSelectedDate() {
return this.mainStore.order.schedule.date;
},
getSelectedTimeSlotInfo() {
const isPremiumAppointment =
methods: {
splitCopyOnCMSPlaceHolder,
arePagePrerequisitesValid() {
const { serviceLocation } = useMainStore().order;
const serviceLocationPreReqs =
serviceLocation.zipCode
&& serviceLocation.zipCodeCtu
&& serviceLocation.appointmentType
&& (serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|| serviceLocation.appointmentType
=== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
|| serviceLocation.provider.providerNumber);
const supportingItems = this.supportingItems !== null;
const damageInfo =
useMainStore().order.damage.isRepair
|| (useMainStore().order.lineItems?.glassParts != null
&& useMainStore().order.lineItems.glassParts.length > 0);
return serviceLocationPreReqs && supportingItems && damageInfo;
},
setData(initialShopTimeSlotsResponse, premiumFeeWithPriceResponse) {
this.selectableDatesData = initialShopTimeSlotsResponse;
this.mobilePremiumAppointmentFee = premiumFeeWithPriceResponse
? premiumFeeWithPriceResponse[0]
: null;
},
async getAvailableDatesMethod(startDate, endDate) {
const newShopTimeSlots = await getAvailableDates(
startDate,
endDate,
this.appointmentType,
this.mainStore.order.serviceLocation.provider.providerNumber
);
// ADD API CALL RESULTS TO EXISTING DATE DATA
this.selectableDatesData.days = this.selectableDatesData.days.concat(newShopTimeSlots.days);
return newShopTimeSlots;
},
getAvailableDates,
getServiceZipCtuCodeFromStore() {
return this.mainStore.order.serviceLocation.zipCodeCtu;
},
openInshopTimeSlotsModal() {
this.$refs.timeSlotModalQuestion.openModal();
},
getSelectedDate() {
return this.mainStore.order.schedule.date;
},
getSelectedTimeSlotInfo() {
const isPremiumAppointment =
!!(
this.supportingItems?.filter(
(lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE
) ?? []
this.supportingItems?.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE) ?? []
).length > 0;
const selectedTimeSlotInfo = {
timeSlot: this.mainStore.order.schedule,
isPremiumAppointment,
};
const selectedTimeSlotInfo = {
timeSlot: this.mainStore.order.schedule,
isPremiumAppointment
};
return selectedTimeSlotInfo;
},
timeSlotModalClosed() {
// Clear the selectedDate if no timeSlot has been selected
if (this.selectedTimeSlotInfo.timeSlot.routeCode == null) {
this.selectedDate = null;
}
},
updateFooterButtonText(timeSlotInfo) {
let navbarButtonText;
if (!timeSlotInfo || !timeSlotInfo.timeSlot.date) {
navbarButtonText = "Continue";
} else {
navbarButtonText = `Select ${this.convertSelectedDateToShortMonthAndDay(
timeSlotInfo.timeSlot.date
)}`;
if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.startTime
)}`;
} else if (
this.appointmentType === AppointmentTypeStrings.MOBILE &&
!timeSlotInfo.isPremiumAppointment
return selectedTimeSlotInfo;
},
timeSlotModalClosed() {
// Clear the selectedDate if no timeSlot has been selected
if (this.selectedTimeSlotInfo.timeSlot.routeCode == null) {
this.selectedDate = null;
}
},
updateFooterButtonText(timeSlotInfo) {
let navbarButtonText;
if (!timeSlotInfo || !timeSlotInfo.timeSlot.date) {
navbarButtonText = 'Continue';
} else {
navbarButtonText = `Select ${this.convertSelectedDateToShortMonthAndDay(timeSlotInfo.timeSlot.date)}`;
if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(timeSlotInfo.timeSlot.startTime)}`;
} else if (
this.appointmentType === AppointmentTypeStrings.MOBILE
&& !timeSlotInfo.isPremiumAppointment
) {
navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.startTime,
true
)} - ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.endTime,
true
)}`;
}
}
this.$refs.navbar.updateButtonText(navbarButtonText);
},
convertSelectedDateToShortMonthAndDay(selectedDate) {
// This conversion ensures we don't get get GMT induced date changes
const dateObject = convertDateStringToDate(selectedDate);
return dateObject.toLocaleDateString('en-us', {
month: 'short',
day: 'numeric'
});
},
getDisplayTextForMilitaryTime(
militaryTimeInput,
shouldTrimMinutesIfEmpty = false
) {
navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.startTime,
true
)} - ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.endTime,
true
)}`;
// Expected input: "HH:MM"
let hours = parseInt(militaryTimeInput.split(':')[0], 10);
const minutes = militaryTimeInput.split(':')[1];
const meridianNotation = hours > 11 ? 'PM' : 'AM';
if (hours > 12) {
hours -= 12;
}
if (shouldTrimMinutesIfEmpty && minutes === '00') {
return `${hours} ${meridianNotation}`;
}
return `${hours}:${minutes} ${meridianNotation}`;
},
forwardButtonAction() {
this.mainStore.saveSchedule(this.selectedTimeSlotInfo.timeSlot);
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
}
}
this.$refs.navbar.updateButtonText(navbarButtonText);
},
convertSelectedDateToShortMonthAndDay(selectedDate) {
// This conversion ensures we don't get get GMT induced date changes
const dateObject = convertDateStringToDate(selectedDate);
return dateObject.toLocaleDateString("en-us", {
month: "short",
day: "numeric",
});
},
getDisplayTextForMilitaryTime(
militaryTimeInput,
shouldTrimMinutesIfEmpty = false
) {
// Expected input: "HH:MM"
let hours = parseInt(militaryTimeInput.split(":")[0], 10);
const minutes = militaryTimeInput.split(":")[1];
const meridianNotation = hours > 11 ? "PM" : "AM";
if (hours > 12) {
hours -= 12;
}
if (shouldTrimMinutesIfEmpty && minutes === "00") {
return `${hours} ${meridianNotation}`;
}
return `${hours}:${minutes} ${meridianNotation}`;
},
forwardButtonAction() {
this.mainStore.saveSchedule(this.selectedTimeSlotInfo.timeSlot);
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
},
},
}
};
</script>

View file

@ -3,12 +3,13 @@
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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 class="mb-2 header" cmsWidgetName="SiteHeaderWidget" />
<siteHeader
class="mb-2 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
@ -16,8 +17,7 @@
<siteSubHeader
id="sub-header"
cmsWidgetName="SiteSubHeader"
class="mb-5 mt-4"
/>
class="mb-5 mt-4" />
</div>
</div>
<div class="row justify-content-center">
@ -28,44 +28,38 @@
modalWidgetName="ServiceZipModalWidget"
:onZipUpdateCallback="reloadShopData"
@updatedServiceability="setServiceabilityDetails"
@updatedContainsMilitaryBase="setContainsMilitaryBase"
/>
@updatedContainsMilitaryBase="setContainsMilitaryBase" />
<alert
v-if="displayMilitaryZipAlert"
ref="alertMilitaryBaseZip"
class="my-5"
cmsWidgetName="AlertMilitaryBaseZipWidget"
alertClass="alert-warning"
/>
alertClass="alert-warning" />
<alert
v-if="displayServiceableMobileOnly"
ref="alertMobileOnly"
class="my-5"
cmsWidgetName="AlertMobileOnlyWidget"
alertClass="alert-warning"
/>
alertClass="alert-warning" />
<alert
v-if="displayRecalibrationWarning"
ref="alertRecalNoMobile"
class="my-5"
cmsWidgetName="AlertRecalNoMobileWidget"
alertClass="alert-warning"
@text-link-clicked="openModalAction"
/>
@text-link-clicked="openModalAction" />
<alert
v-if="displayServiceableInshopOnly"
ref="alertInshopOnly"
class="my-5"
cmsWidgetName="AlertInshopOnlyWidget"
alertClass="alert-warning"
/>
alertClass="alert-warning" />
<alert
v-if="displayNoShopsAlert"
ref="alertNoShops"
class="my-5"
cmsWidgetName="AlertNoShopsWidget"
alertClass="alert-warning"
/>
alertClass="alert-warning" />
<appointmentTypeQuestion
v-show="isAppointmentTypeDisplayed"
ref="appointmentTypeQuestion"
@ -75,8 +69,7 @@
:isDisplayed="isAppointmentTypeDisplayed"
groupName="appointmentTypeQuestion"
cmsWidgetName="AppointmentTypeQuestionWidget"
validationRules="option-required"
/>
validationRules="option-required" />
<mobileLocationModalQuestions
v-if="isMobileLocationDisplayed"
ref="mobileLocationQuestions"
@ -89,8 +82,7 @@
:onZipUpdateCallback="reloadShopData"
@updated-mobile-fee-part="setMobileFeePart"
@updated-serviceability="setServiceabilityDetails"
@updated-contains-military-base="setContainsMilitaryBase"
/>
@updated-contains-military-base="setContainsMilitaryBase" />
<shopQuestion
v-show="isShopQuestionDisplayed"
ref="shopQuestion"
@ -98,10 +90,11 @@
:selectedAppointmentType="selectedAppointmentType"
:isDisplayed="isShopQuestionDisplayed"
cmsWidgetName="ShopQuestionWidget"
@updatedMobileProviderNumber="setMobileProviderNumber"
/>
<contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />
</div>
@updatedMobileProviderNumber="setMobileProviderNumber" />
<contentGroupModal
ref="RecalModal"
cmsWidgetName="RecalModal" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
@ -111,8 +104,7 @@
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid || displayNoShopsAlert"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
/>
@forwardClicked="forwardButtonAction" />
</div>
</div>
</div>
@ -120,395 +112,393 @@
</template>
<script>
// Import Supporting Files
import { AppointmentTypeStrings } from "@/constants/schedule-constants.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import settleAllPromises from "@/helpers/layout-helper";
import { required } from "@/helpers/validation-rules";
import errorMessages from "@/constants/error-messages";
import { useMainStore } from "@/store";
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { required } from '@/helpers/validation-rules';
import errorMessages from '@/constants/error-messages';
import { useMainStore } from '@/store';
import {
getPricedMobileFeePart,
getServiceabilityDetails,
getZipCodeData,
} from "@/helpers/service-location-helper";
getPricedMobileFeePart,
getServiceabilityDetails,
getZipCodeData
} from '@/helpers/service-location-helper';
// Import Component
import alert from "@/ux-components/alert/alert.vue";
import appointmentTypeQuestion from "@/layouts/service-location/appointment-type-question/appointment-type-question.vue";
import baseFormMixin from "@/mixins/base-form-mixin";
import contentGroupModal from "@/iss-components/content-group-modal/content-group-modal.vue";
import mobileLocationModalQuestions from "@/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue";
import { Form, defineRule } from "vee-validate";
import shopQuestion from "@/layouts/service-location/shop-question/shop-question.vue";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import siteHeader from "@/iss-components/site-header/site-header.vue";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue";
import serviceZipModalQuestion from "@/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue";
import alert from '@/ux-components/alert/alert.vue';
import appointmentTypeQuestion from '@/layouts/service-location/appointment-type-question/appointment-type-question.vue';
import baseFormMixin from '@/mixins/base-form-mixin';
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
import mobileLocationModalQuestions from '@/layouts/service-location/mobile-location-modal-questions/mobile-location-modal-questions.vue';
import { Form, defineRule } from 'vee-validate';
import shopQuestion from '@/layouts/service-location/shop-question/shop-question.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import serviceZipModalQuestion from '@/layouts/service-location/service-zip-modal-question/service-zip-modal-question.vue';
// DEFINE VALIDATION RULES
defineRule("mobile-location-required", (value) => {
if (
value.addressQuestions.streetAddress === "" ||
value.addressQuestions.city === "" ||
value.addressQuestions.state === "" ||
value.addressQuestions.zipCode === "" ||
value.isVehicleProtected == null
) {
return errorMessages.MOBILE_LOCATION_REQUIRED;
}
return true;
defineRule('mobile-location-required', (value) => {
if (
value.addressQuestions.streetAddress === ''
|| value.addressQuestions.city === ''
|| value.addressQuestions.state === ''
|| value.addressQuestions.zipCode === ''
|| value.isVehicleProtected == null
) {
return errorMessages.MOBILE_LOCATION_REQUIRED;
}
return true;
});
defineRule("selection-required", required(errorMessages.OPTION_REQUIRED));
defineRule('selection-required', required(errorMessages.OPTION_REQUIRED));
export default {
name: "service-location",
components: {
alert,
appointmentTypeQuestion,
contentGroupModal,
mobileLocationModalQuestions,
siteFooter,
siteHeader,
siteSubHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
serviceZipModalQuestion,
shopQuestion,
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
name: 'service-location',
components: {
alert,
appointmentTypeQuestion,
contentGroupModal,
mobileLocationModalQuestions,
siteFooter,
siteHeader,
siteSubHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
serviceZipModalQuestion,
shopQuestion
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const serviceZipCode =
useMainStore().order.serviceLocation.zipCode ||
useMainStore().order.customer.address.zipCode;
const zipCodeData = getZipCodeData(serviceZipCode);
const serviceZipCode =
useMainStore().order.serviceLocation.zipCode
|| useMainStore().order.customer.address.zipCode;
const zipCodeData = getZipCodeData(serviceZipCode);
const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode);
const serviceabilityDetailsPromise =
const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode);
const serviceabilityDetailsPromise =
getServiceabilityDetails(serviceZipCode);
const shopQuestionInitialDataPromise =
const shopQuestionInitialDataPromise =
shopQuestion.methods.loadInitialData(serviceZipCode);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "mobileFeePart",
promise: mobileFeePartPromise,
},
{
resultKey: "serviceabilityDetails",
promise: serviceabilityDetailsPromise,
},
{
resultKey: "shopQuestionInitialData",
promise: shopQuestionInitialDataPromise,
},
{
resultKey: "zipCodeData",
promise: zipCodeData,
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
},
{
resultKey: 'mobileFeePart',
promise: mobileFeePartPromise
},
{
resultKey: 'serviceabilityDetails',
promise: serviceabilityDetailsPromise
},
{
resultKey: 'shopQuestionInitialData',
promise: shopQuestionInitialDataPromise
},
{
resultKey: 'zipCodeData',
promise: zipCodeData
}
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.setData(
resultMap.zipCodeData,
resultMap.serviceabilityDetails,
resultMap.mobileFeePart,
resultMap.shopQuestionInitialData?.mobileProviderNumber
);
vm.$refs.shopQuestion.initializeComponent(
resultMap.shopQuestionInitialData
);
});
},
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
return {
streetAddress: this.getServiceAddressFromStore(),
streetAddress2: this.getServiceAddress2FromStore(),
city: this.getServiceCityFromStore(),
state: this.getServiceStateFromStore(),
zipCode: this.getServiceZipCodeFromStore(),
isVehicleProtected: this.getIsVehicleProtectedFromStore(),
isGlassServiceableInshop: null,
isRecalibrationServiceableInshop: null,
isGlassServiceableMobile: null,
isRecalibrationServiceableMobile: null,
selectedAppointmentType: this.getSelectedAppointmentType(),
selectedProvider: this.getSelectedProvider(),
mobileFeePart: null,
mobileProviderNumber: null,
zipContainsMilitaryBase: false,
zipCodeCtu: null,
};
},
computed: {
questionText() {
return this.getCmsContent("ServiceTypeQuestionWidget", "QuestionText");
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.setData(
resultMap.zipCodeData,
resultMap.serviceabilityDetails,
resultMap.mobileFeePart,
resultMap.shopQuestionInitialData?.mobileProviderNumber
);
vm.$refs.shopQuestion.initializeComponent(resultMap.shopQuestionInitialData);
});
},
answersFromCms() {
return this.getCmsContent("ServiceTypeQuestionWidget", "Answers");
setup() {
const mainStore = useMainStore();
return { mainStore };
},
serviceZipCodeQuestion: {
get() {
data() {
return {
state: this.state,
zipCode: this.zipCode,
streetAddress: this.getServiceAddressFromStore(),
streetAddress2: this.getServiceAddress2FromStore(),
city: this.getServiceCityFromStore(),
state: this.getServiceStateFromStore(),
zipCode: this.getServiceZipCodeFromStore(),
isVehicleProtected: this.getIsVehicleProtectedFromStore(),
isGlassServiceableInshop: null,
isRecalibrationServiceableInshop: null,
isGlassServiceableMobile: null,
isRecalibrationServiceableMobile: null,
selectedAppointmentType: this.getSelectedAppointmentType(),
selectedProvider: this.getSelectedProvider(),
mobileFeePart: null,
mobileProviderNumber: null,
zipContainsMilitaryBase: false,
zipCodeCtu: null
};
},
set(newValue) {
if (newValue.zipCode !== this.zipCode) {
this.resetMobileLocation();
this.selectedAppointmentType = null;
this.selectedProvider = null;
},
computed: {
questionText() {
return this.getCmsContent('ServiceTypeQuestionWidget', 'QuestionText');
},
answersFromCms() {
return this.getCmsContent('ServiceTypeQuestionWidget', 'Answers');
},
serviceZipCodeQuestion: {
get() {
return {
state: this.state,
zipCode: this.zipCode
};
},
set(newValue) {
if (newValue.zipCode !== this.zipCode) {
this.resetMobileLocation();
this.selectedAppointmentType = null;
this.selectedProvider = null;
}
this.state = newValue.state;
this.zipCode = newValue.zipCode;
// eslint-disable-next-line vue/valid-next-tick
this.$nextTick();
}
},
mobileLocationQuestions: {
get() {
return {
addressQuestions: {
streetAddress: this.streetAddress,
streetAddress2: this.streetAddress2,
city: this.city,
state: this.state,
zipCode: this.zipCode
},
isVehicleProtected: this.isVehicleProtected
};
},
set(newValue) {
this.streetAddress = newValue.addressQuestions.streetAddress;
this.streetAddress2 = newValue.addressQuestions.streetAddress2;
this.city = newValue.addressQuestions.city;
this.state = newValue.addressQuestions.state;
this.zipCode = newValue.addressQuestions.zipCode;
this.isVehicleProtected = newValue.isVehicleProtected;
if (newValue.zipCode !== this.zipCode) {
if (
!(
this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
|| this.selectedAppointmentType
=== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
)
) {
this.selectedAppointmentType = null;
}
this.selectedProvider = null;
}
}
},
isServiceableMobile() {
if (this.isRecalibrationServiceableMobile !== null) {
return (
this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile
);
}
return this.isGlassServiceableMobile;
},
isServiceableInshop() {
if (this.isRecalibrationServiceableInshop !== null) {
return (
this.isGlassServiceableInshop && this.isRecalibrationServiceableInshop
);
}
return this.isGlassServiceableInshop;
},
isShopQuestionDisplayed() {
return (
this.selectedAppointmentType === 'Inshop'
|| this.selectedAppointmentType === 'Dropoff'
);
},
isAppointmentTypeDisplayed() {
return this.zipCode && !this.displayNoShopsAlert;
},
isMobileLocationDisplayed() {
return (
this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
|| this.selectedAppointmentType
=== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
);
},
requiresInshopRecalibration() {
// Specifically check for isRecalibrationServiceableMobile === false, not null or true.
return (
this.isServiceableInshop
&& this.isGlassServiceableMobile
&& this.isRecalibrationServiceableMobile === false
);
},
displayMilitaryZipAlert() {
return this.zipContainsMilitaryBase && this.isServiceableMobile;
},
displayNoShopsAlert() {
return !this.isServiceableInshop && !this.isServiceableMobile;
},
displayRecalibrationWarning() {
return this.requiresInshopRecalibration;
},
displayServiceableInshopOnly() {
return (
!this.displayRecalibrationWarning
&& this.isServiceableInshop
&& !this.isServiceableMobile
);
},
displayServiceableMobileOnly() {
return this.isServiceableMobile && !this.isServiceableInshop;
}
},
methods: {
arePagePrerequisitesValid() {
return (
useMainStore().lineItems.supportingItems !== null
&& useMainStore().order.serviceLocation.zipCode !== null
);
},
async reloadShopData(zipCode) {
await this.$refs.shopQuestion.reloadShopData(zipCode);
},
async forwardButtonAction() {
let provider = this.selectedProvider;
this.mainStore.updateMobileFee(null);
if (this.isMobileLocationDisplayed) {
if (this.mainStore.isNoComp || this.mainStore.isITAC) {
this.mainStore.updateMobileFee(this.mobileFeePart);
}
this.state = newValue.state;
this.zipCode = newValue.zipCode;
provider = {
providerNumber: this.mobileProviderNumber,
address: {
streetAddress: null,
city: null,
state: null,
zipCode: null,
zipCodeCtu: null
}
};
}
// eslint-disable-next-line vue/valid-next-tick
this.$nextTick();
},
},
mobileLocationQuestions: {
get() {
return {
addressQuestions: {
streetAddress: this.streetAddress,
streetAddress2: this.streetAddress2,
city: this.city,
state: this.state,
zipCode: this.zipCode,
},
isVehicleProtected: this.isVehicleProtected,
};
},
set(newValue) {
this.streetAddress = newValue.addressQuestions.streetAddress;
this.streetAddress2 = newValue.addressQuestions.streetAddress2;
this.city = newValue.addressQuestions.city;
this.state = newValue.addressQuestions.state;
this.zipCode = newValue.addressQuestions.zipCode;
this.isVehicleProtected = newValue.isVehicleProtected;
this.mainStore.saveServiceLocation({
address: this.streetAddress,
address2: this.streetAddress2,
city: this.city,
state: this.state,
zipCode: this.zipCode,
zipCodeCtu: this.zipCodeCtu,
appointmentType: this.selectedAppointmentType,
isVehicleProtected: this.isVehicleProtected,
provider
});
if (newValue.zipCode !== this.zipCode) {
if (
!(
this.selectedAppointmentType === AppointmentTypeStrings.MOBILE ||
this.selectedAppointmentType ===
AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
)
) {
this.selectedAppointmentType = null;
}
this.selectedProvider = null;
}
},
},
isServiceableMobile() {
if (this.isRecalibrationServiceableMobile !== null) {
return (
this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile
);
}
return this.isGlassServiceableMobile;
},
isServiceableInshop() {
if (this.isRecalibrationServiceableInshop !== null) {
return (
this.isGlassServiceableInshop && this.isRecalibrationServiceableInshop
);
}
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
},
openModalAction(modalName) {
this.$refs[modalName].openModal();
},
resetDependentState() {},
getServiceAddressFromStore() {
return useMainStore().order.serviceLocation.address;
},
getServiceAddress2FromStore() {
return useMainStore().order.serviceLocation.address2;
},
getServiceCityFromStore() {
return useMainStore().order.serviceLocation.city;
},
getServiceStateFromStore() {
return (
useMainStore().order.serviceLocation.state
|| useMainStore().order.customer.address.state
);
},
getServiceZipCodeFromStore() {
return (
useMainStore().order.serviceLocation.zipCode
|| useMainStore().order.customer.address.zipCode
);
},
getIsVehicleProtectedFromStore() {
return useMainStore().order.serviceLocation.isVehicleProtected;
},
getSelectedAppointmentType() {
return useMainStore().order.serviceLocation.appointmentType;
},
getSelectedProvider() {
return useMainStore().order.serviceLocation.provider;
},
setData(
zipCodeData,
serviceabilityDetails,
mobileFeePart,
mobileProviderNumber
) {
if (zipCodeData) {
this.zipContainsMilitaryBase = zipCodeData.containsMilitaryBase;
this.zipCodeCtu = zipCodeData.zipCodeCtu;
}
return this.isGlassServiceableInshop;
},
isShopQuestionDisplayed() {
return (
this.selectedAppointmentType === "Inshop" ||
this.selectedAppointmentType === "Dropoff"
);
},
isAppointmentTypeDisplayed() {
return this.zipCode && !this.displayNoShopsAlert;
},
isMobileLocationDisplayed() {
return (
this.selectedAppointmentType === AppointmentTypeStrings.MOBILE ||
this.selectedAppointmentType ===
AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
);
},
requiresInshopRecalibration() {
// Specifically check for isRecalibrationServiceableMobile === false, not null or true.
return (
this.isServiceableInshop &&
this.isGlassServiceableMobile &&
this.isRecalibrationServiceableMobile === false
);
},
displayMilitaryZipAlert() {
return this.zipContainsMilitaryBase && this.isServiceableMobile;
},
displayNoShopsAlert() {
return !this.isServiceableInshop && !this.isServiceableMobile;
},
displayRecalibrationWarning() {
return this.requiresInshopRecalibration;
},
displayServiceableInshopOnly() {
return (
!this.displayRecalibrationWarning &&
this.isServiceableInshop &&
!this.isServiceableMobile
);
},
displayServiceableMobileOnly() {
return this.isServiceableMobile && !this.isServiceableInshop;
},
},
methods: {
arePagePrerequisitesValid() {
return (
useMainStore().lineItems.supportingItems !== null &&
useMainStore().order.serviceLocation.zipCode !== null
);
},
async reloadShopData(zipCode) {
await this.$refs.shopQuestion.reloadShopData(zipCode);
},
async forwardButtonAction() {
let provider = this.selectedProvider;
this.mainStore.updateMobileFee(null);
if (this.isMobileLocationDisplayed) {
if (this.mainStore.isNoComp || this.mainStore.isITAC) {
this.mainStore.updateMobileFee(this.mobileFeePart);
}
if (serviceabilityDetails) {
this.setServiceabilityDetails(serviceabilityDetails);
}
provider = {
providerNumber: this.mobileProviderNumber,
address: {
streetAddress: null,
city: null,
state: null,
zipCode: null,
zipCodeCtu: null,
},
};
}
if (mobileFeePart) {
this.mobileFeePart = mobileFeePart;
}
this.mainStore.saveServiceLocation({
address: this.streetAddress,
address2: this.streetAddress2,
city: this.city,
state: this.state,
zipCode: this.zipCode,
zipCodeCtu: this.zipCodeCtu,
appointmentType: this.selectedAppointmentType,
isVehicleProtected: this.isVehicleProtected,
provider,
});
if (mobileProviderNumber) {
this.setMobileProviderNumber(mobileProviderNumber);
}
},
setContainsMilitaryBase(val) {
if (this.zipContainsMilitaryBase !== val) {
this.zipContainsMilitaryBase = val;
}
},
setMobileFeePart(mobileFeePart) {
this.mobileFeePart = mobileFeePart;
},
setMobileProviderNumber(providerNumber) {
this.mobileProviderNumber = providerNumber;
},
resetMobileLocation() {
this.streetAddress = '';
this.streetAddress2 = '';
this.city = '';
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
},
openModalAction(modalName) {
this.$refs[modalName].openModal();
},
resetDependentState() {},
getServiceAddressFromStore() {
return useMainStore().order.serviceLocation.address;
},
getServiceAddress2FromStore() {
return useMainStore().order.serviceLocation.address2;
},
getServiceCityFromStore() {
return useMainStore().order.serviceLocation.city;
},
getServiceStateFromStore() {
return (
useMainStore().order.serviceLocation.state ||
useMainStore().order.customer.address.state
);
},
getServiceZipCodeFromStore() {
return (
useMainStore().order.serviceLocation.zipCode ||
useMainStore().order.customer.address.zipCode
);
},
getIsVehicleProtectedFromStore() {
return useMainStore().order.serviceLocation.isVehicleProtected;
},
getSelectedAppointmentType() {
return useMainStore().order.serviceLocation.appointmentType;
},
getSelectedProvider() {
return useMainStore().order.serviceLocation.provider;
},
setData(
zipCodeData,
serviceabilityDetails,
mobileFeePart,
mobileProviderNumber
) {
if (zipCodeData) {
this.zipContainsMilitaryBase = zipCodeData.containsMilitaryBase;
this.zipCodeCtu = zipCodeData.zipCodeCtu;
}
if (serviceabilityDetails) {
this.setServiceabilityDetails(serviceabilityDetails);
}
if (mobileFeePart) {
this.mobileFeePart = mobileFeePart;
}
if (mobileProviderNumber) {
this.setMobileProviderNumber(mobileProviderNumber);
}
},
setContainsMilitaryBase(val) {
if (this.zipContainsMilitaryBase !== val) {
this.zipContainsMilitaryBase = val;
}
},
setMobileFeePart(mobileFeePart) {
this.mobileFeePart = mobileFeePart;
},
setMobileProviderNumber(providerNumber) {
this.mobileProviderNumber = providerNumber;
},
resetMobileLocation() {
this.streetAddress = "";
this.streetAddress2 = "";
this.city = "";
this.isVehicleProtected = null;
},
setServiceabilityDetails(serviceabilityDetails) {
this.isGlassServiceableInshop =
this.isVehicleProtected = null;
},
setServiceabilityDetails(serviceabilityDetails) {
this.isGlassServiceableInshop =
serviceabilityDetails.isGlassServiceableInshop;
this.isRecalibrationServiceableInshop =
this.isRecalibrationServiceableInshop =
serviceabilityDetails.isRecalibrationServiceableInshop;
this.isGlassServiceableMobile =
this.isGlassServiceableMobile =
serviceabilityDetails.isGlassServiceableMobile;
this.isRecalibrationServiceableMobile =
this.isRecalibrationServiceableMobile =
serviceabilityDetails.isRecalibrationServiceableMobile;
},
},
}
}
};
</script>

View file

@ -3,8 +3,7 @@
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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">
@ -13,520 +12,458 @@
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<alert
v-if="shouldDisplayVehicleChangeAlert"
ref="vehicleChangeAlert"
class="mt-5 mb-0"
cmsWidgetName="VehicleChangeAlert"
alertClass="alert-warning"
:isDismissible="false"
/>
<vehicleBanner
class="mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
/>
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6">
<damageLocationQuestion
ref="damageLocation"
v-model="selectedDamageLocations"
cmsWidgetName="DamageLocationQuestion"
groupName="DamageLocationQuestion"
/>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<windshieldOptions
ref="windshieldOptions"
v-model="selectedWindshieldOptions"
:hasRepairReplaceConflict="hasRepairReplaceConflict"
:hasSplitSingleConflict="hasSplitSingleConflict"
:selectedDamageLocations="selectedDamageLocations"
class="mb-3"
/>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<alert
v-if="hasRepairReplaceConflict"
class="my-5"
cmsWidgetName="HasReplacementConflict"
alertClass="alert-danger"
:isDismissible="false"
/>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<sideDoorOptions
v-show="!hasRepairReplaceConflict"
ref="sideDoorOptions"
v-model="sideDoorOptionsData"
cmsWidgetName="SideDoorSideQuestion"
groupName="SideDoorSideQuestion"
:selectedDamageLocations="selectedDamageLocations"
class="mb-1"
/>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<replaceOptionsQuestion
ref="backGlassOptions"
v-model="selectedRearReplaceOptions"
cmsWidgetName="RearReplaceOptionsQuestion"
:isAvailable="
isRearWindowDamageLocation && !hasRepairReplaceConflict
"
groupName="BackGlassReplaceOptionsQuestion"
validationRules="replace-options-required"
/>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<site-footer
ref="siteFooter"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
/>
</div>
</div>
</div>
<alert
v-if="shouldDisplayVehicleChangeAlert"
ref="vehicleChangeAlert"
class="mt-5 mb-0"
cmsWidgetName="VehicleChangeAlert"
alertClass="alert-warning"
:isDismissible="false" />
<vehicleBanner
class="mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6">
<damageLocationQuestion
ref="damageLocation"
v-model="selectedDamageLocations"
cmsWidgetName="DamageLocationQuestion"
groupName="DamageLocationQuestion" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<windshieldOptions
ref="windshieldOptions"
v-model="selectedWindshieldOptions"
:hasRepairReplaceConflict="hasRepairReplaceConflict"
:hasSplitSingleConflict="hasSplitSingleConflict"
:selectedDamageLocations="selectedDamageLocations"
class="mb-3" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<alert
v-if="hasRepairReplaceConflict"
class="my-5"
cmsWidgetName="HasReplacementConflict"
alertClass="alert-danger"
:isDismissible="false" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<sideDoorOptions
v-show="!hasRepairReplaceConflict"
ref="sideDoorOptions"
v-model="sideDoorOptionsData"
cmsWidgetName="SideDoorSideQuestion"
groupName="SideDoorSideQuestion"
:selectedDamageLocations="selectedDamageLocations"
class="mb-1" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<replaceOptionsQuestion
ref="backGlassOptions"
v-model="selectedRearReplaceOptions"
cmsWidgetName="RearReplaceOptionsQuestion"
:isAvailable="
isRearWindowDamageLocation && !hasRepairReplaceConflict
"
groupName="BackGlassReplaceOptionsQuestion"
validationRules="replace-options-required" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<site-footer
ref="siteFooter"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction" />
</div>
</div>
</div>
</Form>
</template>
<script>
// Components
import siteHeader from "@/iss-components/site-header/site-header.vue";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner.vue";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue";
import sideDoorOptions from "@/layouts/vehicle-damage/side-door-options/side-door-options.vue";
import damageLocationQuestion from "@/layouts/vehicle-damage/damage-location-question/damage-location-question.vue";
import windshieldOptions from "@/layouts/vehicle-damage/windshield-options/windshield-options.vue";
import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question.vue";
import alert from "@/ux-components/alert/alert.vue";
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import sideDoorOptions from '@/layouts/vehicle-damage/side-door-options/side-door-options.vue';
import damageLocationQuestion from '@/layouts/vehicle-damage/damage-location-question/damage-location-question.vue';
import windshieldOptions from '@/layouts/vehicle-damage/windshield-options/windshield-options.vue';
import replaceOptionsQuestion from '@/layouts/vehicle-damage/replace-options-question/replace-options-question.vue';
import alert from '@/ux-components/alert/alert.vue';
// Supporting files
import BaseFormMixin from "@/mixins/base-form-mixin.js";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import settleAllPromises from "@/helpers/layout-helper";
import { Form, defineRule } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import errorMessages from "@/constants/error-messages";
import damageLocationsCms from "@/constants/damage-locations-cms.js";
import damageLocationsSelected from "@/constants/damage-locations-selected.js";
import { useMainStore } from "@/store";
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { Form, defineRule } from 'vee-validate';
import { required } from '@/helpers/validation-rules';
import errorMessages from '@/constants/error-messages';
import damageLocationsCms from '@/constants/damage-locations-cms.js';
import damageLocationsSelected from '@/constants/damage-locations-selected.js';
import { useMainStore } from '@/store';
// DEFINE VALIDATION RULES
defineRule(
"replace-options-required",
required(errorMessages.REPLACE_OPTIONS_REQUIRED)
'replace-options-required',
required(errorMessages.REPLACE_OPTIONS_REQUIRED)
);
export default {
name: "vehicle-damage",
name: 'vehicle-damage',
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
sideDoorOptions,
damageLocationQuestion,
windshieldOptions,
replaceOptionsQuestion,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
alert,
},
mixins: [BaseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
const store = useMainStore();
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const damageOptionsPromise = store.getDamageOptions(
store.order.vehicle.carId
);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "damageOptions",
promise: damageOptionsPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.damageLocation.initializeComponent(resultMap.damageOptions);
vm.$refs.sideDoorOptions.initializeComponent(
resultMap.damageOptions.driverSideOptions.availableReplacementOptions,
resultMap.damageOptions.passengerSideOptions.availableReplacementOptions
);
vm.$refs.windshieldOptions.initializeComponent(
resultMap.damageOptions.windshieldOptions.availableReplacementOptions
);
vm.$refs.backGlassOptions.initializeComponent(
resultMap.damageOptions.backGlassOptions.availableReplacementOptions
);
});
},
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
return {
selectedDamageLocations: this.getDamageLocationsFromStore(),
sideDoorOptionsData: {
selectedDoorSides: this.getDoorSidesFromStore(),
selectedDriverSideReplaceOptions:
this.getDriverSideReplaceOptionsFromStore(),
selectedPassengerSideReplaceOptions:
this.getPassengerSideReplaceOptionsFromStore(),
},
selectedWindshieldOptions: this.getWindshieldOptionsFromStore(),
selectedRearReplaceOptions: this.getRearReplaceOptionsFromStore(),
};
},
computed: {
isWindshieldDamageLocation() {
return this.selectedDamageLocations.some(
(selectedDamages) =>
selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD
);
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
sideDoorOptions,
damageLocationQuestion,
windshieldOptions,
replaceOptionsQuestion,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
alert
},
isSideDoorDamageLocation() {
return this.selectedDamageLocations.some(
(selectedDamages) =>
selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR
);
},
isRearWindowDamageLocation() {
return this.selectedDamageLocations.some(
(selectedDamages) =>
selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW
);
},
isWindshieldRepair() {
return (
this.isWindshieldDamageLocation &&
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR
);
},
isDriverSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
mixins: [BaseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
const store = useMainStore();
return this.sideDoorOptionsData.selectedDoorSides.some(
(selectedDriverSide) =>
selectedDriverSide.toUpperCase() === damageLocationsCms.DRIVERSIDE
);
},
isPassengerSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const damageOptionsPromise = store.getDamageOptions(store.order.vehicle.carId);
return this.sideDoorOptionsData.selectedDoorSides.some(
(selectedPassengerSide) =>
selectedPassengerSide.toUpperCase() ===
damageLocationsCms.PASSENGERSIDE
);
},
hasRepairReplaceConflict() {
return (
this.isWindshieldDamageLocation &&
this.selectedDamageLocations.length > 1 &&
this.isWindshieldRepair
);
},
hasSplitSingleConflict() {
if (
!this.selectedDamageLocations?.includes("Windshield") ||
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR ||
!this.selectedWindshieldOptions.selectedWindshieldReplaceOptions
)
return false;
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
},
{
resultKey: 'damageOptions',
promise: damageOptionsPromise
}
];
return (
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedSingleWindshield) =>
selectedSingleWindshield.toUpperCase() ===
damageLocationsSelected.SINGLE.toUpperCase()
) &&
(this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedDriverWindshield) =>
selectedDriverWindshield.toUpperCase() ===
damageLocationsSelected.DRIVER.toUpperCase()
) ||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedPassengerWindshield) =>
selectedPassengerWindshield.toUpperCase() ===
damageLocationsSelected.PASSENGER.toUpperCase()
))
);
},
shouldDisplayVehicleChangeAlert() {
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
},
},
methods: {
arePagePrerequisitesValid() {
if (useMainStore().order.vehicle.carId) {
return true;
}
return false;
},
getDamageLocationsFromStore() {
const glassSelections = [];
const resultMap = await settleAllPromises(promiseResultMap);
if (
this.mainStore.order.damage.glassToReplace?.some(
(glass) => glass.glassLocation === damageLocationsSelected.WINDSHIELD
) ||
this.mainStore.order.damage.isRepair
) {
glassSelections.push(damageLocationsSelected.WINDSHIELD);
}
if (
this.mainStore.order.damage.glassToReplace?.some(
(glass) =>
glass.glassLocation === damageLocationsSelected.DRIVER ||
glass.glassLocation === damageLocationsSelected.PASSENGER
)
) {
glassSelections.push(damageLocationsSelected.SIDEDOOR);
}
if (
this.mainStore.order.damage.glassToReplace?.some(
(glass) => glass.glassLocation === damageLocationsSelected.REAR
)
) {
glassSelections.push(damageLocationsSelected.REARWINDOW);
}
return glassSelections;
},
getWindshieldOptionsFromStore() {
const windShieldOptions = {
selectedWindshieldDamageType: "",
selectedWindshieldChipCount: null,
selectedWindshieldReplaceOptions: [],
};
if (this.mainStore.order.damage.isRepair === undefined)
return windshieldOptions;
if (this.mainStore.order.damage.isRepair) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPAIR;
windShieldOptions.selectedWindshieldChipCount =
this.mainStore.order.damage.numberOfChips;
} else {
if (
this.mainStore.order.damage.glassToReplace?.some(
(glass) =>
glass.glassLocation === damageLocationsSelected.WINDSHIELD &&
glass.glassName === damageLocationsSelected.SINGLE
)
) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push(
damageLocationsSelected.SINGLE
);
}
if (
this.mainStore.order.damage.glassToReplace?.some(
(glass) =>
glass.glassLocation === damageLocationsSelected.WINDSHIELD &&
glass.glassName === damageLocationsSelected.DRIVER
)
) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push(
damageLocationsSelected.DRIVER
);
}
if (
this.mainStore.order.damage.glassToReplace?.some(
(glass) =>
glass.glassLocation === damageLocationsSelected.WINDSHIELD &&
glass.glassName === damageLocationsSelected.PASSENGER
)
) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push(
damageLocationsSelected.PASSENGER
);
}
}
return windShieldOptions;
},
getDoorSidesFromStore() {
const doorSides = [];
if (
this.mainStore.order.damage.glassToReplace?.some(
(glass) => glass.glassLocation === damageLocationsSelected.DRIVER
)
) {
doorSides.push(damageLocationsSelected.DRIVERSIDE);
}
if (
this.mainStore.order.damage.glassToReplace?.some(
(glass) => glass.glassLocation === damageLocationsSelected.PASSENGER
)
) {
doorSides.push(damageLocationsSelected.PASSENGERSIDE);
}
return doorSides;
},
getDriverSideReplaceOptionsFromStore() {
const driverSideReplaceOptions = [];
this.mainStore.order.damage.glassToReplace?.forEach((glass) => {
if (glass.glassLocation === damageLocationsSelected.DRIVER) {
driverSideReplaceOptions.push(glass.glassName);
}
});
return driverSideReplaceOptions;
},
getPassengerSideReplaceOptionsFromStore() {
const passengerSideReplaceOptions = [];
this.mainStore.order.damage.glassToReplace?.forEach((glass) => {
if (glass.glassLocation === damageLocationsSelected.PASSENGER) {
passengerSideReplaceOptions.push(glass.glassName);
}
});
return passengerSideReplaceOptions;
},
getRearReplaceOptionsFromStore() {
const rearReplaceOptions =
this.mainStore.order.damage.glassToReplace?.filter(
(glass) => glass.glassLocation === damageLocationsSelected.REAR
)[0]?.glassName;
return rearReplaceOptions;
},
async forwardButtonAction() {
this.mainStore.saveVehicleDamage(
this.isWindshieldRepair,
this.selectedGlassToReplace(),
this.selectedWindshieldOptions.selectedWindshieldChipCount
);
if (this.isWindshieldRepair) {
const supportingItems = await useMainStore().getSupportingItems();
useMainStore().updateSupportingItems(supportingItems.data);
}
if (this.mainStore.damage.isRepair) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR,
this.$route
);
} else if (this.mainStore.order.vehicle.vin) {
// If vin already exists, navigate directly to vin-lookup
const partsOrQuestionsResponse = await this.getPartsOrQuestions();
if (partsOrQuestionsResponse.error) {
// To Do: Need requirement on what to do here
window.console.error("Error on retrieving PartsOrQuestions");
this.$refs.siteFooter.removeLoader();
return null;
}
// Comes from vehicleQuestionsMixin.navigateForward()
await this.navigateForward(
partsOrQuestionsResponse.data.partsOrQuestions,
this
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
this.$route
);
}
return null;
},
selectedGlassToReplace() {
const selectedGlassToReplace = [];
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair) {
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(
(wsItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.WINDSHIELD,
glassName: wsItem,
});
}
);
}
if (this.isDriverSideReplace) {
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach(
(driverItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.DRIVER,
glassName: driverItem,
});
}
);
}
if (this.isPassengerSideReplace) {
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(
(passengerItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.PASSENGER,
glassName: passengerItem,
});
}
);
}
if (this.isRearWindowDamageLocation) {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.REAR,
glassName: this.selectedRearReplaceOptions,
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.damageLocation.initializeComponent(resultMap.damageOptions);
vm.$refs.sideDoorOptions.initializeComponent(
resultMap.damageOptions.driverSideOptions.availableReplacementOptions,
resultMap.damageOptions.passengerSideOptions.availableReplacementOptions
);
vm.$refs.windshieldOptions.initializeComponent(resultMap.damageOptions.windshieldOptions.availableReplacementOptions);
vm.$refs.backGlassOptions.initializeComponent(resultMap.damageOptions.backGlassOptions.availableReplacementOptions);
});
}
return selectedGlassToReplace;
},
},
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
return {
selectedDamageLocations: this.getDamageLocationsFromStore(),
sideDoorOptionsData: {
selectedDoorSides: this.getDoorSidesFromStore(),
selectedDriverSideReplaceOptions:
this.getDriverSideReplaceOptionsFromStore(),
selectedPassengerSideReplaceOptions:
this.getPassengerSideReplaceOptionsFromStore()
},
selectedWindshieldOptions: this.getWindshieldOptionsFromStore(),
selectedRearReplaceOptions: this.getRearReplaceOptionsFromStore()
};
},
computed: {
isWindshieldDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) =>
selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD);
},
isSideDoorDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) =>
selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR);
},
isRearWindowDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) =>
selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW);
},
isWindshieldRepair() {
return (
this.isWindshieldDamageLocation
&& this.selectedWindshieldOptions.selectedWindshieldDamageType
=== damageLocationsSelected.REPAIR
);
},
isDriverSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedDriverSide) =>
selectedDriverSide.toUpperCase() === damageLocationsCms.DRIVERSIDE);
},
isPassengerSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedPassengerSide) =>
selectedPassengerSide.toUpperCase()
=== damageLocationsCms.PASSENGERSIDE);
},
hasRepairReplaceConflict() {
return (
this.isWindshieldDamageLocation
&& this.selectedDamageLocations.length > 1
&& this.isWindshieldRepair
);
},
hasSplitSingleConflict() {
if (
!this.selectedDamageLocations?.includes('Windshield')
|| this.selectedWindshieldOptions.selectedWindshieldDamageType
=== damageLocationsSelected.REPAIR
|| !this.selectedWindshieldOptions.selectedWindshieldReplaceOptions
) return false;
return (
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some((selectedSingleWindshield) =>
selectedSingleWindshield.toUpperCase()
=== damageLocationsSelected.SINGLE.toUpperCase())
&& (this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some((selectedDriverWindshield) =>
selectedDriverWindshield.toUpperCase()
=== damageLocationsSelected.DRIVER.toUpperCase())
|| this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some((selectedPassengerWindshield) =>
selectedPassengerWindshield.toUpperCase()
=== damageLocationsSelected.PASSENGER.toUpperCase()))
);
},
shouldDisplayVehicleChangeAlert() {
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
}
},
methods: {
arePagePrerequisitesValid() {
if (useMainStore().order.vehicle.carId) {
return true;
}
return false;
},
getDamageLocationsFromStore() {
const glassSelections = [];
if (
this.mainStore.order.damage.glassToReplace?.some((glass) => glass.glassLocation === damageLocationsSelected.WINDSHIELD)
|| this.mainStore.order.damage.isRepair
) {
glassSelections.push(damageLocationsSelected.WINDSHIELD);
}
if (
this.mainStore.order.damage.glassToReplace?.some((glass) =>
glass.glassLocation === damageLocationsSelected.DRIVER
|| glass.glassLocation === damageLocationsSelected.PASSENGER)
) {
glassSelections.push(damageLocationsSelected.SIDEDOOR);
}
if (
this.mainStore.order.damage.glassToReplace?.some((glass) => glass.glassLocation === damageLocationsSelected.REAR)
) {
glassSelections.push(damageLocationsSelected.REARWINDOW);
}
return glassSelections;
},
getWindshieldOptionsFromStore() {
const windShieldOptions = {
selectedWindshieldDamageType: '',
selectedWindshieldChipCount: null,
selectedWindshieldReplaceOptions: []
};
if (this.mainStore.order.damage.isRepair === undefined) return windshieldOptions;
if (this.mainStore.order.damage.isRepair) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPAIR;
windShieldOptions.selectedWindshieldChipCount =
this.mainStore.order.damage.numberOfChips;
} else {
if (
this.mainStore.order.damage.glassToReplace?.some((glass) =>
glass.glassLocation === damageLocationsSelected.WINDSHIELD
&& glass.glassName === damageLocationsSelected.SINGLE)
) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push(damageLocationsSelected.SINGLE);
}
if (
this.mainStore.order.damage.glassToReplace?.some((glass) =>
glass.glassLocation === damageLocationsSelected.WINDSHIELD
&& glass.glassName === damageLocationsSelected.DRIVER)
) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push(damageLocationsSelected.DRIVER);
}
if (
this.mainStore.order.damage.glassToReplace?.some((glass) =>
glass.glassLocation === damageLocationsSelected.WINDSHIELD
&& glass.glassName === damageLocationsSelected.PASSENGER)
) {
windShieldOptions.selectedWindshieldDamageType =
damageLocationsSelected.REPLACE;
windShieldOptions.selectedWindshieldReplaceOptions.push(damageLocationsSelected.PASSENGER);
}
}
return windShieldOptions;
},
getDoorSidesFromStore() {
const doorSides = [];
if (
this.mainStore.order.damage.glassToReplace?.some((glass) => glass.glassLocation === damageLocationsSelected.DRIVER)
) {
doorSides.push(damageLocationsSelected.DRIVERSIDE);
}
if (
this.mainStore.order.damage.glassToReplace?.some((glass) => glass.glassLocation === damageLocationsSelected.PASSENGER)
) {
doorSides.push(damageLocationsSelected.PASSENGERSIDE);
}
return doorSides;
},
getDriverSideReplaceOptionsFromStore() {
const driverSideReplaceOptions = [];
this.mainStore.order.damage.glassToReplace?.forEach((glass) => {
if (glass.glassLocation === damageLocationsSelected.DRIVER) {
driverSideReplaceOptions.push(glass.glassName);
}
});
return driverSideReplaceOptions;
},
getPassengerSideReplaceOptionsFromStore() {
const passengerSideReplaceOptions = [];
this.mainStore.order.damage.glassToReplace?.forEach((glass) => {
if (glass.glassLocation === damageLocationsSelected.PASSENGER) {
passengerSideReplaceOptions.push(glass.glassName);
}
});
return passengerSideReplaceOptions;
},
getRearReplaceOptionsFromStore() {
const rearReplaceOptions =
this.mainStore.order.damage.glassToReplace?.filter((glass) => glass.glassLocation === damageLocationsSelected.REAR)[0]?.glassName;
return rearReplaceOptions;
},
async forwardButtonAction() {
this.mainStore.saveVehicleDamage(
this.isWindshieldRepair,
this.selectedGlassToReplace(),
this.selectedWindshieldOptions.selectedWindshieldChipCount
);
if (this.isWindshieldRepair) {
const supportingItems = await useMainStore().getSupportingItems();
useMainStore().updateSupportingItems(supportingItems.data);
}
if (this.mainStore.damage.isRepair) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR,
this.$route
);
} else if (this.mainStore.order.vehicle.vin) {
// If vin already exists, navigate directly to vin-lookup
const partsOrQuestionsResponse = await this.getPartsOrQuestions();
if (partsOrQuestionsResponse.error) {
// To Do: Need requirement on what to do here
window.console.error('Error on retrieving PartsOrQuestions');
this.$refs.siteFooter.removeLoader();
return null;
}
// Comes from vehicleQuestionsMixin.navigateForward()
await this.navigateForward(
partsOrQuestionsResponse.data.partsOrQuestions,
this
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
this.$route
);
}
return null;
},
selectedGlassToReplace() {
const selectedGlassToReplace = [];
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair) {
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach((wsItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.WINDSHIELD,
glassName: wsItem
});
});
}
if (this.isDriverSideReplace) {
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach((driverItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.DRIVER,
glassName: driverItem
});
});
}
if (this.isPassengerSideReplace) {
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach((passengerItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.PASSENGER,
glassName: passengerItem
});
});
}
if (this.isRearWindowDamageLocation) {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.REAR,
glassName: this.selectedRearReplaceOptions
});
}
return selectedGlassToReplace;
}
}
};
</script>

View file

@ -1,5 +1,7 @@
<template>
<Form @submit="onSubmit" @invalidSubmit="onInvalidSubmit">
<Form
@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">
@ -12,25 +14,21 @@
<VehicleBanner
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
/>
:displayGenericVehicleImage="false" />
<SiteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-5 mb-2"
/>
class="mt-5 mb-2" />
<VinLookupMethods
ref="VinLookupMethods"
v-model="selectedVinLookupMethod"
cmsWidgetName="VINLookupMethod"
groupName="VinLookupMethods"
/>
groupName="VinLookupMethods" />
<SiteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="isForwardActionDisabled"
class="mt-5"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
/>
@forwardClicked="forwardButtonAction" />
</div>
</div>
</div>
@ -39,88 +37,88 @@
</template>
<script>
// Import Supporting Files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import settleAllPromises from "@/helpers/layout-helper";
import { Form } from "vee-validate";
import BaseFormMixin from "@/mixins/base-form-mixin";
import vinLookupMethodSelections from "@/constants/vin-lookup-methods";
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin';
import vinLookupMethodSelections from '@/constants/vin-lookup-methods';
// Import Component
import SiteFooter from "@/iss-components/site-footer/site-footer.vue";
import SiteHeader from "@/iss-components/site-header/site-header.vue";
import SiteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue";
import VehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner.vue";
import VinLookupMethods from "@/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue";
import SiteFooter from '@/iss-components/site-footer/site-footer.vue';
import SiteHeader from '@/iss-components/site-header/site-header.vue';
import SiteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import VehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import VinLookupMethods from '@/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue';
export default {
name: "vehicle-lookup",
components: {
name: 'vehicle-lookup',
components: {
// eslint-disable-next-line vue/no-reserved-component-names
Form,
SiteFooter,
SiteHeader,
SiteSubHeader,
VehicleBanner,
VinLookupMethods,
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.VinLookupMethods.initializeComponent();
});
},
data() {
return {
selectedVinLookupMethod: null,
};
},
computed: {
isForwardActionDisabled() {
return this.selectedVinLookupMethod === null;
Form,
SiteFooter,
SiteHeader,
SiteSubHeader,
VehicleBanner,
VinLookupMethods
},
},
methods: {
arePagePrerequisiteValid() {
return true;
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
}
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.$refs.VinLookupMethods.initializeComponent();
});
},
forwardButtonAction() {
switch (this.selectedVinLookupMethod) {
case vinLookupMethodSelections.MANUALVIN:
this.$router.navigate(
this.navigationScenarios.SELECTED_MANUAL_VIN,
this.$route
);
break;
case vinLookupMethodSelections.LICENSEPLATE:
this.$router.navigate(
this.navigationScenarios.SELECTED_LICENSE_PLATE,
this.$route
);
break;
case vinLookupMethodSelections.HOMEADDRESS:
this.$router.navigate(
this.navigationScenarios.SELECTED_HOME_ADDRESS,
this.$route
);
break;
default:
break;
}
data() {
return {
selectedVinLookupMethod: null
};
},
resetDependentState() {},
},
computed: {
isForwardActionDisabled() {
return this.selectedVinLookupMethod === null;
}
},
methods: {
arePagePrerequisiteValid() {
return true;
},
forwardButtonAction() {
switch (this.selectedVinLookupMethod) {
case vinLookupMethodSelections.MANUALVIN:
this.$router.navigate(
this.navigationScenarios.SELECTED_MANUAL_VIN,
this.$route
);
break;
case vinLookupMethodSelections.LICENSEPLATE:
this.$router.navigate(
this.navigationScenarios.SELECTED_LICENSE_PLATE,
this.$route
);
break;
case vinLookupMethodSelections.HOMEADDRESS:
this.$router.navigate(
this.navigationScenarios.SELECTED_HOME_ADDRESS,
this.$route
);
break;
default:
break;
}
},
resetDependentState() {}
}
};
</script>

View file

@ -1,5 +1,8 @@
<template>
<Form ref="theForm" @submit="onSubmit" @invalidSubmit="onInvalidSubmit">
<Form
ref="theForm"
@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">
@ -12,12 +15,10 @@
ref="vehicleBanner"
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false"
/>
:displayGenericVehicleImage="false" />
<siteSubHeader
ref="siteSubHeader"
cmsWidgetName="SiteSubHeaderWidget"
/>
cmsWidgetName="SiteSubHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
@ -27,9 +28,10 @@
class="mt-3 mb-3"
alertClass="alert-warning"
cmsWidgetName="AlertWidget"
:isDismissible="false"
/>
<div v-for="(item, i) in PartsOrQuestions" :key="i">
:isDismissible="false" />
<div
v-for="(item, i) in PartsOrQuestions"
:key="i">
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
<hr v-if="i > 0" />
<glassPartQuestion
@ -40,8 +42,7 @@
:glassLocation="item.glassLocation"
:glassName="item.glassName"
:colorAnswers="item.colorAnswers"
:alreadyPopulatedPartsData="alreadyPopulatedPartsData"
/>
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
</div>
<siteFooter
ref="siteFooter"
@ -49,8 +50,7 @@
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="isForwardActionDisabled"
@backClicked="navigateBackByVehicleQuestions"
@ForwardClicked="forwardButtonAction"
/>
@ForwardClicked="forwardButtonAction" />
</div>
</div>
</div>
@ -59,187 +59,182 @@
<script>
// Components
import glassPartQuestion from "@/layouts/vehicle-parts/glass-part-question/glass-part-question.vue";
import siteHeader from "@/iss-components/site-header/site-header.vue";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner.vue";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import alert from "@/ux-components/alert/alert.vue";
import glassPartQuestion from '@/layouts/vehicle-parts/glass-part-question/glass-part-question.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import alert from '@/ux-components/alert/alert.vue';
// Supporting Files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import settleAllPromises from "@/helpers/layout-helper";
import issPageValues from "@/router/router-constants/issPage-values";
import { Form } from "vee-validate";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import BaseFormMixin from "@/mixins/base-form-mixin.js";
import { useMainStore } from "@/store";
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import issPageValues from '@/router/router-constants/issPage-values';
import { Form } from 'vee-validate';
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store';
export default {
name: "vehicle-parts",
components: {
name: 'vehicle-parts',
components: {
// eslint-disable-next-line vue/no-reserved-component-names
Form,
glassPartQuestion,
siteHeader,
vehicleBanner,
siteSubHeader,
siteFooter,
alert,
},
mixins: [BaseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
Form,
glassPartQuestion,
siteHeader,
vehicleBanner,
siteSubHeader,
siteFooter,
alert
},
mixins: [BaseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
}
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
// Glass Part Question dynamic component
Object.keys(vm.$refs)
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
.forEach((c) =>
vm.$refs[c][0].initializeComponent({
ColorQuestionWidget: resultMap.cmsContent.ColorQuestionWidget,
FeatureQuestionWidget: resultMap.cmsContent.FeatureQuestionWidget,
})
);
});
},
data() {
return {
selectedGlassParts: {},
alertWidgetData: Object,
alreadyPopulatedPartsData: [],
};
},
computed: {
isForwardActionDisabled() {
return (
this.selectedGlassPartNumbers?.length !==
this.PartsFromApi.partsOrQuestions?.length
);
// Glass Part Question dynamic component
Object.keys(vm.$refs)
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
.forEach((c) =>
vm.$refs[c][0].initializeComponent({
ColorQuestionWidget: resultMap.cmsContent.ColorQuestionWidget,
FeatureQuestionWidget: resultMap.cmsContent.FeatureQuestionWidget
}));
});
},
selectedGlassPartNumbers() {
// Compile all selected parts from the page.
const numberArray = [];
// eslint-disable-next-line no-restricted-syntax
for (const glassPart of Object.values(this.selectedGlassParts)) {
if (glassPart?.partNumber) {
numberArray.push(glassPart.partNumber);
data() {
return {
selectedGlassParts: {},
alertWidgetData: Object,
alreadyPopulatedPartsData: []
};
},
computed: {
isForwardActionDisabled() {
return (
this.selectedGlassPartNumbers?.length
!== this.PartsFromApi.partsOrQuestions?.length
);
},
selectedGlassPartNumbers() {
// Compile all selected parts from the page.
const numberArray = [];
// eslint-disable-next-line no-restricted-syntax
for (const glassPart of Object.values(this.selectedGlassParts)) {
if (glassPart?.partNumber) {
numberArray.push(glassPart.partNumber);
}
}
return numberArray;
},
PartsOrQuestions() {
const partsData = this.PartsFromApi;
// Map API result data, to vehicle-parts data structure
const mappedData = partsData.partsOrQuestions?.map((g) => ({
glassName: g.glassName,
glassLocation: g.glassLocation,
colorAnswers: g.parts?.reduce((arr, p) => {
arr.push({
ColorAnswerText: p.color,
FeatureAnswers: [
{
FeatureAnswerText:
p.description === '' ? p.color : p.description,
PartNumber: p.partNumber
}
]
});
return arr;
}, [])
}));
return mappedData;
},
PartsFromApi() {
return this.mainStore.pageData(issPageValues.VEHICLE_PARTS);
},
RefPrefix() {
return 'partQuestion';
}
}
return numberArray;
},
PartsOrQuestions() {
const partsData = this.PartsFromApi;
// Map API result data, to vehicle-parts data structure
const mappedData = partsData.partsOrQuestions?.map((g) => ({
glassName: g.glassName,
glassLocation: g.glassLocation,
colorAnswers: g.parts?.reduce((arr, p) => {
arr.push({
ColorAnswerText: p.color,
FeatureAnswers: [
{
FeatureAnswerText:
p.description === "" ? p.color : p.description,
PartNumber: p.partNumber,
},
],
});
return arr;
}, []),
}));
return mappedData;
mounted() {
this.LoadInitialPartsData();
},
methods: {
arePagePrerequisitesValid() {
// Check if isRepair is populated and if the pageData we need is here (Parts data)
return (
useMainStore().damage.isRepair != null
&& useMainStore().pageData(issPageValues.VEHICLE_PARTS)
&& Object.keys(useMainStore().pageData(issPageValues.VEHICLE_PARTS))
.length !== 0
);
},
async forwardButtonAction() {
const matchedParts = [];
PartsFromApi() {
return this.mainStore.pageData(issPageValues.VEHICLE_PARTS);
},
RefPrefix() {
return "partQuestion";
},
},
mounted() {
this.LoadInitialPartsData();
},
methods: {
arePagePrerequisitesValid() {
// Check if isRepair is populated and if the pageData we need is here (Parts data)
return (
useMainStore().damage.isRepair != null &&
useMainStore().pageData(issPageValues.VEHICLE_PARTS) &&
Object.keys(useMainStore().pageData(issPageValues.VEHICLE_PARTS))
.length !== 0
);
},
async forwardButtonAction() {
const matchedParts = [];
// Match them to the parts from the API.
// eslint-disable-next-line no-restricted-syntax
for (const [key, value] of Object.entries(
this.PartsFromApi.partsOrQuestions
)) {
// eslint-disable-next-line no-restricted-syntax
for (const [partKey, partValue] of Object.entries(value.parts)) {
const currentPart =
// Match them to the parts from the API.
// eslint-disable-next-line no-restricted-syntax
for (const [key, value] of Object.entries(this.PartsFromApi.partsOrQuestions)) {
// eslint-disable-next-line no-restricted-syntax
for (const [partKey, partValue] of Object.entries(value.parts)) {
const currentPart =
this.PartsFromApi.partsOrQuestions[key].parts[partKey];
const isMatched = this.selectedGlassPartNumbers.some(
(p) => p === currentPart.partNumber
);
const isMatched = this.selectedGlassPartNumbers.some((p) => p === currentPart.partNumber);
if (isMatched) {
matchedParts.push({
glassLocation: value.glassLocation,
glassName: value.glassName,
parts: [currentPart],
});
}
}
}
// If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts)
if (this.isForwardActionDisabled) {
this.$refs.siteFooter.removeLoader();
throw new Error("Could not match any parts to the selected parts");
}
this.navigateForward(matchedParts, null);
},
LoadInitialPartsData() {
const partsData = this.PartsFromApi;
this.alreadyPopulatedPartsData =
this.mainStore.lineItems.glassParts === null
? []
: this.mainStore.lineItems.glassParts;
partsData.partsOrQuestions.map((g) => {
// If the part is already populated, use the value from the store and populate the v-model.
Object.keys(this.alreadyPopulatedPartsData).forEach((key) => {
const { partNumber } = this.alreadyPopulatedPartsData[key];
g.parts.forEach((p) => {
if (p.partNumber === partNumber) {
this.selectedGlassParts[`${g.glassLocation}-${g.glassName}`] = p;
if (isMatched) {
matchedParts.push({
glassLocation: value.glassLocation,
glassName: value.glassName,
parts: [currentPart]
});
}
}
}
});
});
});
},
},
// If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts)
if (this.isForwardActionDisabled) {
this.$refs.siteFooter.removeLoader();
throw new Error('Could not match any parts to the selected parts');
}
this.navigateForward(matchedParts, null);
},
LoadInitialPartsData() {
const partsData = this.PartsFromApi;
this.alreadyPopulatedPartsData =
this.mainStore.lineItems.glassParts === null
? []
: this.mainStore.lineItems.glassParts;
partsData.partsOrQuestions.map((g) => {
// If the part is already populated, use the value from the store and populate the v-model.
Object.keys(this.alreadyPopulatedPartsData).forEach((key) => {
const { partNumber } = this.alreadyPopulatedPartsData[key];
g.parts.forEach((p) => {
if (p.partNumber === partNumber) {
this.selectedGlassParts[`${g.glassLocation}-${g.glassName}`] = p;
}
});
});
});
}
}
};
</script>
<style lang="scss" scoped>

View file

@ -3,12 +3,13 @@
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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 class="mb-2 header" cmsWidgetName="SiteHeaderWidget" />
<siteHeader
class="mb-2 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
@ -17,8 +18,7 @@
cmsWidgetName="SiteSubHeaderWidget"
class="siteSubHeader"
justification="center"
darkGraySubText
/>
darkGraySubText />
<vehicleQuestion
ref="vehicleYearQuestion"
@ -27,8 +27,7 @@
cmsWidgetName="VehicleYearQuestion"
:updateValues="updateYearValues"
validationRules="year-required"
inputId="yearQuestionField"
/>
inputId="yearQuestionField" />
<vehicleQuestion
ref="vehicleMakeQuestion"
v-model="selectedMake"
@ -36,8 +35,7 @@
cmsWidgetName="VehicleMakeQuestion"
:updateValues="updateMakeValues"
validationRules="make-required"
inputId="makeQuestionField"
/>
inputId="makeQuestionField" />
<vehicleQuestion
ref="vehicleModelQuestion"
v-model="selectedModel"
@ -45,8 +43,7 @@
cmsWidgetName="VehicleModelQuestion"
:updateValues="updateModelValues"
validationRules="model-required"
inputId="modelQuestionField"
/>
inputId="modelQuestionField" />
<vehicleQuestion
ref="vehicleStyleQuestion"
v-model="selectedStyle"
@ -54,15 +51,13 @@
cmsWidgetName="VehicleStyleQuestion"
:updateValues="updateStyleValues"
validationRules="style-required"
inputId="styleQuestionField"
/>
inputId="styleQuestionField" />
<vehicleBanner
ref="banner"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="displayGeneric"
class="mt-5 mb-3"
/>
class="mt-5 mb-3" />
<siteFooter
ref="siteFooter"
@ -70,8 +65,7 @@
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
@backClicked="navigateBack"
/>
@backClicked="navigateBack" />
</div>
</div>
</div>
@ -80,154 +74,154 @@
<script>
// Components
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 vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner.vue";
import vehicleQuestion from "@/layouts/vehicle-selection/vehicle-question/vehicle-question.vue";
import { useMainStore } from "@/store";
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 vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import vehicleQuestion from '@/layouts/vehicle-selection/vehicle-question/vehicle-question.vue';
import { useMainStore } from '@/store';
// Supporting files
import baseFormMixin from "@/mixins/base-form-mixin.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import settleAllPromises from "@/helpers/layout-helper";
import { Form, defineRule } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import errorMessages from "@/constants/error-messages";
import baseFormMixin from '@/mixins/base-form-mixin.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { Form, defineRule } from 'vee-validate';
import { required } from '@/helpers/validation-rules';
import errorMessages from '@/constants/error-messages';
// define validation rules
defineRule("year-required", required(errorMessages.YEAR_REQUIRED));
defineRule("make-required", required(errorMessages.MAKE_REQUIRED));
defineRule("model-required", required(errorMessages.MODEL_REQUIRED));
defineRule("style-required", required(errorMessages.STYLE_REQUIRED));
defineRule('year-required', required(errorMessages.YEAR_REQUIRED));
defineRule('make-required', required(errorMessages.MAKE_REQUIRED));
defineRule('model-required', required(errorMessages.MODEL_REQUIRED));
defineRule('style-required', required(errorMessages.STYLE_REQUIRED));
export default {
name: "vehicle-selection",
components: {
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
vehicleQuestion,
},
mixins: [baseFormMixin],
name: 'vehicle-selection',
components: {
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
vehicleQuestion
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
}
];
const resultMap = await settleAllPromises(promiseResultMap);
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
props: {
cmsWidgetName: String,
validationRules: String,
},
data() {
const { year, make, model, style } = useMainStore().order.vehicle;
return {
selectedYear: year,
selectedMake: make,
selectedModel: model,
selectedStyle: style,
};
},
computed: {
displayGeneric() {
return !this.selectedStyle;
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
},
watch: {
selectedYear(value) {
this.mainStore.updateVehicleYear(value);
this.$refs.vehicleMakeQuestion.clearValues();
if (value) {
this.$refs.vehicleMakeQuestion.getNewValues();
}
props: {
cmsWidgetName: String,
validationRules: String
},
selectedMake(value) {
this.mainStore.updateVehicleMake(value);
this.$refs.vehicleModelQuestion.clearValues();
if (value) {
this.$refs.vehicleModelQuestion.getNewValues();
}
data() {
const { year, make, model, style } = useMainStore().order.vehicle;
return {
selectedYear: year,
selectedMake: make,
selectedModel: model,
selectedStyle: style
};
},
selectedModel(value) {
this.mainStore.updateVehicleModel(value);
this.$refs.vehicleStyleQuestion.clearValues();
if (value) {
this.$refs.vehicleStyleQuestion.getNewValues();
}
},
selectedStyle(value) {
this.mainStore.updateVehicleStyle(value);
this.mainStore.setVehicle();
},
},
mounted() {
this.$refs.vehicleYearQuestion.getNewValues();
if (this.selectedYear) {
this.$refs.vehicleMakeQuestion.getNewValues();
}
if (this.selectedMake) {
this.$refs.vehicleModelQuestion.getNewValues();
}
if (this.selectedModel) {
this.$refs.vehicleStyleQuestion.getNewValues();
}
},
methods: {
arePagePrerequisitesValid() {
return true;
},
async forwardButtonAction() {
return this.navigateForward();
},
navigateForward() {
this.mainStore.setVehicle().then(() => {
if (this.mainStore.isBailout) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
return;
computed: {
displayGeneric() {
return !this.selectedStyle;
}
},
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
});
watch: {
selectedYear(value) {
this.mainStore.updateVehicleYear(value);
this.$refs.vehicleMakeQuestion.clearValues();
if (value) {
this.$refs.vehicleMakeQuestion.getNewValues();
}
},
selectedMake(value) {
this.mainStore.updateVehicleMake(value);
this.$refs.vehicleModelQuestion.clearValues();
if (value) {
this.$refs.vehicleModelQuestion.getNewValues();
}
},
selectedModel(value) {
this.mainStore.updateVehicleModel(value);
this.$refs.vehicleStyleQuestion.clearValues();
if (value) {
this.$refs.vehicleStyleQuestion.getNewValues();
}
},
selectedStyle(value) {
this.mainStore.updateVehicleStyle(value);
this.mainStore.setVehicle();
}
},
async updateYearValues() {
return useMainStore().getVehicleYears();
mounted() {
this.$refs.vehicleYearQuestion.getNewValues();
if (this.selectedYear) {
this.$refs.vehicleMakeQuestion.getNewValues();
}
if (this.selectedMake) {
this.$refs.vehicleModelQuestion.getNewValues();
}
if (this.selectedModel) {
this.$refs.vehicleStyleQuestion.getNewValues();
}
},
async updateMakeValues() {
return this.mainStore.getVehicleMakes();
},
async updateModelValues() {
return this.mainStore.getVehicleModels();
},
async updateStyleValues() {
return this.mainStore.getVehicleStyles();
},
},
methods: {
arePagePrerequisitesValid() {
return true;
},
async forwardButtonAction() {
return this.navigateForward();
},
navigateForward() {
this.mainStore.setVehicle().then(() => {
if (this.mainStore.isBailout) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
return;
}
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
});
},
async updateYearValues() {
return useMainStore().getVehicleYears();
},
async updateMakeValues() {
return this.mainStore.getVehicleMakes();
},
async updateModelValues() {
return this.mainStore.getVehicleModels();
},
async updateStyleValues() {
return this.mainStore.getVehicleStyles();
}
}
};
</script>

View file

@ -3,8 +3,7 @@
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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">
@ -17,19 +16,16 @@
<vehicleBanner
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="!carIdIsValid"
/>
:displayGenericVehicleImage="!carIdIsValid" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<vinLookupAlerts
class="mt-5"
:activeAlertType="activeVehicleLookupAlertType"
/>
:activeAlertType="activeVehicleLookupAlertType" />
<vinQuestion
v-model="vin"
:mask="vinMask"
:isDisabled="vinPopulatedOnPageLoad"
textPosition="left"
/>
textPosition="left" />
<vinLocationInformation />
<siteFooter
ref="siteFooter"
@ -37,8 +33,7 @@
:isForwardActionDisabled="!meta.valid"
class="mt-5"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
/>
@forwardClicked="forwardButtonAction" />
</div>
</div>
</div>
@ -47,262 +42,256 @@
</template>
<script>
// Import Supporting Files
import { computed } from "vue";
import vehicleLookupAlertTypes from "@/constants/vehicle-lookup-alert-types";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { isGlassAvailableForCarId } from "@/helpers/damage-helper";
import settleAllPromises from "@/helpers/layout-helper";
import routerParams from "@/router/router-constants/router-params";
import { useMainStore } from "@/store";
import { computed } from 'vue';
import vehicleLookupAlertTypes from '@/constants/vehicle-lookup-alert-types';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { isGlassAvailableForCarId } from '@/helpers/damage-helper';
import settleAllPromises from '@/helpers/layout-helper';
import routerParams from '@/router/router-constants/router-params';
import { useMainStore } from '@/store';
// Import Component
import baseFormMixin from "@/mixins/base-form-mixin";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { Form } from "vee-validate";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import siteHeader from "@/iss-components/site-header/site-header.vue";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue";
import vehicleBanner from "@/iss-components/vehicle-banner/vehicle-banner.vue";
import vinLocationInformation from "@/layouts/vin-lookup/vin-location-information/vin-location-information.vue";
import vinLookupAlerts from "@/layouts/vin-lookup/vin-lookup-alerts/vin-lookup-alerts.vue";
import vinQuestion from "@/layouts/vin-lookup/vin-question/vin-question.vue";
import bailoutCode from "@/constants/bailoutCode";
import bailoutMessage from "@/constants/bailoutMessage";
import baseFormMixin from '@/mixins/base-form-mixin';
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
import { Form } from 'vee-validate';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import vinLocationInformation from '@/layouts/vin-lookup/vin-location-information/vin-location-information.vue';
import vinLookupAlerts from '@/layouts/vin-lookup/vin-lookup-alerts/vin-lookup-alerts.vue';
import vinQuestion from '@/layouts/vin-lookup/vin-question/vin-question.vue';
import bailoutCode from '@/constants/bailoutCode';
import bailoutMessage from '@/constants/bailoutMessage';
export default {
name: "vin-lookup",
components: {
siteFooter,
siteHeader,
siteSubHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
vehicleBanner,
vinLocationInformation,
vinLookupAlerts,
vinQuestion,
},
mixins: [baseFormMixin, vehicleQuestionsMixin],
provide() {
return {
vehicleFromLookup: computed(() => this.vehicleFromLookup),
};
},
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
const vin = this.getVinFromStore();
return {
activeVehicleLookupAlertType:
vin?.length > 0 && !this.hasValidCarId()
? vehicleLookupAlertTypes.NOT_FOUND
: null,
needToLookupVehicle: true,
vehicleFromLookup: null,
vinWithNonMatchingCarId: vin?.length > 0 && !this.hasValidCarId(),
vin,
forwardButtonCarStyle: "",
vinPopulatedOnPageLoad: vin?.length > 0 && this.hasValidCarId(),
};
},
computed: {
isCarIdDifferentFromTheStore() {
return (
this.vehicleFromLookup !== null &&
this.hasValidCarId() &&
this.vehicleFromLookup.carId !== this.mainStore.vehicle.carId
);
name: 'vin-lookup',
components: {
siteFooter,
siteHeader,
siteSubHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
vehicleBanner,
vinLocationInformation,
vinLookupAlerts,
vinQuestion
},
isTwoIdenticalYMMVehicleFound() {
if (this.vehicleFromLookup === null) {
return false;
}
const vinYmmFound = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return vinYmmFound.toLowerCase() === vinYmmExpected.toLowerCase();
mixins: [baseFormMixin, vehicleQuestionsMixin],
provide() {
return {
vehicleFromLookup: computed(() => this.vehicleFromLookup)
};
},
vinMask() {
// TODO: Side effects in computed.
if (this.vinPopulatedOnPageLoad) {
// TODO: Modify to remove side effects in computed
this.activeVehicleLookupAlertType =
vehicleLookupAlertTypes.PERFECT_MATCH;
this.needToLookupVehicle = false;
const lastSixChars = this.vin.substring(11, this.vin.length);
return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
}
return "*****************";
},
carIdIsValid() {
return this.hasValidCarId();
},
},
watch: {
vin() {
this.resetActiveAlert();
this.$refs.siteFooter.enableForwardAction();
this.needToLookupVehicle = true;
this.$refs.siteFooter.updateButtonText(
this.getCmsContent("SiteFooterWidget", "ForwardButtonText")
);
},
},
methods: {
arePagePrerequisiteValid() {
return true;
},
getVinFromStore() {
return this.mainStore.vehicle.vin;
},
hasValidCarId() {
return (
this.mainStore.vehicle.carId && this.mainStore.vehicle.carId !== "0"
);
},
// NOTE: If form is not valid, this method is not called when 'Continue' button is clicked
async forwardButtonAction() {
this.resetActiveAlert();
// Temp solution to reset the 'disabled' style on the Continue button
this.$refs.siteFooter.enableForwardAction();
async beforeRouteEnter(to, from, next) {
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
if (this.needToLookupVehicle) {
const vehicleLookupResponse = await this.lookupVehicleByVin(this.vin);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
}
];
if (vehicleLookupResponse.error) {
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.NOT_FOUND;
this.mainStore.setBailout(bailoutMessage.vehicleNotFound(this.vin));
this.resetVehicleFromLookup();
this.$refs.siteFooter.removeLoader();
// Temp solution to turn on 'disabled' style on the Continue button
// because the form itself actually passes its client-side validation.
// SSR-189 Scenario #4.
this.$refs.siteFooter.enableForwardAction();
return;
}
const resultMap = await settleAllPromises(promiseResultMap);
this.mainStore.resetBailout();
// Add vin bcs the response from the service doesn't contain vin
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, {
vin: this.vin,
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
}
},
setup() {
const mainStore = useMainStore();
if (this.needToLookupVehicle && this.isCarIdDifferentFromTheStore) {
if (this.isTwoIdenticalYMMVehicleFound) {
this.activeVehicleLookupAlertType =
vehicleLookupAlertTypes.TWO_IDENTICAL_YMM_MATCHED;
this.forwardButtonCarStyle = this.vehicleFromLookup.style;
} else {
this.activeVehicleLookupAlertType =
vehicleLookupAlertTypes.NOT_MATCHED;
return { mainStore };
},
data() {
const vin = this.getVinFromStore();
return {
activeVehicleLookupAlertType:
vin?.length > 0 && !this.hasValidCarId()
? vehicleLookupAlertTypes.NOT_FOUND
: null,
needToLookupVehicle: true,
vehicleFromLookup: null,
vinWithNonMatchingCarId: vin?.length > 0 && !this.hasValidCarId(),
vin,
forwardButtonCarStyle: '',
vinPopulatedOnPageLoad: vin?.length > 0 && this.hasValidCarId()
};
},
computed: {
isCarIdDifferentFromTheStore() {
return (
this.vehicleFromLookup !== null
&& this.hasValidCarId()
&& this.vehicleFromLookup.carId !== this.mainStore.vehicle.carId
);
},
isTwoIdenticalYMMVehicleFound() {
if (this.vehicleFromLookup === null) {
return false;
}
const vinYmmFound = `${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model}`;
const vinYmmExpected = `${this.mainStore.order.vehicle.year} ${this.mainStore.order.vehicle.make} ${this.mainStore.order.vehicle.model}`;
return vinYmmFound.toLowerCase() === vinYmmExpected.toLowerCase();
},
vinMask() {
// TODO: Side effects in computed.
if (this.vinPopulatedOnPageLoad) {
// TODO: Modify to remove side effects in computed
this.activeVehicleLookupAlertType =
vehicleLookupAlertTypes.PERFECT_MATCH;
this.needToLookupVehicle = false;
const lastSixChars = this.vin.substring(11, this.vin.length);
return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
}
return '*****************';
},
carIdIsValid() {
return this.hasValidCarId();
}
},
watch: {
vin() {
this.resetActiveAlert();
this.$refs.siteFooter.enableForwardAction();
this.needToLookupVehicle = true;
this.$refs.siteFooter.updateButtonText(this.getCmsContent('SiteFooterWidget', 'ForwardButtonText'));
}
},
methods: {
arePagePrerequisiteValid() {
return true;
},
getVinFromStore() {
return this.mainStore.vehicle.vin;
},
hasValidCarId() {
return (
this.mainStore.vehicle.carId && this.mainStore.vehicle.carId !== '0'
);
},
// NOTE: If form is not valid, this method is not called when 'Continue' button is clicked
async forwardButtonAction() {
this.resetActiveAlert();
// Temp solution to reset the 'disabled' style on the Continue button
this.$refs.siteFooter.enableForwardAction();
const vehicleYearMakeModelStyle =
if (this.needToLookupVehicle) {
const vehicleLookupResponse = await this.lookupVehicleByVin(this.vin);
if (vehicleLookupResponse.error) {
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.NOT_FOUND;
this.mainStore.setBailout(bailoutMessage.vehicleNotFound(this.vin));
this.resetVehicleFromLookup();
this.$refs.siteFooter.removeLoader();
// Temp solution to turn on 'disabled' style on the Continue button
// because the form itself actually passes its client-side validation.
// SSR-189 Scenario #4.
this.$refs.siteFooter.enableForwardAction();
return;
}
this.mainStore.resetBailout();
// Add vin bcs the response from the service doesn't contain vin
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, {
vin: this.vin
});
}
if (this.needToLookupVehicle && this.isCarIdDifferentFromTheStore) {
if (this.isTwoIdenticalYMMVehicleFound) {
this.activeVehicleLookupAlertType =
vehicleLookupAlertTypes.TWO_IDENTICAL_YMM_MATCHED;
this.forwardButtonCarStyle = this.vehicleFromLookup.style;
} else {
this.activeVehicleLookupAlertType =
vehicleLookupAlertTypes.NOT_MATCHED;
}
const vehicleYearMakeModelStyle =
// eslint-disable-next-line max-len
`${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model} ${this.forwardButtonCarStyle}`;
this.$refs.siteFooter.updateButtonText(
`Continue with ${vehicleYearMakeModelStyle}`
);
this.$refs.siteFooter.removeLoader();
this.$refs.siteFooter.updateButtonText(`Continue with ${vehicleYearMakeModelStyle}`);
this.$refs.siteFooter.removeLoader();
this.needToLookupVehicle = false;
this.needToLookupVehicle = false;
return null;
}
return null;
}
let isSelectedGlassAvailableForVehicle = true;
if (this.isCarIdDifferentFromTheStore) {
isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
this.vehicleFromLookup.carId
);
}
let isSelectedGlassAvailableForVehicle = true;
if (this.isCarIdDifferentFromTheStore) {
isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(this.vehicleFromLookup.carId);
}
// navigate back to vehicle-damage
if (
this.isCarIdDifferentFromTheStore &&
!isSelectedGlassAvailableForVehicle
) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
this.mainStore.resetDamageState();
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
this.$route,
{},
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
);
// navigate back to vehicle-damage
if (
this.isCarIdDifferentFromTheStore
&& !isSelectedGlassAvailableForVehicle
) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
this.mainStore.resetDamageState();
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
this.$route,
{},
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
);
// navigate() doesn't stop the processing flow
return null;
}
// navigate() doesn't stop the processing flow
return null;
}
// save vehicle to store if it hasn't already been saved
if (!this.vinPopulatedOnPageLoad) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
}
// save vehicle to store if it hasn't already been saved
if (!this.vinPopulatedOnPageLoad) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
}
if (this.vinWithNonMatchingCarId) {
this.$router.navigate(
this.navigationScenarios.CORRECTED_VIN_FROM_POLICY_VEHICLE,
this.$route
);
return null;
}
if (this.vinWithNonMatchingCarId) {
this.$router.navigate(
this.navigationScenarios.CORRECTED_VIN_FROM_POLICY_VEHICLE,
this.$route
);
return null;
}
const partsOrQuestionsResponse = await this.getPartsOrQuestions();
if (partsOrQuestionsResponse.error) {
// To Do: Need requirement on what to do here
window.console.error("Error on retrieving PartsOrQuestions");
this.$refs.siteFooter.removeLoader();
return null;
}
const partsOrQuestionsResponse = await this.getPartsOrQuestions();
if (partsOrQuestionsResponse.error) {
// To Do: Need requirement on what to do here
window.console.error('Error on retrieving PartsOrQuestions');
this.$refs.siteFooter.removeLoader();
return null;
}
// Comes from vehicleQuestionsMixin.navigateForward()
await this.navigateForward(
partsOrQuestionsResponse.data.partsOrQuestions,
this
);
// Comes from vehicleQuestionsMixin.navigateForward()
await this.navigateForward(
partsOrQuestionsResponse.data.partsOrQuestions,
this
);
return null;
},
async lookupVehicleByVin(vin) {
try {
return await this.mainStore.lookupVehicleByVin(vin);
} catch (responseError) {
return {
error: {
status: responseError.status,
},
};
}
},
resetActiveAlert() {
this.activeVehicleLookupAlertType = null;
},
resetVehicleFromLookup() {
this.vehicleFromLookup = null;
},
resetDependentState() {},
},
return null;
},
async lookupVehicleByVin(vin) {
try {
return await this.mainStore.lookupVehicleByVin(vin);
} catch (responseError) {
return {
error: {
status: responseError.status
}
};
}
},
resetActiveAlert() {
this.activeVehicleLookupAlertType = null;
},
resetVehicleFromLookup() {
this.vehicleFromLookup = null;
},
resetDependentState() {}
}
};
</script>

View file

@ -3,8 +3,7 @@
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit"
>
@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">
@ -13,7 +12,9 @@
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" class="mt-4" />
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4" />
<textboxQuestion
ref="policyNumber"
v-model="welcomePageModel.policyNumber"
@ -22,8 +23,7 @@
isRequired
disableAutoFill
:isDisabled="isPolicyHolderDisabled"
:validationRules="rules.policyNumber"
/>
:validationRules="rules.policyNumber" />
<textboxQuestion
ref="policyZip"
v-model="welcomePageModel.policyZipCode"
@ -32,8 +32,7 @@
isRequired
mask="#####"
:isDisabled="isPolicyZipDisabled"
:validationRules="rules.policyZip"
/>
:validationRules="rules.policyZip" />
<textboxQuestion
ref="dateOfLoss"
v-model="welcomePageModel.dateOfLoss"
@ -45,13 +44,11 @@
disableAutoFill
:max="new Date().toJSON().slice(0, 10)"
:min="'1972-12-01'"
:validationRules="rules.lossDate"
/>
:validationRules="rules.lossDate" />
<textBlock
cmsWidgetName="DamageDateEstimateWidget"
typeStyle="small"
class="mt-2"
/>
class="mt-2" />
<dropdownQuestion
id="welcomeDropdown"
ref="damageCause"
@ -61,8 +58,7 @@
:options="DamageCauseOptions"
disableAutoFill
:validationRules="rules.damageOption"
placeHolderText="Select an option"
/>
placeHolderText="Select an option" />
<textboxQuestion
ref="phoneNumber"
v-model="welcomePageModel.phoneNumber"
@ -71,8 +67,7 @@
:validationRules="rules.phoneNumber"
isRequired
:mask="phoneMask"
disableAutoFill
/>
disableAutoFill />
<textboxQuestion
ref="email"
v-model="welcomePageModel.email"
@ -80,8 +75,7 @@
cmsWidgetName="EmailAddressQuestion"
:validationRules="rules.email"
isRequired
disableAutoFill
/>
disableAutoFill />
<textboxQuestion
v-if="displayDamageCityQuestion"
ref="damageCity"
@ -91,8 +85,7 @@
cmsWidgetName="DamageCityQuestion"
isRequired
disableAutoFill
:validationRules="rules.lossCity"
/>
:validationRules="rules.lossCity" />
<dropdownQuestion
v-if="displayDamageStateQuestion"
id="welcomeDropdown"
@ -105,8 +98,7 @@
:validationRules="rules.lossState"
isRequired
disableAutoFill
placeHolderText="Select an option"
/>
placeHolderText="Select an option" />
<buttonQuestion
v-if="displayGlassOnlyQuestion"
ref="glassOnlyDamage"
@ -121,289 +113,287 @@
:validationRules="rules.damageOption"
isRequired
isSmallQuestionLabelText
disableAutoFill
/>
<div id="welcomeFooter" class="row">
disableAutoFill />
<div
id="welcomeFooter"
class="row">
<alert
v-if="displayInvalidZipAlert"
ref="alertInvalidZip"
class="my-4"
cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger"
:isDismissible="false"
/>
:isDismissible="false" />
<siteFooter
ref="siteFooter"
class="mt-3"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction"
/>
@ForwardClicked="forwardButtonAction" />
</div>
</div>
</div>
<!-- Footer image component must have parent (usually container-fluid)
set to display: flex and height 100dvh or height 100% -->
<footerImage
cmsWidgetName="SiteFooterWidget" />
<footerImage cmsWidgetName="SiteFooterWidget" />
</div>
</Form>
</template>
<script>
// Components
import { Form, defineRule } from "vee-validate";
import siteHeader from "@/iss-components/site-header/site-header.vue";
import siteSubHeader from "@/iss-components/site-sub-header/site-sub-header.vue";
import siteFooter from "@/iss-components/site-footer/site-footer.vue";
import alert from "@/ux-components/alert/alert.vue";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question.vue";
import buttonQuestion from "@/digital-components/button-question/button-question.vue";
import dropdownQuestion from "@/digital-components/dropdown-question/dropdown-question.vue";
import textBlock from "@/digital-components/text-block/text-block.vue";
import footerImage from "@/iss-components/site-footer/footer-image/footer-image.vue";
import { Form, defineRule } from 'vee-validate';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import alert from '@/ux-components/alert/alert.vue';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
import footerImage from '@/iss-components/site-footer/footer-image/footer-image.vue';
// Supporting files
import {
fetchCmsContentForPage,
fetchGlobalCmsContent,
updateCmsSiteHeader,
} from "@/helpers/cms-content-helper";
import settleAllPromises from "@/helpers/layout-helper";
import { required } from "@/helpers/validation-rules";
import errorMessages from "@/constants/error-messages";
import BaseFormMixin from "@/mixins/base-form-mixin.js";
import { useMainStore } from "@/store";
import states from "@/constants/states";
import globalRules from "@/constants/global-rules";
import routerParams from "@/router/router-constants/router-params";
import MaskaFormattedMasks from "@/constants/maska-masks";
fetchCmsContentForPage,
fetchGlobalCmsContent,
updateCmsSiteHeader
} from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { required } from '@/helpers/validation-rules';
import errorMessages from '@/constants/error-messages';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store';
import states from '@/constants/states';
import globalRules from '@/constants/global-rules';
import routerParams from '@/router/router-constants/router-params';
import MaskaFormattedMasks from '@/constants/maska-masks';
// define validation rules
defineRule(
"damage-option-required",
required(errorMessages.DAMAGE_OPTION_REQUIRED)
'damage-option-required',
required(errorMessages.DAMAGE_OPTION_REQUIRED)
);
export default {
name: "welcome-page",
components: {
siteHeader,
siteSubHeader,
footerImage,
alert,
buttonQuestion,
textboxQuestion,
dropdownQuestion,
siteFooter,
textBlock,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
name: 'welcome-page',
components: {
siteHeader,
siteSubHeader,
footerImage,
alert,
buttonQuestion,
textboxQuestion,
dropdownQuestion,
siteFooter,
textBlock,
// eslint-disable-next-line vue/no-reserved-component-names
Form
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const cmsGlobalSiteHeaderContentPromise =
fetchGlobalCmsContent("iss-siteheader");
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const cmsGlobalSiteHeaderContentPromise =
fetchGlobalCmsContent('iss-siteheader');
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
{
resultKey: "globalSiteHeaderCmsContent",
promise: cmsGlobalSiteHeaderContentPromise,
},
];
// Settle promises and get results
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise
},
{
resultKey: 'globalSiteHeaderCmsContent',
promise: cmsGlobalSiteHeaderContentPromise
}
];
// use resultMap to populate layout content.
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
updateCmsSiteHeader(resultMap.globalSiteHeaderCmsContent);
vm.setCmsContent(resultMap.cmsContent);
});
},
setup() {
const mainStore = useMainStore();
// Set order account number from the issConfig.
mainStore.order.accountNumber = mainStore.issConfig.parentAccountNumber;
return { mainStore };
},
data() {
return {
welcomePageModel: this.getWelcomePageModelFromStore(),
displayInvalidZipAlert: false,
duplicates: [],
rules: {
damageOption: "damage-option-required",
email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`,
lossCity: `${globalRules.DATE_OF_LOSS_CITY_REQUIRED}|${globalRules.DATE_OF_LOSS_CITY_FORMAT}`,
// eslint-disable-next-line max-len
lossDate: `${globalRules.DATE_OF_LOSS_REQUIRED}|${globalRules.DATE_OF_LOSS_NOT_TEN_YEARS_PAST}|${globalRules.DATE_OF_LOSS_NOT_FUTURE}`,
lossState: `${globalRules.DATE_OF_LOSS_STATE_REQUIRED}`,
policyNumber: `${globalRules.POLICY_NUMBER_REQUIRED}|${globalRules.POLICY_NUMBER_FORMAT}`,
policyZip: `${globalRules.POLICY_ZIP_REQUIRED}|${globalRules.POLICY_ZIP_FORMAT}`,
phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`,
},
};
},
computed: {
DamageCauseOptions() {
const damageCauseAnswers = this.getCmsContent(
"DamageCauseQuestion",
"Answers"
);
const damageCauseAnswersObj = {};
if (damageCauseAnswers) {
// eslint-disable-next-line no-restricted-syntax
for (const answer of Object.values(damageCauseAnswers)) {
if (answer?.Name) {
damageCauseAnswersObj[answer.Name] = answer.Name;
}
}
}
return damageCauseAnswersObj;
},
DamageGlassOnlyOptions() {
return this.getCmsContent("GlassOnlyQuestion", "Answers");
},
DamageGlassOnlyQuestion() {
return this.getCmsContent("GlassOnlyQuestion", "QuestionText");
},
displayDamageCityQuestion() {
return !!this.getCmsContent("DamageCityQuestion", "QuestionText");
},
displayDamageStateQuestion() {
return !!this.getCmsContent("DamageStateQuestion", "QuestionText");
},
displayGlassOnlyQuestion() {
return !!this.getCmsContent("GlassOnlyQuestion", "QuestionText");
},
getStates() {
return states;
},
isPolicyHolderDisabled() {
return !!this.mainStore.issConfig.disabledFields.policyNumber;
},
isPolicyZipDisabled() {
return !!this.mainStore.issConfig.disabledFields.policyZipCode;
},
isDateOfLossDisabled() {
return !!this.mainStore.issConfig.disabledFields.dateOfLoss;
},
isCoverageEnabled() {
return this.mainStore.issConfig.isCoverageEnabled;
},
maxCoverageLookupAttemptsReached() {
return this.mainStore.applicationUser.coverageLookupAttempts >= 11;
},
phoneMask() {
return MaskaFormattedMasks.PHONE_NUMBER;
},
},
methods: {
async forwardButtonAction() {
await this.mainStore
.validateZip({ zip: this.welcomePageModel.policyZipCode })
.then(async (zipInfo) => {
if (zipInfo?.data?.isValid === true) {
this.mainStore.updatePolicyData(this.welcomePageModel);
await this.mainStore
.getDuplicateReferrals()
.then(
() => {},
() => {}
)
.finally(async () => {
if (
this.isCoverageEnabled &&
!this.maxCoverageLookupAttemptsReached
) {
await this.mainStore.getCoveragePolicyInfo()?.then(
() => {},
() => {}
);
} else {
this.mainStore.order.policy.policyLookupSuccessful = false;
}
this.navigateForward();
});
} else {
this.displayInvalidZipAlert = true;
this.$refs.siteFooter.removeLoader();
}
// use resultMap to populate layout content.
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
updateCmsSiteHeader(resultMap.globalSiteHeaderCmsContent);
vm.setCmsContent(resultMap.cmsContent);
});
},
navigateForward() {
if (this.mainStore.applicationUser.duplicateOrders?.length > 0 ?? false) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_DUPLICATES,
this.$route,
{},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
);
} else if (this.mainStore.policy.policyLookupSuccessful) {
if (this.mainStore.order.policy.vehicles?.length > 0 ?? false) {
// navigate to policy-vehicles page
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES,
this.$route,
{},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
);
} else {
// navigate to vehicle-selection page (manual entry)
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES,
this.$route,
{},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
);
setup() {
const mainStore = useMainStore();
// Set order account number from the issConfig.
mainStore.order.accountNumber = mainStore.issConfig.parentAccountNumber;
return { mainStore };
},
data() {
return {
welcomePageModel: this.getWelcomePageModelFromStore(),
displayInvalidZipAlert: false,
duplicates: [],
rules: {
damageOption: 'damage-option-required',
email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`,
lossCity: `${globalRules.DATE_OF_LOSS_CITY_REQUIRED}|${globalRules.DATE_OF_LOSS_CITY_FORMAT}`,
// eslint-disable-next-line max-len
lossDate: `${globalRules.DATE_OF_LOSS_REQUIRED}|${globalRules.DATE_OF_LOSS_NOT_TEN_YEARS_PAST}|${globalRules.DATE_OF_LOSS_NOT_FUTURE}`,
lossState: `${globalRules.DATE_OF_LOSS_STATE_REQUIRED}`,
policyNumber: `${globalRules.POLICY_NUMBER_REQUIRED}|${globalRules.POLICY_NUMBER_FORMAT}`,
policyZip: `${globalRules.POLICY_ZIP_REQUIRED}|${globalRules.POLICY_ZIP_FORMAT}`,
phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`
}
};
},
computed: {
DamageCauseOptions() {
const damageCauseAnswers = this.getCmsContent(
'DamageCauseQuestion',
'Answers'
);
const damageCauseAnswersObj = {};
if (damageCauseAnswers) {
// eslint-disable-next-line no-restricted-syntax
for (const answer of Object.values(damageCauseAnswers)) {
if (answer?.Name) {
damageCauseAnswersObj[answer.Name] = answer.Name;
}
}
}
return damageCauseAnswersObj;
},
DamageGlassOnlyOptions() {
return this.getCmsContent('GlassOnlyQuestion', 'Answers');
},
DamageGlassOnlyQuestion() {
return this.getCmsContent('GlassOnlyQuestion', 'QuestionText');
},
displayDamageCityQuestion() {
return !!this.getCmsContent('DamageCityQuestion', 'QuestionText');
},
displayDamageStateQuestion() {
return !!this.getCmsContent('DamageStateQuestion', 'QuestionText');
},
displayGlassOnlyQuestion() {
return !!this.getCmsContent('GlassOnlyQuestion', 'QuestionText');
},
getStates() {
return states;
},
isPolicyHolderDisabled() {
return !!this.mainStore.issConfig.disabledFields.policyNumber;
},
isPolicyZipDisabled() {
return !!this.mainStore.issConfig.disabledFields.policyZipCode;
},
isDateOfLossDisabled() {
return !!this.mainStore.issConfig.disabledFields.dateOfLoss;
},
isCoverageEnabled() {
return this.mainStore.issConfig.isCoverageEnabled;
},
maxCoverageLookupAttemptsReached() {
return this.mainStore.applicationUser.coverageLookupAttempts >= 11;
},
phoneMask() {
return MaskaFormattedMasks.PHONE_NUMBER;
}
} else {
// if policy lookup is unsuccessful, navigate to policy-holder-details page
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED,
this.$route,
{},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
);
}
},
getWelcomePageModelFromStore() {
return {
policyNumber: this.mainStore.order.policy.policyNumber,
policyZipCode: this.mainStore.order.policy.policyZipCode,
dateOfLoss: this.mainStore.order.policy.dateOfLoss,
damageCause: this.mainStore.order.policy.damageCause,
damageState: this.mainStore.order.policy.damageState,
damageCity: this.mainStore.order.policy.damageCity,
isDamageGlassOnly: this.mainStore.order.policy.isDamageGlassOnly,
phoneNumber: this.mainStore.order.customer.phoneNumber,
email: this.mainStore.order.customer.emailAddress,
isPolicyNumberDisabled:
this.mainStore.order.policy.isPolicyNumberDisabled,
};
},
},
methods: {
async forwardButtonAction() {
await this.mainStore
.validateZip({ zip: this.welcomePageModel.policyZipCode })
.then(async (zipInfo) => {
if (zipInfo?.data?.isValid === true) {
this.mainStore.updatePolicyData(this.welcomePageModel);
await this.mainStore
.getDuplicateReferrals()
.then(
() => {},
() => {}
)
.finally(async () => {
if (
this.isCoverageEnabled
&& !this.maxCoverageLookupAttemptsReached
) {
await this.mainStore.getCoveragePolicyInfo()?.then(
() => {},
() => {}
);
} else {
this.mainStore.order.policy.policyLookupSuccessful = false;
}
this.navigateForward();
});
} else {
this.displayInvalidZipAlert = true;
this.$refs.siteFooter.removeLoader();
}
});
},
navigateForward() {
if (this.mainStore.applicationUser.duplicateOrders?.length > 0 ?? false) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_DUPLICATES,
this.$route,
{},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
);
} else if (this.mainStore.policy.policyLookupSuccessful) {
if (this.mainStore.order.policy.vehicles?.length > 0 ?? false) {
// navigate to policy-vehicles page
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES,
this.$route,
{},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
);
} else {
// navigate to vehicle-selection page (manual entry)
this.$router.navigate(
this.navigationScenarios
.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES,
this.$route,
{},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
);
}
} else {
// if policy lookup is unsuccessful, navigate to policy-holder-details page
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED,
this.$route,
{},
{ [routerParams.SAVE_SESSION_SYNCHRONOUS]: true }
);
}
},
getWelcomePageModelFromStore() {
return {
policyNumber: this.mainStore.order.policy.policyNumber,
policyZipCode: this.mainStore.order.policy.policyZipCode,
dateOfLoss: this.mainStore.order.policy.dateOfLoss,
damageCause: this.mainStore.order.policy.damageCause,
damageState: this.mainStore.order.policy.damageState,
damageCity: this.mainStore.order.policy.damageCity,
isDamageGlassOnly: this.mainStore.order.policy.isDamageGlassOnly,
phoneNumber: this.mainStore.order.customer.phoneNumber,
email: this.mainStore.order.customer.emailAddress,
isPolicyNumberDisabled:
this.mainStore.order.policy.isPolicyNumberDisabled
};
}
}
};
</script>
<style lang="scss" scoped>
form {
height: 100dvh;
.container-fluid {
display: flex;
flex-direction: column;
height: 100%;
}
height: 100dvh;
.container-fluid {
display: flex;
flex-direction: column;
height: 100%;
}
}
@-moz-document url-prefix() {
// Temporary solution that prevents the Continue button from being hidden in Firefox