Merge pull request #392 from Safelite/feature/richardson/SSR-524

Bailout Page front end
This commit is contained in:
brich1212safe 2023-08-03 15:52:15 -04:00 committed by GitHub
commit dfbbd714b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 953 additions and 785 deletions

View file

@ -21,18 +21,21 @@ const errorMessages = {
SERVICE_ZIP_REQUIRED: 'Please enter your service ZIP', SERVICE_ZIP_REQUIRED: 'Please enter your service ZIP',
SERVICE_ZIP_FORMAT: 'Please enter a valid service ZIP', SERVICE_ZIP_FORMAT: 'Please enter a valid service ZIP',
VIN_REQUIRED: 'Please enter your VIN', VIN_REQUIRED: 'Please enter your VIN',
VIN_FORMAT: 'Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q', VIN_FORMAT:
'Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q',
OPTION_REQUIRED: 'Please select an option', OPTION_REQUIRED: 'Please select an option',
VEHICLE_REQUIRED: 'Please select a vehicle', VEHICLE_REQUIRED: 'Please select a vehicle',
POLICY_NUMBER_REQUIRED: 'Please enter your policy number', POLICY_NUMBER_REQUIRED: 'Please enter your policy number',
PHONE_NUMBER_REQUIRED: 'Please enter phone number', PHONE_NUMBER_REQUIRED: 'Please enter phone number',
PHONE_NUMBER_FORMAT: 'Please enter your phone number. The format must be ###-###-####', PHONE_NUMBER_FORMAT: 'Please enter your phone number. The format must be ###-###-####',
PHONE_NUMBER_FORMAT_SHORT: 'Please enter a valid phone number',
POLICY_ZIP_REQUIRED: 'Please enter your policy ZIP', POLICY_ZIP_REQUIRED: 'Please enter your policy ZIP',
POLICY_ZIP_FORMAT: 'Please enter a valid ZIP', POLICY_ZIP_FORMAT: 'Please enter a valid ZIP',
LOSS_CAUSE_REQUIRED: 'Please enter loss cause', LOSS_CAUSE_REQUIRED: 'Please enter loss cause',
LOSS_CITY_REQUIRED: 'Please enter a city', LOSS_CITY_REQUIRED: 'Please enter a city',
LOSS_STATE_REQUIRED: 'Please select an option', LOSS_STATE_REQUIRED: 'Please select an option',
LOSS_DATE_REQUIRED: 'Please select a date. Format must be MM/DD/YYYY and the date must be not in the future', LOSS_DATE_REQUIRED:
'Please select a date. Format must be MM/DD/YYYY and the date must be not in the future',
DAMAGE_OPTION_REQUIRED: 'Please select an option', DAMAGE_OPTION_REQUIRED: 'Please select an option',
POLICYHOLDER_FIRST_NAME_REQUIRED: 'Please enter the policyholder first name', POLICYHOLDER_FIRST_NAME_REQUIRED: 'Please enter the policyholder first name',
@ -43,7 +46,6 @@ const errorMessages = {
MAKE_REQUIRED: 'Please select your vehicle make', MAKE_REQUIRED: 'Please select your vehicle make',
MODEL_REQUIRED: 'Please select your vehicle model', MODEL_REQUIRED: 'Please select your vehicle model',
STYLE_REQUIRED: 'Please select your vehicle style' STYLE_REQUIRED: 'Please select your vehicle style'
}; };
export { errorMessages }; export { errorMessages };

View file

