CASH-151
CASH-151 add 'as low as' to quote page. used an experiment version of service-package-radio
This commit is contained in:
parent
86812eefe2
commit
8123cae1a2
5 changed files with 472 additions and 4 deletions
|
|
@ -18,6 +18,7 @@ const experimentSettings = {
|
|||
INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL: "NextGen_InternalInsuranceTabDisplayThreshold",
|
||||
INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL: "NextGen_ExternalInsuranceTabDisplayThreshold",
|
||||
DISPLAY_MSR: "DisplayMSR",
|
||||
PRICING_BY_DAY: "DisplayPricingByDay",
|
||||
};
|
||||
|
||||
const experimentTriggers = {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
|
|||
:additionalButtonData="answer.additionalButtonData"
|
||||
:lastValuePushedToGa="lastValuePushedToGa"
|
||||
:setLastValuePushedToGa="setLastValuePushedToGa"
|
||||
:isInsuranceSelected="isInsuranceSelected"
|
||||
:suppressError="suppressError"
|
||||
@buttonEvent="handleButtonEvent"
|
||||
v-model="selectedValues" />
|
||||
|
|
@ -139,6 +140,7 @@ export default {
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isInsuranceSelected: Boolean,
|
||||
},
|
||||
setup(props) {
|
||||
const propsClone = Object.assign({}, props);
|
||||
|
|
|
|||
455
src/experiment-components/service-package-radio.vue
Normal file
455
src/experiment-components/service-package-radio.vue
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
<template>
|
||||
<baseInputButton v-bind="$props" @buttonClicked="handleAnswerChange" v-model="selectedValue">
|
||||
<div
|
||||
class="package-label"
|
||||
:class="[this.buttonLabelSubCopy ? 'has-subheader' : '',
|
||||
this.isInsuranceSelected ? 'pricing-by-day-pkg-lbl-ins' : 'pricing-by-day-pkg-lbl']"
|
||||
for="testradio">
|
||||
<div class="package-specs">
|
||||
<div v-if="this.additionalButtonData.servicePackageDiscount" class="row">
|
||||
<div class="col md-6">
|
||||
<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>
|
||||
<span class="col md-6 service-package-discount-pricing-by-day">
|
||||
<div>
|
||||
<span v-if="!isInsuranceSelected" class="caption pricing-by-day">as low as</span>
|
||||
<div class="strikethrough-discount-price"
|
||||
v-if="shouldDisplayStrikeThroughPrice"
|
||||
v-html="this.additionalButtonData.strikeThroughPrice"></div>
|
||||
<div class="discount-price" v-html="getDisplayPrice"></div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="m-0">
|
||||
<span v-html="this.buttonLabel"></span>
|
||||
<span class="pricing-info-pricing-by-day">
|
||||
<span v-if="!isInsuranceSelected" class="caption pricing-by-day">as low as</span>
|
||||
<span
|
||||
class="strikethrough-price"
|
||||
v-if="shouldDisplayStrikeThroughPrice"
|
||||
v-html="this.additionalButtonData.strikeThroughPrice"></span>
|
||||
<span v-html="getDisplayPrice"></span>
|
||||
</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>
|
||||
</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";
|
||||
|
||||
import experimentMixin from "@/mixins/experiment-mixin";
|
||||
import { experimentSettings } from "@/constants/experiments";
|
||||
import store from "@/store";
|
||||
|
||||
export default {
|
||||
name: "servicePackageRadio",
|
||||
mixins: [inputButtonWrapperMixin],
|
||||
props: {
|
||||
isInsuranceSelected: Boolean,
|
||||
},
|
||||
components: {
|
||||
baseInputButton,
|
||||
textLink,
|
||||
},
|
||||
computed: {
|
||||
arrayOfListItemsFromBodyText() {
|
||||
return this.getArrayOfListItemsFromRawCmsCopy(this.buttonBodyCopy);
|
||||
},
|
||||
shouldDisplayStrikeThroughPrice() {
|
||||
const displayPrice = this.buttonAuxillaryCopy.substring(
|
||||
this.buttonAuxillaryCopy.indexOf("$")
|
||||
);
|
||||
return displayPrice != this.additionalButtonData.strikeThroughPrice;
|
||||
},
|
||||
getDisplayPrice() {
|
||||
return this.buttonAuxillaryCopy.split(".")[0];
|
||||
},
|
||||
},
|
||||
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);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.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.pricing-by-day-pkg-lbl {
|
||||
/* Copying a component for an experiment will cause duplication of css classes.
|
||||
This can cause problems if you want change the value of something only for the experiment
|
||||
version of the component. So added a more specific selector for the parts I want to change
|
||||
If this experiment wins, move this to package-label ::before/::after below
|
||||
*/
|
||||
&:before {
|
||||
top: 15px;
|
||||
}
|
||||
&:after {
|
||||
top: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
+ .package-label.pricing-by-day-pkg-lbl-ins {
|
||||
&:before {
|
||||
top: 5px;
|
||||
}
|
||||
&:after {
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
+ .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: 3rem;
|
||||
}
|
||||
transition: max-height 0.25s ease-in;
|
||||
|
||||
&.has-subheader {
|
||||
min-height: 72px;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
position: relative;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
+ .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;
|
||||
}
|
||||
|
||||
span.pricing-by-day {
|
||||
color: #4d5151;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.row {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
p {
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
span {
|
||||
&.pricing-info-pricing-by-day {
|
||||
text-align: end;
|
||||
color: $green;
|
||||
font-size: 0.875rem;
|
||||
span.strikethrough-price {
|
||||
text-decoration: line-through;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
color: $gray-550;
|
||||
padding-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.sub-label {
|
||||
color: $green;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
span {
|
||||
&.service-package-discount-pricing-by-day {
|
||||
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 {
|
||||
display:inline;
|
||||
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;
|
||||
display:inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
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: auto;
|
||||
margin-left: -1.25rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.25rem;
|
||||
margin-top: 0.5rem;
|
||||
span {
|
||||
color: $green;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -387,8 +387,7 @@ export default {
|
|||
|
||||
// prettier-ignore
|
||||
{
|
||||
const log = getQuerystringParameter(queryStrings.LOG);
|
||||
if (log === "true") {
|
||||
if (store.getters.applicationUser.loggingOption) {
|
||||
console.log("------------- quote.vue thresholds start -----------------");
|
||||
console.log(new Date() + " isExternalParameter: " + isExternalParameter);
|
||||
console.log(new Date() + " internalThreshold: " + internalThreshold);
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@
|
|||
:answers="servicePackageAnswers"
|
||||
:groupName="groupName"
|
||||
buttonTypeString="servicePackageRadio"
|
||||
:buttonTypeObject="servicePackageRadio"
|
||||
:buttonTypeObject="hasPricingByDay() ? servicePackageRadioExperiment : servicePackageRadio"
|
||||
v-model="selectedPackageName"
|
||||
:validationRules="validationRules"
|
||||
:isRequired="isRequired"
|
||||
:logDisplayedValuesEvent="true" />
|
||||
:logDisplayedValuesEvent="true"
|
||||
:isInsuranceSelected="isInsuranceSelected" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -16,6 +17,7 @@ import buttonQuestion from "@/digital-components/button-question/button-question
|
|||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { processIfStatements } from "@/helpers/cms-content-helper";
|
||||
import servicePackageRadio from "./service-package-radio/service-package-radio";
|
||||
import servicePackageRadioExperiment from "@/experiment-components/service-package-radio";
|
||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||
import { packageNames } from "@/constants/package-names";
|
||||
import {
|
||||
|
|
@ -58,6 +60,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
servicePackageRadio: servicePackageRadio,
|
||||
servicePackageRadioExperiment: servicePackageRadioExperiment,
|
||||
selectedPackageName: null,
|
||||
};
|
||||
},
|
||||
|
|
@ -223,6 +226,14 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
processIfStatements,
|
||||
hasPricingByDay() {
|
||||
return (
|
||||
experimentMixin.methods.hasSettingEqualTo(
|
||||
experimentSettings.PRICING_BY_DAY,
|
||||
"true"
|
||||
) && !this.isInsuranceSelected
|
||||
);
|
||||
},
|
||||
getHeaderTextFromCms(cmsWidgetName) {
|
||||
return this.getCmsContent(cmsWidgetName, "HeaderText");
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue