CASH-1911: Save isSmsMarketingOptIn in vueX and dynamo

This commit is contained in:
credelinghuys 2026-07-15 09:16:11 -04:00
parent 0e8fd97e43
commit 6d6e879441
10 changed files with 90 additions and 40 deletions

View file

@ -88,6 +88,7 @@ const storeActions = {
SAVE_EMAIL: "saveEmail", SAVE_EMAIL: "saveEmail",
SAVE_PHONE_NUMBER: "savePhoneNumber", SAVE_PHONE_NUMBER: "savePhoneNumber",
SAVE_IS_SMS_OPT_IN: "saveIsSmsOptIn", SAVE_IS_SMS_OPT_IN: "saveIsSmsOptIn",
SAVE_IS_SMS_MARKETING_OPT_IN: "saveIsSmsMarketingOptIn",
SAVE_WAITLIST_REQUESTED: "saveWaitListRequested", SAVE_WAITLIST_REQUESTED: "saveWaitListRequested",
SAVE_REGISTRATION_LICENSE_PLATE_LOOKUP: "saveRegistrationLicensePlateLookup", SAVE_REGISTRATION_LICENSE_PLATE_LOOKUP: "saveRegistrationLicensePlateLookup",
SAVE_VIN: "saveVin", SAVE_VIN: "saveVin",

View file

@ -49,6 +49,7 @@ const storeMutations = {
UPDATE_CUSTOMER_EMAIL_ADDRESS: "updateCustomerEmailAddress", UPDATE_CUSTOMER_EMAIL_ADDRESS: "updateCustomerEmailAddress",
UPDATE_CUSTOMER_PHONE_NUMBER: "updateCustomerPhoneNumber", UPDATE_CUSTOMER_PHONE_NUMBER: "updateCustomerPhoneNumber",
UPDATE_CUSTOMER_IS_SMS_OPT_IN: "updateCustomerIsSmsOptin", UPDATE_CUSTOMER_IS_SMS_OPT_IN: "updateCustomerIsSmsOptin",
UPDATE_CUSTOMER_IS_SMS_MARKETING_OPT_IN: "updateCustomerIsSmsMarketingOptin",
UPDATE_CUSTOMER_DETAILS: "updateCustomerDetails", UPDATE_CUSTOMER_DETAILS: "updateCustomerDetails",
UPDATE_CUSTOMER_WAITLIST_REQUESTED: "updateCustomerWaitListRequested", UPDATE_CUSTOMER_WAITLIST_REQUESTED: "updateCustomerWaitListRequested",

View file

@ -10,7 +10,7 @@ jest.mock("@/helpers/heritage-integration/order-helper.js", () => ({
jest.mock("@/helpers/save-progress-sms-consent/save-progress-sms-consent-helper", () => ({ jest.mock("@/helpers/save-progress-sms-consent/save-progress-sms-consent-helper", () => ({
...jest.requireActual("@/helpers/save-progress-sms-consent/save-progress-sms-consent-helper"), ...jest.requireActual("@/helpers/save-progress-sms-consent/save-progress-sms-consent-helper"),
getSaveProgressSmsConsentConfig: jest.fn().mockResolvedValue({ getSaveProgressSmsConsentConfig: jest.fn().mockReturnValue({
copy: { copy: {
transactional: "Sign me up for updates about my upcoming service.", transactional: "Sign me up for updates about my upcoming service.",
marketing: "Sign me up for promotional and product offers.", marketing: "Sign me up for promotional and product offers.",

View file

@ -138,7 +138,7 @@ export default {
}, },
}, },
async mounted() { async mounted() {
await this.loadSmsConsentConfig(); this.loadSmsConsentConfig();
if (this.showSaveProgressPopup) this.modal.openModal(); if (this.showSaveProgressPopup) this.modal.openModal();
}, },
@ -200,8 +200,8 @@ export default {
}, },
}, },
methods: { methods: {
async loadSmsConsentConfig() { loadSmsConsentConfig() {
const config = await getSaveProgressSmsConsentConfig(); const config = getSaveProgressSmsConsentConfig();
this.smsConsentCopy = config.copy; this.smsConsentCopy = config.copy;
if (!this.isProgressSaved) { if (!this.isProgressSaved) {
@ -257,7 +257,6 @@ export default {
contactMethod: this.contactMethod, contactMethod: this.contactMethod,
userInput: this.userInput, userInput: this.userInput,
smsConsent: this.smsConsent, smsConsent: this.smsConsent,
pageName: this.pageName,
}); });
// send store call to send to new API (that triggers an email/SMS send) // send store call to send to new API (that triggers an email/SMS send)

View file

@ -1,5 +1,4 @@
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import store from "@/store";
export const saveProgressPopupContactMethods = { export const saveProgressPopupContactMethods = {
PHONE: "PhoneAnswer", PHONE: "PhoneAnswer",
@ -20,7 +19,7 @@ export function normalizePhoneNumberForStore(phoneNumber) {
export async function saveProgressPopupContactToStore( export async function saveProgressPopupContactToStore(
dispatchStoreAction, dispatchStoreAction,
{ contactMethod, userInput, smsConsent, pageName } { contactMethod, userInput, smsConsent }
) { ) {
if (isPhoneContactMethod(contactMethod)) { if (isPhoneContactMethod(contactMethod)) {
await dispatchStoreAction( await dispatchStoreAction(
@ -29,17 +28,9 @@ export async function saveProgressPopupContactToStore(
false false
); );
await dispatchStoreAction(storeActions.SAVE_IS_SMS_OPT_IN, smsConsent.transactional, false); await dispatchStoreAction(storeActions.SAVE_IS_SMS_OPT_IN, smsConsent.transactional, false);
const existingPageData = store.getters.pageData(pageName) ?? {};
await dispatchStoreAction( await dispatchStoreAction(
storeActions.SAVE_PAGE_DATA, storeActions.SAVE_IS_SMS_MARKETING_OPT_IN,
{ smsConsent.marketing,
page: pageName,
data: {
...existingPageData,
saveProgressSmsConsent: { ...smsConsent },
},
},
false false
); );

View file

@ -1,5 +1,4 @@
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import store from "@/store";
import { import {
isPhoneContactMethod, isPhoneContactMethod,
normalizePhoneNumberForStore, normalizePhoneNumberForStore,
@ -7,16 +6,9 @@ import {
saveProgressPopupContactToStore, saveProgressPopupContactToStore,
} from "./save-progress-popup-contact-helper"; } from "./save-progress-popup-contact-helper";
jest.mock("@/store", () => ({
getters: {
pageData: jest.fn(),
},
}));
describe("save-progress-popup-contact-helper", () => { describe("save-progress-popup-contact-helper", () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
store.getters.pageData.mockReturnValue({ servicePackageSelected: "premium" });
}); });
describe("isPhoneContactMethod", () => { describe("isPhoneContactMethod", () => {
@ -41,7 +33,7 @@ describe("save-progress-popup-contact-helper", () => {
}); });
describe("saveProgressPopupContactToStore", () => { describe("saveProgressPopupContactToStore", () => {
it("should save phone number and persist sms consent on phone tab", async () => { it("should save phone number and sms consent on customer when phone tab is selected", async () => {
const dispatchStoreAction = jest.fn().mockResolvedValue(undefined); const dispatchStoreAction = jest.fn().mockResolvedValue(undefined);
const smsConsent = { transactional: true, marketing: false }; const smsConsent = { transactional: true, marketing: false };
@ -49,7 +41,6 @@ describe("save-progress-popup-contact-helper", () => {
contactMethod: saveProgressPopupContactMethods.PHONE, contactMethod: saveProgressPopupContactMethods.PHONE,
userInput: "555-123-4567", userInput: "555-123-4567",
smsConsent, smsConsent,
pageName: "quote",
}); });
expect(dispatchStoreAction).toHaveBeenCalledWith( expect(dispatchStoreAction).toHaveBeenCalledWith(
@ -68,14 +59,13 @@ describe("save-progress-popup-contact-helper", () => {
false false
); );
expect(dispatchStoreAction).toHaveBeenCalledWith( expect(dispatchStoreAction).toHaveBeenCalledWith(
storeActions.SAVE_IS_SMS_MARKETING_OPT_IN,
false,
false
);
expect(dispatchStoreAction).not.toHaveBeenCalledWith(
storeActions.SAVE_PAGE_DATA, storeActions.SAVE_PAGE_DATA,
{ expect.anything(),
page: "quote",
data: {
servicePackageSelected: "premium",
saveProgressSmsConsent: smsConsent,
},
},
false false
); );
}); });
@ -87,7 +77,6 @@ describe("save-progress-popup-contact-helper", () => {
contactMethod: saveProgressPopupContactMethods.EMAIL, contactMethod: saveProgressPopupContactMethods.EMAIL,
userInput: "test@example.com", userInput: "test@example.com",
smsConsent: { transactional: false, marketing: false }, smsConsent: { transactional: false, marketing: false },
pageName: "quote",
}); });
expect(dispatchStoreAction).toHaveBeenCalledWith( expect(dispatchStoreAction).toHaveBeenCalledWith(
@ -105,6 +94,11 @@ describe("save-progress-popup-contact-helper", () => {
expect.anything(), expect.anything(),
false false
); );
expect(dispatchStoreAction).not.toHaveBeenCalledWith(
storeActions.SAVE_IS_SMS_MARKETING_OPT_IN,
expect.anything(),
false
);
expect(dispatchStoreAction).not.toHaveBeenCalledWith( expect(dispatchStoreAction).not.toHaveBeenCalledWith(
storeActions.SAVE_PAGE_DATA, storeActions.SAVE_PAGE_DATA,
expect.anything(), expect.anything(),

View file

@ -1,3 +1,5 @@
import store from "@/store";
const SAVE_PROGRESS_SMS_CONSENT_FALLBACK_COPY = { const SAVE_PROGRESS_SMS_CONSENT_FALLBACK_COPY = {
transactional: "Sign me up for updates about my upcoming service.", transactional: "Sign me up for updates about my upcoming service.",
marketing: "Sign me up for promotional and product offers.", marketing: "Sign me up for promotional and product offers.",
@ -18,10 +20,12 @@ export function hasSaveProgressSmsConsentSelection(consent, showConsentManagemen
return Boolean(consent?.transactional || (showConsentManagement && consent?.marketing)); return Boolean(consent?.transactional || (showConsentManagement && consent?.marketing));
} }
export async function getSaveProgressSmsConsentConfig() { export function getSaveProgressSmsConsentConfig() {
// Replace with Consent Management API lookup (CASH-1911).
return { return {
copy: getSaveProgressSmsConsentFallbackCopy(), copy: getSaveProgressSmsConsentFallbackCopy(),
value: defaultSaveProgressSmsConsent(), value: {
transactional: Boolean(store.getters.order.customer.isSmsOptIn),
marketing: Boolean(store.getters.order.customer.isSmsMarketingOptIn),
},
}; };
} }

View file

@ -1,3 +1,5 @@
import { storeActions } from "@/constants/store-actions";
import store from "@/store";
import { import {
defaultSaveProgressSmsConsent, defaultSaveProgressSmsConsent,
getSaveProgressSmsConsentFallbackCopy, getSaveProgressSmsConsentFallbackCopy,
@ -5,12 +7,38 @@ import {
hasSaveProgressSmsConsentSelection, hasSaveProgressSmsConsentSelection,
} from "./save-progress-sms-consent-helper"; } from "./save-progress-sms-consent-helper";
jest.mock("@/store", () => ({
getters: {
order: {
customer: {
isSmsOptIn: null,
isSmsMarketingOptIn: null,
},
},
},
}));
describe("save-progress-sms-consent-helper", () => { describe("save-progress-sms-consent-helper", () => {
beforeEach(() => {
jest.clearAllMocks();
store.getters.order.customer.isSmsOptIn = null;
store.getters.order.customer.isSmsMarketingOptIn = null;
});
describe("getSaveProgressSmsConsentConfig", () => { describe("getSaveProgressSmsConsentConfig", () => {
it("should return fallback copy and default consent values", async () => { it("should return fallback copy and consent values from the store", () => {
const config = await getSaveProgressSmsConsentConfig(); store.getters.order.customer.isSmsOptIn = true;
store.getters.order.customer.isSmsMarketingOptIn = true;
const config = getSaveProgressSmsConsentConfig();
expect(config.copy).toEqual(getSaveProgressSmsConsentFallbackCopy()); expect(config.copy).toEqual(getSaveProgressSmsConsentFallbackCopy());
expect(config.value).toEqual({ transactional: true, marketing: true });
});
it("should return defaults when no consent is stored", () => {
const config = getSaveProgressSmsConsentConfig();
expect(config.value).toEqual(defaultSaveProgressSmsConsent()); expect(config.value).toEqual(defaultSaveProgressSmsConsent());
}); });
}); });

View file

@ -113,6 +113,7 @@ const getDefaultState = () => {
phoneNumber: null, phoneNumber: null,
phoneExtension: null, phoneExtension: null,
isSmsOptIn: null, isSmsOptIn: null,
isSmsMarketingOptIn: null,
waitListRequested: null, waitListRequested: null,
address: { address: {
streetAddress: null, streetAddress: null,
@ -499,6 +500,9 @@ export const mutations = {
updateCustomerIsSmsOptin(state, isSmsOptIn) { updateCustomerIsSmsOptin(state, isSmsOptIn) {
state.order.customer.isSmsOptIn = isSmsOptIn; state.order.customer.isSmsOptIn = isSmsOptIn;
}, },
updateCustomerIsSmsMarketingOptin(state, isSmsMarketingOptIn) {
state.order.customer.isSmsMarketingOptIn = isSmsMarketingOptIn;
},
updateCustomerWaitListRequested(state, waitListRequested) { updateCustomerWaitListRequested(state, waitListRequested) {
state.order.customer.waitListRequested = waitListRequested; state.order.customer.waitListRequested = waitListRequested;
}, },
@ -575,6 +579,9 @@ export const mutations = {
state.order.customer.emailAddress = customerDetails.emailAddress; state.order.customer.emailAddress = customerDetails.emailAddress;
state.order.customer.phoneNumber = customerDetails.phoneNumber; state.order.customer.phoneNumber = customerDetails.phoneNumber;
state.order.customer.isSmsOptIn = customerDetails.isSmsOptIn; state.order.customer.isSmsOptIn = customerDetails.isSmsOptIn;
if (customerDetails.isSmsMarketingOptIn !== undefined) {
state.order.customer.isSmsMarketingOptIn = customerDetails.isSmsMarketingOptIn;
}
} }
}, },
updateInsuranceDetails(state, insuranceDetails) { updateInsuranceDetails(state, insuranceDetails) {
@ -972,6 +979,8 @@ export const mutations = {
state.order.customer.phoneNumber = sessionInformation.order.customer.homePhone; state.order.customer.phoneNumber = sessionInformation.order.customer.homePhone;
state.order.customer.phoneExtension = sessionInformation.order.customer.phoneExt; state.order.customer.phoneExtension = sessionInformation.order.customer.phoneExt;
state.order.customer.isSmsOptIn = sessionInformation.order.customer.isSmsOptIn; state.order.customer.isSmsOptIn = sessionInformation.order.customer.isSmsOptIn;
state.order.customer.isSmsMarketingOptIn =
sessionInformation.order.customer.isSmsMarketingOptIn;
if (sessionInformation.order.customer.address) { if (sessionInformation.order.customer.address) {
state.order.customer.address = Object.assign(state.order.customer.address, { state.order.customer.address = Object.assign(state.order.customer.address, {
@ -2830,6 +2839,7 @@ export const actions = {
firstName: order.customer.firstName, firstName: order.customer.firstName,
lastName: order.customer.lastName, lastName: order.customer.lastName,
isSmsOptIn: order.customer.isSmsOptIn, isSmsOptIn: order.customer.isSmsOptIn,
isSmsMarketingOptIn: order.customer.isSmsMarketingOptIn,
phoneNumber: order.customer.phoneNumber, phoneNumber: order.customer.phoneNumber,
phoneExt: order.customer.phoneExtension, phoneExt: order.customer.phoneExtension,
address: { address: {
@ -3882,6 +3892,9 @@ export const actions = {
saveIsSmsOptIn(context, isSmsOptIn) { saveIsSmsOptIn(context, isSmsOptIn) {
context.commit(storeMutations.UPDATE_CUSTOMER_IS_SMS_OPT_IN, isSmsOptIn); context.commit(storeMutations.UPDATE_CUSTOMER_IS_SMS_OPT_IN, isSmsOptIn);
}, },
saveIsSmsMarketingOptIn(context, isSmsMarketingOptIn) {
context.commit(storeMutations.UPDATE_CUSTOMER_IS_SMS_MARKETING_OPT_IN, isSmsMarketingOptIn);
},
saveWaitListRequested(context, waitListRequested) { saveWaitListRequested(context, waitListRequested) {
context.commit(storeMutations.UPDATE_CUSTOMER_WAITLIST_REQUESTED, waitListRequested); context.commit(storeMutations.UPDATE_CUSTOMER_WAITLIST_REQUESTED, waitListRequested);

View file

@ -354,6 +354,7 @@ describe("Mutations", () => {
emailAddress: "foo@bar.com", emailAddress: "foo@bar.com",
phoneNumber: "555-555-5555", phoneNumber: "555-555-5555",
isSmsOptIn: true, isSmsOptIn: true,
isSmsMarketingOptIn: false,
}; };
// Act // Act
@ -365,6 +366,24 @@ describe("Mutations", () => {
expect(state.order.customer.emailAddress).toEqual("foo@bar.com"); expect(state.order.customer.emailAddress).toEqual("foo@bar.com");
expect(state.order.customer.phoneNumber).toEqual("555-555-5555"); expect(state.order.customer.phoneNumber).toEqual("555-555-5555");
expect(state.order.customer.isSmsOptIn).toEqual(true); expect(state.order.customer.isSmsOptIn).toEqual(true);
expect(state.order.customer.isSmsMarketingOptIn).toEqual(false);
});
it("updateCustomerDetails, should preserve marketing sms consent when not provided", () => {
const storeState = state;
storeState.order.customer.isSmsOptIn = true;
storeState.order.customer.isSmsMarketingOptIn = true;
mutations.updateCustomerDetails(storeState, {
firstName: "foo",
lastName: "bar",
emailAddress: "foo@bar.com",
phoneNumber: "555-555-5555",
isSmsOptIn: false,
});
expect(state.order.customer.isSmsOptIn).toEqual(false);
expect(state.order.customer.isSmsMarketingOptIn).toEqual(true);
}); });
it("incrementSubmittedStateRevision, should increment submittedStateRevision", () => { it("incrementSubmittedStateRevision, should increment submittedStateRevision", () => {