diff --git a/src/assets/img/icons/icon-ablue-next.png b/src/assets/img/icons/icon-ablue-next.png new file mode 100644 index 00000000..ff8ec863 Binary files /dev/null and b/src/assets/img/icons/icon-ablue-next.png differ diff --git a/src/assets/img/icons/icon-ablue-previous.png b/src/assets/img/icons/icon-ablue-previous.png new file mode 100644 index 00000000..ebac34a2 Binary files /dev/null and b/src/assets/img/icons/icon-ablue-previous.png differ diff --git a/src/constants/error-messages.js b/src/constants/error-messages.js index e1d23731..71e7d515 100644 --- a/src/constants/error-messages.js +++ b/src/constants/error-messages.js @@ -52,13 +52,15 @@ const errorMessages = Object.freeze({ POLICYHOLDER_FIRST_NAME_REQUIRED: 'First name is required.', POLICYHOLDER_LAST_NAME_REQUIRED: 'Last name is required.', ACKNOWLEDGEMENT_REQUIRED: 'You must agree to the terms to continue', + NO_SELECTION_REQUIRED: 'Please make a selection to continue', YEAR_REQUIRED: 'Vehicle year is required.', MAKE_REQUIRED: 'Vehicle make is required.', MODEL_REQUIRED: 'Vehicle model is required.', STYLE_REQUIRED: 'Vehicle style is required.', MOBILE_LOCATION_REQUIRED: 'Please enter your service address', - DATE_REQUIRED: 'Please select a date' + DATE_REQUIRED: 'Please select a date', + TIME_REQUIRED: 'Please select an appointment time.' }); export default errorMessages; diff --git a/src/constants/provider-preference.js b/src/constants/provider-preference.js new file mode 100644 index 00000000..291aaf97 --- /dev/null +++ b/src/constants/provider-preference.js @@ -0,0 +1,6 @@ +const PROVIDER_PREFERENCE_OPTIONS = Object.freeze({ + SAFELITE: 'SafeliteOption', + TPA: 'TPAOption' +}); + +export default PROVIDER_PREFERENCE_OPTIONS; \ No newline at end of file diff --git a/src/digital-components/date-picker/date-picker.vue b/src/digital-components/date-picker/date-picker.vue index 954451f6..b5cd4b77 100644 --- a/src/digital-components/date-picker/date-picker.vue +++ b/src/digital-components/date-picker/date-picker.vue @@ -2,108 +2,128 @@
-
+
- Select a day and time + When would you like service? +
+ When would you like service? +
+
+ Your service will take approximately {{ appointmentEstimate }} +
-
- {{ month.monthLabel }} {{ month.yearNum?.toString() }} + class="appointment-date-picker-container" + :class="isMobileView ? 'mobile' : 'desktop'"> +
+
-
- = Available +
+ {{ headerDateString }}
-
-
@@ -111,24 +131,27 @@ - - diff --git a/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.spec.js b/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.spec.js index 5ddc7c30..31450a5b 100644 --- a/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.spec.js +++ b/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.spec.js @@ -38,16 +38,26 @@ describe('tpa-Recal-Modal.vue', () => { test('should show error if not acknowledged', () => { const { wrapper } = setupMocks(); wrapper.vm.acknowledged = false; + wrapper.vm.tpaRecalAnswer = 'TPAOption'; wrapper.vm.footerButtonClick(); - expect(wrapper.vm.showError).toBeTruthy(); + expect(wrapper.vm.showAcknowledgementError).toBeTruthy(); }); test('should not show error if acknowledged', () => { const { wrapper } = setupMocks(); wrapper.vm.acknowledged = true; + wrapper.vm.tpaRecalAnswer = 'TPAOption'; wrapper.vm.footerButtonClick(); - expect(wrapper.vm.showError).toBeFalsy(); + expect(wrapper.vm.showAcknowledgementError).toBeFalsy(); + }); + test('should show error if no answer selected', () => { + const { wrapper } = setupMocks(); + wrapper.vm.tpaRecalAnswer = ''; + wrapper.vm.tpaRecalAnswer = undefined; + wrapper.vm.footerButtonClick(); + + expect(wrapper.vm.showNoSelectionError).toBeTruthy(); }); }); diff --git a/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue b/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue index 9141b32e..2b182c9f 100644 --- a/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue +++ b/src/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue @@ -16,11 +16,23 @@ +
-

{{ ackError }}

+

{{ errorMessage }}

