From b10b92a876eb185a88e751d028e69063c9117298 Mon Sep 17 00:00:00 2001
From: Shpuld Shpuldson <shpuld@shpposter.club>
Date: Tue, 14 Jan 2020 10:06:14 +0200
Subject: clean up code, fix prediction bug

---
 src/components/emoji_reactions/emoji_reactions.vue | 51 ++++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 src/components/emoji_reactions/emoji_reactions.vue

(limited to 'src/components/emoji_reactions/emoji_reactions.vue')

diff --git a/src/components/emoji_reactions/emoji_reactions.vue b/src/components/emoji_reactions/emoji_reactions.vue
new file mode 100644
index 00000000..d83f60b6
--- /dev/null
+++ b/src/components/emoji_reactions/emoji_reactions.vue
@@ -0,0 +1,51 @@
+<template>
+  <div class="emoji-reactions">
+    <button
+      v-for="(users, emoji) in emojiReactions"
+      :key="emoji"
+      class="emoji-reaction btn btn-default"
+      :class="{ 'picked-reaction': reactedWith(emoji) }"
+      @click="emojiOnClick(emoji, $event)"
+    >
+      <span v-if="users">{{ users.length }}</span>
+      <span>{{ emoji }}</span>
+    </button>
+  </div>
+</template>
+
+<script src="./emoji_reactions.js" ></script>
+<style lang="scss">
+@import '../../_variables.scss';
+
+.emoji-reactions {
+  display: flex;
+  margin-top: 0.25em;
+  flex-wrap: wrap;
+}
+
+.emoji-reaction {
+  padding: 0 0.5em;
+  margin-right: 0.5em;
+  margin-top: 0.5em;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-sizing: border-box;
+  :first-child {
+    margin-right: 0.25em;
+  }
+  :last-child {
+    width: 1.5em;
+  }
+  &:focus {
+    outline: none;
+  }
+}
+
+.picked-reaction {
+  border: 1px solid var(--link, $fallback--link);
+  margin-left: -1px; // offset the border, can't use inset shadows either
+  margin-right: calc(0.5em - 1px);
+}
+
+</style>
-- 
cgit v1.2.3-70-g09d2


From a018ea622c4ae34fd204e840b20aba53f84cd051 Mon Sep 17 00:00:00 2001
From: Shpuld Shpuldson <shpuld@shpposter.club>
Date: Sun, 26 Jan 2020 15:45:12 +0200
Subject: change emoji reactions to use new format

---
 src/components/conversation/conversation.js        |  2 +-
 src/components/emoji_reactions/emoji_reactions.js  |  9 ++-
 src/components/emoji_reactions/emoji_reactions.vue | 12 ++--
 src/components/status/status.vue                   |  1 -
 src/modules/statuses.js                            | 66 +++++++++++++---------
 .../entity_normalizer/entity_normalizer.service.js |  1 +
 test/unit/specs/modules/statuses.spec.js           | 45 +++++++++++++++
 7 files changed, 99 insertions(+), 37 deletions(-)

(limited to 'src/components/emoji_reactions/emoji_reactions.vue')

diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index 7ff0ac08..45fb2bf6 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -150,7 +150,7 @@ const conversation = {
       if (!id) return
       this.highlight = id
       this.$store.dispatch('fetchFavsAndRepeats', id)
-      this.$store.dispatch('fetchEmojiReactions', id)
+      this.$store.dispatch('fetchEmojiReactionsBy', id)
     },
     getHighlight () {
       return this.isExpanded ? this.highlight : null
diff --git a/src/components/emoji_reactions/emoji_reactions.js b/src/components/emoji_reactions/emoji_reactions.js
index e81e6e25..b37cce3d 100644
--- a/src/components/emoji_reactions/emoji_reactions.js
+++ b/src/components/emoji_reactions/emoji_reactions.js
@@ -4,12 +4,17 @@ const EmojiReactions = {
   props: ['status'],
   computed: {
     emojiReactions () {
-      return this.status.emojiReactions
+      console.log(this.status.emoji_reactions)
+      return this.status.emoji_reactions
     }
   },
   methods: {
     reactedWith (emoji) {
-      return this.status.reactedWithEmoji.includes(emoji)
+      // return []
+      const user = this.$store.state.users.currentUser
+      const reaction = this.status.emoji_reactions.find(r => r.emoji === emoji)
+      console.log(reaction)
+      return reaction.accounts && reaction.accounts.find(u => u.id === user.id)
     },
     reactWith (emoji) {
       this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
diff --git a/src/components/emoji_reactions/emoji_reactions.vue b/src/components/emoji_reactions/emoji_reactions.vue
index d83f60b6..8a229240 100644
--- a/src/components/emoji_reactions/emoji_reactions.vue
+++ b/src/components/emoji_reactions/emoji_reactions.vue
@@ -1,14 +1,14 @@
 <template>
   <div class="emoji-reactions">
     <button
-      v-for="(users, emoji) in emojiReactions"
-      :key="emoji"
+      v-for="(reaction) in emojiReactions"
+      :key="reaction.emoji"
       class="emoji-reaction btn btn-default"
-      :class="{ 'picked-reaction': reactedWith(emoji) }"
-      @click="emojiOnClick(emoji, $event)"
+      :class="{ 'picked-reaction': reactedWith(reaction.emoji) }"
+      @click="emojiOnClick(reaction.emoji, $event)"
     >
-      <span v-if="users">{{ users.length }}</span>
-      <span>{{ emoji }}</span>
+      <span>{{ reaction.count }}</span>
+      <span>{{ reaction.emoji }}</span>
     </button>
   </div>
 </template>
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 87e8b5da..d5739304 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -355,7 +355,6 @@
           </transition>
 
           <EmojiReactions
-            v-if="isFocused"
             :status="status"
           />
 
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index dbae9d38..ea0c1749 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -10,10 +10,7 @@ import {
   first,
   last,
   isArray,
-  omitBy,
-  flow,
-  filter,
-  keys
+  omitBy
 } from 'lodash'
 import { set } from 'vue'
 import apiService from '../services/api/api.service.js'
@@ -534,33 +531,48 @@ export const mutations = {
     newStatus.fave_num = newStatus.favoritedBy.length
     newStatus.favorited = !!newStatus.favoritedBy.find(({ id }) => currentUser.id === id)
   },
-  addEmojiReactions (state, { id, emojiReactions, currentUser }) {
+  addEmojiReactionsBy (state, { id, emojiReactions, currentUser }) {
     const status = state.allStatusesObject[id]
-    set(status, 'emojiReactions', emojiReactions)
-    const reactedWithEmoji = flow(
-      keys,
-      filter(reaction => find(reaction, { id: currentUser.id }))
-    )(emojiReactions)
-    set(status, 'reactedWithEmoji', reactedWithEmoji)
+    set(status, 'emoji_reactions', emojiReactions)
   },
   addOwnReaction (state, { id, emoji, currentUser }) {
     const status = state.allStatusesObject[id]
-    status.emojiReactions = status.emojiReactions || {}
-    const listOfUsers = (status.emojiReactions && status.emojiReactions[emoji]) || []
-    const hasSelfAlready = !!find(listOfUsers, { id: currentUser.id })
-    if (!hasSelfAlready) {
-      set(status.emojiReactions, emoji, listOfUsers.concat([{ id: currentUser.id }]))
-      set(status, 'reactedWithEmoji', [...status.reactedWithEmoji, emoji])
+    const reactionIndex = findIndex(status.emoji_reactions, { emoji })
+    const reaction = status.emoji_reactions[reactionIndex] || { emoji, count: 0, accounts: [] }
+
+    const newReaction = {
+      ...reaction,
+      count: reaction.count + 1,
+      accounts: [
+        ...reaction.accounts,
+        currentUser
+      ]
+    }
+
+    // Update count of existing reaction if it exists, otherwise append at the end
+    if (reactionIndex >= 0) {
+      set(status.emoji_reactions, reactionIndex, newReaction)
+    } else {
+      set(status, 'emoji_reactions', [...status.emoji_reactions, newReaction])
     }
   },
   removeOwnReaction (state, { id, emoji, currentUser }) {
     const status = state.allStatusesObject[id]
-    const listOfUsers = status.emojiReactions[emoji] || []
-    const hasSelfAlready = !!find(listOfUsers, { id: currentUser.id })
-    if (hasSelfAlready) {
-      const newUsers = filter(listOfUsers, user => user.id !== currentUser.id)
-      set(status.emojiReactions, emoji, newUsers)
-      set(status, 'reactedWithEmoji', status.reactedWithEmoji.filter(e => e !== emoji))
+    const reactionIndex = findIndex(status.emoji_reactions, { emoji })
+    if (reactionIndex < 0) return
+
+    const reaction = status.emoji_reactions[reactionIndex]
+
+    const newReaction = {
+      ...reaction,
+      count: reaction.count - 1,
+      accounts: reaction.accounts.filter(acc => acc.id === currentUser.id)
+    }
+
+    if (newReaction.count > 0) {
+      set(status.emoji_reactions, reactionIndex, newReaction)
+    } else {
+      set(status, 'emoji_reactions', status.emoji_reactions.filter(r => r.emoji !== emoji))
     }
   },
   updateStatusWithPoll (state, { id, poll }) {
@@ -672,7 +684,7 @@ const statuses = {
       commit('addOwnReaction', { id, emoji, currentUser })
       rootState.api.backendInteractor.reactWithEmoji({ id, emoji }).then(
         status => {
-          dispatch('fetchEmojiReactions', id)
+          dispatch('fetchEmojiReactionsBy', id)
         }
       )
     },
@@ -681,14 +693,14 @@ const statuses = {
       commit('removeOwnReaction', { id, emoji, currentUser })
       rootState.api.backendInteractor.unreactWithEmoji({ id, emoji }).then(
         status => {
-          dispatch('fetchEmojiReactions', id)
+          dispatch('fetchEmojiReactionsBy', id)
         }
       )
     },
-    fetchEmojiReactions ({ rootState, commit }, id) {
+    fetchEmojiReactionsBy ({ rootState, commit }, id) {
       rootState.api.backendInteractor.fetchEmojiReactions({ id }).then(
         emojiReactions => {
-          commit('addEmojiReactions', { id, emojiReactions, currentUser: rootState.users.currentUser })
+          commit('addEmojiReactionsBy', { id, emojiReactions, currentUser: rootState.users.currentUser })
         }
       )
     },
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index ee007bee..03eaa5d7 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -233,6 +233,7 @@ export const parseStatus = (data) => {
     output.statusnet_html = addEmojis(data.content, data.emojis)
 
     output.tags = data.tags
+    output.emoji_reactions = [{ emoji: 'A', count: 5 }] // data.pleroma.emoji_reactions
 
     if (data.pleroma) {
       const { pleroma } = data
diff --git a/test/unit/specs/modules/statuses.spec.js b/test/unit/specs/modules/statuses.spec.js
index f794997b..e53aa388 100644
--- a/test/unit/specs/modules/statuses.spec.js
+++ b/test/unit/specs/modules/statuses.spec.js
@@ -241,6 +241,51 @@ describe('Statuses module', () => {
     })
   })
 
+  describe('emojiReactions', () => {
+    it('increments count in existing reaction', () => {
+      const state = defaultState()
+      const status = makeMockStatus({ id: '1' })
+      status.emoji_reactions = [ { emoji: '😂', count: 1, accounts: [] } ]
+
+      mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
+      mutations.addOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
+      expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(2)
+      expect(state.allStatusesObject['1'].emoji_reactions[0].accounts[0].id).to.eql('me')
+    })
+
+    it('adds a new reaction', () => {
+      const state = defaultState()
+      const status = makeMockStatus({ id: '1' })
+      status.emoji_reactions = []
+
+      mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
+      mutations.addOwnReaction(state, { id: '1', emoji: '😂', currentUser: { id: 'me' } })
+      expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(1)
+      expect(state.allStatusesObject['1'].emoji_reactions[0].accounts[0].id).to.eql('me')
+    })
+
+    it('decreases count in existing reaction', () => {
+      const state = defaultState()
+      const status = makeMockStatus({ id: '1' })
+      status.emoji_reactions = [ { emoji: '😂', count: 2, accounts: [{ id: 'me' }] } ]
+
+      mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
+      mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: {} })
+      expect(state.allStatusesObject['1'].emoji_reactions[0].count).to.eql(1)
+      expect(state.allStatusesObject['1'].emoji_reactions[0].accounts).to.eql([])
+    })
+
+    it('removes a reaction', () => {
+      const state = defaultState()
+      const status = makeMockStatus({ id: '1' })
+      status.emoji_reactions = [{ emoji: '😂', count: 1, accounts: [{ id: 'me' }] }]
+
+      mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
+      mutations.removeOwnReaction(state, { id: '1', emoji: '😂', currentUser: {} })
+      expect(state.allStatusesObject['1'].emoji_reactions.length).to.eql(0)
+    })
+  })
+
   describe('showNewStatuses', () => {
     it('resets the minId to the min of the visible statuses when adding new to visible statuses', () => {
       const state = defaultState()
-- 
cgit v1.2.3-70-g09d2


From 6afff4f8c205ec70d3694564c706f6a46a61db9e Mon Sep 17 00:00:00 2001
From: Shpuld Shpuldson <shpuld@shpposter.club>
Date: Tue, 28 Jan 2020 17:09:25 +0200
Subject: review changes

---
 src/components/emoji_reactions/emoji_reactions.vue          | 6 +++---
 src/components/react_button/react_button.js                 | 9 +--------
 src/components/react_button/react_button.vue                | 3 +--
 src/services/entity_normalizer/entity_normalizer.service.js | 2 +-
 4 files changed, 6 insertions(+), 14 deletions(-)

(limited to 'src/components/emoji_reactions/emoji_reactions.vue')

diff --git a/src/components/emoji_reactions/emoji_reactions.vue b/src/components/emoji_reactions/emoji_reactions.vue
index 8a229240..741fc11e 100644
--- a/src/components/emoji_reactions/emoji_reactions.vue
+++ b/src/components/emoji_reactions/emoji_reactions.vue
@@ -7,8 +7,8 @@
       :class="{ 'picked-reaction': reactedWith(reaction.emoji) }"
       @click="emojiOnClick(reaction.emoji, $event)"
     >
-      <span>{{ reaction.count }}</span>
       <span>{{ reaction.emoji }}</span>
+      <span>{{ reaction.count }}</span>
     </button>
   </div>
 </template>
@@ -31,10 +31,10 @@
   align-items: center;
   justify-content: center;
   box-sizing: border-box;
-  :first-child {
+  &:first-child {
     margin-right: 0.25em;
   }
-  :last-child {
+  &:last-child {
     width: 1.5em;
   }
   &:focus {
diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js
index d1a179bc..6fb2a780 100644
--- a/src/components/react_button/react_button.js
+++ b/src/components/react_button/react_button.js
@@ -4,7 +4,6 @@ const ReactButton = {
   props: ['status', 'loggedIn'],
   data () {
     return {
-      animated: false,
       showTooltip: false,
       filterWord: '',
       popperOptions: {
@@ -29,7 +28,7 @@ const ReactButton = {
   },
   computed: {
     commonEmojis () {
-      return ['💖', '😠', '👀', '😂', '🔥']
+      return ['❤️', '😠', '👀', '😂', '🔥']
     },
     emojis () {
       if (this.filterWord !== '') {
@@ -37,12 +36,6 @@ const ReactButton = {
       }
       return this.$store.state.instance.emoji || []
     },
-    classes () {
-      return {
-        'icon-smile': true,
-        'animate-spin': this.animated
-      }
-    },
     ...mapGetters(['mergedConfig'])
   }
 }
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index 7f1bc492..c925dd71 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -40,8 +40,7 @@
       @click.prevent="openReactionSelect"
     >
       <i
-        :class="classes"
-        class="button-icon add-reaction-button"
+        class="icon-smile button-icon add-reaction-button"
         :title="$t('tool_tip.add_reaction')"
       />
     </div>
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index f66d09ac..a3d0b782 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -233,7 +233,6 @@ export const parseStatus = (data) => {
     output.statusnet_html = addEmojis(data.content, data.emojis)
 
     output.tags = data.tags
-    output.emoji_reactions = data.pleroma.emoji_reactions
 
     if (data.pleroma) {
       const { pleroma } = data
@@ -243,6 +242,7 @@ export const parseStatus = (data) => {
       output.is_local = pleroma.local
       output.in_reply_to_screen_name = data.pleroma.in_reply_to_account_acct
       output.thread_muted = pleroma.thread_muted
+      output.emoji_reactions = pleroma.emoji_reactions
     } else {
       output.text = data.content
       output.summary = data.spoiler_text
-- 
cgit v1.2.3-70-g09d2

