CASH-2378: new component for multi location modal
This commit is contained in:
parent
0c32eecdcc
commit
b3fb548813
1 changed files with 317 additions and 0 deletions
|
|
@ -0,0 +1,317 @@
|
|||
<template>
|
||||
<div id="multi-location-modal-container">
|
||||
<modal
|
||||
:ref="modalName"
|
||||
:headerText="modalHeaderText"
|
||||
suppressPageScroll
|
||||
:onModalClosedCallback="onModalClosed"
|
||||
:footerButtonText="modalFooterText"
|
||||
:isFooterButtonPrimary="true"
|
||||
@footer-button-event="confirmAppointment"
|
||||
@isModalOpened="setIsModalOpen">
|
||||
<buttonQuestion
|
||||
ref="buttonQuestion"
|
||||
buttonTypeString="multiLocationRadioButton"
|
||||
:buttonTypeObject="multiLocationRadioButton"
|
||||
class="mt-5"
|
||||
:answers="availableAppointments"
|
||||
groupName="multiLocationQuestion"
|
||||
textPosition="text-center"
|
||||
v-model="selectedValue"
|
||||
isRequired
|
||||
validationRules="time-slot-required" />
|
||||
|
||||
<template v-slot:modal-header-slot>
|
||||
<span>{{ modalSubHeaderText }}</span>
|
||||
</template>
|
||||
<template v-slot:modal-footer-slot>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-link"
|
||||
id="see-more-options"
|
||||
:disabled="isLoading"
|
||||
@click="closeModal">
|
||||
{{ buttonText }}
|
||||
</button>
|
||||
</template>
|
||||
</modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Supporting files
|
||||
import store from "@/store";
|
||||
import modal from "@/digital-components/modal/modal";
|
||||
import { splitCopyOnCMSPlaceHolder } from "@/helpers/cms-content-helper";
|
||||
import { get12HourTimeFormat } from "@/helpers/date-helper";
|
||||
import { getDisplayTextForDurationLength } from "@/helpers/duration-length-helper";
|
||||
import buttonQuestion from "@/digital-components/button-question/button-question";
|
||||
import multiLocationRadioButton from "./multi-location-radio/multi-location-radio";
|
||||
|
||||
// Validation
|
||||
import { defineRule, useField } from "vee-validate";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
|
||||
const NULL_APPOINTMENT = {
|
||||
estimatedServiceMinutes: {
|
||||
minimum: null,
|
||||
maximum: null,
|
||||
},
|
||||
timeSlot: null,
|
||||
date: null,
|
||||
};
|
||||
|
||||
// Validation for the modal button
|
||||
defineRule("time-slot-required", required(errorMessages.OPTION_REQUIRED));
|
||||
|
||||
export default {
|
||||
name: "multi-location-modal",
|
||||
props: {
|
||||
cmsWidgetName: String,
|
||||
modalWidgetName: String,
|
||||
buttonWidgetName: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isModalOpen: false,
|
||||
mobileAppointmentOption: NULL_APPOINTMENT,
|
||||
inshopAppointmentOption: NULL_APPOINTMENT,
|
||||
confirmedAppointment: false,
|
||||
multiLocationRadioButton: multiLocationRadioButton,
|
||||
selectedValue: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
splitCopyOnCMSPlaceHolder,
|
||||
get12HourTimeFormat,
|
||||
openModal() {
|
||||
this.modal.openModal();
|
||||
},
|
||||
onModalClosed() {
|
||||
this.pushEvent();
|
||||
this.$emit("close-mobile-first-modal");
|
||||
this.confirmedAppointment = false;
|
||||
},
|
||||
closeModal() {
|
||||
this.modal.closeModal();
|
||||
},
|
||||
confirmAppointment() {
|
||||
if (!this.selectedAppointment) return;
|
||||
|
||||
const selectedTimeSlot = {
|
||||
timeSlot: this.selectedAppointment.timeSlot,
|
||||
routeCode: this.selectedAppointment.timeSlot.id,
|
||||
date: this.selectedAppointment.date,
|
||||
};
|
||||
this.confirmedAppointment = true;
|
||||
this.$emit("confirm-appointment", {
|
||||
selectedTimeSlot: selectedTimeSlot,
|
||||
appointmentType: this.selectedValue,
|
||||
});
|
||||
this.modal.closeModal();
|
||||
},
|
||||
setPromotedMobileAppointment(appointment) {
|
||||
this.mobileAppointmentOption = appointment;
|
||||
},
|
||||
setPromotedInshopAppointment(appointment) {
|
||||
this.inshopAppointmentOption = appointment;
|
||||
},
|
||||
getIsModalOpen() {
|
||||
return this.isModalOpen;
|
||||
},
|
||||
setIsModalOpen(isOpen) {
|
||||
this.isModalOpen = isOpen;
|
||||
},
|
||||
pushEvent() {
|
||||
let gaAction = this.confirmedAppointment ? this.GaActions.YES : this.GaActions.NO;
|
||||
if (this.mobileAppointmentOption && this.mobileAppointmentOption.timeSlot) {
|
||||
this.pushEventToGA(
|
||||
this.GaCategories.CONFIRMATION_CLICKED,
|
||||
gaAction,
|
||||
this.mobileAppointmentOption.timeSlot.startTime +
|
||||
"-" +
|
||||
this.mobileAppointmentOption.timeSlot.endTime +
|
||||
" " +
|
||||
this.mobileAppointmentOption.date,
|
||||
true
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
selectedAppointment() {
|
||||
if (this.selectedValue?.toLowerCase() === "mobile") {
|
||||
return this.mobileAppointmentOption;
|
||||
} else if (this.selectedValue?.toLowerCase() === "inshop") {
|
||||
return this.inshopAppointmentOption;
|
||||
} else {
|
||||
return NULL_APPOINTMENT;
|
||||
}
|
||||
},
|
||||
modalName() {
|
||||
return this.modalWidgetName;
|
||||
},
|
||||
modal() {
|
||||
return this.$refs[this.modalName];
|
||||
},
|
||||
modalSubHeaderText() {
|
||||
return this.getCmsContent(this.modalWidgetName, "SubheaderText");
|
||||
},
|
||||
modalHeaderText() {
|
||||
return this.getCmsContent(this.modalWidgetName, "HeaderText");
|
||||
},
|
||||
modalFooterText() {
|
||||
return this.getCmsContent(this.modalWidgetName, "FooterText");
|
||||
},
|
||||
buttonText() {
|
||||
return this.getCmsContent(this.modalWidgetName, "FooterText2");
|
||||
},
|
||||
mobileButtonLabel() {
|
||||
return this.getCmsContent(this.buttonWidgetName, "HeaderText");
|
||||
},
|
||||
inshopButtonLabel() {
|
||||
return this.getCmsContent(this.buttonWidgetName, "SubheaderText");
|
||||
},
|
||||
mobileButtonDate() {
|
||||
if (!this.mobileAppointmentOption.date) return "";
|
||||
return new Date(this.mobileAppointmentOption.date).toLocaleDateString("en-US", {
|
||||
timeZone: "UTC",
|
||||
weekday: "short",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
},
|
||||
inshopButtonDate() {
|
||||
if (!this.inshopAppointmentOption.date) return "";
|
||||
return new Date(this.inshopAppointmentOption.date).toLocaleDateString("en-US", {
|
||||
timeZone: "UTC",
|
||||
weekday: "short",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
},
|
||||
mobileButtonTime() {
|
||||
const timeslot =
|
||||
this.get12HourTimeFormat(this.mobileAppointmentOption.timeSlot?.startTime) +
|
||||
" - " +
|
||||
this.get12HourTimeFormat(this.mobileAppointmentOption.timeSlot?.endTime);
|
||||
return timeslot;
|
||||
},
|
||||
inshopButtonTime() {
|
||||
const timeslot = this.get12HourTimeFormat(
|
||||
this.inshopAppointmentOption.timeSlot?.startTime
|
||||
);
|
||||
return timeslot;
|
||||
},
|
||||
mobileLocationLabel() {
|
||||
return this.getCmsContent(this.buttonWidgetName, "BodyText");
|
||||
},
|
||||
inshopLocationLabel() {
|
||||
return this.inshopAppointmentOption?.addressCopy;
|
||||
},
|
||||
mobileServiceDuration() {
|
||||
const durationTime = getDisplayTextForDurationLength(
|
||||
this.mobileAppointmentOption.estimatedServiceMinutes.minimum,
|
||||
this.mobileAppointmentOption.estimatedServiceMinutes.maximum
|
||||
);
|
||||
const footerText = this.getCmsContent(this.buttonWidgetName, "FooterText").replaceAll(
|
||||
"{custom:serviceLength}",
|
||||
durationTime
|
||||
);
|
||||
return footerText;
|
||||
},
|
||||
inshopServiceDuration() {
|
||||
const durationTime = getDisplayTextForDurationLength(
|
||||
this.inshopAppointmentOption.estimatedServiceMinutes.minimum,
|
||||
this.inshopAppointmentOption.estimatedServiceMinutes.maximum
|
||||
);
|
||||
const footerText = this.getCmsContent(this.buttonWidgetName, "FooterText").replaceAll(
|
||||
"{custom:serviceLength}",
|
||||
durationTime
|
||||
);
|
||||
return footerText;
|
||||
},
|
||||
availableAppointments() {
|
||||
return [
|
||||
{
|
||||
value: "mobile",
|
||||
buttonLabel: this.mobileButtonDate,
|
||||
buttonLabelSubCopy: this.mobileButtonTime,
|
||||
buttonBodyCopy: this.mobileLocationLabel,
|
||||
buttonAuxillaryCopy: this.mobileButtonLabel,
|
||||
buttonFooterCopy: this.mobileServiceDuration,
|
||||
},
|
||||
{
|
||||
value: "inshop",
|
||||
buttonLabel: this.inshopButtonDate,
|
||||
buttonLabelSubCopy: this.inshopButtonTime,
|
||||
buttonBodyCopy: this.inshopLocationLabel,
|
||||
buttonAuxillaryCopy: this.inshopButtonLabel,
|
||||
buttonFooterCopy: this.inshopServiceDuration,
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
components: { modal, buttonQuestion },
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
#multi-location-modal-container {
|
||||
.modal-component {
|
||||
@include media-breakpoint-up(md) {
|
||||
.modal-dialog {
|
||||
left: 0;
|
||||
align-content: center;
|
||||
flex-wrap: wrap;
|
||||
width: 22.063rem;
|
||||
transform: translate(0, 0);
|
||||
|
||||
.modal-content {
|
||||
border-radius: $border-radius-lg;
|
||||
}
|
||||
}
|
||||
}
|
||||
.modal-dialog {
|
||||
.modal-content {
|
||||
.modal-header {
|
||||
flex-direction: column;
|
||||
& > span {
|
||||
color: $red;
|
||||
font-size: $font-size-14;
|
||||
font-weight: $font-weight-600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: $font-size-20;
|
||||
font-weight: $font-weight-normal;
|
||||
}
|
||||
}
|
||||
.modal-body {
|
||||
padding: 0.5rem 1rem;
|
||||
|
||||
.modal-body-inner {
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 1rem;
|
||||
background-color: #f4f4f4;
|
||||
font-size: $font-size-14;
|
||||
}
|
||||
}
|
||||
}
|
||||
.modal-footer {
|
||||
flex-flow: wrap-reverse;
|
||||
|
||||
#see-more-options {
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
margin-top: 1.5rem;
|
||||
font-weight: $font-weight-600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in a new issue