@ -1,8 +1,8 @@
/** /**
* @file global-rules.js * @file global-rules.js
* @author MB * @author MB
* @copyright Safelite * @copyright Safelite
*/ */
/** /**
* @summary Contains all the globally defined rules. * @summary Contains all the globally defined rules.
@ -12,10 +12,11 @@ const globalRules = {
POLICYHOLDER_LAST_NAME_REQUIRED: 'policyholder-last-name-required', POLICYHOLDER_LAST_NAME_REQUIRED: 'policyholder-last-name-required',
FIRST_NAME_REQUIRED: 'first-name-required', FIRST_NAME_REQUIRED: 'first-name-required',
LAST_NAME_REQUIRED: 'last-name-required', LAST_NAME_REQUIRED: 'last-name-required',
PHONE_NUMBER_REQUIRED: 'phone-number-required',
EMAIL_ADDRESS_REQUIRED: 'email-required', EMAIL_ADDRESS_REQUIRED: 'email-required',
EMAIL_ADDRESS_FORMAT: 'email-address-format', EMAIL_ADDRESS_FORMAT: 'email-address-format',
PHONE_NUMBER_REQUIRED: 'phone-number-required',
PHONE_NUMBER_FORMAT: 'phone-number-format', PHONE_NUMBER_FORMAT: 'phone-number-format',
PHONE_NUMBER_FORMAT_SHORT: 'phone-number-format-short',
OPTION_REQUIRED: 'option-required' OPTION_REQUIRED: 'option-required'
}; };

View file

@ -9,10 +9,14 @@ import { required, regex } from '@/helpers/validation-rules';
function defineGlobalNameRules() { function defineGlobalNameRules() {
defineRule(globalRules.FIRST_NAME_REQUIRED, required(errorMessages.FIRST_NAME_REQUIRED)); defineRule(globalRules.FIRST_NAME_REQUIRED, required(errorMessages.FIRST_NAME_REQUIRED));
defineRule(globalRules.LAST_NAME_REQUIRED, required(errorMessages.LAST_NAME_REQUIRED)); defineRule(globalRules.LAST_NAME_REQUIRED, required(errorMessages.LAST_NAME_REQUIRED));
defineRule(globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED, defineRule(
required(errorMessages.POLICYHOLDER_FIRST_NAME_REQUIRED)); globalRules.POLICYHOLDER_FIRST_NAME_REQUIRED,
defineRule(globalRules.POLICYHOLDER_LAST_NAME_REQUIRED, required(errorMessages.POLICYHOLDER_FIRST_NAME_REQUIRED)
required(errorMessages.POLICYHOLDER_LAST_NAME_REQUIRED)); );
defineRule(
globalRules.POLICYHOLDER_LAST_NAME_REQUIRED,
required(errorMessages.POLICYHOLDER_LAST_NAME_REQUIRED)
);
} }
/** /**
@ -20,9 +24,13 @@ 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.EMAIL_ADDRESS_FORMAT, defineRule(
regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/, globalRules.EMAIL_ADDRESS_FORMAT,
errorMessages.EMAIL_ADDRESS_FORMAT)); regex(
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]{2,})$/,
errorMessages.EMAIL_ADDRESS_FORMAT
)
);
} }
/** /**
@ -30,9 +38,20 @@ function defineGlobalEmailRules() {
*/ */
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.PHONE_NUMBER_FORMAT, defineRule(
regex(/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/, globalRules.PHONE_NUMBER_FORMAT,
errorMessages.PHONE_NUMBER_FORMAT)); regex(
/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/,
errorMessages.PHONE_NUMBER_FORMAT
)
);
defineRule(
globalRules.PHONE_NUMBER_FORMAT_SHORT,
regex(
/^(\([0-9]{3}\)|[0-9]{3}) *[-.]? *[0-9]{3} *[-.]? *[0-9]{4}$/,
errorMessages.PHONE_NUMBER_FORMAT_SHORT
)
);
} }
/** /**

View file

@ -1,51 +1,59 @@
<template> <template>
<div> <div>
<div class="d-flex align-items-center justify-content-center container-fluid overflow-hidden"> <div
<h5 class="d-flex align-items-center justify-content-center container-fluid overflow-hidden">
class="text-center fw-normal mb-0 subheader-primary" <h5 class="text-center fw-normal mb-0 subheader-primary" :class="headerColor">
:class="headerColor"> <span>
<span> {{ content }}
{{ content }}
</span>
<buttonBack
v-if="hasBackButton"
:backButtonAccessibleText="backButtonAccessibleText"
@click-event="clickEvent" />
</h5>
</div>
<div
class="subheader-secondary d-flex align-items-center container-fluid overflow-hidden"
:class="justifySubheader">
<p
class="fw-normal mb-0"
:class="alternateFormatting">
<span v-html="subText">
</span> </span>
<buttonBack
v-if="hasBackButton"
:backButtonAccessibleText="backButtonAccessibleText"
@click-event="clickEvent" />
</h5>
</div>
<div
class="subheader-secondary d-flex align-items-center container-fluid overflow-hidden"
:class="justifySubheader">
<p class="fw-normal mb-0" :class="alternateFormatting">
<span v-html="subText"> </span>
</p> </p>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import buttonBack from '@/iss-components/site-sub-header/button-back/button-back'; import buttonBack from '@/iss-components/site-sub-header/button-back/button-back';
export default ({ export default {
name: 'site-sub-header', name: 'site-sub-header',
components: { buttonBack }, components: { buttonBack },
props: { props: {
cmsWidgetName: String, cmsWidgetName: String,
contentProperty: String,
darkGraySubText: Boolean,
hasBackButton: Boolean, hasBackButton: Boolean,
justification: String,
issContainingPage: String, issContainingPage: String,
darkGraySubText: Boolean justification: String,
stripRteStyle: Boolean,
subContentProperty: String
}, },
emits: ['click-event'], emits: ['click-event'],
computed: { computed: {
content() { content() {
return this.getCmsContent(this.cmsWidgetName, 'SubHeaderText'); return this.getCmsContent(this.cmsWidgetName, this.contentProperty ?? 'SubHeaderText');
}, },
subText() { subText() {
const subText = this.getCmsContent(this.cmsWidgetName, 'SecondaryText'); let subText = this.getCmsContent(
this.cmsWidgetName,
this.subContentProperty ?? 'SecondaryText'
);
if (this.stripRteStyle) {
const regexExp = /[\s*]style="(.*?)"/g;
subText = subText.replace(regexExp, '');
}
return subText ?? ''; return subText ?? '';
}, },
backButtonAccessibleText() { backButtonAccessibleText() {
@ -55,7 +63,7 @@ export default ({
return this.subText ? 'dark-header' : 'light-header'; return this.subText ? 'dark-header' : 'light-header';
}, },
justifySubheader() { justifySubheader() {
return (this.justification?.toLowerCase() === 'left') return this.justification?.toLowerCase() === 'left'
? 'justify-content-left' ? 'justify-content-left'
: 'justify-content-center'; : 'justify-content-center';
}, },
@ -72,53 +80,52 @@ export default ({
this.$emit('click-event'); this.$emit('click-event');
} }
} }
}); };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.dark-header { .dark-header {
color: $black; color: $black;
} }
.light-header { .light-header {
color: $gray-550; color: $gray-550;
} }
h5 { h5 {
line-height: 32px; line-height: 32px;
button { button {
color: inherit; color: inherit;
} }
span{ span {
color: $black; color: $black;
}
}
p.light-gray {
color: $gray-550;
} }
}
p.light-gray {
color: $gray-550;
}
p.dark-gray { p.dark-gray {
color: $darker-gray; color: $darker-gray;
} }
p.service-packages-subtext { p.service-packages-subtext {
font-weight: 500 !important; font-weight: 500 !important;
line-height: 24px; line-height: 24px;
} }
.subheader-secondary { .subheader-secondary {
&.justify-content-center{ &.justify-content-center {
p { p {
text-align: center; text-align: center;
}
}
&.justify-content-left{
p {
text-align: left;
}
} }
} }
&.justify-content-left {
p {
text-align: left;
}
}
}
</style> </style>

View file

@ -1,21 +1,60 @@
<template> <template>
<Form <Form ref="theForm" v-slot="{ meta }" @submit="onSubmit" @invalid-submit="onInvalidSubmit">
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalid-submit="onInvalidSubmit">
<div class="page-container-grouped-styles"> <div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative"> <siteHeader cmsWidgetName="SiteHeaderWidget" />
<siteHeader cmsWidgetName="SiteHeaderWidget" /> <div class="main-content-container">
<div class="container-fluid pb-2"> <siteSubHeader
<p>Placeholder for bailout page</p> v-if="!isNoTpa"
<siteFooter cmsWidgetName="SiteSubHeaderWidget"
ref="siteFooter" class="sub-header-content"
justification="left" />
<siteSubHeader
v-else
cmsWidgetName="ContentGroupNoTPAWidget"
class="sub-header-content"
contentProperty="HeaderText"
justification="left"
:stripRteStyle="true"
subContentProperty="BodyText" />
<textboxQuestion
inputId="firstNameField"
cmsWidgetName="FirstNameQuestion"
v-model="bailoutPageModel.firstName"
isRequired
ref="firstName"
disableAutoFill
:validationRules="rules.firstName" />
<textboxQuestion
inputId="lastNameField"
cmsWidgetName="LastNameQuestion"
v-model="bailoutPageModel.lastName"
isRequired
ref="lastName"
disableAutoFill
:validationRules="rules.lastName" />
<textboxQuestion
inputId="phoneNumberField"
cmsWidgetName="PhoneNumberQuestion"
v-model="bailoutPageModel.phoneNumber"
isRequired
ref="phoneNumber"
mask="###-###-####"
disableAutoFill
:validationRules="rules.phoneNumber" />
<textboxQuestion
inputId="emailAddressField"
cmsWidgetName="EmailAddressQuestion"
v-model="bailoutPageModel.email"
isRequired
ref="emailAddress"
disableAutoFill
:validationRules="rules.email" />
<siteFooter
class="footer-content-container"
cmsWidgetName="SiteFooterWidget" cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@ForwardClicked="forwardButtonAction" @back-clicked="backButtonAction"
@back-clicked="backButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div>
</div> </div>
</div> </div>
</Form> </Form>
@ -23,19 +62,24 @@
<script> <script>
// Components // Components
import siteHeader from '@/iss-components/site-header/site-header'; import siteHeader from '@/iss-components/site-header/site-header';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header';
import siteFooter from '@/iss-components/site-footer/site-footer'; import siteFooter from '@/iss-components/site-footer/site-footer';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question';
// Supporting files // Supporting files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { settleAllPromises } from '@/helpers/layout-helper';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js'; import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { Form } from 'vee-validate';
import globalRules from '@/constants/global-rules';
import { settleAllPromises } from '@/helpers/layout-helper';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
export default { export default {
name: 'bailout-page', name: 'bailout-page',
components: { components: {
siteHeader, siteHeader,
siteSubHeader,
siteFooter, siteFooter,
textboxQuestion,
// eslint-disable-next-line vue/no-reserved-component-names // eslint-disable-next-line vue/no-reserved-component-names
Form Form
}, },
@ -48,9 +92,11 @@ export default {
{ {
resultKey: 'cmsContent', resultKey: 'cmsContent',
promise: cmsContentPromise promise: cmsContentPromise
}]; }
// use resultMap to populate layout content. ];
// use resultMap to populate layout content.
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => { next((vm) => {
vm.setCmsContent(resultMap.cmsContent); vm.setCmsContent(resultMap.cmsContent);
}); });
@ -60,16 +106,79 @@ export default {
return { mainStore }; return { mainStore };
}, },
data() { data() {
}, return {
methods: bailoutPageModel: this.getBailoutPageModelFromStore(),
{ rules: {
backButtonAction() { firstName: globalRules.FIRST_NAME_REQUIRED,
}, lastName: globalRules.LAST_NAME_REQUIRED,
forwardButtonAction() { phoneNumber: `${globalRules.PHONE_NUMBER_REQUIRED}|${globalRules.PHONE_NUMBER_FORMAT_SHORT}`,
return this.navigateForward(); email: `${globalRules.EMAIL_ADDRESS_REQUIRED}|${globalRules.EMAIL_ADDRESS_FORMAT}`
},
navigateForward() {
} }
};
},
computed: {
isNoTpa() {
return true; // not sure what in the data flags this.
} }
},
methods: {
backButtonAction() {
// route to move backwards
this.$router.navigate(this.navigationScenarios.CLICKED_BACK_PREVIOUS, this.$route);
},
forwardButtonAction() {
return this.navigateForward();
},
navigateForward() {},
getBailoutPageModelFromStore() {
return {
firstName: this.mainStore.order.customer.firstName,
lastName: this.mainStore.order.customer.lastName,
phoneNumber: this.mainStore.order.customer.phoneNumber,
email: this.mainStore.order.customer.emailAddress
};
}
}
}; };
</script> </script>
<style lang="scss">
$page-side-padding: 1.5rem;
.page-container-grouped-styles {
> div.main-content-container {
overflow: auto;
padding: 0 $page-side-padding !important;
> div.sub-header-content {
margin-top: 1rem;
padding: 0;
div.subheader-secondary {
margin-top: 0.5rem;
padding: 0;
p {
line-height: 1.5rem;
&:last-child {
margin-bottom: 0;
}
}
span {
font-size: 0.875rem;
}
}
}
div.textbox-question {
margin-top: 1rem;
}
div.footer-content-container {
margin: 1.5rem 0;
}
}
}
</style>

View file

@ -1,55 +1,47 @@
<template> <template>
<Form <Form ref="theForm" v-slot="{ meta }" @submit="onSubmit" @invalid-submit="onInvalidSubmit">
ref="theForm"
v-slot="{ meta }"
@submit="onSubmit"
@invalid-submit="onInvalidSubmit">
<div class="page-container-grouped-styles welcome"> <div class="page-container-grouped-styles welcome">
<div class="fade-on-route-transition position-relative"> <div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" /> <siteHeader cmsWidgetName="SiteHeaderWidget" />
<siteSubHeader <siteSubHeader cmsWidgetName="SiteSubHeaderWidget" class="mt-4" />
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4" />
<div class="container-fluid px-5"> <div class="container-fluid px-5">
<div class="row mt-5"> <div class="row mt-5">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
ref="policyNumber" ref="policyNumber"
v-model="welcomePageModel.policyNumber" v-model="welcomePageModel.policyNumber"
inputId="policyNumberField" inputId="policyNumberField"
cmsWidgetName="PolicyNumberQuestion" cmsWidgetName="PolicyNumberQuestion"
isRequired isRequired
disableAutoFill disableAutoFill
:isDisabled="isPolicyHolderEnabled" :isDisabled="isPolicyHolderEnabled"
:validationRules="rules.policyNumber" /> :validationRules="rules.policyNumber" />
</div> </div>
</div> </div>
<div <div v-if="isCoverageEnabled" class="row mt-4">
v-if="isCoverageEnabled"
class="row mt-4">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
ref="policyZip" ref="policyZip"
v-model="welcomePageModel.policyZipCode" v-model="welcomePageModel.policyZipCode"
inputId="policyZipCode" inputId="policyZipCode"
cmsWidgetName="PolicyZipQuestion" cmsWidgetName="PolicyZipQuestion"
isRequired isRequired
:validationRules="rules.policyZip" /> :validationRules="rules.policyZip" />
</div> </div>
</div> </div>
<div class="row mt-4"> <div class="row mt-4">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
ref="dateOfLoss" ref="dateOfLoss"
v-model="welcomePageModel.dateOfLoss" v-model="welcomePageModel.dateOfLoss"
type="date" type="date"
cmsWidgetName="DateOfLossQuestion" cmsWidgetName="DateOfLossQuestion"
inputId="dateOfLossField" inputId="dateOfLossField"
isRequired isRequired
disableAutoFill disableAutoFill
:max="new Date().toJSON().slice(0,10)" :max="new Date().toJSON().slice(0, 10)"
:min="'1972-12-01'" :min="'1972-12-01'"
:validationRules="rules.lossDate" /> :validationRules="rules.lossDate" />
</div> </div>
</div> </div>
<div class="row px-4"> <div class="row px-4">
@ -63,99 +55,97 @@
<div class="row mt-4"> <div class="row mt-4">
<div class="col"> <div class="col">
<dropdownQuestion <dropdownQuestion
id="welcomeDropdown" id="welcomeDropdown"
ref="damageCause" ref="damageCause"
v-model="welcomePageModel.damageCause" v-model="welcomePageModel.damageCause"
cmsWidgetName="DamageCauseQuestion" cmsWidgetName="DamageCauseQuestion"
inputId="damageCauseQuestionField" inputId="damageCauseQuestionField"
:options="DamageCauseOptions" :options="DamageCauseOptions"
disableAutoFill disableAutoFill
:validationRules="rules.damageOption" :validationRules="rules.damageOption"
placeHolderText="Select an option" /> placeHolderText="Select an option" />
</div>
</div>
<div class="row mt-4 ">
<div class="col">
<textboxQuestion
ref="phoneNumber"
v-model="welcomePageModel.phoneNumber"
inputId="phoneNumberField"
cmsWidgetName="PhoneNumberQuestion"
:validationRules="rules.phoneNumber"
isRequired
mask="###-###-####"
disableAutoFill />
</div> </div>
</div> </div>
<div class="row mt-4"> <div class="row mt-4">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
ref="email" ref="phoneNumber"
v-model="welcomePageModel.email" v-model="welcomePageModel.phoneNumber"
inputId="emailField" inputId="phoneNumberField"
cmsWidgetName="EmailAddressQuestion" cmsWidgetName="PhoneNumberQuestion"
:validationRules="rules.email" :validationRules="rules.phoneNumber"
isRequired isRequired
disableAutoFill /> mask="###-###-####"
disableAutoFill />
</div>
</div>
<div class="row mt-4">
<div class="col">
<textboxQuestion
ref="email"
v-model="welcomePageModel.email"
inputId="emailField"
cmsWidgetName="EmailAddressQuestion"
:validationRules="rules.email"
isRequired
disableAutoFill />
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<textboxQuestion <textboxQuestion
v-if="displayDamageCityQuestion" v-if="displayDamageCityQuestion"
ref="damageCity" ref="damageCity"
v-model="welcomePageModel.damageCity" v-model="welcomePageModel.damageCity"
class="mt-4" class="mt-4"
inputId="damageCityField" inputId="damageCityField"
cmsWidgetName="DamageCityQuestion" cmsWidgetName="DamageCityQuestion"
isRequired isRequired
disableAutoFill disableAutoFill
:validationRules="rules.lossCity" /> :validationRules="rules.lossCity" />
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<dropdownQuestion <dropdownQuestion
v-if="displayDamageStateQuestion" v-if="displayDamageStateQuestion"
id="welcomeDropdown" id="welcomeDropdown"
ref="state" ref="state"
v-model="welcomePageModel.damageState" v-model="welcomePageModel.damageState"
class="mt-4" class="mt-4"
cmsWidgetName="DamageStateQuestion" cmsWidgetName="DamageStateQuestion"
inputId="8fdf9dc2e13e430eb57529499dceb3eb" inputId="8fdf9dc2e13e430eb57529499dceb3eb"
:options="getStates" :options="getStates"
:validationRules="rules.lossState" :validationRules="rules.lossState"
isRequired isRequired
disableAutoFill disableAutoFill
placeHolderText="Select an option" /> placeHolderText="Select an option" />
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<buttonQuestion <buttonQuestion
v-if="displayGlassOnlyQuestion" v-if="displayGlassOnlyQuestion"
ref="glassOnlyDamage" ref="glassOnlyDamage"
v-model="welcomePageModel.isDamageGlassOnly" v-model="welcomePageModel.isDamageGlassOnly"
class="px-0 mt-4" class="px-0 mt-4"
cmsWidgetName="GlassOnlyQuestion" cmsWidgetName="GlassOnlyQuestion"
inputId="isDamageGlassOnly" inputId="isDamageGlassOnly"
:answers="DamageGlassOnlyOptions" :answers="DamageGlassOnlyOptions"
:questionText="DamageGlassOnlyQuestion" :questionText="DamageGlassOnlyQuestion"
buttonTypeString="listButtonHorizontal" buttonTypeString="listButtonHorizontal"
:validationRules="rules.damageOption" :validationRules="rules.damageOption"
isRequired isRequired
isSmallQuestionLabelText isSmallQuestionLabelText
disableAutoFill /> disableAutoFill />
</div> </div>
<div <div id="welcomeFooter" class="row position-sticky top-100">
id="welcomeFooter"
class="row position-sticky top-100">
<div class="col"> <div class="col">
<siteFooter <siteFooter
class="mt-3" class="mt-3"
cmsWidgetName="SiteFooterWidget" cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid" :isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction" @back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
</div> </div>
</div> </div>
</div> </div>
@ -192,7 +182,10 @@ defineRule('loss-state-required', required(errorMessages.LOSS_STATE_REQUIRED));
defineRule('loss-city-required', required(errorMessages.LOSS_CITY_REQUIRED)); defineRule('loss-city-required', required(errorMessages.LOSS_CITY_REQUIRED));
defineRule('damage-option-required', required(errorMessages.DAMAGE_OPTION_REQUIRED)); defineRule('damage-option-required', required(errorMessages.DAMAGE_OPTION_REQUIRED));
defineRule('policy-zip-required', required(errorMessages.POLICY_ZIP_REQUIRED)); defineRule('policy-zip-required', required(errorMessages.POLICY_ZIP_REQUIRED));
defineRule('policy-zip-format', regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.POLICY_ZIP_FORMAT)); defineRule(
'policy-zip-format',
regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.POLICY_ZIP_FORMAT)
);
export default { export default {
name: 'welcome-page', name: 'welcome-page',
@ -289,8 +282,7 @@ export default {
return this.mainStore.issConfig.isCoverageEnabled; return this.mainStore.issConfig.isCoverageEnabled;
} }
}, },
methods: methods: {
{
async forwardButtonAction() { async forwardButtonAction() {
this.mainStore.updatePolicyData(this.welcomePageModel); this.mainStore.updatePolicyData(this.welcomePageModel);
@ -322,7 +314,8 @@ export default {
const policy = policyInfo.policies?.[0]; const policy = policyInfo.policies?.[0];
if (policy) { if (policy) {
// populate policy holder details from policy lookup // populate policy holder details from policy lookup
this.mainStore.order.customer.address.streetAddress = policy.insureds?.[0]?.address; this.mainStore.order.customer.address.streetAddress =
policy.insureds?.[0]?.address;
this.mainStore.order.customer.address.city = policy.insureds?.[0]?.city; this.mainStore.order.customer.address.city = policy.insureds?.[0]?.city;
this.mainStore.order.customer.address.state = policy.insureds?.[0]?.state; this.mainStore.order.customer.address.state = policy.insureds?.[0]?.state;
this.mainStore.order.customer.address.zipCode = policy.insureds?.[0]?.zipCode; this.mainStore.order.customer.address.zipCode = policy.insureds?.[0]?.zipCode;
@ -341,21 +334,27 @@ export default {
if (policy) { if (policy) {
if (this.vehiclesFound) { if (this.vehiclesFound) {
// if policy lookup is successful and vehicles are found, navigate to policy-vehicles page // if policy lookup is successful and vehicles are found, navigate to policy-vehicles page
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES,
this.$route, this.$route,
{}, {},
{}, {},
this.vehiclesFound); this.vehiclesFound
);
} else { } else {
// if policy lookup is successful, but no vehicles are associated with the policy // if policy lookup is successful, but no vehicles are associated with the policy
// navigate to vehicle-selection page (manual entry) // navigate to vehicle-selection page (manual entry)
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, this.$router.navigate(
this.$route); this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES,
this.$route
);
} }
} else { } else {
// if policy lookup is unsuccessful, navigate to policy-holder-details page // if policy lookup is unsuccessful, navigate to policy-holder-details page
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED, this.$router.navigate(
this.$route); this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED,
this.$route
);
} }
}, },

View file

@ -15,6 +15,7 @@ import { experimentTriggers } from '@/constants/experiments';
import { applicationConfig } from '@/constants/application-config'; import { applicationConfig } from '@/constants/application-config';
import analyticsMixin from '@/mixins/analytics-mixin'; import analyticsMixin from '@/mixins/analytics-mixin';
import { navigationScenarios } from './router-constants/navigation-scenarios';
const routes = [ const routes = [
{ {
@ -22,7 +23,9 @@ const routes = [
name: 'root', name: 'root',
async beforeEnter(to, from, next) { async beforeEnter(to, from, next) {
try { try {
to.query.issPage = !to.query.issPage ? issPageValues.WELCOME_PAGE : to.query.issPage; to.query.issPage = !to.query.issPage
? issPageValues.WELCOME_PAGE
: to.query.issPage;
// Do not run these for the main entry page - as it is not part of the user flow. // Do not run these for the main entry page - as it is not part of the user flow.
if (to.query.issPage !== issPageValues.ENTRY_PAG) { if (to.query.issPage !== issPageValues.ENTRY_PAG) {
@ -67,18 +70,20 @@ const routes = [
} }
return null; return null;
} }
}]; }
];
const router = createRouter({ const router = createRouter({
history: createWebHistory('/'), history: createWebHistory('/'),
routes, routes,
scrollBehavior(to, from, savedPosition) { scrollBehavior(to, from, savedPosition) {
// always scroll to top // always scroll to top
return { top: 0 }; return { top: 0 };
} }
}); });
router.afterEach((to, from) => { /*eslint-disable-line*/ router.afterEach((to, from) => {
/*eslint-disable-line*/
const store = useMainStore(); const store = useMainStore();
// Update lastPageVisited in the store // Update lastPageVisited in the store
@ -130,12 +135,25 @@ router.overrideNavigation = (scenario,
next(); next();
}; };
router.navigate = (scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {}) => { router.navigate = (
scenario,
currentRoute,
optionalQuery = {},
optionalParams = {},
optionalPageData = {}
) => {
navigate(scenario, currentRoute, optionalQuery, optionalParams, optionalPageData); navigate(scenario, currentRoute, optionalQuery, optionalParams, optionalPageData);
}; };
// Navigate to the next route, depending on the scenario. // Navigate to the next route, depending on the scenario.
function navigate (scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {}) { /*eslint-disable-line*/ function navigate(
scenario,
currentRoute,
optionalQuery = {},
optionalParams = {},
optionalPageData = {}
) {
/*eslint-disable-line*/
if (!scenario) { if (!scenario) {
console.error('No scenario provided. Please review the routing table.'); console.error('No scenario provided. Please review the routing table.');
return; return;
@ -149,7 +167,11 @@ function navigate (scenario, currentRoute, optionalQuery = {}, optionalParams =
return; return;
} }
if (matchingScenarioMap.destinationIssPageValue) { if (scenario === navigationScenarios.CLICKED_BACK_PREVIOUS) {
// Update page to the prevous page in the router.
// If we need to worry about typing this in from outside of the app, we'll need to pre check history.length or if there is a previous page stored in state.
router.go(-1);
} else if (matchingScenarioMap.destinationIssPageValue) {
// Update page data to the store for next page if provided. Otherwise, keep existing page data or set to empty object // Update page data to the store for next page if provided. Otherwise, keep existing page data or set to empty object
const existingPageDataForPage = useMainStore().pageData(matchingScenarioMap.destinationIssPageValue); const existingPageDataForPage = useMainStore().pageData(matchingScenarioMap.destinationIssPageValue);
baseMixin.methods.savePageDataToStore(matchingScenarioMap.destinationIssPageValue, baseMixin.methods.savePageDataToStore(matchingScenarioMap.destinationIssPageValue,

View file

@ -1,6 +1,7 @@
const navigationScenarios = { const navigationScenarios = {
// General // General
CLICKED_BACK: 'CLICKED_BACK', CLICKED_BACK: 'CLICKED_BACK',
CLICKED_BACK_PREVIOUS: 'CLICKED_BACK_PREVIOUS',
CLICKED_FORWARD: 'CLICKED_FORWARD', CLICKED_FORWARD: 'CLICKED_FORWARD',
// Entry // Entry
@ -65,4 +66,4 @@ const navigationScenarios = {
CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT' CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT'
}; };
export { navigationScenarios }; export { navigationScenarios };

File diff suppressed because it is too large Load diff