Merge pull request #1020 from Safelite/feature/CSR-1088
Feature/csr 1088
This commit is contained in:
commit
002aebb52b
7 changed files with 155 additions and 59 deletions
|
|
@ -25,6 +25,7 @@ const errorMessages = {
|
||||||
"Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q",
|
"Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q",
|
||||||
OPTION_REQUIRED: "Please select an option",
|
OPTION_REQUIRED: "Please select an option",
|
||||||
VEHICLE_REQUIRED: "Please select a vehicle",
|
VEHICLE_REQUIRED: "Please select a vehicle",
|
||||||
|
MOBILE_LOCATION_REQUIRED: "Please enter your service address",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { errorMessages };
|
export { errorMessages };
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
jest.mock("vee-validate", () => ({
|
jest.mock("vee-validate", () => ({
|
||||||
useForm: jest.fn(),
|
useForm: jest.fn(),
|
||||||
useIsFormTouched: jest.fn(),
|
|
||||||
useIsFormDirty: jest.fn(),
|
|
||||||
useIsFormValid: jest.fn(),
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const mockValidate = (returnValue) => jest.fn(async () => Promise.resolve({ valid: returnValue }));
|
const mockValidate = (returnValue) => jest.fn(async () => Promise.resolve({ valid: returnValue }));
|
||||||
|
const mockMeta = (returnValue) => jest.fn(async () => Promise.resolve(returnValue));
|
||||||
|
|
||||||
import { shallowMount } from "@vue/test-utils";
|
import { shallowMount } from "@vue/test-utils";
|
||||||
import modal from "./modal";
|
import modal from "./modal";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { useForm, useIsFormDirty, useIsFormTouched, useIsFormValid } from "vee-validate";
|
import { useForm } from "vee-validate";
|
||||||
import { Modal } from "bootstrap";
|
import { Modal } from "bootstrap";
|
||||||
|
|
||||||
const footerButtonText = "Sample footer text here.";
|
const footerButtonText = "Sample footer text here.";
|
||||||
|
|
@ -21,6 +19,18 @@ global.crypto = crypto;
|
||||||
describe("modal.vue", () => {
|
describe("modal.vue", () => {
|
||||||
it("Should display modal header text when headerText is defined", async () => {
|
it("Should display modal header text when headerText is defined", async () => {
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
|
const fakeMeta = {
|
||||||
|
touched: true,
|
||||||
|
dirty: true,
|
||||||
|
valid: true,
|
||||||
|
validated: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
useForm.mockReturnValue({
|
||||||
|
meta: mockMeta(fakeMeta),
|
||||||
|
validate: mockValidate(true),
|
||||||
|
});
|
||||||
|
|
||||||
const wrapper = shallowMount(modal, {
|
const wrapper = shallowMount(modal, {
|
||||||
props: {
|
props: {
|
||||||
headerText: headerText,
|
headerText: headerText,
|
||||||
|
|
@ -35,6 +45,17 @@ describe("modal.vue", () => {
|
||||||
|
|
||||||
it("Should display footer button text when footerButtonText is defined", async () => {
|
it("Should display footer button text when footerButtonText is defined", async () => {
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
|
const fakeMeta = {
|
||||||
|
touched: true,
|
||||||
|
dirty: true,
|
||||||
|
valid: true,
|
||||||
|
validated: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
useForm.mockReturnValue({
|
||||||
|
meta: mockMeta(fakeMeta),
|
||||||
|
validate: mockValidate(true),
|
||||||
|
});
|
||||||
const wrapper = shallowMount(modal, {
|
const wrapper = shallowMount(modal, {
|
||||||
props: {
|
props: {
|
||||||
footerButtonText: footerButtonText,
|
footerButtonText: footerButtonText,
|
||||||
|
|
@ -48,7 +69,15 @@ describe("modal.vue", () => {
|
||||||
|
|
||||||
it("Should emit 'footer-button-event' if the form is valid", async () => {
|
it("Should emit 'footer-button-event' if the form is valid", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
const fakeMeta = {
|
||||||
|
touched: true,
|
||||||
|
dirty: true,
|
||||||
|
valid: true,
|
||||||
|
validated: true,
|
||||||
|
};
|
||||||
|
|
||||||
useForm.mockReturnValue({
|
useForm.mockReturnValue({
|
||||||
|
meta: mockMeta(fakeMeta),
|
||||||
validate: mockValidate(true),
|
validate: mockValidate(true),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -72,7 +101,15 @@ describe("modal.vue", () => {
|
||||||
|
|
||||||
it("Should not emit 'footer-button-event' if the form is invalid", async () => {
|
it("Should not emit 'footer-button-event' if the form is invalid", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
const fakeMeta = {
|
||||||
|
touched: true,
|
||||||
|
dirty: true,
|
||||||
|
valid: false,
|
||||||
|
validated: true,
|
||||||
|
};
|
||||||
|
|
||||||
useForm.mockReturnValue({
|
useForm.mockReturnValue({
|
||||||
|
meta: mockMeta(fakeMeta),
|
||||||
validate: mockValidate(false),
|
validate: mockValidate(false),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -96,11 +133,17 @@ describe("modal.vue", () => {
|
||||||
|
|
||||||
it("Should have a disabled footer button when the form has not been touched", async () => {
|
it("Should have a disabled footer button when the form has not been touched", async () => {
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
useForm.mockReturnValue({
|
const fakeMeta = {
|
||||||
validate: mockValidate(false),
|
touched: true,
|
||||||
});
|
dirty: true,
|
||||||
|
valid: true,
|
||||||
|
validated: true,
|
||||||
|
};
|
||||||
|
|
||||||
useIsFormTouched.mockReturnValue(false);
|
useForm.mockReturnValue({
|
||||||
|
meta: mockMeta(fakeMeta),
|
||||||
|
validate: mockValidate(true),
|
||||||
|
});
|
||||||
|
|
||||||
const resetButtonStyle = jest.fn();
|
const resetButtonStyle = jest.fn();
|
||||||
const wrapper = shallowMount(modal, {
|
const wrapper = shallowMount(modal, {
|
||||||
|
|
@ -118,13 +161,17 @@ describe("modal.vue", () => {
|
||||||
|
|
||||||
it("Should have a disabled footer button when the form is invalid", async () => {
|
it("Should have a disabled footer button when the form is invalid", async () => {
|
||||||
// Arrange / Act
|
// Arrange / Act
|
||||||
useForm.mockReturnValue({
|
const fakeMeta = {
|
||||||
validate: mockValidate(false),
|
touched: true,
|
||||||
});
|
dirty: true,
|
||||||
|
valid: true,
|
||||||
|
validated: true,
|
||||||
|
};
|
||||||
|
|
||||||
useIsFormTouched.mockReturnValue(true);
|
useForm.mockReturnValue({
|
||||||
useIsFormDirty.mockReturnValue(true);
|
meta: mockMeta(fakeMeta),
|
||||||
useIsFormValid.mockReturnValue(false);
|
validate: mockValidate(true),
|
||||||
|
});
|
||||||
|
|
||||||
const resetButtonStyle = jest.fn();
|
const resetButtonStyle = jest.fn();
|
||||||
const wrapper = shallowMount(modal, {
|
const wrapper = shallowMount(modal, {
|
||||||
|
|
@ -142,12 +189,17 @@ describe("modal.vue", () => {
|
||||||
|
|
||||||
it("Should call bootstrap Modal method 'show' when calling 'openModal'", async () => {
|
it("Should call bootstrap Modal method 'show' when calling 'openModal'", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
useForm.mockReturnValue({
|
const fakeMeta = {
|
||||||
validate: mockValidate(false),
|
touched: true,
|
||||||
});
|
dirty: true,
|
||||||
|
valid: true,
|
||||||
|
validated: true,
|
||||||
|
};
|
||||||
|
|
||||||
useIsFormDirty.mockReturnValue(true);
|
useForm.mockReturnValue({
|
||||||
useIsFormValid.mockReturnValue(true);
|
meta: mockMeta(fakeMeta),
|
||||||
|
validate: mockValidate(true),
|
||||||
|
});
|
||||||
|
|
||||||
const showMock = jest.spyOn(Modal.prototype, "show");
|
const showMock = jest.spyOn(Modal.prototype, "show");
|
||||||
|
|
||||||
|
|
@ -170,13 +222,17 @@ describe("modal.vue", () => {
|
||||||
|
|
||||||
it("Should call bootstrap Modal method 'hide' when calling 'closeModal'", async () => {
|
it("Should call bootstrap Modal method 'hide' when calling 'closeModal'", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
const fakeMeta = {
|
||||||
|
touched: true,
|
||||||
|
dirty: true,
|
||||||
|
valid: true,
|
||||||
|
validated: true,
|
||||||
|
};
|
||||||
|
|
||||||
useForm.mockReturnValue({
|
useForm.mockReturnValue({
|
||||||
validate: mockValidate(false),
|
meta: mockMeta(fakeMeta),
|
||||||
|
validate: mockValidate(true),
|
||||||
});
|
});
|
||||||
|
|
||||||
useIsFormDirty.mockReturnValue(true);
|
|
||||||
useIsFormValid.mockReturnValue(true);
|
|
||||||
|
|
||||||
const hideMock = jest.spyOn(Modal.prototype, "hide");
|
const hideMock = jest.spyOn(Modal.prototype, "hide");
|
||||||
|
|
||||||
const resetButtonStyle = jest.fn();
|
const resetButtonStyle = jest.fn();
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
<script>
|
<script>
|
||||||
import buttonMain from "@/ux-components/button-main/button-main";
|
import buttonMain from "@/ux-components/button-main/button-main";
|
||||||
import { Modal } from "bootstrap";
|
import { Modal } from "bootstrap";
|
||||||
import { useForm, useIsFormTouched, useIsFormDirty, useIsFormValid } from "vee-validate";
|
import { useForm } from "vee-validate";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "modal",
|
name: "modal",
|
||||||
|
|
@ -60,22 +60,18 @@ export default {
|
||||||
setup() {
|
setup() {
|
||||||
const modalId = `modal-${crypto.randomUUID()}`;
|
const modalId = `modal-${crypto.randomUUID()}`;
|
||||||
|
|
||||||
const form = useForm();
|
const { meta, validate, resetForm } = useForm();
|
||||||
const isFormTouched = useIsFormTouched();
|
|
||||||
const isFormDirty = useIsFormDirty();
|
|
||||||
const isFormValid = useIsFormValid();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
modalId,
|
modalId,
|
||||||
form,
|
meta,
|
||||||
isFormTouched,
|
validate,
|
||||||
isFormDirty,
|
resetForm,
|
||||||
isFormValid,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async validateAndEmit() {
|
async validateAndEmit() {
|
||||||
const validationResult = await this.form.validate();
|
const validationResult = await this.validate();
|
||||||
if (validationResult.valid) {
|
if (validationResult.valid) {
|
||||||
this.$emit("footer-button-event");
|
this.$emit("footer-button-event");
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -103,10 +99,10 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isFooterButtonDisabled() {
|
isFooterButtonDisabled() {
|
||||||
if (!this.isFormTouched) {
|
if (!this.meta.touched) {
|
||||||
return !this.isFormValid;
|
return !this.meta.valid;
|
||||||
}
|
}
|
||||||
return !this.isFormDirty || !this.isFormValid;
|
return !this.meta.dirty || !this.meta.valid;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="textbox-question" :class="(errors && errors.length) || hasError ? 'has-error' : ''">
|
<div
|
||||||
|
class="textbox-question"
|
||||||
|
:class="[
|
||||||
|
(errors && errors.length) || hasError ? 'has-error' : '',
|
||||||
|
hideInput ? 'hide-input' : '',
|
||||||
|
]">
|
||||||
<label
|
<label
|
||||||
v-if="displayQuestionText"
|
v-if="displayQuestionText"
|
||||||
:for="inputId"
|
:for="inputId"
|
||||||
:aria-label="questionText"
|
:aria-label="questionText"
|
||||||
class="form-label"
|
class="form-label"
|
||||||
:class="[questionAlignment === 'center' ? 'text-center w-100 mb-5' : '']"
|
:class="[
|
||||||
|
questionAlignment === 'center' ? 'text-center w-100 mb-5' : '',
|
||||||
|
hideInput ? 'hide-input' : '',
|
||||||
|
]"
|
||||||
v-html="questionText"></label>
|
v-html="questionText"></label>
|
||||||
<div class="input-wrapper" :class="[includeSearchIcon ? 'has-search-icon' : '']">
|
<div class="input-wrapper" :class="[includeSearchIcon ? 'has-search-icon' : '']">
|
||||||
<input
|
<input
|
||||||
|
|
@ -25,6 +33,7 @@
|
||||||
hasIcon ? 'has-icon' : '',
|
hasIcon ? 'has-icon' : '',
|
||||||
iconRight ? 'icon-right' : '',
|
iconRight ? 'icon-right' : '',
|
||||||
cornerStyle === 'rounded' ? 'rounded-pill' : '',
|
cornerStyle === 'rounded' ? 'rounded-pill' : '',
|
||||||
|
hideInput ? 'hide-input' : '',
|
||||||
]"
|
]"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
|
|
@ -34,7 +43,12 @@
|
||||||
<button v-if="includeSearchIcon" type="submit" aria-label="Search button" />
|
<button v-if="includeSearchIcon" type="submit" aria-label="Search button" />
|
||||||
</div>
|
</div>
|
||||||
<div v-show="errorMessage" class="row my-1 form-test-error">
|
<div v-show="errorMessage" class="row my-1 form-test-error">
|
||||||
<span class="d-inline-flex small mt-0" role="alert">{{ errorMessage }}</span>
|
<span
|
||||||
|
class="d-inline-flex small mt-0"
|
||||||
|
role="alert"
|
||||||
|
:class="[centerErrorMessage ? 'center-error-message' : '']"
|
||||||
|
>{{ errorMessage }}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -74,6 +88,8 @@ export default {
|
||||||
questionAlignment: String, // Left or center. Left is default.
|
questionAlignment: String, // Left or center. Left is default.
|
||||||
cornerStyle: String, // Rounded or square. Square is default.
|
cornerStyle: String, // Rounded or square. Square is default.
|
||||||
includeSearchIcon: Boolean,
|
includeSearchIcon: Boolean,
|
||||||
|
hideInput: Boolean,
|
||||||
|
centerErrorMessage: Boolean,
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const inputId = !props.customInputId ? `input-${crypto.randomUUID()}` : props.customInputId;
|
const inputId = !props.customInputId ? `input-${crypto.randomUUID()}` : props.customInputId;
|
||||||
|
|
@ -142,6 +158,12 @@ export default {
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.textbox-question {
|
.textbox-question {
|
||||||
|
.hide-input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.center-error-message {
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
label {
|
label {
|
||||||
color: $black;
|
color: $black;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
:ref="modalName"
|
:ref="modalName"
|
||||||
:headerText="modalHeaderText"
|
:headerText="modalHeaderText"
|
||||||
:footerButtonText="modalFooterText"
|
:footerButtonText="modalFooterText"
|
||||||
|
:onModalOpenedCallback="onModalOpened"
|
||||||
|
:onModalClosedCallback="onModalClosed"
|
||||||
@footer-button-event="setMobileLocation">
|
@footer-button-event="setMobileLocation">
|
||||||
<addressQuestions
|
<addressQuestions
|
||||||
ref="addressQuestions"
|
ref="addressQuestions"
|
||||||
|
|
@ -56,7 +58,6 @@ import modal from "@/digital-components/modal/modal";
|
||||||
import alert from "@/ux-components/alert/alert";
|
import alert from "@/ux-components/alert/alert";
|
||||||
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
|
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
|
||||||
import vehicleProtectedQuestion from "@/layouts/service-location/mobile-location-modal-questions/vehicle-protected-question/vehicle-protected-question";
|
import vehicleProtectedQuestion from "@/layouts/service-location/mobile-location-modal-questions/vehicle-protected-question/vehicle-protected-question";
|
||||||
import store from "@/store";
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
import { deepClone } from "@/layouts/service-location/helpers/object-cloning-helper/object-cloning-helper";
|
import { deepClone } from "@/layouts/service-location/helpers/object-cloning-helper/object-cloning-helper";
|
||||||
|
|
@ -138,7 +139,6 @@ export default {
|
||||||
modalFooterText() {
|
modalFooterText() {
|
||||||
return this.getCmsContent(this.modalWidgetName, "FooterText");
|
return this.getCmsContent(this.modalWidgetName, "FooterText");
|
||||||
},
|
},
|
||||||
|
|
||||||
addressModel: {
|
addressModel: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.modelValue.addressQuestions;
|
return this.modelValue.addressQuestions;
|
||||||
|
|
@ -152,12 +152,20 @@ export default {
|
||||||
closeModal() {
|
closeModal() {
|
||||||
this.$refs[this.modalName].closeModal();
|
this.$refs[this.modalName].closeModal();
|
||||||
},
|
},
|
||||||
|
onModalOpened() {
|
||||||
|
this.internalModel = deepClone(this.modelValue);
|
||||||
|
},
|
||||||
|
onModalClosed() {
|
||||||
|
this.internalModel = deepClone(this.modelValue);
|
||||||
|
},
|
||||||
resetComponent(updatedServiceZipCodeInfo) {
|
resetComponent(updatedServiceZipCodeInfo) {
|
||||||
// Reset the validation form, setting the initial values
|
// Reset the validation form, setting the initial values
|
||||||
// for the state and zipCode to those that were entered
|
// for the state and zipCode to those that were entered
|
||||||
// on the service-zip-modal-question component
|
// on the service-zip-modal-question component
|
||||||
this.$refs[this.modalName].form.resetForm({
|
this.$refs[this.modalName].resetForm({
|
||||||
values: {
|
values: {
|
||||||
|
autocomplete: updatedServiceZipCodeInfo.streetAddress,
|
||||||
|
city: updatedServiceZipCodeInfo.city,
|
||||||
state: updatedServiceZipCodeInfo.state,
|
state: updatedServiceZipCodeInfo.state,
|
||||||
zipCode: updatedServiceZipCodeInfo.zipCode,
|
zipCode: updatedServiceZipCodeInfo.zipCode,
|
||||||
isVehicleProtected: updatedServiceZipCodeInfo.isVehicleProtected,
|
isVehicleProtected: updatedServiceZipCodeInfo.isVehicleProtected,
|
||||||
|
|
@ -182,12 +190,13 @@ export default {
|
||||||
|
|
||||||
const mobileFeePart = await getPricedMobileFeePart(serviceZipCode);
|
const mobileFeePart = await getPricedMobileFeePart(serviceZipCode);
|
||||||
|
|
||||||
// emit it to parent
|
// emit additional data to parent
|
||||||
this.$emit("updated-mobile-fee-part", mobileFeePart);
|
this.$emit("updated-mobile-fee-part", mobileFeePart);
|
||||||
|
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
|
||||||
|
|
||||||
// Update the page level model
|
// Update the page level model
|
||||||
this.$emit("update:modelValue", this.internalModel);
|
this.$emit("update:modelValue", this.internalModel);
|
||||||
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase);
|
|
||||||
this.closeModal();
|
this.closeModal();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -198,6 +207,8 @@ export default {
|
||||||
this.internalModel = deepClone(newValue);
|
this.internalModel = deepClone(newValue);
|
||||||
|
|
||||||
this.resetComponent({
|
this.resetComponent({
|
||||||
|
streetAddress: newValue.addressQuestions.streetAddress,
|
||||||
|
city: newValue.addressQuestions.city,
|
||||||
state: newValue.addressQuestions.state,
|
state: newValue.addressQuestions.state,
|
||||||
zipCode: newValue.addressQuestions.zipCode,
|
zipCode: newValue.addressQuestions.zipCode,
|
||||||
isVehicleProtected: newValue.isVehicleProtected,
|
isVehicleProtected: newValue.isVehicleProtected,
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,13 @@
|
||||||
@updated-mobile-fee-part="setMobileFeePart"
|
@updated-mobile-fee-part="setMobileFeePart"
|
||||||
ref="mobileLocationModalQuestions"
|
ref="mobileLocationModalQuestions"
|
||||||
linkWidgetName="MobileLocationLinkWidget"
|
linkWidgetName="MobileLocationLinkWidget"
|
||||||
modalWidgetName="MobileLocationModalWidget"
|
modalWidgetName="MobileLocationModalWidget" />
|
||||||
@updated-contains-military-base="setContainsMilitaryBase" />
|
<textboxQuestion
|
||||||
|
ref="mobileLocationQuestionsError"
|
||||||
|
v-model="mobileLocationValidationField"
|
||||||
|
validationRules="mobile-location-required"
|
||||||
|
hideInput
|
||||||
|
centerErrorMessage />
|
||||||
<funnel-footer
|
<funnel-footer
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
ref="funnelFooter"
|
ref="funnelFooter"
|
||||||
|
|
@ -44,7 +49,8 @@ import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
||||||
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer";
|
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer";
|
||||||
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, defineRule } from "vee-validate";
|
||||||
|
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
|
||||||
|
|
||||||
// Supporting files
|
// Supporting files
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
|
@ -53,6 +59,10 @@ import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
import { getPricedMobileFeePart } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
|
import { getPricedMobileFeePart } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
import { required } from "@/helpers/validation-rules";
|
||||||
|
|
||||||
|
defineRule("mobile-location-required", required(errorMessages.MOBILE_LOCATION_REQUIRED));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "service-location",
|
name: "service-location",
|
||||||
|
|
@ -68,6 +78,7 @@ export default {
|
||||||
isZipServiceableInShop: null,
|
isZipServiceableInShop: null,
|
||||||
mobileFeePart: null,
|
mobileFeePart: null,
|
||||||
zipContainsMilitaryBase: false,
|
zipContainsMilitaryBase: false,
|
||||||
|
mobileLocationValidationField: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
|
|
@ -141,6 +152,8 @@ export default {
|
||||||
this.state = newValue.addressQuestions.state;
|
this.state = newValue.addressQuestions.state;
|
||||||
this.zipCode = newValue.addressQuestions.zipCode;
|
this.zipCode = newValue.addressQuestions.zipCode;
|
||||||
this.isVehicleProtected = newValue.isVehicleProtected;
|
this.isVehicleProtected = newValue.isVehicleProtected;
|
||||||
|
|
||||||
|
this.mobileLocationValidationField = "isValid";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
showMilitaryZipAlert() {
|
showMilitaryZipAlert() {
|
||||||
|
|
@ -190,6 +203,12 @@ export default {
|
||||||
|
|
||||||
this.isVehicleProtected = null;
|
this.isVehicleProtected = null;
|
||||||
},
|
},
|
||||||
|
setServiceZipCodeModalMeta(meta) {
|
||||||
|
this.serviceZipCodeMeta = meta;
|
||||||
|
},
|
||||||
|
setMobileLocationModalMeta(meta) {
|
||||||
|
this.mobileLocationMeta = meta;
|
||||||
|
},
|
||||||
backButtonAction() {
|
backButtonAction() {
|
||||||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||||
},
|
},
|
||||||
|
|
@ -206,6 +225,7 @@ export default {
|
||||||
funnelSubHeader,
|
funnelSubHeader,
|
||||||
Form,
|
Form,
|
||||||
loadingModal,
|
loadingModal,
|
||||||
|
textboxQuestion,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ import textLink from "@/ux-components/text-link/text-link";
|
||||||
import serviceZipQuestion from "@/layouts/service-location/service-zip-modal-question/service-zip-question/service-zip-question";
|
import serviceZipQuestion from "@/layouts/service-location/service-zip-modal-question/service-zip-question/service-zip-question";
|
||||||
import modal from "@/digital-components/modal/modal";
|
import modal from "@/digital-components/modal/modal";
|
||||||
import alert from "@/ux-components/alert/alert";
|
import alert from "@/ux-components/alert/alert";
|
||||||
import store from "@/store";
|
|
||||||
import { getPricedMobileFeePart } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
|
import { getPricedMobileFeePart } from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -96,49 +96,39 @@ export default {
|
||||||
resetAlerts() {
|
resetAlerts() {
|
||||||
this.displayInvalidZipAlert = false;
|
this.displayInvalidZipAlert = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
resetsOnZipInput() {
|
resetsOnZipInput() {
|
||||||
this.resetAlerts();
|
this.resetAlerts();
|
||||||
},
|
},
|
||||||
|
|
||||||
focusOnZipInput() {
|
focusOnZipInput() {
|
||||||
const input = document.getElementById(this.serviceZipCodeTextInputId);
|
const input = document.getElementById(this.serviceZipCodeTextInputId);
|
||||||
input?.focus();
|
input?.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
copyModel(modelToCopy) {
|
copyModel(modelToCopy) {
|
||||||
return {
|
return {
|
||||||
state: modelToCopy.state,
|
state: modelToCopy.state,
|
||||||
zipCode: modelToCopy.zipCode,
|
zipCode: modelToCopy.zipCode,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
openModal() {
|
openModal() {
|
||||||
this.$refs[this.modalName].openModal();
|
this.$refs[this.modalName].openModal();
|
||||||
},
|
},
|
||||||
|
|
||||||
closeModal() {
|
closeModal() {
|
||||||
this.$refs[this.modalName].closeModal();
|
this.$refs[this.modalName].closeModal();
|
||||||
},
|
},
|
||||||
|
|
||||||
resetModalButtonStyle() {
|
resetModalButtonStyle() {
|
||||||
this.$refs[this.modalName].resetButtonStyle();
|
this.$refs[this.modalName].resetButtonStyle();
|
||||||
},
|
},
|
||||||
|
|
||||||
onInputIdAssigned(inputId) {
|
onInputIdAssigned(inputId) {
|
||||||
this.serviceZipCodeTextInputId = inputId;
|
this.serviceZipCodeTextInputId = inputId;
|
||||||
},
|
},
|
||||||
|
|
||||||
onModalOpened() {
|
onModalOpened() {
|
||||||
this.internalModel.zipCode = this.modelValue.zipCode;
|
this.internalModel.zipCode = this.modelValue.zipCode;
|
||||||
this.focusOnZipInput();
|
this.focusOnZipInput();
|
||||||
},
|
},
|
||||||
|
|
||||||
onModalClosed() {
|
onModalClosed() {
|
||||||
this.internalModel.zipCode = this.modelValue.zipCode;
|
this.internalModel.zipCode = this.modelValue.zipCode;
|
||||||
this.resetsOnZipInput();
|
this.resetsOnZipInput();
|
||||||
},
|
},
|
||||||
|
|
||||||
async setZipCode() {
|
async setZipCode() {
|
||||||
if (this.internalModel.zipCode !== this.modelValue.zipCode) {
|
if (this.internalModel.zipCode !== this.modelValue.zipCode) {
|
||||||
this.resetAlerts();
|
this.resetAlerts();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue