Merge pull request #3264 from Safelite/feature/CASH-3027

CASH-3027: Add consent management feature toggle
This commit is contained in:
Chris 2026-07-13 10:54:07 -04:00 committed by GitHub
commit e864350d4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 82 additions and 22 deletions

View file

@ -32,7 +32,8 @@ const errorMessages = {
DATE_REQUIRED: "Please select a date", DATE_REQUIRED: "Please select a date",
PHONE_REQUIRED: "Please enter your phone number", PHONE_REQUIRED: "Please enter your phone number",
PHONE_FORMAT: "Phone number must be 10 digits", PHONE_FORMAT: "Phone number must be 10 digits",
SMS_CONSENT_REQUIRED: "Please select checkbox to receive text messages", SMS_CONSENT_REQUIRED_1: "Please select checkbox to receive text messages",
SMS_CONSENT_REQUIRED_2: "Please select at least one consent option",
YEAR_REQUIRED: "Please select your vehicle year", YEAR_REQUIRED: "Please select your vehicle year",
MAKE_REQUIRED: "Please select your vehicle make", MAKE_REQUIRED: "Please select your vehicle make",
MODEL_REQUIRED: "Please select your vehicle model", MODEL_REQUIRED: "Please select your vehicle model",

View file

@ -58,6 +58,9 @@ const experimentSettings = {
TIER_ONE: "TierOne", TIER_ONE: "TierOne",
TIER_TWO: "TierTwo", TIER_TWO: "TierTwo",
TIER_THREE: "TierThree", TIER_THREE: "TierThree",
// Consent Management
SHOW_CONSENT_MANAGEMENT: "ShowConsentManagement",
}; };
const experimentTriggers = { const experimentTriggers = {

View file

@ -46,7 +46,8 @@
v-model="smsConsent" v-model="smsConsent"
:consentCopy="smsConsentCopy" :consentCopy="smsConsentCopy"
:isDisabled="isProgressSaved" :isDisabled="isProgressSaved"
:showConsentErrors="showConsentErrors" /> :showConsentErrors="showConsentErrors"
:showConsentManagement="showConsentManagement" />
</div> </div>
<saveProgressQuestion <saveProgressQuestion
v-else v-else
@ -129,7 +130,7 @@ export default {
watch: { watch: {
smsConsent: { smsConsent: {
handler(consent) { handler(consent) {
if (hasSaveProgressSmsConsentSelection(consent)) { if (hasSaveProgressSmsConsentSelection(consent, this.showConsentManagement)) {
this.showConsentErrors = false; this.showConsentErrors = false;
} }
}, },
@ -146,6 +147,7 @@ export default {
modalWidgetName: String, modalWidgetName: String,
pageName: String, pageName: String,
showSaveProgressPopup: Boolean, showSaveProgressPopup: Boolean,
showConsentManagement: Boolean,
}, },
computed: { computed: {
buttonText() { buttonText() {
@ -234,7 +236,9 @@ export default {
return; return;
} }
if (!hasSaveProgressSmsConsentSelection(this.smsConsent)) { if (
!hasSaveProgressSmsConsentSelection(this.smsConsent, this.showConsentManagement)
) {
this.showConsentErrors = true; this.showConsentErrors = true;
return; return;
} }

View file

@ -17,6 +17,20 @@ describe("save-progress-popup-sms-consent-question", () => {
expect(checkboxes.at(0).props("labelText")).toBe(fallbackCopy.transactional); expect(checkboxes.at(0).props("labelText")).toBe(fallbackCopy.transactional);
}); });
it("should render the marketing consent checkbox when consent management is enabled", () => {
const fallbackCopy = getSaveProgressSmsConsentFallbackCopy();
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
propsData: {
showConsentManagement: true,
},
});
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
expect(checkboxes).toHaveLength(2);
expect(checkboxes.at(1).props("labelText")).toBe(fallbackCopy.marketing);
});
it("should emit updated consent when a checkbox changes", async () => { it("should emit updated consent when a checkbox changes", async () => {
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, { const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
propsData: { propsData: {
@ -74,20 +88,41 @@ describe("save-progress-popup-sms-consent-question", () => {
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" }); const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
expect(checkboxes.at(0).props("hasError")).toBe(false); expect(checkboxes.at(0).props("hasError")).toBe(false);
expect(wrapper.text()).not.toContain(errorMessages.SMS_CONSENT_REQUIRED); expect(wrapper.text()).not.toContain(errorMessages.SMS_CONSENT_REQUIRED_1);
expect(wrapper.text()).not.toContain(errorMessages.SMS_CONSENT_REQUIRED_2);
}); });
it("should show consent errors when showConsentErrors is true and nothing is selected", async () => { it("should show the transactional consent error when consent management is disabled", async () => {
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, { const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
propsData: { propsData: {
modelValue: defaultSaveProgressSmsConsent(), modelValue: defaultSaveProgressSmsConsent(),
showConsentErrors: false, showConsentErrors: false,
showConsentManagement: false,
}, },
}); });
await wrapper.setProps({ showConsentErrors: true }); await wrapper.setProps({ showConsentErrors: true });
expect(wrapper.text()).toContain(errorMessages.SMS_CONSENT_REQUIRED); expect(wrapper.text()).toContain(errorMessages.SMS_CONSENT_REQUIRED_1);
expect(wrapper.text()).not.toContain(errorMessages.SMS_CONSENT_REQUIRED_2);
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
expect(checkboxes.at(0).props("hasError")).toBe(true);
});
it("should show the multi-consent error when consent management is enabled", async () => {
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
propsData: {
modelValue: defaultSaveProgressSmsConsent(),
showConsentErrors: false,
showConsentManagement: true,
},
});
await wrapper.setProps({ showConsentErrors: true });
expect(wrapper.text()).toContain(errorMessages.SMS_CONSENT_REQUIRED_2);
expect(wrapper.text()).not.toContain(errorMessages.SMS_CONSENT_REQUIRED_1);
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" }); const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
expect(checkboxes.at(0).props("hasError")).toBe(true); expect(checkboxes.at(0).props("hasError")).toBe(true);

View file

@ -9,19 +9,19 @@
:labelText="consentCopy.transactional" :labelText="consentCopy.transactional"
:hasError="showConsentError" :hasError="showConsentError"
:isDisabled="isDisabled" /> :isDisabled="isDisabled" />
<!-- Temporarily hiding marketing consent checkbox. Will be re-added in a future release. <checkboxQuestion
<checkboxQuestion v-if="showConsentManagement"
v-model="marketingConsent" v-model="marketingConsent"
checkboxName="saveProgressMarketingConsent" checkboxName="saveProgressMarketingConsent"
:labelText="consentCopy.marketing" :labelText="consentCopy.marketing"
:hasError="showConsentError" :hasError="showConsentError"
:isDisabled="isDisabled" /> --> :isDisabled="isDisabled" />
<span <span
v-if="showConsentError" v-if="showConsentError"
class="save-progress-popup-sms-consent__error d-inline-flex small mt-1" class="save-progress-popup-sms-consent__error d-inline-flex small mt-1"
role="alert" role="alert"
aria-live="polite"> aria-live="polite">
{{ errorMessages.SMS_CONSENT_REQUIRED }} {{ consentErrorMessage }}
</span> </span>
</fieldset> </fieldset>
</template> </template>
@ -37,11 +37,6 @@ import {
export default { export default {
name: "save-progress-popup-sms-consent-question", name: "save-progress-popup-sms-consent-question",
data() {
return {
errorMessages,
};
},
props: { props: {
modelValue: { modelValue: {
type: Object, type: Object,
@ -53,6 +48,7 @@ export default {
}, },
isDisabled: Boolean, isDisabled: Boolean,
showConsentErrors: Boolean, showConsentErrors: Boolean,
showConsentManagement: Boolean,
}, },
computed: { computed: {
transactionalConsent: { transactionalConsent: {
@ -72,7 +68,15 @@ export default {
}, },
}, },
showConsentError() { showConsentError() {
return this.showConsentErrors && !hasSaveProgressSmsConsentSelection(this.modelValue); return (
this.showConsentErrors &&
!hasSaveProgressSmsConsentSelection(this.modelValue, this.showConsentManagement)
);
},
consentErrorMessage() {
return this.showConsentManagement
? errorMessages.SMS_CONSENT_REQUIRED_2
: errorMessages.SMS_CONSENT_REQUIRED_1;
}, },
}, },
methods: { methods: {

View file

@ -14,8 +14,8 @@ export function getSaveProgressSmsConsentFallbackCopy() {
return { ...SAVE_PROGRESS_SMS_CONSENT_FALLBACK_COPY }; return { ...SAVE_PROGRESS_SMS_CONSENT_FALLBACK_COPY };
} }
export function hasSaveProgressSmsConsentSelection(consent) { export function hasSaveProgressSmsConsentSelection(consent, showConsentManagement = false) {
return Boolean(consent?.transactional || consent?.marketing); return Boolean(consent?.transactional || (showConsentManagement && consent?.marketing));
} }
export async function getSaveProgressSmsConsentConfig() { export async function getSaveProgressSmsConsentConfig() {

View file

@ -20,13 +20,19 @@ describe("save-progress-sms-consent-helper", () => {
expect(hasSaveProgressSmsConsentSelection(defaultSaveProgressSmsConsent())).toBe(false); expect(hasSaveProgressSmsConsentSelection(defaultSaveProgressSmsConsent())).toBe(false);
}); });
it("should return true when either consent option is selected", () => { it("should return true when either consent option is selected and consent management is enabled", () => {
expect( expect(
hasSaveProgressSmsConsentSelection({ transactional: true, marketing: false }) hasSaveProgressSmsConsentSelection({ transactional: true, marketing: false }, true)
).toBe(true); ).toBe(true);
expect( expect(
hasSaveProgressSmsConsentSelection({ transactional: false, marketing: true }) hasSaveProgressSmsConsentSelection({ transactional: false, marketing: true }, true)
).toBe(true); ).toBe(true);
}); });
it("should ignore marketing consent when consent management is disabled", () => {
expect(
hasSaveProgressSmsConsentSelection({ transactional: false, marketing: true }, false)
).toBe(false);
});
}); });
}); });

View file

@ -114,6 +114,7 @@
pageName="quote" pageName="quote"
v-if="showSaveProgressPopup" v-if="showSaveProgressPopup"
:showSaveProgressPopup="showSaveProgressPopup" :showSaveProgressPopup="showSaveProgressPopup"
:showConsentManagement="showConsentManagement"
@save-progress-saved="updateSaveProgressAsSaved" @save-progress-saved="updateSaveProgressAsSaved"
@close-save-progress-popup="closeSaveProgressPopup" /> @close-save-progress-popup="closeSaveProgressPopup" />
</div> </div>
@ -693,6 +694,12 @@ export default {
showRecalDisclaimer() { showRecalDisclaimer() {
return this.isRecalibrationOnOrder && this.isRecalPriceRemove; return this.isRecalibrationOnOrder && this.isRecalPriceRemove;
}, },
showConsentManagement() {
return experimentMixin.methods.hasSettingEqualTo(
experimentSettings.SHOW_CONSENT_MANAGEMENT,
"true"
);
},
afterpayExtendedPayOptionThreshold() { afterpayExtendedPayOptionThreshold() {
let thresholdAmount = experimentMixin.methods.getSettingValue( let thresholdAmount = experimentMixin.methods.getSettingValue(
experimentSettings.AFTERPAY_EXTENDED_PAY_OPTION_THRESHOLD experimentSettings.AFTERPAY_EXTENDED_PAY_OPTION_THRESHOLD