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