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(),
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,41 @@
|
|||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-10 col-lg-8 col-xl-7">
|
||||
<funnelSubHeader class="pb-4" cmsWidgetName="FunnelSubHeaderWidget" />
|
||||
<!--
|
||||
... Page code goes here.
|
||||
-->
|
||||
<div class="my-5" ref="unverified-block">
|
||||
<funnelSubHeader cmsWidgetName="SubHeaderWidgetUnverified" alignLeft />
|
||||
<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
|
||||
cmsWidgetName="FunnelFooterWidget"
|
||||
ref="navbar"
|
||||
|
|
@ -28,6 +59,12 @@ import { Form } from "vee-validate";
|
|||
import store from "@/store";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-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 {
|
||||
name: "coverage-statement",
|
||||
|
|
@ -43,6 +80,11 @@ export default {
|
|||
funnelHeader,
|
||||
navbar,
|
||||
funnelSubHeader,
|
||||
customerInstructions,
|
||||
priceDisplay,
|
||||
saveProgressModalQuestion,
|
||||
afterpayBreakout,
|
||||
contentGroupModal,
|
||||
},
|
||||
// Ensure CMS content is fetched during route navigation without depending on `to`/`from`
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
|
|
@ -98,6 +140,38 @@ export default {
|
|||
arePagePrerequisitesValid() {
|
||||
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>
|
||||
|
||||
<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