Skip to content

Commit

Permalink
Moved lobby settings to the right sidebar
Browse files Browse the repository at this point in the history
Moved lobby settings to the settings tab in the right sidebar.
Added success and error notifications.
Added disabled states where missing while saving.

Signed-off-by: Vincent Petry <vincent@nextcloud.com>
  • Loading branch information
PVince81 committed Nov 11, 2020
1 parent 29e7d5d commit 3731483
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 91 deletions.
4 changes: 4 additions & 0 deletions src/components/RightSidebar/RightSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
:name="conversation.displayName" />
<LinkShareSettings
v-if="token && canFullModerate && showModerationOptions" />
<ModerationSettings
v-if="token && showModerationOptions" />
<div id="app-settings">
<div id="app-settings-header">
<button class="settings-button" @click="showSettings">
Expand All @@ -90,6 +92,7 @@ import MatterbridgeSettings from './Matterbridge/MatterbridgeSettings'
import isInLobby from '../../mixins/isInLobby'
import SetGuestUsername from '../SetGuestUsername'
import LinkShareSettings from './Settings/LinkShareSettings'
import ModerationSettings from './Settings/ModerationSettings'
import { EventBus } from '../../services/EventBus'

export default {
Expand All @@ -103,6 +106,7 @@ export default {
SetGuestUsername,
MatterbridgeSettings,
LinkShareSettings,
ModerationSettings,
},

mixins: [
Expand Down
195 changes: 195 additions & 0 deletions src/components/RightSidebar/Settings/ModerationSettings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
<!--
- @copyright Copyright (c) 2020 Vincent Petry <vincent@nextcloud.com>
-
- @author Vincent Petry <vincent@nextcloud.com>
-
- @license GNU AGPL version 3 or any later version
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<template>
<ul>
<ActionCheckbox
:checked="isReadOnly"
:disabled="isReadOnlyStateLoading"
@change="toggleReadOnly">
{{ t('spreed', 'Lock conversation') }}
</ActionCheckbox>
<ActionCheckbox
:disabled="isLobbyStateLoading"
:checked="hasLobbyEnabled"
@change="toggleLobby">
{{ t('spreed', 'Enable lobby') }}
</ActionCheckbox>
<ActionInput
v-if="hasLobbyEnabled"
icon="icon-calendar-dark"
type="datetime-local"
v-bind="dateTimePickerAttrs"
:value="lobbyTimer"
:disabled="isLobbyTimerLoading || isLobbyStateLoading"
@change="setLobbyTimer">
{{ t('spreed', 'Start time (optional)') }}
</ActionInput>
</ul>
</template>

<script>
import { showError, showSuccess } from '@nextcloud/dialogs'
import { CONVERSATION, WEBINAR } from '../../../constants'
import ActionCheckbox from '@nextcloud/vue/dist/Components/ActionCheckbox'
import ActionInput from '@nextcloud/vue/dist/Components/ActionInput'

export default {
name: 'ModerationSettings',

components: {
ActionCheckbox,
ActionInput,
},

data() {
return {
isReadOnlyStateLoading: false,
isLobbyStateLoading: false,
isLobbyTimerLoading: false,
}
},

computed: {
token() {
return this.$store.getters.getToken()
},

conversation() {
return this.$store.getters.conversation(this.token) || this.$store.getters.dummyConversation
},

isReadOnly() {
return this.conversation.readOnly === CONVERSATION.STATE.READ_ONLY
},

hasLobbyEnabled() {
return this.conversation.lobbyState === WEBINAR.LOBBY.NON_MODERATORS
},

lobbyTimer() {
// A timestamp of 0 means that there is no lobby, but it would be
// interpreted as the Unix epoch by the DateTimePicker.
if (this.conversation.lobbyTimer === 0) {
return undefined
}

// PHP timestamp is second-based; JavaScript timestamp is
// millisecond based.
return new Date(this.conversation.lobbyTimer * 1000)
},

dateTimePickerAttrs() {
return {
format: 'YYYY-MM-DD HH:mm',
firstDayOfWeek: window.firstDay + 1, // Provided by server
lang: {
days: window.dayNamesShort, // Provided by server
months: window.monthNamesShort, // Provided by server
},
// Do not update the value until the confirm button has been
// pressed. Otherwise it would not be possible to set a lobby
// for today, because as soon as the day is selected the lobby
// timer would be set, but as no time was set at that point the
// lobby timer would be set to today at 00:00, which would
// disable the lobby due to being in the past.
confirm: true,
}
},
},

methods: {
async toggleReadOnly() {
const newReadOnly = this.isReadOnly ? CONVERSATION.STATE.READ_WRITE : CONVERSATION.STATE.READ_ONLY
this.isReadOnlyStateLoading = true
try {
await this.$store.dispatch('setReadOnlyState', {
token: this.token,
readOnly: newReadOnly,
})
if (newReadOnly) {
showSuccess(t('spreed', 'You locked the conversation'))
} else {
showSuccess(t('spreed', 'You unlocked the conversation'))
}
} catch (e) {
if (newReadOnly) {
console.error('Error occurred when locking the conversation', e)
showError(t('spreed', 'Error occurred when locking the conversation'))
} else {
console.error('Error updating read-only state', e)
showError(t('spreed', 'Error occurred when unlocking the conversation'))
}
}
this.isReadOnlyStateLoading = false
},

async toggleLobby() {
const newLobbyState = this.conversation.lobbyState !== WEBINAR.LOBBY.NON_MODERATORS
this.isLobbyStateLoading = true
try {
await this.$store.dispatch('toggleLobby', {
token: this.token,
enableLobby: newLobbyState,
})
if (newLobbyState) {
showSuccess(t('spreed', 'You restricted the conversation to moderators'))
} else {
showSuccess(t('spreed', 'You opened the conversation to everyone'))
}
} catch (e) {
if (newLobbyState) {
console.error('Error occurred when restricting the conversation to moderator', e)
showError(t('spreed', 'Error occurred when restricting the conversation to moderator'))
} else {
console.error('Error occurred when opening the conversation to everyone', e)
showError(t('spreed', 'Error occurred when opening the conversation to everyone'))
}
}
this.isLobbyStateLoading = false
},

async setLobbyTimer(date) {
this.isLobbyTimerLoading = true

let timestamp = 0
if (date) {
// PHP timestamp is second-based; JavaScript timestamp is
// millisecond based.
timestamp = date.getTime() / 1000
}

try {
await this.$store.dispatch('setLobbyTimer', {
token: this.token,
timestamp: timestamp,
})
showSuccess(t('spreed', 'Start time has been updated'))
} catch (e) {
console.error('Error occurred while updating start time', e)
showError(t('spreed', 'Error occurred while updating start time'))
}

this.isLobbyTimerLoading = false
},
},
}
</script>
91 changes: 0 additions & 91 deletions src/components/TopBar/TopBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -90,27 +90,6 @@
</ActionButton>
<template
v-if="showModerationOptions">
<ActionCheckbox
:checked="isReadOnly"
:disabled="readOnlyStateLoading"
@change="toggleReadOnly">
{{ t('spreed', 'Lock conversation') }}
</ActionCheckbox>
<ActionCheckbox
:checked="hasLobbyEnabled"
@change="toggleLobby">
{{ t('spreed', 'Enable lobby') }}
</ActionCheckbox>
<ActionInput
v-if="hasLobbyEnabled"
icon="icon-calendar-dark"
type="datetime-local"
v-bind="dateTimePickerAttrs"
:value="lobbyTimer"
:disabled="lobbyTimerLoading"
@change="setLobbyTimer">
{{ t('spreed', 'Start time (optional)') }}
</ActionInput>
<ActionCheckbox
:checked="hasSIPEnabled"
@change="toggleSIPEnabled">
Expand Down Expand Up @@ -185,8 +164,6 @@ export default {
return {
showLayoutHint: false,
hintDismissed: false,
lobbyTimerLoading: false,
readOnlyStateLoading: false,
}
},

Expand Down Expand Up @@ -283,41 +260,7 @@ export default {
return this.conversation.type === CONVERSATION.TYPE.GROUP
|| this.conversation.type === CONVERSATION.TYPE.PUBLIC
},
hasLobbyEnabled() {
return this.conversation.lobbyState === WEBINAR.LOBBY.NON_MODERATORS
},
isReadOnly() {
return this.conversation.readOnly === CONVERSATION.STATE.READ_ONLY
},
lobbyTimer() {
// A timestamp of 0 means that there is no lobby, but it would be
// interpreted as the Unix epoch by the DateTimePicker.
if (this.conversation.lobbyTimer === 0) {
return undefined
}

// PHP timestamp is second-based; JavaScript timestamp is
// millisecond based.
return new Date(this.conversation.lobbyTimer * 1000)
},

dateTimePickerAttrs() {
return {
format: 'YYYY-MM-DD HH:mm',
firstDayOfWeek: window.firstDay + 1, // Provided by server
lang: {
days: window.dayNamesShort, // Provided by server
months: window.monthNamesShort, // Provided by server
},
// Do not update the value until the confirm button has been
// pressed. Otherwise it would not be possible to set a lobby
// for today, because as soon as the day is selected the lobby
// timer would be set, but as no time was set at that point the
// lobby timer would be set to today at 00:00, which would
// disable the lobby due to being in the past.
confirm: true,
}
},
hasSIPEnabled() {
return this.conversation.sipEnabled === WEBINAR.SIP.ENABLED
},
Expand Down Expand Up @@ -402,13 +345,6 @@ export default {
this.showLayoutHint = false
},

async toggleLobby() {
await this.$store.dispatch('toggleLobby', {
token: this.token,
enableLobby: this.conversation.lobbyState !== WEBINAR.LOBBY.NON_MODERATORS,
})
},

async toggleSIPEnabled(checked) {
try {
await this.$store.dispatch('setSIPEnabled', {
Expand All @@ -422,33 +358,6 @@ export default {
}
},

async setLobbyTimer(date) {
this.lobbyTimerLoading = true

let timestamp = 0
if (date) {
// PHP timestamp is second-based; JavaScript timestamp is
// millisecond based.
timestamp = date.getTime() / 1000
}

await this.$store.dispatch('setLobbyTimer', {
token: this.token,
timestamp: timestamp,
})

this.lobbyTimerLoading = false
},

async toggleReadOnly() {
this.readOnlyStateLoading = true
await this.$store.dispatch('setReadOnlyState', {
token: this.token,
readOnly: this.isReadOnly ? CONVERSATION.STATE.READ_WRITE : CONVERSATION.STATE.READ_ONLY,
})
this.readOnlyStateLoading = false
},

async handleCopyLink() {
try {
await this.$copyText(this.linkToConversation)
Expand Down

0 comments on commit 3731483

Please sign in to comment.