@@ -42,24 +54,31 @@ import modal from '@/digital-components/modal/modal.vue'; import tpaRecalToggle from '@/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle.vue'; import checkBox from '@/ux-components/checkbox/checkbox.vue'; +import buttonQuestion from '@/digital-components/button-question/button-question.vue'; import globalRules from '@/constants/global-rules'; +import PROVIDER_PREFERENCE_OPTIONS from '@/constants/provider-preference'; export default { name: 'content-group-modal', components: { modal, tpaRecalToggle, - checkBox + checkBox, + buttonQuestion }, props: { cmsWidgetName: String, - ackError: String + buttonCmsWidgetName: String, + ackError: String, + noSelectionError: String }, emits: ['buttonClick'], data() { return { acknowledged: false, - showError: false, + showAcknowledgementError: false, + showNoSelectionError: false, + tpaRecalAnswer: '', rules: { optionRequired: globalRules.OPTION_REQUIRED } @@ -81,13 +100,34 @@ export default { ModalCloseButtonText() { return this.getCmsContent(this.cmsWidgetName, 'FooterText'); }, + tpaRecalQuestionText() { + return this.getCmsContent(this.buttonCmsWidgetName, 'QuestionText'); + }, + tpaRecalAnswersFromCms() { + return this.getCmsContent(this.buttonCmsWidgetName, 'Answers'); + }, + showAcknowledgementCheckbox() { + return this.tpaRecalAnswer === PROVIDER_PREFERENCE_OPTIONS.TPA; + }, isButtonDisabled() { return !this.acknowledged; + }, + errorMessage() { + if (this.showNoSelectionError) { + return this.noSelectionError; + } else if (this.showAcknowledgementError) { + return this.ackError; + } + return ''; } }, watch: { acknowledged() { - this.showError = false; + this.showAcknowledgementError = false; + }, + tpaRecalAnswer() { + this.showNoSelectionError = false; + this.showAcknowledgementError = false; } }, methods: { @@ -96,12 +136,15 @@ export default { }, footerButtonClick() { - // check if acked, if not show error - if (this.acknowledged) { + if (this.tpaRecalAnswer && (!this.showAcknowledgementCheckbox || this.acknowledged )) { this.$refs[this.ModalName]?.closeModal(); - this.$emit('buttonClick'); + this.$emit('buttonClick', this.tpaRecalAnswer); + } else if (!this.tpaRecalAnswer) { + this.showNoSelectionError = true; + this.showAcknowledgementError = false; } else { - this.showError = true; + this.showAcknowledgementError = true; + this.showNoSelectionError = false; } } } @@ -130,29 +173,16 @@ export default { } } } -} - -.form-check { - .form-check-input { - &:checked { - + label { - p { - font-weight: 400 !important; - font-size: 1rem !important; - color: $gray-600 !important; - line-height: 1.5rem; - } + .safelite-or-tpa-question { + :deep(.question-text) { + span { + font-weight: 500; } } } - p { - font-weight: 400 !important; - font-size: 1rem !important; - color: $gray-600 !important; - line-height: 1.5rem; - } } + .form-test-error { p { font-weight: 500; diff --git a/src/layouts/schedule-page/schedule-page.spec.js b/src/layouts/schedule-page/schedule-page.spec.js index ad18458e..133654da 100644 --- a/src/layouts/schedule-page/schedule-page.spec.js +++ b/src/layouts/schedule-page/schedule-page.spec.js @@ -6,7 +6,6 @@ import { createTestingPinia } from '@pinia/testing'; import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { useMainStore } from '@/store/index.js'; -import { AppointmentTypeStrings } from '@/constants/schedule-constants'; // Mock fetchCmsContentForPage jest.mock('@/helpers/cms-content-helper', () => ({ @@ -214,7 +213,7 @@ describe('schedule-page.vue', () => { // Act const newShopTimeSlots = await wrapper.vm.getAvailableDatesMethod( '2023-01-01', - '2023-01-31' + '2023-01-15' ); // Assert @@ -236,7 +235,7 @@ describe('schedule-page.vue', () => { estimatedServiceMinutesMaximum: 120 }); }); - test('Should call API service in days of 34 or less when getAvailableDatesMethod is called with large date ranges', async () => { + test('Should call API service in days of 15 or less when getAvailableDatesMethod is called with large date ranges', async () => { // Arrange const { wrapper } = getShallowMountedComponent(); wrapper.vm.selectableDatesData = { @@ -264,7 +263,7 @@ describe('schedule-page.vue', () => { // 2023-01-01 --> 2023-02-05 // 2023-02-06 --> 2023-03-12 // 2023-03-13 --> 2023-03-31 - expect(store.getShopTimeSlots).toHaveBeenCalledTimes(3); + expect(store.getShopTimeSlots).toHaveBeenCalledTimes(6); }); }); describe('Rendering', () => { @@ -290,32 +289,16 @@ describe('schedule-page.vue', () => { // Assert expect(testValue).toStrictEqual('01234'); }); - test('getDisplayTextForMilitaryTime should return the correctly formatted string', () => { - // Arrange - const { wrapper } = getShallowMountedComponent(); - wrapper.vm.selectableDatesData = { - days: [] - }; - const timeInput1 = '15:00'; - const timeInput2 = '15:30'; - - // Act - const testOutput1 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput1); - const testOutput2 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput2); - const testOutput3 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput1, true); - const testOutput4 = wrapper.vm.getDisplayTextForMilitaryTime(timeInput2, true); - - // Assert - expect(testOutput1).toBe('3:00 PM'); - expect(testOutput2).toBe('3:30 PM'); - expect(testOutput3).toBe('3 PM'); - expect(testOutput4).toBe('3:30 PM'); - }); }); test('forwardButtonAction should call route method navigateWithoutSaving', async () => { // Arrange const { wrapper } = getShallowMountedComponent(); wrapper.vm.$router.navigate = jest.fn(() => ({})); + wrapper.vm.selectedTimeSlotInfo = { + timeSlot: { + routeCode: 'test-id' + } + }; // Act await wrapper.vm.forwardButtonAction(); diff --git a/src/layouts/schedule-page/schedule-page.vue b/src/layouts/schedule-page/schedule-page.vue index 38a5b1b1..aa08e79a 100644 --- a/src/layouts/schedule-page/schedule-page.vue +++ b/src/layouts/schedule-page/schedule-page.vue @@ -1,7 +1,6 @@