INSR-7557: Add to calender button fixes
This commit is contained in:
parent
4dab87bf3f
commit
8bf7d282d4
8 changed files with 142 additions and 309 deletions
|
|
@ -7,9 +7,7 @@ module.exports = {
|
|||
ecmaVersion: 'latest'
|
||||
},
|
||||
extends: [
|
||||
'eslint-config-airbnb-base',
|
||||
'plugin:vue/vue3-recommended',
|
||||
'plugin:jsdoc/recommended'
|
||||
'plugin:vue/vue3-recommended'
|
||||
],
|
||||
rules: {
|
||||
'linebreak-style': 'off',
|
||||
|
|
@ -30,10 +28,6 @@ module.exports = {
|
|||
singleline: 'never',
|
||||
multiline: 'never'
|
||||
}],
|
||||
'jsdoc/check-tag-names': ['error', {
|
||||
definedTags: ['store', 'endpoint', 'category', 'subcategory', 'remarks']
|
||||
}],
|
||||
'jsdoc/require-jsdoc': 0,
|
||||
'vue/html-self-closing': ['error', {
|
||||
html: {
|
||||
void: 'any',
|
||||
|
|
@ -43,7 +37,6 @@ module.exports = {
|
|||
svg: 'always',
|
||||
math: 'always'
|
||||
}],
|
||||
'import/extensions': ['error', 'always', { js: 'ignorePackages' }],
|
||||
'no-param-reassign': ['error', { props: true, ignorePropertyModificationsFor: ['item'] }],
|
||||
'no-restricted-syntax': ['off', 'ForOfStatement'],
|
||||
'no-return-await': 'off'
|
||||
|
|
|
|||
|
|
@ -321,7 +321,6 @@ export default {
|
|||
},
|
||||
basePriceLabel() {
|
||||
const content = this.getCmsContent(this.widget.basePrice, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
console.log('Base Price Label before processing if statements:', content);
|
||||
return processIfStatements(
|
||||
content,
|
||||
'custom',
|
||||
|
|
@ -436,7 +435,6 @@ export default {
|
|||
return vapsTypeDescription?.Text ?? '';
|
||||
},
|
||||
getCustomValueFromString(str) {
|
||||
console.log(this.cartOrder)
|
||||
switch (str) {
|
||||
case 'isRepair':
|
||||
return this.cartOrder.damage.isRepair;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="calendar-section">
|
||||
<div class="add-to-calendar">
|
||||
<button @click="openCalendarModal">
|
||||
<button @click="toggleCalendarOptionsOpen">
|
||||
<span class="add-to-calendar-span">
|
||||
<img
|
||||
src="@/assets/img/icons/add-to-calendar.svg"
|
||||
|
|
@ -10,14 +10,12 @@
|
|||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<calendarModalQuestion
|
||||
ref="calendarModalQuestion"
|
||||
v-model="selectedCalendarOption"
|
||||
customComponentId="calendarModalQuestion"
|
||||
cmsWidgetName="CalendarModalQuestion"
|
||||
<calendarOptionSelection
|
||||
ref="calendarOptions"
|
||||
:open="calendarOptionsOpen"
|
||||
:calendarOptionsData="calendarValues"
|
||||
@calendarModalClosed="calendarModalClosed">
|
||||
</calendarModalQuestion>
|
||||
@calendarOptionSelected="calendarOptionSelected">
|
||||
</calendarOptionSelection>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
|
@ -32,12 +30,12 @@ import { AppointmentTypeStrings, RouteCodeFlags } from '@/constants/schedule-con
|
|||
import { getCalendarFile, download } from '@/helpers/add-to-calendar-helper';
|
||||
import serviceType from '@/constants/service-type';
|
||||
import applicationConfig from '@/constants/application-config.js';
|
||||
import calendarModalQuestion from '@/layouts/order-confirmation/add-to-calendar/calendar-modal-question/calendar-modal-question.vue';
|
||||
import calendarOptionSelection from '@/layouts/order-confirmation/add-to-calendar/calendar-option-selection/calendar-option-selection.vue';
|
||||
|
||||
export default {
|
||||
name: 'add-to-calendar',
|
||||
components: {
|
||||
calendarModalQuestion
|
||||
calendarOptionSelection
|
||||
},
|
||||
props: {
|
||||
mobileWidgetName: String,
|
||||
|
|
@ -59,7 +57,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
selectedCalendarOption: null
|
||||
calendarOptionsOpen: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -84,7 +82,7 @@ export default {
|
|||
return this.getCmsContent(this.mobileWidgetName, 'BodyText');
|
||||
},
|
||||
AddToCalendar_InShop_Subject() {
|
||||
return this.getCmsContent('AddToCalendar_InShop', 'HeaderText');
|
||||
return this.getCmsContent(this.inShopWidgetName, 'HeaderText');
|
||||
},
|
||||
AddToCalendar_InShop_Body() {
|
||||
return this.getCmsContent(this.inShopWidgetName, 'BodyText');
|
||||
|
|
@ -192,14 +190,6 @@ export default {
|
|||
};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectedCalendarOption(newValue) {
|
||||
if (newValue) {
|
||||
this.setCalendarAppointment(newValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setCalendarAppointment(calendarOption) {
|
||||
if (
|
||||
|
|
@ -211,12 +201,22 @@ export default {
|
|||
window.open(calendarOption.url);
|
||||
}
|
||||
},
|
||||
calendarModalClosed() {
|
||||
// Clear the selectedOption if close the modal
|
||||
this.selectedCalendarOption = null;
|
||||
toggleCalendarOptionsOpen() {
|
||||
if (this.calendarOptionsOpen) {
|
||||
this.closeCalendarOptions();
|
||||
} else {
|
||||
this.openCalendarOptions();
|
||||
}
|
||||
},
|
||||
openCalendarModal() {
|
||||
this.$refs.calendarModalQuestion.openModal();
|
||||
openCalendarOptions() {
|
||||
console.log('Opening calendar options');
|
||||
this.calendarOptionsOpen = true;
|
||||
window.addEventListener('click', this.clickListener);
|
||||
},
|
||||
calendarOptionSelected(calendarOptionIndex) {
|
||||
console.log('Selected calendar option:', calendarOptionIndex);
|
||||
this.setCalendarAppointment(this.calendarValues[calendarOptionIndex]);
|
||||
this.calendarOptionsOpen = false;
|
||||
},
|
||||
getCalendarData(type) {
|
||||
let URL = '';
|
||||
|
|
@ -253,29 +253,37 @@ export default {
|
|||
};
|
||||
const calBody = getCalendarFile(calFile);
|
||||
download('SafeliteAppointment.ics', calBody);
|
||||
},
|
||||
closeCalendarOptions() {
|
||||
console.log('Closing calendar options');
|
||||
this.calendarOptionsOpen = false;
|
||||
window.removeEventListener('click', this.clickListener);
|
||||
},
|
||||
clickListener(event) {
|
||||
const calendarSection = document.querySelector('.calendar-section');
|
||||
if (calendarSection && !calendarSection.contains(event.target)) {
|
||||
this.closeCalendarOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
div.calendar-section {
|
||||
position: relative;
|
||||
top: 17px;
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
}
|
||||
.add-to-calendar-text {
|
||||
margin: 0 0 0 0.4375rem;
|
||||
color: #1574a1;
|
||||
color: $heritage-blue-secondary;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.add-to-calendar button {
|
||||
border: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
.calendar-section {
|
||||
display: table;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.calendar-section .add-to-calendar {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.calendar-section .add-to-calendar .add-to-calendar-span {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
<template>
|
||||
<baseInputButton
|
||||
v-bind="$props"
|
||||
v-model="selectedValue"
|
||||
buttonWrapperClasses="list-group base-input-button list-button rounded-3 d-flex flex-column w-100 mb-2">
|
||||
<div
|
||||
:aria-label="buttonLabel"
|
||||
class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4">
|
||||
<span
|
||||
class="m-0 position-relative"
|
||||
:class="textPosition">
|
||||
<img :src="buttonLabel" />
|
||||
<span class="calendar-text">{{ value }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</baseInputButton>
|
||||
</template>
|
||||
<script>
|
||||
import baseInputButton from '@/digital-components/base-input-button/base-input-button.vue';
|
||||
import inputButtonWrapperMixin from '@/mixins/input-button-wrapper-mixin.js';
|
||||
|
||||
export default {
|
||||
name: 'calendar-modal-list-button',
|
||||
components: {
|
||||
baseInputButton
|
||||
},
|
||||
mixins: [inputButtonWrapperMixin]
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.list-button {
|
||||
outline: none;
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
position: static; //override bootstrap
|
||||
|
||||
&:focus-visible + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:focus + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:checked + .list-button-content {
|
||||
color: $black;
|
||||
font-weight: 500;
|
||||
background: $blue-100;
|
||||
box-shadow: 0 0 0 1px $blue;
|
||||
}
|
||||
&:checked:focus + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
}
|
||||
&:checked + .list-button-content p,
|
||||
&:checked + .list-button-content span {
|
||||
font-weight: 500;
|
||||
}
|
||||
&:checked + .list-button-content span:nth-child(2) {
|
||||
font-weight: 400;
|
||||
color: $gray-600;
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-button-content {
|
||||
color: $gray-600;
|
||||
position: relative;
|
||||
background: $white;
|
||||
transition: all 150ms linear;
|
||||
border-radius: $border-radius-lg;
|
||||
border: 0.063rem solid $gray-500;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
|
||||
span.calendar-text {
|
||||
margin-left: 0.313rem;
|
||||
padding: 0.125rem 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.position-relative {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
<template>
|
||||
<modal
|
||||
:ref="modalName"
|
||||
:fontSize="true"
|
||||
:headerText="modalHeaderText"
|
||||
:footerButtonText="footerCloseButtonText"
|
||||
:onModalClosedCallback="onModalClosed"
|
||||
class="calendar-modal"
|
||||
@isModalOpened="setModalStatus"
|
||||
@footerButtonEvent="setSelectedCalendarOption">
|
||||
<template v-if="isModalOpened">
|
||||
<buttonQuestion
|
||||
ref="buttonQuestion"
|
||||
v-model="selectedCalendarOption"
|
||||
buttonTypeString="calendarModalListButton"
|
||||
:buttonTypeObject="calendarModalListButton"
|
||||
:answers="getCalendarOptionData"
|
||||
groupName="chooseCalendarType"
|
||||
class="mt-1"
|
||||
textPosition="text-center"
|
||||
isRequired
|
||||
validationRules="calendar-option-required" />
|
||||
</template>
|
||||
</modal>
|
||||
</template>
|
||||
<script>
|
||||
import modal from '@/digital-components/modal/modal.vue';
|
||||
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
||||
import { defineRule, useField } from 'vee-validate';
|
||||
import errorMessages from '@/constants/error-messages.js';
|
||||
import { required } from '@/helpers/validation-rules';
|
||||
import { deepClone } from '@/helpers/object-helper';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import calendarModalListButton from './calendar-modal-list-button/calendar-modal-list-button.vue';
|
||||
// Validation for the modal button
|
||||
defineRule('calendar-option-required', required(errorMessages.OPTION_REQUIRED));
|
||||
export default {
|
||||
name: 'calendar-modal-question',
|
||||
components: {
|
||||
modal,
|
||||
buttonQuestion
|
||||
},
|
||||
props: {
|
||||
calendarOptionsData: Object,
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
url: null,
|
||||
name: null,
|
||||
icon: null
|
||||
})
|
||||
}
|
||||
},
|
||||
emits: ['calendar-modal-closed', 'update:modelValue'],
|
||||
setup(props) {
|
||||
const uuid = uuidv4();
|
||||
const componentId = !props.customComponentId
|
||||
? `component-${uuid}`
|
||||
: props.customComponentId;
|
||||
|
||||
const { modelValue } = deepClone(props);
|
||||
const initialValue = modelValue;
|
||||
|
||||
const fieldOptions = {
|
||||
value: modelValue,
|
||||
initialValue
|
||||
};
|
||||
|
||||
const { errorMessage, handleChange, meta, validate, errors } = useField(
|
||||
componentId,
|
||||
props.validationRules,
|
||||
fieldOptions
|
||||
);
|
||||
|
||||
return {
|
||||
componentId,
|
||||
errorMessage,
|
||||
handleChange,
|
||||
validate,
|
||||
meta,
|
||||
errors
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isModalOpened: false,
|
||||
selectedValue: null,
|
||||
calendarModalListButton
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
modalName() {
|
||||
return 'calendarOptions';
|
||||
},
|
||||
modalHeaderText() {
|
||||
return 'Add to Calendar';
|
||||
},
|
||||
footerCloseButtonText() {
|
||||
return 'Add to Calendar';
|
||||
},
|
||||
modal() {
|
||||
return this.$refs[this.modalName];
|
||||
},
|
||||
selectedCalendarOption: {
|
||||
get() {
|
||||
return this.modelValue?.name;
|
||||
},
|
||||
set(newValue) {
|
||||
// Button Question only supports Number, or String data types so we must convert to the full object before emitting
|
||||
this.selectedValue = this.getSelectedCalendarObject(newValue);
|
||||
}
|
||||
},
|
||||
getCalendarOptionData() {
|
||||
return this.calendarOptionsData.map((item) => ({
|
||||
value: item.name,
|
||||
buttonLabel: item.icon
|
||||
}));
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
handler(newValue) {
|
||||
this.handleChange(newValue);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openModal() {
|
||||
this.modal.openModal();
|
||||
},
|
||||
setModalStatus(isOpened) {
|
||||
this.isModalOpened = isOpened;
|
||||
},
|
||||
closeModal() {
|
||||
this.modal.closeModal();
|
||||
},
|
||||
onModalClosed() {
|
||||
this.$emit('calendar-modal-closed');
|
||||
},
|
||||
async setSelectedCalendarOption() {
|
||||
this.$emit('update:modelValue', this.selectedValue);
|
||||
this.closeModal();
|
||||
},
|
||||
|
||||
getSelectedCalendarObject(calendarOptionId) {
|
||||
// eslint-disable-next-line no-shadow
|
||||
const calendarOption = this.calendarOptionsData?.find((calendarOption) => calendarOption.name === calendarOptionId);
|
||||
|
||||
if (calendarOption) {
|
||||
return {
|
||||
url: calendarOption.url,
|
||||
name: calendarOption.name,
|
||||
icon: calendarOption.icon
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
url: null,
|
||||
name: null,
|
||||
icon: null
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.calendar-modal.modal.modal-component {
|
||||
> .modal-dialog > .modal-content {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
.modal-header {
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<template>
|
||||
<a
|
||||
:aria-label="buttonLabel"
|
||||
class="d-flex flex-row option-button">
|
||||
<img :src="buttonLabel" />
|
||||
<span class="calendar-text">{{ value }}</span>
|
||||
</a>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'calendar-option-button',
|
||||
props: {
|
||||
buttonLabel: String,
|
||||
value: String
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.option-button {
|
||||
text-decoration: none;
|
||||
color: #4d4e53;
|
||||
font-weight: 400;
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
padding: .75rem 3.125rem .0625rem 1rem;
|
||||
height: 2.75rem;
|
||||
|
||||
&:hover {
|
||||
background-color: $background-color-selected;
|
||||
}
|
||||
img {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.calendar-text {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import calendarModalQuestion from '@/layouts/order-confirmation/add-to-calendar/calendar-modal-question/calendar-modal-question.vue';
|
||||
import calendarOptionSelection from '@/layouts/order-confirmation/add-to-calendar/calendar-option-selection/calendar-option-selection.vue';
|
||||
|
||||
describe('calendar-modal-question.vue', () => {
|
||||
describe('calendar-option-selection.vue', () => {
|
||||
test('When selected calendar option is changed, a correctly selectedCalendarOption should be emitted', async () => {
|
||||
// Arrange
|
||||
const url = 'iCal url';
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
<template>
|
||||
<div
|
||||
v-if="open"
|
||||
class="calendar-selection">
|
||||
<template
|
||||
v-for="(option, index) in getCalendarOptionData"
|
||||
:key="option.value">
|
||||
<calendarOptionButton
|
||||
:buttonLabel="option.buttonLabel"
|
||||
:value="option.value"
|
||||
@click="setSelectedCalendarOption(index)" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import calendarOptionButton from './calendar-option-button/calendar-option-button.vue';
|
||||
// Validation for the modal button
|
||||
export default {
|
||||
name: 'calendar-modal-question',
|
||||
components: {
|
||||
calendarOptionButton
|
||||
},
|
||||
props: {
|
||||
calendarOptionsData: Object,
|
||||
open: Boolean
|
||||
},
|
||||
emits: ['calendar-option-selected'],
|
||||
computed: {
|
||||
getCalendarOptionData() {
|
||||
return this.calendarOptionsData.map((item) => ({
|
||||
value: item.name,
|
||||
buttonLabel: item.icon
|
||||
}));
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async setSelectedCalendarOption(index) {
|
||||
this.$emit('calendar-option-selected', index);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.calendar-selection {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
display: table;
|
||||
border: solid 1px #d4d6d8;
|
||||
border-radius: .25rem;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 0 10px 0 rgba(88, 188, 233, 0.2);
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in a new issue