TT#99204 CSC: As a Customer, I want to manage "Office Hours" as call forwarding type

AC:
Can select "and Office Hours are" as additional menu item from the Condition Menu of a forwarding group
Can open a popup containing the "Office Hours" controls
Can toggle whether the times for each weekday are the same or not
Can enable/disable specific weekdays, if times are all the same
Can manage times for each day separately, if times are not supposed to be the same
Can add multiple periods for all selected or a specific weekday
Can add a period consisting of start- and end-time
Can remove a period
Can cancel the "Office Hours" popup
Can save the state of the "Office Hours" popup
Can see the "Office Hours" as title of the forwarding group
Can click the "Office Hours" title to open and configure the "Office Hours" again

Change-Id: Id60d2e6f9032102e260570a2f6bb347049acd251
pull/4/head
Carlo Venusino 5 years ago
parent 63347a0b7d
commit efd518f95c

@ -0,0 +1,168 @@
<template>
<q-item
class="justify-center q-pl-none q-pr-none q-pb-none csc-cf-timerange-input-container"
>
<q-input
v-model="timeFrom"
filled
mask="time"
:rules="['time']"
dark
dense
no-error-icon
:placeholder="$t('pages.newCallForward.dateRangeStartTime')"
class="q-pa-sm"
@click="$refs.timeFromPopup.show()"
>
<template
v-slot:append
>
<q-icon
name="access_time"
class="cursor-pointer"
>
<q-popup-proxy
ref="timeFromPopup"
transition-show="scale"
transition-hide="scale"
@hide="addTimeRange"
>
<q-time
v-model="timeFrom"
format24h
>
<div
class="row items-center justify-end"
>
<q-btn
v-close-popup
:label="$t('buttons.close')"
color="primary"
flat
/>
</div>
</q-time>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-input
v-model="timeTo"
filled
mask="time"
:rules="['time']"
dark
dense
no-error-icon
:placeholder="$t('pages.newCallForward.dateRangeEndTime')"
class="q-pa-sm"
@click="$refs.timeToPopup.show()"
>
<template
v-slot:append
>
<q-icon
name="access_time"
class="cursor-pointer"
>
<q-popup-proxy
ref="timeToPopup"
transition-show="scale"
transition-hide="scale"
@hide="addTimeRange"
>
<q-time
v-model="timeTo"
format24h
>
<div
class="row items-center justify-end"
>
<q-btn
v-close-popup
:label="$t('buttons.close')"
color="primary"
flat
/>
</div>
</q-time>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-btn
v-if="mode === 'edit'"
flat
color="red"
icon="delete"
padding="xs"
@click="removeTimeRange"
/>
</q-item>
</template>
<script>
import { showGlobalError } from 'src/helpers/ui'
export default {
name: 'CscTimeRange',
props: {
items: {
type: Array,
default: () => []
},
index: {
type: Number,
default: null
},
time: {
type: Object,
default: null
},
mode: {
type: String,
default: null
}
},
data () {
return {
timeFrom: null,
timeTo: null
}
},
mounted () {
if (this.time && this.time.hour && this.time.minute) {
this.timeFrom = this.time.hour.split('-')[0] + ':' + this.time.minute.split('-')[0]
this.timeTo = this.time.hour.split('-')[1] + ':' + this.time.minute.split('-')[1]
}
},
methods: {
addTimeRange () {
if (this.timeFrom && this.timeTo) {
if (this.isTimerangeValid()) {
this.$emit('add-time-range', { from: this.timeFrom, to: this.timeTo, index: this.index })
if (this.mode === 'add') {
this.timeFrom = this.timeTo = null
}
} else {
this.timeTo = null
showGlobalError(this.$t('pages.newCallForward.officeHoursInvalidTimerange'))
}
}
},
removeTimeRange () {
this.$emit('delete-time-range', { from: this.timeFrom, to: this.timeTo, index: this.index })
},
isTimerangeValid () {
const hourFrom = parseInt(this.timeFrom.split(':')[0])
const minuteFrom = parseInt(this.timeFrom.split(':')[1])
const hourTo = parseInt(this.timeTo.split(':')[0])
const minuteTo = parseInt(this.timeTo.split(':')[1])
return hourTo > hourFrom || (hourFrom === hourTo && minuteTo > minuteFrom)
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
.csc-cf-timerange-input-container
max-width 360px
</style>

@ -16,11 +16,8 @@
{{ $t('pages.newCallForward.conditionBtnLabelPrefix') }} {{ $t('pages.newCallForward.conditionBtnLabelPrefix') }}
<span class="csc-cf-from-link"> <span class="csc-cf-from-link">
{{ $t('pages.newCallForward.fromLabelShort') +'"'+ groupSourceset +'"' }} {{ $t('pages.newCallForward.fromLabelShort') +'"'+ groupSourceset +'"' }}
</span>
<q-menu <q-menu
ref="sourcesList" ref="sourcesListEditMenu"
:target="$refs.target"
@show="showSources()"
> >
<csc-new-call-forward-edit-sources <csc-new-call-forward-edit-sources
ref="editSources" ref="editSources"
@ -29,10 +26,10 @@
:source-set-id="sourceSet.id" :source-set-id="sourceSet.id"
:group-name="group.name" :group-name="group.name"
:group-id="group.id" :group-id="group.id"
@close="()=>{this.$refs.sourcesList.hide}" @close="()=>{this.$refs.sourcesListEditMenu.hide()}"
/> />
</q-menu> </q-menu>
</span>
</span> </span>
<span <span
v-if="groupTimeset && !isRange" v-if="groupTimeset && !isRange"
@ -89,7 +86,7 @@
> >
{{ $t('pages.newCallForward.dateRangeShort') + groupTimeRange }} {{ $t('pages.newCallForward.dateRangeShort') + groupTimeRange }}
<q-menu <q-menu
ref="daterange" ref="editDateRangeMenu"
@hide="resetAction()" @hide="resetAction()"
> >
<csc-new-call-forward-date-range <csc-new-call-forward-date-range
@ -99,7 +96,7 @@
:group-id="group.id" :group-id="group.id"
:group-time-range="groupTimeRangeObj" :group-time-range="groupTimeRangeObj"
@confirm-delete="showConfirmDeleteTimesetDialog()" @confirm-delete="showConfirmDeleteTimesetDialog()"
@close="() => {this.$refs.daterange.hide()}" @close="() => {this.$refs.editDateRangeMenu.hide()}"
/> />
<csc-confirm-dialog <csc-confirm-dialog
ref="confirmDeleteTimesetDialog" ref="confirmDeleteTimesetDialog"
@ -112,7 +109,7 @@
</span> </span>
</span> </span>
<span <span
v-if="isWeekdays" v-if="isWeekdays && !isOfficeHours"
> >
{{ $t('pages.newCallForward.conditionBtnLabelPrefix') }} {{ $t('pages.newCallForward.conditionBtnLabelPrefix') }}
<span <span
@ -122,22 +119,47 @@
{{ weekdaysLabelShort + groupWeekdays }} {{ weekdaysLabelShort + groupWeekdays }}
</span> </span>
<q-menu <q-menu
ref="weekdayEditPanel" ref="addWeekdayMenu"
@show="showWeekdayEditForm()"
> >
<csc-new-call-forward-add-weekday-form <csc-new-call-forward-add-weekday-form
:id="timeSet.id" :id="timeSet.id"
ref="weekdayEditForm" ref="weekdayEditForm"
class="q-pa-md" class="q-pa-md"
:days="times" :days="times"
:enabled="true"
:group-name="group.name" :group-name="group.name"
:group-id="group.id" :group-id="group.id"
@close="() => {this.$refs.addWeekdayMenu.hide()}"
/>
</q-menu>
</span>
<span
v-if="isOfficeHours"
>
{{ $t('pages.newCallForward.conditionBtnLabelPrefix') }}
<span
ref="isOfficeHoursLink"
class="csc-cf-from-link"
>
{{ officeHoursLabelShort +' '+ readableOfficeHours }}
</span>
<q-menu
ref="addOfficeHoursMenu"
persistent
>
<csc-new-call-forward-add-office-hours-form
:id="timeSet.id"
ref="officeHoursEditForm"
class="q-pa-md"
:times="cloneTimes(times)"
:same-office-hours-for-all-days="sameOfficeHoursForAllDays"
:group-name="group.name"
:group-id="group.id"
@close="() => {this.$refs.addOfficeHoursMenu.hide()}"
/> />
</q-menu> </q-menu>
</span> </span>
<span <span
v-if="isTempGroup || (!isTempGroup && !(groupSourceset && groupTimeset || groupSourceset && isWeekdays || groupTimeset && isWeekdays ))" v-if="isTempGroup || !(groupSourceset && groupTimeset || groupSourceset && isWeekdays || groupTimeset && isWeekdays )"
class="csc-cf-destination-add-condition" class="csc-cf-destination-add-condition"
> >
{{ $t('pages.newCallForward.conditionBtnLabelPrefix') }} {{ $t('pages.newCallForward.conditionBtnLabelPrefix') }}
@ -160,7 +182,7 @@
<q-item-section>{{ $t('pages.newCallForward.fromLabel') }}</q-item-section> <q-item-section>{{ $t('pages.newCallForward.fromLabel') }}</q-item-section>
</q-item> </q-item>
<q-item <q-item
v-if="isTempGroup || !groupTimeset && !isRange && !isWeekdays" v-if="isTempGroup || !hasTimeset"
v-close-popup v-close-popup
clickable clickable
@click="()=>{action = 'addDateIsCondition'}" @click="()=>{action = 'addDateIsCondition'}"
@ -168,7 +190,7 @@
<q-item-section>{{ $t('pages.newCallForward.dateIsLabel') }}</q-item-section> <q-item-section>{{ $t('pages.newCallForward.dateIsLabel') }}</q-item-section>
</q-item> </q-item>
<q-item <q-item
v-if="isTempGroup || !groupTimeset && !isRange && !isWeekdays" v-if="isTempGroup || !hasTimeset"
v-close-popup v-close-popup
clickable clickable
@click="()=>{action = 'addDateRangeCondition'}" @click="()=>{action = 'addDateRangeCondition'}"
@ -176,34 +198,40 @@
<q-item-section>{{ $t('pages.newCallForward.dateRangeLabel') }}</q-item-section> <q-item-section>{{ $t('pages.newCallForward.dateRangeLabel') }}</q-item-section>
</q-item> </q-item>
<q-item <q-item
v-if="isTempGroup || !groupTimeset && !isRange && !isWeekdays" v-if="isTempGroup || !hasTimeset"
v-close-popup v-close-popup
clickable clickable
@click="()=>{action = 'addWeekdayCondition'}" @click="()=>{action = 'addWeekdayCondition'}"
> >
<q-item-section>{{ $t('pages.newCallForward.weekdaysLabel') }}</q-item-section> <q-item-section>{{ $t('pages.newCallForward.weekdaysLabel') }}</q-item-section>
</q-item> </q-item>
<q-item
v-if="isTempGroup || !hasTimeset"
v-close-popup
clickable
@click="()=>{action = 'addOfficeHoursCondition'}"
>
<q-item-section>{{ $t('pages.newCallForward.officeHoursLabel') }}</q-item-section>
</q-item>
</q-list> </q-list>
</q-menu> </q-menu>
<span> <span>
<q-menu <q-menu
ref="onlineSourceset" ref="addSourcesetMenu"
@show="showSourcesetForm()" @hide="resetAction()"
@hide="resetToggleCondition(); resetAction()"
> >
<csc-new-call-forward-add-sourceset-form <csc-new-call-forward-add-sourceset-form
ref="addSourceSet" ref="addSourceSet"
class="q-pa-md" class="q-pa-md"
:enabled="true"
:group-name="group.name" :group-name="group.name"
:group-id="group.id" :group-id="group.id"
@close="()=>{this.$refs.onlineSourceset.hide()}" @close="()=>{this.$refs.addSourcesetMenu.hide()}"
/> />
</q-menu> </q-menu>
</span> </span>
<span> <span>
<q-menu <q-menu
ref="dayWidgetFromMenu" ref="addDateFromMenu"
@hide="resetAction()" @hide="resetAction()"
> >
<q-date <q-date
@ -235,7 +263,7 @@
</span> </span>
<span> <span>
<q-menu <q-menu
ref="daterangeFromMenu" ref="addDateRangeMenu"
@hide="resetAction()" @hide="resetAction()"
> >
<csc-new-call-forward-date-range <csc-new-call-forward-date-range
@ -244,22 +272,35 @@
:group-name="group.name" :group-name="group.name"
:group-id="group.id" :group-id="group.id"
:no-clear="true" :no-clear="true"
@close="() => {this.$refs.daterangeFromMenu.hide()}" @close="() => {this.$refs.addDateRangeMenu.hide()}"
/> />
</q-menu> </q-menu>
</span> </span>
<span> <span>
<q-menu <q-menu
ref="weekdayPanel" ref="addWeekdayMenu"
@show="showWeekdayPanel()" @hide="resetAction()"
@hide="resetWeekdayCondition(); resetAction()"
> >
<csc-new-call-forward-add-weekday-form <csc-new-call-forward-add-weekday-form
ref="weekdayForm" ref="weekdayForm"
class="q-pa-md" class="q-pa-md"
:enabled="true"
:group-name="group.name" :group-name="group.name"
:group-id="group.id" :group-id="group.id"
@close="() => {this.$refs.addWeekdayMenu.hide()}"
/>
</q-menu>
</span>
<span>
<q-menu
ref="officeHoursPanel"
persistent
>
<csc-new-call-forward-add-office-hours-form
ref="weekdayForm"
class="q-pa-md"
:group-name="group.name"
:group-id="group.id"
@close="() => {this.$refs.officeHoursPanel.hide()}"
/> />
</q-menu> </q-menu>
</span> </span>
@ -344,7 +385,6 @@
<q-btn <q-btn
flat flat
color="primary" color="primary"
class=""
> >
<q-icon <q-icon
name="add" name="add"
@ -353,13 +393,13 @@
/> />
{{ $t('pages.newCallForward.addDestinationLabel') }} {{ $t('pages.newCallForward.addDestinationLabel') }}
<q-menu <q-menu
ref="destTypeForm" ref="destTypeMenu"
:auto-close="true" :auto-close="true"
@show="showDestTypeForm()"
@hide="showNext()" @hide="showNext()"
> >
<csc-new-call-forward-destination-type-form <csc-new-call-forward-destination-type-form
ref="selectDestinationType" ref="selectDestinationType"
@close="()=>{this.$refs.destTypeMenu.hide()}"
/> />
</q-menu> </q-menu>
</q-btn> </q-btn>
@ -368,18 +408,17 @@
ref="numberForm" ref="numberForm"
:no-parent-event="true" :no-parent-event="true"
:class="{ 'csc-cf-popover-hide': toggleNumberForm }" :class="{ 'csc-cf-popover-hide': toggleNumberForm }"
@show="showNewDestNumber()"
> >
<csc-new-call-forward-add-destination-form <csc-new-call-forward-add-destination-form
ref="addDestinationForm" ref="addDestinationForm"
class="q-pa-md" class="q-pa-md"
:enabled="true"
:group-name="group.name" :group-name="group.name"
:group-id="group.id" :group-id="group.id"
@close="()=>{this.$refs.numberForm.hide()}"
/> />
</q-menu> </q-menu>
</div> </div>
<div class="col-xs-6 col-md-6 " /> <div class="col-xs-6 col-md-6" />
</div> </div>
</div> </div>
</template> </template>
@ -399,6 +438,7 @@ import CscNewCallForwardAddDestinationForm from './CscNewCallForwardAddDestinati
import CscNewCallForwardEditSources from './CscNewCallForwardEditSources' import CscNewCallForwardEditSources from './CscNewCallForwardEditSources'
import CscNewCallForwardAddSourcesetForm from './CscNewCallForwardAddSourcesetForm' import CscNewCallForwardAddSourcesetForm from './CscNewCallForwardAddSourcesetForm'
import CscNewCallForwardAddWeekdayForm from './CscNewCallForwardAddWeekdayForm' import CscNewCallForwardAddWeekdayForm from './CscNewCallForwardAddWeekdayForm'
import CscNewCallForwardAddOfficeHoursForm from './CscNewCallForwardAddOfficeHoursForm'
import CscNewCallForwardDestinationTypeForm from './CscNewCallForwardDestinationTypeForm' import CscNewCallForwardDestinationTypeForm from './CscNewCallForwardDestinationTypeForm'
import CscNewCallForwardDateRange from './CscNewCallForwardDateRange' import CscNewCallForwardDateRange from './CscNewCallForwardDateRange'
export default { export default {
@ -410,6 +450,7 @@ export default {
CscNewCallForwardEditSources, CscNewCallForwardEditSources,
CscNewCallForwardAddSourcesetForm, CscNewCallForwardAddSourcesetForm,
CscNewCallForwardAddWeekdayForm, CscNewCallForwardAddWeekdayForm,
CscNewCallForwardAddOfficeHoursForm,
CscNewCallForwardDestinationTypeForm, CscNewCallForwardDestinationTypeForm,
CscNewCallForwardDateRange CscNewCallForwardDateRange
}, },
@ -426,13 +467,8 @@ export default {
data () { data () {
return { return {
firstDestinationInCreation: false, firstDestinationInCreation: false,
toggleGroup: true,
isEnabled: true, isEnabled: true,
toggleNumberForm: true, toggleNumberForm: true,
toggleConditionFromForm: true,
toggleWeekdayPanel: true,
toggleIsDatePanel: true,
toggleIsRangePanel: true,
groupIsLoading: false, groupIsLoading: false,
sourceSet: null, sourceSet: null,
sources: [], sources: [],
@ -441,7 +477,8 @@ export default {
action: null, action: null,
enabled: false, enabled: false,
day: null, day: null,
today: new Date().toString() today: new Date().toString(),
sameOfficeHoursForAllDays: false
} }
}, },
computed: { computed: {
@ -549,52 +586,53 @@ export default {
? `${this.$t('pages.newCallForward.weekdaysLabelShort')}` ? `${this.$t('pages.newCallForward.weekdaysLabelShort')}`
: `${this.$t('pages.newCallForward.weekdayLabelShort')}` : `${this.$t('pages.newCallForward.weekdayLabelShort')}`
}, },
officeHoursLabelShort () {
return this.$tc('pages.newCallForward.officeHoursLabelShort', this.timeSet.times.length)
},
groupWeekdays () { groupWeekdays () {
let retVal = ''
let times = _.cloneDeep(_.get(this.timeSet, 'times', [])) let times = _.cloneDeep(_.get(this.timeSet, 'times', []))
times = times.sort((a, b) => (parseInt(a.wday) > parseInt(b.wday)) ? 1 : ((parseInt(b.wday) > parseInt(a.wday)) ? -1 : 0)) times = times.sort((a, b) => (parseInt(a.wday) > parseInt(b.wday)) ? 1 : ((parseInt(b.wday) > parseInt(a.wday)) ? -1 : 0))
times.forEach((time, index) => { return this.parseWeekDays(times)
const separator = (index === times.length - 1) ? '' : ', ' },
switch (time.wday) { readableOfficeHours () {
case '2': // TODO improve
retVal += `${this.$t('pages.callForward.times.monday')}` // The goal here is to transform the timeranges from the endpoint format
break // to a human readable format like:
case '3': //
retVal += `${this.$t('pages.callForward.times.tuesday')}` // - Tuesday 12:30 - 14:30, Wednesday 19:12 - 12:45 in case of different
break // timeranges in different days
case '4': // - Monday, Tuesday, Friday 13:39 - 14:45 in case of same timeranges in
retVal += `${this.$t('pages.callForward.times.wednesday')}` // different days
break
case '5': const times = _.cloneDeep(_.get(this.timeSet, 'times', []))
retVal += `${this.$t('pages.callForward.times.thursday')}` let days = []
break for (const time of times) {
case '6': if (days[time.wday]) {
retVal += `${this.$t('pages.callForward.times.friday')}` continue
break }
case '7': days[time.wday] = times.filter(($time) => {
retVal += `${this.$t('pages.callForward.times.saturday')}` return $time.wday === time.wday
break }).map(item => ' ' + item.hour.split('-')[0] + ':' + item.minute.split('-')[0] + '-' + item.hour.split('-')[1] + ':' + item.minute.split('-')[1])
case '1': }
retVal += `${this.$t('pages.callForward.times.sunday')}` days = Object.keys(days).map((key) => { return { wday: key, times: days[key] } })
break this.checkOfficeHoursForAllDays(days.map(day => day.times))
if (this.sameOfficeHoursForAllDays) {
return this.parseWeekDays(days) + ' ' + days[0].times
} else {
return days.map(day => this.parseWeekDays([day]) + day.times).join(', ')
} }
retVal += separator
})
return retVal
}, },
isWeekdays () { isWeekdays () {
const isWeekdays = this.timeSet && return this.timeSet && this.timeSet.times && this.timeSet.times.length > 0 && this.timeSet.times[0].wday !== null
this.timeSet.times && },
this.timeSet.times.length > 0 && isOfficeHours () {
this.timeSet.times[0].wday && return this.isWeekdays && this.timeSet.times[0].hour !== null && this.timeSet.times[0].minute !== null
this.timeSet.times[0].wday > 0
return isWeekdays
}, },
isTempGroup () { isTempGroup () {
return this.group.id.toString().includes('temp-') return this.group.id.toString().includes('temp-')
}, },
isFirstDestInCreation () { hasTimeset () {
return this.group.id.toString() === this.getFirstDestinationInCreation return this.groupTimeset || this.isRange || this.isWeekdays
}, },
toggleLabel () { toggleLabel () {
return this.toggleDefaultNumber ? `${this.$t('pages.newCallForward.primarNumberEnabled')}` : `${this.$t('pages.newCallForward.primarNumberDisabled')}` return this.toggleDefaultNumber ? `${this.$t('pages.newCallForward.primarNumberEnabled')}` : `${this.$t('pages.newCallForward.primarNumberDisabled')}`
@ -651,13 +689,6 @@ export default {
} }
}, },
methods: { methods: {
// we need to generate key because destinations have no id
genKey () {
return Math.random()
},
showNewDestNumber () {
this.$refs.addDestinationForm.add()
},
async showNext () { async showNext () {
switch (this.getSelectedDestinationType) { switch (this.getSelectedDestinationType) {
case 'destination': case 'destination':
@ -680,13 +711,8 @@ export default {
} else { } else {
firstDestinationCmp.movePopoverToTop() firstDestinationCmp.movePopoverToTop()
} }
firstDestinationCmp.$refs.destTypeForm.show() firstDestinationCmp.$refs.destTypeForm.show()
}, },
setCondition (action) {
this.action = action
this.$refs.conditions.hide()
},
showConditionForm () { showConditionForm () {
if (this.isTempGroup) { if (this.isTempGroup) {
this.showFirstDestMenu() this.showFirstDestMenu()
@ -695,33 +721,22 @@ export default {
const action = this.action const action = this.action
switch (action) { switch (action) {
case 'addFromCondition': case 'addFromCondition':
this.toggleConditionFromForm = false this.$refs.addSourcesetMenu.show()
this.$refs.onlineSourceset.show()
break break
case 'addDateIsCondition': case 'addDateIsCondition':
this.toggleIsDatePanel = false this.$refs.addDateFromMenu.show()
this.$refs.dayWidgetFromMenu.show()
break break
case 'addDateRangeCondition': case 'addDateRangeCondition':
this.toggleIsRangePanel = false this.$refs.addDateRangeMenu.show()
this.$refs.daterangeFromMenu.show()
break break
case 'addWeekdayCondition': case 'addWeekdayCondition':
this.toggleWeekdayPanel = false this.$refs.addWeekdayMenu.show()
this.$refs.weekdayPanel.show() break
case 'addOfficeHoursCondition':
this.$refs.officeHoursPanel.show()
break break
} }
}, },
showDestTypeForm () {
this.toggleNumberForm = true
this.$refs.selectDestinationType.add()
},
showWeekdayEditForm () {
this.$refs.weekdayEditForm.add()
},
getDestName (index) {
return 'destination' + index
},
getDestination (index) { getDestination (index) {
const destination = { ...this.group.destinations[index] } const destination = { ...this.group.destinations[index] }
if (index === 0) { if (index === 0) {
@ -740,30 +755,9 @@ export default {
}) })
this.$store.dispatch('newCallForward/removeGroupLoader', this.group.id) this.$store.dispatch('newCallForward/removeGroupLoader', this.group.id)
}, },
openConditionsPopover () {
this.$refs.conditions.show()
},
showConditions () {
this.$refs.addCondition.add()
},
showSourcesetForm () {
this.$refs.addSourceSet.add()
},
showWeekdayPanel () {
this.$refs.weekdayForm.add()
},
showSources () {
this.$refs.editSources.add()
},
resetToggleCondition () {
this.toggleConditionFromForm = true
},
resetAction () { resetAction () {
this.action = null this.action = null
}, },
resetWeekdayCondition () {
this.toggleWeekdayPanel = true
},
async updateSourcesetNames () { async updateSourcesetNames () {
const mappings = this.getMappings const mappings = this.getMappings
const groupMappingId = await this.$store.dispatch('newCallForward/getMappingIdByGroupName', this.group.name) const groupMappingId = await this.$store.dispatch('newCallForward/getMappingIdByGroupName', this.group.name)
@ -860,11 +854,21 @@ export default {
console.log(e) console.log(e)
} }
}, },
rangeChanged () {
this.$refs.daterange.show()
},
minDate (day) { minDate (day) {
return day >= date.formatDate(new Date(), 'YYYY/MM/DD') return day >= date.formatDate(new Date(), 'YYYY/MM/DD')
},
parseWeekDays (times) {
const weekDays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']
return times
.map(time => this.$t('pages.callForward.times.' + weekDays[Number(time.wday) - 1]))
.join(', ')
},
checkOfficeHoursForAllDays (times) {
const weekdaysObj = _.groupBy(_.cloneDeep(this.times), 'wday')
this.sameOfficeHoursForAllDays = Object.keys(weekdaysObj).length > 1 && times.every(array => array.join() === times[0].join())
},
cloneTimes (times) {
return _.cloneDeep(times)
} }
} }
} }

@ -1,6 +1,5 @@
<template> <template>
<div <div
v-if="enabled"
class="csc-form" class="csc-form"
> >
<csc-input <csc-input
@ -88,7 +87,6 @@ export default {
}, },
data () { data () {
return { return {
enabled: false,
number: '', number: '',
numberError: false, numberError: false,
destinationIndex: null destinationIndex: null
@ -147,16 +145,13 @@ export default {
this.$store.dispatch('newCallForward/removeGroupLoader', this.groupId) this.$store.dispatch('newCallForward/removeGroupLoader', this.groupId)
}, },
cancel () { cancel () {
this.enabled = false this.close()
},
add () {
this.enabled = true
}, },
close () { close () {
this.enabled = false this.$emit('close')
}, },
reset () { reset () {
this.cancel() this.close()
}, },
error (state) { error (state) {
this.numberError = state this.numberError = state

@ -0,0 +1,401 @@
<template>
<q-list
class="csc-form"
>
<q-list>
<q-item
class="justify-center text-bold"
>
{{ $t('pages.newCallForward.officeHoursTitle') }}
</q-item>
<q-item
class="justify-center"
>
<q-checkbox
v-model="checkOfficeHoursForAllDays"
:value="sameOfficeHoursForAllDays"
:label="$t('pages.newCallForward.sameOfficeHoursForAllDays')"
@input="toggleAllDaysSameOfficeHours"
/>
</q-item>
<q-item
v-if="!checkOfficeHoursForAllDays"
class="justify-center"
>
<q-tabs
v-model="selectedDay"
active-color="primary"
dense
>
<q-tab
v-for="(dayLetter, index) in $t('pages.newCallForward.daysOfTheWeekShort').split(',')"
:key="index"
:alert="hasOfficeHours(getDayNumber(index))"
:name="getDayNumber(index)"
class="q-pa-xs"
>
<q-btn
class="weekday-btn"
rounded
ripple
>
{{ dayLetter }}
</q-btn>
</q-tab>
</q-tabs>
</q-item>
<q-item
v-if="checkOfficeHoursForAllDays"
class="justify-center"
>
<q-btn
v-for="(dayLetter, index) in $t('pages.newCallForward.daysOfTheWeekShort').split(',')"
:key="index"
class="weekday-btn q-ma-sm"
:class="{ 'day-selected-btn': weekdays.includes(getDayNumber(index))}"
rounded
@click="toggleWeekday(getDayNumber(index))"
>
{{ dayLetter }}
</q-btn>
</q-item>
<div
v-for="(time, index) in timeRanges"
:key="time.wday + '-' + time.hour + '-' + time.minute"
dense
>
<q-item
v-if="showTimeslot(time)"
>
<csc-time-range
:ref="'officeHours-' + index"
:index="getTimeSlotIndex(time, index)"
:time="time"
mode="edit"
@delete-time-range="deleteTimeRange"
@add-time-range="editTimeRange"
/>
</q-item>
</div>
<q-item
v-show="showNewTimeRangeFields"
dense
>
<csc-time-range
mode="add"
@add-time-range="addTimeRange"
/>
</q-item>
<q-item
class="justify-center"
>
<q-btn
flat
color="primary"
:disabled="checkOfficeHoursForAllDays && weekdays.length < 1"
@click="showStaticTimeRangeFields"
>
<q-icon
name="add"
color="primary"
size="24px"
/>
{{ $t('pages.newCallForward.officeHoursAddBtnLabel') }}
</q-btn>
</q-item>
</q-list>
<q-item
class="justify-center csc-actions-cont"
>
<q-btn
:disabled="!id"
flat
color="red"
icon="delete"
@click="showRemoveDialog()"
>
{{ $t('buttons.remove') }}
</q-btn>
<csc-confirm-dialog
ref="confirmDeleteTimesetDialog"
title-icon="delete"
class="csc-cf-delete-weekdays-btn"
:title="$t('pages.newCallForward.cancelTimesetDialogTitle', {name: 'office hours'})"
:message="$t('pages.newCallForward.cancelTimesetText', {name: 'this'})"
@confirm="deleteTimeset"
/>
<q-btn
flat
color="default"
icon="clear"
@click="cancel()"
>
{{ $t('buttons.cancel') }}
</q-btn>
<q-btn
flat
color="primary"
icon="done"
:disabled="timeRanges.length < 1"
@click="save()"
>
{{ $t('buttons.save') }}
</q-btn>
</q-item>
</q-list>
</template>
<script>
import CscConfirmDialog from '../../CscConfirmationDialog'
import CscTimeRange from '../../CscTimeRange'
import _ from 'lodash'
export default {
name: 'CscNewCallForwardAddOfficeHoursForm',
components: {
CscConfirmDialog,
CscTimeRange
},
props: {
groupName: {
type: String,
default: ''
},
groupId: {
type: [String, Number],
default: null
},
id: {
type: [String, Number],
default: null
},
times: {
type: Array,
default: null
},
sameOfficeHoursForAllDays: {
type: Boolean,
default: false
}
},
data () {
return {
timesetId: null,
timesetName: null,
weekdays: [],
timeRanges: [],
checkOfficeHoursForAllDays: false,
showNewTimeRangeFields: false,
selectedDay: '2' // Monday default
}
},
mounted () {
this.timesetName = 'timeset-' + this.groupId
this.timeSetId = this.id
if (this.times) {
this.weekdays = this.times.map(time => time.wday)
this.timeRanges = this.times
this.checkOfficeHoursForAllDays = this.sameOfficeHoursForAllDays
}
},
methods: {
async save () {
const forwardGroupId = this.groupId
this.$store.dispatch('newCallForward/addGroupLoader', forwardGroupId)
try {
if (this.checkOfficeHoursForAllDays && this.weekdays.length < 1) {
this.deleteTimeset()
} else {
if (this.id) {
this.timeSetId = this.id
} else {
this.timeSetId = await this.$store.dispatch('newCallForward/createTimeSet', this.timesetName)
}
await this.$store.dispatch('newCallForward/addTimesetToGroup', {
name: this.groupName,
groupId: this.groupId,
timeSetId: this.timeSetId
})
const updatedTimeset = await this.$store.dispatch('newCallForward/addTimeToTimeset', {
id: this.timeSetId,
time: this.timeRanges
})
this.$store.dispatch('newCallForward/setTimeset', updatedTimeset)
}
} catch (err) {
console.log(err)
}
this.close()
this.$store.dispatch('newCallForward/removeGroupLoader', forwardGroupId)
},
cancel () {
this.weekdays = []
if (this.days) {
for (const day of this.days) {
this.weekdays.push(day.wday)
}
}
this.close()
},
close () {
this.$emit('close')
},
showRemoveDialog () {
this.$refs.confirmDeleteTimesetDialog.open()
},
toggleWeekday (weekday) {
if (this.weekdays.includes(weekday)) {
this.weekdays = this.weekdays.filter(item => item !== weekday)
this.removeDayFromTimerange(weekday)
} else {
this.weekdays.push(weekday)
this.addDayToTimerange(weekday)
}
this.weekdays.sort((a, b) => (parseInt(a) - parseInt(b)))
},
async deleteTimeset () {
this.$store.dispatch('newCallForward/addGroupLoader', this.groupId)
try {
await this.$store.dispatch('newCallForward/deleteTimeset', this.timeSetId)
} catch (error) {
console.log(error)
}
this.$store.dispatch('newCallForward/loadMappings')
this.$store.dispatch('newCallForward/removeGroupLoader', this.groupId)
},
toggleAllDaysSameOfficeHours () {
this.weekdays = []
this.timeRanges = []
this.showNewTimeRangeFields = false
},
showStaticTimeRangeFields () {
this.showNewTimeRangeFields = true
},
editTimeRange (data) {
if (data.from && data.to) {
const timeFrom = data.from.split(':')
const timeTo = data.to.split(':')
const editedTimes = []
const timeRangesGroupByWeekday = _.groupBy(_.cloneDeep(this.timeRanges), 'wday')
if (this.checkOfficeHoursForAllDays) {
for (const wday in timeRangesGroupByWeekday) {
const time = timeRangesGroupByWeekday[wday][data.index]
time.hour = timeFrom[0] + '-' + timeTo[0]
time.minute = timeFrom[1] + '-' + timeTo[1]
editedTimes.push(...timeRangesGroupByWeekday[wday])
}
} else {
const time = timeRangesGroupByWeekday[this.selectedDay][data.index]
time.hour = timeFrom[0] + '-' + timeTo[0]
time.minute = timeFrom[1] + '-' + timeTo[1]
for (const wday in timeRangesGroupByWeekday) {
editedTimes.push(...timeRangesGroupByWeekday[wday])
}
}
this.timeRanges = editedTimes
}
},
addTimeRange (data) {
if (data.from && data.to) {
const timeFrom = data.from.split(':')
const timeTo = data.to.split(':')
if (this.checkOfficeHoursForAllDays) {
for (const weekday of this.weekdays) {
this.timeRanges.push({
wday: weekday,
hour: timeFrom[0] + '-' + timeTo[0],
minute: timeFrom[1] + '-' + timeTo[1]
})
}
} else {
this.timeRanges.push({
wday: this.selectedDay,
hour: timeFrom[0] + '-' + timeTo[0],
minute: timeFrom[1] + '-' + timeTo[1]
})
}
this.showNewTimeRangeFields = false
}
},
addDayToTimerange (day) {
if (this.timeRanges.length > 0) {
const dayRanges = this.timeRanges.filter(time => time.wday === this.timeRanges[0].wday)
for (const range of dayRanges) {
this.timeRanges.push({
wday: day,
hour: range.hour,
minute: range.minute
})
}
}
},
removeDayFromTimerange (day) {
if (this.timeRanges.length > 1) {
this.timeRanges = this.timeRanges.filter(time => time.wday !== day)
}
},
findIndexInGroup (data, timeRange) {
return timeRange.findIndex(time => {
const [fromHours, fromMinutes] = data.from ? data.from.split(':') : []
const [toHours, toMinutes] = data.from ? data.to.split(':') : []
return time.hour === (data.hour ? data.hour : `${fromHours}-${toHours}`) &&
time.minute === (data.minute ? data.minute : `${fromMinutes}-${toMinutes}`)
})
},
deleteTimeRange (data) {
const editedTimes = []
const timeToDelete = this.timeRanges[data.index]
const timeRangesGroupByWeekday = _.groupBy(this.timeRanges, 'wday')
if (this.checkOfficeHoursForAllDays) {
const indexInGroup = this.findIndexInGroup(data, timeRangesGroupByWeekday[timeToDelete.wday])
for (const wday in timeRangesGroupByWeekday) {
delete timeRangesGroupByWeekday[wday][indexInGroup]
editedTimes.push(...timeRangesGroupByWeekday[wday].filter(el => el !== undefined))
}
} else {
delete timeRangesGroupByWeekday[this.selectedDay][data.index]
for (const wday in timeRangesGroupByWeekday) {
editedTimes.push(...timeRangesGroupByWeekday[wday].filter(el => el !== undefined))
}
}
this.timeRanges = editedTimes
},
showTimeslot (time) {
// in case of same office hours for all days, shows the time slot once;
// in case of different office hours for different days, shows the time slot
// if belongs to the selected day
switch (true) {
case this.checkOfficeHoursForAllDays:
return time.wday && time.wday === this.timeRanges[0].wday
case !this.checkOfficeHoursForAllDays:
return time.wday && time.wday === this.selectedDay
default:
return false
}
},
hasOfficeHours (wday) {
const timeRangesGroupByWeekday = _.groupBy(this.timeRanges, 'wday')
return timeRangesGroupByWeekday[wday] && timeRangesGroupByWeekday[wday].length > 0 ? 'primary' : false
},
getTimeSlotIndex (time, index) {
if (this.checkOfficeHoursForAllDays) {
return index
}
const timeRangesGroupByWeekday = _.groupBy(this.timeRanges, 'wday')
return this.findIndexInGroup(time, timeRangesGroupByWeekday[time.wday])
},
getDayNumber (index) {
return index === 7 ? '1' : String(index + 2)
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
.weekday-btn
background $main-menu-item-hover-background
width 35px
.day-selected-btn
background $primary
</style>

@ -1,6 +1,5 @@
<template> <template>
<div <div
v-if="enabled"
class="csc-form" class="csc-form"
> >
<csc-input <csc-input
@ -79,7 +78,6 @@ export default {
data () { data () {
return { return {
loading: false, loading: false,
enabled: false,
number: '', number: '',
name: '', name: '',
nameError: false, nameError: false,
@ -132,16 +130,13 @@ export default {
cancel () { cancel () {
this.number = '' this.number = ''
this.name = '' this.name = ''
this.enabled = false
this.$emit('close') this.$emit('close')
}, },
add () { add () {
this.number = '' this.number = ''
this.name = '' this.name = ''
this.enabled = true
}, },
close () { close () {
this.enabled = false
this.$emit('close') this.$emit('close')
}, },
reset () { reset () {

@ -1,8 +1,6 @@
<template> <template>
<div <div
v-if="enabled"
class="csc-form" class="csc-form"
:class="{ 'csc-cf-popover-hide': toggleFormVisibility}"
> >
<div <div
class="csc-cf-delete-weekdays-btn" class="csc-cf-delete-weekdays-btn"
@ -134,11 +132,11 @@ export default {
default: null default: null
}, },
id: { id: {
type: String, type: [String, Number],
default: null default: null
}, },
days: { days: {
type: Object, type: Array,
default: null default: null
} }
}, },
@ -146,9 +144,7 @@ export default {
return { return {
timesetId: null, timesetId: null,
timesetName: null, timesetName: null,
toggleFormVisibility: false,
loading: false, loading: false,
enabled: false,
weekdays: [] weekdays: []
} }
}, },
@ -209,14 +205,8 @@ export default {
}, },
close () { close () {
this.$emit('close') this.$emit('close')
this.enabled = false
},
add () {
this.toggleFormVisibility = false
this.enabled = true
}, },
showRemoveDialog () { showRemoveDialog () {
this.toggleFormVisibility = true
this.$refs.confirmDeleteTimesetDialog.open() this.$refs.confirmDeleteTimesetDialog.open()
}, },
toggleWeekday (weekday) { toggleWeekday (weekday) {

@ -58,6 +58,7 @@
<q-time <q-time
ref="hourFrom" ref="hourFrom"
v-model="hourFrom" v-model="hourFrom"
format24h
:no-unset="true" :no-unset="true"
> >
<div class="row items-center justify-end q-gutter-sm"> <div class="row items-center justify-end q-gutter-sm">
@ -79,6 +80,7 @@
<q-time <q-time
ref="hourTo" ref="hourTo"
v-model="hourTo" v-model="hourTo"
format24h
:no-unset="true" :no-unset="true"
> >
<div class="row items-center justify-end q-gutter-sm"> <div class="row items-center justify-end q-gutter-sm">

@ -60,6 +60,7 @@
</div> </div>
<csc-new-call-forward-destination-type-form <csc-new-call-forward-destination-type-form
ref="selectDestinationType" ref="selectDestinationType"
@close="()=>{this.$refs.destTypeMenu.hide()}"
/> />
</q-menu> </q-menu>
<q-menu <q-menu
@ -68,7 +69,6 @@
:no-parent-event="true" :no-parent-event="true"
class="csc-cf-dest-popover-bottom" class="csc-cf-dest-popover-bottom"
:class="{ 'csc-cf-popover-hide': disableNumberPopover, 'csc-cf-popover-to-top': popoverToTop, 'csc-cf-popover-timeout-to-top': popoverTimeoutToTop }" :class="{ 'csc-cf-popover-hide': disableNumberPopover, 'csc-cf-popover-to-top': popoverToTop, 'csc-cf-popover-timeout-to-top': popoverTimeoutToTop }"
@show="showNumberForm()"
@hide="movePopoverToInitialPos(); movePopoverTimeoutToInitialPos()" @hide="movePopoverToInitialPos(); movePopoverTimeoutToInitialPos()"
> >
<csc-new-call-forward-add-destination-form <csc-new-call-forward-add-destination-form
@ -79,6 +79,7 @@
:group-name="groupName" :group-name="groupName"
:group-id="groupId" :group-id="groupId"
:first-destination-in-creation="firstDestinationInCreation" :first-destination-in-creation="firstDestinationInCreation"
@close="()=>{this.$refs.numberForm.hide()}"
/> />
</q-menu> </q-menu>
</div> </div>
@ -239,12 +240,8 @@ export default {
this.$refs.destTypeForm.show() this.$refs.destTypeForm.show()
} }
}, },
showNumberForm () {
this.$refs.addDestinationForm.add()
},
showDestTypeForm () { showDestTypeForm () {
this.toggleNumberForm = true this.toggleNumberForm = true
this.$refs.selectDestinationType.add()
}, },
async saveTimeout () { async saveTimeout () {
this.$store.dispatch('newCallForward/addGroupLoader', this.groupId) this.$store.dispatch('newCallForward/addGroupLoader', this.groupId)

@ -1,7 +1,5 @@
<template> <template>
<div <div>
v-if="enabled"
>
<div <div
class="csc-cf-dest-type" class="csc-cf-dest-type"
@click="setSelectedDestinationType('destination')" @click="setSelectedDestinationType('destination')"
@ -23,11 +21,6 @@ import {
} from 'vuex' } from 'vuex'
export default { export default {
name: 'CscNewCallForwardDestinationTypeForm', name: 'CscNewCallForwardDestinationTypeForm',
data () {
return {
enabled: false
}
},
mounted () { mounted () {
this.setSelectedDestinationType(null) this.setSelectedDestinationType(null)
}, },
@ -36,13 +29,10 @@ export default {
'setSelectedDestinationType' 'setSelectedDestinationType'
]), ]),
cancel () { cancel () {
this.enabled = false this.close = false
},
add () {
this.enabled = true
}, },
close () { close () {
this.enabled = false this.$emit('close')
} }
} }
} }

@ -1,7 +1,5 @@
<template> <template>
<div <div>
v-if="enabled"
>
<div <div
class="csc-cf-dest-type" class="csc-cf-dest-type"
@click="addDestinationsetUnconditional()" @click="addDestinationsetUnconditional()"
@ -29,11 +27,6 @@ import {
} from 'vuex' } from 'vuex'
export default { export default {
name: 'CscNewCallForwardDestinationsetTypeSelect', name: 'CscNewCallForwardDestinationsetTypeSelect',
data () {
return {
enabled: true
}
},
computed: { computed: {
...mapGetters('newCallForward', [ ...mapGetters('newCallForward', [
'timeoutGroupExists', 'timeoutGroupExists',
@ -57,15 +50,11 @@ export default {
async addDestinationsetBusy () { async addDestinationsetBusy () {
await this.$store.dispatch('newCallForward/setSelectedDestType', 'busy') await this.$store.dispatch('newCallForward/setSelectedDestType', 'busy')
}, },
cancel () { cancel () {
this.enabled = false this.close()
},
add () {
this.enabled = true
}, },
close () { close () {
this.enabled = false this.$emit('close')
} }
} }
} }

@ -1,6 +1,5 @@
<template> <template>
<div <div
v-if="enabled"
class="csc-form q-pa-lg" class="csc-form q-pa-lg"
:class="{ 'csc-cf-popover-hide': toggleFormVisibility}" :class="{ 'csc-cf-popover-hide': toggleFormVisibility}"
> >
@ -132,7 +131,6 @@ export default {
return { return {
mode: 'create', mode: 'create',
loading: false, loading: false,
enabled: false,
number: '', number: '',
numberError: false, numberError: false,
destinationIndex: null, destinationIndex: null,
@ -206,15 +204,12 @@ export default {
}, },
cancel () { cancel () {
this.number = '' this.number = ''
this.enabled = false this.close()
this.$emit('close')
}, },
add () { add () {
this.number = '' this.number = ''
this.enabled = true
}, },
close () { close () {
this.enabled = false
this.$emit('close') this.$emit('close')
}, },
reset () { reset () {

@ -285,9 +285,16 @@
"weekdaysLabel": "If weekdays are ...", "weekdaysLabel": "If weekdays are ...",
"weekdayLabel": "If weekday is ...", "weekdayLabel": "If weekday is ...",
"weekdaysLabelShort": " weekdays are ", "weekdaysLabelShort": " weekdays are ",
"officeHoursLabelShort": " office hour is | office hours are",
"weekdays":"weekdays", "weekdays":"weekdays",
"weekdayLabelShort": " weekday is ", "weekdayLabelShort": " weekday is ",
"officeHoursLabel": "If office hours are ...",
"offlineLabel": "If not available", "offlineLabel": "If not available",
"officeHoursTitle": "Office hours",
"officeHoursAddBtnLabel": "Add time range",
"officeHoursInvalidTimerange": "Please select a valid timerange",
"daysOfTheWeekShort": "M,T,W,T,F,S,S",
"sameOfficeHoursForAllDays": "Same time for all selected days",
"busyLabel": "If busy", "busyLabel": "If busy",
"sourcesetName": "List name", "sourcesetName": "List name",
"mandatoryDestinationLabel": "Please add a destination to the group before adding conditions", "mandatoryDestinationLabel": "Please add a destination to the group before adding conditions",

Loading…
Cancel
Save