From cd0a7afa06cafc93510286d35a60e9e40ead36bf Mon Sep 17 00:00:00 2001
From: taehoon <th.dev91@gmail.com>
Date: Wed, 24 Apr 2019 13:56:53 -0400
Subject: [PATCH] remove pinned timeline, instead, use simple entity of user
 object

---
 src/components/timeline/timeline.js           |  3 +--
 src/components/timeline/timeline.vue          |  3 +--
 src/components/user_profile/user_profile.js   | 13 +++++++------
 src/components/user_profile/user_profile.vue  | 19 ++++++++++---------
 src/modules/statuses.js                       | 14 ++++++++++----
 src/modules/users.js                          |  3 +++
 .../backend_interactor_service.js             |  2 ++
 .../entity_normalizer.service.js              |  2 ++
 8 files changed, 36 insertions(+), 23 deletions(-)

diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index 953b4a06..19d9a9ac 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -11,8 +11,7 @@ const Timeline = {
     'userId',
     'tag',
     'embedded',
-    'count',
-    'noLoadMore'
+    'count'
   ],
   data () {
     return {
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index 870fe4f5..e6a8d458 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -21,12 +21,11 @@
           class="status-fadein"
           :key="status.id"
           :statusoid="status"
-          :pinned="timelineName === 'pinned'"
           :collapsable="true"
         />
       </div>
     </div>
-    <div :class="classes.footer" v-if="!noLoadMore">
+    <div :class="classes.footer">
       <div v-if="count===0" class="new-status-notification text-center panel-footer faint">
         {{$t('timeline.no_statuses')}}
       </div>
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 71a88dcf..0071fa89 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -2,6 +2,7 @@ import get from 'lodash/get'
 import UserCard from '../user_card/user_card.vue'
 import FollowCard from '../follow_card/follow_card.vue'
 import Timeline from '../timeline/timeline.vue'
+import Conversation from '../conversation/conversation.vue'
 import ModerationTools from '../moderation_tools/moderation_tools.vue'
 import List from '../list/list.vue'
 import withLoadMore from '../../hocs/with_load_more/with_load_more'
@@ -40,9 +41,6 @@ const UserProfile = {
     timeline () {
       return this.$store.state.statuses.timelines.user
     },
-    pinned () {
-      return this.$store.state.statuses.timelines.pinned
-    },
     favorites () {
       return this.$store.state.statuses.timelines.favorites
     },
@@ -56,6 +54,9 @@ const UserProfile = {
     user () {
       return this.$store.getters.findUser(this.userId)
     },
+    pinnedStatuses () {
+      return this.user.pinnedStatusIds.map(id => this.$store.state.statuses.allStatusesObject[id])
+    },
     isExternal () {
       return this.$route.name === 'external-user-profile'
     },
@@ -94,15 +95,14 @@ const UserProfile = {
     fetchTimelines () {
       const userId = this.userId
       this.$store.dispatch('startFetchingTimeline', { timeline: 'user', userId })
-      this.$store.dispatch('startFetchingTimeline', { timeline: 'pinned', userId })
       this.$store.dispatch('startFetchingTimeline', { timeline: 'media', userId })
       if (this.isUs) {
         this.$store.dispatch('startFetchingTimeline', { timeline: 'favorites', userId })
       }
+      this.$store.dispatch('fetchPinnedStatuses', userId)
     },
     cleanUp () {
       this.$store.dispatch('stopFetching', 'user')
-      this.$store.dispatch('stopFetching', 'pinned')
       this.$store.dispatch('stopFetching', 'favorites')
       this.$store.dispatch('stopFetching', 'media')
       this.$store.commit('clearTimeline', { timeline: 'user' })
@@ -133,7 +133,8 @@ const UserProfile = {
     FollowerList,
     FriendList,
     ModerationTools,
-    FollowCard
+    FollowCard,
+    Conversation
   }
 }
 
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index caf297c6..46561e2a 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -4,15 +4,16 @@
     <UserCard :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/>
     <tab-switcher :renderOnlyFocused="true" ref="tabSwitcher">
       <div :label="$t('user_card.statuses')" :disabled="!user.statuses_count">
-        <Timeline
-          :count="user.statuses_count"
-          :embedded="true"
-          :title="$t('user_profile.timeline_title')"
-          :timeline="pinned"
-          :timeline-name="'pinned'"
-          :user-id="userId"
-          :no-load-more="true"
-        />
+        <div class="timeline">
+          <Conversation
+            v-for="status in pinnedStatuses"
+            class="status-fadein"
+            :key="status.id"
+            :statusoid="status"
+            :pinned="true"
+            :collapsable="true"
+          />
+        </div>
         <Timeline
           :count="user.statuses_count"
           :embedded="true"
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index b93f9cb5..3b3ae9e3 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -1,4 +1,4 @@
-import { remove, slice, each, findIndex, find, maxBy, minBy, merge, first, last, isArray, omitBy } from 'lodash'
+import { remove, slice, each, findIndex, find, maxBy, minBy, merge, first, last, isArray, omitBy, map } from 'lodash'
 import { set } from 'vue'
 import apiService from '../services/api/api.service.js'
 // import parse from '../services/status_parser/status_parser.js'
@@ -47,8 +47,7 @@ export const defaultState = () => ({
     publicAndExternal: emptyTl(),
     friends: emptyTl(),
     tag: emptyTl(),
-    dms: emptyTl(),
-    pinned: emptyTl()
+    dms: emptyTl()
   }
 })
 
@@ -171,7 +170,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
   // This makes sure that user timeline won't get data meant for other
   // user. I.e. opening different user profiles makes request which could
   // return data late after user already viewing different user profile
-  if ((timeline === 'user' || timeline === 'media' || timeline === 'pinned') && timelineObject.userId !== userId) {
+  if ((timeline === 'user' || timeline === 'media') && timelineObject.userId !== userId) {
     return
   }
 
@@ -542,6 +541,13 @@ const statuses = {
       rootState.api.backendInteractor.unfavorite(status.id)
         .then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
     },
+    fetchPinnedStatuses ({ rootState, dispatch, commit }, userId) {
+      rootState.api.backendInteractor.fetchPinnedStatuses(userId)
+        .then(statuses => {
+          dispatch('addNewStatuses', { statuses })
+          commit('savePinnedStatusIds', { userId, statusIds: map(statuses, 'id') })
+        })
+    },
     updatePinned ({ rootState, commit }, status) {
       commit('setPinned', { status })
       if (status.pinned) {
diff --git a/src/modules/users.js b/src/modules/users.js
index adcab233..def2b38c 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -160,6 +160,9 @@ export const mutations = {
   saveMuteIds (state, muteIds) {
     state.currentUser.muteIds = muteIds
   },
+  savePinnedStatusIds (state, { userId, statusIds }) {
+    state.usersObject[userId].pinnedStatusIds = statusIds
+  },
   addMuteId (state, muteId) {
     if (state.currentUser.muteIds.indexOf(muteId) === -1) {
       state.currentUser.muteIds.push(muteId)
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
index 816e73c1..7a302f57 100644
--- a/src/services/backend_interactor_service/backend_interactor_service.js
+++ b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -106,6 +106,7 @@ const backendInteractorService = (credentials) => {
   const fetchFollowRequests = () => apiService.fetchFollowRequests({credentials})
   const fetchOAuthTokens = () => apiService.fetchOAuthTokens({credentials})
   const revokeOAuthToken = (id) => apiService.revokeOAuthToken({id, credentials})
+  const fetchPinnedStatuses = (id) => apiService.fetchPinnedStatuses({ id, credentials })
 
   const getCaptcha = () => apiService.getCaptcha()
   const register = (params) => apiService.register(params)
@@ -154,6 +155,7 @@ const backendInteractorService = (credentials) => {
     fetchBlocks,
     fetchOAuthTokens,
     revokeOAuthToken,
+    fetchPinnedStatuses,
     tagUser,
     untagUser,
     addRight,
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 97e20b99..3636c05b 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -131,6 +131,8 @@ export const parseUser = (data) => {
   output.statuses_count = data.statuses_count
   output.friendIds = []
   output.followerIds = []
+  output.pinnedStatusIds = []
+
   if (data.pleroma) {
     output.follow_request_count = data.pleroma.follow_request_count
   }