From dc1d714fa72444f50b61d82fa0e17d7422f15294 Mon Sep 17 00:00:00 2001
From: Nouhaila Idrissi Zouggari <nouhaila.idrissi-zouggari@al-enterprise.com>
Date: Wed, 7 Feb 2024 14:31:20 +0100
Subject: [PATCH] MT#59231 let the user know when it has been put on hold

Change-Id: I0625062f236b8b68ecdc39b67ffdf13ccd981ed6
---
 src/api/ngcp-call.js            | 27 ++++++++++++-----
 src/boot/ngcp-call.js           | 31 +++++++++++++++++++
 src/components/call/CscCall.vue | 53 +++++++++++++++++++++++++++------
 src/layouts/CscLayoutMain.vue   | 10 +++++--
 src/store/call/common.js        |  7 +++--
 src/store/call/getters.js       |  1 +
 src/store/call/mutations.js     | 15 ++++++++++
 src/store/call/state.js         |  4 ++-
 8 files changed, 127 insertions(+), 21 deletions(-)

diff --git a/src/api/ngcp-call.js b/src/api/ngcp-call.js
index 5cf901b8..05bc3d36 100644
--- a/src/api/ngcp-call.js
+++ b/src/api/ngcp-call.js
@@ -152,6 +152,12 @@ export function callRegister ({ instanceId }) {
                         $incomingRtcSession = null
                     })
                     callEvent.emit('incoming', $incomingRtcSession)
+                    $incomingRtcSession.on('hold', (holdEvent) => {
+                        callEvent.emit('incomingHold', holdEvent)
+                    })
+                    $incomingRtcSession.on('unhold', (unholdEvent) => {
+                        callEvent.emit('incomingUnHold', unholdEvent)
+                    })
                 }
             }
         })
@@ -189,6 +195,20 @@ export async function callStart ({ number }) {
                 ended (event) {
                     callEvent.emit('outgoingEnded', event)
                     $outgoingRtcSession = null
+                },
+                hold (event) {
+                    if (event.originator === 'local') {
+                        callEvent.emit('outgoingHold', event)
+                    } else {
+                        callEvent.emit('outgoingHolded', event)
+                    }
+                },
+                unhold (event) {
+                    if (event.originator === 'local') {
+                        callEvent.emit('outgoingUnHold', event)
+                    } else {
+                        callEvent.emit('outgoingUnHolded', event)
+                    }
                 }
             },
             mediaStream: $localMediaStream
@@ -413,15 +433,8 @@ export function callToggleHold () {
     if (rtcSession) {
         if (rtcSession.isOnHold().local) {
             rtcSession.unhold()
-            callEvent.emit('callResumed')
         } else {
             rtcSession.hold()
-            callEvent.emit('callOnHold')
         }
     }
 }
-
-export function callIsOnHold () {
-    const rtcSession = callGetRtcSession()
-    return rtcSession ? rtcSession.isOnHold().local : false
-}
diff --git a/src/boot/ngcp-call.js b/src/boot/ngcp-call.js
index 503f752c..02bf6755 100644
--- a/src/boot/ngcp-call.js
+++ b/src/boot/ngcp-call.js
@@ -78,4 +78,35 @@ export default async ({ app, store }) => {
             hasRemoteVideo: callHasRemoteVideo()
         })
     })
+    callEvent.on('incomingHold', (event) => {
+        if (event.originator === 'remote') {
+            store.commit('call/toggleHold')
+            store.commit('call/setRemoteOnHold', true)
+        } else if (event.originator === 'local') {
+            callEvent.on('outgoingHold', (event) => {
+                store.commit('call/toggleHold')
+                store.commit('call/setLocalOnHold', true)
+                store.commit('call/setRemoteOnHold', false)
+            })
+        }
+    })
+    callEvent.on('incomingUnHold', (event) => {
+        if (event.originator === 'remote') {
+            store.commit('call/toggleHold')
+            store.commit('call/setRemoteOnHold', false)
+        } else if (event.originator === 'local') {
+            callEvent.on('outgoingUnHold', (event) => {
+                store.commit('call/toggleHold')
+                store.commit('call/setLocalOnHold', false)
+            })
+        }
+    })
+    callEvent.on('outgoingHolded', (event) => {
+        store.commit('call/toggleHold')
+        store.commit('call/setLocalOnHold', true)
+    })
+    callEvent.on('outgoingUnHolded', (event) => {
+        store.commit('call/toggleHold')
+        store.commit('call/setLocalOnHold', false)
+    })
 }
diff --git a/src/components/call/CscCall.vue b/src/components/call/CscCall.vue
index d322287a..add535a5 100644
--- a/src/components/call/CscCall.vue
+++ b/src/components/call/CscCall.vue
@@ -67,7 +67,7 @@
                 </div>
             </div>
             <div
-                v-else-if="isEstablished"
+                v-else-if="isEstablished || isHolded"
                 class="csc-call-info-established"
             >
                 <div
