Merge branch 'feature/CSR-1088' into feature/CSR-1012

This commit is contained in:
Leah Schumann 2023-02-20 13:28:34 -05:00
commit cd9a589110
16 changed files with 257 additions and 267 deletions

View file

@ -70,6 +70,10 @@ const endpoints = {
url: "/parts/api/v1/parts/rain-defense",
method: "GET",
},
GetMobileFeePart: {
url: "/parts/api/v1/parts/mobile-fee",
method: "GET",
},
GetSupportingItems: {
url: "/parts/api/v1/parts/supporting-items",
method: "POST",

View file

@ -27,6 +27,7 @@ const storeActions = {
GET_CAPABILITY_QUESTIONS: "getCapabilityQuestions",
GET_PART_FROM_CAPABILITY_QUESTION_ANSWER: "getPartFromCapabilityQuestionAnswer",
GET_MOLDING_QUESTIONS: "getMoldingQuestions",
GET_MOBILE_FEE_PART: "getMobileFeePart",
SAVE_SESSION: "saveSession",
LOAD_SESSION: "loadSession",
UPDATE_STORE_WITH_SAVE_SESSION_RESPONSE: "updateStoreWithSaveSessionResponse",

View file

@ -6,7 +6,7 @@
:for="inputId"
:aria-label="questionText"
class="form-label"
v-html="labelText"></label>
v-html="questionText"></label>
<select
v-model="selectedOption"
class="form-select"
@ -35,20 +35,23 @@ export default {
name: "dropdown-question",
props: {
modelValue: String,
inputId: String,
customInputId: String,
options: {
type: Object,
required: true,
},
isDisabled: Boolean,
isRequired: Boolean,
disableAutoFill: Boolean,
validationRules: String,
cmsWidgetName: String,
hasError: Boolean,
placeHolderText: String,
},
setup(props) {
const inputId = !props.customInputId
? `dropdown-${crypto.randomUUID()}`
: props.customInputId;
const propsClone = Object.assign({}, props);
const modelValue = propsClone.modelValue;
let initialValue;
@ -69,12 +72,13 @@ export default {
};
const { errorMessage, handleBlur, handleChange, meta, errors } = useField(
props.inputId,
inputId,
props.validationRules,
fieldOptions
);
return {
inputId,
errorMessage,
handleBlur,
handleChange,
@ -82,6 +86,9 @@ export default {
errors,
};
},
mounted() {
this.$emit("dropdownQuestionEvent.inputIdAssigned", this.inputId);
},
computed: {
questionText() {
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
@ -94,30 +101,6 @@ export default {
this.$emit("update:modelValue", newValue);
},
},
labelText: {
get: function () {
const noBreakChar = "&NoBreak;";
var questionText = "";
if (this.disableAutoFill) {
var words = this.questionText.toString().split(/[ ]+/);
words.forEach(function (word) {
const position = 1;
word = [
word.toString().slice(0, position),
noBreakChar,
word.toString().slice(position),
].join("");
questionText += `${word} `;
});
questionText = questionText.trimEnd();
} else {
questionText = this.questionText.toString();
}
return questionText;
},
},
},
watch: {
selectedOption(newValue) {

View file

@ -60,22 +60,23 @@ export default {
setup() {
const modalId = `modal-${crypto.randomUUID()}`;
const modalForm = useForm();
const isTouched = useIsFormTouched();
const isDirty = useIsFormDirty();
const isValid = useIsFormValid();
const form = useForm();
const isFormTouched = useIsFormTouched();
const isFormDirty = useIsFormDirty();
const isFormValid = useIsFormValid();
return {
modalId,
modalForm,
isTouched,
isDirty,
isValid,
form,
isFormTouched,
isFormDirty,
isFormValid,
};
},
methods: {
async validateAndEmit() {
if (!this.isFooterButtonDisabled) {
const validationResult = await this.form.validate();
if (validationResult.valid) {
this.$emit("footer-button-event");
}
this.resetButtonStyle();
@ -101,10 +102,10 @@ export default {
},
computed: {
isFooterButtonDisabled() {
if (!this.isTouched) {
return !this.isValid;
if (!this.isFormTouched) {
return !this.isFormValid;
}
return !this.isDirty || !this.isValid;
return !this.isFormDirty || !this.isFormValid;
},
},
components: {

View file

@ -9,6 +9,7 @@
export default {
name: "textBlock",
props: {
customText: String, // used to allow the insert of token values into textblock
justifyText: String, // left, right, center
typeStyle: String, // h1-h6, body, small, label, caption (see Figma or Confluence documentation)
fontWeight: String, // bold=500, default is 400
@ -16,6 +17,9 @@ export default {
},
computed: {
TextBlockCopy() {
if (this.customText) {
return this.customText;
}
return this.getCmsContent(this.cmsWidgetName, "Text");
},
},

View file

@ -73,24 +73,6 @@ describe("textboxQuestion.vue", () => {
expect(paragraph.attributes("class")).toContain("form-control");
});
it("Should render the 'questionText' data value as the label text when disableAutoFill is false.", async () => {
// Arrange
const wrapper = shallowMount(textboxQuestion, {
global: {
directives: {
maska: maska,
},
},
mixins: [mockMixin],
});
// Act
const label = wrapper.find("label");
// Assert
expect(label.text()).toContain(questionText);
});
it("Should return input id as the id of the input field", async () => {
// Arrange
const wrapper = shallowMount(textboxQuestion, {

View file

@ -6,7 +6,7 @@
:aria-label="questionText"
class="form-label"
:class="[questionAlignment === 'center' ? 'text-center w-100 mb-5' : '']"
v-html="labelText"></label>
v-html="questionText"></label>
<div class="input-wrapper" :class="[includeSearchIcon ? 'has-search-icon' : '']">
<input
class="form-control"
@ -41,7 +41,6 @@
<script>
import { useField, validate } from "vee-validate";
import { storeActions } from "@/constants/store-actions";
export default {
name: "textbox-question",
@ -59,7 +58,7 @@ export default {
default: true,
},
modelValue: String,
inputId: String,
customInputId: String,
isDisabled: Boolean,
isRequired: Boolean,
hasIcon: Boolean, // If input has an icon
@ -69,7 +68,6 @@ export default {
type: String,
default: "",
},
handleOnInput: Boolean,
validationRules: String,
cmsWidgetName: String,
maxLength: String,
@ -78,6 +76,8 @@ export default {
includeSearchIcon: Boolean,
},
setup(props) {
const inputId = !props.customInputId ? `input-${crypto.randomUUID()}` : props.customInputId;
const propsClone = Object.assign({}, props);
const modelValue = propsClone.modelValue;
let initialValue;
@ -98,12 +98,13 @@ export default {
};
const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField(
props.inputId,
inputId,
props.validationRules,
fieldOptions
);
return {
inputId,
errorMessage,
handleBlur,
handleChange,
@ -124,30 +125,9 @@ export default {
this.$emit("update:modelValue", newValue);
},
},
labelText: {
get: function () {
const noBreakChar = "&NoBreak;";
var questionText = "";
if (this.disableAutoFill) {
var words = this.questionText.toString().split(/[ ]+/);
words.forEach(function (word) {
const position = 1;
word = [
word.toString().slice(0, position),
noBreakChar,
word.toString().slice(position),
].join("");
questionText += `${word} `;
});
questionText = questionText.trimEnd();
} else {
questionText = this.questionText.toString();
}
return questionText;
},
},
},
mounted() {
this.$emit("textboxQuestionEvent.inputIdAssigned", this.inputId);
},
watch: {
async value(newValue) {

View file

@ -7,11 +7,10 @@
cmsWidgetName="StreetAddressQuestionWidget"
v-model="addressModel.streetAddress"
ref="autocomplete"
inputId="autocomplete"
customInputId="autocomplete"
placeholderText="Search"
aria-haspopup=""
hasIcon
disableAutoFill
validationRules="street-address-required"
@keydown.enter.prevent />
</div>
@ -25,9 +24,7 @@
<textboxQuestion
cmsWidgetName="ApartmentNumberOrBusinessNameQuestionWidget"
v-model="addressModel.apartmentNumberOrBusinessName"
ref="apartmentNumberOrBusinessName"
inputId="639b0aaa35f64609ad6995f86a74322b"
disableAutoFill />
ref="apartmentNumberOrBusinessName" />
</div>
</div>
</transition>
@ -38,8 +35,6 @@
cmsWidgetName="CityQuestionWidget"
v-model="addressModel.city"
ref="city"
inputId="cbf28188fdf2436688fd735915f7ee56"
disableAutoFill
validationRules="city-required" />
</div>
</div>
@ -51,9 +46,7 @@
cmsWidgetName="StateQuestionWidget"
v-model="addressModel.state"
ref="state"
inputId="8fdf9dc2e13e430eb57529499dceb3eb"
:options="stateOptions"
disableAutoFill
validationRules="state-required" />
</div>
<div class="col">
@ -61,9 +54,7 @@
cmsWidgetName="ZipQuestionWidget"
v-model="addressModel.zipCode"
ref="zipCode"
inputId="01a9a1c2de0b4c9da8e023c9ae3be498"
mask="#####"
disableAutoFill
validationRules="zip-code-required|zip-code-format" />
</div>
</div>
@ -207,6 +198,7 @@ export default {
},
methods: {
setupAddressLookup() {
this.showAddressFields = false;
if (
this.addressModel.streetAddress &&
this.addressModel.city &&
@ -223,7 +215,7 @@ export default {
const apiKey = applicationConfig.GOOGLE_PLACES_API_KEY;
this.$loadScript(
`https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places`
`https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places&callback=Function.prototype`
)
.then(() => {
// Script is loaded, initialize the autocomplete textbox

View file

@ -7,7 +7,6 @@
v-model="customerModel.firstName"
ref="firstName"
inputId="08497a2efd9a4a73a70360ab47b4838d"
disableAutoFill
validationRules="first-name-required" />
</div>
</div>
@ -18,7 +17,6 @@
v-model="customerModel.lastName"
ref="lastName"
inputId="0030e56a57e74a4ab92de7fb8e97fec5"
disableAutoFill
validationRules="last-name-required" />
</div>
</div>
@ -29,7 +27,6 @@
v-model="customerModel.emailAddress"
ref="emailAddress"
inputId="00450a91b8964a768ce3992e6feb890f"
disableAutoFill
validationRules="email-address-required|email-address-format" />
</div>
</div>

View file

@ -34,7 +34,6 @@
inputId="serviceZipCode"
mask="#####"
isRequired
disableAutoFill
validationRules="zip-required|zip-format" />
</div>
</div>
@ -45,7 +44,6 @@
v-model="emailAddress"
inputId="emailAddress"
isRequired
disableAutoFill
validationRules="email-address-required|email-address-format" />
</div>
</div>

View file

@ -15,23 +15,33 @@
@click-event="openModal"
aria-label="Modal window" />
</div>
<textBlock cmsWidgetName="MobileFeeDisclaimerWidget" typeStyle="caption" />
<textBlock
:customText="mobileFeeText"
cmsWidgetName="MobileFeeDisclaimerWidget"
typeStyle="caption" />
</div>
<modal
:ref="modalName"
:headerText="modalHeaderText"
:onModalOpenedCallback="onModalOpened"
:onModalClosedCallback="onModalClosed"
:footerButtonText="modalFooterText"
@footer-button-event="setMobileLocation">
<addressQuestions
ref="addressQuestions"
v-model="mobileLocationQuestionsInput.addressQuestions"
v-model="internalModel.addressQuestions"
captureApartmentNumberOrBusinessName="true" />
<vehicleProtectedQuestion
ref="vehicleProtectedQuestion"
v-model="mobileLocationQuestionsInput.isVehicleProtected"
v-model="internalModel.isVehicleProtected"
cmsWidgetName="VehicleProtectedQuestionWidget" />
<textBlock cmsWidgetName="WorkspaceRequirementsWidget" typeStyle="caption" />
<alert
ref="alertInvalidZip"
v-if="displayInvalidZipAlert"
class="my-4"
cmsWidgetName="AlertInvalidZipWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
</modal>
</template>
@ -43,29 +53,17 @@ import alert from "@/ux-components/alert/alert";
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 textBlock from "@/digital-components/text-block/text-block";
// Supporting Files
import { useForm } from "vee-validate";
// Define Validation Rules
import baseMixin from "@/mixins/base-mixin.js";
import { storeActions } from "@/constants/store-actions";
export default {
name: "mobile-location-modal-questions",
emits: ["update:modelValue"], // The component emits an event
data() {
return {
mobileLocationQuestionsInput: {
addressQuestions: {
streetAddress: "",
apartmentNumberOrBusinessName: "",
city: "",
state: "",
zipCode: "",
},
isVehicleProtected: null,
isZipServiceableMobile: null,
isZipServiceableInShop: null,
},
internalModel: this.copyModel(this.modelValue),
displayInvalidZipAlert: false,
mobileFee: "",
};
},
props: {
@ -79,11 +77,11 @@ export default {
state: "",
zipCode: "",
},
isVehicleProtected: Boolean,
isZipServiceableMobile: Boolean,
isZipServiceableInShop: Boolean,
isVehicleProtected: null,
}),
},
isZipServiceableMobile: Boolean,
isZipServiceableInShop: Boolean,
serviceZipCode: String,
linkWidgetName: String,
modalWidgetName: String,
@ -92,19 +90,27 @@ export default {
alertNonServiceableZipWidgetName: String,
alertInvalidZipWidgetName: String,
},
async mounted() {
this.mobileFee = await this.getMobileFee();
},
computed: {
getModalId() {
return "#" + this.modalWidgetName;
mobileFeeText() {
const cmsContentText = this.getCmsContent("MobileFeeDisclaimerWidget", "Text");
return cmsContentText.replaceAll("{custom:mobileFee}", this.mobileFee);
},
mobileLocationLinkPromptText() {
return this.getCmsContent(this.linkWidgetName, "HeaderText");
},
mobileLocationLinkText() {
if (
this.addressModel.streetAddress != "" &&
this.addressModel.city != "" &&
this.addressModel.state != "" &&
this.addressModel.zipCode != ""
this.addressModel.streetAddress !== null &&
this.addressModel.streetAddress !== "" &&
this.addressModel.city !== null &&
this.addressModel.city !== "" &&
this.addressModel.state !== null &&
this.addressModel.state !== "" &&
this.addressModel.zipCode !== null &&
this.addressModel.zipCode !== ""
) {
return `${this.addressModel.streetAddress}\n${this.addressModel.city}, ${this.addressModel.state} ${this.addressModel.zipCode}`;
}
@ -119,64 +125,96 @@ export default {
modalName() {
return this.modalWidgetName;
},
mobileLocationQuestionsModel: {
get: function () {
return this.modelValue;
},
set: function (newValue) {
this.$emit("update:modelValue", newValue);
},
},
addressModel: {
get: function () {
return this.mobileLocationQuestionsInput.addressQuestions;
return this.modelValue.addressQuestions;
},
},
},
methods: {
copyModel(modelToCopy) {
return {
addressQuestions: {
streetAddress: modelToCopy.addressQuestions.streetAddress,
apartmentNumberOrBusinessName:
modelToCopy.addressQuestions.apartmentNumberOrBusinessName,
city: modelToCopy.addressQuestions.city,
state: modelToCopy.addressQuestions.state,
zipCode: modelToCopy.addressQuestions.zipCode,
},
isVehicleProtected: modelToCopy.isVehicleProtected,
isZipServiceableMobile: modelToCopy.isZipServiceableMobile,
isZipServiceableInShop: modelToCopy.isZipServiceableInShop,
};
},
async getMobileFee() {
// Get the Mobile Fee Part
const mobileFeePart = await baseMixin.methods.dispatchStoreAction(
storeActions.GET_MOBILE_FEE_PART,
null,
false
);
// Get the Mobile Fee Part Price
const pricingResults = await baseMixin.methods.dispatchStoreAction(
storeActions.PRICE_ORDER_ITEMS,
[mobileFeePart.data],
false
);
return await baseMixin.methods.getTotalLineItemPrice(pricingResults[0]);
},
openModal() {
this.$refs[this.modalName].openModal();
},
onModalClosed() {
this.mobileLocationQuestionsInput = this.mobileLocationQuestionsModel;
},
closeModal() {
this.$refs[this.modalName].closeModal();
},
resetComponent() {
this.resetModel();
// Reset the validation form
this.$refs[this.modalName].form.resetForm();
// Reinitialize the Address Auto Complete
this.$refs.addressQuestions.setupAddressLookup();
},
resetModel() {
// Address
this.addressModel.streetAddress = "";
this.addressModel.apartmentNumberOrBusinessName = "";
this.addressModel.city = "";
this.addressModel.state = "";
this.addressModel.zipCode = "";
this.internalModel.addressQuestions.streetAddress = "";
this.internalModel.addressQuestions.apartmentNumberOrBusinessName = "";
this.internalModel.addressQuestions.city = "";
this.internalModel.addressQuestions.state = "";
this.internalModel.addressQuestions.zipCode = "";
// Is Vehicle Protected
this.mobileLocationQuestionsInput.isVehicleProtected = null;
this.internalModel.isVehicleProtected = null;
},
async setMobileLocation() {
this.mobileLocationQuestionsModel = {
addressQuestions: {
streetAddress: this.addressModel.streetAddress,
apartmentNumberOrBusinessName: this.addressModel.apartmentNumberOrBusinessName,
city: this.addressModel.city,
state: this.addressModel.state,
zipCode: this.addressModel.zipCode,
},
isVehicleProtected: this.mobileLocationQuestionsInput.isVehicleProtected,
isZipServiceableMobile: this.mobileLocationQuestionsInput.isZipServiceableMobile,
isZipServiceableInShop: this.mobileLocationQuestionsInput.isZipServiceableInShop,
};
this.closeModal();
async setMobileLocation() {
// Validate the Zip Code
const zipCodeData = await this.getZipCodeData(
this.internalModel.addressQuestions.zipCode
);
if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true;
} else {
// Update the page level model
this.$emit("update:modelValue", this.internalModel);
this.closeModal();
}
},
},
watch: {
serviceZipCode: {
handler() {
// if they modify the Service Zip Code, clear the model
this.resetModel();
},
modelValue(newValue) {
this.internalModel = this.copyModel(newValue);
},
},
components: {
@ -185,6 +223,7 @@ export default {
addressQuestions,
vehicleProtectedQuestion,
textBlock,
alert,
},
};
</script>

View file

@ -5,13 +5,15 @@
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<serviceZipModalQuestion
v-model="serviceZipQuestionModel"
v-model="serviceZipCodeQuestion"
@service-zip-updated="resetMobileLocation"
linkWidgetName="ServiceZipLinkWidget"
modalWidgetName="ServiceZipModalWidget"
textboxQuestionWidgetName="ServiceZipQuestionWidget"
alertInvalidZipWidgetName="AlertInvalidZipWidget" />
<mobileLocationModalQuestions
v-model="mobileLocationQuestionsModel"
v-model="mobileLocationQuestions"
ref="mobileLocationModalQuestions"
linkWidgetName="MobileLocationLinkWidget"
modalWidgetName="MobileLocationModalWidget"
mobileFeeDisclaimerWidgetName="MobileFeeDisclaimerWidget"
@ -38,20 +40,29 @@ import { Form } from "vee-validate";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import store from "@/store";
export default {
name: "service-location",
data() {
return {
isServiceable: null,
streetAddress: "",
apartmentNumberOrBusinessName: "",
city: "",
state: "",
zipCode: "",
isVehicleProtected: null,
isZipServiceableMobile: null,
isZipServiceableInShop: null,
serviceZipCodeQuestion: {
state: this.getServiceStateFromStore(),
zipCode: this.getServiceZipCodeFromStore(),
isServiceable: this.getIsServiceableFromStore(),
},
mobileLocationQuestions: {
addressQuestions: {
streetAddress: this.getRegistrationAddressFromStore(),
apartmentNumberOrBusinessName: "",
city: this.getRegistrationCityFromStore(),
state: this.getRegistrationStateFromStore(),
zipCode: this.getRegistrationZipFromStore(),
},
isVehicleProtected: null,
},
};
},
@ -74,54 +85,46 @@ export default {
vm.setCmsContent(resultMap.cmsContent);
});
},
computed: {
serviceZipQuestionModel: {
get: function () {
return {
state: this.state,
zipCode: this.zipCode,
isServiceable: this.isServiceable,
};
},
set: function (newValue) {
this.state = newValue.state;
this.zipCode = newValue.zipCode;
this.isServiceable = newValue.isServiceable;
},
},
mobileLocationQuestionsModel: {
get: function () {
return {
addressQuestions: {
streetAddress: this.streetAddress,
apartmentNumberOrBusinessName: this.apartmentNumberOrBusinessName,
city: this.city,
state: this.state,
zipCode: this.zipCode,
},
isVehicleProtected: this.isVehicleProtected,
isZipServiceableMobile: this.isZipServiceableMobile,
isZipServiceableInShop: this.isZipServiceableInShop,
};
},
set: function (newValue) {
this.streetAddress = newValue.addressQuestions.streetAddress;
this.apartmentNumberOrBusinessName =
newValue.addressQuestions.apartmentNumberOrBusinessName;
this.city = newValue.addressQuestions.city;
this.state = newValue.addressQuestions.state;
this.zipCode = newValue.addressQuestions.zipCode;
this.isVehicleProtected = newValue.isVehicleProtected;
this.isZipServiceableMobile = newValue.isZipServiceableMobile;
this.isZipServiceableInShop = newValue.isZipServiceableInShop;
},
},
},
methods: {
arePagePrerequisitesValid() {
return true;
},
getRegistrationAddressFromStore() {
return this.$store.getters.vehicle.registration.address;
},
getRegistrationCityFromStore() {
return this.$store.getters.vehicle.registration.city;
},
getRegistrationStateFromStore() {
return this.$store.getters.vehicle.registration.state;
},
getRegistrationZipFromStore() {
return this.$store.getters.vehicle.registration.zipCode;
},
getServiceZipCodeFromStore() {
return this.$store.getters.order.serviceLocation.zipCode;
},
getServiceStateFromStore() {
return this.$store.getters.order.serviceLocation.state;
},
getIsServiceableFromStore() {
return this.$store.getters.order.serviceLocation.isServiceable;
},
resetMobileLocation() {
this.mobileLocationQuestions = {
addressQuestions: {
streetAddress: "",
apartmentNumberOrBusinessName: "",
city: "",
state: "",
zipCode: "",
},
isVehicleProtected: null,
};
this.$refs.mobileLocationModalQuestions.resetComponent();
},
backButtonAction() {
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
},

View file

@ -19,8 +19,9 @@
@footer-button-event="setZipCode">
<serviceZipQuestion
ref="serviceZipQuestion"
:cmsWidgetName="textboxQuestionWidgetName"
v-model="serviceZipCodeInput" />
v-model="internalModel.zipCode"
v-on="{ 'textboxQuestionEvent.inputIdAssigned': onInputIdAssigned }"
:cmsWidgetName="textboxQuestionWidgetName" />
<alert
ref="alertInvalidZip"
v-if="displayInvalidZipAlert"
@ -38,20 +39,12 @@ import serviceZipQuestion from "@/layouts/service-location/service-zip-modal-que
import modal from "@/digital-components/modal/modal";
import alert from "@/ux-components/alert/alert";
//Supporting Files
import { defineRule, useForm } from "vee-validate";
import { required, regex } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
// Define Validation Rules
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
export default {
name: "service-zip-modal-question",
data() {
return {
serviceZipCodeInput: null,
internalModel: this.copyModel(this.modelValue),
serviceZipCodeTextInputId: "",
displayInvalidZipAlert: false,
};
},
@ -59,11 +52,9 @@ export default {
modelValue: {
type: Object,
default: () => ({
serviceZipQuestion: {
state: "",
zipCode: "",
isServiceable: null,
},
state: "",
zipCode: "",
isServiceable: null,
}),
},
linkWidgetName: String,
@ -87,14 +78,6 @@ export default {
modalName() {
return this.modalWidgetName;
},
serviceZipModel: {
get: function () {
return this.modelValue;
},
set: function (newValue) {
this.$emit("update:modelValue", newValue);
},
},
},
methods: {
resetAlerts() {
@ -107,10 +90,18 @@ export default {
},
focusOnZipInput() {
const input = document.getElementById("serviceZipCodeTextBoxQuestion");
const input = document.getElementById(this.serviceZipCodeTextInputId);
input.focus();
},
copyModel(modelToCopy) {
return {
state: modelToCopy.state,
zipCode: modelToCopy.zipCode,
isServiceable: modelToCopy.isServiceable,
};
},
openModal() {
this.$refs[this.modalName].openModal();
},
@ -119,38 +110,49 @@ export default {
this.$refs[this.modalName].closeModal();
},
onModalOpened() {
this.serviceZipCodeInput = this.serviceZipModel.zipCode;
this.focusOnZipInput();
onInputIdAssigned(inputId) {
this.serviceZipCodeTextInputId = inputId;
// bubble up the event to the parent
this.$emit("textboxQuestionEvent.inputIdAssigned", inputId);
},
onModalClosed() {
this.serviceZipCodeInput = this.serviceZipModel.zipCode;
this.resetsOnZipInput();
onModalOpened() {
this.focusOnZipInput();
},
async setZipCode() {
this.resetAlerts();
const zipCodeData = await this.getZipCodeData(this.serviceZipCodeInput);
const zipCodeData = await this.getZipCodeData(this.internalModel.zipCode);
if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true;
this.focusOnZipInput();
} else {
this.serviceZipModel = {
state: zipCodeData.state,
zipCode: this.serviceZipCodeInput,
isServiceable: zipCodeData.isServiceable,
};
this.internalModel.state = zipCodeData.state;
this.internalModel.isServiceable = zipCodeData.isServiceable;
// Notify the page that the service zip has been updated to clear Mobile Location form
if (this.internalModel.zipCode !== this.modelValue.zipCode) {
this.$emit("service-zip-updated");
}
// Update the page level model
this.$emit("update:modelValue", this.internalModel);
this.closeModal();
}
},
},
watch: {
serviceZipCodeInput() {
this.resetsOnZipInput();
"internalModel.zipCode": {
handler() {
this.resetsOnZipInput();
},
},
modelValue(newValue) {
this.internalModel = this.copyModel(newValue);
},
},
components: {

View file

@ -3,7 +3,7 @@
ref="zipInputTextQuestion"
:cmsWidgetName="cmsWidgetName"
v-model="value"
inputId="serviceZipCodeTextBoxQuestion"
inputId="serviceZipCode"
questionAlignment="center"
mask="#####"
:displayQuestionText="false"

View file

@ -15,7 +15,6 @@
v-model="vin"
inputId="vin"
isRequired
disableAutoFill
validationRules="vin-required|vin-format"
:isDisabled="vinPopulatedOnPageLoad"
maxLength="17"
@ -35,7 +34,6 @@
inputId="serviceZipCode"
mask="#####"
isRequired
disableAutoFill
validationRules="zip-required|zip-format" />
</div>
</div>
@ -46,7 +44,6 @@
v-model="emailAddress"
inputId="emailAddress"
isRequired
disableAutoFill
validationRules="email-address-required|email-address-format" />
</div>
</div>

View file

@ -907,6 +907,13 @@ export const actions = {
});
},
getMobileFeePart(context) {
return globalMethods.callMockHttpClient({
method: endpoints.GetMobileFeePart.method,
endpoint: "https://run.mocky.io/v3/795de4cb-d014-48b4-9338-dab33261adce", //TODO: Remove Mocky Endpoint
});
},
getSupportingItems(context) {
const glassPartsArray = context.getters.lineItems.glassParts ?? [];
const carId = context.getters.vehicle.carId;