Merge pull request #1097 from Safelite/feature/kroell/INSR-8105
INSR-8105: Afterpay modal on coverage-statement page
This commit is contained in:
commit
0834143cdf
3 changed files with 231 additions and 1 deletions
|
|
@ -0,0 +1,116 @@
|
|||
<template>
|
||||
<div class="afterpay-modal-banner" role="alert">
|
||||
<component
|
||||
src="https://js.squarecdn.com/square-marketplace.js"
|
||||
async
|
||||
:is="'script'">
|
||||
</component>
|
||||
<div class="afterpay-content">
|
||||
<span class="afterpay-copy" v-html="afterpayCopy"></span>
|
||||
<span class="afterpay-copy">{{ afterpayPaymentAmount }}</span>
|
||||
<span class="afterpay-copy" v-html="afterpayCopyTwo"></span>
|
||||
<img :src="imageUrl" class="image" alt="Afterpay logo"/>
|
||||
<span class="afterpay-copy">. </span>
|
||||
<a
|
||||
id="afterpay-learnmore"
|
||||
href="#"
|
||||
data-afterpay-modal="en_US"
|
||||
data-bind="click:afterpayLearnMore"
|
||||
class="afterpay-learn-more"
|
||||
@click.prevent>
|
||||
<span>Learn more</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { setupModalLinks } from "@/helpers/cms-content-helper";
|
||||
import { formatAmountInDollars } from '@/helpers/text-helper.js';
|
||||
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||
import { useMainStore } from '@/store/index.js';
|
||||
|
||||
export default {
|
||||
name: "afterpay-banner",
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
cmsWidgetName: String,
|
||||
totalServicePrice: Number
|
||||
},
|
||||
setup() {
|
||||
const mainStore = useMainStore();
|
||||
return { mainStore };
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
imageUrl() {
|
||||
return this.getCmsContent(this.cmsWidgetName, widgetFields.CONTENT_GROUP_WIDGET.IMAGE);
|
||||
},
|
||||
afterpayCopy() {
|
||||
return this.getCmsContent(this.cmsWidgetName, widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT);
|
||||
},
|
||||
afterpayCopyTwo() {
|
||||
return this.getCmsContent(this.cmsWidgetName, widgetFields.CONTENT_GROUP_WIDGET.SUBHEADER_TEXT);
|
||||
},
|
||||
deductibleValue() {
|
||||
return this.mainStore.currentDeductible;
|
||||
},
|
||||
afterpayPaymentAmount() {
|
||||
return this.calculateAfterpayPaymentAmount;
|
||||
},
|
||||
isDeductibleScenario() {
|
||||
return this.mainStore.isVerified && this.mainStore.isDeductible;
|
||||
},
|
||||
calculateAfterpayPaymentAmount() {
|
||||
const totalAmount = this.isDeductibleScenario ? this.deductibleValue : this.totalServicePrice;
|
||||
const afterpayAmount = (totalAmount / 4).toFixed(2);
|
||||
return formatAmountInDollars(afterpayAmount);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.afterpay-modal-banner {
|
||||
background-color: $blue-100;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.5rem 1rem 0.5rem 1rem;
|
||||
border-radius: 0.25rem;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.afterpay-content {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.afterpay-copy {
|
||||
font-size: 0.875rem;
|
||||
color: $blue-700;
|
||||
font-weight: $font-weight-bold;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
.image-and-link {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.image {
|
||||
border: 0;
|
||||
height: 20px;
|
||||
width: 83px;
|
||||
}
|
||||
|
||||
:deep(a.afterpay-learn-more) {
|
||||
color: $blue-700;
|
||||
fill: $blue-700;
|
||||
text-decoration: underline;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -439,6 +439,109 @@ describe('coverageStatement.vue', () => {
|
|||
expect(result).toBe(expected);
|
||||
});
|
||||
});
|
||||
describe('displayAfterpayBanner', () => {
|
||||
test('returns true if ITAC', () => {
|
||||
// Arrange
|
||||
const mainInitialState = {
|
||||
order: {
|
||||
insuranceCoverage: {
|
||||
coverageStatus: coverageStatuses.VERIFIED,
|
||||
coverageType: coverageType.ITAC
|
||||
}
|
||||
}
|
||||
};
|
||||
const { wrapper } = getMountedComponent(mainInitialState);
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.displayAfterpayBanner;
|
||||
|
||||
// Assert
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
test('returns true if No Comp', () => {
|
||||
// Arrange
|
||||
const mainInitialState = {
|
||||
order: {
|
||||
insuranceCoverage: {
|
||||
coverageStatus: coverageStatuses.VERIFIED,
|
||||
coverageType: coverageType.NO_COMP
|
||||
}
|
||||
}
|
||||
};
|
||||
const { wrapper } = getMountedComponent(mainInitialState);
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.displayAfterpayBanner;
|
||||
|
||||
// Assert
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
test('returns true if deductible is > $0', () => {
|
||||
// Arrange
|
||||
const mainInitialState = {
|
||||
order: {
|
||||
insuranceCoverage: {
|
||||
coverageStatus: coverageStatuses.VERIFIED,
|
||||
coverageType: coverageType.Deductible
|
||||
},
|
||||
damage: {
|
||||
isRepair: false
|
||||
},
|
||||
currentDeductible: {
|
||||
replace: 500
|
||||
}
|
||||
}
|
||||
};
|
||||
const { wrapper } = getMountedComponent(mainInitialState);
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.displayAfterpayBanner;
|
||||
|
||||
// Assert
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
test('returns false if deductible is <= $0', () => {
|
||||
// Arrange
|
||||
const mainInitialState = {
|
||||
order: {
|
||||
insuranceCoverage: {
|
||||
coverageStatus: coverageStatuses.VERIFIED,
|
||||
coverageType: coverageType.Deductible
|
||||
},
|
||||
damage: {
|
||||
isRepair: false
|
||||
},
|
||||
currentDeductible: {
|
||||
replace: 0
|
||||
}
|
||||
}
|
||||
};
|
||||
const { wrapper } = getMountedComponent(mainInitialState);
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.displayAfterpayBanner;
|
||||
|
||||
// Assert
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
test('returns false if Unverified', () => {
|
||||
// Arrange
|
||||
const mainInitialState = {
|
||||
order: {
|
||||
insuranceCoverage: {
|
||||
coverageStatus: coverageStatuses.UNVERIFIED,
|
||||
}
|
||||
}
|
||||
};
|
||||
const { wrapper } = getMountedComponent(mainInitialState);
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.displayAfterpayBanner;
|
||||
|
||||
// Assert
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('methods', () => {
|
||||
describe('arePagePrerequisitesValid', () => {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,10 @@
|
|||
class="d-flex justify-content-center cost mb-0 cost-underline">
|
||||
{{ formatAmountInDollars(totalServicePrice) }}
|
||||
</div>
|
||||
<afterpayModalBanner
|
||||
v-if="displayAfterpayBanner"
|
||||
cmsWidgetName="AfterpayModalWidget"
|
||||
:totalServicePrice="totalServicePrice" />
|
||||
<buttonMain
|
||||
ref="buttonMain"
|
||||
class="full-width-button mt-5 mb-5"
|
||||
|
|
@ -118,6 +122,7 @@ import textBlock from '@/digital-components/text-block/text-block.vue';
|
|||
import textLink from '@/ux-components/text-link/text-link.vue';
|
||||
import buttonMain from '@/ux-components/button-main/button-main.vue';
|
||||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||
import afterpayModalBanner from '@/layouts/coverage-statement/afterpay-modal-banner/afterpay-modal-banner.vue';
|
||||
// Import Supporting Files
|
||||
import {
|
||||
fetchCmsContentForPage,
|
||||
|
|
@ -152,7 +157,8 @@ export default {
|
|||
textBlock,
|
||||
textLink,
|
||||
siteFooter,
|
||||
cancelClaimModal
|
||||
cancelClaimModal,
|
||||
afterpayModalBanner
|
||||
},
|
||||
mixins: [baseFormMixin, vehicleQuestionsMixin],
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
|
|
@ -339,6 +345,11 @@ export default {
|
|||
return 'centered-back-button';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
displayAfterpayBanner() {
|
||||
return this.isITACQuoteVisible
|
||||
|| this.isNoCompQuoteVisible
|
||||
|| (this.showDeductibleOnly && this.deductibleValue > 0);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue