diff options
author | DorraJaouad <dorra.jaoued7@gmail.com> | 2023-07-20 15:28:16 +0200 |
---|---|---|
committer | Maksim Sukharev <antreesy.web@gmail.com> | 2023-08-03 08:28:11 +0200 |
commit | a89b55124fed73b748111e5064e3fbe9fa7776ea (patch) | |
tree | 61804164c8a233ea20acc847a18be2c9168a359d /src/components/RoomSelector.vue | |
parent | de304d1e3971e248bb6ed7705f9bfa320bdc4055 (diff) |
Move RoomSelector.vue to src/components
Signed-off-by: DorraJaouad <dorra.jaoued7@gmail.com>
Diffstat (limited to 'src/components/RoomSelector.vue')
-rw-r--r-- | src/components/RoomSelector.vue | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/src/components/RoomSelector.vue b/src/components/RoomSelector.vue new file mode 100644 index 000000000..a2b5630e0 --- /dev/null +++ b/src/components/RoomSelector.vue @@ -0,0 +1,296 @@ +<!-- + - @copyright Copyright (c) 2019 Julius Härtl <jus@bitgrid.net> + - + - @author Julius Härtl <jus@bitgrid.net> + - + - @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> + <NcModal size="normal" + :container="container" + @close="close"> + <div id="modal-inner" class="talk-modal" :class="{ 'icon-loading': loading }"> + <div id="modal-content"> + <h2> + {{ dialogTitle }} + </h2> + <p v-if="dialogSubtitle" class="subtitle"> + {{ dialogSubtitle }} + </p> + <NcTextField :value.sync="searchText" + trailing-button-icon="close" + class="search-form" + :label="t('spreed', 'Search conversations or users')" + :show-trailing-button="searchText !==''" + @trailing-button-click="clearText"> + <Magnify :size="16" /> + </NcTextField> + <div id="room-list"> + <ul v-if="!loading && availableRooms.length > 0"> + <li v-for="room in availableRooms" + :key="room.token" + :class="{selected: selectedRoom === room.token }" + @click="selectedRoom=room.token"> + <ConversationIcon :item="room" + :hide-call="true" + :hide-favorite="false" + :disable-menu="true" /> + <span>{{ room.displayName }}</span> + </li> + </ul> + <div v-else-if="!loading" class="no-match-message"> + <h2 class="no-match-title"> + {{ noMatchFoundTitle }} + </h2> + <p v-if="noMatchFoundSubtitle" class="subtitle"> + {{ noMatchFoundSubtitle }} + </p> + </div> + </div> + <div id="modal-buttons"> + <NcButton v-if="!loading && availableRooms.length > 0" + type="primary" + :disabled="!selectedRoom" + @click="select"> + {{ t('spreed', 'Select conversation') }} + </NcButton> + </div> + </div> + </div> + </NcModal> +</template> + +<script> +import Magnify from 'vue-material-design-icons/Magnify.vue' + +import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' +import NcModal from '@nextcloud/vue/dist/Components/NcModal.js' +import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' + +import ConversationIcon from './ConversationIcon.vue' + +import { CONVERSATION } from '../constants.js' +import { searchListedConversations, fetchConversations } from '../services/conversationsService.js' + +export default { + name: 'RoomSelector', + components: { + ConversationIcon, + NcModal, + NcButton, + NcTextField, + Magnify, + }, + props: { + container: { + type: String, + default: undefined, + }, + + dialogTitle: { + type: String, + default: t('spreed', 'Link to a conversation'), + }, + + dialogSubtitle: { + type: String, + default: '', + }, + + /** + * Whether to only show conversations to which + * the user can post messages. + */ + showPostableOnly: { + type: Boolean, + default: false, + }, + + listOpenConversations: { + type: Boolean, + default: false, + }, + }, + emits: ['close', 'select'], + data() { + return { + rooms: [], + selectedRoom: null, + currentRoom: null, + searchText: '', + loading: true, + } + }, + computed: { + availableRooms() { + const roomsTemp = this.rooms.filter((room) => { + return room.type !== CONVERSATION.TYPE.CHANGELOG + && (!this.currentRoom || this.currentRoom !== room.token) + && (!this.showPostableOnly || room.readOnly === CONVERSATION.STATE.READ_WRITE) + && room.objectType !== 'file' + && room.objectType !== 'share:password' + }) + if (!this.searchText) { + return roomsTemp + } else { + return roomsTemp.filter(room => room.displayName.toLowerCase().includes(this.searchText.toLowerCase())) + } + }, + + noMatchFoundTitle() { + return this.listOpenConversations + ? t('spreed', 'No open conversations found') + : t('spreed', 'No conversations found') + }, + + noMatchFoundSubtitle() { + return this.listOpenConversations + ? t('spreed', 'Either there are no open conversations or you joined all of them.') + : t('spreed', 'Check spelling or use complete words.') + }, + }, + beforeMount() { + this.fetchRooms() + const $store = OCA.Talk?.instance?.$store + if ($store) { + this.currentRoom = $store.getters.getToken() + } + }, + methods: { + async fetchRooms() { + const response = this.listOpenConversations + ? await searchListedConversations({ searchText: '' }, {}) + : await fetchConversations({}) + + this.rooms = response.data.ocs.data.sort(this.sortConversations) + this.loading = false + }, + sortConversations(conversation1, conversation2) { + if (conversation1.isFavorite !== conversation2.isFavorite) { + return conversation1.isFavorite ? -1 : 1 + } + + return conversation2.lastActivity - conversation1.lastActivity + }, + + clearText() { + this.searchText = '' + }, + + close() { + // FIXME: should not emit on $root but on itself + this.$root.$emit('close') + this.$emit('close') + }, + select() { + this.$root.$emit('select', this.selectedRoom) + this.$emit('select', this.selectedRoom) + }, + }, +} +</script> + +<style lang="scss" scoped> + +:deep(.modal-container) { + height: 700px; +} + +.talk-modal { + height: 80vh; +} + +#modal-inner { + width: 100%; + padding: 16px; + margin: 0 auto; + position: relative; + display: flex; + align-items: center; + justify-content: center; + height: 100%; + box-sizing: border-box; + h2 { + margin-bottom: 4px; + } +} + +#modal-content { + position: absolute; + width: calc(100% - 40px); + height: calc(100% - 40px); + display: flex; + flex-direction: column; +} + +#room-list { + overflow-y: auto; + flex: 0 1 auto; + height: 100%; +} + +.no-match-message{ + padding: 40px 0; + text-align: center; + +} + +.no-match-title{ + font-weight: normal; +} + +li { + padding: 6px; + border: 1px solid transparent; + display: flex; + + &:hover, + &:focus { + background-color: var(--color-background-dark); + border-radius: var(--border-radius-pill); + } + + &.selected { + background-color: var(--color-primary-element-light); + border-radius: var(--border-radius-pill); + } + + & > span { + padding: 5px 5px 5px 10px; + vertical-align: middle; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } +} + +#modal-buttons { + overflow: hidden; + flex-shrink: 0; + margin-left: auto; +} + +.subtitle { + color: var(--color-text-maxcontrast); + margin-bottom: 8px; +} + +.search-form { + margin-bottom: 10px; +} +</style> |