@@ -137,7 +137,7 @@
                 class="csc-call-media-icon row justify-center items-center full-height"
             >
                 <q-icon
-                    name="person"
+                    :name="isHolded ? 'pause_circle_filled' : 'person'"
                     size="128px"
                     color="white"
                 />
@@ -160,7 +160,7 @@
                 style="margin-top: -30px"
             >
                 <q-btn
-                    v-if="isEstablished && !(isMobile && minimized)"
+                    v-if="isHolded || isEstablished && !(isMobile && minimized)"
                     :color="colorToggleMicrophone"
                     :icon="iconToggleMicrophone"
                     class="q-mr-sm"
@@ -170,17 +170,18 @@
                     @click="toggleMicrophone()"
                 />
                 <q-btn
-                    v-if="isEstablished && !(isMobile && minimized)"
+                    v-if="isHolded || isEstablished && !(isMobile && minimized)"
                     :color="colorToggleHold"
                     text-color="dark"
                     icon="pause_circle_filled"
                     class="q-mr-sm"
                     round
                     size="large"
+                    :disable="islocalOnHold || isremoteOnHold"
                     @click="toggleHold()"
                 />
                 <q-btn
-                    v-if="isEstablished && !(isMobile && minimized)"
+                    v-if="isHolded || isEstablished && !(isMobile && minimized)"
                     :color="colorToggleCamera"
                     :icon="iconToggleCamera"
                     class="q-mr-sm"
@@ -190,7 +191,7 @@
                     @click="toggleCamera()"
                 />
                 <q-btn
-                    v-if="isEstablished && !(isMobile && minimized)"
+                    v-if="isHolded || isEstablished && !(isMobile && minimized)"
                     :color="colorToggleScreen"
                     icon="screen_share"
                     class="q-mr-sm"
@@ -200,7 +201,7 @@
                     @click="toggleScreen()"
                 />
                 <q-btn
-                    v-if="isEstablished && !(isMobile && minimized)"
+                    v-if="isHolded || isEstablished && !(isMobile && minimized)"
                     :color="colorToggleRemoteVolume"
                     :icon="iconToggleRemoteVolume"
                     class="q-mr-sm"
@@ -431,6 +432,14 @@ export default {
             type: Boolean,
             default: false
         },
