Merge pull request #1347 from Safelite/CSR-1592-set-desktop-max-width

Csr 1592 set desktop max width
This commit is contained in:
bmauger 2023-09-19 14:46:59 -04:00 committed by GitHub
commit 8f0f49190e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1003 additions and 903 deletions

View file

@ -192,7 +192,7 @@ export default {
classes = "d-flex flex-row p-0"; classes = "d-flex flex-row p-0";
break; break;
case "listCard": case "listCard":
classes = "row g-2 justify-content-center mb-1"; classes = "row g-2 g-md-5 justify-content-center mb-1";
if (this.isWide) { if (this.isWide) {
classes += "flex-column"; classes += "flex-column";
} }

View file

@ -23,8 +23,8 @@
:answerKey="questionsDatum.answerKey" :answerKey="questionsDatum.answerKey"
:validationRules="validationRules" /> :validationRules="validationRules" />
</div> </div>
<funnel-footer <navbar
ref="funnelFooter" ref="navbar"
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!isMetaValid" :isForwardActionDisabled="!isMetaValid"
@back-clicked="handleBackButtonAction" @back-clicked="handleBackButtonAction"
@ -40,7 +40,7 @@ import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import alert from "@/ux-components/alert/alert"; import alert from "@/ux-components/alert/alert";
import questionChain from "@/digital-components/question-chain/question-chain"; import questionChain from "@/digital-components/question-chain/question-chain";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue"; import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
export default { export default {
@ -88,7 +88,7 @@ export default {
alert, alert,
questionChain, questionChain,
funnelSubHeader, funnelSubHeader,
funnelFooter, navbar,
loadingModal, loadingModal,
}, },
}; };

View file

