Merge pull request #3289 from Safelite/feature/CASH-2815-revert
Revert "Merge pull request #3270 from Safelite/feature/CASH-2815"
This commit is contained in:
commit
22f6052848
4 changed files with 0 additions and 341 deletions
|
|
@ -15,9 +15,6 @@ jest.mock("@/store", () => ({
|
||||||
lineItems: { glassParts: [] },
|
lineItems: { glassParts: [] },
|
||||||
policy: { isItac: false, isNoComp: false },
|
policy: { isItac: false, isNoComp: false },
|
||||||
},
|
},
|
||||||
applicationUser: {
|
|
||||||
experiments: [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,10 +48,6 @@
|
||||||
@address-clicked="onInshopAddressClicked(provider)" />
|
@address-clicked="onInshopAddressClicked(provider)" />
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
<waitlistQuestion
|
|
||||||
class="mt-5"
|
|
||||||
v-model="isWaitlistRequested"
|
|
||||||
:availableDates="availableDates" />
|
|
||||||
<navbar
|
<navbar
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
ref="navbar"
|
ref="navbar"
|
||||||
|
|
@ -72,7 +68,6 @@ import datePicker from "@/layouts/scheduling/date-picker/date-picker";
|
||||||
import mobileSchedulingCard from "@/layouts/scheduling/mobile-scheduling-card/mobile-scheduling-card";
|
import mobileSchedulingCard from "@/layouts/scheduling/mobile-scheduling-card/mobile-scheduling-card";
|
||||||
import inshopSchedulingCard from "@/layouts/scheduling/inshop-scheduling-card/inshop-scheduling-card";
|
import inshopSchedulingCard from "@/layouts/scheduling/inshop-scheduling-card/inshop-scheduling-card";
|
||||||
import interceptOverlay from "@/ux-components/intercept-overlay/intercept-overlay";
|
import interceptOverlay from "@/ux-components/intercept-overlay/intercept-overlay";
|
||||||
import waitlistQuestion from "@/layouts/scheduling/waitlist-question/waitlist-question";
|
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants";
|
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants";
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
|
|
@ -320,7 +315,6 @@ export default {
|
||||||
mobileProviderAndTimeSlot: null,
|
mobileProviderAndTimeSlot: null,
|
||||||
mobilePremiumAppointmentFee: null,
|
mobilePremiumAppointmentFee: null,
|
||||||
selectedScheduling: null,
|
selectedScheduling: null,
|
||||||
isWaitlistRequested: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -448,7 +442,6 @@ export default {
|
||||||
mobileSchedulingCard,
|
mobileSchedulingCard,
|
||||||
inshopSchedulingCard,
|
inshopSchedulingCard,
|
||||||
interceptOverlay,
|
interceptOverlay,
|
||||||
waitlistQuestion,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
||||||
import { mount } from "@vue/test-utils";
|
|
||||||
import waitlistQuestion from "./waitlist-question";
|
|
||||||
import store from "@/store";
|
|
||||||
import { experimentSettings } from "@/constants/experiments";
|
|
||||||
|
|
||||||
jest.mock("@/store", () => ({
|
|
||||||
getters: {
|
|
||||||
applicationUser: {
|
|
||||||
experiments: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const MOCK_CMS_CONTENT = {
|
|
||||||
WaitListLabelWidget: { Text: "Want to be notified sooner?" },
|
|
||||||
WaitListQuestionWidget: { QuestionText: "Add me to the waitlist" },
|
|
||||||
};
|
|
||||||
|
|
||||||
function dateStringOffsetFromToday(offsetDays) {
|
|
||||||
const d = new Date();
|
|
||||||
d.setDate(d.getDate() + offsetDays);
|
|
||||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(
|
|
||||||
d.getDate()
|
|
||||||
).padStart(2, "0")}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function enableWaitlistExperiment(thresholdDays = 0) {
|
|
||||||
store.getters.applicationUser.experiments = [
|
|
||||||
{
|
|
||||||
isActive: true,
|
|
||||||
settings: {
|
|
||||||
[experimentSettings.DISPLAY_WAITLIST]: "true",
|
|
||||||
[experimentSettings.WAITLIST_THRESHOLD_DAYS]: String(thresholdDays),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function mountComponent(props = {}) {
|
|
||||||
const cmsMixin = {
|
|
||||||
methods: {
|
|
||||||
getCmsContent: jest.fn((widgetName, fieldName) => {
|
|
||||||
return MOCK_CMS_CONTENT[widgetName]?.[fieldName] ?? "";
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return mount(waitlistQuestion, {
|
|
||||||
props: {
|
|
||||||
modelValue: false,
|
|
||||||
availableDates: [dateStringOffsetFromToday(10)],
|
|
||||||
...props,
|
|
||||||
},
|
|
||||||
global: {
|
|
||||||
mixins: [cmsMixin],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("waitlist-question.vue", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
enableWaitlistExperiment();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
store.getters.applicationUser.experiments = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renders the label and checkbox CMS content", () => {
|
|
||||||
const wrapper = mountComponent();
|
|
||||||
|
|
||||||
expect(wrapper.text()).toContain("Want to be notified sooner?");
|
|
||||||
expect(wrapper.text()).toContain("Add me to the waitlist");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("reflects the modelValue prop on the checkbox", () => {
|
|
||||||
const wrapper = mountComponent({ modelValue: true });
|
|
||||||
|
|
||||||
expect(wrapper.find("input[type='checkbox']").element.checked).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("emits update:modelValue with true when the checkbox is checked", async () => {
|
|
||||||
const wrapper = mountComponent({ modelValue: false });
|
|
||||||
|
|
||||||
const input = wrapper.find("input[type='checkbox']");
|
|
||||||
await input.setValue(true);
|
|
||||||
|
|
||||||
expect(wrapper.emitted("update:modelValue")).toEqual([[true]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("emits update:modelValue with false when the checkbox is unchecked", async () => {
|
|
||||||
const wrapper = mountComponent({ modelValue: true });
|
|
||||||
|
|
||||||
const input = wrapper.find("input[type='checkbox']");
|
|
||||||
await input.setValue(false);
|
|
||||||
|
|
||||||
expect(wrapper.emitted("update:modelValue")).toEqual([[false]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renders nothing when shouldDisplay is false", () => {
|
|
||||||
store.getters.applicationUser.experiments = [];
|
|
||||||
|
|
||||||
const wrapper = mountComponent();
|
|
||||||
|
|
||||||
expect(wrapper.find("input[type='checkbox']").exists()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("clicking the container", () => {
|
|
||||||
it("toggles localValue to true when clicking outside the checkbox", async () => {
|
|
||||||
const wrapper = mountComponent({ modelValue: false });
|
|
||||||
|
|
||||||
await wrapper.find(".waitlist-label").trigger("click");
|
|
||||||
|
|
||||||
expect(wrapper.emitted("update:modelValue")).toEqual([[true]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toggles localValue to false when clicking outside the checkbox", async () => {
|
|
||||||
const wrapper = mountComponent({ modelValue: true });
|
|
||||||
|
|
||||||
await wrapper.find(".waitlist-question").trigger("click");
|
|
||||||
|
|
||||||
expect(wrapper.emitted("update:modelValue")).toEqual([[false]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not toggle when the click target is the checkbox input itself", () => {
|
|
||||||
// jsdom doesn't reliably run a checkbox's native activation behavior
|
|
||||||
// (toggling + firing "change") for script-dispatched clicks, so this
|
|
||||||
// calls the handler directly with the real input element as the
|
|
||||||
// event target to verify the guard is skipped in that case.
|
|
||||||
const wrapper = mountComponent({ modelValue: false });
|
|
||||||
const inputElement = wrapper.find("input[type='checkbox']").element;
|
|
||||||
|
|
||||||
wrapper.vm.handleContainerClick({ target: inputElement });
|
|
||||||
|
|
||||||
expect(wrapper.emitted("update:modelValue")).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not toggle when the click lands inside the checkbox wrapper but not on the input", async () => {
|
|
||||||
const wrapper = mountComponent({ modelValue: false });
|
|
||||||
|
|
||||||
await wrapper.find(".ui-checkbox").trigger("click");
|
|
||||||
|
|
||||||
expect(wrapper.emitted("update:modelValue")).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("shouldDisplay", () => {
|
|
||||||
it("is false when the DISPLAY_WAITLIST experiment is off", () => {
|
|
||||||
store.getters.applicationUser.experiments = [
|
|
||||||
{
|
|
||||||
isActive: true,
|
|
||||||
settings: { [experimentSettings.WAITLIST_THRESHOLD_DAYS]: "3" },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const wrapper = mountComponent({ availableDates: [dateStringOffsetFromToday(10)] });
|
|
||||||
|
|
||||||
expect(wrapper.vm.shouldDisplay).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("is false when the earliest available date is within the threshold", () => {
|
|
||||||
enableWaitlistExperiment(3);
|
|
||||||
|
|
||||||
const wrapper = mountComponent({ availableDates: [dateStringOffsetFromToday(2)] });
|
|
||||||
|
|
||||||
expect(wrapper.vm.shouldDisplay).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("is true when the experiment is on and the earliest available date exceeds the threshold", () => {
|
|
||||||
enableWaitlistExperiment(3);
|
|
||||||
|
|
||||||
const wrapper = mountComponent({ availableDates: [dateStringOffsetFromToday(10)] });
|
|
||||||
|
|
||||||
expect(wrapper.vm.shouldDisplay).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("is false when there are no available dates", () => {
|
|
||||||
enableWaitlistExperiment(0);
|
|
||||||
|
|
||||||
const wrapper = mountComponent({ availableDates: [] });
|
|
||||||
|
|
||||||
expect(wrapper.vm.shouldDisplay).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
||||||
<template>
|
|
||||||
<template v-if="shouldDisplay">
|
|
||||||
<div
|
|
||||||
class="waitlist-question bg-light rounded"
|
|
||||||
v-bind="$attrs"
|
|
||||||
@click="handleContainerClick">
|
|
||||||
<textBlock
|
|
||||||
cmsWidgetName="WaitListLabelWidget"
|
|
||||||
typeStyle="medium"
|
|
||||||
fontWeight="600"
|
|
||||||
class="waitlist-label"
|
|
||||||
marginTopSizeOverride="0" />
|
|
||||||
<div ref="checkboxWrapper">
|
|
||||||
<checkboxQuestion
|
|
||||||
class="mt-3"
|
|
||||||
cmsWidgetName="WaitListQuestionWidget"
|
|
||||||
v-model="localValue" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="localValue" class="rounded waitlist-success">
|
|
||||||
<img :src="waitListSuccessImage" class="success-image" alt="" />
|
|
||||||
<span v-html="waitListSuccessText" class="success-text"></span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import textBlock from "@/digital-components/text-block/text-block";
|
|
||||||
import checkboxQuestion from "@/digital-components/checkbox-question/checkbox-question";
|
|
||||||
import experimentMixin from "@/mixins/experiment-mixin";
|
|
||||||
import { experimentSettings } from "@/constants/experiments";
|
|
||||||
import {
|
|
||||||
calcDaysBetweenDates,
|
|
||||||
convertDateToDateString,
|
|
||||||
} from "@/layouts/schedule/helpers/schedule-helper.js";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "waitlistQuestion",
|
|
||||||
mixins: [experimentMixin],
|
|
||||||
emits: ["update:modelValue"],
|
|
||||||
props: {
|
|
||||||
modelValue: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
availableDates: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
localValue: {
|
|
||||||
get() {
|
|
||||||
return this.modelValue;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.$emit("update:modelValue", value);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
waitListSuccessImage() {
|
|
||||||
return this.getCmsContent("WaitListSuccessWidget", "Image");
|
|
||||||
},
|
|
||||||
waitListSuccessText() {
|
|
||||||
return this.getCmsContent("WaitListSuccessWidget", "BodyText");
|
|
||||||
},
|
|
||||||
waitlistThresholdDays() {
|
|
||||||
return this.hasSetting(experimentSettings.WAITLIST_THRESHOLD_DAYS)
|
|
||||||
? parseInt(this.getSettingValue(experimentSettings.WAITLIST_THRESHOLD_DAYS), 10)
|
|
||||||
: 0;
|
|
||||||
},
|
|
||||||
daysUntilEarliestAvailableDate() {
|
|
||||||
const earliestDateString = this.availableDates?.[0];
|
|
||||||
if (!earliestDateString) return null;
|
|
||||||
|
|
||||||
const todayString = convertDateToDateString(new Date());
|
|
||||||
return calcDaysBetweenDates(todayString, earliestDateString);
|
|
||||||
},
|
|
||||||
shouldDisplay() {
|
|
||||||
return (
|
|
||||||
this.hasSettingEqualTo(experimentSettings.DISPLAY_WAITLIST, "true") &&
|
|
||||||
this.daysUntilEarliestAvailableDate !== null &&
|
|
||||||
this.waitlistThresholdDays < this.daysUntilEarliestAvailableDate
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleContainerClick(event) {
|
|
||||||
// The checkbox's own label/input already toggles localValue natively,
|
|
||||||
// so ignore clicks that originate inside it to avoid double-toggling.
|
|
||||||
// Checking against our own wrapper element (rather than an internal
|
|
||||||
// class name owned by checkboxQuestion) keeps this decoupled from
|
|
||||||
// that component's markup.
|
|
||||||
if (this.$refs.checkboxWrapper?.contains(event.target)) return;
|
|
||||||
this.localValue = !this.localValue;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
textBlock,
|
|
||||||
checkboxQuestion,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.waitlist-question {
|
|
||||||
box-shadow: 0 1px 5px 0 #00000033;
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
.waitlist-label {
|
|
||||||
font-family: UrbanistSemibold;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ui-checkbox) {
|
|
||||||
padding-left: 0px;
|
|
||||||
input {
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 1px 5px 0 #00000033;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.form-check-input) {
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.waitlist-success {
|
|
||||||
margin: 1rem 0 0;
|
|
||||||
background-color: #ecf5e9;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
border: 1px solid #0c7e47;
|
|
||||||
border-radius: 5px;
|
|
||||||
font-size: 1.125rem;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
.success-text {
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
:deep(p) {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.success-image {
|
|
||||||
margin-top: 4.5px;
|
|
||||||
width: 1rem;
|
|
||||||
height: 1rem;
|
|
||||||
color: #0c7e47;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Loading…
Reference in a new issue