Merge branch 'develop' into CASH-191-button-fix-2

This commit is contained in:
CarlNation 2025-02-20 10:08:54 -05:00 committed by GitHub
commit 04160cef0c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 203 additions and 46 deletions

View file

@ -99,8 +99,8 @@
// Supporting files
import loader from "@/ux-components/loader/loader";
import store from "@/store";
import { TIMINGFUNC_MAP, BUFFER_OFFSET, MONTHS_OF_YEAR } from "./mixins/constants";
import { selectableDaysOptions, requiredParameter, forceTwoDigitString } from "./mixins/helpers";
import { TIMINGFUNC_MAP, BUFFER_OFFSET, MONTHS_OF_YEAR } from "@/digital-components/date-picker/mixins/constants";
import { selectableDaysOptions, requiredParameter, forceTwoDigitString } from "@/digital-components/date-picker/mixins/helpers";
import {
convertDateToDateString,
convertDateStringToDate,

View file

@ -5,6 +5,7 @@
:class="[
this.buttonLabelSubCopy ? 'has-subheader' : '',
this.isInsuranceSelected ? 'pricing-by-day-pkg-lbl-ins' : 'pricing-by-day-pkg-lbl',
!this.additionalButtonData.servicePackageDiscount ? 'adjust-top' : '',
]"
for="testradio">
<div class="package-specs">
@ -193,7 +194,7 @@ export default {
position: absolute;
left: -9999px;
+ .package-label.pricing-by-day-pkg-lbl {
+ .package-label.pricing-by-day-pkg-lbl.adjust-top {
/* Copying a component for an experiment will cause duplication of css classes.
This can cause problems if you want change the value of something only for the experiment
version of the component. So added a more specific selector for the parts I want to change

View file

@ -58,3 +58,15 @@ export function getTopLevelPartsWithRecal(lineItems) {
return lineItems.filter((li) => isRecalPartOrHasChildRecalPart(li));
}
export function getRecalPartNumbers(glassPartsArray) {
if (glassPartsArray && glassPartsArray.length > 0) {
const topLevel = glassPartsArray.filter((gp) => isRecalPart(gp)).map((gp) => gp.partNumber);
const children = glassPartsArray.map((gp) => getRecalPartNumbers(gp.childParts)).flat();
return [...topLevel, ...children];
} else {
return [];
}
}

View file

@ -357,15 +357,18 @@ export default {
false
);
if (vinPagesMixin.methods.isPhoneNumber(this.customerQuestions.emailOrSms)) {
const phone = this.customerQuestions.emailOrSms.replace(/[()]/g, "");
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, phone, false);
} else {
await this.dispatchStoreAction(
storeActions.SAVE_EMAIL,
this.customerQuestions.emailOrSms,
false
);
// if no value due to field being optional, blank both phone and email address
if (!this.customerQuestions.emailOrSms) {
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, "", false);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, "", false);
}
else {
if (vinPagesMixin.methods.isPhoneNumber(this.customerQuestions.emailOrSms)) {
const phone = this.customerQuestions.emailOrSms.replace(/[()]/g, "");
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, phone, false);
} else {
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.customerQuestions.emailOrSms, false);
}
}
await this.dispatchStoreAction(

View file

@ -1,3 +0,0 @@
describe("insurance-company.vue", () => {
it.todo("Some test for the future");
});

View file

@ -0,0 +1,105 @@
import { shallowMount } from '@vue/test-utils';
import InsuranceCompany from '@/layouts/insurance-company/insurance-company.vue';
import { applicationConfig } from '@/constants/application-config.js';
import store from "@/store";
import baseMixin from "@/mixins/base-mixin.js";
jest.mock('@/store', () => ({
getters: {
order: {
payment: {
parentAccountNumber: '12345',
},
},
},
}));
var mockRouter = {
navigateWithoutSaving: jest.fn(),
};
jest.mock('@/mixins/base-mixin.js', () => ({
methods: {
navigateWithoutSaving: jest.fn(),
},
data() {
return {
navigationScenarios: {
CLICKED_BACK: 'clicked_back',
},
};
},
}));
describe("insurance-company.vue", () => {
beforeEach(() => {
// Reset the store's parentAccountNumber before each test
store.getters.order.payment.parentAccountNumber = '12345';
});
test('should return true when parentAccountNumber matches CASH_PARENT_ACCOUNT_NUMBER', () => {
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER = "12345";
const wrapper = shallowMount(InsuranceCompany, {
global: {
mocks: {
$store: store
},
},
});
expect(wrapper.vm.isCashParentAccountNumber()).toBe(true);
});
test('should return false when parentAccountNumber does not match CASH_PARENT_ACCOUNT_NUMBER', () => {
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER = "12345";
store.getters.order.payment.parentAccountNumber = '67890';
const wrapper = shallowMount(InsuranceCompany, {
global: {
mocks: {
$store: store,
},
},
});
expect(wrapper.vm.isCashParentAccountNumber()).toBe(false);
});
test('should call navigateWithoutSaving with { isCashSelected: true } when forceCashSelection is true', () => {
const wrapper = shallowMount(InsuranceCompany, {
global: {
mocks: {
$store: store,
$router: mockRouter,
},
mixins: [baseMixin],
},
});
wrapper.vm.backButtonAction(true);
expect(mockRouter.navigateWithoutSaving).toHaveBeenCalledWith(
wrapper.vm.navigationScenarios.CLICKED_BACK,
wrapper.vm.$route,
{ isCashSelected: true }
);
});
test('should call navigateWithoutSaving with no extra parameter when forceCashSelection is false', () => {
const wrapper = shallowMount(InsuranceCompany, {
global: {
mocks: {
$store: store,
$router: mockRouter,
},
mixins: [baseMixin],
},
});
wrapper.vm.backButtonAction(false);
expect(mockRouter.navigateWithoutSaving).toHaveBeenCalledWith(
wrapper.vm.navigationScenarios.CLICKED_BACK,
wrapper.vm.$route
);
});
});

View file

@ -311,11 +311,18 @@ export default {
false
);
if (vinPagesMixin.methods.isPhoneNumber(this.emailOrSms)) {
const phone = this.emailOrSms.replace(/[()]/g, "");
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, phone, false);
} else {
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailOrSms, false);
// if no value due to field being optional, blank both phone and email address
if (!this.emailOrSms) {
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, "", false);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, "", false);
}
else {
if (vinPagesMixin.methods.isPhoneNumber(this.emailOrSms)) {
const phone = this.emailOrSms.replace(/[()]/g, "");
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, phone, false);
} else {
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailOrSms, false);
}
}
await this.dispatchStoreAction(

View file

@ -7,6 +7,7 @@ import { getMountOptions } from "@/helpers/unit-test-helper.js";
import store from "@/store";
import router from "@/router";
import baseMixin from "../../mixins/base-mixin";
import { experimentSettings } from "../../constants/experiments";
// Mock basemixin
jest.mock("@/mixins/base-mixin.js", () => ({
@ -177,6 +178,7 @@ beforeEach(() => {
glassParts: [],
supportingItems: [],
},
experimentSettings: {},
};
});
afterEach(() => {

View file

@ -18,7 +18,18 @@
marginTopSizeOverride="1" />
</template>
<locationAlerts cmsWidgetPrefix="LocationAlert-" ref="locationAlerts" />
<datePicker
v-if="!isPricingByDayExperiment"
customComponentId="dateQuestion"
selectableDatesSetting="custom"
ref="datePicker"
v-model="selectedDate"
class="text-link-small"
:customSelectableDatesCallback="getAvailableDatesMethod"
validationRules="date-required"
@date-clicked="openInshopTimeSlotsModal" />
<datePicker2
v-if="isPricingByDayExperiment"
customComponentId="dateQuestion"
selectableDatesSetting="custom"
ref="datePicker"
@ -69,7 +80,8 @@ import navbar from "@/fmg-components/nav-bar/nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import { Form, defineRule } from "vee-validate";
import datePicker2 from "@/digital-components/date-picker/date-picker-2";
import datePicker from "@/digital-components/date-picker/date-picker";
import datePicker2 from "@/experiment-components/date-picker-2";
import locationAlerts from "@/layouts/schedule/location-alerts/location-alerts";
import timeSlotModalQuestion from "./time-slot-modal-question/time-slot-modal-question";
import textBlock from "@/digital-components/text-block/text-block";
@ -91,6 +103,8 @@ import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/sched
import { errorMessages } from "@/constants/error-messages";
import { required } from "@/helpers/validation-rules";
import store from "@/store";
import experimentMixin from "@/mixins/experiment-mixin.js";
import { experimentSettings } from "@/constants/experiments";
// DEFINE VALIDATION RULES
defineRule("date-required", required(errorMessages.DATE_REQUIRED));
@ -301,6 +315,13 @@ export default {
(selectableDate) => selectableDate.date === this.selectedDate
);
},
isPricingByDayExperiment() {
return (
experimentMixin.methods
.getSettingValue(experimentSettings.PRICING_BY_DAY)
?.toLowerCase() === "true"
);
},
},
methods: {
splitCopyOnCMSPlaceHolder,
@ -537,6 +558,7 @@ export default {
funnelSubHeader,
Form,
loadingModal,
datePicker,
datePicker2,
locationAlerts,
timeSlotModalQuestion,

View file

@ -330,11 +330,18 @@ export default {
false
);
if (vinPagesMixin.methods.isPhoneNumber(this.emailOrSms)) {
const phone = this.emailOrSms.replace(/[()]/g, "");
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, phone, false);
} else {
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailOrSms, false);
// if no value due to field being optional, blank both phone and email address
if (!this.emailOrSms) {
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, "", false);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, "", false);
}
else {
if (vinPagesMixin.methods.isPhoneNumber(this.emailOrSms)) {
const phone = this.emailOrSms.replace(/[()]/g, "");
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, phone, false);
} else {
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailOrSms, false);
}
}
await this.dispatchStoreAction(
@ -380,11 +387,18 @@ export default {
);
}
if (vinPagesMixin.methods.isPhoneNumber(this.emailOrSms)) {
const phone = this.emailOrSms.replace(/[()]/g, "");
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, phone, false);
} else {
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailOrSms, false);
// if no value due to field being optional, blank both phone and email address
if (!this.emailOrSms) {
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, "", false);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, "", false);
}
else {
if (vinPagesMixin.methods.isPhoneNumber(this.emailOrSms)) {
const phone = this.emailOrSms.replace(/[()]/g, "");
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, phone, false);
} else {
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailOrSms, false);
}
}
await this.dispatchStoreAction(

View file

@ -46,6 +46,7 @@ import {
containsRecalParts,
getTopLevelPartsWithRecal,
isRecalPartOrHasChildRecalPart,
getRecalPartNumbers,
} from "@/helpers/recal-helper";
import { externalParameterStatus } from "@/constants/external-parameters";
import { experimentSettings } from "@/constants/experiments";
@ -1714,10 +1715,15 @@ export const actions = {
var endPoint = `${endpoints.GetMobileFeePart.url}/?serviceType=${serviceType}&facilityType=${facilityType}&parentAccountNumber=${parentAccountNumber}&billToAccountNumber=${billToAccountNumber}&providerNumber=${providerNumber}&isItacOptimized=${isItacOptimized}&zipCode=${zipCode}`;
const recalPartNumber = getRecalPartNumber(order.lineItems?.glassParts[0]);
const recalPartNumbers = getRecalPartNumbers(order.lineItems?.glassParts);
const carId = order.vehicle?.carId;
if (recalPartNumber && carId) {
endPoint = `${endPoint}&partNumbers=${recalPartNumber}&carId=${carId}`;
if (recalPartNumbers && recalPartNumbers.length > 0 && carId) {
let additionalQueryParams = ``;
for (let i = 0; i < recalPartNumbers.length; i++) {
additionalQueryParams += `&partNumbers[${i}]=${recalPartNumbers[i]}`;
}
additionalQueryParams += `&carId=${carId}`;
endPoint += additionalQueryParams;
}
if (coverageStatus) {
@ -3798,15 +3804,3 @@ function getExternalParameterDefaultState() {
function saveExternalParameterState(externalParameterState) {
window.sessionStorage.setItem("externalParameterState", JSON.stringify(externalParameterState));
}
//This function finds the recalibration part and returns the part number for it.
function getRecalPartNumber(glassPartsArray) {
const recalPart = glassPartsArray.childParts.find(
(item) => item.partType === partTypeStrings.ADAS_RECALIBRATION
);
if (recalPart) {
return recalPart.partNumber;
} else {
return null;
}
}