Merge pull request #371 from Safelite/feature/digital/SSR-581

Feature/digital/ssr 581
This commit is contained in:
michaela-brydon-safelite 2023-07-21 15:03:29 -04:00 committed by GitHub
commit e5ceaf69f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 349 additions and 365 deletions

View file

@ -3,7 +3,7 @@
ref="theForm" ref="theForm"
v-slot="{ meta }" v-slot="{ meta }"
@submit="onSubmit" @submit="onSubmit"
@invalid-submit="onInvalidSubmit"> @invalidSubmit="onInvalidSubmit">
<div class="page-container-grouped-styles"> <div class="page-container-grouped-styles">
<div class="fade-on-route-transition position-relative"> <div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" /> <siteHeader cmsWidgetName="SiteHeaderWidget" />
@ -13,16 +13,16 @@ v-slot="{ meta }"
<div class="col"> <div class="col">
<div class="pb-1 mt-4"> <div class="pb-1 mt-4">
<h5 <h5
v-html="coverageStatementSubHeader" class="text-center text-black"
class="text-center text-black"> v-html="coverageStatementSubHeader">
</h5> </h5>
<div <div
v-html="explanatoryText" class="body-text text-center mt-4"
class="body-text text-center mt-4"> v-html="explanatoryText">
</div> </div>
<div <div
v-html="secondaryText" class="text-center mt-4 fw-bold text-black"
class="text-center mt-4 fw-bold text-black"> v-html="secondaryText">
</div> </div>
<div <div
v-if="verifiedDeductible" v-if="verifiedDeductible"
@ -41,33 +41,33 @@ v-slot="{ meta }"
<span class="text-success fw-bold">{{ formattedDeductible }}</span> <span class="text-success fw-bold">{{ formattedDeductible }}</span>
</div> </div>
<alert <alert
ref="verifiedITACAlert"
v-if="verifiedITAC" v-if="verifiedITAC"
ref="verifiedITACAlert"
class="mb-4" class="mb-4"
cmsWidgetName="VerifiedITACAlert" cmsWidgetName="VerifiedITACAlert"
:manualHeadline="verifiedITACAlertHeader" :manualHeadline="verifiedITACAlertHeader"
:manualCopy="verifiedITACAlertBody" :manualCopy="verifiedITACAlertBody"
alertClass="alert-success" alertClass="alert-success"
v-bind:isDismissible="false"> :isDismissible="false">
</alert> </alert>
<div <div
v-html="nextStepsHeader" class="fw-bold text-black mb-2"
class="fw-bold text-black mb-2"> v-html="nextStepsHeader">
</div> </div>
<div <div
v-html="nextStepsBody" class="body-text"
class="body-text"> v-html="nextStepsBody">
</div> </div>
<buttonQuestion <buttonQuestion
v-if="displayQuote" v-if="displayQuote"
id="coverage-button-question"
v-model="selectedProvider"
cmsWidgetName="ServiceProviderQuestion" cmsWidgetName="ServiceProviderQuestion"
:questionText="questionText" :questionText="questionText"
:answers="answersFromCms" :answers="answersFromCms"
buttonTypeString="listButton" buttonTypeString="listButton"
isRequired isRequired
v-model="selectedProvider" :validationRules="rules.selectionRequired">
validationRules="selection-required"
id="coverage-button-question">
</buttonQuestion> </buttonQuestion>
</div> </div>
<siteFooter <siteFooter
@ -83,41 +83,49 @@ v-slot="{ meta }"
</div> </div>
</div> </div>
</div> </div>
<recalModal ref="RecalModal" cmsWidgetName="RecalModal" /> <recalModal
<contentGroupModal ref="DeductibleModal" cmsWidgetName="DeductibleModal" class="deductible-modal"/> ref="RecalModal"
cmsWidgetName="RecalModal" />
<contentGroupModal
ref="DeductibleModal"
cmsWidgetName="DeductibleModal"
class="deductible-modal" />
</Form> </Form>
</template> </template>
<script> <script>
// Import Component // Import Component
import baseFormMixin from '@/mixins/base-form-mixin'; import { Form } from 'vee-validate';
import { Form, defineRule } from 'vee-validate'; import siteFooter from '@/iss-components/site-footer/site-footer';
import siteFooter from '@/iss-components/site-footer/site-footer.vue'; import siteHeader from '@/iss-components/site-header/site-header';
import siteHeader from '@/iss-components/site-header/site-header.vue'; import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue'; import alert from '@/ux-components/alert/alert';
import textBlock from "@/digital-components/text-block/text-block";
import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal.vue';
import alert from "@/ux-components/alert/alert";
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal'; import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal';
import buttonQuestion from "@/digital-components/button-question/button-question"; import buttonQuestion from '@/digital-components/button-question/button-question';
// Import Supporting Files // Import Supporting Files
import { fetchCmsContentForPage, setupModalLinks } from '@/helpers/cms-content-helper.js'; import { fetchCmsContentForPage, setupModalLinks, processIfStatements } from '@/helpers/cms-content-helper.js';
import { settleAllPromises } from '@/helpers/layout-helper.js'; import { settleAllPromises } from '@/helpers/layout-helper.js';
import { getDamageString } from '@/helpers/damage-helper.js'; import { getDamageString } from '@/helpers/damage-helper.js';
import { useMainStore } from "@/store"; import { useMainStore } from '@/store/index.js';
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin"; import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin.js';
import { processIfStatements } from '@/helpers/cms-content-helper'; import globalRules from '@/constants/global-rules.js';
import { required } from "@/helpers/validation-rules"; import baseFormMixin from '@/mixins/base-form-mixin.js';
import { errorMessages } from "@/constants/error-messages";
// DEFINE VALIDATION RULES
defineRule("selection-required", required(errorMessages.OPTION_REQUIRED));
const store = useMainStore(); const store = useMainStore();
export default { export default {
name: 'coverage-statement', name: 'coverage-statement',
components: {
siteFooter,
siteHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
recalModal,
alert,
contentGroupModal,
buttonQuestion
},
mixins: [baseFormMixin, vehicleQuestionsMixin], mixins: [baseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
// Call APIs // Call APIs
@ -129,19 +137,21 @@ export default {
const promiseResultMap = [ const promiseResultMap = [
{ {
resultKey: 'cmsContent', resultKey: 'cmsContent',
promise: cmsContentPromise, promise: cmsContentPromise
}, },
{ {
resultKey: 'supportingItems', resultKey: 'supportingItems',
promise: supportingItemsPromise, promise: supportingItemsPromise
}, }
]; ];
if (useMainStore().isClaimRegistrationRequired){ if (useMainStore().policy.policyLookupSuccessful
&& useMainStore().isClaimRegistrationRequired
&& !useMainStore().policy.noCoverage) {
const registerClaimResponse = await useMainStore().registerClaim(); const registerClaimResponse = await useMainStore().registerClaim();
promiseResultMap.push({ promiseResultMap.push({
resultKey: 'registerClaim', resultKey: 'registerClaim',
promise: registerClaimResponse, promise: registerClaimResponse
}); });
} }
@ -152,7 +162,7 @@ export default {
: []; : [];
const availableLineItems = [ const availableLineItems = [
...resultMap.supportingItems, ...resultMap.supportingItems,
...clonedGlassParts, ...clonedGlassParts
]; ];
const pricingResults = await store.getPriceOrderItems(availableLineItems); const pricingResults = await store.getPriceOrderItems(availableLineItems);
@ -165,90 +175,75 @@ export default {
vm.availableLineItems = pricingResults; vm.availableLineItems = pricingResults;
}); });
}, },
components: {
siteFooter,
siteHeader,
siteSubHeader,
Form,
textBlock,
recalModal,
alert,
contentGroupModal,
buttonQuestion
},
mounted() {
setupModalLinks(this);
},
data() { data() {
return { return {
isVerified: store.order.payment.insuranceCoverage.isVerified, isVerified: store.order.payment.insuranceCoverage.isVerified,
supportingItems: [], supportingItems: [],
pricedGlassParts: [], pricedGlassParts: [],
availableLineItems: [], availableLineItems: [],
selectedProvider: "", selectedProvider: '',
deductibleText: "Your deductible is:", deductibleText: 'Your deductible is:',
rules: {
selectionRequired: globalRules.OPTION_REQUIRED
} }
};
}, },
computed: { computed: {
verifiedITACAlertHeader() { verifiedITACAlertHeader() {
return this.getCmsContent( return this.getCmsContent('VerifiedITACAlert',
"VerifiedITACAlert", 'HeadlineText');
"HeadlineText"
)
}, },
verifiedITACAlertBody() { verifiedITACAlertBody() {
return this.getCmsContent( return this.getCmsContent('VerifiedITACAlert',
"VerifiedITACAlert", 'BodyText').replaceAll('{custom:costSavings}', this.costSavings);
"BodyText"
).replaceAll("{custom:costSavings}", this.costSavings);
}, },
coverageStatementSubHeader() { coverageStatementSubHeader() {
const subheader = this.getSubheaderTextFromCms("SiteSubHeaderWidget"); const subheader = this.getSubheaderTextFromCms('SiteSubHeaderWidget');
return subheader; return subheader;
}, },
secondaryText() { secondaryText() {
const secondaryText = this.getSecondaryTextFromCms("SiteSubHeaderWidget"); const secondaryText = this.getSecondaryTextFromCms('SiteSubHeaderWidget');
return secondaryText; return secondaryText;
}, },
explanatoryText() { explanatoryText() {
const explanatoryText = this.getExplantoryTextFromCms("ExplanatoryTextWidget"); const explanatoryText = this.getExplantoryTextFromCms('ExplanatoryTextWidget');
return explanatoryText; return explanatoryText;
}, },
nextStepsHeader() { nextStepsHeader() {
const header = this.getHeaderTextFromCms("NextStepsWidget"); const header = this.getHeaderTextFromCms('NextStepsWidget');
return header; return header;
}, },
nextStepsBody() { nextStepsBody() {
let body = this.getBodyTextFromCms("NextStepsWidget").replaceAll("{custom:damage}", this.damageText); const body = this.getBodyTextFromCms('NextStepsWidget').replaceAll('{custom:damage}', this.damageText);
return body; return body;
}, },
continueWithSchedulingBodyText() { continueWithSchedulingBodyText() {
return this.getCmsContent("continueWithSchedulingCopy", "BodyText"); return this.getCmsContent('continueWithSchedulingCopy', 'BodyText');
}, },
unverifiedADASNextStepsBodyText() { unverifiedADASNextStepsBodyText() {
return this.getCmsContent("UnverifiedADASNextStepsWidget", "BodyText").replaceAll("{custom:damage}", this.damageText); return this.getCmsContent('UnverifiedADASNextStepsWidget', 'BodyText').replaceAll('{custom:damage}', this.damageText);
}, },
unverifiedNonADASNextStepsBodyText() { unverifiedNonADASNextStepsBodyText() {
return this.getCmsContent("UnverifiedNonADASNextStepsWidget", "BodyText").replaceAll("{custom:damage}", this.damageText); return this.getCmsContent('UnverifiedNonADASNextStepsWidget', 'BodyText').replaceAll('{custom:damage}', this.damageText);
}, },
unverifiedNonADASRepairBodyText() { unverifiedNonADASRepairBodyText() {
return this.getCmsContent("UnverifiedNonADASRepairWidget", "BodyText"); return this.getCmsContent('UnverifiedNonADASRepairWidget', 'BodyText');
}, },
damageText() { damageText() {
var damageString = getDamageString(); const damageString = getDamageString();
return damageString == "match" ? "" : damageString; return damageString === 'match' ? '' : damageString;
}, },
vehicleDeductible() { vehicleDeductible() {
if (this.coverageVerified) { if (this.coverageVerified) {
if (store.order.damage.isRepair) { if (store.order.damage.isRepair) {
const repairDeductible = store.order.policy.deductible.repair const repairDeductible = store.order.policy.deductible.repair;
return repairDeductible; return repairDeductible;
} }
else {
const replaceDeductible = store.order.policy.deductible.replace; const replaceDeductible = store.order.policy.deductible.replace;
return replaceDeductible; return replaceDeductible;
} }
} return null;
}, },
formattedDeductible() { formattedDeductible() {
return this.getDeductibleString(this.vehicleDeductible); return this.getDeductibleString(this.vehicleDeductible);
@ -257,11 +252,13 @@ export default {
if (this.coverageVerified && this.verifiedDeductible) { if (this.coverageVerified && this.verifiedDeductible) {
return this.vehicleDeductible === 0; return this.vehicleDeductible === 0;
} }
return null;
}, },
deductibleOverZero() { deductibleOverZero() {
if (this.coverageVerified && this.verifiedDeductible) { if (this.coverageVerified && this.verifiedDeductible) {
return !this.isDeductibleZero; return !this.isDeductibleZero;
} }
return null;
}, },
coverageVerified() { coverageVerified() {
return this.isVerified; return this.isVerified;
@ -270,48 +267,40 @@ export default {
return !this.isVerified; return !this.isVerified;
}, },
verifiedNoComp() { verifiedNoComp() {
if (this.coverageVerified) { return this.coverageVerified ? store.order.policy.noCoverage : false;
return store.order.policy.noCoverage;
}
}, },
verifiedITAC() { verifiedITAC() {
if (this.coverageVerified && !this.verifiedNoComp) { return this.coverageVerified
if (this.vehicleDeductible > this.totalServicePrice) { && !this.verifiedNoComp
return true; && this.vehicleDeductible > this.totalServicePrice;
}
}
}, },
verifiedDeductible() { verifiedDeductible() {
if (this.coverageVerified && !this.verifiedNoComp) { return this.coverageVerified
if (this.totalServicePrice > this.vehicleDeductible) { && !this.verifiedNoComp
return true; && this.totalServicePrice > this.vehicleDeductible;
}
}
}, },
ADASReplace() { ADASReplace() {
if (!store.order.damage.isRepair) { if (!store.order.damage.isRepair) {
let parts = store.order.lineItems.glassParts; const parts = store.order.lineItems.glassParts;
if (parts != null && parts.filter(part => part.requiresRecalibration).length > 0) { if (parts != null && parts.filter((part) =>
part.requiresRecalibration).length > 0) {
return true; return true;
} }
} }
return false;
}, },
nonADASReplace() { nonADASReplace() {
if (!store.order.damage.isRepair) {
return !this.ADASReplace; return !this.ADASReplace;
}
}, },
nonADASRepair() { nonADASRepair() {
if (store.order.damage.isRepair) { return store.order.damage.isRepair;
return true;
}
}, },
totalServicePrice() { totalServicePrice() {
let total = 0; let total = 0;
this.availableLineItems.forEach((lineItem) => { this.availableLineItems.forEach((lineItem) => {
total += this.getTotalLineItemPrice(lineItem); total += this.getTotalLineItemPrice(lineItem);
}) });
return total; return total;
}, },
formattedServicePrice() { formattedServicePrice() {
@ -320,19 +309,29 @@ export default {
costSavings() { costSavings() {
const savings = this.getITACCostSavings(this.vehicleDeductible, this.totalServicePrice); const savings = this.getITACCostSavings(this.vehicleDeductible, this.totalServicePrice);
const formattedSavings = parseFloat(savings).toFixed(2); const formattedSavings = parseFloat(savings).toFixed(2);
return '$' + formattedSavings; return `$${formattedSavings}`;
}, },
questionText() { questionText() {
return this.getCmsContent("ServiceProviderQuestion", "QuestionText"); return this.getCmsContent('ServiceProviderQuestion', 'QuestionText');
}, },
answersFromCms() { answersFromCms() {
return this.getCmsContent("ServiceProviderQuestion", "Answers"); return this.getCmsContent('ServiceProviderQuestion', 'Answers');
}, },
displayQuote() { displayQuote() {
if (this.verifiedITAC || this.verifiedNoComp) { return this.verifiedITAC || this.verifiedNoComp;
return true;
} }
}, },
watch: {
selectedProvider() {
if (this.selectedProvider === 'Safelite') {
this.$refs.siteFooter.updateButtonText('Continue with Safelite');
} else {
this.$refs.siteFooter.updateButtonText('Continue');
}
}
},
mounted() {
setupModalLinks(this);
}, },
methods: { methods: {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
@ -342,34 +341,22 @@ export default {
return false; return false;
}, },
async forwardButtonAction() { async forwardButtonAction() {
return await this.navigateForward(); return this.navigateForward();
}, },
async navigateForward() { async navigateForward() {
if (this.coverageUnverified || this.verifiedDeductible) { if (this.coverageUnverified || this.verifiedDeductible) {
this.$router.navigate( this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD,
this.navigationScenarios.CLICKED_FORWARD, this.$route);
this.$route } else if (this.verifiedITAC || this.verifiedNoComp) {
) if (this.selectedProvider === 'Safelite') {
} this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE,
else if (this.verifiedITAC || this.verifiedNoComp) { this.$route);
if (this.selectedProvider === "Safelite") { } else if (store.issConfig.enableTPAFlow) {
this.$router.navigate( this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_THIRD_PARTY,
this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE, this.$route);
this.$route } else {
) this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
} this.$route);
else if (store.issConfig.enableTPAFlow){
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_THIRD_PARTY,
this.$route
)
}
else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
)
} }
} }
}, },
@ -379,23 +366,23 @@ export default {
processIfStatements, processIfStatements,
getHeaderTextFromCms(cmsWidgetName) { getHeaderTextFromCms(cmsWidgetName) {
const header = this.getCmsContent(cmsWidgetName, 'HeaderText'); const header = this.getCmsContent(cmsWidgetName, 'HeaderText');
return this.processIfStatements(header, "custom", this.getCustomValueFromString); return this.processIfStatements(header, 'custom', this.getCustomValueFromString);
}, },
getSubheaderTextFromCms(cmsWidgetName) { getSubheaderTextFromCms(cmsWidgetName) {
const subHeader = this.getCmsContent(cmsWidgetName, 'SubHeaderText'); const subHeader = this.getCmsContent(cmsWidgetName, 'SubHeaderText');
return this.processIfStatements(subHeader, "custom", this.getCustomValueFromString); return this.processIfStatements(subHeader, 'custom', this.getCustomValueFromString);
}, },
getBodyTextFromCms(cmsWidgetName) { getBodyTextFromCms(cmsWidgetName) {
const bodyText = this.getCmsContent(cmsWidgetName, "BodyText"); const bodyText = this.getCmsContent(cmsWidgetName, 'BodyText');
return this.processIfStatements(bodyText, "custom", this.getCustomValueFromString); return this.processIfStatements(bodyText, 'custom', this.getCustomValueFromString);
}, },
getSecondaryTextFromCms(cmsWidgetName) { getSecondaryTextFromCms(cmsWidgetName) {
const secondaryText = this.getCmsContent(cmsWidgetName, "SecondaryText"); const secondaryText = this.getCmsContent(cmsWidgetName, 'SecondaryText');
return this.processIfStatements(secondaryText, "custom", this.getCustomValueFromString); return this.processIfStatements(secondaryText, 'custom', this.getCustomValueFromString);
}, },
getExplantoryTextFromCms(cmsWidgetName) { getExplantoryTextFromCms(cmsWidgetName) {
const explanatoryText = this.getCmsContent(cmsWidgetName, "BodyText"); const explanatoryText = this.getCmsContent(cmsWidgetName, 'BodyText');
return this.processIfStatements(explanatoryText, "custom", this.getCustomValueFromString); return this.processIfStatements(explanatoryText, 'custom', this.getCustomValueFromString);
}, },
getCustomValueFromString(str) { getCustomValueFromString(str) {
switch (str) { switch (str) {
@ -414,9 +401,9 @@ export default {
case 'nonADASRepair': case 'nonADASRepair':
return this.nonADASRepair; return this.nonADASRepair;
case 'deductibleOverZero': case 'deductibleOverZero':
return this.deductibleOverZero return this.deductibleOverZero;
case 'isDeductibleZero': case 'isDeductibleZero':
return this.isDeductibleZero return this.isDeductibleZero;
default: default:
return null; return null;
} }
@ -426,26 +413,16 @@ export default {
}, },
getDeductibleString(deductible) { getDeductibleString(deductible) {
const formattedDeductibleFloat = parseFloat(deductible).toFixed(2); const formattedDeductibleFloat = parseFloat(deductible).toFixed(2);
return '$' + formattedDeductibleFloat; return `$${formattedDeductibleFloat}`;
}, },
getServicePriceString(price) { getServicePriceString(price) {
const formattedPriceFloat = parseFloat(price).toFixed(2); const formattedPriceFloat = parseFloat(price).toFixed(2);
return '$' + formattedPriceFloat; return `$${formattedPriceFloat}`;
}, },
getITACCostSavings(vehicleDeductible, totalServicePrice) { getITACCostSavings(vehicleDeductible, totalServicePrice) {
const savings = vehicleDeductible - totalServicePrice; const savings = vehicleDeductible - totalServicePrice;
return savings; return savings;
} }
},
watch: {
selectedProvider() {
if (this.selectedProvider === "Safelite") {
this.$refs.siteFooter.updateButtonText('Continue with Safelite');
}
else {
this.$refs.siteFooter.updateButtonText('Continue');
}
}
} }
}; };
</script> </script>

