Merge pull request #797 from Safelite/feature/brydon/SSR-1398

Feature/brydon/ssr 1398
This commit is contained in:
michaela-brydon-safelite 2024-07-23 10:33:28 -04:00 committed by GitHub
commit 47985da12d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 132 additions and 277 deletions

View file

@ -2,6 +2,7 @@
exports[`cart-dropdown component initial data rendered as expected 1`] = `
Object {
"RECYCLING_MODAL_REF_NAME": "RecycleModal",
"cartItemType": Object {
"MOBILE_FEE": "MOBILE FEE",
"RECYCLE_FEE": "RECYCLE FEE",

View file

@ -93,7 +93,7 @@
linkType="text"
:text="item?.name ?? ''"
href="javascript:void(0)"
@clickEvent="openModal(recyclingModalCmsWidgetName)" />
@clickEvent="openModal(RECYCLING_MODAL_REF_NAME)" />
</span>
<span v-else>{{ item?.name ?? '' }}</span>
<span>{{ formatAmountInDollars(item?.subTotal ?? 0) }}</span>
@ -146,7 +146,7 @@
</div>
</div>
<contentGroupModal
ref="RecycleModal"
:ref="RECYCLING_MODAL_REF_NAME"
:cmsWidgetName="recyclingModalCmsWidgetName">
<textBlock cmsWidgetName="RecycleTextBlock" />
</contentGroupModal>
@ -178,6 +178,7 @@ import {
import { getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator';
const VERIFYING_COVERAGE = 'Verifying coverage';
const RECYCLING_MODAL_REF_NAME = "RecycleModal";
export default {
name: 'cart-dropdown',
@ -209,7 +210,8 @@ export default {
servicePackage: 'ServicePackageTitle',
vapsItemDescriptions: 'VapsItemDescriptions'
},
cartItemType
cartItemType,
RECYCLING_MODAL_REF_NAME
};
},
computed: {
@ -467,6 +469,8 @@ export default {
<style lang="scss" scoped>
@import "@/styles/ux-variables-svg-strings.scss";
$RECYCLING_MODAL_REF_NAME: 'RecycleModal';
.force-no-top-margin {
margin-top: 0 !important;
}
@ -492,7 +496,7 @@ export default {
:deep(a) {
padding-bottom: 0 !important;
line-height: 1.625 !important;
line-height: 1.625rem !important;
text-underline-offset: auto !important;
}
@ -536,7 +540,7 @@ export default {
max-width: fit-content;
}
:deep(#RecycleModal h5) {
:deep(##{$RECYCLING_MODAL_REF_NAME} h5) {
text-align: center;
}

View file

@ -2,6 +2,9 @@
exports[`coverageStatement.vue returns the initial data 1`] = `
Object {
"DEDUCTIBLE_MODAL_REF_NAME": "DeductibleModal",
"RECAL_MODAL_REF_NAME": "RecalModal",
"SITE_FOOTER_REF_NAME": "siteFooter",
"baseServiceLineItems": Array [],
"deductibleText": "Your deductible is",
"rules": Object {

View file

@ -4,7 +4,7 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="container-fluid fade-on-route-transition coverage-statement">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
@ -76,7 +76,7 @@
cmsWidgetName="DisclaimerWidget"
typeStyle="caption" />
<siteFooter
ref="siteFooter"
:ref="SITE_FOOTER_REF_NAME"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@ -85,12 +85,11 @@
</div>
</div>
</div>
<recalModal
ref="RecalModal"
cmsWidgetName="RecalModal"
class="recal-modal" />
<contentGroupModal
ref="DeductibleModal"
:ref="RECAL_MODAL_REF_NAME"
cmsWidgetName="RecalModal" />
<contentGroupModal
:ref="DEDUCTIBLE_MODAL_REF_NAME"
cmsWidgetName="DeductibleModal"
class="deductible-modal" />
</Form>
@ -100,7 +99,6 @@
import { Form } from 'vee-validate';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal.vue';
import alert from '@/ux-components/alert/alert.vue';
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
@ -129,6 +127,9 @@ import coverageStatuses from '@/constants/coverage-statuses';
import coverageType from '@/constants/coverage-type';
const SAFELITE_PROVIDER = 'Safelite';
const RECAL_MODAL_REF_NAME = "RecalModal";
const DEDUCTIBLE_MODAL_REF_NAME = "DeductibleModal";
const SITE_FOOTER_REF_NAME = "siteFooter";
export default {
name: 'coverage-statement',
@ -137,7 +138,6 @@ export default {
siteHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
recalModal,
alert,
contentGroupModal,
buttonQuestion,
@ -209,7 +209,10 @@ export default {
explanatoryText: 'ExplanatoryTextWidget',
nextStep: 'NextStepsWidget',
serviceProviderQuestion: 'ServiceProviderQuestion'
}
},
RECAL_MODAL_REF_NAME,
DEDUCTIBLE_MODAL_REF_NAME,
SITE_FOOTER_REF_NAME
};
},
computed: {
@ -331,17 +334,17 @@ export default {
this.selectedProvider === SAFELITE_PROVIDER
? 'Continue with Safelite'
: 'Continue';
this.$refs.siteFooter.updateButtonText(buttonText);
this.$refs[SITE_FOOTER_REF_NAME].updateButtonText(buttonText);
},
nextStepsBody(newValue, oldValue) {
if (newValue !== oldValue) {
setupModalLink(this, 'RecalModal');
setupModalLink(this, 'DeductibleModal');
setupModalLink(this, RECAL_MODAL_REF_NAME);
setupModalLink(this, DEDUCTIBLE_MODAL_REF_NAME);
}
},
verifiedItacAlertBody(newValue, oldValue) {
if (newValue !== oldValue) {
setupModalLink(this, 'DeductibleModal');
setupModalLink(this, DEDUCTIBLE_MODAL_REF_NAME);
}
}
},
@ -464,41 +467,38 @@ export default {
</script>
<style lang="scss" scoped>
.cost {
color: $green;
font-size: 2rem;
font-weight: $font-weight-light;
line-height: 2.75rem;
}
.deductible-text {
line-height: 1.5rem;
}
:deep p {
line-height: 1.5rem;
font-size: 0.875rem;
margin-bottom: 0.5rem;
strong {
color: $black;
.coverage-statement {
.cost {
color: $green;
font-size: 2rem;
font-weight: $font-weight-light;
line-height: 2.75rem;
}
}
:deep .question-text {
margin-top: 1.5rem;
margin-bottom: 0.5rem;
font-size: 1rem;
line-height: 1.5rem;
& > span {
text-align: left;
.deductible-text {
line-height: 1.5rem;
}
:deep p {
line-height: 1.5rem;
font-size: 0.875rem;
margin-bottom: 0.5rem;
strong {
color: $black;
}
}
:deep .question-text {
margin-top: 1.5rem;
margin-bottom: 0.5rem;
font-size: 1rem;
line-height: 1.5rem;
& > span {
text-align: left;
}
}
}
:deep .deductible-modal {
p {
margin-bottom: 0 !important;
font-size: 1rem;
line-height: 1.625rem;
}
img.mb-4 {
margin: 0 !important;
@ -511,17 +511,6 @@ export default {
}
}
:deep(.recal-modal) {
p {
font-size: 1rem;
line-height: 1.625rem;
&.modal-body {
padding: 0;
}
}
}
.modal {
overflow: hidden;
}

View file

@ -1,66 +0,0 @@
import { mount } from '@vue/test-utils';
import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal.vue';
const mockCmsContent = {
HeaderText: 'Sample header text here.',
SubheaderText: 'Sample subheader text here.',
Image: 'https://www.sampleImage.sample',
BodyText: 'Sample body text here.',
FooterText: 'Sample footer text here.'
};
const mockMixin = {
methods: {
getCmsContent: jest.fn((widgetName, cmsFieldName) => mockCmsContent[cmsFieldName])
}
};
describe('modal.vue', () => {
it('Should display header text when HeaderText is defined in the CMS', async () => {
// Act
const wrapper = mount(recalModal, {
mixins: [mockMixin],
props: {
cmsWidgetName: 'test'
},
attachTo: document.body
});
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.HeaderText));
});
it('Should display subheader text when SubheaderText is defined in the CMS', async () => {
// Act
const wrapper = mount(recalModal, {
mixins: [mockMixin],
props: {
cmsWidgetName: 'test'
},
attachTo: document.body
});
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.SubheaderText));
});
it('Should insert image url when Image is defined in the CMS', async () => {
// Act
const wrapper = mount(recalModal, {
mixins: [mockMixin],
props: {
cmsWidgetName: 'test'
},
attachTo: document.body
});
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.Image));
});
it('Should display body text when BodyText is defined in the CMS', async () => {
// Act
const wrapper = mount(recalModal, {
mixins: [mockMixin],
props: {
cmsWidgetName: 'test'
},
attachTo: document.body
});
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent.BodyText));
});
});

