diff --git a/src/components/pages/NewCallForward/CscCallForwardGroup.vue b/src/components/pages/NewCallForward/CscCallForwardGroup.vue index c9f98811..2b9e669b 100644 --- a/src/components/pages/NewCallForward/CscCallForwardGroup.vue +++ b/src/components/pages/NewCallForward/CscCallForwardGroup.vue @@ -3,16 +3,20 @@ class="csc-cf-group" v-if="group.destinations.length > 0" > - - <!-- <csc-object-spinner - /> --> <div - v-if="group.id !== 'unconditional'" - class="csc-cf-group-title" + class="row csc-cf-destination-cont" > - {{ group.title }} + <div class="col col-xs-12 col-md-4 text-right csc-cf-group-title"> + {{ groupTitle }} + </div> + <div class="col text-left col-xs-12 col-md-2 csc-cf-dest-number-cont"> + <q-toggle + v-model="isEnabled" + @change="toggleGroupChange" + /> + </div> + <div class="col col-xs-12 col-md-5 "></div> </div> - <div v-for="(destination, index) in group.destinations" :key="genKey()" @@ -23,6 +27,8 @@ :groupId="group.id" :groupName="group.name" :allCallsFwd="group.name == 'csc-unconditional' && index === 0" + :class="{ 'cf-destination-disabled': !isEnabled }" + /> </div> <div @@ -32,16 +38,17 @@ <div class="col col-xs-12 col-md-2 text-left" v-if="showAddDestBtn" + :class="{ 'cf-destination-disabled': !isEnabled }" > <div class='csc-cf-destination-add-destination' - @click="addDestination" > <q-icon name="add" color="primary" size="24px" /> + {{ $t('pages.newCallForward.addDestinationLabel') }} <q-spinner-dots @@ -52,6 +59,28 @@ /> </div> + <q-popover + ref="destTypeForm" + anchor="top right" + @open="showDestTypeForm()" + @close="showNumberFormPopover()" + > + <csc-new-call-forward-destination-type-form + ref="selectDestinationType" + /> + </q-popover> + <q-popover + ref="numberForm" + anchor="top right" + class="csc-cf-number-form" + v-bind:class="{ 'csc-cf-popover-hide': toggleNumberForm }" + @open="showNewDestNumber()" + > + <csc-new-call-forward-add-destination-form + ref="addDestinationForm" + :groupName="this.group.name" + /> + </q-popover> </div> <div class="col col-xs-12 col-md-6 "></div> </div> @@ -64,6 +93,7 @@ } from 'vuex' import { QSpinnerDots, + QToggle, QIcon, QPopover, QList, @@ -73,7 +103,8 @@ } from 'quasar-framework' import CscObjectSpinner from "../../CscObjectSpinner"; import CscNewCallForwardDestination from './CscNewCallForwardDestination' - + import CscNewCallForwardAddDestinationForm from './CscNewCallForwardAddDestinationForm' + import CscNewCallForwardDestinationTypeForm from './CscNewCallForwardDestinationTypeForm' export default { name: 'csc-cf-group', props: [ @@ -81,6 +112,7 @@ ], components: { QSpinnerDots, + QToggle, QIcon, QPopover, QList, @@ -88,16 +120,33 @@ QItemMain, QItemSide, CscObjectSpinner, - CscNewCallForwardDestination + CscNewCallForwardDestination, + CscNewCallForwardAddDestinationForm, + CscNewCallForwardDestinationTypeForm }, data () { return { - destinationInCreation: false + toggleGroup: true, + isEnabled: true, + toggleNumberForm: true }; }, + async mounted(){ + try{ + if(!this.inCreation){ + const isGroupEnabled = await this.$store.dispatch('newCallForward/isGroupEnabled', this.group.name); + this.isEnabled = isGroupEnabled; + } + + } + catch(err){ + console.log(err) + } + }, computed: { ...mapGetters('newCallForward', [ - 'getOwnPhoneTimeout' + 'getOwnPhoneTimeout', + 'destinationInCreation' ]), showAddDestBtn(){ const destinations = this.group.destinations; @@ -108,6 +157,9 @@ } return true; + }, + groupTitle(){ + return ["csc-unconditional", "csc-timeout"].includes(this.group.name) ? `${this.$t('pages.newCallForward.timeoutGroupTitle')}` : ""; } }, methods: { @@ -115,25 +167,33 @@ genKey(){ return Math.random(); }, - async addDestination(){ - this.destinationInCreation = true; - await this.$store.dispatch('newCallForward/addDestination', { - forwardGroupId: this.group.id, - destination: " " - }); - await this.$store.dispatch('newCallForward/loadForwardGroups'); - this.destinationInCreation = false; - + showNewDestNumber(){ + this.$refs.addDestinationForm.add(); + }, + showNumberFormPopover(){ + this.toggleNumberForm = false; + this.$refs.numberForm.open(); + }, + showDestTypeForm(){ + this.toggleNumberForm = true; + this.$refs.selectDestinationType.add(); }, getDestination(index){ let destination = {...this.group.destinations[index]} if(index === 0){ - destination.timeout = this.getOwnPhoneTimeout; + destination.timeout = !isNaN(this.getOwnPhoneTimeout) ? this.getOwnPhoneTimeout : 5; } else { destination.timeout = this.group.destinations[index-1].timeout; } return destination; + }, + toggleGroupChange(){ + this.$store.dispatch('newCallForward/enableGroup', { + groupName: this.group.name, + id: this.group.id, + enabled: this.isEnabled + }); } } } @@ -143,6 +203,10 @@ @import '../../../themes/app.common.styl' .csc-cf-group width 100% + .csc-cf-group-cont + position relative + .csc-cf-group-title + font-weight bold .csc-cf-group-title text-align right .csc-cf-destination-label @@ -157,4 +221,16 @@ text-overflow ellipsis color $primary cursor pointer + .cf-destination-disabled + color $cf-disabled-label + .csc-cf-timeout, + .csc-cf-destination + color $cf-disabled-link + .csc-cf-destination-actions + .q-icon + color $cf-disabled-btn !important + .csc-cf-destination-add-destination + color $cf-disabled-link + .q-icon + color $cf-disabled-link !important </style> diff --git a/src/components/pages/NewCallForward/CscNewCallForward.vue b/src/components/pages/NewCallForward/CscNewCallForward.vue index 3db2a0e9..d74cb7d0 100644 --- a/src/components/pages/NewCallForward/CscNewCallForward.vue +++ b/src/components/pages/NewCallForward/CscNewCallForward.vue @@ -21,18 +21,15 @@ > <q-toggle - v-if="showSwitcher" + v-if="forwardGroups.length > 0" v-model="toggleDefaultNumber" @change="toggleChange" /> - </div> </div> <div class="csc-cf-row row"> <div class="column col col-xs-12 col-md-4 items-end" > - - <div class="csc-text-action" > @@ -75,7 +72,6 @@ :group="forwardGroup" /> </div> - <div class="csc-cf-row row"> <div class="column col col-xs-12 col-md-4" @@ -156,8 +152,7 @@ ...mapGetters('newCallForward', [ 'primaryNumber', 'subscriberDisplayName', - 'forwardGroups', - 'showSwitcher' + 'forwardGroups' ]), primaryNumberEnabled(){ return true; @@ -172,21 +167,22 @@ if(this.toggleDefaultNumber){ const timeoutFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupByName', 'timeout'); if(!timeoutFwdGroup){ - await this.$store.dispatch('newCallForward/addForwardGroup', 'timeout'); - await this.$store.dispatch('newCallForward/loadForwardGroups'); + //await this.$store.dispatch('newCallForward/addForwardGroup', 'timeout'); + await this.$store.dispatch('newCallForward/addTempDestination','timeout' ); + //await this.$store.dispatch('newCallForward/loadForwardGroups'); } } else{ const unconditionalFwdGroup = await this.$store.dispatch('newCallForward/getForwardGroupByName', 'unconditional'); if(!unconditionalFwdGroup){ - await this.$store.dispatch('newCallForward/addForwardGroup', 'unconditional'); - await this.$store.dispatch('newCallForward/loadForwardGroups'); + //await this.$store.dispatch('newCallForward/addForwardGroup', 'unconditional'); + await this.$store.dispatch('newCallForward/addTempDestination','unconditional' ); + //await this.$store.dispatch('newCallForward/loadForwardGroups'); } } this.groupInCreation = false; }, - togglePrimaryNumber(){}, showForm(){ this.$refs.destinationType.close(); this.$refs.addDestinationForm.add(); diff --git a/src/components/pages/NewCallForward/CscNewCallForwardAddDestinationForm.vue b/src/components/pages/NewCallForward/CscNewCallForwardAddDestinationForm.vue index 4d6d5b9d..b30a0a24 100644 --- a/src/components/pages/NewCallForward/CscNewCallForwardAddDestinationForm.vue +++ b/src/components/pages/NewCallForward/CscNewCallForwardAddDestinationForm.vue @@ -42,6 +42,9 @@ </template> <script> + import { + mapGetters, + } from 'vuex' import CscNewCallForwardInput from './CscNewCallForwardInput' import CscSpinner from '../../CscSpinner' import { @@ -91,6 +94,9 @@ } }, computed: { + ...mapGetters('newCallForward', [ + 'destinationInCreation' + ]), saveDisabled() { return this.numberError|| this.disable || this.loading; } @@ -99,33 +105,34 @@ async save() { const forwardGroupName = this.groupName; const forwardGroup = await this.$store.dispatch('newCallForward/getForwardGroupByName', forwardGroupName); - if (this.numberError || this.saveDisabled) { showGlobalError(this.$t('validationErrors.generic')); } - else if(Number.isInteger(this.destinationIndex)){ // edit mode - this.$store.dispatch('newCallForward/editDestination',{ + else if(Number.isInteger(this.destinationIndex) && Number.isInteger(forwardGroup.id)){ // edit mode + await this.$store.dispatch('newCallForward/editDestination',{ index: this.destinationIndex, forwardGroupId: forwardGroup.id, destination: this.number }); } else { // new destination - let forwardGroupId; - if(!forwardGroup){ - forwardGroupId = await this.$store.dispatch('newCallForward/addForwardGroup', forwardGroupName); - await this.$store.dispatch('newCallForward/loadForwardGroups'); // keeps local data updated + if(forwardGroup.id.toString().includes('temp-')){ // unexisting group + forwardGroup.destinations[0].simple_destination = this.number; // optimistic UI update :) + await this.$store.dispatch('newCallForward/addForwardGroup', { + name: forwardGroupName, + destination: this.number + }); } - else{ - forwardGroupId = forwardGroup.id; + else{ // existing group + await this.$store.dispatch('newCallForward/setDestinationInCreation', true); + await this.$store.dispatch('newCallForward/addDestination', { + forwardGroupId: forwardGroup.id, + destination: this.number + }); } - - this.$store.dispatch('newCallForward/addDestination', { - forwardGroupId: forwardGroupId, - destination: this.number - }); + await this.$store.dispatch('newCallForward/loadForwardGroups'); + await this.$store.dispatch('newCallForward/setDestinationInCreation', false); } - }, cancel() { this.number = ''; diff --git a/src/components/pages/NewCallForward/CscNewCallForwardDestination.vue b/src/components/pages/NewCallForward/CscNewCallForwardDestination.vue index 085aab49..069d1e5a 100644 --- a/src/components/pages/NewCallForward/CscNewCallForwardDestination.vue +++ b/src/components/pages/NewCallForward/CscNewCallForwardDestination.vue @@ -50,7 +50,6 @@ anchor="top right" class="csc-cf-number-form" v-bind:class="{ 'csc-cf-popover-hide': toggleNumberForm }" - v-if="" @open="showNumberForm()" > <csc-new-call-forward-add-destination-form @@ -148,7 +147,11 @@ }, methods: { updateValues(destination){ - this.destinationTimeout = this.index === 0 && this.groupName === 'csc-timeout' ? this.getOwnPhoneTimeout : destination.timeout; + this.destinationTimeout = this.index === 0 + && this.groupName === 'csc-timeout' + && isNaN(this.getOwnPhoneTimeout) === false + ? this.getOwnPhoneTimeout + : destination.timeout; this.destinationNumber = destination.simple_destination; this.destinationIndex = this.index; }, diff --git a/src/locales/en.json b/src/locales/en.json index 48e42543..77075bed 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -223,6 +223,7 @@ "allCallsForwardedTo": "All calls forwarded to", "cancelDialogTitle": "Delete from {groupName} forwarding", "cancelDialogText": "You are about to delete {destination} from {groupName} call forwarding", + "timeoutGroupTitle" : "", "uncoditionalLabel": "Unconditional" }, "callForward": { diff --git a/src/store/new-call-forward.js b/src/store/new-call-forward.js index 2fc8bb7b..700655d0 100644 --- a/src/store/new-call-forward.js +++ b/src/store/new-call-forward.js @@ -26,7 +26,7 @@ export default { state: { mappings: [], forwardGroups: [], - showSwitcher: true + destinationInCreation: false }, getters: { primaryNumber(state, getters, rootState, rootGetters) { @@ -48,8 +48,11 @@ export default { getOwnPhoneTimeout(state){ return parseInt(state.mappings.cft_ringtimeout); }, - showSwitcher(state){ - return state.showSwitcher; + tempDestinations(state){ + return state.tempDestinations; + }, + destinationInCreation(state){ + return state.destinationInCreation; } }, mutations: { @@ -82,15 +85,8 @@ export default { loadForwardGroups(state, forwardGroups){ state.forwardGroups = forwardGroups; }, - setShowSwitcher(state){ - const forwardGroups = state.forwardGroups; - const timeoutGroup = forwardGroups.find(($forwardGroup) => { - return $forwardGroup.name === 'csc-timeout'; - }); - const unconditionalGroup = forwardGroups.find(($forwardGroup) => { - return $forwardGroup.name === 'csc-unconditional'; - }); - state.showSwitcher = (timeoutGroup && timeoutGroup.destinations.length > 0) || (unconditionalGroup && unconditionalGroup.destinations.length > 0); + setDestinationInCreation(state, isInCreation){ + state.destinationInCreation = isInCreation; } }, actions: { @@ -107,7 +103,6 @@ export default { try{ const forwardGroups = await getDestinationsets(localStorage.getItem('subscriberId')); context.commit('loadForwardGroups', forwardGroups); - context.commit('setShowSwitcher'); return forwardGroups; } catch(err){ @@ -117,7 +112,7 @@ export default { async editMapping(context, data){ try{ const subscriberId = localStorage.getItem('subscriberId'); - const groupMappingId = ForwardGroup[data.name].mapping; + const groupMappingId = ForwardGroup[data.name] ? ForwardGroup[data.name].mapping : await context.dispatch('getMappingIdByGroupName', data.name); const allMappings = await getMappings(subscriberId); let groupMappings = allMappings[groupMappingId]; @@ -140,19 +135,32 @@ export default { } }, - async addForwardGroup(context, name) { + createEmptyForwardGroup(context, groupName){ + const destination = { + "announcement_id": null, + "simple_destination": " ", + "destination": " ", + "priority": 1, + "timeout": 5 + }; + context.state.tempForwardGroups.push({ + name: groupName, + destinations:[destination] + }); + }, + async addForwardGroup(context, data) { try{ - const newForwardGroupId = await addNewDestinationsetWithName(ForwardGroup[name].name); + const newForwardGroupId = await addNewDestinationsetWithName(ForwardGroup[data.name] ? ForwardGroup[data.name].name : data.name); const destination = { "announcement_id": null, - "simple_destination": " ", - "destination": " ", + "simple_destination": data.destination || " ", + "destination": data.destination || " ", "priority": 1, "timeout": 5 }; await context.dispatch('editMapping', { - name: name, + name: data.name, groupId: newForwardGroupId }); @@ -163,7 +171,7 @@ export default { // setting cft_ringtimeout in case it is // not set while creating timeout group - if(name === 'timeout' && !context.getters.getOwnPhoneTimeout){ + if((data.name === 'timeout' || data.name === 'csc-timeout') && (!context.getters.getOwnPhoneTimeout || isNaN(context.getters.getOwnPhoneTimeout))){ await context.dispatch('editRingTimeout', 5); } @@ -196,10 +204,23 @@ export default { }); return forwardGroups.length > 0 ? forwardGroups[0] : null; }, + addTempDestination(context, groupName){ + context.state.forwardGroups.push({ + id: "temp-" + ForwardGroup[groupName].name, + name: ForwardGroup[groupName].name, + destinations: [{ + "announcement_id": null, + "simple_destination": " ", + "destination": " ", + "priority": 1, + "timeout": 5 + }] + }); + }, async addDestination(context, data){ try{ let group = context.state.forwardGroups.find((group)=>{ - return group.id === data.forwardGroupId; + return group.id === data.forwardGroupId || group.id.toString() === data.forwardGroupId; }); const destination = { "announcement_id": null, @@ -312,13 +333,17 @@ export default { let timeoutGroup = await context.dispatch('getForwardGroupByName', 'timeout'); if(!unconditionalGroup){ - await context.dispatch('addForwardGroup', 'unconditional'); + await context.dispatch('addForwardGroup', { + name: 'unconditional' + }); await context.dispatch('loadMappings'); await context.dispatch('loadForwardGroups'); unconditionalGroup = await context.dispatch('getForwardGroupByName', 'unconditional'); } if(!timeoutGroup){ - await context.dispatch('addForwardGroup', 'timeout'); + await context.dispatch('addForwardGroup', { + name: 'timeout' + }); await context.dispatch('loadMappings'); await context.dispatch('loadForwardGroups'); timeoutGroup = await context.dispatch('getForwardGroupByName', 'timeout'); @@ -346,6 +371,48 @@ export default { catch(err){ console.log(err) } + }, + getMappingIdByGroupName(context, groupName){ + let mappingId; + for(let key in ForwardGroup){ + if(ForwardGroup[key].name == groupName){ + mappingId = ForwardGroup[key].mapping; + break; + } + } + return mappingId; + }, + async isGroupEnabled(context, groupName){ + const mappingId = await context.dispatch('getMappingIdByGroupName', groupName); + return mappingId + && context.state.mappings[mappingId] + && context.state.mappings[mappingId][0] // IMPROVE remove hardcoded [0] + ? context.state.mappings[mappingId][0].enabled + : true; + }, + async enableGroup(context, data){ + try{ + if(!data.id.toString().includes('temp-')){ + const subscriberId = localStorage.getItem('subscriberId'); + const mappingId = await context.dispatch('getMappingIdByGroupName', data.groupName); + let groupMappings = context.state.mappings[mappingId]; + groupMappings[0].enabled = data.enabled; // IMPROVE remove hardcoded [0] + + await addNewMapping({ + mappings: groupMappings, + group: mappingId, + subscriberId: subscriberId + }); + context.dispatch('loadMappings'); + } + + } + catch(err){ + console.log(err) + } + }, + setDestinationInCreation(context, isInCreation){ + context.commit('setDestinationInCreation', isInCreation); } } }; diff --git a/src/themes/app.variables.styl b/src/themes/app.variables.styl index 25fdc27f..df4b8002 100644 --- a/src/themes/app.variables.styl +++ b/src/themes/app.variables.styl @@ -97,3 +97,7 @@ $chip-color = $dark $conf-participant-icon-color = rgba(255, 255, 255, 0.6); $conf-participant-box-color = rgba(21,29,48,0.8); + +$cf-disabled-label = lighten($white, -35%); +$cf-disabled-link = lighten($primary, -35%); +$cf-disabled-btn = lighten($negative, -35%);