This commit is contained in:
Sneha 2024-06-20 09:34:32 +05:30
parent eae9ab9375
commit df2755ad62
6 changed files with 206 additions and 4 deletions

View file

@ -4,8 +4,14 @@
:modalId="ModalName"
:footerButtonText="ModalCloseButtonText"
@footer-button-event="footerButtonClick">
<img :src="ModalImage" class="mw-100 d-flex mx-auto mb-4" alt="" />
<h5 class="mb-4" v-html="ModalHeadline"></h5>
<div v-if="ModalName == 'RecalModal'">
<h5 class="mb-4 recal-header" v-html="ModalHeadline"></h5>
<img :src="ModalImage" class="mw-100 d-flex mx-auto mb-4" alt="" />
</div>
<div v-else>
<img :src="ModalImage" class="mw-100 d-flex mx-auto mb-4" alt="" />
<h5 class="mb-4" v-html="ModalHeadline"></h5>
</div>
<p class="fw-bold mb-2 subheader-text" v-html="ModalSubheadertext"></p>
<p class="mb-0" v-html="ModalBodyText"></p>
<p
@ -78,6 +84,10 @@ export default {
.modal-dialog {
.modal-content {
.modal-body {
.recal-header {
line-height: 32px;
text-align: center;
}
.modal-sub-body {
color: $gray-600;
}

View file

@ -8,6 +8,7 @@ import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-h
import { nextTick } from "vue";
import { experimentSettings } from "@/constants/experiments";
import baseMixin from "@/mixins/base-mixin.js";
import { containsLineItemWithPartType } from "../../helpers/service-package-helper";
jest.mock("@/store", () => ({
commit: jest.fn(),
@ -22,6 +23,9 @@ jest.mock("@/helpers/cms-content-helper", () => ({
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
navigateToHeritageFunnel: jest.fn(),
}));
jest.mock("@/helpers/service-package-helper", () => ({
containsLineItemWithPartType: jest.fn(),
}));
jest.mock("@/helpers/promotions-helper", () => ({
revalidatePromosAndValidateQueryStringPromo: jest.fn(() => {

View file

@ -36,12 +36,19 @@
isRequired />
<afterpayModalBanner
v-if="!isInsuranceSelected"
v-if="!isInsuranceSelected && !isRecalibrationOnOrder"
cmsWidgetName="AfterpayModalWidget"
:activePromos="lineItems.promos"
:availableLineItems="availableLineItems"
:lineItems="lineItems" />
<recalDisclaimer
class="my-5"
cmsWidgetName="RecalDisclaimerWidget"
v-if="isRecalibrationOnOrder"
v-on="{ textLinkClicked: openModalAction }"
alertClass="alert-info" />
<promoModalQuestion
class="small mt-4"
v-model="lineItems"
@ -86,6 +93,7 @@ import textBlock from "@/digital-components/text-block/text-block";
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import afterpayModalBanner from "@/layouts/quote/afterpay-modal-banner/afterpay-modal-banner";
import recalDisclaimer from "@/layouts/quote/recal-disclaimer/recal-disclaimer.vue";
import baseMixin from "@/mixins/base-mixin.js";
import experimentMixin from "@/mixins/experiment-mixin.js";
import vehicleQuestionsMixin from "../../mixins/vehicle-questions-mixin";
@ -108,6 +116,8 @@ import { queryStrings } from "@/constants/query-strings";
import { getQuerystringParameter } from "@/helpers/querystring-helper";
import promoModalQuestion from "@/fmg-components/promo-modal-question/promo-modal-question";
import { experimentSettings } from "@/constants/experiments";
import { partTypeStrings } from "@/constants/part-type-strings";
import { containsLineItemWithPartType } from "@/helpers/service-package-helper";
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
export default {
@ -256,6 +266,12 @@ export default {
lineItemsCloneForWatcher() {
return Object.assign({}, this.lineItems);
},
isRecalibrationOnOrder() {
return containsLineItemWithPartType(
partTypeStrings.RECALIBRATION,
this?.availableLineItems
);
},
},
methods: {
openModalAction(modalName) {
@ -405,6 +421,7 @@ export default {
loadingModal,
afterpayModalBanner,
promoModalQuestion,
recalDisclaimer,
},
};
</script>

View file

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

View file

@ -0,0 +1,115 @@
<template>
<div class="alert fade show alert-info recal-alert" role="alert">
<div class="alert-heading">
<span>
<img v-if="hasImage" :src="imageUrl" />
<span class="px-2"> {{ recalHeaderText }}</span>
</span>
</div>
<div>
<span v-for="copy in recalBody" :key="copy">
<span v-if="doesCopyContainTextLink(copy)" class="recal-link">
<textLink
linkType="text"
:text="getRouterLinkDisplayTextFromCopy(copy)"
href="#!"
@click-event="$emit('textLinkClicked', getRouterLinkRouteFromCopy(copy))"
:data-bs-target="'#' + getRouterLinkRouteFromCopy(copy)" />
</span>
<span v-else v-html="copy" class="alert-body"></span>
</span>
</div>
</div>
</template>
<script>
import textLink from "@/ux-components/text-link/text-link";
// Supporting files
import {
doesCopyContainTextLink,
splitCopyOnCMSPlaceHolder,
getRouterLinkRouteFromCopy,
getRouterLinkDisplayTextFromCopy,
getExternalLink,
} from "@/helpers/cms-content-helper";
function getInlineAltText(token) {
const innerTokens = token.split(",");
return innerTokens[1] ?? "";
}
export default {
name: "recal-disclaimer",
props: {
cmsWidgetName: String,
},
data() {
return {};
},
methods: {
getInlineAltText,
doesCopyContainTextLink,
splitCopyOnCMSPlaceHolder,
getRouterLinkRouteFromCopy,
getRouterLinkDisplayTextFromCopy,
getExternalLink,
},
computed: {
imageUrl() {
return this.getCmsContent(this.cmsWidgetName, "Image");
},
hasImage() {
return !!this.imageUrl;
},
recalHeaderText() {
return this.getCmsContent(this.cmsWidgetName, "HeaderText");
},
recalBody() {
return splitCopyOnCMSPlaceHolder(
this.getCmsContent(this.cmsWidgetName, "SubheaderText")
);
},
},
components: {
textLink,
},
};
</script>
<style lang="scss" scoped>
.alert {
text-align: center;
&.recal-alert {
padding: 16px 18px;
}
&.alert-info {
background-color: #e5f1fa;
color: #525656;
.alert-heading {
color: #0070d1;
font-weight: 600;
font-size: 14px;
line-height: 17.3px;
}
svg {
fill: #0070d1;
width: 1rem;
height: 1rem;
}
}
& .alert-heading {
font-size: 14px;
}
.alert-body {
font-size: 14px;
font-weight: 400px;
}
.recal-link {
font-size: 14px;
line-height: 24px;
font-weight: 600;
}
}
</style>

View file

@ -234,10 +234,15 @@ export default {
},
getPackagePrice(packageName, { discountedPrice = false, servicePackageDiscount = false }) {
var lineItemsToPrice = [...this.nullSafeAvailableLineItems];
if (this.isRecalibrationOnOrder) {
lineItemsToPrice = this.nullSafeAvailableLineItems.filter((item) => {
return item.partType != partTypeStrings.RECALIBRATION;
});
}
//remove service package discount part
if (this.isServicePackageDiscountOnOrder) {
lineItemsToPrice = this.nullSafeAvailableLineItems.filter((item) => {
lineItemsToPrice = lineItemsToPrice.filter((item) => {
return item.partType != this.servicePackageDiscountParts[0].partType;
});
}