Merge branch 'release/2025.04.24' into feature/CASH-498
This commit is contained in:
commit
5b8e1d55c8
7 changed files with 587 additions and 6 deletions
|
|
@ -3,6 +3,7 @@ const experimentUniverses = {
|
||||||
RECAL_PRICE_REMOVAL: "NextGen_RecalPriceRemoval",
|
RECAL_PRICE_REMOVAL: "NextGen_RecalPriceRemoval",
|
||||||
MSR: "MSR",
|
MSR: "MSR",
|
||||||
IGQ_SkipQuote: "NextGen_IGQSkipToInsurance",
|
IGQ_SkipQuote: "NextGen_IGQSkipToInsurance",
|
||||||
|
AFTERPAY_BREAKOUT_DISPLAY: "AfterpayBreakoutDisplay",
|
||||||
};
|
};
|
||||||
|
|
||||||
const experimentSettings = {
|
const experimentSettings = {
|
||||||
|
|
@ -24,6 +25,7 @@ const experimentSettings = {
|
||||||
PRICING_BY_DAY: "DisplayPricingByDay",
|
PRICING_BY_DAY: "DisplayPricingByDay",
|
||||||
FOSTER_LOVE: "DisplayFosterLove",
|
FOSTER_LOVE: "DisplayFosterLove",
|
||||||
SKIP_TO_INSURANCE: "SkipToInsurance",
|
SKIP_TO_INSURANCE: "SkipToInsurance",
|
||||||
|
DISPLAY_AFTERPAY_BREAKOUT_DISPLAY: "Display_AfterpayBreakoutDisplay",
|
||||||
};
|
};
|
||||||
|
|
||||||
const experimentTriggers = {
|
const experimentTriggers = {
|
||||||
|
|
|
||||||
474
src/experiment-components/service-package-radio-for-afterpay.vue
Normal file
474
src/experiment-components/service-package-radio-for-afterpay.vue
Normal file
|
|
@ -0,0 +1,474 @@
|
||||||
|
<template>
|
||||||
|
<baseInputButton v-bind="$props" @buttonClicked="handleAnswerChange" v-model="selectedValue">
|
||||||
|
<div
|
||||||
|
class="package-label"
|
||||||
|
:class="[
|
||||||
|
this.buttonLabelSubCopy ? 'has-subheader' : '',
|
||||||
|
this.additionalButtonData.isInsuranceSelected ? 'is-insurance' : '',
|
||||||
|
]"
|
||||||
|
for="testradio">
|
||||||
|
<div class="package-specs">
|
||||||
|
<div>
|
||||||
|
<p class="m-0">
|
||||||
|
<span v-html="this.buttonLabel"></span>
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="sub-label m-0"
|
||||||
|
v-if="this.buttonLabelSubCopy"
|
||||||
|
v-html="this.buttonLabelSubCopy"></p>
|
||||||
|
</div>
|
||||||
|
<div class="hide-when-closed">
|
||||||
|
<!-- Parse the body text containing <ul> with logic -->
|
||||||
|
<ul>
|
||||||
|
<li v-for="listItem in this.arrayOfListItemsFromBodyText" :key="listItem">
|
||||||
|
<!-- no textLink -->
|
||||||
|
<span
|
||||||
|
v-if="!doesCopyContainTextLink(listItem)"
|
||||||
|
v-html="listItem"></span>
|
||||||
|
<!-- with textLink -->
|
||||||
|
<template
|
||||||
|
v-else
|
||||||
|
v-for="copy in splitCopyOnCMSPlaceHolder(listItem)"
|
||||||
|
:key="copy">
|
||||||
|
<span v-if="!doesCopyContainTextLink(copy)" v-html="copy"></span>
|
||||||
|
<span v-else>
|
||||||
|
<textLink
|
||||||
|
linkType="text"
|
||||||
|
:text="getRouterLinkDisplayTextFromCopy(copy)"
|
||||||
|
href="#!"
|
||||||
|
@click-event="
|
||||||
|
$emit('buttonEvent', {
|
||||||
|
eventName: 'openModal',
|
||||||
|
args: getRouterLinkRouteFromCopy(copy),
|
||||||
|
})
|
||||||
|
"
|
||||||
|
:data-bs-target="'#' + getRouterLinkRouteFromCopy(copy)" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<!-- End of body text parsing -->
|
||||||
|
<div
|
||||||
|
class="package-footer fw-bold caption ms-n4 mt-4"
|
||||||
|
v-if="this.buttonFooterCopy"
|
||||||
|
v-html="this.buttonFooterCopy"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
this.additionalButtonData.servicePackageDiscount &&
|
||||||
|
this.additionalButtonData.Text
|
||||||
|
"
|
||||||
|
class="special-save-box">
|
||||||
|
<span v-html="this.additionalButtonData.Text"></span>
|
||||||
|
</div>
|
||||||
|
<span class="pricing-info">
|
||||||
|
<div
|
||||||
|
class="insurance-pricing"
|
||||||
|
v-if="this.additionalButtonData.isInsuranceSelected">
|
||||||
|
<span
|
||||||
|
class="strikethrough-price"
|
||||||
|
v-if="shouldDisplayStrikeThroughPrice"
|
||||||
|
v-html="this.additionalButtonData.strikeThroughPrice"></span>
|
||||||
|
<span v-html="this.buttonAuxillaryCopy"></span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<span v-html="afterpayPrice()"></span>
|
||||||
|
<span class="afterpay-breakout">
|
||||||
|
<span>in 4 interest-free payments</span>
|
||||||
|
<div>
|
||||||
|
or
|
||||||
|
<span v-html="this.buttonAuxillaryCopy"></span>
|
||||||
|
<span
|
||||||
|
class="strikethrough-price"
|
||||||
|
v-if="shouldDisplayStrikeThroughPrice"
|
||||||
|
v-html="this.additionalButtonData.strikeThroughPrice"></span>
|
||||||
|
in single payment
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</baseInputButton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import baseInputButton from "@/digital-components/base-input-button/base-input-button";
|
||||||
|
import textLink from "@/ux-components/text-link/text-link";
|
||||||
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
import {
|
||||||
|
getRouterLinkDisplayTextFromCopy,
|
||||||
|
getRouterLinkRouteFromCopy,
|
||||||
|
splitCopyOnCMSPlaceHolder,
|
||||||
|
doesCopyContainTextLink,
|
||||||
|
} from "@/helpers/cms-content-helper";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "servicePackageRadio",
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
components: {
|
||||||
|
baseInputButton,
|
||||||
|
textLink,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
arrayOfListItemsFromBodyText() {
|
||||||
|
return this.getArrayOfListItemsFromRawCmsCopy(this.buttonBodyCopy);
|
||||||
|
},
|
||||||
|
shouldDisplayStrikeThroughPrice() {
|
||||||
|
const displayPrice = this.buttonAuxillaryCopy.substring(
|
||||||
|
this.buttonAuxillaryCopy.indexOf("$")
|
||||||
|
);
|
||||||
|
return displayPrice != this.additionalButtonData.strikeThroughPrice;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getRouterLinkDisplayTextFromCopy,
|
||||||
|
getRouterLinkRouteFromCopy,
|
||||||
|
splitCopyOnCMSPlaceHolder,
|
||||||
|
doesCopyContainTextLink,
|
||||||
|
stripUlTagFromCopy(copy) {
|
||||||
|
const regex = /(?:<ul(?:.*?)>)|(?:<\/ul>)/g;
|
||||||
|
return copy.replace(regex, "");
|
||||||
|
},
|
||||||
|
getArrayOfListItemsFromRawCmsCopy(copy) {
|
||||||
|
const withoutUlTags = this.stripUlTagFromCopy(copy);
|
||||||
|
return withoutUlTags
|
||||||
|
.split(/(?:<li(?:.*?)>)|(?:<\/li>)/g)
|
||||||
|
.filter((lineItem) => lineItem);
|
||||||
|
},
|
||||||
|
afterpayPrice() {
|
||||||
|
const decimalPrice = parseFloat(this.buttonAuxillaryCopy.replace("$", ""));
|
||||||
|
return "$" + (decimalPrice / 4).toFixed(2);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.package-main {
|
||||||
|
.package-wrapper {
|
||||||
|
margin: 1rem 0;
|
||||||
|
&:first-child {
|
||||||
|
margin: 1rem 0 0 0;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
margin: 1rem 0 0 0;
|
||||||
|
}
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
margin: 1rem 0.5rem 0 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
&:first-child {
|
||||||
|
margin: 1rem 0.5rem 0 0;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
margin: 1rem 0 0 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"] {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
left: -9999px;
|
||||||
|
|
||||||
|
+ .package-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border: 1px solid $gray-300;
|
||||||
|
box-shadow:
|
||||||
|
0px 4px 8px -4px rgba(0, 0, 0, 0.15),
|
||||||
|
0px 4px 24px -8px rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 52px;
|
||||||
|
max-height: 126px;
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
max-height: 500px;
|
||||||
|
padding-bottom: 4.75rem;
|
||||||
|
}
|
||||||
|
@include media-breakpoint-down(md) {
|
||||||
|
padding-bottom: 4rem;
|
||||||
|
}
|
||||||
|
transition: max-height 0.25s ease-in;
|
||||||
|
|
||||||
|
&.is-insurance {
|
||||||
|
padding-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.has-subheader {
|
||||||
|
min-height: 150px;
|
||||||
|
|
||||||
|
&.is-insurance {
|
||||||
|
min-height: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .package-specs {
|
||||||
|
& > div:first-of-type {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
position: relative;
|
||||||
|
top: 5px;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid $gray-500;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
min-width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 15px;
|
||||||
|
top: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
min-width: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
+ .package-label {
|
||||||
|
&:before {
|
||||||
|
border: 1px solid #8e9292;
|
||||||
|
box-shadow:
|
||||||
|
0px 0px 0px 4px #9fcee6,
|
||||||
|
0px 1px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:checked {
|
||||||
|
+ .package-label {
|
||||||
|
.package-specs {
|
||||||
|
max-height: 1000px;
|
||||||
|
|
||||||
|
.sub-label {
|
||||||
|
background-color: $green-200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ .package-label {
|
||||||
|
.package-specs {
|
||||||
|
.hide-when-closed {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ .package-label {
|
||||||
|
background-color: $blue-100;
|
||||||
|
border: 1px solid $blue;
|
||||||
|
max-height: 500px;
|
||||||
|
.special-save-box {
|
||||||
|
background-color: $green-200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ .package-label {
|
||||||
|
&:before {
|
||||||
|
box-shadow: 0px 0px 0px 1px $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ .package-label {
|
||||||
|
&:after {
|
||||||
|
background: $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
+ .package-label {
|
||||||
|
&:before {
|
||||||
|
border: 2px solid $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.package-footer {
|
||||||
|
color: $red;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package-specs {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&.sub-label {
|
||||||
|
color: $green;
|
||||||
|
background-color: $green-100;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
&.service-package-discount {
|
||||||
|
color: $green;
|
||||||
|
text-align: end;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
align-self: flex-start;
|
||||||
|
div.strikethrough-discount-price {
|
||||||
|
text-decoration: line-through;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 20px;
|
||||||
|
color: $gray-550;
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.discount-price {
|
||||||
|
color: $green;
|
||||||
|
}
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0.75rem;
|
||||||
|
left: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
margin: 1rem 0 0 -5px;
|
||||||
|
padding: 0;
|
||||||
|
li {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.714;
|
||||||
|
color: $gray-550;
|
||||||
|
a {
|
||||||
|
line-height: 1.714;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideaway {
|
||||||
|
from {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateY(40px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-when-closed {
|
||||||
|
display: none;
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.discount-text {
|
||||||
|
height: 2rem;
|
||||||
|
display: flex;
|
||||||
|
border-top-right-radius: 0.5rem;
|
||||||
|
border-top-left-radius: 0.5rem;
|
||||||
|
background-color: $green;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
color: white;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.75px;
|
||||||
|
}
|
||||||
|
.special-save-box {
|
||||||
|
background-color: $green-100;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin: 0.5rem auto 1rem -1.25rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
span {
|
||||||
|
color: $green;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pricing-info {
|
||||||
|
color: $green;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0.75rem;
|
||||||
|
left: 0;
|
||||||
|
width: calc(100% - 1.25rem);
|
||||||
|
margin-left: 1.25rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 20px;
|
||||||
|
|
||||||
|
span.strikethrough-price {
|
||||||
|
text-decoration: line-through;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: $gray-550;
|
||||||
|
margin-left: 0.25rem;
|
||||||
|
}
|
||||||
|
span.afterpay-breakout {
|
||||||
|
color: $gray-550;
|
||||||
|
font-weight: initial;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
margin-left: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
|
||||||
|
& > span:first-of-type {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -53,11 +53,33 @@ import { Form, defineRule } from "vee-validate";
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
import { applicationConfig } from "@/constants/application-config";
|
import { applicationConfig } from "@/constants/application-config";
|
||||||
|
import experimentMixin from "@/mixins/experiment-mixin.js";
|
||||||
|
import { experimentSettings } from "@/constants/experiments";
|
||||||
|
import { partNumberStrings } from "@/constants/part-number-strings";
|
||||||
|
import { deepClone } from "@/helpers/object-helper";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "insurance-company",
|
name: "insurance-company",
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
|
// Remove any Pricing By Day lineItems before going to Heritage insurance
|
||||||
|
const isPricingByDayExperiment = experimentMixin.methods.hasSettingEqualTo(
|
||||||
|
experimentSettings.PRICING_BY_DAY,
|
||||||
|
"true"
|
||||||
|
);
|
||||||
|
if (isPricingByDayExperiment) {
|
||||||
|
const lineItems = deepClone(store.getters.order.lineItems);
|
||||||
|
const supportingItemsWithoutPricingByDay =
|
||||||
|
baseMixin.methods.filterOutCertainPartTypesOrNumbers(lineItems.supportingItems, {
|
||||||
|
partNumbersToRemove: [partNumberStrings.PRICING_BY_DAY_UPCHARGE],
|
||||||
|
});
|
||||||
|
baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
|
||||||
|
supportingItemsWithoutPricingByDay,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
const insuranceCompanyListPromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
const insuranceCompanyListPromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
<div class="alert fade show my-2 py-2 border-0 alert-info" role="alert">
|
<div class="alert fade show my-2 py-2 border-0 alert-info" role="alert">
|
||||||
<component :is="'script'" src="https://js.afterpay.com/afterpay-1.x.js" async></component>
|
<component :is="'script'" src="https://js.afterpay.com/afterpay-1.x.js" async></component>
|
||||||
|
|
||||||
<div class="mx-4 my-0 fw-bold alert-heading text-center">
|
<div
|
||||||
|
class="mx-4 my-0 alert-heading text-center"
|
||||||
|
:class="[isAfterpayBreakoutDisplay ? 'fw-bolder' : 'fw-bold']">
|
||||||
<span v-for="token in afterpayCopyTokens" :key="token">
|
<span v-for="token in afterpayCopyTokens" :key="token">
|
||||||
<span v-if="isAfterpayPriceToken(token)">{{ afterpayPrice }}</span>
|
<span v-if="isAfterpayPriceToken(token)">{{ afterpayPrice }}</span>
|
||||||
<span v-else-if="isInlineImageToken(token)">
|
<span v-else-if="isInlineImageToken(token)">
|
||||||
<img v-if="hasImage" :src="imageUrl" :alt="getInlineAltText(token)" />
|
<img v-if="hasImage" :src="imageUrl" :alt="getInlineAltText(token)" />
|
||||||
<span v-else>{{ getInlineAltText(token) }}</span>
|
<span v-else>{{ getInlineAltText(token) }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else v-html="token"></span>
|
||||||
{{ token }}
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
|
|
@ -52,6 +52,7 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
lineItems: Array,
|
lineItems: Array,
|
||||||
|
isAfterpayBreakoutDisplay: Boolean,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -69,7 +70,16 @@ export default {
|
||||||
return !!this.imageUrl;
|
return !!this.imageUrl;
|
||||||
},
|
},
|
||||||
afterpayCopyTokens() {
|
afterpayCopyTokens() {
|
||||||
return splitCopyOnCMSPlaceHolder(this.getCmsContent(this.cmsWidgetName, "HeaderText"));
|
if (this.isAfterpayBreakoutDisplay) {
|
||||||
|
// Text for Afterpay Breakout experiment
|
||||||
|
return splitCopyOnCMSPlaceHolder(
|
||||||
|
this.getCmsContent(this.cmsWidgetName, "BodyText2")
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return splitCopyOnCMSPlaceHolder(
|
||||||
|
this.getCmsContent(this.cmsWidgetName, "HeaderText")
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
modalCopy() {
|
modalCopy() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, "BodyText");
|
return this.getCmsContent(this.cmsWidgetName, "BodyText");
|
||||||
|
|
@ -117,6 +127,12 @@ export default {
|
||||||
.alert-heading {
|
.alert-heading {
|
||||||
color: $blue-700;
|
color: $blue-700;
|
||||||
}
|
}
|
||||||
|
&.fw-bolder {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
vertical-align: text-top;
|
||||||
|
}
|
||||||
svg {
|
svg {
|
||||||
fill: $blue-700;
|
fill: $blue-700;
|
||||||
width: 1rem;
|
width: 1rem;
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,12 @@ jest.mock("@/mixins/experiment-mixin.js", () => ({
|
||||||
}
|
}
|
||||||
return "test";
|
return "test";
|
||||||
},
|
},
|
||||||
|
hasSettingEqualTo(settingName) {
|
||||||
|
if (settingName === mockExperimentSettings.DISPLAY_AFTERPAY_BREAKOUT_DISPLAY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return "test";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@
|
||||||
<afterpayModalBanner
|
<afterpayModalBanner
|
||||||
v-if="showAfterpayBanner"
|
v-if="showAfterpayBanner"
|
||||||
cmsWidgetName="AfterpayModalWidget"
|
cmsWidgetName="AfterpayModalWidget"
|
||||||
|
:isAfterpayBreakoutDisplay="isAfterpayBreakoutDisplay"
|
||||||
:lineItems="lineItems" />
|
:lineItems="lineItems" />
|
||||||
|
|
||||||
<!-- If vehicle requires recal AND we are hiding recal pricing info, then show recal disclaimer banner. -->
|
<!-- If vehicle requires recal AND we are hiding recal pricing info, then show recal disclaimer banner. -->
|
||||||
|
|
@ -221,6 +222,36 @@ export default {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AfterpayBreakoutDisplay Custom Exposure
|
||||||
|
const IGQExperiment = store.getters.applicationUser.experiments.find(
|
||||||
|
(e) => e.universeName === experimentUniverses.RECAL_PRICE_REMOVAL
|
||||||
|
);
|
||||||
|
const hasExposedIGQExperiment = IGQExperiment?.isExposed;
|
||||||
|
|
||||||
|
const afterpayBreakoutDisplayExperiment = store.getters.applicationUser.experiments.find(
|
||||||
|
(e) => e.universeName === experimentUniverses.AFTERPAY_BREAKOUT_DISPLAY
|
||||||
|
);
|
||||||
|
const hasExposedAfterpayBreakoutDisplay = afterpayBreakoutDisplayExperiment?.isExposed;
|
||||||
|
const shouldSendAfterpayBreakoutDisplayExposeRequest =
|
||||||
|
afterpayBreakoutDisplayExperiment &&
|
||||||
|
!hasExposedAfterpayBreakoutDisplay &&
|
||||||
|
!hasExposedIGQExperiment;
|
||||||
|
|
||||||
|
if (shouldSendAfterpayBreakoutDisplayExposeRequest) {
|
||||||
|
baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
storeActions.LOG_EXPERIMENT_EXPOSURE_AND_UPDATE_STORE,
|
||||||
|
{
|
||||||
|
userId: getUserIdValue(),
|
||||||
|
deviceId: getDeviceIdValue(),
|
||||||
|
sessionKey: getSessionKeyValue(),
|
||||||
|
pageName: to.query.fmgPage,
|
||||||
|
experiment: afterpayBreakoutDisplayExperiment,
|
||||||
|
},
|
||||||
|
"quote",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const promiseResultMap = [
|
const promiseResultMap = [
|
||||||
{
|
{
|
||||||
resultKey: "cmsContent",
|
resultKey: "cmsContent",
|
||||||
|
|
@ -571,6 +602,15 @@ export default {
|
||||||
showRecalDisclaimer() {
|
showRecalDisclaimer() {
|
||||||
return this.isRecalibrationOnOrder && this.isRecalPriceRemove;
|
return this.isRecalibrationOnOrder && this.isRecalPriceRemove;
|
||||||
},
|
},
|
||||||
|
isAfterpayBreakoutDisplay() {
|
||||||
|
return (
|
||||||
|
(!this.isRecalPriceRemove || !this.isRecalibrationOnOrder) &&
|
||||||
|
experimentMixin.methods.hasSettingEqualTo(
|
||||||
|
experimentSettings.DISPLAY_AFTERPAY_BREAKOUT_DISPLAY,
|
||||||
|
"true"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getColCount() {
|
getColCount() {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
:answers="servicePackageAnswers"
|
:answers="servicePackageAnswers"
|
||||||
:groupName="groupName"
|
:groupName="groupName"
|
||||||
buttonTypeString="servicePackageRadio"
|
buttonTypeString="servicePackageRadio"
|
||||||
:buttonTypeObject="hasPricingByDay() ? servicePackageRadioExperiment : servicePackageRadio"
|
:buttonTypeObject="getButtonTypeObject()"
|
||||||
v-model="selectedPackageName"
|
v-model="selectedPackageName"
|
||||||
:validationRules="validationRules"
|
:validationRules="validationRules"
|
||||||
:isRequired="isRequired"
|
:isRequired="isRequired"
|
||||||
|
|
@ -18,6 +18,7 @@ import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { processIfStatements } from "@/helpers/cms-content-helper";
|
import { processIfStatements } from "@/helpers/cms-content-helper";
|
||||||
import servicePackageRadio from "./service-package-radio/service-package-radio";
|
import servicePackageRadio from "./service-package-radio/service-package-radio";
|
||||||
import servicePackageRadioExperiment from "@/experiment-components/service-package-radio";
|
import servicePackageRadioExperiment from "@/experiment-components/service-package-radio";
|
||||||
|
import servicePackageRadioAfterpayExperiment from "@/experiment-components/service-package-radio-for-afterpay";
|
||||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||||
import { packageNames } from "@/constants/package-names";
|
import { packageNames } from "@/constants/package-names";
|
||||||
import {
|
import {
|
||||||
|
|
@ -61,6 +62,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
servicePackageRadio: servicePackageRadio,
|
servicePackageRadio: servicePackageRadio,
|
||||||
servicePackageRadioExperiment: servicePackageRadioExperiment,
|
servicePackageRadioExperiment: servicePackageRadioExperiment,
|
||||||
|
servicePackageRadioAfterpayExperiment: servicePackageRadioAfterpayExperiment,
|
||||||
selectedPackageName: null,
|
selectedPackageName: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
@ -156,6 +158,7 @@ export default {
|
||||||
Text: this.isInsuranceSelected
|
Text: this.isInsuranceSelected
|
||||||
? false
|
? false
|
||||||
: "Special: Save $" + this.getServicePackageDiscountPrice(),
|
: "Special: Save $" + this.getServicePackageDiscountPrice(),
|
||||||
|
isInsuranceSelected: this.isInsuranceSelected,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
this.$emit("currentNumberOfPackages", modifiedAnswers.length);
|
this.$emit("currentNumberOfPackages", modifiedAnswers.length);
|
||||||
|
|
@ -237,6 +240,24 @@ export default {
|
||||||
"true"
|
"true"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
isAfterpayBreakoutDisplay() {
|
||||||
|
return (
|
||||||
|
(!this.shouldHideRecalibration || !this.isRecalibrationOnOrder) &&
|
||||||
|
experimentMixin.methods.hasSettingEqualTo(
|
||||||
|
experimentSettings.DISPLAY_AFTERPAY_BREAKOUT_DISPLAY,
|
||||||
|
"true"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getButtonTypeObject() {
|
||||||
|
if (this.isAfterpayBreakoutDisplay()) {
|
||||||
|
return this.servicePackageRadioAfterpayExperiment;
|
||||||
|
}
|
||||||
|
if (this.hasPricingByDay()) {
|
||||||
|
return this.servicePackageRadioExperiment;
|
||||||
|
}
|
||||||
|
return this.servicePackageRadio;
|
||||||
|
},
|
||||||
getHeaderTextFromCms(cmsWidgetName) {
|
getHeaderTextFromCms(cmsWidgetName) {
|
||||||
return this.getCmsContent(cmsWidgetName, "HeaderText");
|
return this.getCmsContent(cmsWidgetName, "HeaderText");
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue