Merge branch 'release/2025.02.13' into feature/CASH-183

This commit is contained in:
scottkiener 2025-02-05 10:20:16 -05:00 committed by GitHub
commit c3bd439703
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 116 additions and 53 deletions

View file

@ -18,6 +18,8 @@ const errorMessages = {
LAST_NAME_REQUIRED: "Please enter your last name", LAST_NAME_REQUIRED: "Please enter your last name",
EMAIL_ADDRESS_REQUIRED: "Please enter your email address", EMAIL_ADDRESS_REQUIRED: "Please enter your email address",
EMAIL_ADDRESS_FORMAT: "Please enter a valid email address", EMAIL_ADDRESS_FORMAT: "Please enter a valid email address",
EMAIL_SMS_REQUIRED: "Please enter your mobile phone number or email",
EMAIL_SMS_FORMAT: "Please enter a valid mobile phone number or email",
SERVICE_ZIP_REQUIRED: "Please enter your service ZIP", SERVICE_ZIP_REQUIRED: "Please enter your service ZIP",
SERVICE_ZIP_FORMAT: "Please enter a valid service ZIP", SERVICE_ZIP_FORMAT: "Please enter a valid service ZIP",
VIN_REQUIRED: "Please enter your VIN", VIN_REQUIRED: "Please enter your VIN",

View file

@ -1,6 +1,7 @@
const storeActions = { const storeActions = {
// Content Actions // Content Actions
GET_PAGE_DATA: "getPageData", GET_PAGE_DATA: "getPageData",
SAVE_PAGE_DATA: "savePageData",
// Vehicle Actions // Vehicle Actions
GET_VEHICLE_YEARS: "getVehicleYears", GET_VEHICLE_YEARS: "getVehicleYears",

View file

@ -121,9 +121,9 @@ export default {
const partsOrQuestions = orderFromStore.damage?.partQuestionAnswers; const partsOrQuestions = orderFromStore.damage?.partQuestionAnswers;
if (partsOrQuestions) { if (partsOrQuestions) {
partsOrQuestions.forEach(pqa => { partsOrQuestions.forEach((pqa) => {
const payloadPartQuestions = []; const payloadPartQuestions = [];
pqa.answeredQuestions.forEach(answer => { pqa.answeredQuestions.forEach((answer) => {
payloadPartQuestions.push({ payloadPartQuestions.push({
questionSeq: answer?.questionNum, questionSeq: answer?.questionNum,
questionText: answer?.questionText, questionText: answer?.questionText,

View file

@ -181,6 +181,7 @@ function applyMockStoreDataToGetters() {
payment: mockStoreData.payment, payment: mockStoreData.payment,
policy: mockStoreData.policy, policy: mockStoreData.policy,
externalParameterServiceZip: mockStoreData.externalParameterServiceZip, externalParameterServiceZip: mockStoreData.externalParameterServiceZip,
emailOrSms: mockStoreData.customer.emailAddress,
}; };
store.state.order = mockStoreData; store.state.order = mockStoreData;
store.state.applicationUser.experiments = mockExperimentSettings; store.state.applicationUser.experiments = mockExperimentSettings;
@ -241,7 +242,7 @@ describe("service-zip.vue", () => {
// Assert // Assert
expect(wrapper.vm.serviceZipCode).toEqual("11111"); expect(wrapper.vm.serviceZipCode).toEqual("11111");
expect(wrapper.vm.emailAddress).toEqual("builddigitaltest@safelite.com"); expect(wrapper.vm.emailOrSms).toEqual("builddigitaltest@safelite.com");
}); });
test("Zip in querystring -> pushed to data", () => { test("Zip in querystring -> pushed to data", () => {

View file

@ -23,11 +23,11 @@
<textboxQuestion <textboxQuestion
class="mb-0" class="mb-0"
cmsWidgetName="EmailAddressQuestionWidget" cmsWidgetName="EmailAddressQuestionWidget"
v-model="emailAddress" v-model="emailOrSms"
inputId="emailAddress" inputId="emailOrSms"
:isRequired="!IsEmailOptional" :isRequired="!IsEmailOptional"
disableAutoFill disableAutoFill
:validationRules="EmailValidationRules" :validationRules="EmailOrSmsValidationRules"
:addOptionalText="IsEmailOptional" /> :addOptionalText="IsEmailOptional" />
<textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" /> <textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" />
@ -88,16 +88,17 @@ import vinPagesMixin from "@/mixins/vin-pages-mixin";
import { saveSession } from "@/helpers/heritage-integration/order-helper.js"; import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
import baseMixin from "@/mixins/base-mixin.js"; import baseMixin from "@/mixins/base-mixin.js";
import { queryStrings } from "@/constants/query-strings"; import { queryStrings } from "@/constants/query-strings";
import { fmgPageValues } from "@/router/router-constants/fmgPage-values";
// Define Validation Rules // Define Validation Rules
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED)); defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT)); defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED)); defineRule("email-sms-required", required(errorMessages.EMAIL_SMS_REQUIRED));
defineRule( defineRule(
"email-address-format", "email-sms-format",
regex( regex(
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/, /^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$|^\(?(\d{3})\)?[-. ]?(\d{3})[-. ]?(\d{4})$/,
errorMessages.EMAIL_ADDRESS_FORMAT errorMessages.EMAIL_SMS_FORMAT
) )
); );
defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
@ -108,7 +109,7 @@ export default {
data() { data() {
return { return {
serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode, serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode,
emailAddress: this.getEmailFromStore(), emailOrSms: this.getEmailOrSmsFromStore(),
displayInvalidZipAlert: false, displayInvalidZipAlert: false,
displayNonServiceableZipAlert: false, displayNonServiceableZipAlert: false,
}; };
@ -160,11 +161,11 @@ export default {
store.getters.order.serviceLocation.zipCode store.getters.order.serviceLocation.zipCode
); );
}, },
getEmailFromStore() { getEmailOrSmsFromStore() {
return ( return store.getters.emailOrSms;
store.getters.externalParameterServiceZip.emailAddress ?? },
store.getters.order.customer.emailAddress getPhoneFromStore() {
); return store.getters.order.customer.phoneNumber;
}, },
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
return store.getters.damage.isRepair || store.getters.damage.glassToReplace?.length > 0; return store.getters.damage.isRepair || store.getters.damage.glassToReplace?.length > 0;
@ -186,7 +187,23 @@ export default {
}, },
async forwardButtonAction() { async forwardButtonAction() {
const zipCodeData = await this.getZipCodeData(this.serviceZipCode); const zipCodeData = await this.getZipCodeData(this.serviceZipCode);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, 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);
}
await this.dispatchStoreAction(
storeActions.SAVE_PAGE_DATA,
{
page: fmgPageValues.EMAIL_SMS_PAGES,
data: { emailOrSmsValue: this.emailOrSms },
},
false
);
await this.dispatchStoreAction( await this.dispatchStoreAction(
storeActions.SAVE_SERVICE_ZIP_CODE_INFO, storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
{ {

View file

@ -16,6 +16,11 @@ export default {
? "email-address-format" ? "email-address-format"
: "email-address-required|email-address-format"; : "email-address-required|email-address-format";
}, },
EmailOrSmsValidationRules() {
return this.IsEmailOptional
? "email-sms-format"
: "email-sms-required|email-sms-format";
},
}, },
methods: { methods: {
async navigateForwardWithSingleCarMatch() { async navigateForwardWithSingleCarMatch() {
@ -56,5 +61,9 @@ export default {
false false
); );
}, },
isPhoneNumber(input) {
const phoneRegex = /^\(?(\d{3})\)?[-. ]?(\d{3})[-. ]?(\d{4})$/;
return phoneRegex.test(input);
},
}, },
}; };

View file

@ -23,6 +23,7 @@ const fmgPageValues = {
PAYMENT_PIA_RETURN: "payment-pia-return", PAYMENT_PIA_RETURN: "payment-pia-return",
CONFIRMATION: "confirmation", CONFIRMATION: "confirmation",
RETURN_USER: "return-user", RETURN_USER: "return-user",
EMAIL_SMS_PAGES: "email-or-sms-related-pages",
}; };
const funnelStartPageName = fmgPageValues.VEHICLE; const funnelStartPageName = fmgPageValues.VEHICLE;

View file

@ -678,34 +678,38 @@ export const mutations = {
sessionInformation.order.payment.billToAccountNumber; sessionInformation.order.payment.billToAccountNumber;
state.order.payment.inactivePromos = sessionInformation.order.payment.inactivePromos; state.order.payment.inactivePromos = sessionInformation.order.payment.inactivePromos;
state.order.serviceLocation.address = //Do not assign default service type once user make service type selection
sessionInformation.order.serviceLocation.streetAddress; if (state.order.serviceLocation.appointmentType == null) {
state.order.serviceLocation.address2 = state.order.serviceLocation.address =
sessionInformation.order.serviceLocation.streetAddress2; sessionInformation.order.serviceLocation.streetAddress;
state.order.serviceLocation.city = sessionInformation.order.serviceLocation.city; state.order.serviceLocation.address2 =
state.order.serviceLocation.state = sessionInformation.order.serviceLocation.state; sessionInformation.order.serviceLocation.streetAddress2;
state.order.serviceLocation.zipCode = sessionInformation.order.serviceLocation.zipCode; state.order.serviceLocation.city = sessionInformation.order.serviceLocation.city;
state.order.serviceLocation.zipCodeCtu = state.order.serviceLocation.state = sessionInformation.order.serviceLocation.state;
sessionInformation.order.serviceLocation.zipCodeCtu; state.order.serviceLocation.zipCode = sessionInformation.order.serviceLocation.zipCode;
state.order.serviceLocation.zipCodeCtu =
sessionInformation.order.serviceLocation.zipCodeCtu;
state.order.serviceLocation.appointmentType = state.order.serviceLocation.appointmentType =
sessionInformation.order.serviceLocation.appointmentType; sessionInformation.order.serviceLocation.appointmentType;
state.order.serviceLocation.isVehicleProtected = state.order.serviceLocation.isVehicleProtected =
sessionInformation.order.serviceLocation.isVehicleProtected; sessionInformation.order.serviceLocation.isVehicleProtected;
state.order.serviceLocation.provider.providerNumber = state.order.serviceLocation.provider.providerNumber =
sessionInformation.order.serviceLocation.provider?.providerNumber; sessionInformation.order.serviceLocation.provider?.providerNumber;
state.order.serviceLocation.provider.address.streetAddress = state.order.serviceLocation.provider.address.streetAddress =
sessionInformation.order.serviceLocation.provider?.address?.streetAddress; sessionInformation.order.serviceLocation.provider?.address?.streetAddress;
state.order.serviceLocation.provider.address.city = state.order.serviceLocation.provider.address.city =
sessionInformation.order.serviceLocation.provider?.address?.city; sessionInformation.order.serviceLocation.provider?.address?.city;
state.order.serviceLocation.provider.address.state = state.order.serviceLocation.provider.address.state =
sessionInformation.order.serviceLocation.provider?.address?.state; sessionInformation.order.serviceLocation.provider?.address?.state;
state.order.serviceLocation.provider.address.zipCode = state.order.serviceLocation.provider.address.zipCode =
sessionInformation.order.serviceLocation.provider?.address?.zipCode; sessionInformation.order.serviceLocation.provider?.address?.zipCode;
state.order.serviceLocation.provider.address.zipCodeCtu = state.order.serviceLocation.provider.address.zipCodeCtu =
sessionInformation.order.serviceLocation.provider?.address?.zipCodeCtu; sessionInformation.order.serviceLocation.provider?.address?.zipCodeCtu;
state.order.serviceLocation.techNotes = sessionInformation.order.serviceLocation.techNotes; state.order.serviceLocation.techNotes =
sessionInformation.order.serviceLocation.techNotes;
}
// if we're loading a session and we do not have a provider number yet, then set isInsurance to null so that // if we're loading a session and we do not have a provider number yet, then set isInsurance to null so that
// a service package is not selected by default on the quote page. // a service package is not selected by default on the quote page.
@ -749,14 +753,15 @@ export const mutations = {
state.applicationUser.savedSessionId = state.applicationUser.savedSessionId =
sessionInformation.applicationUser.savedSessionId; sessionInformation.applicationUser.savedSessionId;
} }
//Do not assign default schedule details once user make schedule selection
state.order.schedule.date = sessionInformation.order.schedule?.date; if (state.order.schedule.date == null) {
state.order.schedule.startTime = sessionInformation.order.schedule?.startTime; state.order.schedule.date = sessionInformation.order.schedule?.date;
state.order.schedule.endTime = sessionInformation.order.schedule?.endTime; state.order.schedule.startTime = sessionInformation.order.schedule?.startTime;
state.order.schedule.routeCode = sessionInformation.order.schedule?.routeCode; state.order.schedule.endTime = sessionInformation.order.schedule?.endTime;
state.order.schedule.jobMaxMinutes = sessionInformation.order.schedule?.jobMaxMinutes; state.order.schedule.routeCode = sessionInformation.order.schedule?.routeCode;
state.order.schedule.jobMinMinutes = sessionInformation.order.schedule?.jobMinMinutes; state.order.schedule.jobMaxMinutes = sessionInformation.order.schedule?.jobMaxMinutes;
state.order.schedule.jobMinMinutes = sessionInformation.order.schedule?.jobMinMinutes;
}
state.order.policy.currentDeductible = sessionInformation.order.policy?.currentDeductible; state.order.policy.currentDeductible = sessionInformation.order.policy?.currentDeductible;
state.order.policy.originalDeductible = sessionInformation.order.policy?.originalDeductible; state.order.policy.originalDeductible = sessionInformation.order.policy?.originalDeductible;
state.order.policy.additionalAuthFlag = sessionInformation.order.policy?.additionalAuthFlag; state.order.policy.additionalAuthFlag = sessionInformation.order.policy?.additionalAuthFlag;
@ -997,6 +1002,26 @@ export const getters = {
externalParameterEstimate: (state) => externalParameterState?.estimate, externalParameterEstimate: (state) => externalParameterState?.estimate,
externalParameterCustomer: (state) => externalParameterState?.customer, externalParameterCustomer: (state) => externalParameterState?.customer,
isExternalParameter: (state) => externalParameterState?.isExternalParameter, isExternalParameter: (state) => externalParameterState?.isExternalParameter,
emailOrSms: (state) => {
const email = externalParameterState.serviceZip.emailAddress ?? state.order.customer.emailAddress;
const phone = state.order.customer.phoneNumber;
if (!phone && !email) {
return null;
}
if (phone && !email) {
return phone;
}
if (email && !phone) {
return email;
}
// if we're here, then we have both email and phone so get the value from pageData to reflect what they entered on the page
return state.applicationUser.pageData[fmgPageValues.EMAIL_SMS_PAGES]?.emailOrSmsValue;
},
}; };
function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) { function getNonFalseValuesOfPropertyInArrayOfObjects(array, propertyName) {
@ -2267,7 +2292,7 @@ export const actions = {
response.data response.data
); );
await resetScheduleIfUnavailable(context, response.data.order, pageNameToLog); await resetScheduleIfUnavailable(context, context.state.order, pageNameToLog);
return response; return response;
}, },
(error) => { (error) => {
@ -3055,7 +3080,14 @@ export const actions = {
}, },
savePhoneNumber(context, phoneNumber) { savePhoneNumber(context, phoneNumber) {
context.commit(storeMutations.UPDATE_CUSTOMER_PHONE_NUMBER, phoneNumber === "" ? null : phoneNumber); context.commit(
storeMutations.UPDATE_CUSTOMER_PHONE_NUMBER,
phoneNumber === "" ? null : phoneNumber
);
},
savePageData(context, emailOrSms) {
context.commit(storeMutations.UPDATE_PAGE_DATA, emailOrSms);
}, },
saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) { saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) {