Merge pull request #838 from Safelite/feature/richardson/SSR-1465
Updates for ITAC Coverage Statement redesign
This commit is contained in:
commit
7b40a8fcb2
7 changed files with 268 additions and 14 deletions
|
|
@ -35,17 +35,30 @@
|
|||
</div>
|
||||
<div class="modal-footer px-5 py-4">
|
||||
<modalButtonMain
|
||||
v-if="useDefaultButton"
|
||||
id="modalbtn"
|
||||
ref="modalButtonMain"
|
||||
isPrimary
|
||||
class="w-100"
|
||||
loaderColor="white"
|
||||
:buttonText="footerButtonText"
|
||||
:class="
|
||||
:class="[
|
||||
(isButtonDisabled || isFooterButtonDisabled) &&
|
||||
'form-test-invalid'
|
||||
"
|
||||
'form-test-invalid',
|
||||
additionalClassesString
|
||||
]"
|
||||
@clickEvent="validateAndEmit" />
|
||||
<button
|
||||
v-if="!useDefaultButton"
|
||||
class="w-100 btn d-flex align-items-center justify-content-center delay"
|
||||
:class="[
|
||||
(isButtonDisabled || isFooterButtonDisabled) &&
|
||||
'form-test-invalid',
|
||||
additionalClassesString
|
||||
]"
|
||||
@click="validateAndEmit">
|
||||
<span class="m-0">{{ footerButtonText }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -73,7 +86,15 @@ export default {
|
|||
onModalClosedCallback: {
|
||||
type: Function
|
||||
},
|
||||
isButtonDisabled: Boolean
|
||||
isButtonDisabled: Boolean,
|
||||
useDefaultButton: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
additionalClassesString: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
emits: ['footer-button-event', 'isModalOpened'],
|
||||
setup(props) {
|
||||
|
|
@ -181,6 +202,16 @@ export default {
|
|||
z-index: 5;
|
||||
border-radius: 0;
|
||||
background-color: $gray-100;
|
||||
|
||||
> .navigation-link {
|
||||
color: $black;
|
||||
font-weight: $font-weight-bold;
|
||||
line-height: 1.625rem;
|
||||
white-space: nowrap;
|
||||
align-items: center;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: .3125rem;
|
||||
}
|
||||
}
|
||||
&.modal-component {
|
||||
.modal-dialog {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
exports[`coverageStatement.vue returns the initial data 1`] = `
|
||||
Object {
|
||||
"CANCEL_CLAIM_REF_NAME": "CancelClaimModal",
|
||||
"DEDUCTIBLE_MODAL_REF_NAME": "DeductibleModal",
|
||||
"RECAL_MODAL_REF_NAME": "RecalModal",
|
||||
"SITE_FOOTER_REF_NAME": "siteFooter",
|
||||
|
|
@ -12,6 +13,7 @@ Object {
|
|||
},
|
||||
"selectedProvider": "",
|
||||
"widget": Object {
|
||||
"disclaimerText": "DisclaimerWidget",
|
||||
"explanatoryText": "ExplanatoryTextWidget",
|
||||
"nextStep": "NextStepsWidget",
|
||||
"serviceProviderQuestion": "ServiceProviderQuestion",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`returns the initial data 1`] = `
|
||||
Object {
|
||||
"isLoaderDisplayed": false,
|
||||
"isModalOpened": false,
|
||||
}
|
||||
`;
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import cancelClaimModal from '@/layouts/coverage-statement/cancel-claim-modal/cancel-claim-modal.vue';
|
||||
|
||||
const mockDataStrings = {
|
||||
cmsBodyText: 'Some Body Text from CMS',
|
||||
cmsBodyText2: 'Some Text for Button in Body from CMS',
|
||||
cmsFooterText: 'Some Footer Text from CMS',
|
||||
cmsHeaderText: 'Some Header Text from CMS'
|
||||
};
|
||||
|
||||
const mockCmsContent = {
|
||||
BodyText: mockDataStrings.cmsBodyText,
|
||||
BodyText2: mockDataStrings.cmsBodyText2,
|
||||
FooterText: mockDataStrings.cmsFooterText,
|
||||
HeaderText: mockDataStrings.cmsHeaderText
|
||||
};
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((_, cmsFieldName) => mockCmsContent[cmsFieldName])
|
||||
}
|
||||
};
|
||||
|
||||
function setupMocks() {
|
||||
const wrapper = shallowMount(cancelClaimModal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: 'test'
|
||||
},
|
||||
attachTo: document.body
|
||||
});
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
test('returns the initial data', () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$data).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('Computed', () => {
|
||||
test('Should get modal body text from Widget CMS', () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks();
|
||||
|
||||
// Act
|
||||
const modalHeader = wrapper.vm.modalBodyText;
|
||||
|
||||
// Assert
|
||||
expect(modalHeader).toBe(mockDataStrings.cmsBodyText);
|
||||
});
|
||||
|
||||
test('Should get modal body text2 from Widget CMS', () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks();
|
||||
|
||||
// Act
|
||||
const modalHeader = wrapper.vm.modalBodyText2;
|
||||
|
||||
// Assert
|
||||
expect(modalHeader).toBe(mockDataStrings.cmsBodyText2);
|
||||
});
|
||||
|
||||
test('Should get modal footer text from Widget CMS', () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks();
|
||||
|
||||
// Act
|
||||
const modalHeader = wrapper.vm.modalFooterText;
|
||||
|
||||
// Assert
|
||||
expect(modalHeader).toBe(mockDataStrings.cmsFooterText);
|
||||
});
|
||||
|
||||
test('Should get modal header text from Widget CMS', () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks();
|
||||
|
||||
// Act
|
||||
const modalHeader = wrapper.vm.modalHeaderText;
|
||||
|
||||
// Assert
|
||||
expect(modalHeader).toBe(mockDataStrings.cmsHeaderText);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<transition
|
||||
name="fade"
|
||||
mode="out-in">
|
||||
<div class="cancel-claim-modal-container">
|
||||
<modal
|
||||
ref="cancelClaimModal"
|
||||
:headerText="modalHeaderText"
|
||||
:footerButtonText="modalFooterText"
|
||||
additionalClassesString="navigation-link"
|
||||
:useDefaultButton="false"
|
||||
@isModalOpened="setModalStatus"
|
||||
@footerButtonEvent="cancelClaimConfirmation">
|
||||
<div v-html="modalBodyText"></div>
|
||||
<button
|
||||
id="btnContinueReferral"
|
||||
type="button"
|
||||
:aria-disabled="false"
|
||||
class="btn btn-primary btn-override
|
||||
align-items-center justify-content-center d-inline-flex mt-4 py-3 px-4 delay w-100"
|
||||
@click="returnToClaim">
|
||||
{{ modalBodyText2 }}
|
||||
<loader
|
||||
v-if="isLoaderDisplayed"
|
||||
class="ms-2 button-loader" />
|
||||
</button>
|
||||
</modal>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import loader from '@/ux-components/loader/loader.vue';
|
||||
import modal from '@/digital-components/modal/modal.vue';
|
||||
|
||||
export default {
|
||||
name: 'cancel-claim-modal',
|
||||
components: {
|
||||
loader,
|
||||
modal
|
||||
},
|
||||
emits: ['cancel-claim-confirmation', 'return-to-claim'],
|
||||
data() {
|
||||
return {
|
||||
isLoaderDisplayed: false,
|
||||
isModalOpened: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
modalBodyText() {
|
||||
return this.getCmsContent('CancelClaimModal', 'BodyText');
|
||||
},
|
||||
modalBodyText2() {
|
||||
return this.getCmsContent('CancelClaimModal', 'BodyText2');
|
||||
},
|
||||
modalHeaderText() {
|
||||
return this.getCmsContent('CancelClaimModal', 'HeaderText');
|
||||
},
|
||||
modalFooterText() {
|
||||
return this.getCmsContent('CancelClaimModal', 'FooterText');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openModal() {
|
||||
this.$refs.cancelClaimModal.openModal();
|
||||
},
|
||||
removeLoader() {
|
||||
this.isLoaderDisplayed = false;
|
||||
},
|
||||
setModalStatus(isOpened) {
|
||||
this.isModalOpened = isOpened;
|
||||
},
|
||||
closeModal() {
|
||||
this.$refs.cancelClaimModal.closeModal();
|
||||
},
|
||||
cancelClaimConfirmation() {
|
||||
this.$emit('cancel-claim-confirmation');
|
||||
},
|
||||
returnToClaim() {
|
||||
this.$emit('return-to-claim');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.btn {
|
||||
&.btn-primary {
|
||||
position: relative;
|
||||
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
|
||||
border: none;
|
||||
border-radius: $border-radius-lg;
|
||||
color: $white;
|
||||
justify-content: center;
|
||||
font-weight: $font-weight-bold;
|
||||
@media (hover: hover) {
|
||||
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -27,6 +27,7 @@ jest.mock('@/helpers/cms-content-helper', () => ({
|
|||
}));
|
||||
|
||||
const SAFELITE_PROVIDER = 'Safelite';
|
||||
const CANCEL_CLAIM_REF_NAME = 'CancelClaimModal';
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
|
|
@ -91,6 +92,7 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
|
|||
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
|
||||
|
||||
const wrapper = shallowMount(coverageStatement, mountOptions);
|
||||
wrapper.vm.$refs[CANCEL_CLAIM_REF_NAME].openModal = jest.fn();
|
||||
return { wrapper };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@
|
|||
isRequired
|
||||
:validationRules="rules.selectionRequired">
|
||||
</buttonQuestion>
|
||||
<text-block
|
||||
<textBlock
|
||||
v-if="isQuoteDisplayed"
|
||||
cmsWidgetName="DisclaimerWidget"
|
||||
:customText="disclaimerText"
|
||||
typeStyle="caption" />
|
||||
<siteFooter
|
||||
:ref="SITE_FOOTER_REF_NAME"
|
||||
|
|
@ -93,6 +93,10 @@
|
|||
:ref="DEDUCTIBLE_MODAL_REF_NAME"
|
||||
cmsWidgetName="DeductibleModal"
|
||||
class="deductible-modal" />
|
||||
<cancelClaimModal
|
||||
:ref="CANCEL_CLAIM_REF_NAME"
|
||||
@cancelClaimConfirmation="cancelClaim"
|
||||
@returnToClaim="continueClaim" />
|
||||
</Form>
|
||||
</template>
|
||||
<script>
|
||||
|
|
@ -101,6 +105,7 @@ 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 alert from '@/ux-components/alert/alert.vue';
|
||||
import cancelClaimModal from '@/layouts/coverage-statement/cancel-claim-modal/cancel-claim-modal.vue';
|
||||
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
|
||||
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
||||
import textBlock from '@/digital-components/text-block/text-block.vue';
|
||||
|
|
@ -127,6 +132,7 @@ import { getPriceOfLineItems } from '@/helpers/price-calculator';
|
|||
import coverageStatuses from '@/constants/coverage-statuses';
|
||||
import coverageType from '@/constants/coverage-type';
|
||||
|
||||
const CANCEL_CLAIM_REF_NAME = 'CancelClaimModal';
|
||||
const SAFELITE_PROVIDER = 'Safelite';
|
||||
const RECAL_MODAL_REF_NAME = 'RecalModal';
|
||||
const DEDUCTIBLE_MODAL_REF_NAME = 'DeductibleModal';
|
||||
|
|
@ -140,6 +146,7 @@ export default {
|
|||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
Form,
|
||||
alert,
|
||||
cancelClaimModal,
|
||||
contentGroupModal,
|
||||
buttonQuestion,
|
||||
textBlock
|
||||
|
|
@ -164,7 +171,7 @@ export default {
|
|||
}
|
||||
];
|
||||
|
||||
const { vehicle, isITAC, isDeductible, serviceLocation } = store;
|
||||
const { isITAC, isDeductible, serviceLocation } = store;
|
||||
if (isITAC || isDeductible) {
|
||||
promiseResultMap.push({
|
||||
resultKey: 'getFinalDeductible',
|
||||
|
|
@ -205,12 +212,14 @@ export default {
|
|||
selectionRequired: globalRules.OPTION_REQUIRED
|
||||
},
|
||||
widget: {
|
||||
disclaimerText: 'DisclaimerWidget',
|
||||
subheader: 'SiteSubHeaderWidget',
|
||||
verifiedItacAlert: 'VerifiedITACAlert',
|
||||
explanatoryText: 'ExplanatoryTextWidget',
|
||||
nextStep: 'NextStepsWidget',
|
||||
serviceProviderQuestion: 'ServiceProviderQuestion'
|
||||
},
|
||||
CANCEL_CLAIM_REF_NAME,
|
||||
RECAL_MODAL_REF_NAME,
|
||||
DEDUCTIBLE_MODAL_REF_NAME,
|
||||
SITE_FOOTER_REF_NAME
|
||||
|
|
@ -237,7 +246,6 @@ export default {
|
|||
widgetFields.ALERT_WIDGET.BODY_TEXT
|
||||
)?.replaceAll(
|
||||
'{custom:costSavings}',
|
||||
|
||||
formatAmountInDollars(itacCostSavings)
|
||||
);
|
||||
},
|
||||
|
|
@ -247,6 +255,12 @@ export default {
|
|||
widgetFields.SUB_HEADER_WIDGET.SECONDARY_TEXT
|
||||
);
|
||||
},
|
||||
disclaimerText() {
|
||||
return this.getCmsContent(this.widget.disclaimerText, widgetFields.TEXT_BLOCK_WIDGET.TEXT)?.replaceAll(
|
||||
'{custom:disclaimerAmount}',
|
||||
formatAmountInDollars(this.totalServicePrice)
|
||||
);
|
||||
},
|
||||
explanatoryText() {
|
||||
return this.getTextFromCmsWithCustomIfStatements(
|
||||
this.widget.explanatoryText,
|
||||
|
|
@ -331,11 +345,9 @@ export default {
|
|||
},
|
||||
watch: {
|
||||
selectedProvider() {
|
||||
const buttonText =
|
||||
this.selectedProvider === SAFELITE_PROVIDER
|
||||
? 'Continue with Safelite'
|
||||
: 'Continue';
|
||||
this.$refs[SITE_FOOTER_REF_NAME].updateButtonText(buttonText);
|
||||
if (this.selectedProvider && this.selectedProvider !== SAFELITE_PROVIDER) {
|
||||
this.$refs[this.CANCEL_CLAIM_REF_NAME].openModal();
|
||||
}
|
||||
},
|
||||
nextStepsBody(newValue, oldValue) {
|
||||
if (newValue !== oldValue) {
|
||||
|
|
@ -462,7 +474,16 @@ export default {
|
|||
setBaseServiceLineItems(lineItems) {
|
||||
this.baseServiceLineItems = lineItems;
|
||||
},
|
||||
formatAmountInDollars
|
||||
formatAmountInDollars,
|
||||
cancelClaim() {
|
||||
useMainStore().updateIsSafeliteProvider(false);
|
||||
useMainStore().setBailout(bailoutMessage.RequestCallback());
|
||||
this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP);
|
||||
},
|
||||
continueClaim() {
|
||||
useMainStore().updateIsSafeliteProvider(true);
|
||||
this.navigateWithScenario(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in a new issue