+        localOnHold: {
+            type: Boolean,
+            default: false
+        },
+        remoteOnHold: {
+            type: Boolean,
+            default: false
+        },
         remoteVolumeEnabled: {
             type: Boolean,
             default: false
@@ -485,7 +494,7 @@ export default {
             return this.isInitiating || this.isRinging || this.isIncoming
         },
         isActive () {
-            return this.isCalling || this.isEstablished
+            return this.isCalling || this.isEstablished || this.isHolded
         },
         isInitiating () {
             return this.callState === 'initiating'
@@ -502,6 +511,9 @@ export default {
         isEnded () {
             return this.callState === 'ended'
         },
+        isHolded () {
+            return this.callState === 'hold'
+        },
         canStart () {
             return this.callState === 'input' || this.callState === 'incoming'
         },
@@ -550,7 +562,7 @@ export default {
             }
         },
         colorToggleHold () {
-            if (this.holdEnabled) {
+            if (this.holdEnabled && !this.remoteOnHold && !this.localOnHold) {
                 return 'primary'
             } else {
                 return 'grey-1'
@@ -575,6 +587,12 @@ export default {
         },
         isNumberInputDefined () {
             return this.numberInput !== '' && this.numberInput !== null
+        },
+        islocalOnHold () {
+            return this.localOnHold
+        },
+        isremoteOnHold () {
+            return this.remoteOnHold
         }
     },
     watch: {
@@ -754,6 +772,19 @@ export default {
             .csc-dialpad-button
                 vertical-align: center
                 margin-left: $flex-gutter-sm
+        .csc-call-info-hold
+            position: absolute
+            bottom: $call-footer-action-margin * 2
+            right: 0
+            left: 0
+            justify-items: center
+            z-index: 3
+            color: white
+            .csc-media-icon
+                margin-right: $flex-gutter-xs
+            .csc-dialpad-button
+                vertical-align: center
+                margin-left: $flex-gutter-sm
     .csc-call-media-remote
         position: absolute
         top: 0
@@ -834,6 +865,9 @@ export default {
 .csc-call.csc-call-established
     .csc-call-content
         background-color: transparent
+.csc-call.csc-call-hold
+    .csc-call-content
+        background-color: transparent
 .csc-call.csc-call-minimized
     opacity: 0
     height: $call-footer-height-big
@@ -865,6 +899,7 @@ export default {
 .csc-call.csc-call-minimized.csc-call-initiating,
 .csc-call.csc-call-minimized.csc-call-ringing,
 .csc-call.csc-call-minimized.csc-call-established,
+.csc-call.csc-call-minimized.csc-call-hold,
 .csc-call.csc-call-minimized.csc-call-ended
     bottom: 0
     opacity: 1
diff --git a/src/layouts/CscLayoutMain.vue b/src/layouts/CscLayoutMain.vue
index 2b458bc0..92d6ee43 100644
--- a/src/layouts/CscLayoutMain.vue
+++ b/src/layouts/CscLayoutMain.vue
@@ -179,6 +179,8 @@
             :camera-enabled="cameraEnabled"
             :screen-enabled="screenEnabled"
             :hold-enabled="holdEnabled"
+            :local-on-hold="localOnHold"
+            :remote-on-hold="remoteOnHold"
             :remote-volume-enabled="remoteAudioEnabled"
             :dialpad-opened="dialpadOpened"
             :menu-minimized="menuMinimized"
@@ -295,7 +297,9 @@ export default {
             'microphoneEnabled',
             'remoteAudioEnabled',
             'maximized',
-            'dialpadOpened'
+            'dialpadOpened',
+            'localOnHold',
+            'remoteOnHold'
         ]),
         ...mapGetters('user', [
             'isLogged',
@@ -395,7 +399,8 @@ export default {
                 this.callState === 'ringing' ||
                 this.callState === 'established' ||
                 this.callState === 'incoming' ||
-                this.callState === 'ended'
+                this.callState === 'ended' ||
+                this.callState === 'hold'
         },
         getLocalMediaStream () {
             if (this.localMediaStream) {
@@ -431,6 +436,7 @@ export default {
             if (this.callState === CallState.initiating ||
                 this.callState === CallState.ringing ||
                 this.callState === CallState.incoming ||
+                this.callState === CallState.hold ||
                 this.callState === CallState.established) {
                 return this.callNumberFormatted
             } else if (this.callState === CallState.ended) {
diff --git a/src/store/call/common.js b/src/store/call/common.js
index 7b1b9a26..f0071ceb 100644
--- a/src/store/call/common.js
+++ b/src/store/call/common.js
@@ -8,7 +8,9 @@ export const CallState = {
     ringing: 'ringing',
     incoming: 'incoming',
     established: 'established',
-    ended: 'ended'
+    ended: 'ended',
+    hold: 'hold',
+    unhold: 'unhold'
 }
 export const CallStateTitle = {
     get input () { return i18n.global.tc('Start new call') },
@@ -16,7 +18,8 @@ export const CallStateTitle = {
     get ringing () { return i18n.global.tc('Ringing at') },
     get incoming () { return i18n.global.tc('Incoming call from') },
     get established () { return i18n.global.tc('In call with') },
-    get ended () { return i18n.global.tc('Call ended') }
+    get ended () { return i18n.global.tc('Call ended') },
+    get hold () { return i18n.global.tc('Call holded') }
 }
 
 export const MediaType = {
diff --git a/src/store/call/getters.js b/src/store/call/getters.js
index b6ebdcf1..f60ce928 100644
--- a/src/store/call/getters.js
+++ b/src/store/call/getters.js
@@ -26,6 +26,7 @@ export default {
         if (state.callState === CallState.initiating ||
             state.callState === CallState.ringing ||
             state.callState === CallState.incoming ||
+            state.callState === CallState.hold ||
             state.callState === CallState.established) {
             return getters.callNumberFormatted
         } else if (state.callState === CallState.ended) {
diff --git a/src/store/call/mutations.js b/src/store/call/mutations.js
index 1fef2681..321fb5e0 100644
--- a/src/store/call/mutations.js
+++ b/src/store/call/mutations.js
@@ -58,6 +58,9 @@ export default {
     endCall (state, reason) {
         if (reason) {
             state.callState = CallState.ended
+            state.holdEnabled = false
+            state.remoteOnHold = false
+            state.localOnHold = false
             state.endedReason = reason
         }
         state.dialpadOpened = false
@@ -107,7 +110,19 @@ export default {
     toggleHold (state) {
         state.holdEnabled = !state.holdEnabled
         if (state.holdEnabled) {
+            state.callState = CallState.hold
             state.holdEnabled = true
+        } else {
+            state.callState = CallState.established
+            state.holdEnabled = false
         }
+    },
+    setLocalOnHold (state, value) {
+        state.localOnHold = value
+    },
+    
+    setRemoteOnHold (state, value) {
+        state.remoteOnHold = value
     }
+    
 }
diff --git a/src/store/call/state.js b/src/store/call/state.js
index b2ad1d4f..0bba10d3 100644
--- a/src/store/call/state.js
+++ b/src/store/call/state.js
@@ -21,5 +21,7 @@ export default {
     remoteAudioEnabled: true,
     remoteVideoEnabled: true,
     maximized: false,
-    dialpadOpened: false
+    dialpadOpened: false,
+    localOnHold: false,
+    remoteOnHold: false
 }