View file

@ -53,6 +53,7 @@ const getDefaultState = () =>
damageState: null, damageState: null,
damageCity: null, damageCity: null,
isDamageGlassOnly: null, isDamageGlassOnly: null,
policyLookupSuccessful: null,
noCoverage: null, noCoverage: null,
deductible: { deductible: {
repair: null, // numerical value; how much customer owes on deductible in repair case repair: null, // numerical value; how much customer owes on deductible in repair case
@ -349,6 +350,7 @@ export const useMainStore = defineStore({
getCoveragePolicyInfo({ accountNumber, policyNumber, dateOfLoss, zipCode }) { getCoveragePolicyInfo({ accountNumber, policyNumber, dateOfLoss, zipCode }) {
// TODO: replace place holder correlationId with the real thing // TODO: replace place holder correlationId with the real thing
const placeHolderCorrelationId = '00000000-0000-0000-0000-000000000000'; const placeHolderCorrelationId = '00000000-0000-0000-0000-000000000000';
const { policy } = this.order;
try { try {
const response = globalMethods.callHttpClient({ const response = globalMethods.callHttpClient({
method: endpoints.CoveragePolicyInfo.method, method: endpoints.CoveragePolicyInfo.method,
@ -360,9 +362,14 @@ export const useMainStore = defineStore({
zipCode, zipCode,
correlationId: placeHolderCorrelationId correlationId: placeHolderCorrelationId
} }
}).then((r) => {
const responsePolicy = response.policies?.[0];
policy.policyLookupSuccessful = !!responsePolicy;
return r;
}); });
return response; return response;
} catch (responseError) { } catch (responseError) {
policy.policyLookupSuccessful = false;
return { return {
error: { error: {
status: responseError.status status: responseError.status