View file

@ -1,89 +0,0 @@
<template>
<modal
:ref="ModalName"
:modalId="ModalName"
:footerButtonText="ModalCloseButtonText"
@footerButtonEvent="closeModal">
<div class="recal-modal-body">
<h5
class="mb-4 text-center"
v-html="ModalHeadline"></h5>
<img
:src="ModalImage"
class="mw-100 d-flex mx-auto mb-4"
alt="" />
<p
class="fw-bold mb-2 subheader-text"
v-html="ModalSubheadertext"></p>
<p
class="mb-0 small modal-body"
v-html="ModalBodyText"></p>
<p
v-if="ModalSubBodyText"
class="my-4 caption modal-sub-body"
v-html="ModalSubBodyText">
</p>
</div>
</modal>
</template>
<script>
import modal from '@/digital-components/modal/modal.vue';
export default {
name: 'recal-modal',
components: {
modal
},
props: {
cmsWidgetName: String
},
computed: {
ModalName() {
return this.cmsWidgetName;
},
ModalHeadline() {
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
},
ModalSubheadertext() {
return this.getCmsContent(this.cmsWidgetName, 'SubheaderText');
},
ModalBodyText() {
return this.getCmsContent(this.cmsWidgetName, 'BodyText');
},
ModalSubBodyText() {
return this.getCmsContent(this.cmsWidgetName, 'BodyText2');
},
ModalImage() {
return this.getCmsContent(this.cmsWidgetName, 'Image');
},
ModalCloseButtonText() {
return this.getCmsContent(this.cmsWidgetName, 'FooterText');
}
},
methods: {
openModal() {
this.$refs[this.ModalName].openModal();
},
closeModal() {
this.$refs[this.ModalName].closeModal();
}
}
};
</script>
<style lang="scss" scoped>
:deep .recal-modal-body {
h5 {
color: $black;
}
.modal-body {
strong {
color: $black;
font-weight: 400;
}
}
}
</style>

