Merge pull request #2499 from Safelite/feature/Digital/CASH-502

CASH-502
This commit is contained in:
hiteshkumar87 2025-05-13 14:49:05 +05:30 committed by GitHub
commit 3d38c046b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 221 additions and 208 deletions

View file

@ -35,4 +35,9 @@ export const inputButtonProps = {
default: false,
},
suppressError: Boolean,
labelBold: {
type: Boolean,
required: false,
default: false,
},
};

View file

@ -9,7 +9,9 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
v-if="questionText && answers && answers.length > 0"
class="question-text d-flex"
:class="{ 'small-question-text': isSmallQuestionText }">
<span class="fw-bold w-100">{{ questionText }}</span>
<span class="fw-bold w-100" :class="[labelBold ? 'span-bold' : '']">
{{ questionText }}
</span>
</div>
<div class="w-100 d-flex justify-content-center">
@ -57,6 +59,7 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
:setLastValuePushedToGa="setLastValuePushedToGa"
:isInsuranceSelected="isInsuranceSelected"
:suppressError="suppressError"
:labelBold="labelBold"
@buttonEvent="handleButtonEvent"
v-model="selectedValues" />
<!-- For nested questions -->
@ -141,6 +144,11 @@ export default {
default: false,
},
isInsuranceSelected: Boolean,
labelBold: {
type: Boolean,
required: false,
default: false,
},
},
setup(props) {
const propsClone = Object.assign({}, props);
@ -360,6 +368,9 @@ export default {
& > span {
text-align: center;
}
.span-bold {
font-weight: 600;
}
}
.small-question-text {
&.question-text {

View file

@ -6,6 +6,7 @@
:for="dropdownId"
:aria-label="questionText"
class="form-label"
:class="[labelBold ? 'label-bold' : '']"
v-html="questionText"></label>
<select
v-model="selectedOption"
@ -61,6 +62,11 @@ export default {
required: false,
default: false,
},
labelBold: {
type: Boolean,
required: false,
default: false,
},
},
setup(props) {
const uuid = uuidv4();
@ -133,6 +139,10 @@ export default {
color: $black;
font-weight: 500;
}
.label-bold {
color: $black;
font-weight: 600;
}
.form-label {
margin-bottom: 0.25rem;
}

View file

@ -13,6 +13,7 @@
:class="[
questionAlignment === 'center' ? 'text-center w-100 mb-5' : '',
hideInput ? 'hide-input' : '',
labelBold ? 'label-bold' : '',
]"
v-html="questionText"></label>
<div
@ -132,6 +133,11 @@ export default {
isRequired: false,
},
autocomplete: String,
labelBold: {
type: Boolean,
required: false,
default: false,
},
},
setup(props) {
const uuid = uuidv4();
@ -251,6 +257,9 @@ export default {
color: $black;
font-weight: 500;
}
.label-bold {
font-weight: 600;
}
.input-wrapper {
position: relative;
&.has-search-icon {

View file

@ -14,7 +14,8 @@
hasIcon
validationRules="street-address-required"
autocomplete="street-address"
@keydown.enter.prevent />
@keydown.enter.prevent
:labelBold="labelBold" />
</div>
</div>
<transition name="fade" mode="out-in">
@ -27,7 +28,8 @@
customInputId="apartmentNumberOrBusinessName"
cmsWidgetName="ApartmentNumberOrBusinessNameQuestionWidget"
v-model="addressModel.apartmentNumberOrBusinessName"
ref="apartmentNumberOrBusinessName" />
ref="apartmentNumberOrBusinessName"
:labelBold="labelBold" />
</div>
</div>
</transition>
@ -40,7 +42,8 @@
v-model="addressModel.city"
ref="city"
validationRules="city-required"
autocomplete="address-level2" />
autocomplete="address-level2"
:labelBold="labelBold" />
</div>
</div>
</transition>
@ -54,7 +57,8 @@
ref="state"
:options="stateOptions"
validationRules="state-required"
autocomplete="address-level1" />
autocomplete="address-level1"
:labelBold="labelBold" />
</div>
<div class="col">
<textboxQuestion
@ -64,7 +68,8 @@
ref="zipCode"
mask="#####"
validationRules="zip-code-required|zip-code-format"
autocomplete="postal-code" />
autocomplete="postal-code"
:labelBold="labelBold" />
</div>
</div>
</transition>
@ -124,6 +129,11 @@ export default {
type: Boolean,
default: false,
},
labelBold: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {

View file

@ -11,7 +11,8 @@
v-model="selectedValue"
:suppressError="suppressError"
:validationRules="validationRules"
isRequired />
isRequired
:labelBold="labelBold" />
</div>
</transition>
</template>
@ -34,6 +35,11 @@ export default {
isServiceableInshop: Boolean,
isServiceableDropoff: Boolean,
mobileFeeApplies: Boolean,
labelBold: {
type: Boolean,
required: false,
default: false,
},
zipCode: String,
},
computed: {

View file

@ -189,41 +189,7 @@ describe("mobile-location-modal-questions.vue", () => {
expect(wrapper.vm.internalModel.serviceZipCode).toEqual("55555");
});
it("Should open the modal when the 'Enter your service address' link is clicked", async () => {
// Arrange
const mobileLocationQuestions = {
addressQuestions: {
streetAddress: "555 Some St",
apartmentNumberOrBusinessName: "Apt 1",
city: "Funkytown",
state: "OH",
zipCode: "55555",
},
isVehicleProtected: true,
serviceZipCode: "55555",
};
const { wrapper } = setupMocks({
mixins: [mockMixin],
props: {
modelValue: mobileLocationQuestions,
},
mountOptions: {
attachTo: document.body,
},
});
wrapper.vm.$refs.MobileLocationModalWidget.openModal = jest.fn();
const mobileLocationLink = wrapper.findComponent({ ref: "mobileLocationLink" });
// // Act
await mobileLocationLink.trigger("click-event");
// // Assert
expect(wrapper.vm.$refs.MobileLocationModalWidget.openModal).toHaveBeenCalled();
});
it("Should emit setMobileLocationAndProceed on setMobileLocation for a valid address and vehicle protection answer", async () => {
it("Should emit setMobileLocation on setMobileLocation for a valid address and vehicle protection answer", async () => {
// Arrange
const mobileLocationQuestions = {
addressQuestions: {
@ -258,7 +224,6 @@ describe("mobile-location-modal-questions.vue", () => {
},
attachTo: document.body,
});
wrapper.vm.$refs.MobileLocationModalWidget.closeModal = jest.fn();
// Act
wrapper.vm.internalModel = newMobileLocationQuestions;
@ -266,13 +231,13 @@ describe("mobile-location-modal-questions.vue", () => {
await wrapper.vm.setMobileLocation();
// Assert
expect(wrapper.emitted()["setMobileLocationAndProceed"]).toBeTruthy();
expect(wrapper.emitted()["setMobileLocationAndProceed"][0][0]).toStrictEqual(
expect(wrapper.emitted()["setMobileLocation"]).toBeTruthy();
expect(wrapper.emitted()["setMobileLocation"][0][0]).toStrictEqual(
newMobileLocationQuestions
);
});
it("Should not emit setMobileLocationAndProceed on setMobileLocation for an invalid address zip code", async () => {
it("Should not emit setMobileLocation on setMobileLocation for an invalid address zip code", async () => {
// Arrange
const mobileLocationQuestions = {
addressQuestions: {
@ -307,15 +272,13 @@ describe("mobile-location-modal-questions.vue", () => {
},
attachTo: document.body,
});
wrapper.vm.$refs.MobileLocationModalWidget.closeModal = jest.fn();
wrapper.vm.resetModalButtonStyle = jest.fn();
// Act
wrapper.vm.internalModel = newMobileLocationQuestions;
await wrapper.vm.setMobileLocation();
// Assert
expect(wrapper.emitted("setMobileLocationAndProceed")).not.toBeTruthy();
expect(wrapper.emitted("setMobileLocation")).not.toBeTruthy();
});
it("Should display invalid zip alert for invalid address zip inputs", async () => {

View file

@ -1,52 +1,48 @@
<template>
<div class="mobile-location-questions">
<div class="text-center" :id="componentId">
<label
for="mobileLocationLinkPromptId"
:aria-label="mobileLocationLinkPromptText"
class="form-label fw-bold w-100 ps-4 pe-4 pt-4 text-black"
v-html="mobileLocationLinkPromptText"></label>
<div class="update-mobile-location-text-link">
<textLink
ref="mobileLocationLink"
id="mobileLocationLinkPromptId"
linkType="text"
:text="mobileLocationLinkText"
href="#!"
@click-event="openModal" />
<transition name="fade" mode="out-in">
<div class="mobile-location-questions">
<div class="text-center" :id="componentId">
<label
for="mobileLocationLinkPromptId"
:aria-label="mobileLocationLinkPromptText"
class="form-label fw-bold w-100 ps-4 pe-4 pt-4 text-black"
v-html="mobileLocationLinkPromptText"></label>
<div class="update-mobile-location-text-link">
<textLink
ref="mobileLocationLink"
id="mobileLocationLinkPromptId"
linkType="text"
:text="mobileLocationLinkText"
href="#!"
@click-event="toggleMobileLocation" />
</div>
<div v-show="errorMessage" class="row my-1 form-test-error">
<span
class="d-inline-flex small mt-0 center-error-message"
aria-atomic="true"
aria-live="polite">
{{ errorMessage }}
</span>
</div>
<textBlock
v-if="mobileFeeApplies"
:customText="mobileFeeText"
cmsWidgetName="MobileFeeDisclaimerWidget"
typeStyle="caption" />
</div>
<div v-show="errorMessage" class="row my-1 form-test-error">
<span
class="d-inline-flex small mt-0 center-error-message"
aria-atomic="true"
aria-live="polite">
{{ errorMessage }}
</span>
</div>
<textBlock
v-if="mobileFeeApplies"
:customText="mobileFeeText"
cmsWidgetName="MobileFeeDisclaimerWidget"
typeStyle="caption" />
</div>
<modal
:ref="modalName"
:headerText="modalHeaderText"
:footerButtonText="modalFooterText"
:onModalOpenedCallback="onModalOpened"
:onModalClosedCallback="onModalClosed"
@isModalOpened="setModalStatus"
@footer-button-event="setMobileLocation">
<template v-if="isModalOpened">
<div v-if="isMobileLocationOpened" class="address-questions-container">
<div v-html="headerText" class="HeaderText" />
<addressQuestions
ref="addressQuestions"
v-model="internalModel.addressQuestions"
captureApartmentNumberOrBusinessName="true"
preserveCityAndStateOnReset="true" />
preserveCityAndStateOnReset="true"
labelBold="true" />
<vehicleProtectedQuestion
ref="vehicleProtectedQuestion"
v-model="internalModel.isVehicleProtected"
cmsWidgetName="VehicleProtectedQuestionWidget" />
cmsWidgetName="VehicleProtectedQuestionWidget"
labelBold="true" />
<textBlock cmsWidgetName="WorkspaceRequirementsWidget" typeStyle="caption" />
<alert
ref="alertInvalidZip"
@ -62,16 +58,14 @@
cmsWidgetName="AlertMismatchStateAndZipWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
</template>
</modal>
</div>
</div>
</div>
</transition>
</template>
<script>
// Components
import textLink from "@/ux-components/text-link/text-link";
import textBlock from "@/digital-components/text-block/text-block";
import modal from "@/digital-components/modal/modal";
import alert from "@/ux-components/alert/alert";
import addressQuestions from "@/fmg-components/address-questions/address-questions";
import vehicleProtectedQuestion from "@/layouts/service-location/mobile-location-modal-questions/vehicle-protected-question/vehicle-protected-question";
@ -96,14 +90,14 @@ export default {
"updated-mobile-fee-part",
"updated-contains-military-base",
"updated-bill-to-account-number",
"setMobileLocationAndProceed",
"updated-modal-opened",
"setMobileLocation",
"set-mobile-location-invalid",
],
data() {
return {
internalModel: deepClone(this.modelValue),
displayInvalidZipAlert: false,
isModalOpened: false,
isMobileLocationOpened: false,
displayMismatchStateAndZipAlert: false,
};
},
@ -189,23 +183,29 @@ export default {
this.mobileFeePart.kitPrice
);
},
modalName() {
return "MobileLocationModalWidget";
},
modalHeaderText() {
headerText() {
return this.getCmsContent(this.modalWidgetName, "HeaderText");
},
modalFooterText() {
return this.getCmsContent(this.modalWidgetName, "FooterText");
},
modal() {
return this.$refs[this.modalName];
},
addressModel: {
get: function () {
return this.modelValue.addressQuestions;
},
},
isMobileAddressAvailable: {
get: function () {
return (
this.addressModel.streetAddress &&
this.addressModel.streetAddress !== "" &&
this.addressModel.city &&
this.addressModel.city !== "" &&
this.addressModel.state &&
this.addressModel.state !== "" &&
this.addressModel.zipCode &&
this.addressModel.zipCode !== "" &&
this.internalModel.isVehicleProtected !== null
);
},
},
},
methods: {
isMobileAddressComplete() {
@ -221,25 +221,14 @@ export default {
this.internalModel.isVehicleProtected !== null
);
},
openModal() {
this.modal.openModal();
getIsMobleLocationOpened() {
if (this.isServiceAddressFromStoreAvailable) {
return false;
}
return true;
},
onModalOpened() {
this.internalModel = deepClone(this.modelValue);
},
setModalStatus(isOpened) {
this.isModalOpened = isOpened;
this.$emit("updated-modal-opened", isOpened);
},
closeModal() {
this.modal.closeModal();
},
onModalClosed() {
this.resetAlerts();
this.internalModel = deepClone(this.modelValue);
},
resetModalButtonStyle() {
this.modal.resetButtonStyle();
setMobileLocationInvalid(isFormInvalid) {
this.$emit("set-mobile-location-invalid", isFormInvalid);
},
resetAlerts() {
this.displayInvalidZipAlert = false;
@ -248,6 +237,10 @@ export default {
async setMobileLocation() {
this.resetAlerts();
// Validate the Zip Code
if (this.internalModel.addressQuestions.zipCode === "") {
this.setMobileLocationInvalid(true);
return;
}
const zipCodeData = await this.getZipCodeData(
this.internalModel.addressQuestions.zipCode,
"service-location"
@ -255,11 +248,11 @@ export default {
if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true;
this.resetModalButtonStyle();
this.setMobileLocationInvalid(true);
return;
} else if (zipCodeData.state != this.internalModel.addressQuestions.state) {
this.displayMismatchStateAndZipAlert = true;
this.resetModalButtonStyle();
this.setMobileLocationInvalid(true);
return;
} else if (
this.internalModel.addressQuestions.zipCode !==
@ -298,10 +291,21 @@ export default {
this.$emit("updated-bill-to-account-number", billToAccountNumber);
}
// update the page level model
this.$emit("setMobileLocationAndProceed", this.internalModel);
this.$emit("setMobileLocation", this.internalModel);
this.setMobileLocationInvalid(false);
},
toggleMobileLocation() {
this.isMobileLocationOpened = !this.isMobileLocationOpened;
},
},
watch: {
internalModel: {
handler() {
this.setMobileLocation();
},
deep: true,
},
modelValue: {
handler(newValue) {
this.internalModel = deepClone(newValue);
@ -310,15 +314,11 @@ export default {
deep: true,
},
},
unmounted() {
if (this.isModalOpened) this.closeModal();
},
components: {
textLink,
modal,
addressQuestions,
vehicleProtectedQuestion,
textBlock,
textLink,
alert,
},
};
@ -329,28 +329,34 @@ export default {
.center-error-message {
justify-content: center !important;
}
}
.update-zip-text-link::before {
content: "";
display: inline-block;
width: 13px;
height: 16px;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 13 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.49635 1.00142e-07C5.64734 -0.000153295 4.80722 0.175918 4.0274 0.517444C3.24757 0.858969 2.54443 1.35877 1.96099 1.98626C0.765713 3.27588 0.0999756 4.98141 0.0999756 6.75394C0.0999756 8.52646 0.765713 10.232 1.96099 11.5216L5.98324 15.777C6.04954 15.8475 6.12918 15.9036 6.21736 15.9419C6.30555 15.9802 6.40045 16 6.49635 16C6.59225 16 6.68716 15.9802 6.77534 15.9419C6.86353 15.9036 6.94317 15.8475 7.00946 15.777L11.0317 11.52C12.2391 10.2383 12.909 8.52914 12.8999 6.75394C12.9094 4.97818 12.2394 3.26832 11.0317 1.98626C10.4481 1.35899 9.74493 0.859347 8.96514 0.517839C8.18535 0.176331 7.34532 0.000130509 6.49635 1.00142e-07V1.00142e-07ZM6.49635 9.13131C6.02507 9.13131 5.56437 8.98913 5.17251 8.72275C4.78065 8.45637 4.47524 8.07776 4.29488 7.63479C4.11453 7.19181 4.06734 6.70438 4.15928 6.23412C4.25123 5.76387 4.47817 5.33191 4.81142 4.99287C5.14467 4.65384 5.56925 4.42295 6.03148 4.32941C6.49371 4.23587 6.97282 4.28388 7.40823 4.46736C7.84364 4.65085 8.21579 4.96157 8.47762 5.36023C8.73945 5.7589 8.87921 6.2276 8.87921 6.70707C8.87921 7.34974 8.62837 7.96611 8.18185 8.4207C7.73532 8.87528 7.12964 9.13088 6.49794 9.13131H6.49635Z' fill='%231574A1'/%3E%3C/svg%3E%0A");
background-size: contain;
vertical-align: middle;
margin-right: 0.5em;
}
.update-zip-text-link::before {
content: "";
display: inline-block;
width: 13px;
height: 16px;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 13 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.49635 1.00142e-07C5.64734 -0.000153295 4.80722 0.175918 4.0274 0.517444C3.24757 0.858969 2.54443 1.35877 1.96099 1.98626C0.765713 3.27588 0.0999756 4.98141 0.0999756 6.75394C0.0999756 8.52646 0.765713 10.232 1.96099 11.5216L5.98324 15.777C6.04954 15.8475 6.12918 15.9036 6.21736 15.9419C6.30555 15.9802 6.40045 16 6.49635 16C6.59225 16 6.68716 15.9802 6.77534 15.9419C6.86353 15.9036 6.94317 15.8475 7.00946 15.777L11.0317 11.52C12.2391 10.2383 12.909 8.52914 12.8999 6.75394C12.9094 4.97818 12.2394 3.26832 11.0317 1.98626C10.4481 1.35899 9.74493 0.859347 8.96514 0.517839C8.18535 0.176331 7.34532 0.000130509 6.49635 1.00142e-07V1.00142e-07ZM6.49635 9.13131C6.02507 9.13131 5.56437 8.98913 5.17251 8.72275C4.78065 8.45637 4.47524 8.07776 4.29488 7.63479C4.11453 7.19181 4.06734 6.70438 4.15928 6.23412C4.25123 5.76387 4.47817 5.33191 4.81142 4.99287C5.14467 4.65384 5.56925 4.42295 6.03148 4.32941C6.49371 4.23587 6.97282 4.28388 7.40823 4.46736C7.84364 4.65085 8.21579 4.96157 8.47762 5.36023C8.73945 5.7589 8.87921 6.2276 8.87921 6.70707C8.87921 7.34974 8.62837 7.96611 8.18185 8.4207C7.73532 8.87528 7.12964 9.13088 6.49794 9.13131H6.49635Z' fill='%231574A1'/%3E%3C/svg%3E%0A");
background-size: contain;
vertical-align: middle;
margin-right: 0.5em;
}
.address-questions {
margin-top: 0em;
}
.update-mobile-location-text-link {
white-space: pre-line;
}
.address-questions-container {
margin-top: 1rem;
}
.update-mobile-location-text-link {
white-space: pre-line;
}
.text-black {
color: $black;
.text-black {
color: $black;
}
.HeaderText {
font-size: 1rem;
font-weight: 600;
line-height: 1.625rem;
color: $black;
text-align: center;
}
}
</style>

View file

@ -7,7 +7,8 @@
textPosition="text-center"
v-model="selectedValue"
validationRules="option-required"
isRequired />
isRequired
:labelBold="labelBold" />
</template>
<script>
@ -27,6 +28,11 @@ export default {
isVehicleProtected: Boolean,
},
cmsWidgetName: String,
labelBold: {
type: Boolean,
required: false,
default: false,
},
},
components: {
buttonQuestion,

View file

@ -343,7 +343,6 @@ describe("service-location.vue", () => {
zipCode: "43054",
},
isVehicleProtected: true,
isMobileSelectedAndModalClosed: true,
};
wrapper.vm.mobileLocationQuestions = mobileLocationQuestions;
@ -356,7 +355,6 @@ describe("service-location.vue", () => {
zipCode: "61606",
},
isVehicleProtected: null,
isMobileSelectedAndModalClosed: false,
};
// Act
@ -459,7 +457,6 @@ describe("service-location.vue", () => {
zipCode: "",
},
isVehicleProtected: null,
isMobileSelectedAndModalClosed: false,
};
wrapper.vm.mobileLocationQuestions = mobileLocationQuestions;
const newMobileLocationQuestions = {
@ -471,15 +468,14 @@ describe("service-location.vue", () => {
zipCode: "43054",
},
isVehicleProtected: true,
isMobileSelectedAndModalClosed: true,
};
wrapper.vm.closeModalAction = jest.fn();
//wrapper.vm.closeModalAction = jest.fn();
// Act
// Trigger the event
await mobileLocationQuestionsComponent.vm.$emit(
"setMobileLocationAndProceed",
"setMobileLocation",
newMobileLocationQuestions
);
@ -556,7 +552,7 @@ describe("service-location.vue", () => {
// Trigger the event
await mobileLocationQuestionsComponent.vm.$emit(
"setMobileLocationAndProceed",
"setMobileLocation",
newMobileLocationQuestions
);
@ -604,10 +600,7 @@ describe("service-location.vue", () => {
wrapper.vm.closeModalAction = jest.fn();
// Act
mobileLocationQuestionsComponent.vm.$emit(
"setMobileLocationAndProceed",
mobileLocationQuestions
);
mobileLocationQuestionsComponent.vm.$emit("setMobileLocation", mobileLocationQuestions);
// Assert
expect(wrapper.vm.selectedAppointmentType).toStrictEqual("Mobile");

View file

@ -83,7 +83,8 @@
ref="appointmentTypeQuestion"
groupName="appointmentTypeQuestion"
cmsWidgetName="AppointmentTypeQuestionWidget"
validationRules="option-required" />
validationRules="option-required"
labelBold="true" />
</div>
</div>
<div class="row justify-content-center">
@ -99,12 +100,12 @@
@updated-serviceability="setServiceabilityDetails"
@updated-contains-military-base="setContainsMilitaryBase"
@updated-mobile-ctu="setCtuForMobile"
@updated-modal-opened="setMobileLocationModalOpened"
validationRules="mobile-location-required"
ref="mobileLocationQuestions"
linkWidgetName="MobileLocationLinkWidget"
modalWidgetName="MobileLocationModalWidget"
@setMobileLocationAndProceed="setMobileLocationQuestions" />
@setMobileLocation="setMobileLocationQuestions"
@set-mobile-location-invalid="setMobileLocationInValid" />
<shopQuestion
ref="shopQuestion"
@ -113,17 +114,14 @@
:selectedAppointmentType="selectedAppointmentType"
:shopProviderData="shopProviderData"
:isDisplayed="isShopQuestionDisplayed"
cmsWidgetName="ShopQuestionWidget"
:isInshopOnly="isInshopOnly" />
cmsWidgetName="ShopQuestionWidget" />
<contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />
<navbar
cmsWidgetName="FunnelFooterWidget"
ref="navbar"
:isForwardActionDisabled="
!meta.valid || displayNoShopsAlert || mobileLocationModalOpened
"
:isForwardActionDisabled="!meta.valid || isForwardActionDisabled"
@back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" />
</div>
@ -177,12 +175,12 @@ const MOBILE_FEE_PART_TYPE = "MOBILE FEE";
// DEFINE VALIDATION RULES
defineRule("mobile-location-required", (value) => {
if (
value.isMobileSelectedAndModalClosed &&
(!value.addressQuestions.streetAddress ||
!value.addressQuestions.city ||
!value.addressQuestions.state ||
!value.addressQuestions.zipCode ||
!value.isVehicleProtected)
!value.isVehicleProtected) &&
value.isMobileSelected
) {
return errorMessages.MOBILE_LOCATION_REQUIRED;
}
@ -216,7 +214,7 @@ export default {
billToAccountNumber: null,
shopProviderData: null,
navigatingForward: false,
mobileLocationModalOpened: false,
isMobileAddressValid: true,
};
},
async beforeRouteEnter(to, from, next) {
@ -307,9 +305,6 @@ export default {
zipCode: this.zipCode,
},
isVehicleProtected: this.isVehicleProtected,
isMobileSelectedAndModalClosed:
this.selectedAppointmentType === "Mobile" &&
!this.mobileLocationModalOpened,
};
},
},
@ -423,10 +418,8 @@ export default {
isNoComp() {
return store.getters.order.policy.isNoComp;
},
isInshopOnly() {
return (
this.isServiceableInshop && !this.isServiceableMobile && !this.isServiceableDropoff
);
isForwardActionDisabled() {
return this.displayNoShopsAlert || !this.isMobileAddressValid;
},
},
methods: {
@ -515,9 +508,6 @@ export default {
setRecycleFeePart(recycleFeePart) {
this.recycleFeePart = recycleFeePart;
},
setMobileLocationModalOpened(isModalOpened) {
this.mobileLocationModalOpened = isModalOpened;
},
//creating async function as the computed property can not directly handle asynchronous operations or promises.
async setMobileLocationQuestions(newValue) {
var newZipCode = newValue.addressQuestions.zipCode;
@ -533,10 +523,7 @@ export default {
}
if (this.isServiceableMobile) {
this.setMobileLocation(newValue);
//proceed to next page
this.forwardButtonAction();
} else {
this.closeModalAction("mobileLocationQuestions");
await getZipCodeData(newZipCode).then((zipCodeData) => {
this.serviceZipCodeQuestion = {
state: zipCodeData.state,
@ -704,7 +691,7 @@ export default {
},
async forwardButtonAction() {
this.navigatingForward = true;
var ctu = this.zipCodeCtu;
if (
this.selectedAppointmentType == AppointmentTypeStrings.MOBILE &&
this.selectedProvider &&
@ -715,18 +702,13 @@ export default {
this.selectedProvider.address.state = null;
this.selectedProvider.address.zipCode = null;
this.selectedProvider.address.zipCodeCtu = null;
}
var ctu = this.zipCodeCtu;
if (this.selectedAppointmentType == AppointmentTypeStrings.IN_SHOP) {
} else {
// if we have a provider.zipCodeCtu that's different than the servicelocation.zipCodeCtu then they
// may have selected a shop in a different ctu. change the servicelocation zip/ctu if different
if (this.zipCodeCtu != this.selectedProvider.address.zipCodeCtu) {
ctu = this.selectedProvider.address.zipCodeCtu;
}
this.city = null;
this.streetAddress = null;
this.resetMobileLocation();
}
await this.dispatchStoreAction(
@ -769,11 +751,15 @@ export default {
this.pageName
);
},
openModalAction(modalName) {
this.$refs[modalName].openModal();
setMobileLocationInValid(isMobileLocationInValid) {
this.isMobileAddressValid = !isMobileLocationInValid;
},
closeModalAction(modalName) {
this.$refs[modalName].closeModal();
displayMobileAddressQuestion(openMobileLocation) {
var mobileLocationQuestionsRef = this.$refs.mobileLocationQuestions;
var isMobileAddressComplete = mobileLocationQuestionsRef.isMobileAddressComplete;
if (isMobileAddressComplete) {
mobileLocationQuestionsRef.isMobileLocationOpened = openMobileLocation;
}
},
},
watch: {
@ -786,8 +772,10 @@ export default {
this.selectedProvider = new Provider(
this.shopProviderData.mobileProviderNumber
);
this.displayMobileAddressQuestion(true);
} else {
this.selectedProvider = new Provider();
this.displayMobileAddressQuestion(false);
}
});
}
@ -799,12 +787,10 @@ export default {
this.selectedProvider = new Provider(
this.shopProviderData.mobileProviderNumber
);
var mobileLocationQs = this.$refs.mobileLocationQuestions;
if (!mobileLocationQs.isMobileAddressComplete()) {
mobileLocationQs.openModal();
}
this.displayMobileAddressQuestion(true);
} else {
this.selectedProvider = new Provider();
this.displayMobileAddressQuestion(false);
}
},
},

View file

@ -77,7 +77,6 @@ export default {
cmsWidgetName: String,
validationRules: String,
isDisplayed: Boolean,
isInshopOnly: Boolean,
},
computed: {
questionText() {

View file

@ -6,7 +6,7 @@
<div
:aria-label="buttonLabel"
class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4 p-md-4">
<span class="m-0" :class="textPosition">
<span class="m-0" :class="[textPosition, labelBold ? 'span-bold' : '']">
{{ buttonLabel }}
</span>
<span v-if="buttonLabelSubCopy" class="m-0 small" :class="textPosition">
@ -88,6 +88,9 @@ export default {
&:checked + .list-button-content span {
font-weight: 500;
}
&:checked + .list-button-content .span-bold {
font-weight: 600;
}
&:checked + .list-button-content span:nth-child(2) {
font-weight: 400;
color: $gray-600;

View file

@ -15,7 +15,10 @@
:class="!isWide ? 'order-1' : 'ms-auto order-3'"
:src="buttonImage"
:alt="altText" />
<p v-if="!isWide" class="small order-3" :class="isMultiSelect ? 'm-0' : 'mt-2 mb-0'">
<p
v-if="!isWide"
class="small order-3"
:class="[isMultiSelect ? 'm-0' : 'mt-2 mb-0', labelBold ? 'p-bold' : '']">
{{ buttonLabel }}
</p>
<p v-if="buttonLabelSubCopy && !isWide" class="fs-7 m-0 order-4 sub-copy">
@ -122,6 +125,9 @@ export default {
color: $black;
font-weight: 500;
}
.p-bold {
font-weight: 600;
}
.sub-copy {
color: $gray-600;