From 092e6bd2249e19a33c7dcd2494b02e4844b2d029 Mon Sep 17 00:00:00 2001 From: Carlo Venusino <cvenusino@sipwise.com> Date: Mon, 8 Jun 2020 18:45:07 +0200 Subject: [PATCH] TT#82509 CF: As a Customer, I want to remove the condition "call from ..." MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EXTRA: - Main title -- √ change wording online -> available -- √ Add number placeholder after Primary number -- √ if no groups exist label should be “All calls group to the primary number” - √ When adding a sourceset to an unpersisted group, all the popovers should be in the same context, - √ and the alert message should be within the popover (instead of yellow toast) - √ Change buttons in the sourceset edit popover ADD button for adding sources under the input field CLOSE and DELETE (red + trash icon) buttons for the whole list on the same line at the bottom of the popover - √ Prevent creation of more than one unpersisted group by alerting the user “You have to create a destination on the unsaved group” - √ Gray out “All calls go to the primary number” on available groups when group is disabled Cosmetic - √ Remove bold from main title - √ Adjust paddings for buttons in the popover - √ Line heights within each group should be consistent - √ Timeout popover > more width + dots Change-Id: I1adab34f5bd921779027adacf7ff50f235ff2510 --- src/components/CscConfirmationDialog.vue | 4 + src/components/CscDialog.vue | 1 + .../NewCallForward/CscCallForwardGroup.vue | 27 ++++-- .../NewCallForward/CscNewCallForward.vue | 93 ++++++++++++------- .../CscNewCallForwardAddDestinationForm.vue | 9 +- .../CscNewCallForwardAddSourcesetForm.vue | 4 +- .../CscNewCallForwardDestination.vue | 52 +++++++++-- .../CscNewCallForwardEditSources.vue | 73 +++++++++++++-- .../CscNewCallForwardSource.vue | 7 +- src/locales/en.json | 7 +- src/store/new-call-forward.js | 8 +- 11 files changed, 214 insertions(+), 71 deletions(-) diff --git a/src/components/CscConfirmationDialog.vue b/src/components/CscConfirmationDialog.vue index 9edc60f0..0bc0d573 100644 --- a/src/components/CscConfirmationDialog.vue +++ b/src/components/CscConfirmationDialog.vue @@ -4,6 +4,7 @@ :title="title" :titleIcon="titleIcon" :opened="opened" + @close="onClose()" > <div slot="content" @@ -50,6 +51,9 @@ close() { this.$refs.dialogComp.close(); }, + onClose(){ + this.$emit('closed'); + }, cancel() { this.close(); this.$emit('cancel'); diff --git a/src/components/CscDialog.vue b/src/components/CscDialog.vue index 435e25ab..323cded2 100644 --- a/src/components/CscDialog.vue +++ b/src/components/CscDialog.vue @@ -88,6 +88,7 @@ }, close() { this.$refs.modal.close(); + this.$emit('close'); }, cancel() { this.close(); diff --git a/src/components/pages/NewCallForward/CscCallForwardGroup.vue b/src/components/pages/NewCallForward/CscCallForwardGroup.vue index 54a26224..8432be0b 100644 --- a/src/components/pages/NewCallForward/CscCallForwardGroup.vue +++ b/src/components/pages/NewCallForward/CscCallForwardGroup.vue @@ -8,11 +8,9 @@ class="row csc-cf-destination-cont" > <div - class="col col-xs-12 col-md-4 text-right csc-cf-group-title" + class="col col-xs-12 col-md-4 text-right csc-cf-group-title-bold" > - {{groupTitle}} - <span class="csc-cf-destination-add-condition" v-if="isTempGroup" @@ -124,11 +122,12 @@ </div> <div - class="csc-cf-row row" + class="csc-cf-destination-cont row" v-if="isTimeoutOrUnconditional" > <div class="col col-xs-12 col-md-4 text-right" + :class="{ 'csc-cf-destination-disabled': !isEnabled }" > {{ toggleLabel }} </div> @@ -213,9 +212,7 @@ import { mapGetters, } from 'vuex' - import { - showGlobalWarning - } from '../../../helpers/ui' + import { QSpinnerDots, QToggle, @@ -251,7 +248,6 @@ QItemSide, CscConfirmDialog, CscObjectSpinner, - showGlobalWarning, CscNewCallForwardDestination, CscNewCallForwardAddDestinationForm, CscNewCallForwardEditSources, @@ -380,8 +376,14 @@ showFirstDestMenu(){ const firstDestinationCmp = this.$refs.destination[0]; firstDestinationCmp.firstDestinationInCreation = true; + if(this.group.name.includes('timeout') || this.group.name.includes('unconditional')){ + firstDestinationCmp.movePopoverTimeoutToTop(); + } + else{ + firstDestinationCmp.movePopoverToTop(); + } + firstDestinationCmp.$refs.destTypeForm.open(); - showGlobalWarning(`${this.$t('pages.newCallForward.mandatoryDestinationLabel')}`, 5000) }, async showConditionForm(){ this.toggleConditionFromForm = false; @@ -441,6 +443,10 @@ this.sourceSet = sourceSet; this.sources = this.sourceSet.sources; } + else{ + this.sourceSet = null; + this.sources = []; + } } }, showConfirmDialog(){ @@ -466,6 +472,9 @@ @import '../../../themes/app.common.styl' .csc-cf-group width 100% + .csc-cf-group-title-bold + text-align right + font-weight bold .csc-cf-group-cont position relative .csc-cf-destination-label diff --git a/src/components/pages/NewCallForward/CscNewCallForward.vue b/src/components/pages/NewCallForward/CscNewCallForward.vue index 83ad417e..d092c5a1 100644 --- a/src/components/pages/NewCallForward/CscNewCallForward.vue +++ b/src/components/pages/NewCallForward/CscNewCallForward.vue @@ -7,8 +7,15 @@ > <div class="col col-xs-12 col-md-4 csc-cf-group-title" + v-if="this.groupsCount > 0" > - {{ $t('pages.newCallForward.titles.mainTitle') }} + {{ $t('pages.newCallForward.titles.mainTitle', {number: this.subscriberDisplayName}) }} + </div> + <div + class="col col-xs-12 col-md-4 csc-cf-group-title" + v-else + > + {{$t('pages.newCallForward.primarNumberEnabled')}} {{ subscriberDisplayName }} </div> <div class="col col-xs-12 col-md-2 text-left csc-cf-self-number-cont" @@ -91,6 +98,9 @@ import { mapGetters, } from 'vuex' + import { + showGlobalWarning + } from '../../../helpers/ui' import { QSpinnerDots, QField, @@ -114,6 +124,7 @@ CscNewCallForwardDestination, CscNewCallForwardAddDestinationForm, CscNewCallForwardDestinationsetTypeSelect, + showGlobalWarning, QSpinnerDots, QField, QToggle, @@ -152,53 +163,64 @@ 'subscriberDisplayName', 'forwardGroups', 'selectedDestType' - ]) + ]), + groupsCount(){ + return this.forwardGroups.length; + } }, methods: { async addForwardGroup(){ this.groupInCreation = true; const selectedDestType = this.selectedDestType; - switch(selectedDestType){ - case "unconditional":{ - if(this.toggleDefaultNumber){ - const tempTimeoutFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupById', 'temp-csc-timeout'); - if(!tempTimeoutFwdGroup){ - await this.$store.dispatch('newCallForward/addTempGroup','timeout' ); + let tempGroups = this.forwardGroups.filter(($group)=>{ + return $group.id.toString().indexOf('temp-') > -1; + }); + + if(tempGroups.length > 0){ + showGlobalWarning(`${this.$t('pages.newCallForward.addDestinationAlert')}`, 5000); + } + else{ + switch(selectedDestType){ + case "unconditional":{ + if(this.toggleDefaultNumber){ + const tempTimeoutFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupById', 'temp-csc-timeout'); + if(!tempTimeoutFwdGroup){ + await this.$store.dispatch('newCallForward/addTempGroup','timeout' ); + } } - } - else{ - const tempUnconditionalFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupById', 'temp-csc-unconditional'); - if(!tempUnconditionalFwdGroup){ - await this.$store.dispatch('newCallForward/addTempGroup','unconditional' ); + else{ + const tempUnconditionalFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupById', 'temp-csc-unconditional'); + if(!tempUnconditionalFwdGroup){ + await this.$store.dispatch('newCallForward/addTempGroup','unconditional' ); + } } } - } - break; - case "unconditional-from":{ - if(this.toggleDefaultNumber){ - const tempTimeoutFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupById', 'temp-csc-timeout-from'); - if(!tempTimeoutFwdGroup){ - await this.$store.dispatch('newCallForward/addTempGroup','timeoutFrom' ); + break; + case "unconditional-from":{ + if(this.toggleDefaultNumber){ + const tempTimeoutFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupById', 'temp-csc-timeout-from'); + if(!tempTimeoutFwdGroup){ + await this.$store.dispatch('newCallForward/addTempGroup','timeoutFrom' ); + } } - } - else{ - const tempUnconditionalFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupById', 'temp-csc-unconditional-from'); - if(!tempUnconditionalFwdGroup){ - await this.$store.dispatch('newCallForward/addTempGroup','unconditionalFrom' ); + else{ + const tempUnconditionalFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupById', 'temp-csc-unconditional-from'); + if(!tempUnconditionalFwdGroup){ + await this.$store.dispatch('newCallForward/addTempGroup','unconditionalFrom' ); + } } } + break; + case "offline":{ + await this.$store.dispatch('newCallForward/addTempGroup','offline' ); + } + break; + case "busy":{ + await this.$store.dispatch('newCallForward/addTempGroup','busy' ); + } + break; } - break; - case "offline":{ - await this.$store.dispatch('newCallForward/addTempGroup','offline' ); - } - break; - case "busy":{ - await this.$store.dispatch('newCallForward/addTempGroup','busy' ); - } - break; } - this.groupInCreation = false; }, showForm(){ @@ -224,7 +246,6 @@ float right .csc-cf-group-title text-align right - font-weight bold .csc-cf-destinations-cont margin-top 25px .csc-cf-field-toggle diff --git a/src/components/pages/NewCallForward/CscNewCallForwardAddDestinationForm.vue b/src/components/pages/NewCallForward/CscNewCallForwardAddDestinationForm.vue index b840bb92..8d08870a 100644 --- a/src/components/pages/NewCallForward/CscNewCallForwardAddDestinationForm.vue +++ b/src/components/pages/NewCallForward/CscNewCallForwardAddDestinationForm.vue @@ -11,7 +11,7 @@ @error="error" /> <div - class="csc-form-actions row justify-center" + class="csc-form-actions row justify-center csc-actions-cont" > <q-btn flat @@ -79,7 +79,8 @@ 'disable', 'loading', 'groupName', - 'groupId' + 'groupId', + 'firstDestinationInCreation' ], validations: { number: { @@ -122,7 +123,7 @@ await this.$store.dispatch('newCallForward/loadForwardGroups'); - if(this.destinationIndex === 0){ + if(this.destinationIndex === 0 && this.firstDestinationInCreation){ await this.$store.dispatch('newCallForward/setFirstDestinationInCreation', newGroupId); } @@ -161,4 +162,6 @@ <style lang="stylus" rel="stylesheet/stylus"> @import '../../../themes/app.common.styl' + .csc-actions-cont + margin-bottom 15px </style> diff --git a/src/components/pages/NewCallForward/CscNewCallForwardAddSourcesetForm.vue b/src/components/pages/NewCallForward/CscNewCallForwardAddSourcesetForm.vue index 3cfa87d9..2361d9c7 100644 --- a/src/components/pages/NewCallForward/CscNewCallForwardAddSourcesetForm.vue +++ b/src/components/pages/NewCallForward/CscNewCallForwardAddSourcesetForm.vue @@ -18,7 +18,7 @@ /> <div - class="csc-form-actions row justify-center" + class="csc-form-actions row justify-center csc-actions-cont" > <q-btn flat @@ -162,4 +162,6 @@ <style lang="stylus" rel="stylesheet/stylus"> @import '../../../themes/app.common.styl' + .csc-actions-cont + margin-bottom 15px </style> diff --git a/src/components/pages/NewCallForward/CscNewCallForwardDestination.vue b/src/components/pages/NewCallForward/CscNewCallForwardDestination.vue index 263c878f..5906e94e 100644 --- a/src/components/pages/NewCallForward/CscNewCallForwardDestination.vue +++ b/src/components/pages/NewCallForward/CscNewCallForwardDestination.vue @@ -22,7 +22,8 @@ label-always :step="5" :min="5" - :max="300" + :max="60" + markers snap /> </q-popover> @@ -47,10 +48,16 @@ ref="destTypeForm" class="csc-cf-dest-popover-bottom" v-if="!isVoiceMail()" - v-bind:class="{ 'csc-cf-popover-hide': disableDestType }" + v-bind:class="{ 'csc-cf-popover-hide': disableDestType, 'csc-cf-popover-to-top': popoverToTop, 'csc-cf-popover-timeout-to-top': popoverTimeoutToTop }" @open="showDestTypeForm()" @close="showNext()" > + <div + v-if="this.firstDestinationInCreation && (this.popoverToTop || this.popoverTimeoutToTop)" + class="csc-cf-popver-alert" + > + {{ $t('pages.newCallForward.mandatoryDestinationLabel') }} + </div> <csc-new-call-forward-destination-type-form ref="selectDestinationType" /> @@ -60,8 +67,9 @@ ref="numberForm" class="csc-cf-number-form csc-cf-dest-popover-bottom" v-if="!isVoiceMail()" - v-bind:class="{ 'csc-cf-popover-hide': disableNumberPopover }" + v-bind:class="{ 'csc-cf-popover-hide': disableNumberPopover, 'csc-cf-popover-to-top': popoverToTop, 'csc-cf-popover-timeout-to-top': popoverTimeoutToTop }" @open="showNumberForm()" + @close="movePopoverToInitialPos(); movePopoverTimeoutToInitialPos()" > <csc-new-call-forward-add-destination-form ref="addDestinationForm" @@ -69,6 +77,7 @@ :destination="this.destinationNumber" :groupName="this.groupName" :groupId="this.groupId" + :firstDestinationInCreation="this.firstDestinationInCreation" /> </q-popover> </div> @@ -142,7 +151,9 @@ destinationIndex: null, removeInProgress: false, toggleNumberForm: true, - firstDestinationInCreation: false + firstDestinationInCreation: false, + popoverToTop: false, + popoverTimeoutToTop: false } }, computed: { @@ -192,7 +203,12 @@ await this.$store.dispatch('newCallForward/addVoiceMail', this.groupId); } await this.$store.dispatch('newCallForward/removeGroupLoader', this.groupId); + this.popoverToTop = false; + this.popoverTimeoutToTop = false; break; + default: + this.popoverToTop = false; + this.popoverTimeoutToTop = false; } }, showNumberForm(){ @@ -242,6 +258,18 @@ : this.isVoiceMail() ? `${this.$t('pages.newCallForward.voiceMailLabel')}` : ""; + }, + movePopoverToTop(){ + this.popoverToTop = true; + }, + movePopoverToInitialPos(){ + this.popoverToTop = false; + }, + movePopoverTimeoutToTop(){ + this.popoverTimeoutToTop = true; + }, + movePopoverTimeoutToInitialPos(){ + this.popoverTimeoutToTop = false; } } } @@ -262,10 +290,11 @@ .csc-cf-destination-link color $primary cursor pointer - .csc-cf-timeout-form, + .csc-cf-timeout-form + min-width 200px + padding 0 20px 20px 20px .csc-cf-number-form padding 0 20px 0 20px - min-width 120px .csc-cf-dest-number-cont padding-left 30px .csc-cf-destination-actions @@ -279,4 +308,15 @@ visibility hidden opacity 0 transition visibility 0s 2s, opacity 2s linear + .csc-cf-popover-to-top + position: fixed; + margin: -4vh 0px 0px -120px; + .csc-cf-popover-timeout-to-top + position: fixed; + margin: -8.5vh 0px 0px -120px; + .csc-cf-popver-alert + padding 10px + max-width 160px + font-size 12px + color $red </style> diff --git a/src/components/pages/NewCallForward/CscNewCallForwardEditSources.vue b/src/components/pages/NewCallForward/CscNewCallForwardEditSources.vue index 252e7030..7cb88a1b 100644 --- a/src/components/pages/NewCallForward/CscNewCallForwardEditSources.vue +++ b/src/components/pages/NewCallForward/CscNewCallForwardEditSources.vue @@ -2,6 +2,7 @@ <div v-if="enabled" class="csc-form" + v-bind:class="{ 'csc-cf-popover-hide': toggleFormVisibility}" > <div class="col text-left col-xs-12 col-md-12 "> @@ -9,9 +10,25 @@ class='csc-cf-sourceset-name' > {{ sourceSetName }} + <span + class="csc-cf-delete-sourceset-btn" + > + + <csc-confirm-dialog + ref="confirmDialog" + title-icon="delete" + :title="$t('pages.newCallForward.cancelSourcesetDialogTitle', {name: this.sourceSetName})" + :message="$t('pages.newCallForward.cancelSourcesetText', {name: this.sourceSetName})" + @confirm="confirmDeleteSourceset" + @closed="restorePopver" + /> + + </span> </div> + + </div> <div v-for="(source, item) in sources" @@ -36,10 +53,20 @@ @submit="save()" @error="errorNumber" /> + <q-btn + v-if="!loading" + flat + color="primary" + icon="add" + @click="save()" + :disable="saveDisabled" + class="csc-cf-btn-reduced-size" + > + </q-btn> </div> <div - class="csc-form-actions row justify-center" + class="csc-form-actions row justify-center csc-actions-cont" > <q-btn flat @@ -47,17 +74,15 @@ icon="clear" @mousedown.native="cancel()" > - {{ $t('buttons.cancel') }} + {{ $t('buttons.close') }} </q-btn> <q-btn - v-if="!loading" flat - color="primary" - icon="done" - @click="save()" - :disable="saveDisabled" + color="red" + icon="delete" + @mousedown.native="showRemoveDialog()" > - {{ $t('buttons.save') }} + {{ $t('buttons.remove') }} </q-btn> <div v-if="loading" @@ -75,6 +100,7 @@ } from 'vuex' import CscNewCallForwardInput from './CscNewCallForwardInput' import CscNewCallForwardSource from './CscNewCallForwardSource' + import CscConfirmDialog from "../../CscConfirmationDialog"; import CscSpinner from '../../CscSpinner' import { showGlobalError @@ -93,6 +119,7 @@ components: { CscNewCallForwardInput, CscNewCallForwardSource, + CscConfirmDialog, CscSpinner, QField, QInput, @@ -106,7 +133,8 @@ number: '', numberError: false, destinationIndex: null, - sources: [] + sources: [], + toggleFormVisibility: false } }, props: [ @@ -171,6 +199,22 @@ await this.$store.dispatch('newCallForward/removeGroupLoader', this.groupId); } }, + showRemoveDialog(){ + this.$refs.confirmDialog.open(); + this.toggleFormVisibility = true; + }, + async confirmDeleteSourceset(){ + await this.$store.dispatch('newCallForward/addGroupLoader', this.groupId); + await this.$store.dispatch('newCallForward/deleteSourcesetById', this.sourceSetId); + await this.$store.dispatch('newCallForward/loadMappings'); + await this.$store.dispatch('newCallForward/loadSourcesets'); + await this.$store.dispatch('newCallForward/loadForwardGroups'); + await this.$store.dispatch('newCallForward/removeGroupLoader', this.groupId); + this.restorePopver(); + }, + restorePopver(){ + this.toggleFormVisibility = false; + }, cancel() { this.number = ''; this.enabled = false; @@ -196,4 +240,15 @@ @import '../../../themes/app.common.styl' .csc-cf-sourceset-name margin-top 10px + .csc-cf-popover-hide + display none + .csc-cf-delete-sourceset-btn + float right + margin-top -10px + margin-right -20px + .csc-cf-btn-reduced-size + .on-left + margin-right 0px + .csc-actions-cont + margin-bottom 15px </style> diff --git a/src/components/pages/NewCallForward/CscNewCallForwardSource.vue b/src/components/pages/NewCallForward/CscNewCallForwardSource.vue index 300dbba0..d6a12ff0 100644 --- a/src/components/pages/NewCallForward/CscNewCallForwardSource.vue +++ b/src/components/pages/NewCallForward/CscNewCallForwardSource.vue @@ -3,7 +3,7 @@ class="row csc-cf-source-cont" v-bind:class="{ 'csc-cf-removed-source': removeInProgress }" > - <div class="col text-left col-xs-12 col-md-6 "> + <div class="col text-left col-xs-12 col-md-10 "> <div class='csc-cf-source' @@ -13,7 +13,7 @@ </div> </div> - <div class="col col-xs-12 col-md-6 csc-cf-source-actions"> + <div class="col col-xs-12 col-md-2 csc-cf-source-actions"> <q-icon name="delete" color="negative" @@ -103,7 +103,6 @@ width 100% padding 5px .csc-cf-source - width 100px white-space nowrap overflow hidden text-overflow ellipsis @@ -113,6 +112,8 @@ .csc-cf-source-actions text-align left cursor pointer + .q-icon + margin-left 4px .csc-cf-popover-hide display none .csc-cf-sourceset-name diff --git a/src/locales/en.json b/src/locales/en.json index ca32c17c..054ce851 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -217,7 +217,7 @@ "timeoutGroupFromPost" : "call from ...", "offlineGroup" : "If not available", "busyGroup" : "If busy", - "mainTitle": "Primary number rings before forwarded if the user is online" + "mainTitle": "Primary number {number} rings before forwarded if the user is available" }, "primarNumberEnabled": "All calls go to the primary number", "primarNumberDisabled": "No call goes to primary number", @@ -235,6 +235,8 @@ "cancelDialogTitle": "Delete from {groupName} forwarding", "cancelGroupDialogTitle": "Delete {groupName} forwarding group", "cancelDialogText": "You are about to delete {destination} from {groupName} call forwarding", + "cancelSourcesetDialogTitle": "Delete {name} sourceset", + "cancelSourcesetText": "You are about to delete {name} sourceset", "cancelGroupDialogText": "You are about to delete {groupName} call forwarding group", "unconditionalLabel": "If available", "fromLabel": "If call from ...", @@ -242,7 +244,8 @@ "offlineLabel": "If not available", "busyLabel": "If busy", "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", + "addDestinationAlert": "You have to add a destination to the unsaved group" }, "callForward": { "titles": { diff --git a/src/store/new-call-forward.js b/src/store/new-call-forward.js index 06cc758f..ac902a42 100644 --- a/src/store/new-call-forward.js +++ b/src/store/new-call-forward.js @@ -11,7 +11,8 @@ import { updateDestinationsetName, createSourcesetWithSource, getSourcesets, - addSourceToSourceset + addSourceToSourceset, + deleteSourcesetById } from '../api/call-forward'; const ForwardGroup = { @@ -129,7 +130,7 @@ export default { }, getSourcesesBySourcesetId: (state) => (sourceSetId) => { const sourceSet = state.sourceSets.filter($sourceset => $sourceset.id == sourceSetId); - return sourceSet ? sourceSet[0].sources : null; + return sourceSet && sourceSet[0] ? sourceSet[0].sources : null; } }, mutations: { @@ -625,6 +626,9 @@ export default { async removeSourceFromSourceset(context, data){ await addSourceToSourceset(data) }, + async deleteSourcesetById(context, sourceSetId){ + await deleteSourcesetById(sourceSetId) + }, setFirstDestinationInCreation(context, groupId){ context.commit('setFirstDestinationInCreation', groupId); }