Merge pull request #3181 from Safelite/feature/CASH-613
Visual build of coverage-statement
This commit is contained in:
commit
bb396078c9
4 changed files with 235 additions and 4 deletions
|
|
@ -62,6 +62,28 @@ function setupMocks() {
|
||||||
navigateWithSaving: jest.fn(),
|
navigateWithSaving: jest.fn(),
|
||||||
navigateWithoutSaving: jest.fn(),
|
navigateWithoutSaving: jest.fn(),
|
||||||
},
|
},
|
||||||
|
store: {
|
||||||
|
getters: {
|
||||||
|
order: {
|
||||||
|
policy: {
|
||||||
|
currentDeductible: 1000,
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: [],
|
||||||
|
promos: [],
|
||||||
|
supportingItems: [],
|
||||||
|
vaps: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mixins: [
|
||||||
|
{
|
||||||
|
methods: {
|
||||||
|
getTotalPriceOfAllLineItemsAndChildParts: jest.fn().mockReturnValue(250),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const wrapper = shallowMount(coverageStatement, mountOptions);
|
const wrapper = shallowMount(coverageStatement, mountOptions);
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,41 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-10 col-lg-8 col-xl-7">
|
<div class="col-12 col-md-10 col-lg-8 col-xl-7">
|
||||||
<funnelSubHeader class="pb-4" cmsWidgetName="FunnelSubHeaderWidget" />
|
<div class="my-5" ref="unverified-block">
|
||||||
<!--
|
<funnelSubHeader cmsWidgetName="SubHeaderWidgetUnverified" alignLeft />
|
||||||
... Page code goes here.
|
<customerInstructions
|
||||||
-->
|
cmsWidgetName="InstructionsWidgetUnverified"
|
||||||
|
v-on="{ textLinkClicked: openModalAction }" />
|
||||||
|
</div>
|
||||||
|
<div class="my-5" ref="verified-block">
|
||||||
|
<funnelSubHeader cmsWidgetName="SubHeaderWidgetVerified" alignLeft />
|
||||||
|
<priceDisplay
|
||||||
|
cmsWidgetName="PriceWidgetVerified"
|
||||||
|
:price="deductibleAmount" />
|
||||||
|
<customerInstructions
|
||||||
|
cmsWidgetName="InstructionsWidgetVerified"
|
||||||
|
v-on="{ textLinkClicked: openModalAction }" />
|
||||||
|
<contentGroupModal ref="OemModal" cmsWidgetName="OemModalWidget" />
|
||||||
|
<afterpayBreakout
|
||||||
|
cmsWidgetName="AfterpayBreakoutWidget"
|
||||||
|
:totalAmount="cashPrice" />
|
||||||
|
</div>
|
||||||
|
<div class="my-5" ref="itac-block">
|
||||||
|
<funnelSubHeader
|
||||||
|
class="mb-4"
|
||||||
|
cmsWidgetName="SubHeaderWidgetItac"
|
||||||
|
alignLeft />
|
||||||
|
<div class="price-compare">
|
||||||
|
<priceDisplay
|
||||||
|
cmsWidgetName="DeductibleWidgetItac"
|
||||||
|
:price="deductibleAmount" />
|
||||||
|
<priceDisplay cmsWidgetName="PriceWidgetItac" :price="cashPrice" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<saveProgressModalQuestion
|
||||||
|
modalWidgetName="SaveProgressModalWidget"
|
||||||
|
modalName="SaveProgressModal"
|
||||||
|
pageName="coverage-statement" />
|
||||||
<navbar
|
<navbar
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
ref="navbar"
|
ref="navbar"
|
||||||
|
|
@ -28,6 +59,12 @@ import { Form } from "vee-validate";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
import customerInstructions from "./customer-instructions/customer-instructions.vue";
|
||||||
|
import priceDisplay from "./price-display/price-display.vue";
|
||||||
|
import saveProgressModalQuestion from "@/fmg-components/save-progress-modal-question/save-progress-modal-question.vue";
|
||||||
|
import afterpayBreakout from "../payment-method/afterpay-breakout/afterpay-breakout.vue";
|
||||||
|
import modal from "@/digital-components/modal/modal";
|
||||||
|
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "coverage-statement",
|
name: "coverage-statement",
|
||||||
|
|
@ -43,6 +80,11 @@ export default {
|
||||||
funnelHeader,
|
funnelHeader,
|
||||||
navbar,
|
navbar,
|
||||||
funnelSubHeader,
|
funnelSubHeader,
|
||||||
|
customerInstructions,
|
||||||
|
priceDisplay,
|
||||||
|
saveProgressModalQuestion,
|
||||||
|
afterpayBreakout,
|
||||||
|
contentGroupModal,
|
||||||
},
|
},
|
||||||
// Ensure CMS content is fetched during route navigation without depending on `to`/`from`
|
// Ensure CMS content is fetched during route navigation without depending on `to`/`from`
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
|
|
@ -98,6 +140,38 @@ export default {
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
openModalAction(modalName) {
|
||||||
|
this.$refs[modalName]?.openModal();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
deductibleAmount() {
|
||||||
|
return this.$store.getters.order.policy.currentDeductible;
|
||||||
|
},
|
||||||
|
cashPrice() {
|
||||||
|
const lineItems = this.$store.getters.order.lineItems;
|
||||||
|
const lineItemsFlattened = [
|
||||||
|
...(lineItems?.glassParts ?? []),
|
||||||
|
...(lineItems?.promos ?? []),
|
||||||
|
...(lineItems?.supportingItems ?? []),
|
||||||
|
...(lineItems?.vaps ?? []),
|
||||||
|
];
|
||||||
|
const price = this.getTotalPriceOfAllLineItemsAndChildParts(lineItemsFlattened, false);
|
||||||
|
|
||||||
|
return price;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.price-compare {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
> :not(:last-child) {
|
||||||
|
padding-right: 1em;
|
||||||
|
margin-right: 1em;
|
||||||
|
border-right: 2px solid $gray-300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<strong>
|
||||||
|
{{ headerText }}
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ol>
|
||||||
|
<li v-for="block in instructionBlocks" :key="block">
|
||||||
|
<span v-for="token in block" :key="token">
|
||||||
|
<span v-if="doesCopyContainTextLink(token)" class="link">
|
||||||
|
<textLink
|
||||||
|
linkType="text"
|
||||||
|
:text="getRouterLinkDisplayTextFromCopy(token)"
|
||||||
|
href="#!"
|
||||||
|
@click-event="
|
||||||
|
$emit('textLinkClicked', getRouterLinkRouteFromCopy(token))
|
||||||
|
"
|
||||||
|
:data-bs-target="'#' + getRouterLinkRouteFromCopy(token)" />
|
||||||
|
</span>
|
||||||
|
<span v-else v-html="token" class="copy"></span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import textLink from "@/ux-components/text-link/text-link";
|
||||||
|
|
||||||
|
import {
|
||||||
|
doesCopyContainTextLink,
|
||||||
|
splitCopyOnCMSPlaceHolder,
|
||||||
|
getRouterLinkRouteFromCopy,
|
||||||
|
getRouterLinkDisplayTextFromCopy,
|
||||||
|
getExternalLink,
|
||||||
|
} from "@/helpers/cms-content-helper";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "customer-instructions",
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
doesCopyContainTextLink,
|
||||||
|
splitCopyOnCMSPlaceHolder,
|
||||||
|
getRouterLinkRouteFromCopy,
|
||||||
|
getRouterLinkDisplayTextFromCopy,
|
||||||
|
getExternalLink,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
headerText() {
|
||||||
|
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
|
||||||
|
},
|
||||||
|
instructionBlocks() {
|
||||||
|
const answers = this.getCmsContent(this.cmsWidgetName, "Answers");
|
||||||
|
|
||||||
|
const instructionBlocksRaw = answers.map((ans) => ans.Text);
|
||||||
|
|
||||||
|
const instructionBlocksAsTokens = instructionBlocksRaw.map((raw) =>
|
||||||
|
splitCopyOnCMSPlaceHolder(raw)
|
||||||
|
);
|
||||||
|
|
||||||
|
return instructionBlocksAsTokens;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
textLink,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(li) {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<template>
|
||||||
|
<div class="mb-4">
|
||||||
|
<div>
|
||||||
|
<strong>
|
||||||
|
{{ headerText }}
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
<div class="price" :class="markAsHigher ? 'red' : 'green'">
|
||||||
|
{{ priceText }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "price-display",
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String,
|
||||||
|
price: Number,
|
||||||
|
markAsHigher: Boolean,
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
computed: {
|
||||||
|
headerText() {
|
||||||
|
return this.getCmsContent(this.cmsWidgetName, "Text");
|
||||||
|
},
|
||||||
|
priceText() {
|
||||||
|
const toFixed = this.price.toFixed(2);
|
||||||
|
return `$${toFixed}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.price {
|
||||||
|
font-size: 1.5em;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
&.green {
|
||||||
|
color: $green-700;
|
||||||
|
border-bottom: 3px solid $red-800;
|
||||||
|
}
|
||||||
|
&.red {
|
||||||
|
color: $red-700;
|
||||||
|
border-bottom: 3px solid $red-800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in a new issue