WIP ISS desktop updates.
This commit is contained in:
parent
567657b3b4
commit
fa3c7711f6
14 changed files with 1349 additions and 1206 deletions
|
|
@ -119,25 +119,17 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="scss">
|
||||
.modal {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
|
||||
:deep(h5) {
|
||||
color: $black;
|
||||
}
|
||||
|
||||
:deep(p) {
|
||||
strong {
|
||||
color: $black;
|
||||
}
|
||||
}
|
||||
|
||||
h5,
|
||||
strong,
|
||||
.subheader-text {
|
||||
color: $black;
|
||||
}
|
||||
.modal-header {
|
||||
padding: 1rem 0 0.5rem 0;
|
||||
border-bottom: none;
|
||||
.btn-close {
|
||||
position: absolute;
|
||||
|
|
@ -145,11 +137,14 @@ export default {
|
|||
top: 1rem;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15.6874 1.82179L9.50889 8L15.6874 14.1782C16.1042 14.595 16.1042 15.2707 15.6874 15.6875C15.4843 15.8907 15.2146 16 14.9328 16C14.6514 16 14.3818 15.8906 14.1787 15.6875L8.00017 9.50934L1.82171 15.6875C1.6182 15.8907 1.34876 16 1.06708 16C0.785733 16 0.516056 15.8906 0.312965 15.6875C-0.10429 15.2706 -0.10429 14.5952 0.312797 14.1784L6.03276 8.45867L6.49146 8L0.312945 1.82177C-0.10429 1.40483 -0.10429 0.729418 0.312797 0.31262C0.728936 -0.104145 1.40489 -0.104051 1.82185 0.31262L7.54152 6.03202L8.00017 6.49065L14.1786 0.312472C14.5955 -0.104107 15.2707 -0.104201 15.6874 0.312452C16.1042 0.729289 16.1042 1.40496 15.6874 1.82179Z' fill='%231574A1'/%3E%3C/svg%3E%0A");
|
||||
opacity: 1;
|
||||
margin: 0.3rem -0.5rem -0.5rem auto;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-weight: 500;
|
||||
color: $black;
|
||||
font-size: 1.25rem;
|
||||
line-height: 32px;
|
||||
color: rgb(0, 0, 0);
|
||||
}
|
||||
}
|
||||
.modal-footer {
|
||||
|
|
@ -157,17 +152,31 @@ export default {
|
|||
width: 100%;
|
||||
bottom: 0;
|
||||
z-index: 5;
|
||||
background-color: $gray-100;
|
||||
}
|
||||
&.modal-component {
|
||||
.modal-dialog {
|
||||
max-width: 576px;
|
||||
max-width: 767px;
|
||||
margin: 0 auto;
|
||||
@include media-breakpoint-up(md) {
|
||||
width: 376px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform: translate(100%, 0);
|
||||
}
|
||||
.modal-content {
|
||||
margin: 0 auto;
|
||||
margin: 1.5rem auto 0 auto;
|
||||
box-shadow: 0px 16px 48px -16px rgba(0, 0, 0, 0.25);
|
||||
border-radius: 1.5rem 1.5rem 0 0;
|
||||
@include media-breakpoint-up(md) {
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.modal-body {
|
||||
.col {
|
||||
max-width: 100%;
|
||||
}
|
||||
.modal-sub-body {
|
||||
color: $gray-600;
|
||||
}
|
||||
|
|
@ -179,22 +188,36 @@ export default {
|
|||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
overflow: auto;
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.modal-dialog-centered {
|
||||
align-items: flex-end;
|
||||
min-height: 100%;
|
||||
@include media-breakpoint-up(md) {
|
||||
align-items: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
.modal-footer {
|
||||
border-top: none;
|
||||
background-color: $gray-100;
|
||||
box-shadow: 0px -1px 0px rgba(179, 180, 181, 0.3);
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.show .modal-dialog {
|
||||
transform: translateY(0);
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
&.fade {
|
||||
transition: opacity 0.25s linear;
|
||||
}
|
||||
}
|
||||
}
|
||||
body {
|
||||
.modal-backdrop {
|
||||
|
|
|
|||
|
|
@ -1,222 +1,234 @@
|
|||
<template>
|
||||
<Form
|
||||
ref="contact-details-form"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader
|
||||
ref="siteHeader"
|
||||
:cmsWidgetName="widget.siteHeader" />
|
||||
<div class="container-fluid px-6">
|
||||
<siteSubHeader
|
||||
id="sub-header"
|
||||
ref="siteSubHeader"
|
||||
class="mt-5"
|
||||
:cmsWidgetName="widget.siteSubHeader" />
|
||||
<textboxQuestion
|
||||
ref="firstNameQuestion"
|
||||
v-model="firstName"
|
||||
class="mt-6"
|
||||
inputId="firstName"
|
||||
:cmsWidgetName="widget.firstNameQuestion"
|
||||
isRequired
|
||||
:validationRules="rules.firstName" />
|
||||
<textboxQuestion
|
||||
ref="lastNameQuestion"
|
||||
v-model="lastName"
|
||||
class="mt-5"
|
||||
inputId="lastName"
|
||||
:cmsWidgetName="widget.lastNameQuestion"
|
||||
isRequired
|
||||
:validationRules="rules.lastName" />
|
||||
<textboxQuestion
|
||||
ref="emailQuestion"
|
||||
v-model="emailAddress"
|
||||
class="mt-5"
|
||||
inputId="emailAddress"
|
||||
:cmsWidgetName="widget.emailQuestion"
|
||||
isRequired
|
||||
:validationRules="rules.emailAddress" />
|
||||
<textboxQuestion
|
||||
ref="phoneNumberQuestion"
|
||||
v-model="phoneNumber"
|
||||
class="mt-5"
|
||||
inputId="phoneNumber"
|
||||
:cmsWidgetName="widget.phoneNumberQuestion"
|
||||
isRequired
|
||||
:mask="phoneMask"
|
||||
:validationRules="rules.phoneNumber" />
|
||||
<checkbox
|
||||
ref="requestTextUpdatesCheckbox"
|
||||
v-model="requestTextUpdates"
|
||||
:isChecked="requestTextUpdates"
|
||||
class="mt-3"
|
||||
checkboxName="requestTextUpdates"
|
||||
buttonID="requestTextUpdates"
|
||||
:checkboxLabel="requestTextUpdatesCheckboxText" />
|
||||
<textareaQuestion
|
||||
ref="notesQuestion"
|
||||
v-model="notesForTechnician"
|
||||
class="mt-5"
|
||||
inputId="technicianNotes"
|
||||
:isDisabled="false"
|
||||
:isRequired="false"
|
||||
:cmsWidgetName="widget.notesQuestion"
|
||||
maxLength="250"
|
||||
: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" />
|
||||
and
|
||||
<textLink
|
||||
ref="termsOfUseLink"
|
||||
class="normal-line-height"
|
||||
linkType="text"
|
||||
text="Terms of Use"
|
||||
href="//www.safelite.com/terms-of-use" />.
|
||||
</p>
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
class="my-5"
|
||||
:cmsWidgetName="widget.siteFooter"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@forwardClicked="forwardButtonAction"
|
||||
@backClicked="navigateBack" />
|
||||
</div>
|
||||
</div>
|
||||
<Form
|
||||
ref="contact-details-form"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit"
|
||||
>
|
||||
<div class="container-fluid fade-on-route-transition">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader ref="siteHeader" :cmsWidgetName="widget.siteHeader" />
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<siteSubHeader
|
||||
id="sub-header"
|
||||
ref="siteSubHeader"
|
||||
class="mt-5"
|
||||
:cmsWidgetName="widget.siteSubHeader"
|
||||
/>
|
||||
<textboxQuestion
|
||||
ref="firstNameQuestion"
|
||||
v-model="firstName"
|
||||
class="mt-6"
|
||||
inputId="firstName"
|
||||
:cmsWidgetName="widget.firstNameQuestion"
|
||||
isRequired
|
||||
:validationRules="rules.firstName"
|
||||
/>
|
||||
<textboxQuestion
|
||||
ref="lastNameQuestion"
|
||||
v-model="lastName"
|
||||
class="mt-5"
|
||||
inputId="lastName"
|
||||
:cmsWidgetName="widget.lastNameQuestion"
|
||||
isRequired
|
||||
:validationRules="rules.lastName"
|
||||
/>
|
||||
<textboxQuestion
|
||||
ref="emailQuestion"
|
||||
v-model="emailAddress"
|
||||
class="mt-5"
|
||||
inputId="emailAddress"
|
||||
:cmsWidgetName="widget.emailQuestion"
|
||||
isRequired
|
||||
:validationRules="rules.emailAddress"
|
||||
/>
|
||||
<textboxQuestion
|
||||
ref="phoneNumberQuestion"
|
||||
v-model="phoneNumber"
|
||||
class="mt-5"
|
||||
inputId="phoneNumber"
|
||||
:cmsWidgetName="widget.phoneNumberQuestion"
|
||||
isRequired
|
||||
:mask="phoneMask"
|
||||
:validationRules="rules.phoneNumber"
|
||||
/>
|
||||
<checkbox
|
||||
ref="requestTextUpdatesCheckbox"
|
||||
v-model="requestTextUpdates"
|
||||
:isChecked="requestTextUpdates"
|
||||
class="mt-3"
|
||||
checkboxName="requestTextUpdates"
|
||||
buttonID="requestTextUpdates"
|
||||
:checkboxLabel="requestTextUpdatesCheckboxText"
|
||||
/>
|
||||
<textareaQuestion
|
||||
ref="notesQuestion"
|
||||
v-model="notesForTechnician"
|
||||
class="mt-5"
|
||||
inputId="technicianNotes"
|
||||
:isDisabled="false"
|
||||
:isRequired="false"
|
||||
:cmsWidgetName="widget.notesQuestion"
|
||||
maxLength="250"
|
||||
: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"
|
||||
/>
|
||||
and
|
||||
<textLink
|
||||
ref="termsOfUseLink"
|
||||
class="normal-line-height"
|
||||
linkType="text"
|
||||
text="Terms of Use"
|
||||
href="//www.safelite.com/terms-of-use"
|
||||
/>.
|
||||
</p>
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
class="my-5"
|
||||
:cmsWidgetName="widget.siteFooter"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@forwardClicked="forwardButtonAction"
|
||||
@backClicked="navigateBack"
|
||||
/>
|
||||
</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 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);
|
||||
});
|
||||
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")}*`;
|
||||
},
|
||||
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}`
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @returns {string} Returns the CMS text associated with the "get text updates" checkbox.
|
||||
*/
|
||||
textUpdateDisclaimerText() {
|
||||
return `*${this.getCmsContent(this.widget.disclaimer, "Text")}`;
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* @returns {string} Returns the CMS text associated with the "get text updates" checkbox.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
phoneMask() {
|
||||
return MaskaFormattedMasks.PHONE_NUMBER;
|
||||
},
|
||||
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 = 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);
|
||||
}
|
||||
}
|
||||
},
|
||||
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 =
|
||||
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);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dark-gray {
|
||||
color: $darker-gray;
|
||||
color: $darker-gray;
|
||||
}
|
||||
|
||||
.normal-line-height {
|
||||
line-height: normal;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@
|
|||
>
|
||||
<div class="container-fluid fade-on-route-transition">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<loadingModal ref="loadingModal" :textSlides="loadingText" />
|
||||
<siteHeader ref="siteHeader" cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="row justify-content-center pt-5">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<h5
|
||||
ref="siteSubHeader"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
>
|
||||
<div class="container-fluid fade-on-route-transition">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader ref="siteHeader" :cmsWidgetName="widget.siteHeader" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
>
|
||||
<div class="container-fluid fade-on-route-transition">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader class="mb-2 header" cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<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">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader class="mb-2 header" cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,434 +1,498 @@
|
|||
<template>
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<siteSubHeader
|
||||
cmsWidgetName="ScheduleSubHeaderWidget"
|
||||
subTextClasses="text-center small sub-text"
|
||||
class="mt-4" />
|
||||
<template v-if="ChangeShopLink.length">
|
||||
<textBlock
|
||||
cmsWidgetName="ChangeShopLink"
|
||||
justifyText="center"
|
||||
class="mb-3 text-link-small"
|
||||
:marginTopSizeOverride="1" />
|
||||
</template>
|
||||
<div class="main-content-container">
|
||||
<locationAlerts
|
||||
ref="locationAlerts"
|
||||
cmsWidgetPrefix="LocationAlert-" />
|
||||
<datePicker
|
||||
ref="datePicker"
|
||||
v-model="selectedDate"
|
||||
customComponentId="dateQuestion"
|
||||
selectableDatesSetting="custom"
|
||||
class="text-link-small"
|
||||
:customSelectableDatesCallback="getAvailableDatesMethod"
|
||||
validationRules="date-required"
|
||||
@dateClicked="openInshopTimeSlotsModal" />
|
||||
<timeSlotModalQuestion
|
||||
ref="timeSlotModalQuestion"
|
||||
v-model="selectedTimeSlotInfo"
|
||||
customComponentId="timeSlotModalQuestion"
|
||||
cmsWidgetName="TimeSlotModalQuestion"
|
||||
mobilePremiumCmsWidgetName="MobilePremiumTimeSlotModal"
|
||||
mobileCmsWidgetName="MobileTimeSlotModal"
|
||||
dropoffCmsWidgetName="DropOffTimeSlotModal"
|
||||
sameDayDropOffCmsWidgetName="SameDayDropOffTimeSlotModal"
|
||||
overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal"
|
||||
:selectedDate="selectedDate"
|
||||
:appointmentType="appointmentType"
|
||||
:premiumAppointmentFee="mobilePremiumAppointmentFee"
|
||||
:timeSlotsForSelectedDate="timeSlotsForSelectedDate"
|
||||
:estimatedServiceMinutesMinimum="selectableDatesData.estimatedServiceMinutesMinimum"
|
||||
:estimatedServiceMinutesMaximum="selectableDatesData.estimatedServiceMinutesMaximum"
|
||||
validationRules="time-slot-selection-required"
|
||||
@timeSlotModalClosed="timeSlotModalClosed" />
|
||||
<siteFooter
|
||||
ref="navbar"
|
||||
class="mt-5"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@backClicked="navigateBack"
|
||||
@forwardClicked="forwardButtonAction" />
|
||||
</div>
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit"
|
||||
>
|
||||
<div class="container-fluid fade-on-route-transition">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader class="mb-2 header" cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<siteSubHeader
|
||||
cmsWidgetName="ScheduleSubHeaderWidget"
|
||||
subTextClasses="text-center small sub-text"
|
||||
class="mt-4"
|
||||
/>
|
||||
<template v-if="ChangeShopLink.length">
|
||||
<textBlock
|
||||
cmsWidgetName="ChangeShopLink"
|
||||
justifyText="center"
|
||||
class="mb-3 text-link-small"
|
||||
:marginTopSizeOverride="1"
|
||||
/>
|
||||
</template>
|
||||
<div class="main-content-container">
|
||||
<locationAlerts
|
||||
ref="locationAlerts"
|
||||
cmsWidgetPrefix="LocationAlert-"
|
||||
/>
|
||||
<datePicker
|
||||
ref="datePicker"
|
||||
v-model="selectedDate"
|
||||
customComponentId="dateQuestion"
|
||||
selectableDatesSetting="custom"
|
||||
class="text-link-small"
|
||||
:customSelectableDatesCallback="getAvailableDatesMethod"
|
||||
validationRules="date-required"
|
||||
@dateClicked="openInshopTimeSlotsModal"
|
||||
/>
|
||||
<timeSlotModalQuestion
|
||||
ref="timeSlotModalQuestion"
|
||||
v-model="selectedTimeSlotInfo"
|
||||
customComponentId="timeSlotModalQuestion"
|
||||
cmsWidgetName="TimeSlotModalQuestion"
|
||||
mobilePremiumCmsWidgetName="MobilePremiumTimeSlotModal"
|
||||
mobileCmsWidgetName="MobileTimeSlotModal"
|
||||
dropoffCmsWidgetName="DropOffTimeSlotModal"
|
||||
sameDayDropOffCmsWidgetName="SameDayDropOffTimeSlotModal"
|
||||
overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal"
|
||||
:selectedDate="selectedDate"
|
||||
:appointmentType="appointmentType"
|
||||
:premiumAppointmentFee="mobilePremiumAppointmentFee"
|
||||
:timeSlotsForSelectedDate="timeSlotsForSelectedDate"
|
||||
:estimatedServiceMinutesMinimum="
|
||||
selectableDatesData.estimatedServiceMinutesMinimum
|
||||
"
|
||||
:estimatedServiceMinutesMaximum="
|
||||
selectableDatesData.estimatedServiceMinutesMaximum
|
||||
"
|
||||
validationRules="time-slot-selection-required"
|
||||
@timeSlotModalClosed="timeSlotModalClosed"
|
||||
/>
|
||||
<siteFooter
|
||||
ref="navbar"
|
||||
class="mt-5"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@backClicked="navigateBack"
|
||||
@forwardClicked="forwardButtonAction"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</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';
|
||||
import { 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';
|
||||
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";
|
||||
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";
|
||||
|
||||
// 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
|
||||
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;
|
||||
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 (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
|
||||
}
|
||||
};
|
||||
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 {
|
||||
storeActionConfig = {
|
||||
storeAction: GET_SHOP_TIME_SLOTS,
|
||||
payload: {
|
||||
startDate: apiStartDate,
|
||||
endDate: apiEndDate,
|
||||
shopAppointmentType: appointmentType,
|
||||
providerNumber
|
||||
}
|
||||
};
|
||||
timeSlotsResponse = await useMainStore().getMobileTimeSlots(
|
||||
storeAction.payload.startDate,
|
||||
storeAction.payload.endDate
|
||||
);
|
||||
}
|
||||
if (apiStartDate < apiEndDate) storeActionConfigs.push(storeActionConfig);
|
||||
}
|
||||
|
||||
const timeSlotsResponsesData = {
|
||||
days: []
|
||||
};
|
||||
timeSlotsResponsesData.estimatedServiceMinutesMinimum =
|
||||
timeSlotsResponse.data.estimatedServiceMinutesMinimum;
|
||||
timeSlotsResponsesData.estimatedServiceMinutesMaximum =
|
||||
timeSlotsResponse.data.estimatedServiceMinutesMaximum;
|
||||
timeSlotsResponsesData.days = [
|
||||
...timeSlotsResponsesData.days,
|
||||
...timeSlotsResponse.data.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;
|
||||
});
|
||||
return makeParallelCalls().then(() => {
|
||||
// sort days chronologically
|
||||
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) {
|
||||
// Call APIs
|
||||
let preSelectedDate = await useMainStore().order.schedule.date;
|
||||
if (!preSelectedDate || preSelectedDate.startTime === null) {
|
||||
preSelectedDate = null;
|
||||
}
|
||||
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
||||
const datePickerInitialDataPromise = await datePicker.methods.loadInitialData({
|
||||
selectableDatesSetting: 'custom',
|
||||
initialViewRowsToShow: 5,
|
||||
customSelectableDatesCallback: getAvailableDates,
|
||||
preSelectedDate
|
||||
});
|
||||
|
||||
const premiumFeePromise = useMainStore().getMobilePremiumFee();
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
// 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');
|
||||
},
|
||||
ChangeShopLink() {
|
||||
return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
|
||||
},
|
||||
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
|
||||
};
|
||||
}
|
||||
},
|
||||
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);
|
||||
|
||||
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) ?? [])
|
||||
.length > 0;
|
||||
|
||||
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
|
||||
) {
|
||||
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) {
|
||||
// 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
||||
const datePickerInitialDataPromise =
|
||||
await datePicker.methods.loadInitialData({
|
||||
selectableDatesSetting: "custom",
|
||||
initialViewRowsToShow: 5,
|
||||
customSelectableDatesCallback: getAvailableDates,
|
||||
preSelectedDate,
|
||||
});
|
||||
|
||||
const premiumFeePromise = useMainStore().getMobilePremiumFee();
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
// 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");
|
||||
},
|
||||
ChangeShopLink() {
|
||||
return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
|
||||
},
|
||||
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,
|
||||
};
|
||||
}
|
||||
},
|
||||
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);
|
||||
|
||||
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
|
||||
) ?? []
|
||||
).length > 0;
|
||||
|
||||
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
|
||||
) {
|
||||
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
|
||||
) {
|
||||
// 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>
|
||||
|
||||
|
|
@ -436,23 +500,24 @@ export default {
|
|||
$page-side-padding: 1.5rem;
|
||||
|
||||
.page-container-grouped-styles {
|
||||
overflow: auto;
|
||||
overflow: auto;
|
||||
|
||||
.main-content-container {
|
||||
padding: 0 1.5rem !important;
|
||||
}
|
||||
.main-content-container {
|
||||
padding: 0 1.5rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.text-link-small) {
|
||||
a, .btn-link {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
a,
|
||||
.btn-link {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.subheader-primary) {
|
||||
h5.dark-header {
|
||||
margin-bottom: 0.25rem !important;
|
||||
}
|
||||
h5.dark-header {
|
||||
margin-bottom: 0.25rem !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
>
|
||||
<div class="container-fluid fade-on-route-transition">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader class="mb-2 header" cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
>
|
||||
<div class="container-fluid fade-on-route-transition">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,117 +1,126 @@
|
|||
<template>
|
||||
<Form
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="select-car">
|
||||
<div class="container-fluid pb-2">
|
||||
<div class="row px-3">
|
||||
<div class="col">
|
||||
<div class="select-car-form rounded">
|
||||
<VehicleBanner
|
||||
class="mt-2 mb-4"
|
||||
cmsWidgetName="VehicleBannerWidget"
|
||||
:displayGenericVehicleImage="false" />
|
||||
<SiteSubHeader
|
||||
cmsWidgetName="SiteSubHeaderWidget"
|
||||
class="mt-5 mb-2" />
|
||||
<VinLookupMethods
|
||||
ref="VinLookupMethods"
|
||||
v-model="selectedVinLookupMethod"
|
||||
cmsWidgetName="VINLookupMethod"
|
||||
groupName="VinLookupMethods" />
|
||||
<SiteFooter
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="isForwardActionDisabled"
|
||||
class="mt-5"
|
||||
@backClicked="navigateBack"
|
||||
@forwardClicked="forwardButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<div class="select-car-form rounded">
|
||||
<VehicleBanner
|
||||
class="mt-2 mb-4"
|
||||
cmsWidgetName="VehicleBannerWidget"
|
||||
:displayGenericVehicleImage="false"
|
||||
/>
|
||||
<SiteSubHeader
|
||||
cmsWidgetName="SiteSubHeaderWidget"
|
||||
class="mt-5 mb-2"
|
||||
/>
|
||||
<VinLookupMethods
|
||||
ref="VinLookupMethods"
|
||||
v-model="selectedVinLookupMethod"
|
||||
cmsWidgetName="VINLookupMethod"
|
||||
groupName="VinLookupMethods"
|
||||
/>
|
||||
<SiteFooter
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="isForwardActionDisabled"
|
||||
class="mt-5"
|
||||
@backClicked="navigateBack"
|
||||
@forwardClicked="forwardButtonAction"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</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: {
|
||||
// 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);
|
||||
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
|
||||
}
|
||||
];
|
||||
// Settle promises and get results
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: "cmsContent",
|
||||
promise: cmsContentPromise,
|
||||
},
|
||||
];
|
||||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
vm.$refs.VinLookupMethods.initializeComponent();
|
||||
});
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
vm.$refs.VinLookupMethods.initializeComponent();
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedVinLookupMethod: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isForwardActionDisabled() {
|
||||
return this.selectedVinLookupMethod === null;
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedVinLookupMethod: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisiteValid() {
|
||||
return true;
|
||||
},
|
||||
computed: {
|
||||
isForwardActionDisabled() {
|
||||
return this.selectedVinLookupMethod === null;
|
||||
}
|
||||
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;
|
||||
}
|
||||
},
|
||||
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() {}
|
||||
}
|
||||
resetDependentState() {},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<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">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,240 +1,247 @@
|
|||
<template>
|
||||
<Form
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles position-relative">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="select-car">
|
||||
<div class="container-fluid pb-2">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="select-car-form rounded">
|
||||
<siteSubHeader
|
||||
cmsWidgetName="SiteSubHeaderWidget"
|
||||
class="siteSubHeader"
|
||||
justification="center"
|
||||
darkGraySubText />
|
||||
@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" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<siteSubHeader
|
||||
cmsWidgetName="SiteSubHeaderWidget"
|
||||
class="siteSubHeader"
|
||||
justification="center"
|
||||
darkGraySubText
|
||||
/>
|
||||
|
||||
<vehicleQuestion
|
||||
ref="vehicleYearQuestion"
|
||||
v-model="selectedYear"
|
||||
class="mb-2 mt-4"
|
||||
cmsWidgetName="VehicleYearQuestion"
|
||||
:updateValues="updateYearValues"
|
||||
validationRules="year-required"
|
||||
inputId="yearQuestionField" />
|
||||
<vehicleQuestion
|
||||
ref="vehicleMakeQuestion"
|
||||
v-model="selectedMake"
|
||||
class="mb-2 mt-4"
|
||||
cmsWidgetName="VehicleMakeQuestion"
|
||||
:updateValues="updateMakeValues"
|
||||
validationRules="make-required"
|
||||
inputId="makeQuestionField" />
|
||||
<vehicleQuestion
|
||||
ref="vehicleModelQuestion"
|
||||
v-model="selectedModel"
|
||||
class="mb-2 mt-4"
|
||||
cmsWidgetName="VehicleModelQuestion"
|
||||
:updateValues="updateModelValues"
|
||||
validationRules="model-required"
|
||||
inputId="modelQuestionField" />
|
||||
<vehicleQuestion
|
||||
ref="vehicleStyleQuestion"
|
||||
v-model="selectedStyle"
|
||||
class="mb-2 mt-4"
|
||||
cmsWidgetName="VehicleStyleQuestion"
|
||||
:updateValues="updateStyleValues"
|
||||
validationRules="style-required"
|
||||
inputId="styleQuestionField" />
|
||||
<vehicleQuestion
|
||||
ref="vehicleYearQuestion"
|
||||
v-model="selectedYear"
|
||||
class="mb-2 mt-4"
|
||||
cmsWidgetName="VehicleYearQuestion"
|
||||
:updateValues="updateYearValues"
|
||||
validationRules="year-required"
|
||||
inputId="yearQuestionField"
|
||||
/>
|
||||
<vehicleQuestion
|
||||
ref="vehicleMakeQuestion"
|
||||
v-model="selectedMake"
|
||||
class="mb-2 mt-4"
|
||||
cmsWidgetName="VehicleMakeQuestion"
|
||||
:updateValues="updateMakeValues"
|
||||
validationRules="make-required"
|
||||
inputId="makeQuestionField"
|
||||
/>
|
||||
<vehicleQuestion
|
||||
ref="vehicleModelQuestion"
|
||||
v-model="selectedModel"
|
||||
class="mb-2 mt-4"
|
||||
cmsWidgetName="VehicleModelQuestion"
|
||||
:updateValues="updateModelValues"
|
||||
validationRules="model-required"
|
||||
inputId="modelQuestionField"
|
||||
/>
|
||||
<vehicleQuestion
|
||||
ref="vehicleStyleQuestion"
|
||||
v-model="selectedStyle"
|
||||
class="mb-2 mt-4"
|
||||
cmsWidgetName="VehicleStyleQuestion"
|
||||
:updateValues="updateStyleValues"
|
||||
validationRules="style-required"
|
||||
inputId="styleQuestionField"
|
||||
/>
|
||||
|
||||
<vehicleBanner
|
||||
ref="banner"
|
||||
cmsWidgetName="VehicleBannerWidget"
|
||||
:displayGenericVehicleImage="displayGeneric"
|
||||
class="mt-5 mb-3" />
|
||||
<vehicleBanner
|
||||
ref="banner"
|
||||
cmsWidgetName="VehicleBannerWidget"
|
||||
:displayGenericVehicleImage="displayGeneric"
|
||||
class="mt-5 mb-3"
|
||||
/>
|
||||
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
class="mt-5"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
@backClicked="navigateBack" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
class="mt-5"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
@backClicked="navigateBack"
|
||||
/>
|
||||
</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 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) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
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);
|
||||
});
|
||||
},
|
||||
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;
|
||||
},
|
||||
},
|
||||
|
||||
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();
|
||||
}
|
||||
watch: {
|
||||
selectedYear(value) {
|
||||
this.mainStore.updateVehicleYear(value);
|
||||
this.$refs.vehicleMakeQuestion.clearValues();
|
||||
if (value) {
|
||||
this.$refs.vehicleMakeQuestion.getNewValues();
|
||||
}
|
||||
},
|
||||
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();
|
||||
}
|
||||
selectedMake(value) {
|
||||
this.mainStore.updateVehicleMake(value);
|
||||
this.$refs.vehicleModelQuestion.clearValues();
|
||||
if (value) {
|
||||
this.$refs.vehicleModelQuestion.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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.select-car-form {
|
||||
margin-left: .75rem;
|
||||
margin-right: .75rem;
|
||||
}
|
||||
.siteSubHeader {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
.select-car-form {
|
||||
margin-left: 0.75rem;
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
.siteSubHeader {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.subheader-secondary {
|
||||
margin-top: .5rem;
|
||||
padding: 0px;
|
||||
}
|
||||
.subheader-secondary {
|
||||
margin-top: 0.5rem;
|
||||
padding: 0px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,283 +1,308 @@
|
|||
<template>
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit">
|
||||
<div class="page-container-grouped-styles">
|
||||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="select-car">
|
||||
<div class="container-fluid pb-2">
|
||||
<div class="row px-3">
|
||||
<div class="col">
|
||||
<div class="select-car-form rounded">
|
||||
<vehicleBanner
|
||||
class="mt-2 mb-4"
|
||||
cmsWidgetName="VehicleBannerWidget"
|
||||
:displayGenericVehicleImage="!carIdIsValid" />
|
||||
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
|
||||
<vinLookupAlerts
|
||||
class="mt-5"
|
||||
:activeAlertType="activeVehicleLookupAlertType" />
|
||||
<vinQuestion
|
||||
v-model="vin"
|
||||
:mask="vinMask"
|
||||
:isDisabled="vinPopulatedOnPageLoad"
|
||||
textPosition="left" />
|
||||
<vinLocationInformation />
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
class="mt-5"
|
||||
@backClicked="navigateBack"
|
||||
@forwardClicked="forwardButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Form
|
||||
ref="theForm"
|
||||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit"
|
||||
>
|
||||
<div class="container-fluid fade-on-route-transition">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<div class="select-car-form rounded">
|
||||
<vehicleBanner
|
||||
class="mt-2 mb-4"
|
||||
cmsWidgetName="VehicleBannerWidget"
|
||||
:displayGenericVehicleImage="!carIdIsValid"
|
||||
/>
|
||||
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
|
||||
<vinLookupAlerts
|
||||
class="mt-5"
|
||||
:activeAlertType="activeVehicleLookupAlertType"
|
||||
/>
|
||||
<vinQuestion
|
||||
v-model="vin"
|
||||
:mask="vinMask"
|
||||
:isDisabled="vinPopulatedOnPageLoad"
|
||||
textPosition="left"
|
||||
/>
|
||||
<vinLocationInformation />
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
class="mt-5"
|
||||
@backClicked="navigateBack"
|
||||
@forwardClicked="forwardButtonAction"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</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
|
||||
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
|
||||
);
|
||||
},
|
||||
mixins: [baseFormMixin, vehicleQuestionsMixin],
|
||||
provide() {
|
||||
return {
|
||||
vehicleFromLookup: computed(() => this.vehicleFromLookup)
|
||||
};
|
||||
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();
|
||||
},
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
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();
|
||||
|
||||
// Settle promises and get results
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: 'cmsContent',
|
||||
promise: cmsContentPromise
|
||||
}
|
||||
];
|
||||
if (this.needToLookupVehicle) {
|
||||
const vehicleLookupResponse = await this.lookupVehicleByVin(this.vin);
|
||||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
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;
|
||||
}
|
||||
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
this.mainStore.resetBailout();
|
||||
|
||||
// Add vin bcs the response from the service doesn't contain vin
|
||||
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, {
|
||||
vin: this.vin,
|
||||
});
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
}
|
||||
|
||||
return { mainStore };
|
||||
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.needToLookupVehicle = false;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
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() 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Comes from vehicleQuestionsMixin.navigateForward()
|
||||
await this.navigateForward(
|
||||
partsOrQuestionsResponse.data.partsOrQuestions,
|
||||
this
|
||||
);
|
||||
|
||||
return null;
|
||||
},
|
||||
data() {
|
||||
const vin = this.getVinFromStore();
|
||||
async lookupVehicleByVin(vin) {
|
||||
try {
|
||||
return await this.mainStore.lookupVehicleByVin(vin);
|
||||
} catch (responseError) {
|
||||
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()
|
||||
error: {
|
||||
status: responseError.status,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
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();
|
||||
}
|
||||
resetActiveAlert() {
|
||||
this.activeVehicleLookupAlertType = null;
|
||||
},
|
||||
watch: {
|
||||
vin() {
|
||||
this.resetActiveAlert();
|
||||
this.$refs.siteFooter.enableForwardAction();
|
||||
this.needToLookupVehicle = true;
|
||||
this.$refs.siteFooter.updateButtonText(this.getCmsContent('SiteFooterWidget', 'ForwardButtonText'));
|
||||
}
|
||||
resetVehicleFromLookup() {
|
||||
this.vehicleFromLookup = null;
|
||||
},
|
||||
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();
|
||||
|
||||
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.needToLookupVehicle = false;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
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() 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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() {}
|
||||
}
|
||||
resetDependentState() {},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
>
|
||||
<div class="container-fluid fade-on-route-transition">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6 px-0 px-md-2">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -142,6 +142,8 @@
|
|||
</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" />
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue