Merge pull request #3248 from Safelite/feature/CASH-2934
CASH-2934: Add phone option and consent checks to quote page modal
This commit is contained in:
commit
e35704dce9
16 changed files with 1009 additions and 21 deletions
|
|
@ -32,6 +32,7 @@ const errorMessages = {
|
|||
DATE_REQUIRED: "Please select a date",
|
||||
PHONE_REQUIRED: "Please enter your phone number",
|
||||
PHONE_FORMAT: "Phone number must be 10 digits",
|
||||
SMS_CONSENT_REQUIRED: "Please select at least one consent option",
|
||||
YEAR_REQUIRED: "Please select your vehicle year",
|
||||
MAKE_REQUIRED: "Please select your vehicle make",
|
||||
MODEL_REQUIRED: "Please select your vehicle model",
|
||||
|
|
|
|||
|
|
@ -89,4 +89,15 @@ describe("checkbox-question.vue", () => {
|
|||
|
||||
expect(paragraph.text()).toEqual("screenreader text");
|
||||
});
|
||||
|
||||
it("Should prefer labelText prop over CMS content", () => {
|
||||
const wrapper = shallowMount(checkboxQuestion, {
|
||||
propsData: {
|
||||
labelText: "Hardcoded label",
|
||||
},
|
||||
mixins: [mockMixin],
|
||||
});
|
||||
|
||||
expect(wrapper.vm.checkboxLabelCopy).toBe("Hardcoded label");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
:validationRules="validationRules"
|
||||
:id="inputId"
|
||||
:tabindex="tabIndex"
|
||||
:disabled="isDisabled"
|
||||
:aria-required="isRequired" />
|
||||
<textBlock
|
||||
class="m-0"
|
||||
|
|
@ -34,7 +35,7 @@ export default {
|
|||
name: "checkboxQuestion",
|
||||
computed: {
|
||||
checkboxLabelCopy() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
|
||||
return this.labelText || this.getCmsContent(this.cmsWidgetName, "QuestionText");
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
|
|
@ -72,11 +73,13 @@ export default {
|
|||
customInputId: String,
|
||||
validationRules: String,
|
||||
cmsWidgetName: String,
|
||||
labelText: String,
|
||||
checkboxName: String,
|
||||
buttonID: String,
|
||||
tabIndex: Number,
|
||||
screenReaderOnlyText: String,
|
||||
isRequired: Boolean,
|
||||
isDisabled: Boolean,
|
||||
hasError: Boolean,
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
|
|
|
|||
|
|
@ -61,4 +61,24 @@ describe("phone-number-question.vue", () => {
|
|||
"outsideValidation|phone-number-format"
|
||||
);
|
||||
});
|
||||
|
||||
it("Should pass placeholderText through to textbox-question", async () => {
|
||||
const wrapper = shallowMount(phoneNumberQuestion, {
|
||||
propsData: {
|
||||
placeholderText: "",
|
||||
},
|
||||
});
|
||||
|
||||
const phoneNumber = wrapper.findComponent({ ref: "phoneNumber" });
|
||||
|
||||
expect(phoneNumber.props("placeholderText")).toBe("");
|
||||
});
|
||||
|
||||
it("Should default placeholderText to masked phone format", async () => {
|
||||
const wrapper = shallowMount(phoneNumberQuestion, {});
|
||||
|
||||
const phoneNumber = wrapper.findComponent({ ref: "phoneNumber" });
|
||||
|
||||
expect(phoneNumber.props("placeholderText")).toBe("###-###-####");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@
|
|||
:max-length="12"
|
||||
v-model="selectedValue"
|
||||
:mask="mask"
|
||||
placeholderText="###-###-####"
|
||||
:placeholderText="placeholderText"
|
||||
:isRequired="isRequired"
|
||||
:isDisabled="isDisabled"
|
||||
:validationRules="validationRulesForTextBoxQuestion"
|
||||
:cmsWidgetName="cmsWidgetName" />
|
||||
</div>
|
||||
|
|
@ -32,10 +33,15 @@ export default {
|
|||
props: {
|
||||
cmsWidgetName: String,
|
||||
isRequired: Boolean,
|
||||
isDisabled: Boolean,
|
||||
validationRules: String,
|
||||
hasError: Boolean,
|
||||
centerErrorMessage: Boolean,
|
||||
modelValue: String,
|
||||
placeholderText: {
|
||||
type: String,
|
||||
default: "###-###-####",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
questionAlignment="center"
|
||||
cornerStyle="rounded"
|
||||
:displayQuestionText="true"
|
||||
:isDisabled="isDisabled"
|
||||
isRequired
|
||||
@input="validateEmail"
|
||||
validationRules="email-address-required|email-address-format" />
|
||||
|
|
@ -37,6 +38,7 @@ export default {
|
|||
props: {
|
||||
modelValue: String,
|
||||
cmsWidgetName: String,
|
||||
isDisabled: Boolean,
|
||||
},
|
||||
computed: {
|
||||
value: {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,23 @@
|
|||
import { mount, shallowMount } from "@vue/test-utils";
|
||||
import { mount, flushPromises } from "@vue/test-utils";
|
||||
import saveProgressPopupQuestion from "./save-progress-popup-question";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||
|
||||
jest.mock("@/helpers/heritage-integration/order-helper.js", () => ({
|
||||
saveQuote: jest.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
jest.mock("@/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({
|
||||
copy: {
|
||||
transactional: "Sign me up for updates about my upcoming service.",
|
||||
marketing: "Sign me up for promotional and product offers.",
|
||||
},
|
||||
value: { transactional: false, marketing: false },
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock("@/digital-components/modal/modal", () => ({
|
||||
methods: {
|
||||
|
|
@ -15,7 +32,6 @@ describe("save-progress-popup-question ", () => {
|
|||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modelValue: "",
|
||||
modalWidgetName: "testModal",
|
||||
},
|
||||
});
|
||||
|
|
@ -27,16 +43,276 @@ describe("save-progress-popup-question ", () => {
|
|||
expect(wrapper.vm.modal).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("contact method tabs", () => {
|
||||
test("should default to the phone tab", () => {
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.vm.isPhoneTabSelected).toBe(true);
|
||||
});
|
||||
|
||||
test("should use tab labels from phone and email specific CMS widgets", () => {
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
},
|
||||
cmsContent: {
|
||||
SaveProgressPopupWidget_PhoneSpecific: { HeadlineText: "PHONE" },
|
||||
SaveProgressPopupWidget_EmailSpecific: { HeadlineText: "EMAIL" },
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.vm.contactTabs).toEqual([
|
||||
{ label: "PHONE", value: "PhoneAnswer" },
|
||||
{ label: "EMAIL", value: "EmailAnswer" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("should use disclaimer BodyText from the selected tab widget", async () => {
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
},
|
||||
cmsContent: {
|
||||
SaveProgressPopupWidget_PhoneSpecific: { BodyText: "Phone disclaimer" },
|
||||
SaveProgressPopupWidget_EmailSpecific: { BodyText: "Email disclaimer" },
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.vm.modalDisclaimerText).toBe("Phone disclaimer");
|
||||
|
||||
wrapper.vm.selectContactMethod("EmailAnswer");
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.modalDisclaimerText).toBe("Email disclaimer");
|
||||
});
|
||||
|
||||
test("should use phone question CMS widget on the phone tab", () => {
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.vm.phoneQuestionWidgetName).toBe("SaveProgressPopupPhoneQuestionWidget");
|
||||
});
|
||||
|
||||
test("should show email content when the email tab is selected", async () => {
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.selectContactMethod("EmailAnswer");
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.contactMethod).toBe("EmailAnswer");
|
||||
expect(wrapper.vm.isPhoneTabSelected).toBe(false);
|
||||
expect(wrapper.vm.userInput).toBe("");
|
||||
expect(wrapper.vm.emailQuestionWidgetName).toBe("SaveProgressPopupEmailQuestionWidget");
|
||||
});
|
||||
|
||||
test("should reset sms consent when switching tabs", async () => {
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.smsConsent = { transactional: true, marketing: true };
|
||||
wrapper.vm.showConsentErrors = true;
|
||||
wrapper.vm.selectContactMethod("EmailAnswer");
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.smsConsent).toEqual({ transactional: false, marketing: false });
|
||||
expect(wrapper.vm.showConsentErrors).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("validatePhoneAndSave", () => {
|
||||
test("should show consent errors when phone is valid but no consent is selected", async () => {
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.modal.validate = jest.fn().mockResolvedValue({ valid: true });
|
||||
const resetSpy = jest.spyOn(wrapper.vm, "resetPhoneSendButtonStyle");
|
||||
|
||||
await wrapper.vm.validatePhoneAndSave();
|
||||
|
||||
expect(wrapper.vm.showConsentErrors).toBe(true);
|
||||
expect(resetSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should reset the send button loader when phone validation fails", async () => {
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.modal.validate = jest.fn().mockResolvedValue({ valid: false });
|
||||
const resetSpy = jest.spyOn(wrapper.vm, "resetPhoneSendButtonStyle");
|
||||
|
||||
await wrapper.vm.validatePhoneAndSave();
|
||||
|
||||
expect(wrapper.vm.showConsentErrors).toBe(false);
|
||||
expect(resetSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should save when phone and consent are valid", async () => {
|
||||
const dispatchStoreAction = jest.fn().mockResolvedValue(undefined);
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
pageName: "quote",
|
||||
},
|
||||
});
|
||||
|
||||
await flushPromises();
|
||||
|
||||
wrapper.vm.dispatchStoreAction = dispatchStoreAction;
|
||||
wrapper.vm.userInput = "555-123-4567";
|
||||
wrapper.vm.smsConsent = { transactional: true, marketing: false };
|
||||
wrapper.vm.modal.validate = jest.fn().mockResolvedValue({ valid: true });
|
||||
const resetSpy = jest.spyOn(wrapper.vm, "resetPhoneSendButtonStyle");
|
||||
|
||||
await wrapper.vm.validatePhoneAndSave();
|
||||
|
||||
expect(wrapper.vm.showConsentErrors).toBe(false);
|
||||
expect(wrapper.vm.isProgressSaved).toBe(true);
|
||||
expect(resetSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("saveProgress", () => {
|
||||
test("should save phone number and sms consent when phone tab is selected", async () => {
|
||||
const dispatchStoreAction = jest.fn().mockResolvedValue(undefined);
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
pageName: "quote",
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.dispatchStoreAction = dispatchStoreAction;
|
||||
wrapper.vm.userInput = "555-123-4567";
|
||||
wrapper.vm.smsConsent = { transactional: true, marketing: false };
|
||||
|
||||
await wrapper.vm.saveProgress();
|
||||
|
||||
expect(dispatchStoreAction).toHaveBeenCalledWith(
|
||||
storeActions.SAVE_PHONE_NUMBER,
|
||||
"555-123-4567",
|
||||
false
|
||||
);
|
||||
expect(dispatchStoreAction).not.toHaveBeenCalledWith(
|
||||
storeActions.SAVE_EMAIL,
|
||||
expect.anything(),
|
||||
false
|
||||
);
|
||||
expect(dispatchStoreAction).toHaveBeenCalledWith(
|
||||
storeActions.SAVE_IS_SMS_OPT_IN,
|
||||
true,
|
||||
false
|
||||
);
|
||||
expect(saveQuote).toHaveBeenCalledWith({ pageNameToLog: "quote" });
|
||||
expect(wrapper.vm.isProgressSaved).toBe(true);
|
||||
expect(wrapper.vm.savedContactMethod).toBe("PhoneAnswer");
|
||||
});
|
||||
|
||||
test("should save email when email tab is selected", async () => {
|
||||
const dispatchStoreAction = jest.fn().mockResolvedValue(undefined);
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
pageName: "quote",
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.dispatchStoreAction = dispatchStoreAction;
|
||||
wrapper.vm.selectContactMethod("EmailAnswer");
|
||||
wrapper.vm.userInput = "test@example.com";
|
||||
|
||||
await wrapper.vm.saveProgress();
|
||||
|
||||
expect(dispatchStoreAction).toHaveBeenCalledWith(
|
||||
storeActions.SAVE_EMAIL,
|
||||
"test@example.com",
|
||||
false
|
||||
);
|
||||
expect(dispatchStoreAction).not.toHaveBeenCalledWith(
|
||||
storeActions.SAVE_PHONE_NUMBER,
|
||||
expect.anything(),
|
||||
false
|
||||
);
|
||||
expect(saveQuote).toHaveBeenCalledWith({ pageNameToLog: "quote" });
|
||||
expect(wrapper.vm.savedContactMethod).toBe("EmailAnswer");
|
||||
});
|
||||
|
||||
test("should not allow switching tabs after a successful phone save", async () => {
|
||||
const dispatchStoreAction = jest.fn().mockResolvedValue(undefined);
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
pageName: "quote",
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.dispatchStoreAction = dispatchStoreAction;
|
||||
wrapper.vm.userInput = "555-123-4567";
|
||||
wrapper.vm.smsConsent = { transactional: true, marketing: false };
|
||||
|
||||
await wrapper.vm.saveProgress();
|
||||
wrapper.vm.selectContactMethod("EmailAnswer");
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.contactMethod).toBe("PhoneAnswer");
|
||||
expect(wrapper.vm.isContactMethodTabDisabled("EmailAnswer")).toBe(true);
|
||||
expect(wrapper.vm.isContactMethodTabDisabled("PhoneAnswer")).toBe(false);
|
||||
});
|
||||
|
||||
test("should not allow switching tabs after a successful email save", async () => {
|
||||
const dispatchStoreAction = jest.fn().mockResolvedValue(undefined);
|
||||
const { wrapper } = setupMocks({
|
||||
props: {
|
||||
modalWidgetName: "SaveProgressPopupWidget",
|
||||
pageName: "quote",
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.dispatchStoreAction = dispatchStoreAction;
|
||||
wrapper.vm.selectContactMethod("EmailAnswer");
|
||||
wrapper.vm.userInput = "test@example.com";
|
||||
|
||||
await wrapper.vm.saveProgress();
|
||||
wrapper.vm.selectContactMethod("PhoneAnswer");
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.contactMethod).toBe("EmailAnswer");
|
||||
expect(wrapper.vm.isContactMethodTabDisabled("PhoneAnswer")).toBe(true);
|
||||
expect(wrapper.vm.isContactMethodTabDisabled("EmailAnswer")).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocks({ options, props }) {
|
||||
function setupMocks({ options, props, cmsContent = {} }) {
|
||||
const mountOptions = getMountOptions({
|
||||
...options,
|
||||
});
|
||||
|
||||
const mockBaseMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn(),
|
||||
getCmsContent: jest.fn(
|
||||
(widgetName, fieldName) => cmsContent[widgetName]?.[fieldName] ?? ""
|
||||
),
|
||||
dispatchStoreAction: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,12 +7,53 @@
|
|||
:onModalClosedCallback="onModalClosed"
|
||||
:footerButtonText="modalButtonText"
|
||||
:isFooterButtonPrimary="true"
|
||||
:isFooterButtonSuppressed="isPhoneTabSelected && !isProgressSaved"
|
||||
@footer-button-event="saveProgress">
|
||||
<p class="modal-body-inner">{{ modalBodyText }}</p>
|
||||
<fieldset class="save-progress-popup-question__tabs">
|
||||
<div class="save-progress-popup-question__tab-list" role="radiogroup">
|
||||
<label
|
||||
v-for="tab in contactTabs"
|
||||
:key="tab.value"
|
||||
class="save-progress-popup-question__tab"
|
||||
:class="{
|
||||
'save-progress-popup-question__tab--active':
|
||||
contactMethod === tab.value,
|
||||
'save-progress-popup-question__tab--disabled':
|
||||
isContactMethodTabDisabled(tab.value),
|
||||
}">
|
||||
<input
|
||||
type="radio"
|
||||
class="save-progress-popup-question__tab-input"
|
||||
name="saveProgressPopupContactMethod"
|
||||
:value="tab.value"
|
||||
:checked="contactMethod === tab.value"
|
||||
:disabled="isContactMethodTabDisabled(tab.value)"
|
||||
@change="selectContactMethod(tab.value)" />
|
||||
<span class="save-progress-popup-question__tab-label">{{ tab.label }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div v-if="isPhoneTabSelected" class="save-progress-popup-question__phone-fields">
|
||||
<phoneNumberQuestion
|
||||
v-model="userInput"
|
||||
:cmsWidgetName="phoneQuestionWidgetName"
|
||||
placeholderText=""
|
||||
:isDisabled="isProgressSaved"
|
||||
isRequired
|
||||
validationRules="phone-number-required" />
|
||||
<saveProgressPopupSmsConsentQuestion
|
||||
v-model="smsConsent"
|
||||
:consentCopy="smsConsentCopy"
|
||||
:isDisabled="isProgressSaved"
|
||||
:showConsentErrors="showConsentErrors" />
|
||||
</div>
|
||||
<saveProgressQuestion
|
||||
v-else
|
||||
ref="saveProgressQuestion"
|
||||
v-model="userInput"
|
||||
cmsWidgetName="SaveProgressPopupQuestionWidget"
|
||||
:cmsWidgetName="emailQuestionWidgetName"
|
||||
:isDisabled="isProgressSaved"
|
||||
class="save-progress-popup-question" />
|
||||
<template v-slot:modal-footer-slot>
|
||||
<buttonMain
|
||||
|
|
@ -23,6 +64,13 @@
|
|||
:suppressLoader="true"
|
||||
class="skip-button"
|
||||
@click-event="closeModal" />
|
||||
<modalButtonMain
|
||||
v-if="isPhoneTabSelected && !isProgressSaved"
|
||||
ref="phoneSendButton"
|
||||
:isPrimary="true"
|
||||
class="w-100 modal-footer-button"
|
||||
:buttonText="modalButtonText"
|
||||
@click-event="validatePhoneAndSave" />
|
||||
<p class="modal-disclaimer" v-html="modalDisclaimerText"></p>
|
||||
</template>
|
||||
<alert
|
||||
|
|
@ -36,11 +84,33 @@
|
|||
|
||||
<script>
|
||||
import saveProgressQuestion from "@/fmg-components/save-progress-modal-question/save-progress-question/save-progress-question";
|
||||
import saveProgressPopupSmsConsentQuestion from "./save-progress-popup-sms-consent-question";
|
||||
import phoneNumberQuestion from "@/digital-components/phone-number-question/phone-number-question";
|
||||
import modal from "@/digital-components/modal/modal";
|
||||
import { storeActions } from "@/constants/store-actions.js";
|
||||
import modalButtonMain from "@/digital-components/modal/ux-components/modal-button-main/modal-button-main";
|
||||
import buttonMain from "@/ux-components/button-main/button-main";
|
||||
import alert from "@/ux-components/alert/alert";
|
||||
import { saveQuote } from "@/helpers/heritage-integration/order-helper.js";
|
||||
import {
|
||||
saveProgressPopupContactToStore,
|
||||
saveProgressPopupContactMethods,
|
||||
} from "@/helpers/save-progress-popup-contact-helper";
|
||||
import {
|
||||
defaultSaveProgressSmsConsent,
|
||||
getSaveProgressSmsConsentFallbackCopy,
|
||||
getSaveProgressSmsConsentConfig,
|
||||
hasSaveProgressSmsConsentSelection,
|
||||
} from "@/helpers/save-progress-sms-consent/save-progress-sms-consent-helper";
|
||||
import { defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
|
||||
const PHONE_SPECIFIC_WIDGET = "SaveProgressPopupWidget_PhoneSpecific";
|
||||
const EMAIL_SPECIFIC_WIDGET = "SaveProgressPopupWidget_EmailSpecific";
|
||||
const PHONE_QUESTION_WIDGET = "SaveProgressPopupPhoneQuestionWidget";
|
||||
const EMAIL_QUESTION_WIDGET = "SaveProgressPopupEmailQuestionWidget";
|
||||
|
||||
defineRule("phone-number-required", required(errorMessages.PHONE_REQUIRED));
|
||||
|
||||
export default {
|
||||
name: "save-progress-popup-question",
|
||||
|
|
@ -48,15 +118,31 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
userInput: "",
|
||||
contactMethod: saveProgressPopupContactMethods.PHONE,
|
||||
smsConsent: defaultSaveProgressSmsConsent(),
|
||||
smsConsentCopy: getSaveProgressSmsConsentFallbackCopy(),
|
||||
isProgressSaved: false,
|
||||
savedContactMethod: null,
|
||||
showConsentErrors: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
watch: {
|
||||
smsConsent: {
|
||||
handler(consent) {
|
||||
if (hasSaveProgressSmsConsentSelection(consent)) {
|
||||
this.showConsentErrors = false;
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadSmsConsentConfig();
|
||||
|
||||
if (this.showSaveProgressPopup) this.modal.openModal();
|
||||
},
|
||||
emits: ["close-save-progress-popup", "save-progress"], // <--- should remove oodles of warnings in dev tools
|
||||
emits: ["close-save-progress-popup", "save-progress-saved"],
|
||||
props: {
|
||||
modelValue: Object,
|
||||
modalWidgetName: String,
|
||||
pageName: String,
|
||||
showSaveProgressPopup: Boolean,
|
||||
|
|
@ -77,7 +163,11 @@ export default {
|
|||
return this.getCmsContent(this.modalWidgetName, "FooterText");
|
||||
},
|
||||
modalDisclaimerText() {
|
||||
return this.getCmsContent(this.modalWidgetName, "FooterText2");
|
||||
const disclaimerWidgetName = this.isPhoneTabSelected
|
||||
? PHONE_SPECIFIC_WIDGET
|
||||
: EMAIL_SPECIFIC_WIDGET;
|
||||
|
||||
return this.getCmsContent(disclaimerWidgetName, "BodyText");
|
||||
},
|
||||
modalName() {
|
||||
return this.modalWidgetName;
|
||||
|
|
@ -85,23 +175,92 @@ export default {
|
|||
modal() {
|
||||
return this.$refs[this.modalName];
|
||||
},
|
||||
contactTabs() {
|
||||
return [
|
||||
{
|
||||
label: this.getCmsContent(PHONE_SPECIFIC_WIDGET, "HeadlineText") || "Phone",
|
||||
value: saveProgressPopupContactMethods.PHONE,
|
||||
},
|
||||
{
|
||||
label: this.getCmsContent(EMAIL_SPECIFIC_WIDGET, "HeadlineText") || "Email",
|
||||
value: saveProgressPopupContactMethods.EMAIL,
|
||||
},
|
||||
];
|
||||
},
|
||||
isPhoneTabSelected() {
|
||||
return this.contactMethod === saveProgressPopupContactMethods.PHONE;
|
||||
},
|
||||
phoneQuestionWidgetName() {
|
||||
return PHONE_QUESTION_WIDGET;
|
||||
},
|
||||
emailQuestionWidgetName() {
|
||||
return EMAIL_QUESTION_WIDGET;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async loadSmsConsentConfig() {
|
||||
const config = await getSaveProgressSmsConsentConfig();
|
||||
this.smsConsentCopy = config.copy;
|
||||
|
||||
if (!this.isProgressSaved) {
|
||||
this.smsConsent = config.value;
|
||||
}
|
||||
},
|
||||
selectContactMethod(contactMethod) {
|
||||
if (this.isProgressSaved || this.contactMethod === contactMethod) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.contactMethod = contactMethod;
|
||||
this.userInput = "";
|
||||
this.smsConsent = defaultSaveProgressSmsConsent();
|
||||
this.showConsentErrors = false;
|
||||
},
|
||||
isContactMethodTabDisabled(contactMethod) {
|
||||
return this.isProgressSaved && contactMethod !== this.savedContactMethod;
|
||||
},
|
||||
closeModal() {
|
||||
this.modal.closeModal();
|
||||
},
|
||||
onModalClosed() {
|
||||
// send call to close popup
|
||||
this.showConsentErrors = false;
|
||||
this.$emit("close-save-progress-popup");
|
||||
},
|
||||
async saveProgress() {
|
||||
// save email address to store
|
||||
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.userInput, false);
|
||||
async validatePhoneAndSave() {
|
||||
try {
|
||||
const validationResult = await this.modal.validate();
|
||||
|
||||
// send store call to send to new API (that triggers an email send)
|
||||
if (!validationResult.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasSaveProgressSmsConsentSelection(this.smsConsent)) {
|
||||
this.showConsentErrors = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.showConsentErrors = false;
|
||||
await this.saveProgress();
|
||||
} finally {
|
||||
this.resetPhoneSendButtonStyle();
|
||||
}
|
||||
},
|
||||
resetPhoneSendButtonStyle() {
|
||||
this.$refs.phoneSendButton?.resetButtonStyle();
|
||||
},
|
||||
async saveProgress() {
|
||||
await saveProgressPopupContactToStore(this.dispatchStoreAction, {
|
||||
contactMethod: this.contactMethod,
|
||||
userInput: this.userInput,
|
||||
smsConsent: this.smsConsent,
|
||||
pageName: this.pageName,
|
||||
});
|
||||
|
||||
// send store call to send to new API (that triggers an email/SMS send)
|
||||
await saveQuote({ pageNameToLog: this.pageName });
|
||||
|
||||
// hide save progress button; show success message alert
|
||||
this.savedContactMethod = this.contactMethod;
|
||||
this.isProgressSaved = true;
|
||||
|
||||
// communicate to parent the new status
|
||||
|
|
@ -111,8 +270,11 @@ export default {
|
|||
|
||||
components: {
|
||||
modal,
|
||||
modalButtonMain,
|
||||
buttonMain,
|
||||
saveProgressQuestion,
|
||||
phoneNumberQuestion,
|
||||
saveProgressPopupSmsConsentQuestion,
|
||||
alert,
|
||||
},
|
||||
};
|
||||
|
|
@ -227,8 +389,91 @@ export default {
|
|||
}
|
||||
.modal-body-inner {
|
||||
text-align: center;
|
||||
margin-bottom: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.save-progress-popup-question__tabs {
|
||||
border: 0;
|
||||
margin: 0 0 1rem 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.save-progress-popup-question__tab-list {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.save-progress-popup-question__tab {
|
||||
flex: 1 1 50%;
|
||||
display: grid;
|
||||
min-height: 3.25rem;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.save-progress-popup-question__tab-input {
|
||||
grid-area: 1 / 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
cursor: inherit;
|
||||
|
||||
&:focus-visible + .save-progress-popup-question__tab-label {
|
||||
outline: 2px solid $blue;
|
||||
outline-offset: 2px;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.save-progress-popup-question__tab-label {
|
||||
grid-area: 1 / 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 0.875rem 0.5rem;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.25rem;
|
||||
color: $gray-600;
|
||||
border-bottom: 3px solid transparent;
|
||||
transition:
|
||||
color 150ms linear,
|
||||
border-color 150ms linear;
|
||||
}
|
||||
|
||||
.save-progress-popup-question__tab--active .save-progress-popup-question__tab-label {
|
||||
color: $red;
|
||||
border-bottom-color: $red;
|
||||
}
|
||||
|
||||
.save-progress-popup-question__tab--disabled {
|
||||
cursor: not-allowed;
|
||||
|
||||
.save-progress-popup-question__tab-label {
|
||||
color: $gray-400;
|
||||
}
|
||||
}
|
||||
|
||||
.save-progress-popup-question__phone-fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
margin: 0 0 1.5rem 0;
|
||||
}
|
||||
|
||||
.phone-number-question {
|
||||
margin: 0;
|
||||
|
||||
label {
|
||||
text-align: left;
|
||||
font-weight: 900;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: 0 1.5rem;
|
||||
margin: 0 0 1.5rem 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import saveProgressPopupSmsConsentQuestion from "./save-progress-popup-sms-consent-question";
|
||||
import {
|
||||
defaultSaveProgressSmsConsent,
|
||||
getSaveProgressSmsConsentFallbackCopy,
|
||||
} from "@/helpers/save-progress-sms-consent/save-progress-sms-consent-helper";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
|
||||
describe("save-progress-popup-sms-consent-question", () => {
|
||||
it("should render two consent checkboxes with default copy", () => {
|
||||
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion);
|
||||
const fallbackCopy = getSaveProgressSmsConsentFallbackCopy();
|
||||
|
||||
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
|
||||
|
||||
expect(checkboxes).toHaveLength(2);
|
||||
expect(checkboxes.at(0).props("labelText")).toBe(fallbackCopy.transactional);
|
||||
expect(checkboxes.at(1).props("labelText")).toBe(fallbackCopy.marketing);
|
||||
});
|
||||
|
||||
it("should emit updated consent when a checkbox changes", async () => {
|
||||
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
|
||||
propsData: {
|
||||
modelValue: defaultSaveProgressSmsConsent(),
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.transactionalConsent = true;
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.emitted("update:modelValue")).toEqual([
|
||||
[{ transactional: true, marketing: false }],
|
||||
]);
|
||||
});
|
||||
|
||||
it("should accept API-ready consent copy via prop", () => {
|
||||
const apiCopy = {
|
||||
transactional: "API transactional copy",
|
||||
marketing: "API marketing copy",
|
||||
};
|
||||
|
||||
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
|
||||
propsData: {
|
||||
consentCopy: apiCopy,
|
||||
},
|
||||
});
|
||||
|
||||
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
|
||||
|
||||
expect(checkboxes.at(0).props("labelText")).toBe("API transactional copy");
|
||||
expect(checkboxes.at(1).props("labelText")).toBe("API marketing copy");
|
||||
});
|
||||
|
||||
it("should disable consent checkboxes when isDisabled is true", () => {
|
||||
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
|
||||
propsData: {
|
||||
isDisabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
|
||||
|
||||
expect(checkboxes.at(0).props("isDisabled")).toBe(true);
|
||||
expect(checkboxes.at(1).props("isDisabled")).toBe(true);
|
||||
expect(wrapper.find("fieldset").attributes("disabled")).toBe("");
|
||||
});
|
||||
|
||||
it("should not show consent errors before showConsentErrors is true", () => {
|
||||
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
|
||||
propsData: {
|
||||
modelValue: defaultSaveProgressSmsConsent(),
|
||||
showConsentErrors: false,
|
||||
},
|
||||
});
|
||||
|
||||
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
|
||||
|
||||
expect(checkboxes.at(0).props("hasError")).toBe(false);
|
||||
expect(checkboxes.at(1).props("hasError")).toBe(false);
|
||||
expect(wrapper.text()).not.toContain(errorMessages.SMS_CONSENT_REQUIRED);
|
||||
});
|
||||
|
||||
it("should show consent errors when showConsentErrors is true and nothing is selected", async () => {
|
||||
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
|
||||
propsData: {
|
||||
modelValue: defaultSaveProgressSmsConsent(),
|
||||
showConsentErrors: false,
|
||||
},
|
||||
});
|
||||
|
||||
await wrapper.setProps({ showConsentErrors: true });
|
||||
|
||||
expect(wrapper.text()).toContain(errorMessages.SMS_CONSENT_REQUIRED);
|
||||
|
||||
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
|
||||
expect(checkboxes.at(0).props("hasError")).toBe(true);
|
||||
expect(checkboxes.at(1).props("hasError")).toBe(true);
|
||||
});
|
||||
|
||||
it("should clear consent errors when a selection is made while showConsentErrors is true", async () => {
|
||||
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
|
||||
propsData: {
|
||||
modelValue: defaultSaveProgressSmsConsent(),
|
||||
showConsentErrors: true,
|
||||
},
|
||||
});
|
||||
|
||||
await wrapper.setProps({
|
||||
modelValue: { transactional: true, marketing: false },
|
||||
});
|
||||
|
||||
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
|
||||
expect(checkboxes.at(0).props("hasError")).toBe(false);
|
||||
expect(checkboxes.at(1).props("hasError")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
<template>
|
||||
<fieldset
|
||||
class="save-progress-popup-sms-consent"
|
||||
:class="{ 'has-error': showConsentError }"
|
||||
:disabled="isDisabled">
|
||||
<checkboxQuestion
|
||||
v-model="transactionalConsent"
|
||||
checkboxName="saveProgressTransactionalConsent"
|
||||
:labelText="consentCopy.transactional"
|
||||
:hasError="showConsentError"
|
||||
:isDisabled="isDisabled" />
|
||||
<checkboxQuestion
|
||||
v-model="marketingConsent"
|
||||
checkboxName="saveProgressMarketingConsent"
|
||||
:labelText="consentCopy.marketing"
|
||||
:hasError="showConsentError"
|
||||
:isDisabled="isDisabled" />
|
||||
<span
|
||||
v-if="showConsentError"
|
||||
class="save-progress-popup-sms-consent__error d-inline-flex small mt-1"
|
||||
role="alert"
|
||||
aria-live="polite">
|
||||
{{ errorMessages.SMS_CONSENT_REQUIRED }}
|
||||
</span>
|
||||
</fieldset>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import checkboxQuestion from "@/digital-components/checkbox-question/checkbox-question";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
import {
|
||||
defaultSaveProgressSmsConsent,
|
||||
getSaveProgressSmsConsentFallbackCopy,
|
||||
hasSaveProgressSmsConsentSelection,
|
||||
} from "@/helpers/save-progress-sms-consent/save-progress-sms-consent-helper";
|
||||
|
||||
export default {
|
||||
name: "save-progress-popup-sms-consent-question",
|
||||
data() {
|
||||
return {
|
||||
errorMessages,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: defaultSaveProgressSmsConsent,
|
||||
},
|
||||
consentCopy: {
|
||||
type: Object,
|
||||
default: getSaveProgressSmsConsentFallbackCopy,
|
||||
},
|
||||
isDisabled: Boolean,
|
||||
showConsentErrors: Boolean,
|
||||
},
|
||||
computed: {
|
||||
transactionalConsent: {
|
||||
get() {
|
||||
return this.modelValue.transactional;
|
||||
},
|
||||
set(value) {
|
||||
this.emitConsentUpdate({ transactional: value });
|
||||
},
|
||||
},
|
||||
marketingConsent: {
|
||||
get() {
|
||||
return this.modelValue.marketing;
|
||||
},
|
||||
set(value) {
|
||||
this.emitConsentUpdate({ marketing: value });
|
||||
},
|
||||
},
|
||||
showConsentError() {
|
||||
return this.showConsentErrors && !hasSaveProgressSmsConsentSelection(this.modelValue);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
emitConsentUpdate(partialConsent) {
|
||||
this.$emit("update:modelValue", {
|
||||
...this.modelValue,
|
||||
...partialConsent,
|
||||
});
|
||||
},
|
||||
},
|
||||
components: {
|
||||
checkboxQuestion,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.save-progress-popup-sms-consent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
&__error {
|
||||
color: $red;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
38
src/helpers/save-progress-popup-contact-helper.js
Normal file
38
src/helpers/save-progress-popup-contact-helper.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { storeActions } from "@/constants/store-actions";
|
||||
import store from "@/store";
|
||||
|
||||
export const saveProgressPopupContactMethods = {
|
||||
PHONE: "PhoneAnswer",
|
||||
EMAIL: "EmailAnswer",
|
||||
};
|
||||
|
||||
export function isPhoneContactMethod(contactMethod) {
|
||||
return contactMethod === saveProgressPopupContactMethods.PHONE;
|
||||
}
|
||||
|
||||
export async function saveProgressPopupContactToStore(
|
||||
dispatchStoreAction,
|
||||
{ contactMethod, userInput, smsConsent, pageName }
|
||||
) {
|
||||
if (isPhoneContactMethod(contactMethod)) {
|
||||
await dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, userInput, false);
|
||||
await dispatchStoreAction(storeActions.SAVE_IS_SMS_OPT_IN, smsConsent.transactional, false);
|
||||
|
||||
const existingPageData = store.getters.pageData(pageName) ?? {};
|
||||
await dispatchStoreAction(
|
||||
storeActions.SAVE_PAGE_DATA,
|
||||
{
|
||||
page: pageName,
|
||||
data: {
|
||||
...existingPageData,
|
||||
saveProgressSmsConsent: { ...smsConsent },
|
||||
},
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await dispatchStoreAction(storeActions.SAVE_EMAIL, userInput, false);
|
||||
}
|
||||
103
src/helpers/save-progress-popup-contact-helper.spec.js
Normal file
103
src/helpers/save-progress-popup-contact-helper.spec.js
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import { storeActions } from "@/constants/store-actions";
|
||||
import store from "@/store";
|
||||
import {
|
||||
isPhoneContactMethod,
|
||||
saveProgressPopupContactMethods,
|
||||
saveProgressPopupContactToStore,
|
||||
} from "./save-progress-popup-contact-helper";
|
||||
|
||||
jest.mock("@/store", () => ({
|
||||
getters: {
|
||||
pageData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe("save-progress-popup-contact-helper", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
store.getters.pageData.mockReturnValue({ servicePackageSelected: "premium" });
|
||||
});
|
||||
|
||||
describe("isPhoneContactMethod", () => {
|
||||
it("should return true for the phone contact method", () => {
|
||||
expect(isPhoneContactMethod(saveProgressPopupContactMethods.PHONE)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for the email contact method", () => {
|
||||
expect(isPhoneContactMethod(saveProgressPopupContactMethods.EMAIL)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("saveProgressPopupContactToStore", () => {
|
||||
it("should save phone number and persist sms consent on phone tab", async () => {
|
||||
const dispatchStoreAction = jest.fn().mockResolvedValue(undefined);
|
||||
const smsConsent = { transactional: true, marketing: false };
|
||||
|
||||
await saveProgressPopupContactToStore(dispatchStoreAction, {
|
||||
contactMethod: saveProgressPopupContactMethods.PHONE,
|
||||
userInput: "555-123-4567",
|
||||
smsConsent,
|
||||
pageName: "quote",
|
||||
});
|
||||
|
||||
expect(dispatchStoreAction).toHaveBeenCalledWith(
|
||||
storeActions.SAVE_PHONE_NUMBER,
|
||||
"555-123-4567",
|
||||
false
|
||||
);
|
||||
expect(dispatchStoreAction).not.toHaveBeenCalledWith(
|
||||
storeActions.SAVE_EMAIL,
|
||||
expect.anything(),
|
||||
false
|
||||
);
|
||||
expect(dispatchStoreAction).toHaveBeenCalledWith(
|
||||
storeActions.SAVE_IS_SMS_OPT_IN,
|
||||
true,
|
||||
false
|
||||
);
|
||||
expect(dispatchStoreAction).toHaveBeenCalledWith(
|
||||
storeActions.SAVE_PAGE_DATA,
|
||||
{
|
||||
page: "quote",
|
||||
data: {
|
||||
servicePackageSelected: "premium",
|
||||
saveProgressSmsConsent: smsConsent,
|
||||
},
|
||||
},
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it("should save email on email tab without updating phone or sms opt in", async () => {
|
||||
const dispatchStoreAction = jest.fn().mockResolvedValue(undefined);
|
||||
|
||||
await saveProgressPopupContactToStore(dispatchStoreAction, {
|
||||
contactMethod: saveProgressPopupContactMethods.EMAIL,
|
||||
userInput: "test@example.com",
|
||||
smsConsent: { transactional: false, marketing: false },
|
||||
pageName: "quote",
|
||||
});
|
||||
|
||||
expect(dispatchStoreAction).toHaveBeenCalledWith(
|
||||
storeActions.SAVE_EMAIL,
|
||||
"test@example.com",
|
||||
false
|
||||
);
|
||||
expect(dispatchStoreAction).not.toHaveBeenCalledWith(
|
||||
storeActions.SAVE_PHONE_NUMBER,
|
||||
expect.anything(),
|
||||
false
|
||||
);
|
||||
expect(dispatchStoreAction).not.toHaveBeenCalledWith(
|
||||
storeActions.SAVE_IS_SMS_OPT_IN,
|
||||
expect.anything(),
|
||||
false
|
||||
);
|
||||
expect(dispatchStoreAction).not.toHaveBeenCalledWith(
|
||||
storeActions.SAVE_PAGE_DATA,
|
||||
expect.anything(),
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
const SAVE_PROGRESS_SMS_CONSENT_FALLBACK_COPY = {
|
||||
transactional: "Sign me up for updates about my upcoming service.",
|
||||
marketing: "Sign me up for promotional and product offers.",
|
||||
};
|
||||
|
||||
export function defaultSaveProgressSmsConsent() {
|
||||
return {
|
||||
transactional: false,
|
||||
marketing: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function getSaveProgressSmsConsentFallbackCopy() {
|
||||
return { ...SAVE_PROGRESS_SMS_CONSENT_FALLBACK_COPY };
|
||||
}
|
||||
|
||||
export function hasSaveProgressSmsConsentSelection(consent) {
|
||||
return Boolean(consent?.transactional || consent?.marketing);
|
||||
}
|
||||
|
||||
export async function getSaveProgressSmsConsentConfig() {
|
||||
// Replace with Consent Management API lookup (CASH-1911).
|
||||
return {
|
||||
copy: getSaveProgressSmsConsentFallbackCopy(),
|
||||
value: defaultSaveProgressSmsConsent(),
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import {
|
||||
defaultSaveProgressSmsConsent,
|
||||
getSaveProgressSmsConsentFallbackCopy,
|
||||
getSaveProgressSmsConsentConfig,
|
||||
hasSaveProgressSmsConsentSelection,
|
||||
} from "./save-progress-sms-consent-helper";
|
||||
|
||||
describe("save-progress-sms-consent-helper", () => {
|
||||
describe("getSaveProgressSmsConsentConfig", () => {
|
||||
it("should return fallback copy and default consent values", async () => {
|
||||
const config = await getSaveProgressSmsConsentConfig();
|
||||
|
||||
expect(config.copy).toEqual(getSaveProgressSmsConsentFallbackCopy());
|
||||
expect(config.value).toEqual(defaultSaveProgressSmsConsent());
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasSaveProgressSmsConsentSelection", () => {
|
||||
it("should return false when no consent is selected", () => {
|
||||
expect(hasSaveProgressSmsConsentSelection(defaultSaveProgressSmsConsent())).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true when either consent option is selected", () => {
|
||||
expect(
|
||||
hasSaveProgressSmsConsentSelection({ transactional: true, marketing: false })
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasSaveProgressSmsConsentSelection({ transactional: false, marketing: true })
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -324,12 +324,15 @@ export default {
|
|||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
const emailFromStore = store.getters.order.customer.emailAddress;
|
||||
const phoneFromStore = store.getters.order.customer.phoneNumber;
|
||||
const isEmailInStoreOnPageLoad = emailFromStore?.length > 0;
|
||||
const isPhoneInStoreOnPageLoad = phoneFromStore?.length > 0;
|
||||
const hasSaveProgressContactInStore = isEmailInStoreOnPageLoad || isPhoneInStoreOnPageLoad;
|
||||
const isPopupSkipped =
|
||||
store.getters.pageData(routeData.QUOTE.name)?.saveProgressPopupSkipped === true;
|
||||
// "popup" is the automatic opening centered popup on load
|
||||
const showSaveProgressPopup = !(isEmailInStoreOnPageLoad || isPopupSkipped);
|
||||
const showSaveProgressModal = isEmailInStoreOnPageLoad ? false : true;
|
||||
const showSaveProgressPopup = !(hasSaveProgressContactInStore || isPopupSkipped);
|
||||
const showSaveProgressModal = !hasSaveProgressContactInStore;
|
||||
const shouldSkipToInsurance =
|
||||
getBoolFromString(
|
||||
experimentMixin.methods.getSettingValue(experimentSettings.SKIP_TO_INSURANCE)
|
||||
|
|
|
|||
|
|
@ -2579,7 +2579,8 @@ export const actions = {
|
|||
referralCorrelationId: order.referralCorrelationId,
|
||||
referralNumber: order.referralNumber?.toString(),
|
||||
referralSequenceNumber: order.referralSequenceNumber,
|
||||
emailAddress: order.customer.emailAddress,
|
||||
emailAddress: order.customer.emailAddress || undefined,
|
||||
phoneNumber: order.customer.phoneNumber || undefined,
|
||||
lastPage: pageNameToLog,
|
||||
isRepair: damage.isRepair,
|
||||
firstName: order.customer.firstName,
|
||||
|
|
|
|||
Loading…
Reference in a new issue