Rework TPA Recal Modal

Move things to constants
Add button question
Rework navigation now that it can change inside modal
Add error message
This commit is contained in:
scottkiener-at-safelite 2026-01-14 13:50:48 -05:00
parent a39e786eca
commit bfccc340a1
4 changed files with 109 additions and 61 deletions

View file

@ -52,6 +52,7 @@ const errorMessages = Object.freeze({
POLICYHOLDER_FIRST_NAME_REQUIRED: 'First name is required.', POLICYHOLDER_FIRST_NAME_REQUIRED: 'First name is required.',
POLICYHOLDER_LAST_NAME_REQUIRED: 'Last name is required.', POLICYHOLDER_LAST_NAME_REQUIRED: 'Last name is required.',
ACKNOWLEDGEMENT_REQUIRED: 'You must agree to the terms to continue', ACKNOWLEDGEMENT_REQUIRED: 'You must agree to the terms to continue',
NO_SELECTION_REQUIRED: 'Please select an option',
YEAR_REQUIRED: 'Vehicle year is required.', YEAR_REQUIRED: 'Vehicle year is required.',
MAKE_REQUIRED: 'Vehicle make is required.', MAKE_REQUIRED: 'Vehicle make is required.',

View file

@ -0,0 +1,6 @@
const PROVIDER_PREFERENCE_OPTIONS = Object.freeze({
SAFELITE: 'SafeliteOption',
TPA: 'TPAOption'
});
export default PROVIDER_PREFERENCE_OPTIONS;

View file

@ -23,7 +23,7 @@
class="full-width-button" class="full-width-button"
variant="navigation" variant="navigation"
buttonText="Schedule now" buttonText="Schedule now"
@clickEvent="forwardButtonAction(options.SAFELITE)" /> @clickEvent="scheduleWithSafelite" />
<div <div
class="mt-5 mb-5" class="mt-5 mb-5"
v-html="scheduleWithOtherText"></div> v-html="scheduleWithOtherText"></div>
@ -32,9 +32,9 @@
linkType="navigation" linkType="navigation"
text="Find another shop" text="Find another shop"
href="#" href="#"
@clickEvent="forwardButtonAction(options.TPA)" /> @clickEvent="findAnotherShopClicked" />
<siteFooter <siteFooter
:ref="componentRefs.SITE_FOOTER_REF_NAME" :ref="SITE_FOOTER_REF_NAME"
class="mt-6" class="mt-6"
cmsWidgetName="SiteFooterWidget" cmsWidgetName="SiteFooterWidget"
:isForwardButtonHidden="true" :isForwardButtonHidden="true"
@ -43,13 +43,15 @@
</div> </div>
</div> </div>
<steeringModal <steeringModal
:ref="componentRefs.STEERING_MODAL_REF_NAME" :ref="STEERING_MODAL_REF_NAME"
cmsWidgetName="StateSteeringModal" /> cmsWidgetName="StateSteeringModal" />
<tpaRecalModal <tpaRecalModal
:ref="componentRefs.TPA_RECAL_MODAL_REF_NAME" :ref="TPA_RECAL_MODAL_REF_NAME"
cmsWidgetName="TPARecalModal" cmsWidgetName="TPARecalModal"
buttonCmsWidgetName="TPARecalQuestion"
:ackError="ackError" :ackError="ackError"
@buttonClick="navigateWithTPAAck" /> :noSelectionError="noSelectionError"
@buttonClick="navigateWithTPARecalAnswer"/>
</Form> </Form>
</template> </template>
<script> <script>
@ -64,6 +66,7 @@ import buttonQuestion from '@/digital-components/button-question/button-question
import showIssLoadingModal from '@/helpers/loading-modal-helper'; import showIssLoadingModal from '@/helpers/loading-modal-helper';
import bailoutMessage from '@/constants/bailoutMessage'; import bailoutMessage from '@/constants/bailoutMessage';
import baseFormMixin from '@/mixins/base-form-mixin'; import baseFormMixin from '@/mixins/base-form-mixin';
import PROVIDER_PREFERENCE_OPTIONS from '@/constants/provider-preference';
// Import Component // Import Component
import { Form } from 'vee-validate'; import { Form } from 'vee-validate';
@ -75,7 +78,6 @@ import tpaRecalModal from '@/layouts/provider-preference/tpa-recal-modal/tpa-rec
import textLink from '@/ux-components/text-link/text-link.vue'; import textLink from '@/ux-components/text-link/text-link.vue';
import buttonMain from '@/ux-components/button-main/button-main.vue'; import buttonMain from '@/ux-components/button-main/button-main.vue';
const options = { SAFELITE: 'SafeliteOption', TPA: 'TPAOption' };
const STEERING_MODAL_REF_NAME = 'StateSteeringModal'; const STEERING_MODAL_REF_NAME = 'StateSteeringModal';
const TPA_RECAL_MODAL_REF_NAME = 'TPARecalModal'; const TPA_RECAL_MODAL_REF_NAME = 'TPARecalModal';
const SITE_FOOTER_REF_NAME = 'siteFooter'; const SITE_FOOTER_REF_NAME = 'siteFooter';
@ -115,29 +117,25 @@ export default {
}); });
}, },
data() { data() {
return {
providerPreferenceOptions: PROVIDER_PREFERENCE_OPTIONS,
STEERING_MODAL_REF_NAME,
TPA_RECAL_MODAL_REF_NAME,
SITE_FOOTER_REF_NAME
};
}, },
computed: { computed: {
ackError() { ackError() {
return errorMessages.ACKNOWLEDGEMENT_REQUIRED; return errorMessages.ACKNOWLEDGEMENT_REQUIRED;
}, },
noSelectionError() {
return errorMessages.NO_SELECTION_REQUIRED;
},
scheduleWithSafeliteText() { scheduleWithSafeliteText() {
return this.getCmsContent('ScheduleWithSafeliteText', 'BodyText'); return this.getCmsContent('ScheduleWithSafeliteText', 'BodyText');
}, },
scheduleWithOtherText() { scheduleWithOtherText() {
return this.getCmsContent('ScheduleWithOtherText', 'BodyText'); return this.getCmsContent('ScheduleWithOtherText', 'BodyText');
},
// Expose options for use in the template
options() {
return options;
},
// Expose component refs for use in the template
componentRefs() {
return {
STEERING_MODAL_REF_NAME,
TPA_RECAL_MODAL_REF_NAME,
SITE_FOOTER_REF_NAME
};
} }
}, },
mounted() { mounted() {
@ -164,39 +162,37 @@ export default {
showIssLoadingModal(true); showIssLoadingModal(true);
this.$router.navigate(scenario, this.$route); this.$router.navigate(scenario, this.$route);
}, },
navigateWithTPAAck() { navigateWithTPARecalAnswer(answer) {
this.navigateForward(this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED); if (answer === this.providerPreferenceOptions.TPA) {
}, this.scheduleWithTPA();
forwardButtonAction(selectedProvider) { } else {
let scenario = null; this.scheduleWithSafelite();
switch (selectedProvider) {
case options.SAFELITE:
this.mainStore.updateIsSafeliteProvider(true);
scenario =
this.navigationScenarios
.CLICKED_FORWARD_WITH_SAFELITE;
break;
case options.TPA:
this.mainStore.updateIsSafeliteProvider(false);
if (this.mainStore.issConfig.enableTPAFlow) {
if (this.mainStore.hasRecalibrationPart) {
this.$refs[TPA_RECAL_MODAL_REF_NAME].openModal();
return;
}
scenario =
this.navigationScenarios
.CLICKED_FORWARD_WITH_TPA_ENABLED;
} else {
this.mainStore.setBailout(bailoutMessage.TPANotEnabled());
scenario =
this.navigationScenarios
.CLICKED_FORWARD_WITH_TPA_DISABLED;
}
break;
default:
} }
},
scheduleWithSafelite() {
this.mainStore.updateIsSafeliteProvider(true);
const scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE;
this.navigateForward(scenario); this.navigateForward(scenario);
}, },
scheduleWithTPA() {
this.mainStore.updateIsSafeliteProvider(false);
const scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED;
this.navigateForward(scenario);
},
findAnotherShopClicked() {
if (this.mainStore.issConfig.enableTPAFlow) {
if (this.mainStore.hasRecalibrationPart) {
this.$refs[TPA_RECAL_MODAL_REF_NAME].openModal();
return;
} else {
this.scheduleWithTPA();
}
} else {
this.mainStore.setBailout(bailoutMessage.TPANotEnabled());
const scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_DISABLED;
this.navigateForward(scenario);
}
},
openStateSteeringModal() { openStateSteeringModal() {
this.$refs[STEERING_MODAL_REF_NAME].openModal(); this.$refs[STEERING_MODAL_REF_NAME].openModal();
} }

View file

@ -16,11 +16,25 @@
<tpaRecalToggle <tpaRecalToggle
class="mb-5" class="mb-5"
cmsWidgetName="TPARecalModalToggle" /> cmsWidgetName="TPARecalModalToggle" />
<buttonQuestion
ref="tpaRecalQuestion"
v-model="tpaRecalAnswer"
class="radioQuestion windshield-chip-count-question mb-4"
:cmsWidgetName="buttonCmsWidgetName"
:questionText="tpaRecalQuestionText"
:answers="tpaRecalAnswersFromCms"
groupName="tpaRecalQuestion"
buttonID="tpaRecalQuestion"
buttonTypeString="listButtonHorizontal"
isRequired
:validationRules="rules.selectionRequired">
</buttonQuestion>
<checkBox <checkBox
v-if="showAcknowledgementCheckbox"
ref="tpaAcknowledgement" ref="tpaAcknowledgement"
v-model="acknowledged" v-model="acknowledged"
class="mb-2" class="mb-2"
:class="showError && ' has-error'" :class="showAcknowledgementError && ' has-error'"
:validationRules="rules.optionRequired" :validationRules="rules.optionRequired"
checkboxName="tpaAcknowledgement" checkboxName="tpaAcknowledgement"
buttonID="tpaAcknowledgement" buttonID="tpaAcknowledgement"
@ -29,9 +43,9 @@
:screenReaderOnlyText="ModalSubBodyText" :screenReaderOnlyText="ModalSubBodyText"
isRequired /> isRequired />
<div <div
v-if="showError" v-if="showAcknowledgementError || showNoSelectionError"
class="row form-test-error mt-1"> class="row form-test-error mt-1">
<p>{{ ackError }}</p> <p>{{ errorMessage }}</p>
</div> </div>
</div> </div>
</div> </div>
@ -42,24 +56,31 @@
import modal from '@/digital-components/modal/modal.vue'; 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 tpaRecalToggle from '@/layouts/provider-preference/tpa-recal-modal/tpa-recal-toggle/tpa-recal-toggle.vue';
import checkBox from '@/ux-components/checkbox/checkbox.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 globalRules from '@/constants/global-rules';
import PROVIDER_PREFERENCE_OPTIONS from '@/constants/provider-preference';
export default { export default {
name: 'content-group-modal', name: 'content-group-modal',
components: { components: {
modal, modal,
tpaRecalToggle, tpaRecalToggle,
checkBox checkBox,
buttonQuestion
}, },
props: { props: {
cmsWidgetName: String, cmsWidgetName: String,
ackError: String buttonCmsWidgetName: String,
ackError: String,
noSelectionError: String
}, },
emits: ['buttonClick'], emits: ['buttonClick'],
data() { data() {
return { return {
acknowledged: false, acknowledged: false,
showError: false, showAcknowledgementError: false,
showNoSelectionError: false,
tpaRecalAnswer: '',
rules: { rules: {
optionRequired: globalRules.OPTION_REQUIRED optionRequired: globalRules.OPTION_REQUIRED
} }
@ -81,13 +102,34 @@ export default {
ModalCloseButtonText() { ModalCloseButtonText() {
return this.getCmsContent(this.cmsWidgetName, 'FooterText'); 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() { isButtonDisabled() {
return !this.acknowledged; return !this.acknowledged;
},
errorMessage() {
if (this.showNoSelectionError) {
return this.noSelectionError;
} else if (this.showAcknowledgementError) {
return this.ackError;
}
return '';
} }
}, },
watch: { watch: {
acknowledged() { acknowledged() {
this.showError = false; this.showAcknowledgementError = false;
},
tpaRecalAnswer() {
this.showNoSelectionError = false;
this.showAcknowledgementError = false;
} }
}, },
methods: { methods: {
@ -96,12 +138,15 @@ export default {
}, },
footerButtonClick() { footerButtonClick() {
// check if acked, if not show error if (this.tpaRecalAnswer && (!this.showAcknowledgementCheckbox || this.acknowledged )) {
if (this.acknowledged) {
this.$refs[this.ModalName]?.closeModal(); this.$refs[this.ModalName]?.closeModal();
this.$emit('buttonClick'); this.$emit('buttonClick', this.tpaRecalAnswer);
} else if (!this.tpaRecalAnswer) {
this.showNoSelectionError = true;
this.showAcknowledgementError = false;
} else { } else {
this.showError = true; this.showAcknowledgementError = true;
this.showNoSelectionError = false;
} }
} }
} }