Merge branch 'release/2025.02.27' into rlsmerge/2025.02.27-to-develop
This commit is contained in:
commit
24286d2f27
33 changed files with 1697 additions and 150 deletions
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"tabWidth": 4,
|
||||
"htmlWhitespaceSensitivity": "ignore",
|
||||
"bracketSameLine": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma" : "es5"
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ module.exports = {
|
|||
"!src/layouts/insurance/*.vue", // Temp test exclusion while in development
|
||||
"!src/layouts/insurance-company/*.vue", // Temp test exclusion while in development
|
||||
"!src/layouts/insurance-company/insurance-company-question/*.vue", // Temp test exclusion while in development
|
||||
"!src/experiment-components/.vue",
|
||||
// END
|
||||
], // ! means exclude from coverage.
|
||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
1071
src/digital-components/date-picker/date-picker-2.vue
Normal file
1071
src/digital-components/date-picker/date-picker-2.vue
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -17,18 +17,40 @@
|
|||
<div
|
||||
v-if="calendarViewDirection === 'future'"
|
||||
class="legend caption d-flex align-items-center justify-content-end">
|
||||
<span class="legend-circle me-1"></span> = Available
|
||||
<span class="legend-circle me-1"></span>
|
||||
= Available
|
||||
</div>
|
||||
<div class="separator-line"></div>
|
||||
<div class="nav-back ps-3"><button></button></div>
|
||||
<div class="nav-forward pe-3"><button></button></div>
|
||||
<div class="grid-item caption"><span class="sr-only">Sunday</span>S</div>
|
||||
<div class="grid-item caption"><span class="sr-only">Monday</span>M</div>
|
||||
<div class="grid-item caption"><span class="sr-only">Tuesday</span>T</div>
|
||||
<div class="grid-item caption"><span class="sr-only">Wednesday</span>W</div>
|
||||
<div class="grid-item caption"><span class="sr-only">Thursday</span>T</div>
|
||||
<div class="grid-item caption"><span class="sr-only">Friday</span>F</div>
|
||||
<div class="grid-item caption"><span class="sr-only">Saturday</span>S</div>
|
||||
<div class="grid-item caption">
|
||||
<span class="sr-only">Sunday</span>
|
||||
S
|
||||
</div>
|
||||
<div class="grid-item caption">
|
||||
<span class="sr-only">Monday</span>
|
||||
M
|
||||
</div>
|
||||
<div class="grid-item caption">
|
||||
<span class="sr-only">Tuesday</span>
|
||||
T
|
||||
</div>
|
||||
<div class="grid-item caption">
|
||||
<span class="sr-only">Wednesday</span>
|
||||
W
|
||||
</div>
|
||||
<div class="grid-item caption">
|
||||
<span class="sr-only">Thursday</span>
|
||||
T
|
||||
</div>
|
||||
<div class="grid-item caption">
|
||||
<span class="sr-only">Friday</span>
|
||||
F
|
||||
</div>
|
||||
<div class="grid-item caption">
|
||||
<span class="sr-only">Saturday</span>
|
||||
S
|
||||
</div>
|
||||
<div
|
||||
v-for="date in month.dates"
|
||||
:key="date.inputValue"
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@
|
|||
:maxlength="maxLength"
|
||||
role="textbox"
|
||||
aria-multiline="true"
|
||||
:aria-required="isRequired">
|
||||
</textarea>
|
||||
:aria-required="isRequired"></textarea>
|
||||
<p
|
||||
tabindex="-1"
|
||||
class="caption mt-2 mb-0 w-100"
|
||||
|
|
|
|||
|
|
@ -75,9 +75,9 @@
|
|||
class="d-inline-flex small mt-1"
|
||||
aria-atomic="true"
|
||||
aria-live="polite"
|
||||
:class="[centerErrorMessage ? 'center-error-message' : '']"
|
||||
>{{ errorMessage }}</span
|
||||
>
|
||||
:class="[centerErrorMessage ? 'center-error-message' : '']">
|
||||
{{ errorMessage }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
462
src/experiment-components/service-package-radio.vue
Normal file
462
src/experiment-components/service-package-radio.vue
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
<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>
|
||||
|
|
@ -10,9 +10,9 @@
|
|||
href="javascript:void(0)"
|
||||
class="col d-flex justify-content-between py-0">
|
||||
<span class="label">{{ OrderDetailsText }}</span>
|
||||
<span class="label amount-due">{{
|
||||
getLineItemAmount(amountDue, showCoverageAsPending)
|
||||
}}</span>
|
||||
<span class="label amount-due">
|
||||
{{ getLineItemAmount(amountDue, showCoverageAsPending) }}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="cart-panel">
|
||||
|
|
@ -48,11 +48,11 @@
|
|||
v-for="(cartItem, i) in packageCartItems"
|
||||
:key="i"
|
||||
class="packaged-cart-item">
|
||||
<span
|
||||
><span :class="cartItem.category === 'promos' ? 'promo' : ''">{{
|
||||
cartItem.name
|
||||
}}</span></span
|
||||
>
|
||||
<span>
|
||||
<span :class="cartItem.category === 'promos' ? 'promo' : ''">
|
||||
{{ cartItem.name }}
|
||||
</span>
|
||||
</span>
|
||||
<textLink
|
||||
v-if="allowItemRemoval"
|
||||
ref="removeLink"
|
||||
|
|
@ -99,11 +99,9 @@
|
|||
!showCoverageAsVerified ||
|
||||
cartItem.name === 'Recycling' ||
|
||||
(showCoverageAsVerified && !cartItem.isCoveredByInsurance)
|
||||
"
|
||||
>{{
|
||||
getLineItemAmount(cartItem.subTotal, null, cartItem.category)
|
||||
}}</span
|
||||
>
|
||||
">
|
||||
{{ getLineItemAmount(cartItem.subTotal, null, cartItem.category) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Sub total, sales tax, total columns -->
|
||||
|
|
@ -143,8 +141,10 @@
|
|||
class="my-2 lh-1 applied-promo-tag"
|
||||
v-for="(promoCode, i) in getPromoCodeList"
|
||||
:key="i">
|
||||
<span class="caption"
|
||||
>Promo code <span class="promo-code">{{ promoCode }}</span> applied
|
||||
<span class="caption">
|
||||
Promo code
|
||||
<span class="promo-code">{{ promoCode }}</span>
|
||||
applied
|
||||
</span>
|
||||
</div>
|
||||
<contentGroupModal ref="RecycleModal" cmsWidgetName="RecycleModal">
|
||||
|
|
|
|||
|
|
@ -54,8 +54,10 @@
|
|||
class="mt-4 d-flex align-items-center justify-content-between"
|
||||
v-for="(promoCode, i) in this.getPromoCodeList()"
|
||||
:key="i">
|
||||
<span class="applied-promo"
|
||||
>Promo code <span class="promo-code">{{ promoCode }}</span> applied
|
||||
<span class="applied-promo">
|
||||
Promo code
|
||||
<span class="promo-code">{{ promoCode }}</span>
|
||||
applied
|
||||
</span>
|
||||
<textLink
|
||||
ref="removeLink"
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
<button v-on:click="openCalendarModal">
|
||||
<span class="add-to-calendar-span">
|
||||
<img src="@/assets/img/icons/add-to-calendar.svg" class="add-to-calendar-img" />
|
||||
<span class="add-to-calendar-text">Add to calendar</span></span
|
||||
>
|
||||
<span class="add-to-calendar-text">Add to calendar</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<calendarModalQuestion
|
||||
|
|
@ -14,8 +14,7 @@
|
|||
cmsWidgetName="CalendarModalQuestion"
|
||||
@calendar-modal-closed="calendarModalClosed"
|
||||
:calendarOptionsData="calendarValues"
|
||||
v-model="selectedCalendarOption">
|
||||
</calendarModalQuestion>
|
||||
v-model="selectedCalendarOption"></calendarModalQuestion>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
linkType="text"
|
||||
:text="payWithCashButtonCopy"
|
||||
href="javascript:void(0)"
|
||||
@click-event="backButtonAction(foreceCashSelectionOnQuote = true)" />
|
||||
@click-event="backButtonAction((foreceCashSelectionOnQuote = true))" />
|
||||
|
||||
<navbar
|
||||
cmsWidgetName="FunnelFooterWidget"
|
||||
|
|
@ -102,7 +102,7 @@ export default {
|
|||
},
|
||||
payWithCashButtonCopy() {
|
||||
return this.getCmsContent("PayWithCashWidget", "Text");
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isCashParentAccountNumber() {
|
||||
|
|
@ -123,10 +123,14 @@ export default {
|
|||
backButtonAction(forceCashSelectionOnQuote) {
|
||||
// Go back to Quote page
|
||||
if (forceCashSelectionOnQuote) {
|
||||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route, {"isCashSelected": true});
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_BACK,
|
||||
this.$route,
|
||||
{ isCashSelected: true }
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ export default {
|
|||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
baseMixin.methods.ResetExternalParamsAndHideModal();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
v-if="hasImage"
|
||||
:src="buttonImage"
|
||||
:alt="getInlineAltText(token)" />
|
||||
<span v-else> {{ getInlineAltText(token) }}</span>
|
||||
<span v-else>{{ getInlineAltText(token) }}</span>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ token }}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
class="ms-2"
|
||||
:src="buttonImage"
|
||||
:alt="getInlineAltText(token)" />
|
||||
<span v-else> {{ getInlineAltText(token) }}</span>
|
||||
<span v-else>{{ getInlineAltText(token) }}</span>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ token }}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,7 @@
|
|||
id="card-frame"
|
||||
seamless
|
||||
scrolling="no"
|
||||
allow="payment *; microphone *; geolocation *;">
|
||||
</iframe>
|
||||
allow="payment *; microphone *; geolocation *;"></iframe>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
|
|
|||
|
|
@ -612,14 +612,10 @@ describe("quote.vue", () => {
|
|||
mockTierOnePrice = 505;
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
|
||||
//Act
|
||||
await quote.beforeRouteEnter.call(
|
||||
wrapper.vm,
|
||||
{ query: { fmgPage: "quote",
|
||||
isInsuranceSelected: true,
|
||||
isCashSelected: true,
|
||||
} },
|
||||
{ query: { fmgPage: "quote", isInsuranceSelected: true, isCashSelected: true } },
|
||||
undefined,
|
||||
(c) => c(wrapper.vm)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<div class="alert-heading">
|
||||
<span>
|
||||
<img v-if="hasImage" :src="imageUrl" />
|
||||
<span class="px-2"> {{ recalHeaderText }}</span>
|
||||
<span class="px-2">{{ recalHeaderText }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ jest.mock("@/mixins/experiment-mixin.js", () => ({
|
|||
return true;
|
||||
}
|
||||
},
|
||||
hasSettingEqualTo(settingName, settingValue) {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
},
|
||||
|
|
|
|||
|
|
@ -27,9 +27,10 @@
|
|||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4 start-over">
|
||||
<a @click="startOver" alt="Start Over Button"
|
||||
><img v-bind:src="startOverImage" />{{ startOverText }}</a
|
||||
>
|
||||
<a @click="startOver" alt="Start Over Button">
|
||||
<img v-bind:src="startOverImage" />
|
||||
{{ startOverText }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
marginTopSizeOverride="1" />
|
||||
</template>
|
||||
<locationAlerts cmsWidgetPrefix="LocationAlert-" ref="locationAlerts" />
|
||||
<datePicker
|
||||
<datePicker2
|
||||
customComponentId="dateQuestion"
|
||||
selectableDatesSetting="custom"
|
||||
ref="datePicker"
|
||||
|
|
@ -69,7 +69,7 @@ import navbar from "@/fmg-components/nav-bar/nav-bar";
|
|||
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
||||
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||
import { Form, defineRule } from "vee-validate";
|
||||
import datePicker from "@/digital-components/date-picker/date-picker";
|
||||
import datePicker2 from "@/digital-components/date-picker/date-picker-2";
|
||||
import locationAlerts from "@/layouts/schedule/location-alerts/location-alerts";
|
||||
import timeSlotModalQuestion from "./time-slot-modal-question/time-slot-modal-question";
|
||||
import textBlock from "@/digital-components/text-block/text-block";
|
||||
|
|
@ -213,7 +213,7 @@ export default {
|
|||
preSelectedDate = null;
|
||||
}
|
||||
|
||||
const datePickerInitialDataPromise = await datePicker.methods.loadInitialData({
|
||||
const datePickerInitialDataPromise = await datePicker2.methods.loadInitialData({
|
||||
// setup config options for date-picker
|
||||
selectableDatesSetting: "custom",
|
||||
initialViewRowsToShow: 5,
|
||||
|
|
@ -537,7 +537,7 @@ export default {
|
|||
funnelSubHeader,
|
||||
Form,
|
||||
loadingModal,
|
||||
datePicker,
|
||||
datePicker2,
|
||||
locationAlerts,
|
||||
timeSlotModalQuestion,
|
||||
textBlock,
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ describe("mobile-location-modal-questions.vue", () => {
|
|||
expect(wrapper.vm.$refs.MobileLocationModalWidget.openModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Should emit updated-mobile-location-questions on setMobileLocation for a valid address and vehicle protection answer", async () => {
|
||||
it("Should emit setMobileLocationAndProceed on setMobileLocation for a valid address and vehicle protection answer", async () => {
|
||||
// Arrange
|
||||
const mobileLocationQuestions = {
|
||||
addressQuestions: {
|
||||
|
|
@ -240,26 +240,19 @@ describe("mobile-location-modal-questions.vue", () => {
|
|||
});
|
||||
wrapper.vm.$refs.MobileLocationModalWidget.closeModal = jest.fn();
|
||||
|
||||
// Mock the emitEvent function
|
||||
wrapper.vm.emitEvent = jest.fn(async (eventName, payload) => {
|
||||
return new Promise((resolve) => {
|
||||
wrapper.vm.$emit(eventName, newMobileLocationQuestions, resolve);
|
||||
resolve(newMobileLocationQuestions);
|
||||
});
|
||||
});
|
||||
// Act
|
||||
wrapper.vm.internalModel = newMobileLocationQuestions;
|
||||
|
||||
await wrapper.vm.setMobileLocation();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.emitted()["updated-mobile-location-questions"]).toBeTruthy();
|
||||
expect(wrapper.emitted()["updated-mobile-location-questions"][0][0]).toBe(
|
||||
expect(wrapper.emitted()["setMobileLocationAndProceed"]).toBeTruthy();
|
||||
expect(wrapper.emitted()["setMobileLocationAndProceed"][0][0]).toStrictEqual(
|
||||
newMobileLocationQuestions
|
||||
);
|
||||
});
|
||||
|
||||
it("Should not emit updated-mobile-location-questions on setMobileLocation for an invalid address zip code", async () => {
|
||||
it("Should not emit setMobileLocationAndProceed on setMobileLocation for an invalid address zip code", async () => {
|
||||
// Arrange
|
||||
const mobileLocationQuestions = {
|
||||
addressQuestions: {
|
||||
|
|
@ -302,7 +295,7 @@ describe("mobile-location-modal-questions.vue", () => {
|
|||
await wrapper.vm.setMobileLocation();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.emitted("updated-mobile-location-questions")).not.toBeTruthy();
|
||||
expect(wrapper.emitted("setMobileLocationAndProceed")).not.toBeTruthy();
|
||||
});
|
||||
|
||||
it("Should display invalid zip alert for invalid address zip inputs", async () => {
|
||||
|
|
|
|||
|
|
@ -97,8 +97,7 @@ export default {
|
|||
"updated-mobile-fee-part",
|
||||
"updated-contains-military-base",
|
||||
"updated-bill-to-account-number",
|
||||
"mobileLocationSelected",
|
||||
"updated-mobile-location-questions",
|
||||
"setMobileLocationAndProceed",
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -287,15 +286,7 @@ export default {
|
|||
this.$emit("updated-bill-to-account-number", billToAccountNumber);
|
||||
}
|
||||
// update the page level model
|
||||
await this.emitEvent("updated-mobile-location-questions", this.internalModel);
|
||||
|
||||
this.$emit("mobileLocationSelected");
|
||||
},
|
||||
//creating emitEvent function to raise events with resolve callback to handle events sequencing
|
||||
async emitEvent(eventName, payload) {
|
||||
return new Promise((resolve) => {
|
||||
this.$emit(eventName, payload, resolve);
|
||||
});
|
||||
this.$emit("setMobileLocationAndProceed", this.internalModel);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
|
|
|||
|
|
@ -435,6 +435,7 @@ describe("service-location.vue", () => {
|
|||
ref: "serviceZipCodeQuestion",
|
||||
});
|
||||
serviceZipCodeComponent.resetMobileFeePart = jest.fn();
|
||||
wrapper.vm.forwardButtonAction = jest.fn();
|
||||
|
||||
const mobileLocationQuestions = {
|
||||
addressQuestions: {
|
||||
|
|
@ -447,7 +448,6 @@ describe("service-location.vue", () => {
|
|||
isVehicleProtected: null,
|
||||
};
|
||||
wrapper.vm.mobileLocationQuestions = mobileLocationQuestions;
|
||||
|
||||
const newMobileLocationQuestions = {
|
||||
addressQuestions: {
|
||||
streetAddress: "5555 Sulgrave Dr",
|
||||
|
|
@ -461,21 +461,13 @@ describe("service-location.vue", () => {
|
|||
|
||||
// Act
|
||||
|
||||
// Mock the emitEvent function
|
||||
mobileLocationQuestionsComponent.vm.emitEvent = jest.fn(async (eventName, payload) => {
|
||||
return new Promise((resolve) => {
|
||||
mobileLocationQuestionsComponent.vm.$emit(eventName, payload, resolve);
|
||||
});
|
||||
});
|
||||
|
||||
// Trigger the event
|
||||
await mobileLocationQuestionsComponent.vm.emitEvent(
|
||||
"updated-mobile-location-questions",
|
||||
await mobileLocationQuestionsComponent.vm.$emit(
|
||||
"setMobileLocationAndProceed",
|
||||
newMobileLocationQuestions
|
||||
);
|
||||
|
||||
await wrapper.vm.$nextTick(); // Wait for DOM updates
|
||||
await new Promise((resolve) => setTimeout(resolve, 0)); // Wait for promise to resolve
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.mobileLocationQuestions).toStrictEqual(newMobileLocationQuestions);
|
||||
|
|
@ -502,7 +494,7 @@ describe("service-location.vue", () => {
|
|||
ref: "serviceZipCodeQuestion",
|
||||
});
|
||||
serviceZipCodeComponent.resetMobileFeePart = jest.fn();
|
||||
|
||||
wrapper.vm.forwardButtonAction = jest.fn();
|
||||
const mobileLocationQuestions = {
|
||||
addressQuestions: {
|
||||
streetAddress: "",
|
||||
|
|
@ -542,21 +534,13 @@ describe("service-location.vue", () => {
|
|||
|
||||
// Act
|
||||
|
||||
// Mock the emitEvent function
|
||||
mobileLocationQuestionsComponent.vm.emitEvent = jest.fn(async (eventName, payload) => {
|
||||
return new Promise((resolve) => {
|
||||
mobileLocationQuestionsComponent.vm.$emit(eventName, payload, resolve);
|
||||
});
|
||||
});
|
||||
|
||||
// Trigger the event
|
||||
await mobileLocationQuestionsComponent.vm.emitEvent(
|
||||
"updated-mobile-location-questions",
|
||||
await mobileLocationQuestionsComponent.vm.$emit(
|
||||
"setMobileLocationAndProceed",
|
||||
newMobileLocationQuestions
|
||||
);
|
||||
|
||||
await wrapper.vm.$nextTick(); // Wait for DOM updates
|
||||
await new Promise((resolve) => setTimeout(resolve, 0)); // Wait for promise to resolve
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.serviceZipCodeQuestion).toStrictEqual(newServiceZipCodeInfo);
|
||||
|
|
@ -578,6 +562,7 @@ describe("service-location.vue", () => {
|
|||
ref: "mobileLocationQuestions",
|
||||
});
|
||||
mobileLocationQuestionsComponent.resetComponent = jest.fn();
|
||||
wrapper.vm.forwardButtonAction = jest.fn();
|
||||
|
||||
const serviceZipCodeComponent = wrapper.findComponent({
|
||||
ref: "serviceZipCodeQuestion",
|
||||
|
|
@ -596,7 +581,10 @@ describe("service-location.vue", () => {
|
|||
};
|
||||
|
||||
// Act
|
||||
mobileLocationQuestionsComponent.vm.$emit("update:modelValue", mobileLocationQuestions);
|
||||
mobileLocationQuestionsComponent.vm.$emit(
|
||||
"setMobileLocationAndProceed",
|
||||
mobileLocationQuestions
|
||||
);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.selectedAppointmentType).toStrictEqual("Mobile");
|
||||
|
|
@ -1429,6 +1417,5 @@ function setupMocks({ mountOptionsMockData = {} }) {
|
|||
const mountOptions = getMountOptions(mountOptionsMockData);
|
||||
const wrapper = shallowMount(serviceLocation, mountOptions);
|
||||
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
|
||||
|
||||
return { wrapper, apiPromise };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,12 +93,11 @@
|
|||
@updated-serviceability="setServiceabilityDetails"
|
||||
@updated-contains-military-base="setContainsMilitaryBase"
|
||||
@updated-mobile-ctu="setCtuForMobile"
|
||||
@updated-mobile-location-questions="setMobileLocationQuestions"
|
||||
validationRules="mobile-location-required"
|
||||
ref="mobileLocationQuestions"
|
||||
linkWidgetName="MobileLocationLinkWidget"
|
||||
modalWidgetName="MobileLocationModalWidget"
|
||||
@mobileLocationSelected="forwardButtonAction" />
|
||||
@setMobileLocationAndProceed="setMobileLocationQuestions" />
|
||||
|
||||
<shopQuestion
|
||||
ref="shopQuestion"
|
||||
|
|
@ -295,19 +294,6 @@ export default {
|
|||
isVehicleProtected: this.isVehicleProtected,
|
||||
};
|
||||
},
|
||||
async set(newValue) {
|
||||
if (newValue.addressQuestions.zipCode !== this.zipCode) {
|
||||
await getShopProviderData(newValue.addressQuestions.zipCode).then((result) => {
|
||||
this.shopProviderData = result.data;
|
||||
this.selectedProvider = new Provider(
|
||||
this.shopProviderData.mobileProviderNumber
|
||||
);
|
||||
});
|
||||
}
|
||||
this.setMobileLocation(newValue);
|
||||
//handle promise
|
||||
newValue.resolve?.();
|
||||
},
|
||||
},
|
||||
isServiceableMobile() {
|
||||
if (this.isRecalibrationServiceableMobile !== null) {
|
||||
|
|
@ -488,8 +474,18 @@ export default {
|
|||
this.mobileFeePart = mobileFeePart;
|
||||
},
|
||||
//creating async function as the computed property can not directly handle asynchronous operations or promises.
|
||||
async setMobileLocationQuestions(newValue, resolve) {
|
||||
this.mobileLocationQuestions = { ...newValue, resolve };
|
||||
async setMobileLocationQuestions(newValue) {
|
||||
if (newValue.addressQuestions.zipCode !== this.zipCode) {
|
||||
await getShopProviderData(newValue.addressQuestions.zipCode).then((result) => {
|
||||
this.shopProviderData = result.data;
|
||||
this.selectedProvider = new Provider(
|
||||
this.shopProviderData.mobileProviderNumber
|
||||
);
|
||||
});
|
||||
}
|
||||
this.setMobileLocation(newValue);
|
||||
//proceed to next page
|
||||
this.forwardButtonAction();
|
||||
},
|
||||
getServiceAddressFromStore() {
|
||||
return store.getters.order.serviceLocation.address;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
href="#!"
|
||||
@click-event="openModal">
|
||||
<template v-slot:after-text v-if="editScreenReaderTextCmsWidgetName">
|
||||
<span class="sr-only"> {{ screenReaderOnlyText }} </span>
|
||||
<span class="sr-only">{{ screenReaderOnlyText }}</span>
|
||||
</template>
|
||||
</textLink>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@
|
|||
:aria-label="buttonLabel"
|
||||
class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4">
|
||||
<div class="row-one">
|
||||
<span class="m-0 button-label-copy text-truncate" :class="textPosition">{{
|
||||
buttonLabel
|
||||
}}</span>
|
||||
<span class="m-0 caption mx-1 text-nowrap" :class="textPosition">{{
|
||||
buttonLabelSubCopy
|
||||
}}</span>
|
||||
<span class="m-0 button-label-copy text-truncate" :class="textPosition">
|
||||
{{ buttonLabel }}
|
||||
</span>
|
||||
<span class="m-0 caption mx-1 text-nowrap" :class="textPosition">
|
||||
{{ buttonLabelSubCopy }}
|
||||
</span>
|
||||
<div
|
||||
v-if="displayAvailabilityIndicators"
|
||||
class="availability-indicator rounded-pill text-nowrap"
|
||||
|
|
@ -22,9 +22,9 @@
|
|||
v-if="!isLoaderDisplayed"
|
||||
class="availability-badge"
|
||||
:class="availabilityRating == 'high' ? 'green' : 'orange'"></div>
|
||||
<span v-if="!isLoaderDisplayed" class="m-0 button-auxillary-copy">{{
|
||||
badgeText
|
||||
}}</span>
|
||||
<span v-if="!isLoaderDisplayed" class="m-0 button-auxillary-copy">
|
||||
{{ badgeText }}
|
||||
</span>
|
||||
<loader
|
||||
v-if="isLoaderDisplayed"
|
||||
:loaderPosition="left"
|
||||
|
|
|
|||
|
|
@ -206,8 +206,7 @@ export default {
|
|||
if (!this.emailOrSms) {
|
||||
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, "", false);
|
||||
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, "", false);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (vinPagesMixin.methods.isPhoneNumber(this.emailOrSms)) {
|
||||
const phone = this.emailOrSms.replace(/[()]/g, "");
|
||||
await this.dispatchStoreAction(storeActions.SAVE_PHONE_NUMBER, phone, false);
|
||||
|
|
|
|||
|
|
@ -1016,8 +1016,12 @@ export const getters = {
|
|||
return email;
|
||||
}
|
||||
|
||||
// if we're here, then we have both email and phone so get the value from pageData to reflect what they entered on the page
|
||||
return state.applicationUser.pageData[fmgPageValues.EMAIL_SMS_PAGES]?.emailOrSmsValue;
|
||||
// if we're here, then we have both email and phone so get the value from pageData to reflect what they entered on the page.
|
||||
// if they didn't enter anything on the page default to email
|
||||
return (
|
||||
state.applicationUser.pageData[fmgPageValues.EMAIL_SMS_PAGES]?.emailOrSmsValue ??
|
||||
state.order.customer.emailAddress
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,26 @@
|
|||
<template>
|
||||
<loadingModal v-if="useLoadingModal" notFullScreen ref="loadingModal" />
|
||||
<a v-if="linkType === 'navigation'" @click="handleClick" class="navigation-link" :href="href"
|
||||
>{{ text }}<slot name="after-text"></slot
|
||||
></a>
|
||||
<a v-if="linkType === 'navigation'" @click="handleClick" class="navigation-link" :href="href">
|
||||
{{ text }}
|
||||
<slot name="after-text"></slot>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="linkType === 'newWindowLink'"
|
||||
@click="handleClick"
|
||||
class="new-window-link"
|
||||
:href="href"
|
||||
target="_blank"
|
||||
>{{ text }}<slot name="after-text"></slot
|
||||
></a>
|
||||
<a v-else-if="linkType === 'textSmall'" @click="handleClick" class="small" :href="href"
|
||||
>{{ text }}<slot name="after-text"></slot
|
||||
></a>
|
||||
<a v-else-if="linkType === 'text'" @click="handleClick" :href="href"
|
||||
>{{ text }}<slot name="after-text"></slot
|
||||
></a>
|
||||
target="_blank">
|
||||
{{ text }}
|
||||
<slot name="after-text"></slot>
|
||||
</a>
|
||||
<a v-else-if="linkType === 'textSmall'" @click="handleClick" class="small" :href="href">
|
||||
{{ text }}
|
||||
<slot name="after-text"></slot>
|
||||
</a>
|
||||
<a v-else-if="linkType === 'text'" @click="handleClick" :href="href">
|
||||
{{ text }}
|
||||
<slot name="after-text"></slot>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
Loading…
Reference in a new issue