View file

@ -163,7 +163,7 @@ export default {
.label {
color: $black;
font-weight: 500;
line-height: 1.625;
line-height: 1.625rem;
}
}
</style>

View file

@ -3,7 +3,7 @@
ref="theForm"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="container-fluid fade-on-route-transition provider-preference">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
@ -32,7 +32,7 @@ ref="theForm"
:validationRules="rules.optionRequired"
isRequired />
<siteFooter
ref="siteFooter"
:ref="SITE_FOOTER_REF_NAME"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="isForwardActionDisabled"
@ -40,30 +40,30 @@ ref="theForm"
@forwardClicked="forwardButtonAction" />
</div>
</div>
<recalModal
ref="recalModal"
cmsWidgetName="RecalModal"
class="recal-modal" />
<steeringModal
ref="StateSteeringModal"
cmsWidgetName="StateSteeringModal" />
<shopPreferenceModal
ref="ShopPreferenceDrawer"
cmsWidgetName="ShopPreferenceDrawer"
:showSteeringLink="showSteeringLink"
@openSteering="openStateSteeringModal" />
<tpaRecalModal
ref="TPARecalModal"
cmsWidgetName="TPARecalModal"
:ackError="ackError"
@buttonClick="navigateWithTPAAck" />
</div>
<contentGroupModal
:ref="RECAL_MODAL_REF_NAME"
cmsWidgetName="RecalModal" />
<steeringModal
:ref="STEERING_MODAL_REF_NAME"
cmsWidgetName="StateSteeringModal" />
<shopPreferenceModal
:ref="SHOP_PREFERENCE_MODAL_REF_NAME"
cmsWidgetName="ShopPreferenceDrawer"
:showSteeringLink="showSteeringLink"
@openSteering="openStateSteeringModal" />
<tpaRecalModal
:ref="TPA_RECAL_MODAL_REF_NAME"
cmsWidgetName="TPARecalModal"
:ackError="ackError"
@buttonClick="navigateWithTPAAck" />
</Form>
</template>
<script>
// Import Supporting Files
import {
fetchCmsContentForPage,
setupModalLink,
setupModalLinks
} from '@/helpers/cms-content-helper';
import settleAllPromises from '@/helpers/layout-helper';
@ -77,18 +77,22 @@ import { Form } from 'vee-validate';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import recalModal from '@/layouts/coverage-statement/recal-modal/recal-modal.vue';
import steeringModal from '@/layouts/provider-preference/steering-modal/steering-modal.vue';
import shopPreferenceModal from '@/layouts/provider-preference/shop-preference-modal/shop-preference-modal.vue';
import tpaRecalModal from '@/layouts/provider-preference/tpa-recal-modal/tpa-recal-modal.vue';
import globalRules from '@/constants/global-rules';
import bailoutMessage from '@/constants/bailoutMessage';
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
const options = { SAFELITE: 'SafeliteOption', TPA: 'TPAOption' };
const RECAL_MODAL_REF_NAME = "RecalModal";
const STEERING_MODAL_REF_NAME = "StateSteeringModal";
const SHOP_PREFERENCE_MODAL_REF_NAME = "ShopPreferenceDrawer";
const TPA_RECAL_MODAL_REF_NAME = "TPARecalModal";
const SITE_FOOTER_REF_NAME = "siteFooter";
export default {
name: 'provider-preference',
components: {
siteFooter,
siteHeader,
@ -96,10 +100,10 @@ export default {
// eslint-disable-next-line vue/no-reserved-component-names
Form,
buttonQuestion,
recalModal,
steeringModal,
shopPreferenceModal,
tpaRecalModal
tpaRecalModal,
contentGroupModal
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
@ -115,9 +119,9 @@ export default {
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.showSteeringLink = !!vm.$refs.StateSteeringModal.ModalBodyText;
vm.showSteeringLink = !!vm.$refs[STEERING_MODAL_REF_NAME].ModalBodyText;
if (vm.showSteeringLink) {
vm.$refs.StateSteeringModal.openModal();
vm.openStateSteeringModal();
}
});
},
@ -128,7 +132,12 @@ export default {
tpaAcknowledgement: false,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
},
RECAL_MODAL_REF_NAME,
STEERING_MODAL_REF_NAME,
SHOP_PREFERENCE_MODAL_REF_NAME,
TPA_RECAL_MODAL_REF_NAME,
SITE_FOOTER_REF_NAME
};
},
computed: {
@ -169,6 +178,13 @@ export default {
return errorMessages.ACKNOWLEDGEMENT_REQUIRED;
}
},
watch: {
prefAnswers(newValue, oldValue) {
if (newValue !== oldValue) {
setupModalLink(this, RECAL_MODAL_REF_NAME);
}
}
},
mounted() {
setupModalLinks(this);
const pageData = this.mainStore.pageData(issPageValues.PROVIDER_PREFERENCE);
@ -220,8 +236,8 @@ export default {
this.mainStore.updateIsSafeliteProvider(false);
if (this.mainStore.issConfig.enableTPAFlow) {
if (this.mainStore.hasRecalibrationPart) {
this.$refs.TPARecalModal.openModal();
this.$refs.siteFooter.removeLoader();
this.$refs[TPA_RECAL_MODAL_REF_NAME].openModal();
this.$refs[SITE_FOOTER_REF_NAME].removeLoader();
return;
}
scenario =
@ -244,41 +260,30 @@ export default {
}
},
openStateSteeringModal() {
this.$refs.StateSteeringModal.openModal();
this.$refs[STEERING_MODAL_REF_NAME].openModal();
}
}
};
</script>
<style lang="scss" scoped>
#sub-header span {
color: $black;
}
.question-text {
margin-top: 0;
margin-bottom: 0.5rem;
& > span {
text-align: left;
.provider-preference {
#sub-header span {
color: $black;
}
}
:deep(.safeliteLogo) {
background-image: url(~@/assets/img/icons/logo.svg);
background-repeat: no-repeat;
background-size: 4.5rem;
margin: 0 0.25rem 0 0.25rem;
padding: 0 2.5rem 0 2.5rem;
background-position: center;
}
:deep(.recal-modal) {
p {
font-size: 1rem;
line-height: 1.625rem;
&.modal-body {
padding: 0;
.question-text {
margin-top: 0;
margin-bottom: 0.5rem;
& > span {
text-align: left;
}
}
:deep(.safeliteLogo) {
background-image: url(~@/assets/img/icons/logo.svg);
background-repeat: no-repeat;
background-size: 4.5rem;
margin: 0 0.25rem 0 0.25rem;
padding: 0 2.5rem 0 2.5rem;
background-position: center;
}
}
</style>

View file

@ -86,7 +86,7 @@
" />
<shopQuestion
v-show="isShopQuestionDisplayed"
ref="shopQuestion"
:ref="SHOP_QUESTION_REF_NAME"
v-model="selectedProvider"
:selectedAppointmentType="selectedAppointmentType"
:isDisplayed="isShopQuestionDisplayed"
@ -95,10 +95,10 @@
setMobileProviderNumber
" />
<contentGroupModal
ref="RecalModal"
:ref="RECAL_MODAL_REF_NAME"
cmsWidgetName="RecalModal" />
<siteFooter
ref="siteFooter"
:ref="SITE_FOOTER_REF_NAME"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="
@ -152,6 +152,11 @@ defineRule('mobile-location-required', (value) => {
return true;
});
defineRule('selection-required', required(errorMessages.OPTION_REQUIRED));
const SHOP_QUESTION_REF_NAME = "shopQuestion";
const RECAL_MODAL_REF_NAME = "RecalModal";
const SITE_FOOTER_REF_NAME = "siteFooter";
export default {
name: 'service-location',
components: {
@ -217,7 +222,7 @@ export default {
resultMap.mobileFeePart,
resultMap.shopQuestionInitialData?.mobileProviderNumber
);
vm.$refs.shopQuestion.initializeComponent(resultMap.shopQuestionInitialData);
vm.$refs[SHOP_QUESTION_REF_NAME].initializeComponent(resultMap.shopQuestionInitialData);
});
},
setup() {
@ -241,7 +246,10 @@ export default {
mobileFeePart: null,
mobileProviderNumber: null,
zipContainsMilitaryBase: false,
zipCodeCtu: null
zipCodeCtu: null,
SHOP_QUESTION_REF_NAME,
RECAL_MODAL_REF_NAME,
SITE_FOOTER_REF_NAME
};
},
computed: {
@ -389,7 +397,7 @@ export default {
);
},
async reloadShopData(zipCode) {
await this.$refs.shopQuestion.reloadShopData(zipCode);
await this.$refs[SHOP_QUESTION_REF_NAME].reloadShopData(zipCode);
},
async forwardButtonAction() {
let provider = this.selectedProvider;

View file

@ -2,7 +2,7 @@
p,
body {
font-size: 1rem;
line-height: 1.625;
line-height: 1.625rem;
font-weight: 400;
}