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",
PHONE_REQUIRED: "Please enter your phone number",
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",
MAKE_REQUIRED: "Please select your vehicle make",
MODEL_REQUIRED: "Please select your vehicle model",

View file

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

View file

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

View file

@ -17,6 +17,20 @@ describe("save-progress-popup-sms-consent-question", () => {
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 () => {
const wrapper = shallowMount(saveProgressPopupSmsConsentQuestion, {
propsData: {
@ -74,20 +88,41 @@ describe("save-progress-popup-sms-consent-question", () => {
const checkboxes = wrapper.findAllComponents({ name: "checkboxQuestion" });
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, {
propsData: {
modelValue: defaultSaveProgressSmsConsent(),
showConsentErrors: false,
showConsentManagement: false,
},
});
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" });
expect(checkboxes.at(0).props("hasError")).toBe(true);

View file

@ -9,19 +9,19 @@
:labelText="consentCopy.transactional"
:hasError="showConsentError"
:isDisabled="isDisabled" />
<!-- Temporarily hiding marketing consent checkbox. Will be re-added in a future release.
<checkboxQuestion
<checkboxQuestion
v-if="showConsentManagement"
v-model="marketingConsent"
checkboxName="saveProgressMarketingConsent"
:labelText="consentCopy.marketing"
:hasError="showConsentError"
:isDisabled="isDisabled" /> -->
: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 }}
{{ consentErrorMessage }}
</span>
</fieldset>
</template>
@ -37,11 +37,6 @@ import {
export default {
name: "save-progress-popup-sms-consent-question",
data() {
return {
errorMessages,
};
},
props: {
modelValue: {
type: Object,
@ -53,6 +48,7 @@ export default {
},
isDisabled: Boolean,
showConsentErrors: Boolean,
showConsentManagement: Boolean,
},
computed: {
transactionalConsent: {
@ -72,7 +68,15 @@ export default {
},
},
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: {

View file

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

View file

@ -20,13 +20,19 @@ describe("save-progress-sms-consent-helper", () => {
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(
hasSaveProgressSmsConsentSelection({ transactional: true, marketing: false })
hasSaveProgressSmsConsentSelection({ transactional: true, marketing: false }, true)
).toBe(true);
expect(
hasSaveProgressSmsConsentSelection({ transactional: false, marketing: true })
hasSaveProgressSmsConsentSelection({ transactional: false, marketing: true }, 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"
v-if="showSaveProgressPopup"
:showSaveProgressPopup="showSaveProgressPopup"
:showConsentManagement="showConsentManagement"
@save-progress-saved="updateSaveProgressAsSaved"
@close-save-progress-popup="closeSaveProgressPopup" />
</div>
@ -693,6 +694,12 @@ export default {
showRecalDisclaimer() {
return this.isRecalibrationOnOrder && this.isRecalPriceRemove;
},
showConsentManagement() {
return experimentMixin.methods.hasSettingEqualTo(
experimentSettings.SHOW_CONSENT_MANAGEMENT,
"true"
);
},
afterpayExtendedPayOptionThreshold() {
let thresholdAmount = experimentMixin.methods.getSettingValue(
experimentSettings.AFTERPAY_EXTENDED_PAY_OPTION_THRESHOLD