From 73d7a64d19a4918c9ac28f0b220e9cc8dae09dea Mon Sep 17 00:00:00 2001 From: Leah Schumann Date: Tue, 23 May 2023 09:01:04 -0400 Subject: [PATCH 01/10] Bryan pointed out I was diplaying the streetAddress where the city should be --- src/layouts/service-location/shop-question/shop-question.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/service-location/shop-question/shop-question.vue b/src/layouts/service-location/shop-question/shop-question.vue index fffb36c49..3183cbc9e 100644 --- a/src/layouts/service-location/shop-question/shop-question.vue +++ b/src/layouts/service-location/shop-question/shop-question.vue @@ -143,7 +143,7 @@ export default { const distanceInMiles = Math.round(shopProvider.distanceInMiles * 2) / 2; return { - buttonLabel: streetAddress, + buttonLabel: city, buttonLabelSubCopy: `${distanceInMiles} mi`, buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`, value: shopProvider.providerNumber, From b3813eedb150e1e71536efbc8bdec37ceec92af7 Mon Sep 17 00:00:00 2001 From: Chloe Herd Date: Tue, 23 May 2023 09:09:54 -0400 Subject: [PATCH 02/10] Revert CSR-1367 --- .../text-block/text-block.vue | 9 +- src/layouts/review/review.spec.js | 3 - src/layouts/review/review.vue | 102 ------------------ src/router/index.js | 6 -- 4 files changed, 2 insertions(+), 118 deletions(-) delete mode 100644 src/layouts/review/review.spec.js delete mode 100644 src/layouts/review/review.vue diff --git a/src/digital-components/text-block/text-block.vue b/src/digital-components/text-block/text-block.vue index 3a608f3a0..4f9c41599 100644 --- a/src/digital-components/text-block/text-block.vue +++ b/src/digital-components/text-block/text-block.vue @@ -1,7 +1,7 @@ @@ -11,11 +11,6 @@ export default { props: { customText: String, // used to allow the insert of token values into textblock justifyText: String, // left, right, center - margin: { - // bootstrap margin to apply to the block. - type: String, - default: "mt-2", - }, typeStyle: String, // h1-h6, body, small, label, caption (see Figma or Confluence documentation) fontWeight: String, // bold=500, default is 400 cmsWidgetName: String, diff --git a/src/layouts/review/review.spec.js b/src/layouts/review/review.spec.js deleted file mode 100644 index 674dc71f7..000000000 --- a/src/layouts/review/review.spec.js +++ /dev/null @@ -1,3 +0,0 @@ -describe("Review Page", () => { - test.todo("Add more tests as specific functionality is added."); -}); diff --git a/src/layouts/review/review.vue b/src/layouts/review/review.vue deleted file mode 100644 index 9bccb2014..000000000 --- a/src/layouts/review/review.vue +++ /dev/null @@ -1,102 +0,0 @@ - - - - - diff --git a/src/router/index.js b/src/router/index.js index 86c402187..3abfa058d 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -31,7 +31,6 @@ import { applicationConfig } from "../constants/application-config"; // Components import datePicker from "@/digital-components/date-picker/date-picker.vue"; import demoDatePicker from "@/layouts/demo-date-picker/demo-date-picker.vue"; -import review from "@/layouts/review/review"; const routes = [ { @@ -44,11 +43,6 @@ const routes = [ name: "date-picker", component: datePicker, }, - { - path: "/review", // This is a temporary route for testing. - name: "review", - component: review, - }, { path: "/", name: "root", From 0e167607ad0882c06d492f735d6fc5240c3a4750 Mon Sep 17 00:00:00 2001 From: Leah Schumann Date: Tue, 23 May 2023 09:13:31 -0400 Subject: [PATCH 03/10] Fixed unit tests --- .../shop-question/shop-question.spec.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/layouts/service-location/shop-question/shop-question.spec.js b/src/layouts/service-location/shop-question/shop-question.spec.js index c61fe2720..c4efdea91 100644 --- a/src/layouts/service-location/shop-question/shop-question.spec.js +++ b/src/layouts/service-location/shop-question/shop-question.spec.js @@ -179,19 +179,19 @@ describe("shop-question.vue", () => { expect(wrapper.vm.answers).toEqual([ { buttonBodyCopy: "4403 Executive Pkwy, Westerville, OH 43081", - buttonLabel: "4403 Executive Pkwy", + buttonLabel: "Westerville", buttonLabelSubCopy: "5 mi", value: "003335", }, { buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085", - buttonLabel: "760 Dearborn Park Ln", + buttonLabel: "Worthington", buttonLabelSubCopy: "10.5 mi", value: "001820", }, { buttonBodyCopy: "5015 N High St, Columbus, OH 43214", - buttonLabel: "5015 N High St", + buttonLabel: "Columbus", buttonLabelSubCopy: "11.5 mi", value: "003343", }, @@ -320,19 +320,19 @@ describe("shop-question.vue", () => { const displayedAnswers = [ { buttonBodyCopy: "4403 Executive Pkwy, Westerville, OH 43081", - buttonLabel: "4403 Executive Pkwy", + buttonLabel: "Westerville", buttonLabelSubCopy: "5 mi", value: "003335", }, { buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085", - buttonLabel: "760 Dearborn Park Ln", + buttonLabel: "Worthington", buttonLabelSubCopy: "10.5 mi", value: "001820", }, { buttonBodyCopy: "5015 N High St, Columbus, OH 43214", - buttonLabel: "5015 N High St", + buttonLabel: "Columbus", buttonLabelSubCopy: "11.5 mi", value: "003343", }, @@ -388,37 +388,37 @@ describe("shop-question.vue", () => { expect(wrapper.vm.answers).toEqual([ { buttonBodyCopy: "4403 Executive Pkwy, Westerville, OH 43081", - buttonLabel: "4403 Executive Pkwy", + buttonLabel: "Westerville", buttonLabelSubCopy: "5 mi", value: "003335", }, { buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085", - buttonLabel: "760 Dearborn Park Ln", + buttonLabel: "Worthington", buttonLabelSubCopy: "10.5 mi", value: "001820", }, { buttonBodyCopy: "5015 N High St, Columbus, OH 43214", - buttonLabel: "5015 N High St", + buttonLabel: "Columbus", buttonLabelSubCopy: "11.5 mi", value: "003343", }, { buttonBodyCopy: "1670 Harmon Ave, Columbus, OH 43223", - buttonLabel: "1670 Harmon Ave", + buttonLabel: "Columbus", buttonLabelSubCopy: "16 mi", value: "006747", }, { buttonBodyCopy: "3938 Powell Rd, Powell, OH 43065", - buttonLabel: "3938 Powell Rd", + buttonLabel: "Powell", buttonLabelSubCopy: "16.5 mi", value: "003341", }, { buttonBodyCopy: "4580 W Broad St, Columbus, OH 43228", - buttonLabel: "4580 W Broad St", + buttonLabel: "Columbus", buttonLabelSubCopy: "19.5 mi", value: "003342", }, From 5b6e68b8c52ded15dbb392f0a2b8bae09e54d4fe Mon Sep 17 00:00:00 2001 From: Adam Caouette Date: Tue, 23 May 2023 11:10:31 -0400 Subject: [PATCH 04/10] CSR-886: remove demo pages / code --- .../demo-date-picker/demo-date-picker.spec.js | 19 ---- .../demo-date-picker/demo-date-picker.vue | 90 ------------------- src/router/index.js | 14 --- 3 files changed, 123 deletions(-) delete mode 100644 src/layouts/demo-date-picker/demo-date-picker.spec.js delete mode 100644 src/layouts/demo-date-picker/demo-date-picker.vue diff --git a/src/layouts/demo-date-picker/demo-date-picker.spec.js b/src/layouts/demo-date-picker/demo-date-picker.spec.js deleted file mode 100644 index 9f7fa378b..000000000 --- a/src/layouts/demo-date-picker/demo-date-picker.spec.js +++ /dev/null @@ -1,19 +0,0 @@ -import demoDatePicker from "./demo-date-picker"; - -// Supporting Files -import { shallowMount } from "@vue/test-utils"; -import { getMountOptions } from "@/helpers/unit-test-helper.js"; - -describe("demo-date-picker.vue", () => { - test.only("test TK...", () => {}); -}); - -function setupMocks({ mountOptionsMockData = {} }) { - const mountOptions = getMountOptions({ - ...mountOptionsMockData, - }); - - const wrapper = shallowMount(demoDatePicker, mountOptions); - - return { wrapper }; -} diff --git a/src/layouts/demo-date-picker/demo-date-picker.vue b/src/layouts/demo-date-picker/demo-date-picker.vue deleted file mode 100644 index 20416b1d4..000000000 --- a/src/layouts/demo-date-picker/demo-date-picker.vue +++ /dev/null @@ -1,90 +0,0 @@ - - - - - diff --git a/src/router/index.js b/src/router/index.js index 3abfa058d..15ba52647 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -28,21 +28,7 @@ import analyticsMixin from "@/mixins/analytics-mixin"; import { experimentTriggers } from "../constants/experiments"; import { applicationConfig } from "../constants/application-config"; -// Components -import datePicker from "@/digital-components/date-picker/date-picker.vue"; -import demoDatePicker from "@/layouts/demo-date-picker/demo-date-picker.vue"; - const routes = [ - { - path: "/demo-date-picker", // This is a temporary route for testing. - name: "demo-date-picker", - component: demoDatePicker, - }, - { - path: "/date-picker", // This is a temporary route for testing. - name: "date-picker", - component: datePicker, - }, { path: "/", name: "root", From 98889512d6a856536e22e249f45fed147f754e34 Mon Sep 17 00:00:00 2001 From: Scott Kiener Date: Wed, 24 May 2023 10:37:43 -0400 Subject: [PATCH 05/10] CSR-1137 | More changes Added early-bird styling Added auto select if only one option Refactored early-bird names Moved constants to constant file Changed time-slot-modal-question v-model to reflect premium appointment Moved same-day dropoff content to new CMS widget --- .../cash-or-insurance-question.vue | 7 +- .../schedule/constants/schedule-constants.js | 11 ++ src/layouts/schedule/schedule.vue | 40 ++++--- .../time-slot-modal-question.vue | 103 ++++++++++-------- .../timeslot-modal-list-button.vue | 35 ++++-- 5 files changed, 126 insertions(+), 70 deletions(-) create mode 100644 src/layouts/schedule/constants/schedule-constants.js diff --git a/src/layouts/quote/cash-or-insurance-question/cash-or-insurance-question.vue b/src/layouts/quote/cash-or-insurance-question/cash-or-insurance-question.vue index 45fef683a..f5fec2255 100644 --- a/src/layouts/quote/cash-or-insurance-question/cash-or-insurance-question.vue +++ b/src/layouts/quote/cash-or-insurance-question/cash-or-insurance-question.vue @@ -5,7 +5,7 @@ :groupName="groupName" buttonTypeString="listButtonHorizontal" v-model="selectedValues" - :additionalButtonData="{ additionalButtonStyling: 'listButtonHorizontalStrong' }" + :additionalButtonData="additionalButtonData" isRequired /> @@ -27,6 +27,11 @@ export default { answersFromCms() { return this.getCmsContent(this.cmsWidgetName, "Answers"); }, + additionalButtonData() { + return { + additionalButtonStyling: 'listButtonHorizontalStrong' + }; + }, selectedValues: { get: function () { // Convert to CMS answer name from bool diff --git a/src/layouts/schedule/constants/schedule-constants.js b/src/layouts/schedule/constants/schedule-constants.js new file mode 100644 index 000000000..aae307675 --- /dev/null +++ b/src/layouts/schedule/constants/schedule-constants.js @@ -0,0 +1,11 @@ +const AppointmentTypeStrings = { + IN_SHOP: "Inshop", + MOBILE: "Mobile", + DROP_OFF: "Dropoff", +}; + +const PREMIUM_TIME_SLOT_ID_FLAG = "-premium"; + +const PREMIUM_FEE_PART_TYPE = "EARLY BIRD"; + +export { AppointmentTypeStrings, PREMIUM_TIME_SLOT_ID_FLAG, PREMIUM_FEE_PART_TYPE }; \ No newline at end of file diff --git a/src/layouts/schedule/schedule.vue b/src/layouts/schedule/schedule.vue index 60fb90b75..6c859c68b 100644 --- a/src/layouts/schedule/schedule.vue +++ b/src/layouts/schedule/schedule.vue @@ -39,13 +39,14 @@ @@ -49,15 +49,13 @@ import { defineRule, useField } from "vee-validate"; import { errorMessages } from "@/constants/error-messages"; import { required } from "@/helpers/validation-rules"; +// Constants +import { AppointmentTypeStrings, PREMIUM_TIME_SLOT_ID_FLAG, PREMIUM_FEE_PART_TYPE} from "../constants/schedule-constants"; + // Validation for the modal button defineRule("time-slot-required", required(errorMessages.OPTION_REQUIRED)); // Constants -const AppointmentTypeStrings = { - IN_SHOP: "Inshop", - MOBILE: "Mobile", - DROP_OFF: "Dropoff", -}; export default { name: "timeSlotModalQuestion", @@ -65,18 +63,20 @@ export default { modelValue: Object, cmsWidgetName: String, mobileCmsWidgetName: String, - earlyBirdCmsWidgetName: String, + mobilePremiumCmsWidgetName: String, dropoffCmsWidgetName: String, + sameDayDropOffCmsWidgetName: String, appointmentType: String, dateAndTimeSlotData: Object, - mobileEarlyBirdFee: Object, + premiumAppointmentFee: Object, estimatedServiceMinutesMinimum: Number, estimatedServiceMinutesMaximum: Number, validationRules: String, }, data() { return { - selectedTimeSlot: null, + selectedTimeSlotId: null, + isSelectedAppointmentPremium: null, timeslotModalListButton: timeslotModalListButton, }; }, @@ -89,42 +89,36 @@ export default { }, watch: { modelValue() { - this.selectedTimeSlot = this.modelValue; // Run component validation that is used at parent level - this.handleChange(this.modelValue); + this.handleChange(this.modelValue.id); }, - // dateAndTimeSlotData(newValue, oldValue) { - // const numberOfOptions = newValue?.timeSlots.length; - // console.log('running'); - // if (numberOfOptions === 1) { - // this.selectedTimeSlot = newValue.timeSlots[0].id; - // } - // } + dateAndTimeSlotData(newValue, oldValue) { + const numberOfOptions = newValue?.timeSlots.length; + if (numberOfOptions === 1) { + this.selectedTimeSlotId = newValue.timeSlots[0].id; + } + } }, computed: { supplementalInformationBlock() { let appointmentTypeCmsWidgetName; - let cmsFieldName = "BodyText"; if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) { return null; } else if (this.appointmentType === AppointmentTypeStrings.MOBILE) { appointmentTypeCmsWidgetName = - this.selectedTimeSlot === this.earlyBirdButtonText - ? this.earlyBirdCmsWidgetName + this.selectedTimeSlotId === this.premiumAppointmentButtonText + ? this.mobilePremiumCmsWidgetName : this.mobileCmsWidgetName; } else { - appointmentTypeCmsWidgetName = this.dropoffCmsWidgetName; - if (this.isSameDay) { - cmsFieldName = "BodyText2"; - } + appointmentTypeCmsWidgetName = this.isSameDay ? this.sameDayDropOffCmsWidgetName : this.dropoffCmsWidgetName; } - return this.getCmsContent(appointmentTypeCmsWidgetName, cmsFieldName); + return this.getCmsContent(appointmentTypeCmsWidgetName, "BodyText"); }, footerCloseButtonText() { return this.getCmsContent(this.cmsWidgetName, "FooterText"); }, - earlyBirdButtonText() { - return this.getCmsContent(this.earlyBirdCmsWidgetName, "HeaderText"); + premiumAppointmentButtonText() { + return this.getCmsContent(this.mobilePremiumCmsWidgetName, "HeaderText"); }, dropoffButtonText() { return this.getCmsContent(this.dropoffCmsWidgetName, "HeaderText"); @@ -136,14 +130,11 @@ export default { return this.getCmsContent(this.dropoffCmsWidgetName, "SubheaderText"); }, inshopDurationText() { - const inshopDurationTextWithoutTime = this.getCmsContent( - this.cmsWidgetName, - "SubheaderText" - ); + const inshopDurationTextWithoutTime = this.getCmsContent(this.cmsWidgetName, "SubheaderText"); const inshopDurationTime = this.getDisplayTextForDurationLength( - this.estimatedServiceMinutesMinimum, - this.estimatedServiceMinutesMaximum - ); + this.estimatedServiceMinutesMinimum, + this.estimatedServiceMinutesMaximum + ); return `${inshopDurationTextWithoutTime} ${inshopDurationTime}`; }, durationTextBlockCopy() { @@ -203,13 +194,18 @@ export default { } if (this.appointmentType === AppointmentTypeStrings.MOBILE) { - const offerPremium = this.dateAndTimeSlotData.timeSlots[0].offerPremium; - const hasEarlyBird = this.mobileEarlyBirdFee?.partType === "EARLY BIRD"; - if (offerPremium && hasEarlyBird) { + const isPremiumTimeSlot = this.dateAndTimeSlotData.timeSlots[0].offerPremium; + const hasPremiumPartAvailable = this.premiumAppointmentFee?.partType === PREMIUM_FEE_PART_TYPE; + if (isPremiumTimeSlot && hasPremiumPartAvailable) { + const formattedPrice = "+$" + this.getTotalLineItemPrice(this.premiumAppointmentFee).toFixed(2); availableTimeSlots.unshift({ - value: this.dateAndTimeSlotData.timeSlots[0].id + "-earlybird", - buttonLabel: this.earlyBirdButtonText, - buttonLabelSubCopy: this.getTotalLineItemPrice(this.mobileEarlyBirdFee), + // Unique value is required for each and the premium appoinment shares a timeslot ID + value: this.addPremiumFlagToInput(this.dateAndTimeSlotData.timeSlots[0].id), + buttonLabel: this.premiumAppointmentButtonText, + buttonLabelSubCopy: formattedPrice, + additionalButtonData: { + isPremiumAppointment: true + } }); } } @@ -222,12 +218,27 @@ export default { }, // fires any time the footer button is used, is fired before "onModalClosed" closeModal() { - this.$emit("update:modelValue", this.selectedTimeSlot); + if (this.selectedTimeSlotId.toString().includes(PREMIUM_TIME_SLOT_ID_FLAG)) { + this.selectedTimeSlotId = this.removePremiumFlagFromInput(this.selectedTimeSlotId); + this.isSelectedAppointmentPremium = true; + } else { + this.isSelectedAppointmentPremium = false; + } + const selectedTimeSlotData = { + id: this.selectedTimeSlotId, + isPremiumAppointment: this.isSelectedAppointmentPremium, + } + this.$emit("update:modelValue", selectedTimeSlotData); this.$refs["timeSlots"].closeModal(); }, // fires any time the modal is closed, AFTER "closeModal" fires if footer button is used onModalClosed() { - this.selectedTimeSlot = this.modelValue; + this.isSelectedAppointmentPremium = this.modelValue.isPremiumAppointment; + if (this.isSelectedAppointmentPremium) { + this.selectedTimeSlotId = this.addPremiumFlagToInput(this.modelValue.id); + } else { + this.selectedTimeSlotId = this.modelValue.id; + } this.$emit("time-slot-modal-closed"); }, // Expected input: "HH:MM:SS" @@ -252,6 +263,12 @@ export default { } return displayTextForDurationLength; }, + addPremiumFlagToInput(timeSlotId) { + return timeSlotId += PREMIUM_TIME_SLOT_ID_FLAG; + }, + removePremiumFlagFromInput(timeSlotId) { + return parseInt(timeSlotId.trim(PREMIUM_TIME_SLOT_ID_FLAG.length)); + }, }, components: { modal, diff --git a/src/layouts/schedule/time-slot-modal-question/timeslot-modal-list-button/timeslot-modal-list-button.vue b/src/layouts/schedule/time-slot-modal-question/timeslot-modal-list-button/timeslot-modal-list-button.vue index 60b2f9e81..8c71a9bb3 100644 --- a/src/layouts/schedule/time-slot-modal-question/timeslot-modal-list-button/timeslot-modal-list-button.vue +++ b/src/layouts/schedule/time-slot-modal-question/timeslot-modal-list-button/timeslot-modal-list-button.vue @@ -6,12 +6,13 @@
- + {{ buttonLabel }} - - + {{ formattedButtonLabelSubCopy }} + + {{ screenReaderOnlyText }} @@ -28,7 +29,7 @@ import baseInputButton from "@/digital-components/base-input-button/base-input-b import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin"; export default { - name: "timeslotMOdalListButton", + name: "timeslotModalListButton", mixins: [inputButtonWrapperMixin], props: { loaderColor: String, @@ -44,7 +45,7 @@ export default { }, computed: { formattedButtonLabelSubCopy() { - return this.buttonLabelSubCopy?.toFixed(2); + return this.buttonLabelSubCopy; }, }, methods: { @@ -85,6 +86,9 @@ export default { font-weight: 500; background: $blue-100; box-shadow: 0 0 0 1px $blue; + span.premium-appointment-price { + background: $green-200; + } } &:checked:focus + .list-button-content { box-shadow: 0 0 0 2.5px $blue; @@ -109,11 +113,22 @@ export default { width: 100%; outline: none; - span { - &.small { - font-size: 0.75rem; - color: $gray-550; - } + span.premium-appointment-price { + position: absolute; + background: $green-100; + border-radius: 4.5rem; + line-height: 1.25rem; + color: $green-700; + font-size: 0.75rem; + margin-left:4px; + padding: 2px 8px; + font-weight: 500; } } + +.position-relative { + position: relative; +} + + From 389b11ac2d59ac0cc0089d4f961bba91491498c6 Mon Sep 17 00:00:00 2001 From: Bryan Mauger Date: Wed, 24 May 2023 11:00:00 -0400 Subject: [PATCH 06/10] CSR-1420 fix misalignment of disclaimer copy Update code for text-block to not use flex. Use text-align accordingly. --- src/digital-components/text-block/text-block.vue | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/digital-components/text-block/text-block.vue b/src/digital-components/text-block/text-block.vue index 4f9c41599..2deb126e5 100644 --- a/src/digital-components/text-block/text-block.vue +++ b/src/digital-components/text-block/text-block.vue @@ -10,7 +10,7 @@ export default { name: "textBlock", props: { customText: String, // used to allow the insert of token values into textblock - justifyText: String, // left, right, center + justifyText: String, // right, center (left is default) typeStyle: String, // h1-h6, body, small, label, caption (see Figma or Confluence documentation) fontWeight: String, // bold=500, default is 400 cmsWidgetName: String, @@ -28,15 +28,11 @@ export default {