Merge pull request #1894 from Safelite/CSR-2115-remove-recal-from-cart
Csr 2115 remove recal from cart
This commit is contained in:
commit
fd31a38681
7 changed files with 186 additions and 22 deletions
|
|
@ -6,7 +6,7 @@ This public/css folder uses a standalone .scss > .css setup.
|
||||||
From a Terminal window, run the Sass Watch command from the public folder only:
|
From a Terminal window, run the Sass Watch command from the public folder only:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sass --no-source-map --watch scss:css
|
sass --watch scss:css
|
||||||
```
|
```
|
||||||
This will compile and output .css files (into the public/css folder) that can be consumed by the Payment page.
|
This will compile and output .css files (into the public/css folder) that can be consumed by the Payment page.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ const errorMessages = {
|
||||||
VIN_FORMAT:
|
VIN_FORMAT:
|
||||||
"Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q",
|
"Invalid VIN. Please make sure that you entered the correct 17-digit, alpha-numeric number. VINs do not contain the letters I, O, or Q",
|
||||||
OPTION_REQUIRED: "Please select an option",
|
OPTION_REQUIRED: "Please select an option",
|
||||||
|
RECAL_ACK_REQUIRED: "Please acknowledge recalibration alert",
|
||||||
VEHICLE_REQUIRED: "Please select a vehicle",
|
VEHICLE_REQUIRED: "Please select a vehicle",
|
||||||
MOBILE_LOCATION_REQUIRED: "Please enter your service address",
|
MOBILE_LOCATION_REQUIRED: "Please enter your service address",
|
||||||
DATE_REQUIRED: "Please select a date",
|
DATE_REQUIRED: "Please select a date",
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,25 @@ describe("checkbox-question.vue", () => {
|
||||||
expect(input.attributes().name).toEqual("Checkbox");
|
expect(input.attributes().name).toEqual("Checkbox");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should return checkbox id", async () => {
|
it("Should return default id when no custom id is specified", async () => {
|
||||||
|
// Act
|
||||||
|
const wrapper = shallowMount(checkboxQuestion, {
|
||||||
|
propsData: {},
|
||||||
|
mixins: [mockMixin],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Expect
|
||||||
|
expect(input.attributes().id).not.toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should return custom id when specified", async () => {
|
||||||
// Act
|
// Act
|
||||||
const wrapper = shallowMount(checkboxQuestion, {
|
const wrapper = shallowMount(checkboxQuestion, {
|
||||||
propsData: {
|
propsData: {
|
||||||
buttonID: "Checkbox ID",
|
customInputId: "Checkbox ID",
|
||||||
},
|
},
|
||||||
mixins: [mockMixin],
|
mixins: [mockMixin],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,32 +10,67 @@
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
aria-checked="false"
|
aria-checked="false"
|
||||||
:name="checkboxName"
|
:name="checkboxName"
|
||||||
:id="buttonID"
|
:validationRules="validationRules"
|
||||||
|
:id="inputId"
|
||||||
:tabindex="tabIndex"
|
:tabindex="tabIndex"
|
||||||
:aria-required="isRequired" />
|
:aria-required="isRequired" />
|
||||||
<p v-html="checkboxLabelCopy" class="m-0"></p>
|
<textBlock
|
||||||
|
class="m-0"
|
||||||
|
:customText="checkboxLabelCopy"
|
||||||
|
marginTopSizeOverride="0"
|
||||||
|
typeStyle="small"
|
||||||
|
@text-link-clicked="bubbleTextBlockClick" />
|
||||||
<span v-if="screenReaderOnlyText" class="sr-only">{{ screenReaderOnlyText }}</span>
|
<span v-if="screenReaderOnlyText" class="sr-only">{{ screenReaderOnlyText }}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { useField, validate } from "vee-validate";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import textBlock from "@/digital-components/text-block/text-block";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "checkboxQuestion",
|
name: "checkboxQuestion",
|
||||||
computed: {
|
computed: {
|
||||||
checkboxLabelCopy() {
|
checkboxLabelCopy() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
|
return this.getCmsContent(this.cmsWidgetName, "QuestionText");
|
||||||
},
|
},
|
||||||
value: {
|
},
|
||||||
get: function () {
|
setup(props) {
|
||||||
return this.modelValue;
|
const uuid = uuidv4();
|
||||||
},
|
const inputId = !props.customInputId ? `input-${uuid}` : props.customInputId;
|
||||||
set: function (newValue) {
|
|
||||||
this.$emit("update:modelValue", newValue);
|
const fieldOptions = {
|
||||||
},
|
initialValue: props.modelValue,
|
||||||
},
|
};
|
||||||
|
|
||||||
|
const {
|
||||||
|
value,
|
||||||
|
errorMessage,
|
||||||
|
handleBlur,
|
||||||
|
handleChange,
|
||||||
|
meta,
|
||||||
|
validate,
|
||||||
|
errors,
|
||||||
|
resetField,
|
||||||
|
} = useField(inputId, props.validationRules, fieldOptions);
|
||||||
|
|
||||||
|
return {
|
||||||
|
value,
|
||||||
|
errorMessage,
|
||||||
|
handleBlur,
|
||||||
|
handleChange,
|
||||||
|
validate,
|
||||||
|
meta,
|
||||||
|
errors,
|
||||||
|
resetField,
|
||||||
|
inputId,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
customInputId: String,
|
||||||
|
validationRules: String,
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String,
|
||||||
checkboxName: String,
|
checkboxName: String,
|
||||||
buttonID: String,
|
buttonID: String,
|
||||||
|
|
@ -48,6 +83,24 @@ export default {
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
bubbleTextBlockClick(event) {
|
||||||
|
this.$emit("textLinkClicked", event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
modelValue(newValue, oldValue) {
|
||||||
|
if (this.value !== newValue) {
|
||||||
|
this.value = newValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value(newValue, oldValue) {
|
||||||
|
this.$emit("update:modelValue", newValue);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
textBlock,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -56,6 +109,7 @@ export default {
|
||||||
.form-check-input {
|
.form-check-input {
|
||||||
border: 1px solid $gray-500;
|
border: 1px solid $gray-500;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
min-width: 1rem; // Prevent squish
|
||||||
&:checked {
|
&:checked {
|
||||||
background-size: 125%;
|
background-size: 125%;
|
||||||
border: 1px solid $blue;
|
border: 1px solid $blue;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="cart">
|
<div class="cart">
|
||||||
<div class="px-0">
|
<div class="px-0">
|
||||||
|
<!-- set class to 'expaned' on line 7 so cart is open on page load. This may be temporary -->
|
||||||
<div
|
<div
|
||||||
class="row vin-toggle flex align-items-center pt-4"
|
class="row vin-toggle flex align-items-center pt-4"
|
||||||
:class="[isExpanded ? 'expanded' : '']"
|
:class="[isExpanded ? '' : 'expanded']"
|
||||||
@click="toggleIsExpanded()">
|
@click="toggleIsExpanded()">
|
||||||
<a
|
<a
|
||||||
aria-label="expand cart"
|
aria-label="expand cart"
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,12 @@ describe("payment-method.vue", () => {
|
||||||
function setupMocks() {
|
function setupMocks() {
|
||||||
store.getters = {
|
store.getters = {
|
||||||
damage: {},
|
damage: {},
|
||||||
lineItems: [],
|
lineItems: {
|
||||||
|
glassParts: [],
|
||||||
|
supportingItems: [],
|
||||||
|
vaps: [],
|
||||||
|
promos: [],
|
||||||
|
},
|
||||||
order: {
|
order: {
|
||||||
payment: {
|
payment: {
|
||||||
isPia: false,
|
isPia: false,
|
||||||
|
|
@ -55,6 +60,12 @@ function setupMocks() {
|
||||||
isVerified: true,
|
isVerified: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: [],
|
||||||
|
supportingItems: [],
|
||||||
|
vaps: [],
|
||||||
|
promos: [],
|
||||||
|
},
|
||||||
policy: {
|
policy: {
|
||||||
currentDeductible: 123,
|
currentDeductible: 123,
|
||||||
isNoComp: false,
|
isNoComp: false,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||||
<loadingModal notFullScreen ref="loadingModal" />
|
<loadingModal notFullScreen ref="loadingModal" />
|
||||||
<div class="container-fluid">
|
<div class="container-fluid payment-method">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
|
|
@ -46,10 +46,28 @@
|
||||||
v-bind:isDismissible="false" />
|
v-bind:isDismissible="false" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="hasRecal && !isInsurance" class="questions-about-service my-5">
|
||||||
|
<textBlock
|
||||||
|
cmsWidgetName="QuestionsAboutYourServiceWidget"
|
||||||
|
justifyText="left"
|
||||||
|
class="service-questions" />
|
||||||
|
<textBlock cmsWidgetName="CallOrTextWidget" justifyText="left" />
|
||||||
|
<hr class="my-5" />
|
||||||
|
<div class="d-flex flex-row checkbox-group">
|
||||||
|
<checkboxQuestion
|
||||||
|
cmsWidgetName="RecalConfirmWidget"
|
||||||
|
class="mb-5"
|
||||||
|
isRequired="true"
|
||||||
|
v-model="isRecalAckOptIn"
|
||||||
|
validationRules="recal-ack-required"
|
||||||
|
@text-link-clicked="openModal('RecalModal')" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<paymentMethodQuestion
|
<paymentMethodQuestion
|
||||||
v-if="isPiaEnabled && totalAmountDue > 0"
|
v-if="isPiaEnabled && totalAmountDue > 0"
|
||||||
v-model="paymentMethodInternalModel"
|
v-model="paymentMethodInternalModel"
|
||||||
validationRules="option-required" />
|
validationRules="payment-method-required" />
|
||||||
|
|
||||||
<alert
|
<alert
|
||||||
v-if="!isPiaEnabled && totalAmountDue > 0"
|
v-if="!isPiaEnabled && totalAmountDue > 0"
|
||||||
|
|
@ -66,6 +84,11 @@
|
||||||
buttonSize
|
buttonSize
|
||||||
@back-clicked="backButtonAction"
|
@back-clicked="backButtonAction"
|
||||||
@ForwardClicked="forwardButtonAction" />
|
@ForwardClicked="forwardButtonAction" />
|
||||||
|
|
||||||
|
<contentGroupModal
|
||||||
|
ref="RecalModal"
|
||||||
|
cmsWidgetName="RecalModal"
|
||||||
|
class="recal-modal" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -83,13 +106,20 @@ import cart from "@/fmg-components/cart/cart";
|
||||||
import reviewDropdown from "@/layouts/payment-method/review-dropdown/review-dropdown";
|
import reviewDropdown from "@/layouts/payment-method/review-dropdown/review-dropdown";
|
||||||
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
||||||
import alert from "@/ux-components/alert/alert";
|
import alert from "@/ux-components/alert/alert";
|
||||||
|
import textBlock from "@/digital-components/text-block/text-block";
|
||||||
|
import checkboxQuestion from "@/digital-components/checkbox-question/checkbox-question";
|
||||||
|
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
|
||||||
|
|
||||||
// Supporting Items
|
// Supporting Items
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
import { storeActions } from "@/constants/store-actions";
|
import { storeActions } from "@/constants/store-actions";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import {
|
||||||
|
fetchCmsContentForPage,
|
||||||
|
doesCopyContainRouterLink,
|
||||||
|
getRouterLinkRouteFromCopy,
|
||||||
|
} from "@/helpers/cms-content-helper";
|
||||||
import { paymentMethods } from "@/constants/payment-method-constants";
|
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||||
import { experimentSettings } from "@/constants/experiments";
|
import { experimentSettings } from "@/constants/experiments";
|
||||||
import {
|
import {
|
||||||
|
|
@ -116,10 +146,14 @@ import { partTypeStrings } from "@/constants/part-type-strings";
|
||||||
import { mapTaxedLineItemsToStoreFormat } from "../../store";
|
import { mapTaxedLineItemsToStoreFormat } from "../../store";
|
||||||
import { coverageStatus } from "@/constants/insurance";
|
import { coverageStatus } from "@/constants/insurance";
|
||||||
|
|
||||||
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("payment-method-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
defineRule("recal-ack-required", required(errorMessages.RECAL_ACK_REQUIRED));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "paymentMethod",
|
name: "paymentMethod",
|
||||||
|
props: {
|
||||||
|
recyclingModalCmsWidgetName: String,
|
||||||
|
},
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||||
|
|
@ -309,9 +343,15 @@ export default {
|
||||||
availableVaps: [],
|
availableVaps: [],
|
||||||
paymentMethodInternalModel: this.getPaymentMethodFromStore(),
|
paymentMethodInternalModel: this.getPaymentMethodFromStore(),
|
||||||
inactivePromos: this.getInactivePromosFromStore(),
|
inactivePromos: this.getInactivePromosFromStore(),
|
||||||
|
isRecalAckOptIn: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
doesCopyContainRouterLink,
|
||||||
|
getRouterLinkRouteFromCopy,
|
||||||
|
navigateWithScenario(scenarioName) {
|
||||||
|
this.$router.navigateWithoutSaving(scenarioName, this.$route);
|
||||||
|
},
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
// Service Location
|
// Service Location
|
||||||
const serviceLocation = store.getters.order.serviceLocation;
|
const serviceLocation = store.getters.order.serviceLocation;
|
||||||
|
|
@ -451,14 +491,12 @@ export default {
|
||||||
this.paymentMethod,
|
this.paymentMethod,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
// save lineitems as they now have salestax added
|
// save lineitems as they now have salestax added
|
||||||
await this.dispatchStoreAction(
|
await this.dispatchStoreAction(
|
||||||
storeActions.SAVE_GLASS_PARTS_SUPPRESSING_STATE_RESETTING,
|
storeActions.SAVE_GLASS_PARTS_SUPPRESSING_STATE_RESETTING,
|
||||||
this.lineItems.glassParts,
|
this.lineItems.glassParts,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.dispatchStoreAction(
|
await this.dispatchStoreAction(
|
||||||
storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
|
storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
|
||||||
this.lineItems.supportingItems,
|
this.lineItems.supportingItems,
|
||||||
|
|
@ -473,7 +511,6 @@ export default {
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.paymentMethod == paymentMethods.LATER) {
|
if (this.paymentMethod == paymentMethods.LATER) {
|
||||||
// this creates the final work order
|
// this creates the final work order
|
||||||
await submitWorkOrder({ pageNameToLog: "payment-method", submitAfterSave: true });
|
await submitWorkOrder({ pageNameToLog: "payment-method", submitAfterSave: true });
|
||||||
|
|
@ -513,8 +550,20 @@ export default {
|
||||||
hasSubmittedOrder() {
|
hasSubmittedOrder() {
|
||||||
return this.$store.getters.hasSubmittedOrder;
|
return this.$store.getters.hasSubmittedOrder;
|
||||||
},
|
},
|
||||||
|
openModal(modalName) {
|
||||||
|
this.$refs[modalName].openModal();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
hasRecal() {
|
||||||
|
const recalLineItem = this.$store.getters.order.lineItems.supportingItems.find(
|
||||||
|
(lineItem) => lineItem.partType == partTypeStrings.RECALIBRATION
|
||||||
|
);
|
||||||
|
if (recalLineItem) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
damageInfo() {
|
damageInfo() {
|
||||||
return this.$store.getters.damage;
|
return this.$store.getters.damage;
|
||||||
},
|
},
|
||||||
|
|
@ -653,11 +702,27 @@ export default {
|
||||||
alert,
|
alert,
|
||||||
paymentMethodQuestion,
|
paymentMethodQuestion,
|
||||||
reviewDropdown,
|
reviewDropdown,
|
||||||
|
textBlock,
|
||||||
|
checkboxQuestion,
|
||||||
|
contentGroupModal,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.checkbox-group {
|
||||||
|
align-items: start;
|
||||||
|
> * {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.questions-about-service {
|
||||||
|
.service-questions {
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
.cart {
|
.cart {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -665,4 +730,22 @@ export default {
|
||||||
color: $gray-550;
|
color: $gray-550;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.payment-method {
|
||||||
|
.recal-modal {
|
||||||
|
:deep(.modal-body) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
h5 {
|
||||||
|
text-align: center;
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
order: 3;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue