Merge pull request #1047 from Safelite/feature/INSR-7749

INSR-7749: Bailout Page and Contact Confirmation Page
This commit is contained in:
katiekroell 2026-02-05 14:04:35 -05:00 committed by GitHub
commit 751807da9d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 77 additions and 40 deletions

View file

@ -65,7 +65,9 @@ const errorMessages = Object.freeze({
STYLE_REQUIRED: 'Vehicle style is required.', STYLE_REQUIRED: 'Vehicle style is required.',
MOBILE_LOCATION_REQUIRED: 'Please enter your service address', 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.' TIME_REQUIRED: 'Please select an appointment time.',
PRIMARY_PHONE_REQUIRED: 'Primary phone number is required.',
BAILOUT_EMAIL_ADDRESS_REQUIRED: 'Email address is required.'
}); });
export default errorMessages; export default errorMessages;

View file

@ -26,7 +26,9 @@ const globalRules = Object.freeze({
EXTENSION_FORMAT: 'extension-format', EXTENSION_FORMAT: 'extension-format',
ZIP_CODE_REQUIRED: 'zip-code-required', ZIP_CODE_REQUIRED: 'zip-code-required',
ZIP_CODE_SEARCH_FORMAT: 'zip-code-search-format', ZIP_CODE_SEARCH_FORMAT: 'zip-code-search-format',
OPTION_REQUIRED: 'option-required' OPTION_REQUIRED: 'option-required',
PRIMARY_PHONE_REQUIRED: 'primary-phone-required',
BAILOUT_EMAIL_ADDRESS_REQUIRED: 'bailout-email-address-required'
}); });
export default globalRules; export default globalRules;

View file