@ -1,10 +1,10 @@
import { mount } from "@vue/test-utils"; import { mount } from "@vue/test-utils";
import funnelFooter from "./funnel-footer"; import navbar from "./nav-bar";
describe("funnel-footer.vue", () => { describe("nav-bar.vue", () => {
test("Should emit ForwardClicked on button click", async () => { test("Should emit ForwardClicked on button click", async () => {
// Act // Act
const wrapper = mount(funnelFooter, { const wrapper = mount(navbar, {
mixins: [mockMixin], mixins: [mockMixin],
}); });
wrapper.vm.buttonClick(); wrapper.vm.buttonClick();
@ -14,7 +14,7 @@ describe("funnel-footer.vue", () => {
test("Should emit BackClicked on link click", async () => { test("Should emit BackClicked on link click", async () => {
// Act // Act
const wrapper = mount(funnelFooter, { const wrapper = mount(navbar, {
mixins: [mockMixin], mixins: [mockMixin],
}); });
wrapper.vm.linkClick(); wrapper.vm.linkClick();
@ -24,7 +24,7 @@ describe("funnel-footer.vue", () => {
test("Should change button text when update button text is called", async () => { test("Should change button text when update button text is called", async () => {
// Act // Act
const wrapper = mount(funnelFooter, { const wrapper = mount(navbar, {
mixins: [mockMixin], mixins: [mockMixin],
}); });
wrapper.vm.updateButtonText("newText"); wrapper.vm.updateButtonText("newText");
@ -35,7 +35,7 @@ describe("funnel-footer.vue", () => {
test("should run removeLoader fn on buttonMain and return false for onkeydown fn", async () => { test("should run removeLoader fn on buttonMain and return false for onkeydown fn", async () => {
// Arrange // Arrange
const wrapper = mount(funnelFooter, { const wrapper = mount(navbar, {
mixins: [mockMixin], mixins: [mockMixin],
}); });

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="row"></div> <div class="row"></div>
<footer class="footer container-fluid g-5 my-5 px-0" id="infoBox"> <div class="nav-bar container-fluid g-5 my-5 px-0" id="infoBox">
<div class="row d-flex flex-row-reverse align-items-center vw-100"> <div class="row d-flex flex-row-reverse align-items-center vw-100">
<div class="col button-col d-flex" id="stacked"> <div class="col button-col d-flex" id="stacked">
<buttonMain <buttonMain
@ -13,7 +13,7 @@
:isDisabled="isForwardActionDisabled" :isDisabled="isForwardActionDisabled"
@click-event="buttonClick" @click-event="buttonClick"
data-bs-target="#footerModal" data-bs-target="#footerModal"
data-test-id="funnel-footer-main-button" data-test-id="nav-bar-main-button"
data-bs-dismiss="modal" /> data-bs-dismiss="modal" />
</div> </div>
<div v-if="!isBackButtonHidden" class="col-auto link-col py-1 text-break"> <div v-if="!isBackButtonHidden" class="col-auto link-col py-1 text-break">
@ -27,7 +27,7 @@
data-bs-dismiss="modal" /> data-bs-dismiss="modal" />
</div> </div>
</div> </div>
</footer> </div>
</template> </template>
<script> <script>
@ -35,7 +35,7 @@ import textLink from "@/ux-components/text-link/text-link";
import buttonMain from "@/ux-components/button-main/button-main"; import buttonMain from "@/ux-components/button-main/button-main";
export default { export default {
name: "funnelFooter", name: "navbar",
emits: ["BackClicked", "ForwardClicked"], // <--- should remove oodles of warnings in dev tools emits: ["BackClicked", "ForwardClicked"], // <--- should remove oodles of warnings in dev tools
props: { props: {
isForwardActionDisabled: Boolean, isForwardActionDisabled: Boolean,
@ -90,7 +90,7 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.footer { .nav-bar {
overflow: visible; overflow: visible;
display: flex; display: flex;
a { a {

View file

@ -722,8 +722,8 @@ function setupMocks({
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
wrapper.vm.setCmsContent = jest.fn(); wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); wrapper.vm.$refs.navbar.removeLoader = jest.fn();
return { wrapper }; return { wrapper };
} }

View file

@ -5,15 +5,23 @@
ref="theForm" ref="theForm"
v-slot="{ meta }" v-slot="{ meta }"
autocomplete="off"> autocomplete="off">
<div class="page-container-grouped-styles"> <div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
ref="vehicleBanner" ref="vehicleBanner"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" ref="funnelSubHeader" />
<div class="fade-on-route-transition sub-container make-tall">
<customerQuestions ref="customerQuestions" v-model="customerQuestions" /> <customerQuestions ref="customerQuestions" v-model="customerQuestions" />
<alert <alert
ref="alertVinNotFound" ref="alertVinNotFound"
v-if="displayVinNotFoundAlert" v-if="displayVinNotFoundAlert"
@ -21,6 +29,7 @@
cmsWidgetName="AlertVinNotFoundWidget" cmsWidgetName="AlertVinNotFoundWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
ref="alertMatchedDifferentVehicle" ref="alertMatchedDifferentVehicle"
v-if="displayMatchedDifferentVehicleAlert" v-if="displayMatchedDifferentVehicleAlert"
@ -29,6 +38,7 @@
:manualCopy="AlertMatchedDifferentVehicleBody" :manualCopy="AlertMatchedDifferentVehicleBody"
alertClass="alert-warning" alertClass="alert-warning"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
ref="alertInvalidZip" ref="alertInvalidZip"
v-if="displayInvalidZipAlert" v-if="displayInvalidZipAlert"
@ -36,6 +46,7 @@
cmsWidgetName="AlertInvalidZipWidget" cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
ref="alertNonServiceableZip" ref="alertNonServiceableZip"
v-if="displayNonServiceableZipAlert" v-if="displayNonServiceableZipAlert"
@ -44,6 +55,7 @@
:manualHeadline="AlertNonServiceableZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
:manualCopy="AlertNonServiceableZipBody" :manualCopy="AlertNonServiceableZipBody"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
ref="alertVinLookupsByHomeAddressNotAllowed" ref="alertVinLookupsByHomeAddressNotAllowed"
v-if="displayVinLookupByHomeAddressNotAllowedAlert" v-if="displayVinLookupByHomeAddressNotAllowedAlert"
@ -51,8 +63,12 @@
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget" cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
<div class="service-zip-field" v-if="showServiceZipField" aria-live="polite"> <div
class="service-zip-field"
v-if="showServiceZipField"
aria-live="polite">
<div class="row mt-4 mb-1"> <div class="row mt-4 mb-1">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
@ -67,22 +83,23 @@
</div> </div>
</div> </div>
</transition> </transition>
<funnel-footer <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter" ref="navbar"
:isDisabled="!meta.valid" :isDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction" @ForwardClicked="forwardButtonAction"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
:isForwardActionDisabled="!meta.valid" /> :isForwardActionDisabled="!meta.valid" />
</div> </div>
</div> </div>
</div>
</Form> </Form>
</template> </template>
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions"; import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions";
@ -241,14 +258,14 @@ export default {
if (!resultMap.vinLookupResponse.isStatePermissible) { if (!resultMap.vinLookupResponse.isStatePermissible) {
// State Restrictions forbid lookup by address // State Restrictions forbid lookup by address
this.displayVinLookupByHomeAddressNotAllowedAlert = true; this.displayVinLookupByHomeAddressNotAllowedAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
// If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert // If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert
const isZipValid = resultMap.serviceZipValidationResponse.isValid; const isZipValid = resultMap.serviceZipValidationResponse.isValid;
if (this.serviceZipCode && !isZipValid) { if (this.serviceZipCode && !isZipValid) {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
@ -271,10 +288,10 @@ export default {
); );
// Update button "Continue with..." // Update button "Continue with..."
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
`Continue with ${carFound.year} ${carFound.make} ${carFound.model}` `Continue with ${carFound.year} ${carFound.make} ${carFound.model}`
); );
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
// update data if the zip or service zip is serviceable // update data if the zip or service zip is serviceable
@ -294,7 +311,7 @@ export default {
} else { } else {
// No VINS found. // No VINS found.
this.displayVinNotFoundAlert = true; this.displayVinNotFoundAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
// If the either the registration zip code or service zip code are not serviceable // If the either the registration zip code or service zip code are not serviceable
@ -302,7 +319,7 @@ export default {
if (!this.isZipServiceable) { if (!this.isZipServiceable) {
this.displayNonServiceableZipAlert = true; this.displayNonServiceableZipAlert = true;
this.showServiceZipField = true; this.showServiceZipField = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
// If the registration zip code is serviceable and nothing was entered for the service zip code // If the registration zip code is serviceable and nothing was entered for the service zip code
@ -420,7 +437,7 @@ export default {
customerQuestions: { customerQuestions: {
handler(newValue) { handler(newValue) {
// if they modify one of the lookup fields (address, city, state, zipCode, or lastName), then modify the button text back to "Get my personalized quote" // if they modify one of the lookup fields (address, city, state, zipCode, or lastName), then modify the button text back to "Get my personalized quote"
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );
this.showServiceZipField = false; this.showServiceZipField = false;
@ -445,7 +462,7 @@ export default {
}, },
components: { components: {
funnelHeader, funnelHeader,
funnelFooter, navbar,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
customerQuestions, customerQuestions,

View file

@ -76,8 +76,8 @@ describe("addressVehicles.vue", () => {
}; };
// the following has to be set BEFORE changing the data which is being watched, and requires updateButtonText to be mocked // the following has to be set BEFORE changing the data which is being watched, and requires updateButtonText to be mocked
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); wrapper.vm.$refs.navbar.removeLoader = jest.fn();
wrapper.vm.lookupVin = jest.fn(() => Promise.resolve(lookupVinResponse)); wrapper.vm.lookupVin = jest.fn(() => Promise.resolve(lookupVinResponse));
wrapper.vm.$router.navigate = jest.fn(); wrapper.vm.$router.navigate = jest.fn();
wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(() => {}); wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(() => {});
@ -106,8 +106,8 @@ describe("addressVehicles.vue", () => {
}; };
// the following has to be set BEFORE changing the data which is being watched, and requires updateButtonText to be mocked // the following has to be set BEFORE changing the data which is being watched, and requires updateButtonText to be mocked
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); wrapper.vm.$refs.navbar.removeLoader = jest.fn();
wrapper.vm.lookupVin = jest.fn(() => Promise.reject(lookupVinResponse)); wrapper.vm.lookupVin = jest.fn(() => Promise.reject(lookupVinResponse));
wrapper.vm.$router.navigateWithSaving = jest.fn(); wrapper.vm.$router.navigateWithSaving = jest.fn();
wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(() => {}); wrapper.vm.updateCustomerInfo = jest.fn().mockImplementation(() => {});
@ -128,7 +128,7 @@ describe("addressVehicles.vue", () => {
test("Should navigate to CLICKED_FORWARD scenario if carId is different and selected glass not available for vehicle on navigateForward", async () => { test("Should navigate to CLICKED_FORWARD scenario if carId is different and selected glass not available for vehicle on navigateForward", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.$router.navigateWithSaving = jest.fn(); wrapper.vm.$router.navigateWithSaving = jest.fn();
// Act // Act
@ -148,7 +148,7 @@ describe("addressVehicles.vue", () => {
test("carId is not different on navigateForward (car was found) => Should handle navigating forward with car match", async () => { test("carId is not different on navigateForward (car was found) => Should handle navigating forward with car match", async () => {
// Arrange // Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
navigateToHeritage.navigateToHeritageFunnel = jest.fn(); navigateToHeritage.navigateToHeritageFunnel = jest.fn();
// Act // Act
@ -224,7 +224,7 @@ function setupMocks({}) {
const wrapper = shallowMount(addressVehicles, mountOptions); const wrapper = shallowMount(addressVehicles, mountOptions);
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn(); wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
return { wrapper }; return { wrapper };

View file

@ -27,9 +27,9 @@
class="mb-3" class="mb-3"
marginTopSizeOverride="3" /> marginTopSizeOverride="3" />
</div> </div>
<funnelFooter <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter" ref="navbar"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
@ -40,7 +40,7 @@
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import alert from "@/ux-components/alert/alert"; import alert from "@/ux-components/alert/alert";
@ -165,7 +165,7 @@ export default {
const vinLookup = await this.dispatchStoreAction(storeActions.LOOKUP_VEHICLE_BY_VIN, { const vinLookup = await this.dispatchStoreAction(storeActions.LOOKUP_VEHICLE_BY_VIN, {
vin: this.selectedVehicle.vin, vin: this.selectedVehicle.vin,
}).catch(() => { }).catch(() => {
this.$refs.funnelFooter.removeLoader(); this.$refs.navbar.removeLoader();
}); });
if (!vinLookup) { if (!vinLookup) {
@ -210,11 +210,11 @@ export default {
this.isCarIdDifferent = this.isCarIdDifferent =
this.selectedVehicle?.vehicle.carId !== store.getters.vehicle.carId; this.selectedVehicle?.vehicle.carId !== store.getters.vehicle.carId;
if (this.isCarIdDifferent) { if (this.isCarIdDifferent) {
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
`Continue with ${this.selectedVehicle.vehicle.year} ${this.selectedVehicle.vehicle.make} ${this.selectedVehicle.vehicle.model}` `Continue with ${this.selectedVehicle.vehicle.year} ${this.selectedVehicle.vehicle.make} ${this.selectedVehicle.vehicle.model}`
); );
} else { } else {
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );
} }
@ -229,7 +229,7 @@ export default {
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
alert, alert,
funnelFooter, navbar,
addressVehiclesQuestion, addressVehiclesQuestion,
textBlock, textBlock,
}, },

View file

@ -1,7 +1,13 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles"> <div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="my-5" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="my-5" />
<textboxQuestion <textboxQuestion
class="mb-4" class="mb-4"
@ -10,6 +16,7 @@
ref="firstName" ref="firstName"
customInputId="firstName" customInputId="firstName"
validationRules="first-name-required" /> validationRules="first-name-required" />
<textboxQuestion <textboxQuestion
class="mb-4" class="mb-4"
cmsWidgetName="LastNameWidget" cmsWidgetName="LastNameWidget"
@ -17,41 +24,49 @@
ref="lastName" ref="lastName"
customInputId="lastName" customInputId="lastName"
validationRules="last-name-required" /> validationRules="last-name-required" />
<textboxQuestion <textboxQuestion
class="mb-4" class="mb-4"
cmsWidgetName="emailQuestionWidget" cmsWidgetName="emailQuestionWidget"
v-model="emailAddress" v-model="emailAddress"
inputId="email" inputId="email"
validationRules="email-address-required|email-address-format" /> validationRules="email-address-required|email-address-format" />
<phoneNumberQuestion <phoneNumberQuestion
class="mb-4" class="mb-4"
cmsWidgetName="PhoneNumberQuestionWidget" cmsWidgetName="PhoneNumberQuestionWidget"
v-model="phoneNumber" v-model="phoneNumber"
isRequired isRequired
validationRules="phone-number-required" /> validationRules="phone-number-required" />
<checkboxQuestion <checkboxQuestion
class="mb-5" class="mb-5"
cmsWidgetName="TextMeQuestionWidget" cmsWidgetName="TextMeQuestionWidget"
v-model="isSmsOptIn" /> v-model="isSmsOptIn" />
<textareaQuestion <textareaQuestion
class="mb-4" class="mb-4"
v-model="techNotes" v-model="techNotes"
cmsWidgetName="TextAreaContentWidget" cmsWidgetName="TextAreaContentWidget"
maxLength="250" /> maxLength="250" />
<textBlock cmsWidgetName="DisclaimerCopyWidget" typeStyle="caption" /> <textBlock cmsWidgetName="DisclaimerCopyWidget" typeStyle="caption" />
<funnel-footer
<navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter" ref="navbar"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div>
</div>
</Form> </Form>
</template> </template>
<script> <script>
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import textareaQuestion from "@/digital-components/textarea-question/textarea-question"; import textareaQuestion from "@/digital-components/textarea-question/textarea-question";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question"; import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
@ -172,7 +187,7 @@ export default {
funnelSubHeader, funnelSubHeader,
textareaQuestion, textareaQuestion,
textboxQuestion, textboxQuestion,
funnelFooter, navbar,
Form, Form,
textBlock, textBlock,
phoneNumberQuestion, phoneNumberQuestion,

View file

@ -254,7 +254,7 @@ function setupMocks({
{ Name: "Provide my license plate # Most accurate VIN match" }, { Name: "Provide my license plate # Most accurate VIN match" },
{ Name: "Provide my home address Most convenient VIN match" }, { Name: "Provide my home address Most convenient VIN match" },
], ],
funnelFooterWidget = { ForwardButtonText: "test txt" }, FunnelFooterWidget = { ForwardButtonText: "test txt" },
mountOptionsMockData = { mountOptionsMockData = {
router: { router: {
navigate: jest.fn(), navigate: jest.fn(),
@ -271,7 +271,7 @@ function setupMocks({
groupName: groupName, groupName: groupName,
QuestionText: cmsQuestionText, QuestionText: cmsQuestionText,
Answers: cmsAnswers, Answers: cmsAnswers,
FunnelFooterWidget: funnelFooterWidget, FunnelFooterWidget: FunnelFooterWidget,
}; };
const apiPromise = Promise.resolve({ cmsContent }); const apiPromise = Promise.resolve({ cmsContent });

View file

@ -1,11 +1,16 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles">
<loadingModal ref="loadingModal" /> <loadingModal ref="loadingModal" />
<div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" /> <vehicleBanner cmsWidgetName="VehicleBannerWidget" />
<funnelSubHeader class="pb-4" cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader class="pb-4" cmsWidgetName="FunnelSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall">
<div v-if="!skipVin"> <div v-if="!skipVin">
<div class="vinlookupquestion" v-html="this.VinLookupQuestionText"></div> <div class="vinlookupquestion" v-html="this.VinLookupQuestionText"></div>
<buttonQuestion <buttonQuestion
@ -17,15 +22,22 @@
isRequired isRequired
validationRules="option-required" validationRules="option-required"
:logDisplayedValuesEvent="true" /> :logDisplayedValuesEvent="true" />
<navbar
cmsWidgetName="FunnelFooterWidget"
ref="navbar"
:isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" />
</div> </div>
<div v-else> <div v-else>
<alert <alert
class="my-4" class="my-4"
:cmsWidgetName="alertInfo" :cmsWidgetName="alertInfo"
alertClass="alert-info" alertClass="alert-info"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<div class="row my-2">
<div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="ServiceZipQuestionWidget" cmsWidgetName="ServiceZipQuestionWidget"
v-model="serviceZipCode" v-model="serviceZipCode"
@ -33,10 +45,7 @@
mask="#####" mask="#####"
isRequired isRequired
validationRules="zip-required|zip-format" /> validationRules="zip-required|zip-format" />
</div>
</div>
<div class="row mt-2">
<div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="EmailAddressQuestionWidget" cmsWidgetName="EmailAddressQuestionWidget"
v-model="emailAddress" v-model="emailAddress"
@ -44,15 +53,8 @@
isRequired isRequired
disableAutoFill disableAutoFill
validationRules="email-address-required|email-address-format" /> validationRules="email-address-required|email-address-format" />
</div> <textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" />
</div>
<div class="row mb-2">
<div class="col">
<textBlock
cmsWidgetName="QuoteEmailTextBlockWidget"
typeStyle="caption" />
</div>
</div>
<alert <alert
ref="alertInvalidZip" ref="alertInvalidZip"
v-if="displayInvalidZipAlert" v-if="displayInvalidZipAlert"
@ -60,6 +62,7 @@
cmsWidgetName="AlertInvalidZipWidget" cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertNonServiceableZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
@ -67,22 +70,24 @@
v-model="customAlertData" v-model="customAlertData"
v-if="displayNonServiceableZipAlert" v-if="displayNonServiceableZipAlert"
alertClass="alert-danger" /> alertClass="alert-danger" />
</div>
<funnel-footer <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter" ref="navbar"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div> </div>
</div>
</div>
</Form> </Form>
</template> </template>
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import buttonQuestion from "@/digital-components/button-question/button-question"; import buttonQuestion from "@/digital-components/button-question/button-question";
@ -238,13 +243,13 @@ export default {
if (!zipCodeData.isValid) { if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
if (!zipCodeData.isServiceable) { if (!zipCodeData.isServiceable) {
this.displayNonServiceableZipAlert = true; this.displayNonServiceableZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
this.displayNonServiceableZipAlert = false; this.displayNonServiceableZipAlert = false;
@ -346,7 +351,7 @@ export default {
funnelHeader, funnelHeader,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
funnelFooter, navbar,
buttonQuestion, buttonQuestion,
Form, Form,
alert, alert,

View file

@ -315,7 +315,7 @@ describe("license-plate-lookup.vue", () => {
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
//Assert //Assert
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); expect(wrapper.vm.$refs.navbar.updateButtonText).toHaveBeenCalled();
}); });
test("Button Text should revert to initial value when registrationZip textfield has new text", async () => { test("Button Text should revert to initial value when registrationZip textfield has new text", async () => {
@ -330,7 +330,7 @@ describe("license-plate-lookup.vue", () => {
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
//Assert //Assert
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); expect(wrapper.vm.$refs.navbar.updateButtonText).toHaveBeenCalled();
}); });
test("Button Text should revert to initial value when serviceZip textfield has new text", async () => { test("Button Text should revert to initial value when serviceZip textfield has new text", async () => {
@ -345,7 +345,7 @@ describe("license-plate-lookup.vue", () => {
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
//Assert //Assert
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toHaveBeenCalled(); expect(wrapper.vm.$refs.navbar.updateButtonText).toHaveBeenCalled();
}); });
}); });
@ -703,8 +703,8 @@ function setupMocks({
wrapper.vm.setCmsContent = jest.fn(); wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => ""); wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); wrapper.vm.$refs.navbar.removeLoader = jest.fn();
return { wrapper, apiPromise }; return { wrapper, apiPromise };
} }

View file

@ -1,52 +1,48 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles"> <div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall">
<div class="row mt-2 mb-4">
<div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="LicensePlateNumberQuestionWidget" cmsWidgetName="LicensePlateNumberQuestionWidget"
v-model="licensePlate" v-model="licensePlate"
isRequired isRequired
customInputId="licensePlate" customInputId="licensePlate"
validationRules="license-plate-required" /> validationRules="license-plate-required" />
</div>
</div>
<div class="row mt-0 mb-4">
<div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="RegistrationZipQuestionWidget" cmsWidgetName="RegistrationZipQuestionWidget"
v-model="registrationZipCode" v-model="registrationZipCode"
customInputId="zip" customInputId="zip"
mask="#####" mask="#####"
validationRules="registration-zip-required|zip-format" /> validationRules="registration-zip-required|zip-format" />
</div>
</div>
<div class="row mt-0">
<div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="EmailAddressQuestionWidget" cmsWidgetName="EmailAddressQuestionWidget"
v-model="email" v-model="email"
customInputId="email" customInputId="email"
validationRules="email-address-required|email-address-format" /> validationRules="email-address-required|email-address-format" />
</div>
</div>
<div class="row mb-2">
<div class="col">
<textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" /> <textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" />
</div>
</div>
<alert <alert
v-if="displayInvalidZipAlert" v-if="displayInvalidZipAlert"
class="my-3" class="my-3"
cmsWidgetName="AlertInvalidZipWidget" cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
v-if="displayNonServiceableZipAlert" v-if="displayNonServiceableZipAlert"
class="my-3" class="my-3"
@ -54,6 +50,7 @@
:manualCopy="AlertNonServiceableZipBody" :manualCopy="AlertNonServiceableZipBody"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<div class="row mt-2" v-if="showServiceZipField"> <div class="row mt-2" v-if="showServiceZipField">
<div class="col mb-1"> <div class="col mb-1">
<textboxQuestion <textboxQuestion
@ -64,12 +61,14 @@
mask="#####" /> mask="#####" />
</div> </div>
</div> </div>
<alert <alert
v-if="displayVinNotFoundAlert" v-if="displayVinNotFoundAlert"
class="my-3" class="my-3"
cmsWidgetName="AlertVinNotFoundWidget" cmsWidgetName="AlertVinNotFoundWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
v-if="displayMatchedDifferentVehicleAlert" v-if="displayMatchedDifferentVehicleAlert"
class="my-3" class="my-3"
@ -77,21 +76,23 @@
:manualCopy="AlertMatchedDifferentVehicleBody" :manualCopy="AlertMatchedDifferentVehicleBody"
alertClass="alert-warning" alertClass="alert-warning"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<funnelFooter
ref="funnelFooter" <navbar
ref="navbar"
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div> </div>
</div>
</Form> </Form>
</template> </template>
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import alert from "@/ux-components/alert/alert"; import alert from "@/ux-components/alert/alert";
@ -230,7 +231,7 @@ export default {
).catch(() => { ).catch(() => {
// No VIN found. // No VIN found.
this.displayVinNotFoundAlert = true; this.displayVinNotFoundAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
}); });
// If no VIN was found, stop processing after displaying alert // If no VIN was found, stop processing after displaying alert
if (!vinLookup) { if (!vinLookup) {
@ -241,7 +242,7 @@ export default {
const isZipValid = resultMap.serviceZipValidationResponse.isValid; const isZipValid = resultMap.serviceZipValidationResponse.isValid;
if (this.serviceZipCode && !isZipValid) { if (this.serviceZipCode && !isZipValid) {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
@ -264,10 +265,10 @@ export default {
); );
// Update button "Continue with..." // Update button "Continue with..."
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
`Continue with ${vinLookup.data.vehicle.year} ${vinLookup.data.vehicle.make} ${vinLookup.data.vehicle.model}` `Continue with ${vinLookup.data.vehicle.year} ${vinLookup.data.vehicle.make} ${vinLookup.data.vehicle.model}`
); );
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
// If the either the registration zip code or service zip code are not serviceable // If the either the registration zip code or service zip code are not serviceable
@ -275,7 +276,7 @@ export default {
if (!this.isZipServiceable) { if (!this.isZipServiceable) {
this.displayNonServiceableZipAlert = true; this.displayNonServiceableZipAlert = true;
this.showServiceZipField = true; this.showServiceZipField = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
// If the registration zip code is serviceable and nothing was entered for the service zip code // If the registration zip code is serviceable and nothing was entered for the service zip code
@ -367,26 +368,26 @@ export default {
}, },
watch: { watch: {
licensePlate() { licensePlate() {
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );
}, },
registrationZipCode() { registrationZipCode() {
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );
}, },
serviceZipCode() { serviceZipCode() {
// If they modify the service zip code, then hide the error message. // If they modify the service zip code, then hide the error message.
this.displayNonServiceableZipAlert = false; this.displayNonServiceableZipAlert = false;
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );
}, },
}, },
components: { components: {
funnelHeader, funnelHeader,
funnelFooter, navbar,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
textboxQuestion, textboxQuestion,

View file

@ -6,7 +6,7 @@
<funnelSubHeader class="mb-5" cmsWidgetName="FunnelSubHeaderWidget" leftAlignHeader /> <funnelSubHeader class="mb-5" cmsWidgetName="FunnelSubHeaderWidget" leftAlignHeader />
<hr class="mt-0" /> <hr class="mt-0" />
<div class="fade-on-route-transition sub-container make-tall"> <div class="fade-on-route-transition sub-container make-tall">
<funnel-footer <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
:isBackButtonHidden="shouldHideBackButton" :isBackButtonHidden="shouldHideBackButton"
@ -20,7 +20,7 @@
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
@ -63,7 +63,7 @@ export default {
}, },
components: { components: {
funnelHeader, funnelHeader,
funnelFooter, navbar,
funnelSubHeader, funnelSubHeader,
Form, Form,
}, },

View file

@ -1,18 +1,26 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles">
<loadingModal ref="loadingModal" /> <loadingModal ref="loadingModal" />
<div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader class="mb-5" cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader class="mb-5" cmsWidgetName="FunnelSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall">
<cashOrInsuranceQuestion <cashOrInsuranceQuestion
ref="cashOrInsurance" ref="cashOrInsurance"
cmsWidgetName="CashOrInsuranceQuestionWidget" cmsWidgetName="CashOrInsuranceQuestionWidget"
v-model="isInsuranceSelected" v-model="isInsuranceSelected"
groupName="CashOrInsuranceQuestion" /> groupName="CashOrInsuranceQuestion" />
<servicePackageQuestion <servicePackageQuestion
ref="servicePackage" ref="servicePackage"
cashCmsWidgetName="CashServicePackageQuestionWidget" cashCmsWidgetName="CashServicePackageQuestionWidget"
@ -30,11 +38,13 @@
justifyText="left" justifyText="left"
typeStyle="caption" typeStyle="caption"
class="mt-4" /> class="mt-4" />
<contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" /> <contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" />
<contentGroupModal ref="FrontWiperModal" cmsWidgetName="FrontWiperModal" /> <contentGroupModal ref="FrontWiperModal" cmsWidgetName="FrontWiperModal" />
<contentGroupModal ref="RearWiperModal" cmsWidgetName="RearWiperModal" /> <contentGroupModal ref="RearWiperModal" cmsWidgetName="RearWiperModal" />
<contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" /> <contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />
<funnel-footer
<navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
:isBackButtonHidden="shouldHideBackButton" :isBackButtonHidden="shouldHideBackButton"
@ -42,13 +52,14 @@
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div> </div>
</div>
</Form> </Form>
</template> </template>
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import cashOrInsuranceQuestion from "./cash-or-insurance-question/cash-or-insurance-question"; import cashOrInsuranceQuestion from "./cash-or-insurance-question/cash-or-insurance-question";
@ -237,7 +248,7 @@ export default {
}, },
components: { components: {
funnelHeader, funnelHeader,
funnelFooter, navbar,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
Form, Form,

View file

@ -1,8 +1,14 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
<!-- When customer-details is added: v-slot="{ meta }" --> <!-- When customer-details is added: v-slot="{ meta }" -->
<div class="page-container-grouped-styles"> <div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
@ -89,17 +95,19 @@
<hr class="my-0" /> <hr class="my-0" />
</div> </div>
<funnelFooter <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div>
</div>
</Form> </Form>
</template> </template>
<script> <script>
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import buttonMain from "@/ux-components/button-main/button-main"; import buttonMain from "@/ux-components/button-main/button-main";
import textBlock from "@/digital-components/text-block/text-block"; import textBlock from "@/digital-components/text-block/text-block";
@ -292,7 +300,7 @@ export default {
}, },
components: { components: {
funnelHeader, funnelHeader,
funnelFooter, navbar,
vehicleBanner, vehicleBanner,
buttonMain, buttonMain,
textBlock, textBlock,

View file

@ -623,7 +623,7 @@ function setupMocks({ customMountOptions }) {
wrapper.vm.setCmsContent = jest.fn(); wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.$refs.datePicker.initializeComponent = jest.fn(); wrapper.vm.$refs.datePicker.initializeComponent = jest.fn();
wrapper.vm.$refs.locationAlerts.initializeComponent = jest.fn(); wrapper.vm.$refs.locationAlerts.initializeComponent = jest.fn();
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.$refs.timeSlotModalQuestion.openModal = jest.fn(); wrapper.vm.$refs.timeSlotModalQuestion.openModal = jest.fn();
return { wrapper }; return { wrapper };

View file

@ -1,8 +1,14 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles">
<loadingModal ref="loadingModal" /> <loadingModal ref="loadingModal" />
<div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" />
<template v-if="ChangeShopLink.length"> <template v-if="ChangeShopLink.length">
<textBlock <textBlock
@ -35,24 +41,30 @@
:appointmentType="appointmentType" :appointmentType="appointmentType"
:premiumAppointmentFee="mobilePremiumAppointmentFee" :premiumAppointmentFee="mobilePremiumAppointmentFee"
:timeSlotsForSelectedDate="timeSlotsForSelectedDate" :timeSlotsForSelectedDate="timeSlotsForSelectedDate"
:estimatedServiceMinutesMinimum="selectableDatesData.estimatedServiceMinutesMinimum" :estimatedServiceMinutesMinimum="
:estimatedServiceMinutesMaximum="selectableDatesData.estimatedServiceMinutesMaximum" selectableDatesData.estimatedServiceMinutesMinimum
"
:estimatedServiceMinutesMaximum="
selectableDatesData.estimatedServiceMinutesMaximum
"
@time-slot-modal-closed="timeSlotModalClosed" @time-slot-modal-closed="timeSlotModalClosed"
validationRules="time-slot-selection-required" /> validationRules="time-slot-selection-required" />
<funnel-footer <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter" ref="navbar"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div>
</div>
</Form> </Form>
</template> </template>
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue"; import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import { Form, defineRule } from "vee-validate"; import { Form, defineRule } from "vee-validate";
@ -352,23 +364,23 @@ export default {
} }
}, },
updateFooterButtonText(timeSlotInfo) { updateFooterButtonText(timeSlotInfo) {
let funnelFooterButtonText; let navbarButtonText;
if (!timeSlotInfo || !timeSlotInfo.timeSlot.date) { if (!timeSlotInfo || !timeSlotInfo.timeSlot.date) {
funnelFooterButtonText = "Continue"; navbarButtonText = "Continue";
} else { } else {
funnelFooterButtonText = `Select ${this.convertSelectedDateToShortMonthAndDay( navbarButtonText = `Select ${this.convertSelectedDateToShortMonthAndDay(
timeSlotInfo.timeSlot.date timeSlotInfo.timeSlot.date
)}`; )}`;
if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) { if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
funnelFooterButtonText += ` at ${this.getDisplayTextForMilitaryTime( navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.startTime timeSlotInfo.timeSlot.startTime
)}`; )}`;
} else if ( } else if (
this.appointmentType === AppointmentTypeStrings.MOBILE && this.appointmentType === AppointmentTypeStrings.MOBILE &&
!timeSlotInfo.isPremiumAppointment !timeSlotInfo.isPremiumAppointment
) { ) {
funnelFooterButtonText += ` at ${this.getDisplayTextForMilitaryTime( navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
timeSlotInfo.timeSlot.startTime, timeSlotInfo.timeSlot.startTime,
true true
)} - ${this.getDisplayTextForMilitaryTime( )} - ${this.getDisplayTextForMilitaryTime(
@ -377,7 +389,7 @@ export default {
)}`; )}`;
} }
} }
this.$refs.funnelFooter.updateButtonText(funnelFooterButtonText); this.$refs.navbar.updateButtonText(navbarButtonText);
}, },
convertSelectedDateToShortMonthAndDay(selectedDate) { convertSelectedDateToShortMonthAndDay(selectedDate) {
// This conversion ensures we don't get get GMT induced date changes // This conversion ensures we don't get get GMT induced date changes
@ -483,7 +495,7 @@ export default {
}, },
components: { components: {
funnelHeader, funnelHeader,
funnelFooter, navbar,
funnelSubHeader, funnelSubHeader,
Form, Form,
loadingModal, loadingModal,

View file

@ -1,9 +1,16 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles">
<loadingModal ref="loadingModal" /> <loadingModal ref="loadingModal" />
<div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" />
<serviceZipModalQuestion <serviceZipModalQuestion
v-model="serviceZipCodeQuestion" v-model="serviceZipCodeQuestion"
ref="serviceZipCodeQuestion" ref="serviceZipCodeQuestion"
@ -14,18 +21,21 @@
linkWidgetName="ServiceZipLinkWidget" linkWidgetName="ServiceZipLinkWidget"
modalWidgetName="ServiceZipModalWidget" modalWidgetName="ServiceZipModalWidget"
:onZipUpdateCallback="reloadShopData" /> :onZipUpdateCallback="reloadShopData" />
<alert <alert
ref="alertMilitaryBaseZip" ref="alertMilitaryBaseZip"
class="my-5" class="my-5"
cmsWidgetName="AlertMilitaryBaseZipWidget" cmsWidgetName="AlertMilitaryBaseZipWidget"
v-if="displayMilitaryZipAlert" v-if="displayMilitaryZipAlert"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
ref="alertMobileOnly" ref="alertMobileOnly"
class="my-5" class="my-5"
cmsWidgetName="AlertMobileOnlyWidget" cmsWidgetName="AlertMobileOnlyWidget"
v-if="displayServiceableMobileOnly" v-if="displayServiceableMobileOnly"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
ref="alertRecalNoMobile" ref="alertRecalNoMobile"
class="my-5" class="my-5"
@ -33,18 +43,21 @@
v-if="displayRecalibrationWarning" v-if="displayRecalibrationWarning"
@text-link-clicked="openModalAction" @text-link-clicked="openModalAction"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
ref="alertInshopOnly" ref="alertInshopOnly"
class="my-5" class="my-5"
cmsWidgetName="AlertInshopOnlyWidget" cmsWidgetName="AlertInshopOnlyWidget"
v-if="displayServiceableInshopOnly" v-if="displayServiceableInshopOnly"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
ref="alertNoShops" ref="alertNoShops"
class="my-5" class="my-5"
cmsWidgetName="AlertNoShopsWidget" cmsWidgetName="AlertNoShopsWidget"
v-if="displayNoShopsAlert" v-if="displayNoShopsAlert"
alertClass="alert-warning" /> alertClass="alert-warning" />
<appointmentTypeQuestion <appointmentTypeQuestion
v-model="selectedAppointmentType" v-model="selectedAppointmentType"
v-show="isAppointmentTypeDisplayed" v-show="isAppointmentTypeDisplayed"
@ -55,6 +68,7 @@
groupName="appointmentTypeQuestion" groupName="appointmentTypeQuestion"
cmsWidgetName="AppointmentTypeQuestionWidget" cmsWidgetName="AppointmentTypeQuestionWidget"
validationRules="option-required" /> validationRules="option-required" />
<mobileLocationModalQuestions <mobileLocationModalQuestions
customComponentId="mobileLocationQuestions" customComponentId="mobileLocationQuestions"
v-if="selectedAppointmentType === 'Mobile'" v-if="selectedAppointmentType === 'Mobile'"
@ -68,6 +82,7 @@
linkWidgetName="MobileLocationLinkWidget" linkWidgetName="MobileLocationLinkWidget"
modalWidgetName="MobileLocationModalWidget" modalWidgetName="MobileLocationModalWidget"
:onZipUpdateCallback="reloadShopData" /> :onZipUpdateCallback="reloadShopData" />
<shopQuestion <shopQuestion
ref="shopQuestion" ref="shopQuestion"
v-show="isShopQuestionDisplayed" v-show="isShopQuestionDisplayed"
@ -75,14 +90,18 @@
:selectedAppointmentType="selectedAppointmentType" :selectedAppointmentType="selectedAppointmentType"
:isDisplayed="isShopQuestionDisplayed" :isDisplayed="isShopQuestionDisplayed"
cmsWidgetName="ShopQuestionWidget" /> cmsWidgetName="ShopQuestionWidget" />
<contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" /> <contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />
<funnel-footer
<navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter" ref="navbar"
:isForwardActionDisabled="!meta.valid || displayNoShopsAlert" :isForwardActionDisabled="!meta.valid || displayNoShopsAlert"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div>
</div>
</Form> </Form>
</template> </template>
@ -95,7 +114,7 @@ import appointmentTypeQuestion from "@/layouts/service-location/appointment-type
import shopQuestion from "@/layouts/service-location/shop-question/shop-question"; import shopQuestion from "@/layouts/service-location/shop-question/shop-question";
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue"; import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import { Form } from "vee-validate"; import { Form } from "vee-validate";
@ -456,7 +475,7 @@ export default {
appointmentTypeQuestion, appointmentTypeQuestion,
mobileLocationModalQuestions, mobileLocationModalQuestions,
funnelHeader, funnelHeader,
funnelFooter, navbar,
funnelSubHeader, funnelSubHeader,
Form, Form,
loadingModal, loadingModal,

View file

@ -1,12 +1,19 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles"> <div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall">
<alert <alert
ref="vehicleChangeAlert" ref="vehicleChangeAlert"
v-if="shouldDisplayVehicleChangeAlert" v-if="shouldDisplayVehicleChangeAlert"
@ -14,23 +21,30 @@
cmsWidgetName="VehicleChangeAlert" cmsWidgetName="VehicleChangeAlert"
alertClass="alert-warning" alertClass="alert-warning"
:isDismissible="false" /> :isDismissible="false" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-8 col-xl-6">
<damageLocationQuestion <damageLocationQuestion
ref="damageLocation" ref="damageLocation"
cmsWidgetName="DamageLocationQuestion" cmsWidgetName="DamageLocationQuestion"
v-model="selectedDamageLocations" v-model="selectedDamageLocations"
groupName="DamageLocationQuestion" /> groupName="DamageLocationQuestion" />
<windshieldOptions <windshieldOptions
ref="windshieldOptions" ref="windshieldOptions"
v-model="selectedWindshieldOptions" v-model="selectedWindshieldOptions"
:hasRepairReplaceConflict="hasRepairReplaceConflict" :hasRepairReplaceConflict="hasRepairReplaceConflict"
:hasSplitSingleConflict="hasSplitSingleConflict" :hasSplitSingleConflict="hasSplitSingleConflict"
:selectedDamageLocations="selectedDamageLocations" /> :selectedDamageLocations="selectedDamageLocations" />
<alert <alert
v-if="hasRepairReplaceConflict" v-if="hasRepairReplaceConflict"
class="my-5" class="my-5"
cmsWidgetName="HasReplacementConflict" cmsWidgetName="HasReplacementConflict"
alertClass="alert-danger" alertClass="alert-danger"
:isDismissible="false" /> :isDismissible="false" />
<sideDoorOptions <sideDoorOptions
ref="sideDoorOptions" ref="sideDoorOptions"
cmsWidgetName="SideDoorSideQuestion" cmsWidgetName="SideDoorSideQuestion"
@ -38,6 +52,7 @@
v-model="sideDoorOptionsData" v-model="sideDoorOptionsData"
v-show="!hasRepairReplaceConflict" v-show="!hasRepairReplaceConflict"
:selectedDamageLocations="selectedDamageLocations" /> :selectedDamageLocations="selectedDamageLocations" />
<replaceOptionsQuestion <replaceOptionsQuestion
ref="backGlassOptions" ref="backGlassOptions"
cmsWidgetName="RearReplaceOptionsQuestion" cmsWidgetName="RearReplaceOptionsQuestion"
@ -45,7 +60,11 @@
v-model="selectedRearReplaceOptions" v-model="selectedRearReplaceOptions"
groupName="BackGlassReplaceOptionsQuestion" groupName="BackGlassReplaceOptionsQuestion"
validationRules="replace-options-required" /> validationRules="replace-options-required" />
<funnel-footer </div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
:isBackButtonHidden="shouldHideBackButton" :isBackButtonHidden="shouldHideBackButton"
@ -53,13 +72,14 @@
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div> </div>
</div>
</Form> </Form>
</template> </template>
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import sideDoorOptions from "@/layouts/vehicle-damage/side-door-options/side-door-options"; import sideDoorOptions from "@/layouts/vehicle-damage/side-door-options/side-door-options";
@ -509,7 +529,7 @@ export default {
components: { components: {
funnelHeader, funnelHeader,
funnelFooter, navbar,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
sideDoorOptions, sideDoorOptions,

View file

@ -542,7 +542,7 @@ function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {}
partQuestionRearWrapper.vm.initializeComponent = glassPartQuestion.methods.initializeComponent; partQuestionRearWrapper.vm.initializeComponent = glassPartQuestion.methods.initializeComponent;
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); wrapper.vm.$refs.navbar.removeLoader = jest.fn();
wrapper.vm.$refs.loadingModal.showModal = jest.fn(); wrapper.vm.$refs.loadingModal.showModal = jest.fn();
// wrapper.vm.$refs.onSubmit = jest.fn(); // wrapper.vm.$refs.onSubmit = jest.fn();
// wrapper.vm.$refs.onInvalidSubmit = jest.fn(); // wrapper.vm.$refs.onInvalidSubmit = jest.fn();

View file

@ -1,14 +1,22 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
<div class="page-container-grouped-styles vehicle-parts small-question-text"> <div class="vehicle-parts small-question-text">
<loadingModal ref="loadingModal" /> <loadingModal ref="loadingModal" />
<funnelHeader ref="funnelHeader" cmsWidgetName="FunnelHeaderWidget" /> <div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-lg-4">
<vehicleBanner <vehicleBanner
ref="vehicleBanner" ref="vehicleBanner"
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader ref="funnelSubHeader" cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader
<div class="fade-on-route-transition sub-container make-tall"> ref="funnelSubHeader"
cmsWidgetName="FunnelSubHeaderWidget" />
<div class="prevent-squish my-5"> <div class="prevent-squish my-5">
<div class="row"> <div class="row">
<div class="col pb-0"> <div class="col pb-0">
@ -25,20 +33,24 @@
<hr v-if="i > 0" /> <hr v-if="i > 0" />
<glassPartQuestion <glassPartQuestion
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`" :ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
v-model="selectedGlassParts[item.glassLocation + '-' + item.glassName]" v-model="
selectedGlassParts[item.glassLocation + '-' + item.glassName]
"
:glassLocation="item.glassLocation" :glassLocation="item.glassLocation"
:glassName="item.glassName" :glassName="item.glassName"
:colorAnswers="item.colorAnswers" :colorAnswers="item.colorAnswers"
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" /> :alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
</div> </div>
<funnelFooter <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter" ref="navbar"
:isForwardActionDisabled="isForwardActionDisabled" :isForwardActionDisabled="isForwardActionDisabled"
@back-clicked="navigateBack" @back-clicked="navigateBack"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div> </div>
</div>
</div>
</Form> </Form>
</template> </template>
@ -48,7 +60,7 @@ import glassPartQuestion from "@/layouts/vehicle-parts/glass-part-question/glass
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import alert from "@/ux-components/alert/alert"; import alert from "@/ux-components/alert/alert";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue"; import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
// Supporting Files // Supporting Files
@ -178,7 +190,7 @@ export default {
} }
// If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts) // If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts)
if (this.isForwardActionDisabled) { if (this.isForwardActionDisabled) {
this.$refs.funnelFooter.removeLoader(); this.$refs.navbar.removeLoader();
throw new Error("Could not match any parts to the selected parts"); throw new Error("Could not match any parts to the selected parts");
} }
@ -221,9 +233,19 @@ export default {
funnelHeader, funnelHeader,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
funnelFooter, navbar,
alert, alert,
loadingModal, loadingModal,
}, },
}; };
</script> </script>
<style lang="scss">
.vehicle-parts {
label {
&.list-card {
height: auto;
}
}
}
</style>

View file

@ -1,15 +1,14 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles position-relative"> <div class="container-fluid">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
<div class="select-car">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<div class="select-car-form rounded"> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
<funnelSubHeader </div>
cmsWidgetName="FunnelSubHeaderWidget" </div>
class="siteSubHeader" /> <div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="siteSubHeader" />
<vehicleQuestion <vehicleQuestion
ref="vehicleYearQuestion" ref="vehicleYearQuestion"
v-model="selectedYear" v-model="selectedYear"
@ -49,7 +48,7 @@
validationRules="style-required" validationRules="style-required"
placeHolderText="Select style" placeHolderText="Select style"
inputId="styleQuestionField" /> inputId="styleQuestionField" />
<div class="col-md-3">&nbsp;</div>
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="displayGeneric" :displayGenericVehicleImage="displayGeneric"
@ -59,13 +58,11 @@
class="mt-5 vehicle-footer" class="mt-5 vehicle-footer"
ref="banner" /> ref="banner" />
<funnelFooter <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
@ForwardClicked="forwardButtonAction" @ForwardClicked="forwardButtonAction"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
ref="funnelFooter" /> ref="navbar" />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -75,7 +72,7 @@
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import vehicleQuestion from "@/layouts/vehicle/vehicle-question/vehicle-question"; import vehicleQuestion from "@/layouts/vehicle/vehicle-question/vehicle-question";
@ -390,7 +387,7 @@ export default {
components: { components: {
funnelHeader, funnelHeader,
funnelFooter, navbar,
funnelSubHeader, funnelSubHeader,
vehicleBanner, vehicleBanner,
Form, Form,

View file

@ -47,14 +47,14 @@ jest.mock("@/helpers/damage-helper", () => ({
})); }));
describe("vin-lookup.vue", () => { describe("vin-lookup.vue", () => {
it("Should update the funnel-footer forward button when VIN is changed", (done) => { it("Should update the nav-bar forward button when VIN is changed", (done) => {
//Arrange //Arrange
const { wrapper } = setupMocks({}); const { wrapper } = setupMocks({});
//Act //Act
wrapper.setData({ vin: "newValue" }); wrapper.setData({ vin: "newValue" });
//Assert //Assert
wrapper.vm.$nextTick(() => { wrapper.vm.$nextTick(() => {
expect(wrapper.vm.$refs.funnelFooter.updateButtonText).toBeCalled(); expect(wrapper.vm.$refs.navbar.updateButtonText).toBeCalled();
done(); done();
}); });
}); });
@ -368,8 +368,8 @@ function mockOutPromises({ carId, isZipValid = true, isZipServiceable = true })
} }
function mockOutStubFunctions(wrapper) { function mockOutStubFunctions(wrapper) {
wrapper.vm.$refs.funnelFooter.updateButtonText = jest.fn(); wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
wrapper.vm.$refs.funnelFooter.removeLoader = jest.fn(); wrapper.vm.$refs.navbar.removeLoader = jest.fn();
wrapper.vm.getZipCodeData = jest wrapper.vm.getZipCodeData = jest
.fn() .fn()
.mockReturnValue({ isValid: true, isServiceable: true, state: "OH" }); .mockReturnValue({ isValid: true, isServiceable: true, state: "OH" });

View file

@ -1,23 +1,26 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles">
<loadingModal ref="loadingModal" /> <loadingModal ref="loadingModal" />
<div class="container-fluid">
<div class="row">
<div class="col">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
</div>
</div>
<div class="row justify-content-md-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner <vehicleBanner
cmsWidgetName="VehicleBannerWidget" cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" /> :displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<div class="fade-on-route-transition sub-container make-tall">
<div class="row mb-2">
<div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="VinNumberQuestionWidget" cmsWidgetName="VinNumberQuestionWidget"
v-model="vin" v-model="vin"
customInputId="vin" customInputId="vin"
isRequired isRequired
:validationRules=" :validationRules="!vinPopulatedOnPageLoad ? 'vin-required|vin-format' : ''"
!vinPopulatedOnPageLoad ? 'vin-required|vin-format' : ''
"
:isDisabled="vinPopulatedOnPageLoad" :isDisabled="vinPopulatedOnPageLoad"
maxLength="17" maxLength="17"
:mask="vinMask" :mask="vinMask"
@ -28,23 +31,14 @@
@image-validity-error="displayVinScanAlert" @image-validity-error="displayVinScanAlert"
data-test="vin-lookup-field" data-test="vin-lookup-field"
ref="vinLookupQuestion" /> ref="vinLookupQuestion" />
</div>
</div>
<div class="row">
<div class="col">
<alert <alert
cmsWidgetName="AlertVinScanFailed" cmsWidgetName="AlertVinScanFailed"
v-if="displayVinScanFailedAlert" v-if="displayVinScanFailedAlert"
alertClass="alert-danger" /> alertClass="alert-danger" />
</div>
</div>
<div class="row">
<div class="col">
<vinInformation /> <vinInformation />
</div>
</div>
<div class="row mb-0 mt-4">
<div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="ServiceZipQuestionWidget" cmsWidgetName="ServiceZipQuestionWidget"
v-model="serviceZipCode" v-model="serviceZipCode"
@ -52,23 +46,16 @@
mask="#####" mask="#####"
isRequired isRequired
validationRules="zip-required|zip-format" /> validationRules="zip-required|zip-format" />
</div>
</div>
<div class="row mt-4">
<div class="col">
<textboxQuestion <textboxQuestion
cmsWidgetName="EmailAddressQuestionWidget" cmsWidgetName="EmailAddressQuestionWidget"
v-model="emailAddress" v-model="emailAddress"
customInputId="emailAddress" customInputId="emailAddress"
isRequired isRequired
validationRules="email-address-required|email-address-format" /> validationRules="email-address-required|email-address-format" />
</div>
</div>
<div class="row mb-0">
<div class="col">
<textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" /> <textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" />
</div>
</div>
<alert <alert
ref="alertInvalidZip" ref="alertInvalidZip"
v-if="displayInvalidZipAlert" v-if="displayInvalidZipAlert"
@ -76,6 +63,7 @@
cmsWidgetName="AlertInvalidZipWidget" cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertPerfectMatchInsuranceVerifiedHeader" :manualHeadline="AlertPerfectMatchInsuranceVerifiedHeader"
@ -88,6 +76,7 @@
!displayNonServiceableZipAlert !displayNonServiceableZipAlert
" "
alertClass="alert-success" /> alertClass="alert-success" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertMatchedDifferentVehicleHeader" :manualHeadline="AlertMatchedDifferentVehicleHeader"
@ -95,6 +84,7 @@
v-model="customAlertData" v-model="customAlertData"
v-if="displayMatchedDifferentVehicleAlert" v-if="displayMatchedDifferentVehicleAlert"
alertClass="alert-warning" /> alertClass="alert-warning" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertNonServiceableZipHeader" :manualHeadline="AlertNonServiceableZipHeader"
@ -102,12 +92,14 @@
v-model="customAlertData" v-model="customAlertData"
v-if="displayNonServiceableZipAlert" v-if="displayNonServiceableZipAlert"
alertClass="alert-danger" /> alertClass="alert-danger" />
<alert <alert
class="my-4" class="my-4"
v-model="customAlertData" v-model="customAlertData"
v-if="displayVinNotFoundAlert" v-if="displayVinNotFoundAlert"
alertClass="alert-danger" alertClass="alert-danger"
cmsWidgetName="AlertVinNotFoundWidget" /> cmsWidgetName="AlertVinNotFoundWidget" />
<alert <alert
class="my-4" class="my-4"
:manualHeadline="AlertPerfectMatchInsuranceNotVerifiedHeader" :manualHeadline="AlertPerfectMatchInsuranceNotVerifiedHeader"
@ -120,21 +112,23 @@
!displayNonServiceableZipAlert !displayNonServiceableZipAlert
" "
alertClass="alert-success" /> alertClass="alert-success" />
<funnelFooter
<navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="funnelFooter" ref="navbar"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div> </div>
</div>
</Form> </Form>
</template> </template>
<script> <script>
// Components // Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import alert from "@/ux-components/alert/alert"; import alert from "@/ux-components/alert/alert";
@ -278,7 +272,7 @@ export default {
const isZipValid = resultMap.zipCodeData.isValid; const isZipValid = resultMap.zipCodeData.isValid;
if (this.serviceZipCode && !isZipValid) { if (this.serviceZipCode && !isZipValid) {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
@ -295,7 +289,7 @@ export default {
} }
// Remove loader and stop processing the page. // Remove loader and stop processing the page.
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
// Check if the CarId is different from the lookup vs what is in state currently. // Check if the CarId is different from the lookup vs what is in state currently.
@ -315,10 +309,10 @@ export default {
); );
// Update button "Continue with..." // Update button "Continue with..."
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
`Continue with ${resultMap.vehicleLookupResponse.year} ${resultMap.vehicleLookupResponse.make} ${resultMap.vehicleLookupResponse.model}` `Continue with ${resultMap.vehicleLookupResponse.year} ${resultMap.vehicleLookupResponse.make} ${resultMap.vehicleLookupResponse.model}`
); );
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
} }
// Save vin, vehicle, customer and service information // Save vin, vehicle, customer and service information
@ -380,7 +374,7 @@ export default {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
} }
return this.$refs.funnelFooter.removeLoader(); return this.$refs.navbar.removeLoader();
}, },
async navigateForward() { async navigateForward() {
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) { if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
@ -488,7 +482,7 @@ export default {
vin() { vin() {
this.displayVinNotFoundAlert = false; this.displayVinNotFoundAlert = false;
this.displayVinScanFailedAlert = false; this.displayVinScanFailedAlert = false;
this.$refs.funnelFooter.updateButtonText( this.$refs.navbar.updateButtonText(
this.getCmsContent("FunnelFooterWidget", "ForwardButtonText") this.getCmsContent("FunnelFooterWidget", "ForwardButtonText")
); );
}, },
@ -498,7 +492,7 @@ export default {
}, },
components: { components: {
funnelHeader, funnelHeader,
funnelFooter, navbar,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
textboxQuestion, textboxQuestion,

View file

@ -100,11 +100,11 @@ export default {
return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice; return lineItem.kitPrice + lineItem.laborAmount + lineItem.sellingPrice;
}, },
scrollToPageTop() { scrollToPageTop() {
const container = document.getElementsByClassName("page-container-grouped-styles")[0]; const container = document.getElementsByClassName("container-fluid")[0];
container.scrollTo({ top: 0, left: 0, behavior: "smooth" }); container.scrollTo({ top: 0, left: 0, behavior: "smooth" });
}, },
scrollToPageBottom() { scrollToPageBottom() {
const container = document.getElementsByClassName("page-container-grouped-styles")[0]; const container = document.getElementsByClassName("container-fluid")[0];
container.scrollTo({ top: container.scrollHeight, left: 0, behavior: "smooth" }); container.scrollTo({ top: container.scrollHeight, left: 0, behavior: "smooth" });
}, },
}, },

View file

@ -5,15 +5,7 @@ body {
background-color: #fff; background-color: #fff;
color: #4d5151; color: #4d5151;
.container-fluid { .container-fluid {
max-width: 576px; //Remove once desktop app is complete max-width: 1400px;
&.container-shadow {
box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.15); //Use instead of Bootstrap's helper
}
&.make-tall {
height: 100vh;
display: flex;
flex-direction: column;
}
.prevent-squish { .prevent-squish {
overflow-x: unset; overflow-x: unset;
} }
@ -44,10 +36,6 @@ body {
overflow: hidden; overflow: hidden;
} }
.page-container-grouped-styles {
@extend .container-fluid, .shadow, .rounded-3, .p-2, .position-relative, .make-tall, .px-5;
}
//Footer modal backdrop adjustments for positioning //Footer modal backdrop adjustments for positioning
.modal-backdrop { .modal-backdrop {
left: 50%; left: 50%;

View file

@ -170,15 +170,6 @@ $spacers: (
//Enable negative spacing (does NOT work on padding) //Enable negative spacing (does NOT work on padding)
$enable-negative-margins: true; $enable-negative-margins: true;
//Grid breakpoints
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 838px,
lg: 1074px,
xl: 1416px,
);
//Shadow //Shadow
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15); $box-shadow: 0 0.5rem 1rem rgba($black, 0.15);
$box-shadow-sm: 0 0.125rem 0.25rem rgba($black, 0.075); $box-shadow-sm: 0 0.125rem 0.25rem rgba($black, 0.075);