Merge branch 'develop' into feature/CSR-1382-loose-ends
This commit is contained in:
commit
32d7ce105f
13 changed files with 379 additions and 196 deletions
|
|
@ -22,6 +22,8 @@ module.exports = {
|
||||||
"!src/common-components/funnel-header/menu-modal/**/*.vue",
|
"!src/common-components/funnel-header/menu-modal/**/*.vue",
|
||||||
"!src/layouts/schedule/helpers/schedule-helper.js", // Temp test exclusion while in development
|
"!src/layouts/schedule/helpers/schedule-helper.js", // Temp test exclusion while in development
|
||||||
"!src/layouts/review/*.vue", // Temp test exclusion while in development
|
"!src/layouts/review/*.vue", // Temp test exclusion while in development
|
||||||
|
"!src/layouts/payment/*.vue", // Temp test exclusion while in development
|
||||||
|
"!src/layouts/payment-pia-return/*.vue", // Temp test exclusion while in development
|
||||||
// END
|
// END
|
||||||
], // ! means exclude from coverage.
|
], // ! means exclude from coverage.
|
||||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||||
|
|
|
||||||
18
src/App.vue
18
src/App.vue
|
|
@ -5,15 +5,33 @@
|
||||||
<component :is="Component" @focusin="handleAnyComponentFocus" />
|
<component :is="Component" @focusin="handleAnyComponentFocus" />
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
<loadingModal :showLoader="shouldShowLoader" :showTextCarousel="shouldShowTextCarousel" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { handleAnyComponentFocus } from "@/helpers/button-question-focus-helper";
|
import { handleAnyComponentFocus } from "@/helpers/button-question-focus-helper";
|
||||||
|
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||||
|
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
|
||||||
export default {
|
export default {
|
||||||
name: "app",
|
name: "app",
|
||||||
|
setup() {
|
||||||
|
const { globalNonpersistedState } = showFmgLoadingModal();
|
||||||
|
return { globalNonpersistedState };
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleAnyComponentFocus: handleAnyComponentFocus,
|
handleAnyComponentFocus: handleAnyComponentFocus,
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
shouldShowLoader() {
|
||||||
|
return this.globalNonpersistedState.showLoadingModal;
|
||||||
|
},
|
||||||
|
shouldShowTextCarousel() {
|
||||||
|
return this.globalNonpersistedState.showTextCarousel;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
loadingModal,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@ import listButton from "@/ux-components/list-button/list-button";
|
||||||
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
|
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
|
||||||
import listCard from "@/ux-components/list-card/list-card";
|
import listCard from "@/ux-components/list-card/list-card";
|
||||||
import radio from "@/ux-components/radio/radio";
|
import radio from "@/ux-components/radio/radio";
|
||||||
|
import checkbox from "@/ux-components/checkbox/checkbox";
|
||||||
import { useField, ErrorMessage } from "vee-validate";
|
import { useField, ErrorMessage } from "vee-validate";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
|
|
||||||
|
|
@ -132,7 +133,6 @@ export default {
|
||||||
suppressError: Boolean,
|
suppressError: Boolean,
|
||||||
useTextForValue: Boolean,
|
useTextForValue: Boolean,
|
||||||
valueToLogType: String,
|
valueToLogType: String,
|
||||||
additionalButtonData: Object,
|
|
||||||
isSmallQuestionText: Boolean,
|
isSmallQuestionText: Boolean,
|
||||||
customButtonQuestionId: String,
|
customButtonQuestionId: String,
|
||||||
logDisplayedValuesEvent: {
|
logDisplayedValuesEvent: {
|
||||||
|
|
@ -209,6 +209,9 @@ export default {
|
||||||
case "radio":
|
case "radio":
|
||||||
classes = "ui-radio d-flex";
|
classes = "ui-radio d-flex";
|
||||||
break;
|
break;
|
||||||
|
case "checkbox":
|
||||||
|
classes = "ui-checkbox d-flex";
|
||||||
|
break;
|
||||||
case "servicePackageRadio":
|
case "servicePackageRadio":
|
||||||
classes = "package-main";
|
classes = "package-main";
|
||||||
break;
|
break;
|
||||||
|
|
@ -252,7 +255,7 @@ export default {
|
||||||
buttonFooterCopy: answer.buttonFooterCopy ?? answer.buttonFooterCopy,
|
buttonFooterCopy: answer.buttonFooterCopy ?? answer.buttonFooterCopy,
|
||||||
buttonImage: answer.buttonImage ?? answer.AnswerImageUrl,
|
buttonImage: answer.buttonImage ?? answer.AnswerImageUrl,
|
||||||
buttonImageId: answer.buttonImageId ?? answer.ImageId,
|
buttonImageId: answer.buttonImageId ?? answer.ImageId,
|
||||||
additionalButtonData: answer.additionalButtonData ?? answer.additionalButtonData,
|
additionalButtonData: answer.additionalButtonData,
|
||||||
groupName: this.formatString(this.groupName),
|
groupName: this.formatString(this.groupName),
|
||||||
value:
|
value:
|
||||||
answer.value ??
|
answer.value ??
|
||||||
|
|
@ -317,6 +320,7 @@ export default {
|
||||||
listCard,
|
listCard,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
radio,
|
radio,
|
||||||
|
checkbox,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
<template>
|
|
||||||
<transition name="fade" mode="out-in">
|
|
||||||
<div class="add-vaps-buttons" aria-live="polite" v-if="isDisplayed">
|
|
||||||
<buttonQuestion
|
|
||||||
ref="buttonQuestion"
|
|
||||||
:answers="answersToDisplay"
|
|
||||||
groupName="addVaps"
|
|
||||||
v-model="selectedValues"
|
|
||||||
buttonTypeString="addVapsButton"
|
|
||||||
:buttonTypeObject="addVapsButton"
|
|
||||||
:isWide="answersToDisplay.length > 1 ? false : true" />
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import buttonQuestion from "@/digital-components/button-question/button-question";
|
|
||||||
import addVapsButton from "./add-vaps-button/add-vaps-button";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "add-vaps-modal-buttons",
|
|
||||||
props: {
|
|
||||||
cartItems: Object,
|
|
||||||
vapsTilesCmsName: String,
|
|
||||||
availableLineItems: Object,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
addVapsButton: addVapsButton,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
selectedValues: {
|
|
||||||
get: function () {
|
|
||||||
return this.answersToDisplay;
|
|
||||||
},
|
|
||||||
set: function (newValue) {
|
|
||||||
// TODO - emit event to open modal
|
|
||||||
},
|
|
||||||
},
|
|
||||||
isDisplayed() {
|
|
||||||
return this.showAddRainDefense || this.showAddWipers;
|
|
||||||
},
|
|
||||||
showAddRainDefense() {
|
|
||||||
// if not found in the cart
|
|
||||||
return !this.cartItems.some((vap) => {
|
|
||||||
return vap?.partType === "RAIN DEFENSE";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
showAddWipers() {
|
|
||||||
// if not found in the cart
|
|
||||||
return !this.cartItems.some((vap) => {
|
|
||||||
return vap?.partType?.includes(" WIPER");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
rainDefensePrice() {
|
|
||||||
// const lineItem = this.rainDefenseItem;
|
|
||||||
const lineItem = this.availableLineItems.find((item) => {
|
|
||||||
return item.partType === "RAIN DEFENSE";
|
|
||||||
});
|
|
||||||
|
|
||||||
const price = lineItem?.laborAmount + lineItem?.sellingPrice + lineItem?.kitPrice;
|
|
||||||
return parseFloat(price).toFixed(2);
|
|
||||||
},
|
|
||||||
wipersPrice() {
|
|
||||||
let price = 0;
|
|
||||||
const lineItems = this.availableLineItems.filter((item) => {
|
|
||||||
return item.partType.includes(" WIPER");
|
|
||||||
});
|
|
||||||
lineItems?.forEach((item) => {
|
|
||||||
price += item?.laborAmount + item?.sellingPrice + item?.kitPrice;
|
|
||||||
});
|
|
||||||
return parseFloat(price).toFixed(2);
|
|
||||||
},
|
|
||||||
answersCmsData() {
|
|
||||||
return this.getCmsContent(this.vapsTilesCmsName, "Answers");
|
|
||||||
},
|
|
||||||
answersToDisplay() {
|
|
||||||
const answers = [];
|
|
||||||
if (!this.answersCmsData) return answers;
|
|
||||||
|
|
||||||
const getAnswer = (name, answers) => {
|
|
||||||
const answerIndex = answers.findIndex((answer) => {
|
|
||||||
return answer.Name === name;
|
|
||||||
});
|
|
||||||
return answers[answerIndex];
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.showAddWipers) {
|
|
||||||
const answer = getAnswer("WipersModal", this.answersCmsData);
|
|
||||||
answer.SubText = "+$" + this.wipersPrice;
|
|
||||||
answers.push(answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (this.showAddRainDefense) {
|
|
||||||
// const answer = getAnswer("RainDefenseModal", this.answersCmsData);
|
|
||||||
// answer.SubText = "+$" + this.rainDefensePrice;
|
|
||||||
// answers.push(answer);
|
|
||||||
// }
|
|
||||||
|
|
||||||
return answers;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
buttonQuestion,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="isModalVisible">
|
<div v-if="showModalContent">
|
||||||
<div v-if="notFullScreen" class="dimmer-overlay"></div>
|
<div v-if="notFullScreen" class="dimmer-overlay"></div>
|
||||||
<div class="modal-loader" :class="layoutClass">
|
<div class="modal-loader" :class="layoutClass">
|
||||||
<div class="row g-2 h-100 d-flex align-items-center">
|
<div class="row g-2 h-100 d-flex align-items-center">
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div v-if="showTextCarouselContent" class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="text-container slide">
|
<div class="text-container slide">
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -59,6 +59,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isModalVisible: false,
|
isModalVisible: false,
|
||||||
|
isModalTextCarouselVisible: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -66,15 +67,30 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
showLoader: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
showTextCarousel: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
layoutClass() {
|
layoutClass() {
|
||||||
return this.notFullScreen ? "card-layout" : "full-screen container-fluid";
|
return this.notFullScreen ? "card-layout" : "full-screen container-fluid";
|
||||||
},
|
},
|
||||||
|
showModalContent() {
|
||||||
|
return this.isModalVisible || this.showLoader;
|
||||||
|
},
|
||||||
|
showTextCarouselContent() {
|
||||||
|
return this.isModalTextCarouselVisible || this.showTextCarousel;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showModal() {
|
showModal(showTextCarousel = true) {
|
||||||
//Display modal
|
//Display modal
|
||||||
|
this.isModalTextCarouselVisible = showTextCarousel;
|
||||||
this.isModalVisible = true;
|
this.isModalVisible = true;
|
||||||
//Force page reload on back button
|
//Force page reload on back button
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
|
|
|
||||||
18
src/helpers/loading-modal-helper.js
Normal file
18
src/helpers/loading-modal-helper.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { reactive } from "vue";
|
||||||
|
|
||||||
|
// state encapsulated and managed by the composable
|
||||||
|
const globalNonpersistedState = reactive({
|
||||||
|
showLoadingModal: true,
|
||||||
|
showTextCarousel: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const showFmgLoadingModal = (newValue, showTextCarousel = false) => {
|
||||||
|
if (newValue !== undefined) {
|
||||||
|
globalNonpersistedState.showLoadingModal = newValue;
|
||||||
|
}
|
||||||
|
if (showTextCarousel !== undefined) {
|
||||||
|
globalNonpersistedState.showTextCarousel = showTextCarousel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { globalNonpersistedState };
|
||||||
|
};
|
||||||
|
|
@ -26,30 +26,23 @@
|
||||||
v-if="wipersModal"
|
v-if="wipersModal"
|
||||||
@footer-button-action="addWipersToCart('WipersModal', wipersModal)"
|
@footer-button-action="addWipersToCart('WipersModal', wipersModal)"
|
||||||
footerButtonActionName="footer-button-action">
|
footerButtonActionName="footer-button-action">
|
||||||
<div v-if="wipersToDisplay === wipersToDisplayStrings.BOTH" class="wiper-options">
|
<div v-if="wipersOffered === wipersOfferedStrings.BOTH" class="wiper-options">
|
||||||
<div>
|
<buttonQuestion
|
||||||
<checkboxQuestion
|
ref="buttonQuestion"
|
||||||
class="mb-5"
|
buttonTypeString="checkbox"
|
||||||
cmsWidgetName="AddFrontBladesQuestionWidget"
|
class="mt-5"
|
||||||
v-model="selectedFrontWipers" />
|
:answers="wipersOptions"
|
||||||
<p class="price">+${{ wipersModal.totalFrontPrice }}</p>
|
groupName="wipers-options"
|
||||||
</div>
|
textPosition="text-center"
|
||||||
<div>
|
v-model="selectedWipers"
|
||||||
<checkboxQuestion
|
isMultiSelect
|
||||||
class="mb-5"
|
isRequired
|
||||||
cmsWidgetName="AddRearBladesQuestionWidget"
|
validationRules="checkbox-required" />
|
||||||
v-model="selectedRearWipers" />
|
|
||||||
<p class="price">+${{ wipersModal.totalRearPrice }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-else-if="wipersOffered === wipersOfferedStrings.FRONT" class="wiper-options">
|
||||||
v-else-if="wipersToDisplay === wipersToDisplayStrings.FRONT"
|
|
||||||
class="wiper-options">
|
|
||||||
<p class="price">+${{ wipersModal.totalFrontPrice }}</p>
|
<p class="price">+${{ wipersModal.totalFrontPrice }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-else-if="wipersOffered === wipersOfferedStrings.REAR" class="wiper-options">
|
||||||
v-else-if="wipersToDisplay === wipersToDisplayStrings.REAR"
|
|
||||||
class="wiper-options">
|
|
||||||
<p class="price">+${{ wipersModal.totalRearPrice }}</p>
|
<p class="price">+${{ wipersModal.totalRearPrice }}</p>
|
||||||
</div>
|
</div>
|
||||||
</contentGroupModal>
|
</contentGroupModal>
|
||||||
|
|
@ -62,12 +55,17 @@
|
||||||
import buttonQuestion from "@/digital-components/button-question/button-question";
|
import buttonQuestion from "@/digital-components/button-question/button-question";
|
||||||
import addVapsButton from "./add-vaps-button/add-vaps-button";
|
import addVapsButton from "./add-vaps-button/add-vaps-button";
|
||||||
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
|
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
|
||||||
import checkboxQuestion from "@/digital-components/checkbox-question/checkbox-question";
|
|
||||||
|
|
||||||
// SUPPORTING
|
// SUPPORTING
|
||||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||||
|
import { defineRule } from "vee-validate";
|
||||||
|
import { required } from "@/helpers/validation-rules";
|
||||||
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
|
||||||
const wipersToDisplayStrings = {
|
// DEFINE VALIDATION RULES
|
||||||
|
defineRule("checkbox-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
||||||
|
const wipersOfferedStrings = {
|
||||||
FRONT: "FRONT",
|
FRONT: "FRONT",
|
||||||
REAR: "REAR",
|
REAR: "REAR",
|
||||||
BOTH: "BOTH",
|
BOTH: "BOTH",
|
||||||
|
|
@ -83,15 +81,18 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
addVapsButton: addVapsButton,
|
addVapsButton: addVapsButton,
|
||||||
selectedFrontWipers: false,
|
wipersOffered: null,
|
||||||
selectedRearWipers: false,
|
isModalOpened: false,
|
||||||
wipersToDisplay: null,
|
selectedWipers: this.getSelectedWipers(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openModal(modalName) {
|
openModal(modalName) {
|
||||||
this.$refs[modalName].openModal();
|
this.$refs[modalName].openModal();
|
||||||
},
|
},
|
||||||
|
closeModal(modalName) {
|
||||||
|
this.$refs[modalName].closeModal();
|
||||||
|
},
|
||||||
addRainDefenseToCart(modalName, part) {
|
addRainDefenseToCart(modalName, part) {
|
||||||
const alreadyInCart = this.currentCartItems.vaps.some((item) => {
|
const alreadyInCart = this.currentCartItems.vaps.some((item) => {
|
||||||
return item.partType === part.partType;
|
return item.partType === part.partType;
|
||||||
|
|
@ -99,9 +100,11 @@ export default {
|
||||||
if (!alreadyInCart) {
|
if (!alreadyInCart) {
|
||||||
this.currentCartItems.vaps.push(part);
|
this.currentCartItems.vaps.push(part);
|
||||||
}
|
}
|
||||||
this.$refs[modalName].closeModal();
|
this.closeModal(modalName);
|
||||||
},
|
},
|
||||||
addWipersToCart(modalName, part) {
|
addWipersToCart(modalName, part) {
|
||||||
|
const itemsForCart = [];
|
||||||
|
|
||||||
const frontWipersAlreadyInCart = this.currentCartItems.vaps.some((item) => {
|
const frontWipersAlreadyInCart = this.currentCartItems.vaps.some((item) => {
|
||||||
return item.partType === part.frontWiperLineItems[0].partType;
|
return item.partType === part.frontWiperLineItems[0].partType;
|
||||||
});
|
});
|
||||||
|
|
@ -109,36 +112,43 @@ export default {
|
||||||
return item.partType === part.rearWiperLineItems[0]?.partType;
|
return item.partType === part.rearWiperLineItems[0]?.partType;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.wipersToDisplay === wipersToDisplayStrings.FRONT) {
|
if (this.wipersOffered === wipersOfferedStrings.BOTH) {
|
||||||
this.selectedFrontWipers = true; // set as true if front wipers is only option
|
this.selectedWipers.forEach((wiper) => {
|
||||||
|
itemsForCart.push(wiper);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
!frontWipersAlreadyInCart &&
|
||||||
|
this.wipersOffered === wipersOfferedStrings.FRONT
|
||||||
|
) {
|
||||||
|
itemsForCart.push(wipersOfferedStrings.FRONT);
|
||||||
|
}
|
||||||
|
if (!rearWipersAlreadyInCart && this.wipersOffered === wipersOfferedStrings.REAR) {
|
||||||
|
itemsForCart.push(wipersOfferedStrings.REAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.wipersToDisplay === wipersToDisplayStrings.REAR) {
|
|
||||||
this.selectedRearWipers = true; // set as true if rear wipers is only option
|
itemsForCart.forEach((type) => {
|
||||||
}
|
if (type === wipersOfferedStrings.FRONT) {
|
||||||
if (!frontWipersAlreadyInCart && this.selectedFrontWipers) {
|
|
||||||
if (part.frontWiperLineItems) {
|
|
||||||
// for wipers, a "combined" part (frontWiperLineItems)
|
|
||||||
part.frontWiperLineItems.forEach((part) => {
|
part.frontWiperLineItems.forEach((part) => {
|
||||||
this.currentCartItems.vaps.push(part);
|
this.currentCartItems.vaps.push(part);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
if (type === wipersOfferedStrings.REAR) {
|
||||||
if (!rearWipersAlreadyInCart && this.selectedRearWipers) {
|
|
||||||
if (part.rearWiperLineItems) {
|
|
||||||
part.rearWiperLineItems.forEach((part) => {
|
part.rearWiperLineItems.forEach((part) => {
|
||||||
this.currentCartItems.vaps.push(part);
|
this.currentCartItems.vaps.push(part);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
this.$refs[modalName].closeModal();
|
|
||||||
|
|
||||||
if (this.wipersToDisplay === wipersToDisplayStrings.BOTH) {
|
this.closeModal(modalName);
|
||||||
this.selectedFrontWipers = false; // set as false if both options are given
|
this.selectedWipers;
|
||||||
this.selectedRearWipers = false; // set as false if both options are given
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
updateWipersToDisplay(value) {
|
updateWipersOffered(value) {
|
||||||
this.wipersToDisplay = value;
|
this.wipersOffered = value;
|
||||||
|
},
|
||||||
|
getSelectedWipers() {
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -229,31 +239,72 @@ export default {
|
||||||
];
|
];
|
||||||
prices.sort((a, b) => a - b);
|
prices.sort((a, b) => a - b);
|
||||||
modalData.SubText = "+$" + prices[0] + " - $" + prices[prices.length - 1];
|
modalData.SubText = "+$" + prices[0] + " - $" + prices[prices.length - 1];
|
||||||
this.updateWipersToDisplay(wipersToDisplayStrings.BOTH);
|
this.updateWipersOffered(wipersOfferedStrings.BOTH);
|
||||||
buttons.push(modalData);
|
buttons.push(modalData);
|
||||||
} else {
|
} else {
|
||||||
// NO FRONT WIPERS IN CART; SHOW ONLY FRONT WIPERS BUTTON
|
// NO FRONT WIPERS IN CART; SHOW ONLY FRONT WIPERS BUTTON
|
||||||
modalData.SubText = "+$" + this.wipersModal?.totalFrontPrice;
|
modalData.SubText = "+$" + this.wipersModal?.totalFrontPrice;
|
||||||
this.updateWipersToDisplay(wipersToDisplayStrings.FRONT);
|
this.updateWipersOffered(wipersOfferedStrings.FRONT);
|
||||||
buttons.push(modalData);
|
buttons.push(modalData);
|
||||||
}
|
}
|
||||||
} else if (!rearWipersInCart && this.wipersModal?.rearWiperLineItems.length > 0) {
|
} else if (!rearWipersInCart && this.wipersModal?.rearWiperLineItems.length > 0) {
|
||||||
// NO REAR WIPERS IN CART; SHOW ONLY REAR WIPERS BUTTON
|
// NO REAR WIPERS IN CART; SHOW ONLY REAR WIPERS BUTTON
|
||||||
modalData.SubText = "+$" + this.wipersModal?.totalRearPrice;
|
modalData.SubText = "+$" + this.wipersModal?.totalRearPrice;
|
||||||
this.updateWipersToDisplay(wipersToDisplayStrings.REAR);
|
this.updateWipersOffered(wipersOfferedStrings.REAR);
|
||||||
buttons.push(modalData);
|
buttons.push(modalData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buttons;
|
return buttons;
|
||||||
},
|
},
|
||||||
wipersToDisplayStrings() {
|
wipersOfferedStrings() {
|
||||||
return wipersToDisplayStrings;
|
return wipersOfferedStrings;
|
||||||
|
},
|
||||||
|
wipersOptions() {
|
||||||
|
const wipersOptions = [];
|
||||||
|
const wipersFrontCopy = this.getCmsContent(
|
||||||
|
"AddFrontBladesQuestionWidget",
|
||||||
|
"QuestionText"
|
||||||
|
);
|
||||||
|
const wipersRearCopy = this.getCmsContent(
|
||||||
|
"AddRearBladesQuestionWidget",
|
||||||
|
"QuestionText"
|
||||||
|
);
|
||||||
|
const frontWipersLineItems = this.wipersModal.frontWiperLineItems;
|
||||||
|
const rearWipersLineItems = this.wipersModal.rearWiperLineItems;
|
||||||
|
|
||||||
|
if (frontWipersLineItems) {
|
||||||
|
const wipersOption = {
|
||||||
|
buttonLabel: wipersFrontCopy,
|
||||||
|
groupName: "wipers-options",
|
||||||
|
value: wipersOfferedStrings.FRONT,
|
||||||
|
buttonLabelSubCopy: "buttonLabelSubCopy",
|
||||||
|
buttonBodyCopy: "buttonBodyCopy",
|
||||||
|
buttonAuxillaryCopy: "buttonAuxillaryCopy",
|
||||||
|
buttonFooterCopy: "buttonFooterCopy",
|
||||||
|
additionalButtonData: "+$" + this.wipersModal.totalFrontPrice,
|
||||||
|
};
|
||||||
|
wipersOptions.push(wipersOption);
|
||||||
|
}
|
||||||
|
if (rearWipersLineItems) {
|
||||||
|
const wipersOption = {
|
||||||
|
buttonLabel: wipersRearCopy,
|
||||||
|
groupName: "wipers-options",
|
||||||
|
value: wipersOfferedStrings.REAR,
|
||||||
|
buttonLabelSubCopy: "buttonLabelSubCopy",
|
||||||
|
buttonBodyCopy: "buttonBodyCopy",
|
||||||
|
buttonAuxillaryCopy: "buttonAuxillaryCopy",
|
||||||
|
buttonFooterCopy: "buttonFooterCopy",
|
||||||
|
additionalButtonData: "+$" + this.wipersModal.totalRearPrice,
|
||||||
|
};
|
||||||
|
wipersOptions.push(wipersOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
return wipersOptions;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
contentGroupModal,
|
contentGroupModal,
|
||||||
checkboxQuestion,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -286,26 +337,31 @@ export default {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.wiper-options {
|
.wiper-options {
|
||||||
& > div {
|
.ui-checkbox {
|
||||||
display: flex;
|
display: block;
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
|
|
||||||
&:last-child {
|
& > div.col {
|
||||||
margin-bottom: 0;
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.checkbox {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
.form-check {
|
.additional-button-data {
|
||||||
margin-bottom: 0;
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.75;
|
||||||
|
padding-left: 0.5rem;
|
||||||
|
color: $green;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p {
|
p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
line-height: 1.75;
|
||||||
p.price {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
padding-left: 0.5rem;
|
|
||||||
color: $green;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -186,18 +186,21 @@ describe("shop-question.vue", () => {
|
||||||
buttonLabel: "Westerville",
|
buttonLabel: "Westerville",
|
||||||
buttonLabelSubCopy: "5 mi",
|
buttonLabelSubCopy: "5 mi",
|
||||||
value: "003335",
|
value: "003335",
|
||||||
|
additionalButtonData: wrapper.vm.additionalButtonData,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085",
|
buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085",
|
||||||
buttonLabel: "Worthington",
|
buttonLabel: "Worthington",
|
||||||
buttonLabelSubCopy: "10.5 mi",
|
buttonLabelSubCopy: "10.5 mi",
|
||||||
value: "001820",
|
value: "001820",
|
||||||
|
additionalButtonData: wrapper.vm.additionalButtonData,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
buttonBodyCopy: "5015 N High St, Columbus, OH 43214",
|
buttonBodyCopy: "5015 N High St, Columbus, OH 43214",
|
||||||
buttonLabel: "Columbus",
|
buttonLabel: "Columbus",
|
||||||
buttonLabelSubCopy: "11.5 mi",
|
buttonLabelSubCopy: "11.5 mi",
|
||||||
value: "003343",
|
value: "003343",
|
||||||
|
additionalButtonData: wrapper.vm.additionalButtonData,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
@ -414,6 +417,10 @@ describe("shop-question.vue", () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
displayedAnswers.forEach(
|
||||||
|
(answer) => (answer.additionalButtonData = wrapper.vm.additionalButtonData)
|
||||||
|
);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.setProps({
|
await wrapper.setProps({
|
||||||
shopProviderData: shopQuestionInitialData,
|
shopProviderData: shopQuestionInitialData,
|
||||||
|
|
@ -445,42 +452,49 @@ describe("shop-question.vue", () => {
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.answers.length).toBe(6);
|
expect(wrapper.vm.answers.length).toBe(6);
|
||||||
|
console.log(wrapper.vm.answers);
|
||||||
expect(wrapper.vm.answers).toEqual([
|
expect(wrapper.vm.answers).toEqual([
|
||||||
{
|
{
|
||||||
buttonBodyCopy: "4403 Executive Pkwy, Westerville, OH 43081",
|
buttonBodyCopy: "4403 Executive Pkwy, Westerville, OH 43081",
|
||||||
buttonLabel: "Westerville",
|
buttonLabel: "Westerville",
|
||||||
buttonLabelSubCopy: "5 mi",
|
buttonLabelSubCopy: "5 mi",
|
||||||
value: "003335",
|
value: "003335",
|
||||||
|
additionalButtonData: wrapper.vm.additionalButtonData,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085",
|
buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085",
|
||||||
buttonLabel: "Worthington",
|
buttonLabel: "Worthington",
|
||||||
buttonLabelSubCopy: "10.5 mi",
|
buttonLabelSubCopy: "10.5 mi",
|
||||||
value: "001820",
|
value: "001820",
|
||||||
|
additionalButtonData: wrapper.vm.additionalButtonData,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
buttonBodyCopy: "5015 N High St, Columbus, OH 43214",
|
buttonBodyCopy: "5015 N High St, Columbus, OH 43214",
|
||||||
buttonLabel: "Columbus",
|
buttonLabel: "Columbus",
|
||||||
buttonLabelSubCopy: "11.5 mi",
|
buttonLabelSubCopy: "11.5 mi",
|
||||||
value: "003343",
|
value: "003343",
|
||||||
|
additionalButtonData: wrapper.vm.additionalButtonData,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
buttonBodyCopy: "1670 Harmon Ave, Columbus, OH 43223",
|
buttonBodyCopy: "1670 Harmon Ave, Columbus, OH 43223",
|
||||||
buttonLabel: "Columbus",
|
buttonLabel: "Columbus",
|
||||||
buttonLabelSubCopy: "16 mi",
|
buttonLabelSubCopy: "16 mi",
|
||||||
value: "006747",
|
value: "006747",
|
||||||
|
additionalButtonData: wrapper.vm.additionalButtonData,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
buttonBodyCopy: "3938 Powell Rd, Powell, OH 43065",
|
buttonBodyCopy: "3938 Powell Rd, Powell, OH 43065",
|
||||||
buttonLabel: "Powell",
|
buttonLabel: "Powell",
|
||||||
buttonLabelSubCopy: "16.5 mi",
|
buttonLabelSubCopy: "16.5 mi",
|
||||||
value: "003341",
|
value: "003341",
|
||||||
|
additionalButtonData: wrapper.vm.additionalButtonData,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
buttonBodyCopy: "4580 W Broad St, Columbus, OH 43228",
|
buttonBodyCopy: "4580 W Broad St, Columbus, OH 43228",
|
||||||
buttonLabel: "Columbus",
|
buttonLabel: "Columbus",
|
||||||
buttonLabelSubCopy: "19.5 mi",
|
buttonLabelSubCopy: "19.5 mi",
|
||||||
value: "003342",
|
value: "003342",
|
||||||
|
additionalButtonData: wrapper.vm.additionalButtonData,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,7 @@
|
||||||
textPosition="text-start"
|
textPosition="text-start"
|
||||||
v-model="selectedProviderNumber"
|
v-model="selectedProviderNumber"
|
||||||
isRequired
|
isRequired
|
||||||
validationRules="option-required"
|
validationRules="option-required" />
|
||||||
:additionalButtonData="additionalButtonData" />
|
|
||||||
<textLink
|
<textLink
|
||||||
v-if="displaySeeMoreLocationsLink"
|
v-if="displaySeeMoreLocationsLink"
|
||||||
ref="showMoreShopsLink"
|
ref="showMoreShopsLink"
|
||||||
|
|
@ -156,6 +155,7 @@ export default {
|
||||||
buttonLabel: city,
|
buttonLabel: city,
|
||||||
buttonLabelSubCopy: `${distanceInMiles} mi`,
|
buttonLabelSubCopy: `${distanceInMiles} mi`,
|
||||||
buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`,
|
buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`,
|
||||||
|
additionalButtonData: this.additionalButtonData,
|
||||||
value: shopProvider.providerNumber,
|
value: shopProvider.providerNumber,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { globalEvents, globalEventTypes } from "@/constants/events";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||||
import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
|
import { getDeviceIdValue } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import { showFmgLoadingModal } from "@/helpers/loading-modal-helper";
|
||||||
|
|
||||||
// Heritage integration
|
// Heritage integration
|
||||||
import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper";
|
import { isSavedSessionStillActive } from "@/helpers/heritage-integration/session-helper";
|
||||||
|
|
@ -154,6 +155,11 @@ router.beforeEach(async (to, from, next) => {
|
||||||
// use current page url query string name when to.name is "root" (due to unresolved navigation in beforeEach)
|
// use current page url query string name when to.name is "root" (due to unresolved navigation in beforeEach)
|
||||||
router.lastNavigationPage = to.name == "root" ? analyticsMixin.methods.getPageName() : to.name;
|
router.lastNavigationPage = to.name == "root" ? analyticsMixin.methods.getPageName() : to.name;
|
||||||
|
|
||||||
|
const fromQueryPage = from.query?.fmgPage;
|
||||||
|
if (fromQueryPage === undefined) {
|
||||||
|
showFmgLoadingModal(true);
|
||||||
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -171,6 +177,8 @@ router.afterEach(async (to, from) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showFmgLoadingModal(false);
|
||||||
|
|
||||||
// Push page view to GA
|
// Push page view to GA
|
||||||
analyticsMixin.methods.pushPageViewToGA();
|
analyticsMixin.methods.pushPageViewToGA();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2196,15 +2196,25 @@ export const actions = {
|
||||||
"lineItems"
|
"lineItems"
|
||||||
);
|
);
|
||||||
|
|
||||||
let queryString =
|
let queryString = "";
|
||||||
`ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` +
|
if (appointmentType == "Mobile") {
|
||||||
`&BillToAccountNumber=${billToAccountNumber}` +
|
queryString =
|
||||||
`&ProviderNumber=${providerNumber}` +
|
`ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` +
|
||||||
`&AppointmentType=${appointmentType}` +
|
`&BillToAccountNumber=${billToAccountNumber}` +
|
||||||
`&ServiceLocation.City=${serviceLocationCity}` +
|
`&ProviderNumber=${providerNumber}` +
|
||||||
`&ServiceLocation.State=${serviceLocationState}` +
|
`&AppointmentType=${appointmentType}` +
|
||||||
`&ServiceLocation.ZipCode=${serviceLocationZipCode}` +
|
`&ServiceLocation.City=${serviceLocationCity}` +
|
||||||
`&${pricedLineItemsFormattedForRequest}`;
|
`&ServiceLocation.State=${serviceLocationState}` +
|
||||||
|
`&ServiceLocation.ZipCode=${serviceLocationZipCode}` +
|
||||||
|
`&${pricedLineItemsFormattedForRequest}`;
|
||||||
|
} else {
|
||||||
|
queryString =
|
||||||
|
`ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` +
|
||||||
|
`&BillToAccountNumber=${billToAccountNumber}` +
|
||||||
|
`&ProviderNumber=${providerNumber}` +
|
||||||
|
`&AppointmentType=${appointmentType}` +
|
||||||
|
`&${pricedLineItemsFormattedForRequest}`;
|
||||||
|
}
|
||||||
|
|
||||||
const lineItemServerData = context.getters.order.lineItems.serverData;
|
const lineItemServerData = context.getters.order.lineItems.serverData;
|
||||||
if (lineItemServerData) {
|
if (lineItemServerData) {
|
||||||
|
|
@ -2257,13 +2267,18 @@ export const actions = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateResponse = await globalMethods.callHttpClient({
|
const validateResponse = await globalMethods
|
||||||
method: endpoints.ValidatePromo.method,
|
.callHttpClient({
|
||||||
endpoint: endpoints.ValidatePromo.url,
|
method: endpoints.ValidatePromo.method,
|
||||||
payload: requestObject,
|
endpoint: endpoints.ValidatePromo.url,
|
||||||
logApiCall: true,
|
payload: requestObject,
|
||||||
pageNameToLog: pageNameToLog,
|
logApiCall: true,
|
||||||
});
|
pageNameToLog: pageNameToLog,
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
// Validate promo will return 4xx errors when an invalid promo
|
||||||
|
return error;
|
||||||
|
});
|
||||||
|
|
||||||
if (validateResponse?.data?.serverData) {
|
if (validateResponse?.data?.serverData) {
|
||||||
context.commit(
|
context.commit(
|
||||||
|
|
|
||||||
66
src/ux-components/checkbox/checkbox.spec.js
Normal file
66
src/ux-components/checkbox/checkbox.spec.js
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { mount } from "@vue/test-utils";
|
||||||
|
import checkbox from "./checkbox";
|
||||||
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
|
||||||
|
describe("checkbox.vue", () => {
|
||||||
|
it("Should have correct group name", async () => {
|
||||||
|
// Arrange
|
||||||
|
let { wrapper } = setupMocks({
|
||||||
|
mountOptionsMockData: {
|
||||||
|
propsData: {
|
||||||
|
groupName: "checkbox-button-test",
|
||||||
|
value: "test value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const input = wrapper.find("input");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(input.attributes().name).toEqual("checkbox-button-test");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should have correct label text", async () => {
|
||||||
|
// Act
|
||||||
|
let { wrapper } = setupMocks({
|
||||||
|
mountOptionsMockData: {
|
||||||
|
propsData: {
|
||||||
|
buttonLabel: "label text",
|
||||||
|
value: "test value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Arrange
|
||||||
|
const paragraph = wrapper.find("p");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(paragraph.text()).toEqual("label text");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should have correct screenreader-only text", async () => {
|
||||||
|
// Act
|
||||||
|
let { wrapper } = setupMocks({});
|
||||||
|
|
||||||
|
// Arrange
|
||||||
|
await wrapper.setProps({
|
||||||
|
screenReaderOnlyText: "screenreader text",
|
||||||
|
value: "test value",
|
||||||
|
});
|
||||||
|
const paragraph = wrapper.find(".sr-only");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(paragraph.text()).toEqual("screenreader text");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupMocks({ mountOptionsMockData = {} }) {
|
||||||
|
const wrapper = mount(checkbox, {
|
||||||
|
...mountOptionsMockData,
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
});
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
74
src/ux-components/checkbox/checkbox.vue
Normal file
74
src/ux-components/checkbox/checkbox.vue
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<baseInputButton
|
||||||
|
v-bind="$props"
|
||||||
|
buttonWrapperClasses="form-check base-input-button checkbox"
|
||||||
|
inputClasses="form-check-input"
|
||||||
|
v-model="selectedValue">
|
||||||
|
<div class="d-flex align-items-start form-check-label">
|
||||||
|
<p v-if="buttonLabel" class="m-0">{{ buttonLabel }}</p>
|
||||||
|
<span v-if="screenReaderOnlyText" class="sr-only">{{ screenReaderOnlyText }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="additionalButtonData"
|
||||||
|
v-html="additionalButtonData"
|
||||||
|
class="additional-button-data"></div>
|
||||||
|
</baseInputButton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import baseInputButton from "@/digital-components/base-input-button/base-input-button";
|
||||||
|
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "checkbox",
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
components: {
|
||||||
|
baseInputButton,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.form-check {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.form-check-input {
|
||||||
|
border: 1px solid $gray-500; //
|
||||||
|
border-radius: 2px; //
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
opacity: 1;
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
|
||||||
|
&:checked {
|
||||||
|
background-color: $blue; //
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
border: 1px solid $blue;
|
||||||
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e");
|
||||||
|
|
||||||
|
+ .form-check-label {
|
||||||
|
p {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 0 0 2.5px $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.form-check-input:not(:checked) {
|
||||||
|
box-shadow: 0 0 0 4px $blue-300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: $gray-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in a new issue