From 0153bb98e2363b59a0e039900b6fc0d4371bd723 Mon Sep 17 00:00:00 2001 From: Mary Kate <mk@marykatefain.com> Date: Thu, 10 Sep 2020 15:27:41 -0500 Subject: [PATCH] chat show style cleanup and basic message moderation functions --- src/api/chat.js | 7 +- src/components/ChatMessage/index.vue | 145 ++++++++++++------ src/lang/en.js | 3 + src/store/modules/chat.js | 6 +- src/views/chats/show.vue | 215 ++++++++------------------- 5 files changed, 177 insertions(+), 199 deletions(-) diff --git a/src/api/chat.js b/src/api/chat.js index 7a3bd66c..e37b6a8a 100644 --- a/src/api/chat.js +++ b/src/api/chat.js @@ -2,10 +2,13 @@ import request from '@/utils/request' import { getToken } from '@/utils/auth' import { baseName } from './utils' -export async function deleteChatMessage(id, message_id, authHost, token) { +export async function deleteChatMessage(chat_id, message_id, authHost, token) { + console.log(chat_id) + console.log(message_id) + return await request({ baseURL: baseName(authHost), - url: `/api/pleroma/admin/chats/{id}/messages/${message_id}`, + url: `/api/pleroma/admin/chats/${chat_id}/messages/${message_id}`, method: 'delete', headers: authHeaders(token) }) diff --git a/src/components/ChatMessage/index.vue b/src/components/ChatMessage/index.vue index 400ec205..2e6a05cb 100644 --- a/src/components/ChatMessage/index.vue +++ b/src/components/ChatMessage/index.vue @@ -1,28 +1,57 @@ <template> - <el-card v-if="!message.deleted" class="message-card" @click.native="handleRouteChange()"> + <el-card v-if="!message.deleted" class="message-card"> <div slot="header"> <div class="message-header"> - <div class="chat-particiants-sender"> - <img v-if="propertyExists(author, 'avatar')" :src="author.avatar" class="chat-avatar-img"> - <span v-if="propertyExists(author, 'username')" class="chat-account-name">{{ author.username }}</span> - <span v-else> - <span v-if="propertyExists(author, 'username')" class="chat-account-name"> - {{ author.username }} - </span> - <span v-else class="chat-account-name deactivated">({{ $t('users.invalidNickname') }})</span> - </span> + <div class="message-meta"> + <router-link + v-if="propertyExists(author, 'id')" + :to="{ name: 'UsersShow', params: { id: author.id }}" + class="router-link" + @click.native.stop> + <div class="message-author"> + <img v-if="propertyExists(author, 'avatar')" :src="author.avatar" class="message-author-avatar-img"> + <span v-if="propertyExists(author, 'username')" class="message-author-name">{{ author.username }}</span> + <span v-else> + <span v-if="propertyExists(author, 'username')" class="message-author-name"> + {{ author.username }} + </span> + <span v-else class="message-author-name deactivated">({{ $t('users.invalidNickname') }})</span> + </span> + </div> + </router-link> + <span class="message-timestamp">{{ parseTimestamp(message.created_at) }}</span> + </div> + <div class="message-actions"> + <el-dropdown trigger="click" @click.native.stop> + <el-button plain size="small" icon="el-icon-edit" class="status-actions-button"> + {{ $t('reports.messageModeration') }}<i class="el-icon-arrow-down el-icon--right"/> + </el-button> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item + @click.native="deleteMessage()"> + {{ $t('reports.deleteMessage') }} + </el-dropdown-item> + <el-dropdown-item + @click.native="handleRouteChange()"> + {{ $t('users.moderateUser') }} + </el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> </div> - {{ message.created_at }} </div> </div> <div class="message-body"> - {{ message.content }} + <span class="message-content" v-html="message.content"/> + <div v-if="message.attachment" class="image"> + <img :src="message.attachment.preview_url"> + </div> </div> </el-card> </template> <script> +import moment from 'moment' export default { name: 'ChatMessage', @@ -48,15 +77,41 @@ export default { methods: { propertyExists(account, property) { return account[property] + }, + parseTimestamp(timestamp) { + return moment(timestamp).format('YYYY-MM-DD HH:mm') + }, + deleteMessage() { + this.$confirm('Are you sure you want to delete this message?', 'Warning', { + confirmButtonText: 'OK', + cancelButtonText: 'Cancel', + type: 'warning' + }).then(() => { + this.$store.dispatch('DeleteMessage', { + chat_id: this.message.chat_id, + message_id: this.message.id + }) + this.$message({ + type: 'success', + message: 'Delete completed' + }) + }).catch(() => { + this.$message({ + type: 'info', + message: 'Delete canceled' + }) + }) + }, + handleRouteChange() { + this.$router.push({ name: 'UsersShow', params: { id: this.author.id }}) } } } </script> <style rel='stylesheet/scss' lang='scss'> -.chat-card { +.message-card { margin-bottom: 10px; - cursor: pointer; .account { line-height: 26px; font-size: 13px; @@ -82,61 +137,55 @@ export default { .show-more-button { margin-left: 5px; } - .chat-account { + .message-author { display: flex; align-items: center; } - .chat-avatar-img { + .message-author-avatar-img { display: inline-block; width: 15px; height: 15px; margin-right: 5px; } - .chat-account-name { + .message-author-name { display: inline-block; margin: 0; font-size: 15px; font-weight: 500; } - .chat-body { + .message-body { display: flex; flex-direction: column; } - .chat-card-header { + .message-card-header { display: flex; align-items: center; } - .chat-checkbox { - margin-right: 7px; - } + .chat-content { font-size: 15px; line-height: 26px; } - .chat-created-at { + .message-timestamp { font-size: 13px; color: #606266; + margin-left: 20px; } - .chat-deleted { + .message-deleted { font-style: italic; margin-top: 3px; } - .chat-footer { - display: flex; - justify-content: space-between; - align-items: center; - } - .chat-header { + .message-header { display: flex; justify-content: space-between; align-items: center; + .message-meta { + display: flex; + justify-content: flex-start; + align-items: flex-end; + } } - .chat-tags { - display: inline; - } - .chat-without-content { - font-style: italic; - } + } @media only screen and (max-width:480px) { @@ -146,35 +195,39 @@ export default { .el-message-box { width: 80%; } - .chat-card { + .message-card { .el-card__header { padding: 10px 17px; } .el-tag { margin: 3px 0; } - .chat-account-container { + .message-author-container { margin-bottom: 5px; } - .chat-actions-button { + .message-action-buttons { margin: 3px 0 3px; } - .chat-actions { + .message-actions { width: 100%; display: flex; flex-wrap: wrap; justify-content: space-between; } - .chat-footer { - flex-direction: column; - align-items: flex-start; - margin-top: 10px; - } - .chat-header { + .message-header { display: flex; flex-direction: column; align-items: flex-start; } } + .message-actions-button { + margin: 3px 0 3px; + } + .message-actions { + width: 100%; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + } } </style> diff --git a/src/lang/en.js b/src/lang/en.js index 76f8b879..bd60ce52 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -382,6 +382,7 @@ export default { unlisted: 'Make status unlisted', sensitive: 'Sensitive', deleteStatus: 'Delete status', + deleteMessage: 'Delete message', reportOn: 'Report on', reportsOn: 'Reports on', id: 'ID', @@ -391,6 +392,8 @@ export default { content: 'Content', reportedStatus: 'Reported status', statusDeleted: 'This status has been deleted', + messageDeleted: 'This message has been deleted', + messageModeration: 'Message options', leaveNote: 'Leave a note', postNote: 'Send', deleteNote: 'Delete', diff --git a/src/store/modules/chat.js b/src/store/modules/chat.js index 5a78093f..29c993fc 100644 --- a/src/store/modules/chat.js +++ b/src/store/modules/chat.js @@ -1,4 +1,4 @@ -import { fetchChat, fetchChatMessages } from '@/api/chat' +import { fetchChat, fetchChatMessages, deleteChatMessage } from '@/api/chat' const chat = { state: { @@ -30,6 +30,10 @@ const chat = { const chat = await fetchChatMessages(id, getters.authHost, getters.token) commit('SET_CHAT_MESSAGES', chat.data) commit('SET_LOADING', false) + }, + async DeleteMessage({ commit, dispatch, getters, state }, params) { + await deleteChatMessage(params.chat_id, params.message_id, getters.authHost, getters.token) + dispatch('FetchChatMessages', params.chat_id) } } } diff --git a/src/views/chats/show.vue b/src/views/chats/show.vue index 5ca80032..74603fa9 100644 --- a/src/views/chats/show.vue +++ b/src/views/chats/show.vue @@ -1,49 +1,47 @@ <template> <div v-if="!loading" class="chat-show-container"> - <header v-if="isDesktop || isTablet" class="user-page-header"> - <div class="avatar-name-container"/> + <header v-if="isDesktop || isTablet" class="chat-page-header"> + <h1> + {{ $t('chats.chatHistory') }}: + </h1> + <div class="chat-card-participants"> + <div class="chat-particiants-sender"> + <div class="avatar-name-container"> + <el-avatar v-if="propertyExists(chat.sender, 'avatar')" :src="chat.sender.avatar" size="large" /> + <h1 v-if="propertyExists(chat.sender, 'display_name')" class="particiant-display-name">{{ chat.sender.display_name }}</h1> + <h1 v-else class="particiant-display-name invalid">({{ $t('users.invalidNickname') }})</h1> + <a v-if="propertyExists(chat.sender, 'url')" :href="chat.sender.url" target="_blank"> + <i :title="$t('userProfile.openAccountInInstance')" class="el-icon-top-right"/> + </a> + </div> + </div> + <div class="chat-particiants-receiver"> + <div class="avatar-name-container"> + <el-avatar v-if="propertyExists(chat.receiver, 'avatar')" :src="chat.receiver.avatar" size="large" /> + <h1 v-if="propertyExists(chat.receiver, 'display_name')" class="particiant-display-name">{{ chat.receiver.display_name }}</h1> + <h1 v-else class="particiant-display-name invalid">({{ $t('users.invalidNickname') }})</h1> + <a v-if="propertyExists(chat.receiver, 'url')" :href="chat.receiver.url" target="_blank"> + <i :title="$t('userProfile.openAccountInInstance')" class="el-icon-top-right"/> + </a> + </div> + </div> + </div> </header> <div v-if="isMobile" class="chat-page-header-container"> - <header class="user-page-header"> + <header class="chat-page-header"> <div class="avatar-name-container"/> <reboot-button/> </header> </div> - <div class="chat-container"> - <div class="chat-card-header"> - <h1> - {{ $t('chats.chatHistory') }} - </h1> - <div class="chat-card-participants"> - <div class="chat-particiants-sender"> - <img v-if="propertyExists(chat.sender, 'avatar')" :src="chat.sender.avatar" class="chat-avatar-img"> - <span v-if="propertyExists(chat.sender, 'username')" class="chat-account-name">{{ chat.sender.username }}</span> - <span v-else> - <span v-if="propertyExists(chat.sender, 'username')" class="chat-account-name"> - {{ chat.sender.username }} - </span> - <span v-else class="chat-account-name deactivated">({{ $t('users.invalidNickname') }})</span> - </span> - </div> - <div class="chat-particiants-receiver"> - <img v-if="propertyExists(chat.receiver, 'avatar')" :src="chat.receiver.avatar" class="chat-avatar-img"> - <span v-if="propertyExists(chat.receiver, 'username')" class="chat-account-name">{{ chat.receiver.username }}</span> - <span v-else> - <span v-if="propertyExists(chat.receiver, 'username')" class="chat-account-name"> - {{ chat.receiver.username }} - </span> - <span v-else class="chat-account-name deactivated">({{ $t('users.invalidNickname') }})</span> - </span> - </div> - </div> - </div> + <div class="chat-messages-container"> - <div class="chat-messages"> - <div v-for="message in chatMessages" :key="message.id" class=""> + <el-timeline v-if="!loading" class="messages"> + <el-timeline-item v-for="message in chatMessages" :key="message.id"> <chat-message :message="message" :author="getAuthor(message.account_id)"/> - </div> - </div> + </el-timeline-item> + <p v-if="chatMessages.length === 0" class="no-statuses">{{ $t('userProfile.noStatuses') }}</p> + </el-timeline> </div> </div> @@ -101,7 +99,20 @@ export default { </script> <style rel='stylesheet/scss' lang='scss'> +.chat-page-header { + display: flex; + margin: 22px 15px 22px 20px; + padding: 0; + h1 { + display: inline + } +} +.chat-card-participants { + display: flex; + margin: 0 20px; +} .avatar-name-container { + padding-right: 20px; display: flex; align-items: center; .el-icon-top-right { @@ -109,47 +120,29 @@ export default { line-height: 36px; color: #606266; } + .particiant-display-name { + padding-left: 5px; + } } -.avatar-name-header { - display: flex; - height: 40px; - align-items: center; +.el-avatar h1 { + padding-right: 5px; } -.invalid { - color: gray; +.chat-messages-container { + display: flex; + flex-direction: column; + max-width: 1000px; + .el-timeline-item { + margin-left: 20px; + } } .no-chats { margin-left: 28px; color: #606266; } -.password-reset-token { - margin: 0 0 14px 0; -} -.password-reset-token-dialog { - width: 50% -} .reboot-button { padding: 10px; margin-left: 6px; } - -.recent-chats-container-show { - display: flex; - flex-direction: column; - .el-timeline-item { - margin-left: 20px; - } - .recent-chats { - margin-left: 20px; - } - .show-private-chats { - margin-left: 20px; - margin-bottom: 20px; - } -} -.reset-password-link { - text-decoration: underline; -} .router-link { text-decoration: none; } @@ -159,103 +152,25 @@ export default { .chats { padding: 0 20px 0 0; } -.user-page-header { - display: flex; - justify-content: space-between; - margin: 22px 15px 22px 20px; - padding: 0; - align-items: center; - h1 { - display: inline; - margin: 0 0 0 10px; - } -} @media only screen and (min-width: 1824px) { - .chat-show-container { - max-width: 1824px; - margin: auto; - } + } @media only screen and (max-width:480px) { + .chat-page-header { + padding: 0; + margin: 7px 15px 15px 10px; + } .avatar-name-container { margin-bottom: 10px; } + .el-timeline-item__wrapper { padding-left: 18px; } - .left-header-container { - align-items: center; - display: flex; - justify-content: space-between; - } - .password-reset-token-dialog { - width: 85% - } - .recent-chats { - margin: 20px 10px 15px 10px; - } - .recent-chats-container-show { - width: 100%; - margin: 0 0 0 10px; - .el-timeline-item { - margin-left: 0; - } - .recent-chats { - margin-left: 0; - } - .show-private-chats { - margin: 0 10px 20px 0; - } - } - .chat-card { - .el-card__body { - padding: 15px; - } - } - .chat-container { - margin: 0 10px; - } - .chats { - padding-right: 10px; - margin-left: 0; - .el-timeline-item__wrapper { - margin-right: 10px; - } - } - .user-page-header { - padding: 0; - margin: 7px 15px 5px 10px; - } - .chat-page-header-container { - width: 100%; - .el-dropdown { - width: stretch; - margin: 0 10px 15px 10px; - } - } } @media only screen and (max-width:801px) and (min-width: 481px) { - .recent-chats-container-show { - width: 97%; - margin: 0 20px; - .el-timeline-item { - margin-left: 2px; - } - .recent-chats { - margin: 20px 10px 15px 0; - } - .show-private-chats { - margin: 0 10px 20px 0; - } - } - .show-private-chats { - margin: 0 10px 20px 0; - } - .user-page-header { - padding: 0; - margin: 7px 15px 20px 20px; - } + } </style> -- GitLab