Merge branch 'feature/CSR-1088' into feature/CSR-1012
This commit is contained in:
commit
cd9a589110
16 changed files with 257 additions and 267 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 = "⁠";
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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, {
|
||||
|
|
|
|||
|
|
@ -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 = "⁠";
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
ref="zipInputTextQuestion"
|
||||
:cmsWidgetName="cmsWidgetName"
|
||||
v-model="value"
|
||||
inputId="serviceZipCodeTextBoxQuestion"
|
||||
inputId="serviceZipCode"
|
||||
questionAlignment="center"
|
||||
mask="#####"
|
||||
:displayQuestionText="false"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue