You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngcp-csc-ui/src/layouts/CscLayoutMain.vue

690 lines
20 KiB

<template>
<q-layout
id="csc-layout-main"
view="lHh LpR lFf"
@resize="layoutResized"
>
<q-header
id="csc-header-main"
v-model="header"
reveal
class="bg-secondary"
>
<q-toolbar
id="csc-header-toolbar-main"
>
<q-btn
v-if="isMobile"
flat
icon="menu"
color="primary"
@click="$refs.mainMenu.show()"
/>
<q-btn
v-if="hasFaxCapabilityAndFaxActive && hasSendFaxFeature"
class="q-mr-sm"
flat
dense
icon="apps"
color="primary"
>
<csc-popup-menu>
<csc-popup-menu-item
icon="description"
color="primary"
:label="$t('Send Fax')"
@click="showSendFax()"
/>
</csc-popup-menu>
</q-btn>
<csc-selection-language
v-if="!isMobile"
/>
<q-btn
icon="person"
color="primary"
small
flat
dense
:label="getUsername"
>
<q-menu>
<csc-user-menu
:username="getUsername"
/>
</q-menu>
</q-btn>
<q-btn
v-if="showQrBtn"
flat
dense
class="q-ml-sm"
icon="qr_code"
color="primary"
@click="showQrDialog"
/>
<q-space />
<csc-logo
v-if="isLogoRequested && !customLogo"
id="csc-default-logo"
color="light"
/>
<csc-custom-logo
v-else-if="isLogoRequested && customLogo"
id="csc-custom-logo"
:logo-data="customLogo"
/>
</q-toolbar>
<q-toolbar
v-if="menuMinimized"
inset
>
<q-item
class="bg-secondary q-pa-none"
>
<q-item-section>
<q-item-label
class="text-h6"
>
{{ route.meta.title }}
</q-item-label>
<q-item-label
v-if="route.meta.subtitle"
class="text-subtitle2"
>
{{ route.meta.subtitle }}
</q-item-label>
</q-item-section>
</q-item>
</q-toolbar>
</q-header>
<q-drawer
id="csc-drawer-left"
ref="mainMenu"
v-model="menuClosed"
:mini="menuMinimized"
content-class="bg-main-menu"
:behavior="drawerBehavior"
show-if-above
:width="280"
@mouseleave="minimizeMenu"
@mouseenter="maximizeMenu"
@on-layout="layoutResized"
>
<div
v-if="$q.platform.is.desktop"
:class="pinMenuButtonClasses"
>
<div
class="col col-auto"
>
<q-btn
v-if="!menuMinimized"
:icon="pinMenuButtonIcon"
color="white"
flat
dense
round
@click="pinMenu"
/>
</div>
</div>
<csc-selection-language-mobile
v-if="$q.platform.is.mobile"
id="csc-language-menu-main-mobile"
class="csc-language-menu"
/>
<csc-main-menu-top
id="csc-main-menu-top"
class="csc-main-menu no-margin"
:call-state-title="callStateTitle"
:call-state-subtitle="callStateSubtitle"
:is-call-forward="isCallForward"
:is-call-blocking="isCallBlocking"
:is-pbx-admin="isPbxAdmin"
:is-pbx-configuration="isPbxConfiguration"
/>
<aui-mobile-app-badges />
</q-drawer>
<q-page-container
id="csc-page-main"
>
<router-view />
</q-page-container>
<csc-send-fax
v-model="faxDialog"
/>
<csc-call
id="csc-call"
ref="call"
:call-state="callState"
:call-number="callNumber"
:ended-reason="endedReason"
:full-view="isFullView"
:minimized="!isHome && !isMaximized"
:maximizable="!isHome"
:closed="!isCalling && !isHome"
:local-media-stream="localMediaStream"
:remote-media-stream="remoteMediaStream"
:is-video-call="hasVideo"
:has-local-video="hasLocalVideo"
:has-remote-video="hasRemoteVideo"
:microphone-enabled="isMicrophoneEnabled"
:camera-enabled="isCameraEnabled"
:remote-volume-enabled="isRemoteVolumeEnabled"
:dialpad-opened="isDialpadOpened"
:menu-minimized="menuMinimized"
@start-call="startCall"
@accept-call="acceptCall"
@end-call="endCall"
@close-call="closeCall"
@toggle-microphone="toggleMicrophone"
@toggle-camera="toggleCamera"
@toggle-remote-volume="toggleRemoteVolume"
@click-dialpad="clickDialpad"
@toggle-dialpad="toggleDialpad"
@maximize-call="maximizeCall"
@minimize-call="minimizeCall"
/>
</q-layout>
</template>
<script>
import { colors } from 'quasar'
import platformMixin from '../mixins/platform'
import {
startLoading,
stopLoading,
showToast,
showGlobalError,
enableIncomingCallNotifications
} from 'src/helpers/ui'
import {
mapGetters,
mapActions,
mapState
} from 'vuex'
import CscCall from 'components/call/CscCall'
import CscSendFax from 'components/CscSendFax'
import CscLogo from 'components/CscLogo'
import CscCustomLogo from 'components/CscCustomLogo'
import CscUserMenu from 'components/CscUserMenu'
import CscMainMenuTop from 'components/CscMainMenuTop'
import CscPopupMenu from 'components/CscPopupMenu'
import CscPopupMenuItem from 'components/CscPopupMenuItem'
import AuiMobileAppBadges from 'components/AuiMobileAppBadges'
import CscDialogQrCode from 'components/CscDialogQrCode'
import CscSelectionLanguage from 'components/CscSelectionLanguage'
import CscSelectionLanguageMobile from 'components/CscSelectionLanguageMobile'
export default {
name: 'CscMainLayout',
components: {
CscSelectionLanguage,
CscSelectionLanguageMobile,
AuiMobileAppBadges,
CscPopupMenuItem,
CscPopupMenu,
CscMainMenuTop,
CscCall,
CscSendFax,
CscLogo,
CscCustomLogo,
CscUserMenu
},
mixins: [
platformMixin
],
data () {
return {
header: true,
menuClosed: false,
menuPinned: true,
menuMinimized: false,
sideStates: {
left: true,
right: false
},
mobileMenu: null,
faxDialog: false,
customLogo: null
}
},
computed: {
...mapState([
'route'
]),
...mapGetters([
'isCallForward',
'isCallBlocking',
'isPbxConfiguration',
'isHome'
]),
...mapGetters('call', [
'isCallEnabled',
'callState',
'callNumber',
'callNumberInput',
'endedReason',
'isCalling',
'localMediaStream',
'remoteMediaStream',
'hasVideo',
'hasLocalVideo',
'hasRemoteVideo',
'isMicrophoneEnabled',
'isCameraEnabled',
'isRemoteVolumeEnabled',
'isMaximized',
'isDialpadOpened',
'callStateTitle',
'callStateSubtitle'
]),
...mapGetters('conference', [
'isConferencingEnabled'
]),
...mapGetters('user', [
'isLogged',
'hasUser',
'getUsername',
'isPbxAdmin',
'hasSmsCapability',
'hasFaxCapabilityAndFaxActive',
'hasSendSmsFeature',
'hasSendFaxFeature',
'userDataRequesting',
'userDataSucceeded',
'isRtcEngineUiVisible',
'isLogoRequesting',
'isLogoRequested'
]),
...mapState('user', [
'resellerBranding',
'defaultBranding',
'platformInfo'
]),
...mapGetters('communication', [
'createFaxState',
'createFaxError'
]),
showQrBtn () {
return this.platformInfo?.app?.show_qr
},
hasCommunicationCapabilities () {
return (this.hasSmsCapability && this.hasSendSmsFeature) ||
(this.hasFaxCapabilityAndFaxActive && this.hasSendFaxFeature)
},
isMenuClosed () {
return !this.sideStates.left
},
isFullView () {
return this.isMenuClosed || this.isMobile || this.mobileMenu
},
layoutClasses () {
const classes = []
if (this.isCalling) {
classes.push('csc-layout-call-active')
}
if (this.menuMinimized) {
classes.push('csc-menu-minimized')
}
return classes
},
headerClasses () {
const classes = ['transition-generic']
if (this.isMobile) {
classes.push('csc-header-mobile')
}
if (this.isMobile || this.isMenuClosed) {
classes.push('csc-header-full')
}
return classes
},
pinMenuButtonIcon () {
if (!this.menuPinned) {
return 'push_pin'
} else {
return 'arrow_left'
}
},
pinMenuButtonClasses () {
const classes = ['pin-menu-button row items-center']
if (!this.menuMinimized) {
classes.push('justify-end')
classes.push('q-pl-sm q-pr-sm')
} else {
classes.push('justify-center')
}
return classes
},
drawerBehavior () {
if (this.$q.platform.is.mobile) {
return 'mobile'
} else {
return 'desktop'
}
}
},
watch: {
callState (state) {
if (state === 'established') {
this.menuPinned = false
this.menuMinimized = true
this.header = true
} else {
this.header = true
}
},
isHome (isHome) {
if (isHome) {
this.$store.commit('call/minimize')
}
},
userDataSucceeded (userDataSucceeded) {
if (userDataSucceeded) {
enableIncomingCallNotifications()
this.updateBrandings()
}
},
isCallEnabled (value) {
if (value && this.isRtcEngineUiVisible) {
showToast(this.$i18n.t('You are now able to start and receive calls'))
}
},
createFaxState (state) {
if (state === 'requesting') {
startLoading()
} else if (state === 'failed') {
stopLoading()
showGlobalError(this.createFaxError)
} else if (state === 'succeeded') {
stopLoading()
showToast(this.$t('Sending fax completed successfully.'))
this.hideSendFax()
}
},
$route (route) {
if (!this.isHome) {
this.$store.commit('call/minimize')
}
if (this.$refs.call) {
this.$nextTick(() => {
this.$refs.call.fitMedia()
})
}
window.scrollTo(0, 0)
if (route.path === '/user/home') {
this.forwardHome()
}
}
},
async mounted () {
window.addEventListener('orientationchange', () => {
this.$root.$emit('orientation-changed')
})
window.addEventListener('resize', () => {
this.$root.$emit('window-resized')
})
this.updateBrandings()
this.customLogo = await this.$store.dispatch('user/getCustomLogo')
},
methods: {
...mapActions('user', [
'forwardHome',
'fetchAuthToken'
]),
layoutResized () {
this.$refs.call.fitMedia()
},
pinMenu () {
this.menuPinned = !this.menuPinned
if (this.menuPinned === false) {
this.menuMinimized = true
}
},
minimizeMenu () {
if (!this.menuPinned) {
this.menuMinimized = true
}
this.layoutResized()
},
maximizeMenu () {
if (!this.menuPinned) {
this.menuMinimized = false
}
this.layoutResized()
},
showSendFax () {
this.faxDialog = true
},
hideSendFax () {
this.faxDialog = false
},
startCall (localMedia) {
if (this.callNumberInput !== '' && this.callNumberInput !== null) {
this.$store.dispatch('call/start', localMedia)
}
},
acceptCall (localMedia) {
this.$store.dispatch('call/accept', localMedia)
},
closeCall () {
this.$store.commit('call/inputNumber')
},
endCall () {
this.$store.dispatch('call/end')
},
toggleMicrophone () {
this.$store.dispatch('call/toggleMicrophone')
},
toggleCamera () {
this.$store.dispatch('call/toggleCamera')
},
toggleRemoteVolume () {
this.$store.dispatch('call/toggleRemoteVolume')
},
clickDialpad (value) {
this.$store.dispatch('call/sendDTMF', value)
},
toggleDialpad () {
this.$store.commit('call/toggleDialpad')
},
maximizeCall () {
if (this.isMobile) {
this.$router.push({ path: '/user/home' })
} else {
this.$store.commit('call/maximize')
}
},
minimizeCall () {
this.$store.commit('call/minimize')
},
leftBreakpoint (enabled) {
this.mobileMenu = !enabled
},
toggleMenu () {
this.menuMinimized = !this.menuMinimized
},
sideStateLeft () {
return this.sideStates.left
},
updateBrandings () {
const primaryColor = this.resellerBranding?.csc_color_primary || this.defaultBranding?.primaryColor
const secondaryColor = this.resellerBranding?.csc_color_secondary || this.defaultBranding?.secondaryColor
if (primaryColor) {
colors.setBrand('primary', primaryColor)
}
if (secondaryColor) {
colors.setBrand('secondary', secondaryColor)
}
},
async showQrDialog () {
await this.fetchAuthToken()
this.$q.dialog({
component: CscDialogQrCode,
parent: this
})
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
.app-badge
width: 60% !important
.pin-menu-button
height: $header-height
#csc-header-toolbar
background-color $secondary
#csc-main-logo
height 52px
width auto
right 12px
top 4px
position absolute
.csc-user-menu-button
margin-left 0
margin-right 0.2rem
padding 0.2rem
.on-left
margin 0
.csc-username
padding-left 3px
font-weight normal
color rgba(255,255,255,0.6)
.page.page-call-active
padding-bottom 120px
#main-menu
padding 0
.q-item
padding-top $flex-gutter-xs * 1.4
padding-bottom $flex-gutter-xs * 1.4
.q-item-side-left
min-width auto
.q-item-main
margin-left $flex-gutter-sm
.q-icon
color $main-menu-icon-color
.q-item-label
color $main-menu-title-color
font-weight bold
white-space nowrap
.q-item-sublabel
color $main-menu-subtitle-color
.q-item:hover
background-color $main-menu-item-hover-background
.q-item.router-link-active
.q-icon
color $main-menu-icon-active-color
.q-item-label
color $main-menu-title-active-color
font-weight bold
.q-item-sublabel
color $main-menu-subtitle-active-color
background-color transparent
#user-login-as
display inline-block
text-transform none
#user-login-as:after
content " "
white-space pre
#user-name
font-weight bold
.q-card
margin 15px
margin-left 0
margin-right 0
.q-card.page
padding 0
margin 0
.q-if-control.q-if-control-before.q-icon,
.q-if-control.q-if-control-before.q-icon:before
font-size 24px
.csc-toolbar-btn-popover
.q-item-main.q-item-section
margin-left 0
.q-toolbar
.csc-toolbar-btn.q-btn
padding-left 8px
padding-right 8px
.csc-toolbar-btn-right
.csc-toolbar-btn-icon
margin-right 8px
.csc-layout-call-active
padding-bottom 152px
#csc-header
position fixed
top 0
left $layout-aside-left-width
right 0
height $header-height
overflow hidden
z-index 100
background-color $secondary
.csc-header-content
position absolute
top 0
right 0
left 0
bottom 0
padding $logo-margin
background linear-gradient(to bottom, rgba(21,29,48,0.5) 0%,rgba(21,29,48,0) 75%,rgba(21,29,48,0) 100%)
#csc-header.csc-header-full
left 0
#csc-user-menu
cursor pointer
display inline-block
.csc-username
padding-left 4px
.csc-toggle-menu
cursor pointer
position absolute
top $logo-margin
right $logo-margin
display flex
justify-content center
align-items center
width 40px
height 40px
.q-icon
display flex
position relative
font-size 24px
.layout-aside-left
padding-top $header-height
.csc-menu-minimized
.layout-aside-left
width $main-menu-minimized-width
.q-item-main
display none
.csc-toggle-menu
width $main-menu-minimized-width
left 0
#main-menu
.q-collapsible
.q-collapsible-sub-item
padding 0
#csc-header
left $main-menu-minimized-width
.mobile
.layout-aside-left
width auto
right 0
.csc-subitem-label
padding-left 20px
.csc-toolbar-btn-popover
.q-collapsible-sub-item
padding 0 16px 0 16px
.csc-collapsible-menu
.q-icon
display none
#csc-default-logo
height 48px
#csc-custom-logo
min-width $logo-min-width
max-width $logo-max-width
max-height $logo-max-height
</style>