CSR-1384: work to add a auto-dismissing alert / 'toast' message for adding vap to cart
This commit is contained in:
parent
4e1f246ae3
commit
20cda7ef69
4 changed files with 113 additions and 32 deletions
|
|
@ -5,14 +5,18 @@
|
|||
<img class="logo-image img-fluid" :src="imageSrc" alt="Safelite logo" />
|
||||
<menuModal />
|
||||
</div>
|
||||
<alert
|
||||
v-if="displayGlobalAlert"
|
||||
class="rounded-0 w-100 border-0 shadow-sm"
|
||||
cmsWidgetName="GlobalAlert"
|
||||
:manualHeadline="globalAlertMessage.messageHeadline"
|
||||
:manualCopy="globalAlertMessage.messageCopy"
|
||||
:alertClass="globalAlertMessage.type"
|
||||
v-bind:isDismissible="globalAlertMessage.isDismissible" />
|
||||
|
||||
<transition name="fade" mode="out-in">
|
||||
<alert
|
||||
v-if="displayGlobalAlert"
|
||||
class="rounded-0 w-100 border-0 shadow-sm"
|
||||
cmsWidgetName="GlobalAlert"
|
||||
:manualHeadline="globalAlertMessage.messageHeadline"
|
||||
:manualCopy="globalAlertMessage.messageCopy"
|
||||
:alertClass="globalAlertMessage.type"
|
||||
:onAlertCloseCallback="onAlertClose"
|
||||
v-bind:isDismissible="globalAlertMessage.isDismissible" />
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -21,6 +25,9 @@ import eventBus from "@/helpers/event-bus/event-bus";
|
|||
import { globalEvents } from "@/constants/events";
|
||||
import menuModal from "@/fmg-components/funnel-header/menu-modal/menu-modal";
|
||||
|
||||
// Constants
|
||||
const ALERT_DURATION = 3000; // millisecond time to display alert before dismissal
|
||||
|
||||
export default {
|
||||
name: "funnel-header",
|
||||
data() {
|
||||
|
|
@ -32,6 +39,7 @@ export default {
|
|||
messageHeadline: "",
|
||||
type: "",
|
||||
},
|
||||
countdownTimer: () => {},
|
||||
};
|
||||
},
|
||||
props: {
|
||||
|
|
@ -42,6 +50,21 @@ export default {
|
|||
return this.getCmsContent(this.cmsWidgetName, "LogoImage");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
triggerGlobalAlert(alertEvent, isAutoDismissing) {
|
||||
clearTimeout(this.countdownTimer);
|
||||
this.displayGlobalAlert = true;
|
||||
this.globalAlertMessage = alertEvent;
|
||||
if (isAutoDismissing) {
|
||||
this.countdownTimer = setTimeout(() => {
|
||||
this.displayGlobalAlert = false;
|
||||
}, ALERT_DURATION);
|
||||
}
|
||||
},
|
||||
onAlertClose() {
|
||||
this.displayGlobalAlert = false;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
alert,
|
||||
menuModal,
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@
|
|||
v-model="selectedWipers"
|
||||
isMultiSelect
|
||||
isRequired
|
||||
validationRules="checkbox-required"
|
||||
:additionalButtonData="additionalButtonData" />
|
||||
validationRules="checkbox-required" />
|
||||
</div>
|
||||
<div v-else-if="wipersOffered === wipersOfferedStrings.FRONT" class="wiper-options">
|
||||
<p class="price">+${{ wipersModal.totalFrontPrice }}</p>
|
||||
|
|
@ -62,6 +61,7 @@ import { partTypeStrings } from "@/constants/part-type-strings";
|
|||
import { defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
import { processIfStatements } from "@/helpers/cms-content-helper";
|
||||
|
||||
// DEFINE VALIDATION RULES
|
||||
defineRule("checkbox-required", required(errorMessages.OPTION_REQUIRED));
|
||||
|
|
@ -88,20 +88,23 @@ export default {
|
|||
};
|
||||
},
|
||||
methods: {
|
||||
processIfStatements,
|
||||
openModal(modalName) {
|
||||
this.selectedWipers = this.getSelectedWipers(); // reset selectedWipers to null upon modal open
|
||||
this.$refs[modalName].openModal();
|
||||
},
|
||||
closeModal(modalName) {
|
||||
this.$refs[modalName].closeModal();
|
||||
},
|
||||
addRainDefenseToCart(modalName, part) {
|
||||
const alreadyInCart = this.currentCartItems.vaps.some((item) => {
|
||||
return item.partType === part.partType;
|
||||
});
|
||||
if (!alreadyInCart) {
|
||||
this.currentCartItems.vaps.push(part);
|
||||
}
|
||||
this.currentCartItems.vaps.push(part);
|
||||
this.closeModal(modalName);
|
||||
const message = this.getRainDefenseAddedMessage();
|
||||
this.$emit("added-to-cart", {
|
||||
messageHeadline: message,
|
||||
type: "alert-success",
|
||||
isDismissible: true,
|
||||
});
|
||||
},
|
||||
addWipersToCart(modalName, part) {
|
||||
const itemsForCart = [];
|
||||
|
|
@ -123,9 +126,11 @@ export default {
|
|||
this.wipersOffered === wipersOfferedStrings.FRONT
|
||||
) {
|
||||
itemsForCart.push(wipersOfferedStrings.FRONT);
|
||||
this.selectedWipers = ["FRONT"];
|
||||
}
|
||||
if (!rearWipersAlreadyInCart && this.wipersOffered === wipersOfferedStrings.REAR) {
|
||||
itemsForCart.push(wipersOfferedStrings.REAR);
|
||||
this.selectedWipers = ["REAR"];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +148,13 @@ export default {
|
|||
});
|
||||
|
||||
this.closeModal(modalName);
|
||||
this.selectedWipers;
|
||||
|
||||
const message = this.getWipersAddedMessage();
|
||||
this.$emit("added-to-cart", {
|
||||
messageHeadline: message,
|
||||
type: "alert-success",
|
||||
isDismissible: true,
|
||||
});
|
||||
},
|
||||
updateWipersOffered(value) {
|
||||
this.wipersOffered = value;
|
||||
|
|
@ -151,6 +162,34 @@ export default {
|
|||
getSelectedWipers() {
|
||||
return null;
|
||||
},
|
||||
getRainDefenseAddedMessage() {
|
||||
return this.AddRainDefenseSuccessMessageFromCms;
|
||||
},
|
||||
getWipersAddedMessage() {
|
||||
return this.processIfStatements(
|
||||
this.AddWipersSuccessMessageFromCms,
|
||||
"custom",
|
||||
this.getCustomValueFromString
|
||||
);
|
||||
},
|
||||
getCustomValueFromString(str) {
|
||||
switch (str) {
|
||||
case "vapsAddedIsFrontWipers":
|
||||
return (
|
||||
this.selectedWipers?.length === 1 &&
|
||||
this.selectedWipers[0] === wipersOfferedStrings.FRONT
|
||||
);
|
||||
case "vapsAddedIsRearWipers":
|
||||
return (
|
||||
this.selectedWipers?.length === 1 &&
|
||||
this.selectedWipers[0] === wipersOfferedStrings.REAR
|
||||
);
|
||||
case "vapsAddedIsBothWipers":
|
||||
return this.selectedWipers?.length > 1;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
currentCartItems() {
|
||||
|
|
@ -302,6 +341,12 @@ export default {
|
|||
|
||||
return wipersOptions;
|
||||
},
|
||||
AddRainDefenseSuccessMessageFromCms() {
|
||||
return this.getCmsContent("AddRainDefenseSuccessMessageWidget", "Text");
|
||||
},
|
||||
AddWipersSuccessMessageFromCms() {
|
||||
return this.getCmsContent("AddWipersSuccessMessageWidget", "Text");
|
||||
},
|
||||
},
|
||||
components: {
|
||||
buttonQuestion,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@
|
|||
<add-vaps-modal-buttons
|
||||
v-model="lineItems"
|
||||
:availableLineItems="availableLineItems"
|
||||
vapsTilesCmsName="VapsProductTiles" />
|
||||
vapsTilesCmsName="VapsProductTiles"
|
||||
@added-to-cart="showAlert" />
|
||||
|
||||
<paymentMethodQuestion
|
||||
v-if="!isPiaDisabled"
|
||||
|
|
@ -321,6 +322,9 @@ export default {
|
|||
this.$route
|
||||
);
|
||||
},
|
||||
showAlert(alert) {
|
||||
this.$refs.funnelHeader.triggerGlobalAlert(alert, true);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
damageInfo() {
|
||||
|
|
|
|||
|
|
@ -2,18 +2,19 @@
|
|||
<div
|
||||
class="alert fade show text-center mb-0 py-2 px-4 border-0"
|
||||
role="alert"
|
||||
v-on="{ 'close.bs.alert': onAlertClose }"
|
||||
:class="[
|
||||
isDismissible ? 'alert-dismissible' : '',
|
||||
this.alertClass,
|
||||
this.cssClassNameForCmsWidget,
|
||||
]">
|
||||
<p class="m-0 fw-bold alert-heading">{{ alertHeadline }}</p>
|
||||
<p class="mx-6 my-0 fw-bold alert-heading">{{ alertHeadline }}</p>
|
||||
<template v-for="paragraph in splitAlertCopyForParagraphTag" :key="paragraph">
|
||||
<p
|
||||
class="m-0 text-body small"
|
||||
class="mx-4 mt-1 text-body small"
|
||||
v-if="!doesCopyContainRouterLink(paragraph) && !doesCopyContainTextLink(paragraph)"
|
||||
v-html="paragraph"></p>
|
||||
<p class="m-0 text-body small" v-else>
|
||||
<p class="mx-4 mt-1 text-body small" v-else>
|
||||
<template v-if="doesCopyContainRouterLink(paragraph)">
|
||||
<textBlock :customText="paragraph" class="mb-1" marginTopSizeOverride="0" />
|
||||
</template>
|
||||
|
|
@ -32,7 +33,7 @@
|
|||
</template>
|
||||
</p>
|
||||
</template>
|
||||
<button type="button" class="btn-close p-2" data-bs-dismiss="alert" aria-label="Close">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23.7 23.7" xml:space="preserve">
|
||||
<path
|
||||
d="m23.24 2.7-9.15 9.15L23.24 21a1.581 1.581 0 0 1-1.12 2.7c-.42 0-.82-.16-1.12-.46l-9.15-9.15-9.15 9.15c-.3.3-.7.46-1.12.46A1.581 1.581 0 0 1 .46 21l8.47-8.47.68-.68L.46 2.7c-.62-.62-.62-1.62 0-2.24.62-.62 1.62-.62 2.24 0l8.47 8.47.68.68L21 .46a1.57 1.57 0 0 1 2.23 0c.63.62.63 1.62.01 2.24z" />
|
||||
|
|
@ -58,14 +59,14 @@ export default {
|
|||
name: "alert",
|
||||
props: {
|
||||
isDismissible: Boolean,
|
||||
/*
|
||||
alertClass class names:
|
||||
alert-success (green)
|
||||
alert-danger (red)
|
||||
alert-warning (yellow)
|
||||
alert-info (blue)
|
||||
*/
|
||||
alertClass: String,
|
||||
/*
|
||||
alertClass class names:
|
||||
alert-success (green)
|
||||
alert-danger (red)
|
||||
alert-warning (yellow)
|
||||
alert-info (blue)
|
||||
*/
|
||||
cmsWidgetName: {
|
||||
type: String,
|
||||
default(rawProps) {
|
||||
|
|
@ -81,6 +82,9 @@ export default {
|
|||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
onAlertCloseCallback: {
|
||||
type: Function,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
pageQueryString() {
|
||||
|
|
@ -124,6 +128,9 @@ export default {
|
|||
document.documentElement.clientHeight - footerHeight)
|
||||
);
|
||||
},
|
||||
onAlertClose() {
|
||||
this.onAlertCloseCallback?.();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.ensureAlertIsInViewPort();
|
||||
|
|
@ -137,6 +144,8 @@ export default {
|
|||
|
||||
<style lang="scss">
|
||||
.alert {
|
||||
padding: 0.675rem 0;
|
||||
|
||||
button {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -145,12 +154,13 @@ export default {
|
|||
opacity: 1;
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
padding: 0;
|
||||
}
|
||||
&.alert-dismissible {
|
||||
button {
|
||||
display: flex;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
top: 0.875rem;
|
||||
right: 1rem;
|
||||
}
|
||||
}
|
||||
&.alert-info {
|
||||
|
|
@ -199,7 +209,6 @@ export default {
|
|||
}
|
||||
& p {
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in a new issue