@ -10,7 +10,7 @@ function canBailoutNavigateBack() {
switch (code) { switch (code) {
case BailoutCode.VehicleNotFound: case BailoutCode.VehicleNotFound:
case BailoutCode.DoNotSeeMyShop: case BailoutCode.RequestCallback:
case BailoutCode.TPANotEnabled: case BailoutCode.TPANotEnabled:
return true; return true;

View file

@ -24,6 +24,7 @@ function defineGlobalNameRules() {
*/ */
function defineGlobalEmailRules() { function defineGlobalEmailRules() {
defineRule(globalRules.EMAIL_ADDRESS_REQUIRED, required(errorMessages.EMAIL_ADDRESS_REQUIRED)); defineRule(globalRules.EMAIL_ADDRESS_REQUIRED, required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule(globalRules.BAILOUT_EMAIL_ADDRESS_REQUIRED, required(errorMessages.BAILOUT_EMAIL_ADDRESS_REQUIRED));
defineRule( defineRule(
globalRules.EMAIL_ADDRESS_FORMAT, globalRules.EMAIL_ADDRESS_FORMAT,
regex( regex(
@ -71,6 +72,7 @@ function defineGlobalDateOfLossRules() {
*/ */
function defineGlobalPhoneNumberRules() { function defineGlobalPhoneNumberRules() {
defineRule(globalRules.PHONE_NUMBER_REQUIRED, required(errorMessages.PHONE_NUMBER_REQUIRED)); defineRule(globalRules.PHONE_NUMBER_REQUIRED, required(errorMessages.PHONE_NUMBER_REQUIRED));
defineRule(globalRules.PRIMARY_PHONE_REQUIRED, required(errorMessages.PRIMARY_PHONE_REQUIRED));
defineRule( defineRule(
globalRules.PHONE_NUMBER_FORMAT, globalRules.PHONE_NUMBER_FORMAT,
regex( regex(

View file

@ -12,13 +12,14 @@ Object {
"phoneNumber": "6145550909", "phoneNumber": "6145550909",
}, },
"rules": Object { "rules": Object {
"email": "email-required|email-address-format", "email": "bailout-email-address-required|email-address-format",
"firstName": "first-name-required", "firstName": "policyholder-first-name-required",
"lastName": "last-name-required", "lastName": "policyholder-last-name-required",
"phoneNumber": "phone-number-required|phone-number-format", "phoneNumber": "primary-phone-required|phone-number-format",
}, },
"widget": Object { "widget": Object {
"defaultSiteHeader": "SiteSubHeaderWidget", "defaultSiteHeader": "SiteSubHeaderWidget",
"disclaimerText": "DisclaimerWidget",
"noTpa": "ContentGroupNoTPAWidget", "noTpa": "ContentGroupNoTPAWidget",
"notSeeingPreferredShop": "ContentGroupNotSeeingPreferredShop", "notSeeingPreferredShop": "ContentGroupNotSeeingPreferredShop",
}, },

View file

@ -156,6 +156,16 @@ describe('Bailout page', () => {
// Assert // Assert
expect(siteFooter.exists()).toBeTruthy(); expect(siteFooter.exists()).toBeTruthy();
}); });
test('disclaimer text block', () => {
// Arrange
const wrapper = shallowMount(bailoutPage, getMountOptions());
// Act
const disclaimerText = wrapper.findComponent({ ref: 'disclaimerText' });
// Assert
expect(disclaimerText.exists()).toBeTruthy();
});
}); });
describe('computed', () => { describe('computed', () => {
describe('subHeaderCmsWidgetName', () => { describe('subHeaderCmsWidgetName', () => {

View file

@ -20,28 +20,34 @@
:subContentProperty="subContentProperty" :subContentProperty="subContentProperty"
class="sub-header-content mt-2 mb-5" class="sub-header-content mt-2 mb-5"
justification="left" /> justification="left" />
<textboxQuestion <div class="row">
ref="firstName" <div class="col">
v-model="bailoutPageModel.firstName" <textboxQuestion
class="mb-3" ref="firstName"
inputId="firstNameField" v-model="bailoutPageModel.firstName"
cmsWidgetName="FirstNameQuestion" class="input"
isRequired inputId="firstNameField"
disableAutoFill cmsWidgetName="FirstNameQuestion"
:validationRules="rules.firstName" /> isRequired
<textboxQuestion disableAutoFill
ref="lastName" :validationRules="rules.firstName" />
v-model="bailoutPageModel.lastName" </div>
class="mb-3" <div class="col">
inputId="lastNameField" <textboxQuestion
cmsWidgetName="LastNameQuestion" ref="lastName"
isRequired v-model="bailoutPageModel.lastName"
disableAutoFill class="input"
:validationRules="rules.lastName" /> inputId="lastNameField"
cmsWidgetName="LastNameQuestion"
isRequired
disableAutoFill
:validationRules="rules.lastName" />
</div>
</div>
<textboxQuestion <textboxQuestion
ref="phoneNumber" ref="phoneNumber"
v-model="bailoutPageModel.phoneNumber" v-model="bailoutPageModel.phoneNumber"
class="mb-3" class="input"
inputId="phoneNumberField" inputId="phoneNumberField"
cmsWidgetName="PhoneNumberQuestion" cmsWidgetName="PhoneNumberQuestion"
isRequired isRequired
@ -51,7 +57,7 @@
<textboxQuestion <textboxQuestion
ref="emailAddress" ref="emailAddress"
v-model="bailoutPageModel.email" v-model="bailoutPageModel.email"
class="mb-3" class="input"
inputId="emailAddressField" inputId="emailAddressField"
cmsWidgetName="EmailAddressQuestion" cmsWidgetName="EmailAddressQuestion"
isRequired isRequired
@ -65,6 +71,9 @@
:isBackButtonHidden="!canNavigateBack" :isBackButtonHidden="!canNavigateBack"
@backClicked="backButtonAction" @backClicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
<textBlock
ref="disclaimerText"
cmsWidgetName="DisclaimerWidget" />
</div> </div>
</div> </div>
</div> </div>
@ -77,6 +86,7 @@ import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue'; import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue'; import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue'; import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
// Supporting files // Supporting files
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
@ -99,7 +109,8 @@ export default {
siteFooter, siteFooter,
textboxQuestion, textboxQuestion,
// eslint-disable-next-line vue/no-reserved-component-names // eslint-disable-next-line vue/no-reserved-component-names
Form Form,
textBlock
}, },
mixins: [BaseFormMixin], mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
@ -130,13 +141,14 @@ export default {
widget: { widget: {
defaultSiteHeader: 'SiteSubHeaderWidget', defaultSiteHeader: 'SiteSubHeaderWidget',
noTpa: 'ContentGroupNoTPAWidget', noTpa: 'ContentGroupNoTPAWidget',
notSeeingPreferredShop: 'ContentGroupNotSeeingPreferredShop' notSeeingPreferredShop: 'ContentGroupNotSeeingPreferredShop',
disclaimerText: 'DisclaimerWidget'
}, },
rules: { rules: {
firstName: globalRules.FIRST_NAME_REQUIRED, firstName: globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED,
lastName: globalRules.LAST_NAME_REQUIRED, lastName: globalRules.POLICYHOLDER_LAST_NAME_REQUIRED,
phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`, phoneNumber: `${globalRules.PRIMARY_PHONE_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT}`,
email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}` email: `${globalRules.BAILOUT_EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`
} }
}; };
}, },
@ -221,9 +233,7 @@ export default {
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
@import '@/styles/bailout-common.scss';
.iss-heritage-container-width { .iss-heritage-container-width {
.bailout-page-container { .bailout-page-container {
position: relative; position: relative;
@ -232,4 +242,12 @@ export default {
padding-right: .9375rem; padding-right: .9375rem;
} }
} }
.input {
margin-bottom: 20px;
}
.footer-content-container {
margin: 30px 0 30px 0;
}
</style> </style>

View file

@ -24,6 +24,7 @@ import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import issPageValues from '@/router/router-constants/issPage-values.js'; import issPageValues from '@/router/router-constants/issPage-values.js';
import settleAllPromises from '@/helpers/layout-helper'; import settleAllPromises from '@/helpers/layout-helper';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import showIssLoadingModal from '@/helpers/loading-modal-helper';
export default { export default {
name: 'contact-confirmation', name: 'contact-confirmation',
@ -47,6 +48,7 @@ export default {
next((vm) => { next((vm) => {
vm.setCmsContent(resultMap.cmsContent); vm.setCmsContent(resultMap.cmsContent);
}); });
showIssLoadingModal(false);
}, },
setup() { setup() {
const mainStore = useMainStore(); const mainStore = useMainStore();

View file

@ -389,9 +389,9 @@ export default {
return getTpaProvidersResult?.data?.shopProviders ?? []; return getTpaProvidersResult?.data?.shopProviders ?? [];
}, },
doNotSeeMyShopLinkClick() { doNotSeeMyShopLinkClick() {
this.mainStore.setBailout(bailoutMessage.doNotSeeMyShop()); this.mainStore.setBailout(bailoutMessage.RequestCallback());
this.$router.navigate( this.$router.navigate(
this.navigationScenarios.CLICKED_DO_NOT_SEE_MY_SHOP_LINK, this.navigationScenarios.CLICKED_NEED_HELP,
this.$route this.$route
); );
}, },

View file

@ -73,7 +73,7 @@ const navigationScenarios = Object.freeze({
PRICING_LOOKUP_ERROR: 'PRICING_LOOKUP_ERROR', PRICING_LOOKUP_ERROR: 'PRICING_LOOKUP_ERROR',
// TPA Search // TPA Search
CLICKED_DO_NOT_SEE_MY_SHOP_LINK: 'CLICKED_DO_NOT_SEE_MY_SHOP_LINK', CLICKED_NEED_HELP: 'CLICKED_NEED_HELP',
CLICKED_FORWARD_WITH_SAFELITE_SHOP: 'CLICKED_FORWARD_WITH_SAFELITE_SHOP', CLICKED_FORWARD_WITH_SAFELITE_SHOP: 'CLICKED_FORWARD_WITH_SAFELITE_SHOP',
CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP: 'CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP', CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP: 'CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP',

View file

@ -744,7 +744,7 @@ const routingTable = () => [
destinationIssPageValue: issPageValues.TPA_SUBMIT destinationIssPageValue: issPageValues.TPA_SUBMIT
}, },
{ {
scenario: navigationScenarios.CLICKED_DO_NOT_SEE_MY_SHOP_LINK, scenario: navigationScenarios.CLICKED_NEED_HELP,
destinationIssPageValue: issPageValues.BAILOUT_PAGE destinationIssPageValue: issPageValues.BAILOUT_PAGE
} }
] ]