From 8ce513ed09124fa0183943c359950f49ebcf2f89 Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Thu, 31 Jan 2019 21:11:28 +0200
Subject: initial draft for follows/following pagination

---
 src/components/user_profile/user_profile.vue | 1 +
 1 file changed, 1 insertion(+)

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

diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index f9b964ce..baf6aef6 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -7,6 +7,7 @@
       <div :label="$t('user_card.followees')">
         <div v-if="friends">
           <user-card v-for="friend in friends" :key="friend.id" :user="friend" :showFollows="true"></user-card>
+          <div @click="nextFollowsPage" class="panel-footer">MORE</div>
         </div>
         <div class="userlist-placeholder" v-else>
           <i class="icon-spin3 animate-spin"></i>
-- 
cgit v1.2.3-70-g09d2


From dbb16d56e29b8a32fb7c1a7af56a7953f571cdb4 Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Sat, 2 Feb 2019 22:29:10 +0200
Subject: follows/followers pagination ready for review

---
 src/components/followers_list/followers_list.js    | 61 +++++++++++++++++
 src/components/followers_list/followers_list.vue   | 12 ++++
 src/components/friends_list/friends_list.js        | 61 +++++++++++++++++
 src/components/friends_list/friends_list.vue       | 12 ++++
 src/components/user_card/user_card.vue             |  4 +-
 src/components/user_profile/user_profile.js        | 76 +++++++---------------
 src/components/user_profile/user_profile.vue       |  9 +--
 src/modules/users.js                               | 66 +++++++++++++++----
 .../user_profile_link_generator.js                 |  2 +-
 9 files changed, 228 insertions(+), 75 deletions(-)
 create mode 100644 src/components/followers_list/followers_list.js
 create mode 100644 src/components/followers_list/followers_list.vue
 create mode 100644 src/components/friends_list/friends_list.js
 create mode 100644 src/components/friends_list/friends_list.vue

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

diff --git a/src/components/followers_list/followers_list.js b/src/components/followers_list/followers_list.js
new file mode 100644
index 00000000..13aace18
--- /dev/null
+++ b/src/components/followers_list/followers_list.js
@@ -0,0 +1,61 @@
+import UserCard from '../user_card/user_card.vue'
+
+const FollowersList = {
+  data () {
+    return {
+      loading: false,
+      bottomedOut: false,
+      error: false
+    }
+  },
+  props: ['userId'],
+  created () {
+    window.addEventListener('scroll', this.scrollLoad)
+    if (this.user.followers.length === 0) {
+      this.fetchFollowers()
+    }
+  },
+  destroyed () {
+    window.removeEventListener('scroll', this.scrollLoad)
+    this.$store.dispatch('clearFriendsAndFollowers', this.userId)
+  },
+  computed: {
+    user () {
+      return this.$store.getters.userById(this.userId)
+    },
+    followers () {
+      return this.user.followers
+    }
+  },
+  methods: {
+    fetchFollowers () {
+      if (!this.loading) {
+        this.loading = true
+        this.$store.dispatch('addFollowers', this.userId).then(followers => {
+          this.error = false
+          this.loading = false
+          this.bottomedOut = followers.length === 0
+        }).catch(() => {
+          this.error = true
+          this.loading = false
+        })
+      }
+    },
+    scrollLoad (e) {
+      const bodyBRect = document.body.getBoundingClientRect()
+      const height = Math.max(bodyBRect.height, -(bodyBRect.y))
+      if (this.loading === false &&
+        this.bottomedOut === false &&
+        this.$el.offsetHeight > 0 &&
+        (window.innerHeight + window.pageYOffset) >= (height - 750)
+      ) {
+        this.fetchFollowers()
+      }
+    }
+  },
+  components: {
+    UserCard
+  }
+}
+
+export default FollowersList
diff --git a/src/components/followers_list/followers_list.vue b/src/components/followers_list/followers_list.vue
new file mode 100644
index 00000000..b6bd35e1
--- /dev/null
+++ b/src/components/followers_list/followers_list.vue
@@ -0,0 +1,12 @@
+<template>
+  <div>
+    <user-card v-for="follower in followers" :key="follower.id" :user="follower" :showFollows="true"></user-card>
+    <div @click="fetchFollowers" class="new-status-notification text-center panel-footer">
+      <span v-if="error" class="alert error">Error loading followers</span>
+      <i v-else-if="loading" class="icon-spin3 animate-spin"/>
+      <span v-else-if="bottomedOut"></span>
+    </div>
+  </div>
+</template>
+
+<script src="./followers_list.js" />
diff --git a/src/components/friends_list/friends_list.js b/src/components/friends_list/friends_list.js
new file mode 100644
index 00000000..d5c1837a
--- /dev/null
+++ b/src/components/friends_list/friends_list.js
@@ -0,0 +1,61 @@
+import UserCard from '../user_card/user_card.vue'
+
+const FriendsList = {
+  data () {
+    return {
+      loading: false,
+      bottomedOut: false,
+      error: false
+    }
+  },
+  props: ['userId'],
+  created () {
+    window.addEventListener('scroll', this.scrollLoad)
+    if (this.user.followers.length === 0) {
+      this.fetchFriends()
+    }
+  },
+  destroyed () {
+    window.removeEventListener('scroll', this.scrollLoad)
+    this.$store.dispatch('clearFriendsAndFollowers', this.userId)
+  },
+  computed: {
+    user () {
+      return this.$store.getters.userById(this.userId)
+    },
+    friends () {
+      return this.user.friends
+    }
+  },
+  methods: {
+    fetchFriends () {
+      if (!this.loading) {
+        this.loading = true
+        this.$store.dispatch('addFriends', this.userId).then(friends => {
+          this.error = false
+          this.loading = false
+          this.bottomedOut = friends.length === 0
+        }).catch(() => {
+          this.error = true
+          this.loading = false
+        })
+      }
+    },
+    scrollLoad (e) {
+      const bodyBRect = document.body.getBoundingClientRect()
+      const height = Math.max(bodyBRect.height, -(bodyBRect.y))
+      if (this.loading === false &&
+        this.bottomedOut === false &&
+        this.$el.offsetHeight > 0 &&
+        (window.innerHeight + window.pageYOffset) >= (height - 750)
+      ) {
+        this.fetchFriends()
+      }
+    }
+  },
+  components: {
+    UserCard
+  }
+}
+
+export default FriendsList
diff --git a/src/components/friends_list/friends_list.vue b/src/components/friends_list/friends_list.vue
new file mode 100644
index 00000000..75657cc8
--- /dev/null
+++ b/src/components/friends_list/friends_list.vue
@@ -0,0 +1,12 @@
+<template>
+  <div>
+    <user-card v-for="friend in friends" :key="friend.id" :user="friend" :showFollows="true"></user-card>
+    <div @click="fetchFriends" class="new-status-notification text-center panel-footer">
+      <span v-if="error" class="alert error">Error loading follows</span>
+      <i v-else-if="loading" class="icon-spin3 animate-spin"/>
+      <span v-else-if="bottomedOut"></span>
+    </div>
+  </div>
+</template>
+
+<script src="./friends_list.js" />
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index cf69606d..2a590889 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="card">
     <a href="#">
-      <StillImage @click.prevent="toggleUserExpanded" class="avatar" :src="user.profile_image_url"/>
+      <StillImage @click.prevent.native="toggleUserExpanded" class="avatar" :src="user.profile_image_url"/>
     </a>
     <div class="usercard" v-if="userExpanded">
       <user-card-content :user="user" :switcher="false"></user-card-content>
@@ -79,7 +79,7 @@
 
 .usercard {
   width: fill-available;
-  margin: 0.2em 0 0.7em 0;
+  margin: 0.2em 0 0 0.7em;
   border-radius: $fallback--panelRadius;
   border-radius: var(--panelRadius, $fallback--panelRadius);
   border-style: solid;
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 4f09c9e7..0361d253 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -1,6 +1,8 @@
 import UserCardContent from '../user_card_content/user_card_content.vue'
 import UserCard from '../user_card/user_card.vue'
 import Timeline from '../timeline/timeline.vue'
+import FriendsList from '../friends_list/friends_list.vue'
+import FollowersList from '../followers_list/followers_list.vue'
 
 const UserProfile = {
   created () {
@@ -15,15 +17,7 @@ const UserProfile = {
     }
   },
   destroyed () {
-    this.$store.dispatch('stopFetching', 'user')
-    this.$store.dispatch('stopFetching', 'favorites')
-    this.$store.dispatch('stopFetching', 'media')
-  },
-  data () {
-    return {
-      followsPage: 0,
-      followersPage: 0
-    }
+    this.cleanUp(this.userId)
   },
   computed: {
     timeline () {
@@ -45,12 +39,6 @@ const UserProfile = {
       return this.userId && this.$store.state.users.currentUser.id &&
         this.userId === this.$store.state.users.currentUser.id
     },
-    friends () {
-      return this.user.friends
-    },
-    followers () {
-      return this.user.followers
-    },
     userInStore () {
       if (this.isExternal) {
         return this.$store.getters.userById(this.userId)
@@ -74,66 +62,48 @@ const UserProfile = {
     }
   },
   methods: {
-    fetchFollowers () {
-      const id = this.userId
-      this.$store.dispatch('addFollowers', { id })
-    },
-    fetchFriends () {
-      const id = this.userId
-      this.$store.dispatch('addFriends', { id })
-    },
     startFetchFavorites () {
       if (this.isUs) {
         this.$store.dispatch('startFetching', ['favorites', this.fetchBy])
       }
     },
-    nextFollowsPage () {
-      this.followsPage += 1
-      this.$store.dispatch('addFriends', { id: this.userId, page: this.followsPage })
-      console.log(this.user.friends)
-    }
-  },
-  watch: {
-    // TODO get rid of this copypasta
-    userName () {
-      if (this.isExternal) {
-        return
-      }
-      this.$store.dispatch('stopFetching', 'user')
-      this.$store.dispatch('stopFetching', 'favorites')
-      this.$store.dispatch('stopFetching', 'media')
-      this.$store.commit('clearTimeline', { timeline: 'user' })
-      this.$store.commit('clearTimeline', { timeline: 'favorites' })
-      this.$store.commit('clearTimeline', { timeline: 'media' })
+    startUp () {
       this.$store.dispatch('startFetching', ['user', this.fetchBy])
       this.$store.dispatch('startFetching', ['media', this.fetchBy])
+
       this.startFetchFavorites()
     },
-    userId () {
-      if (!this.isExternal) {
-        return
-      }
+    cleanUp () {
       this.$store.dispatch('stopFetching', 'user')
       this.$store.dispatch('stopFetching', 'favorites')
       this.$store.dispatch('stopFetching', 'media')
       this.$store.commit('clearTimeline', { timeline: 'user' })
       this.$store.commit('clearTimeline', { timeline: 'favorites' })
       this.$store.commit('clearTimeline', { timeline: 'media' })
-      this.$store.dispatch('startFetching', ['user', this.fetchBy])
-      this.$store.dispatch('startFetching', ['media', this.fetchBy])
-      this.startFetchFavorites()
+    }
+  },
+  watch: {
+    userName () {
+      if (this.isExternal) {
+        return
+      }
+      this.cleanUp()
+      this.startUp()
     },
-    user () {
-      if (this.user.id && !this.user.followers) {
-        this.fetchFollowers()
-        this.fetchFriends()
+    userId () {
+      if (!this.isExternal) {
+        return
       }
+      this.cleanUp()
+      this.startUp()
     }
   },
   components: {
     UserCardContent,
     UserCard,
-    Timeline
+    Timeline,
+    FriendsList,
+    FollowersList
   }
 }
 
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index baf6aef6..4ba09dc3 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -5,18 +5,13 @@
     <tab-switcher>
       <Timeline :label="$t('user_card.statuses')" :embedded="true" :title="$t('user_profile.timeline_title')" :timeline="timeline" :timeline-name="'user'" :user-id="fetchBy"/>
       <div :label="$t('user_card.followees')">
-        <div v-if="friends">
-          <user-card v-for="friend in friends" :key="friend.id" :user="friend" :showFollows="true"></user-card>
-          <div @click="nextFollowsPage" class="panel-footer">MORE</div>
-        </div>
+        <FriendsList v-if="user.friends_count > 0" :userId="userId" />
         <div class="userlist-placeholder" v-else>
           <i class="icon-spin3 animate-spin"></i>
         </div>
       </div>
       <div :label="$t('user_card.followers')">
-        <div v-if="followers">
-          <user-card v-for="follower in followers" :key="follower.id" :user="follower" :showFollows="false"></user-card>
-        </div>
+        <FollowersList v-if="user.followers_count > 0" :userId="userId" />
         <div class="userlist-placeholder" v-else>
           <i class="icon-spin3 animate-spin"></i>
         </div>
diff --git a/src/modules/users.js b/src/modules/users.js
index ca8e5606..ca2e0f31 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -1,5 +1,5 @@
 import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
-import { compact, map, each, merge, concat } from 'lodash'
+import { compact, map, each, merge, find } from 'lodash'
 import { set } from 'vue'
 import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js'
 import oauthApi from '../services/new_api/oauth'
@@ -52,14 +52,35 @@ export const mutations = {
     state.loggingIn = false
   },
   // TODO Clean after ourselves?
-  addFriends (state, { id, friends }) {
+  addFriends (state, { id, friends, page }) {
     const user = state.usersObject[id]
-    console.log(user.friends)
-    user.friends = concat(user.friends, friends)
+    each(friends, friend => {
+      if (!find(user.friends, { id: friend.id })) {
+        user.friends.push(friend)
+      }
+    })
+    user.friendsPage = page + 1
   },
-  addFollowers (state, { id, followers }) {
+  addFollowers (state, { id, followers, page }) {
     const user = state.usersObject[id]
-    user.followers = followers
+    each(followers, follower => {
+      if (!find(user.followers, { id: follower.id })) {
+        user.followers.push(follower)
+      }
+    })
+    user.followersPage = page + 1
+  },
+  // Because frontend doesn't have a reason to keep these stuff in memory
+  // outside of viewing someones user profile.
+  clearFriendsAndFollowers (state, userKey) {
+    const user = state.usersObject[userKey]
+    if (!user) {
+      return
+    }
+    user.friends = []
+    user.followers = []
+    user.friendsPage = 0
+    user.followersPage = 0
   },
   addNewUsers (state, users) {
     each(users, (user) => mergeOrAdd(state.users, state.usersObject, user))
@@ -116,13 +137,34 @@ const users = {
       store.rootState.api.backendInteractor.fetchUser({ id })
         .then((user) => store.commit('addNewUsers', [user]))
     },
-    addFriends ({ rootState, commit }, { id, page }) {
-      rootState.api.backendInteractor.fetchFriends({ id, page })
-        .then((friends) => commit('addFriends', { id, friends }))
+    addFriends ({ rootState, commit }, fetchBy) {
+      return new Promise((resolve, reject) => {
+        const user = rootState.users.usersObject[fetchBy]
+        const page = user.friendsPage || 1
+        rootState.api.backendInteractor.fetchFriends({ id: user.id, page })
+          .then((friends) => {
+            commit('addFriends', { id: user.id, friends, page })
+            resolve(friends)
+          }).catch(() => {
+            reject()
+          })
+      })
+    },
+    addFollowers ({ rootState, commit }, fetchBy) {
+      return new Promise((resolve, reject) => {
+        const user = rootState.users.usersObject[fetchBy]
+        const page = user.followersPage || 1
+        rootState.api.backendInteractor.fetchFollowers({ id: user.id, page })
+          .then((followers) => {
+            commit('addFollowers', { id: user.id, followers, page })
+            resolve(followers)
+          }).catch(() => {
+            reject()
+          })
+      })
     },
-    addFollowers ({ rootState, commit }, { id, page }) {
-      rootState.api.backendInteractor.fetchFollowers({ id, page })
-        .then((followers) => commit('addFollowers', { id, followers }))
+    clearFriendsAndFollowers ({ commit }, userKey) {
+      commit('clearFriendsAndFollowers', userKey)
     },
     registerPushNotifications (store) {
       const token = store.state.currentUser.credentials
diff --git a/src/services/user_profile_link_generator/user_profile_link_generator.js b/src/services/user_profile_link_generator/user_profile_link_generator.js
index bca2c9cd..a214ca48 100644
--- a/src/services/user_profile_link_generator/user_profile_link_generator.js
+++ b/src/services/user_profile_link_generator/user_profile_link_generator.js
@@ -8,6 +8,6 @@ const generateProfileLink = (id, screenName, restrictedNicknames) => {
   }
 }
 
-const isExternal = screenName => screenName.includes('@')
+const isExternal = screenName => screenName && screenName.includes('@')
 
 export default generateProfileLink
-- 
cgit v1.2.3-70-g09d2


From 18ae7bd5f366598d46a65e9da1312c98f7bb00e7 Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Sun, 3 Feb 2019 11:58:49 +0200
Subject: Combine friends/followers

---
 src/components/follow_list/follow_list.js        | 62 ++++++++++++++++++++++++
 src/components/follow_list/follow_list.vue       | 33 +++++++++++++
 src/components/followers_list/followers_list.js  | 61 -----------------------
 src/components/followers_list/followers_list.vue | 12 -----
 src/components/friends_list/friends_list.js      | 61 -----------------------
 src/components/friends_list/friends_list.vue     | 12 -----
 src/components/user_profile/user_profile.js      |  6 +--
 src/components/user_profile/user_profile.vue     |  4 +-
 src/i18n/en.json                                 | 10 ++--
 src/i18n/fi.json                                 |  4 +-
 10 files changed, 108 insertions(+), 157 deletions(-)
 create mode 100644 src/components/follow_list/follow_list.js
 create mode 100644 src/components/follow_list/follow_list.vue
 delete mode 100644 src/components/followers_list/followers_list.js
 delete mode 100644 src/components/followers_list/followers_list.vue
 delete mode 100644 src/components/friends_list/friends_list.js
 delete mode 100644 src/components/friends_list/friends_list.vue

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

diff --git a/src/components/follow_list/follow_list.js b/src/components/follow_list/follow_list.js
new file mode 100644
index 00000000..6d00eb94
--- /dev/null
+++ b/src/components/follow_list/follow_list.js
@@ -0,0 +1,62 @@
+import UserCard from '../user_card/user_card.vue'
+
+const FollowList = {
+  data () {
+    return {
+      loading: false,
+      bottomedOut: false,
+      error: false
+    }
+  },
+  props: ['userId', 'showFollowers'],
+  created () {
+    window.addEventListener('scroll', this.scrollLoad)
+    if (this.entries.length === 0) {
+      this.fetchEntries()
+    }
+  },
+  destroyed () {
+    window.removeEventListener('scroll', this.scrollLoad)
+    this.$store.dispatch('clearFriendsAndFollowers', this.userId)
+  },
+  computed: {
+    user () {
+      return this.$store.getters.userById(this.userId)
+    },
+    entries () {
+      return this.showFollowers ? this.user.followers : this.user.friends
+    }
+  },
+  methods: {
+    fetchEntries () {
+      if (!this.loading) {
+        const command = this.showFollowers ? 'addFollowers' : 'addFriends'
+        this.loading = true
+        this.$store.dispatch(command, this.userId).then(entries => {
+          this.error = false
+          this.loading = false
+          this.bottomedOut = entries.length === 0
+        }).catch(() => {
+          this.error = true
+          this.loading = false
+        })
+      }
+    },
+    scrollLoad (e) {
+      const bodyBRect = document.body.getBoundingClientRect()
+      const height = Math.max(bodyBRect.height, -(bodyBRect.y))
+      if (this.loading === false &&
+        this.bottomedOut === false &&
+        this.$el.offsetHeight > 0 &&
+        (window.innerHeight + window.pageYOffset) >= (height - 750)
+      ) {
+        this.fetchEntries()
+      }
+    }
+  },
+  components: {
+    UserCard
+  }
+}
+
+export default FollowList
diff --git a/src/components/follow_list/follow_list.vue b/src/components/follow_list/follow_list.vue
new file mode 100644
index 00000000..24ab97d8
--- /dev/null
+++ b/src/components/follow_list/follow_list.vue
@@ -0,0 +1,33 @@
+<template>
+  <div class="follow-list">
+    <user-card
+      v-for="entry in entries"
+      :key="entry.id" :user="entry"
+      :showFollows="true"
+    />
+    <div class="text-center panel-footer">
+      <a v-if="error" @click="fetchEntries" class="alert error">
+        {{$t('general.generic_error')}}
+      </a>
+      <i v-else-if="loading" class="icon-spin3 animate-spin"/>
+      <span v-else-if="bottomedOut"></span>
+      <a v-else @click="fetchEntries">{{$t('general.more')}}</a>
+    </div>
+  </div>
+</template>
+
+<script src="./follow_list.js"></script>
+
+<style lang="scss">
+
+.follow-list {
+  .panel-footer {
+    padding: 10px;
+  }
+
+  .error {
+    font-size: 14px;
+  }
+}
+
+</style>
diff --git a/src/components/followers_list/followers_list.js b/src/components/followers_list/followers_list.js
deleted file mode 100644
index 13aace18..00000000
--- a/src/components/followers_list/followers_list.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import UserCard from '../user_card/user_card.vue'
-
-const FollowersList = {
-  data () {
-    return {
-      loading: false,
-      bottomedOut: false,
-      error: false
-    }
-  },
-  props: ['userId'],
-  created () {
-    window.addEventListener('scroll', this.scrollLoad)
-    if (this.user.followers.length === 0) {
-      this.fetchFollowers()
-    }
-  },
-  destroyed () {
-    window.removeEventListener('scroll', this.scrollLoad)
-    this.$store.dispatch('clearFriendsAndFollowers', this.userId)
-  },
-  computed: {
-    user () {
-      return this.$store.getters.userById(this.userId)
-    },
-    followers () {
-      return this.user.followers
-    }
-  },
-  methods: {
-    fetchFollowers () {
-      if (!this.loading) {
-        this.loading = true
-        this.$store.dispatch('addFollowers', this.userId).then(followers => {
-          this.error = false
-          this.loading = false
-          this.bottomedOut = followers.length === 0
-        }).catch(() => {
-          this.error = true
-          this.loading = false
-        })
-      }
-    },
-    scrollLoad (e) {
-      const bodyBRect = document.body.getBoundingClientRect()
-      const height = Math.max(bodyBRect.height, -(bodyBRect.y))
-      if (this.loading === false &&
-        this.bottomedOut === false &&
-        this.$el.offsetHeight > 0 &&
-        (window.innerHeight + window.pageYOffset) >= (height - 750)
-      ) {
-        this.fetchFollowers()
-      }
-    }
-  },
-  components: {
-    UserCard
-  }
-}
-
-export default FollowersList
diff --git a/src/components/followers_list/followers_list.vue b/src/components/followers_list/followers_list.vue
deleted file mode 100644
index b6bd35e1..00000000
--- a/src/components/followers_list/followers_list.vue
+++ /dev/null
@@ -1,12 +0,0 @@
-<template>
-  <div>
-    <user-card v-for="follower in followers" :key="follower.id" :user="follower" :showFollows="true"></user-card>
-    <div @click="fetchFollowers" class="new-status-notification text-center panel-footer">
-      <span v-if="error" class="alert error">Error loading followers</span>
-      <i v-else-if="loading" class="icon-spin3 animate-spin"/>
-      <span v-else-if="bottomedOut"></span>
-    </div>
-  </div>
-</template>
-
-<script src="./followers_list.js" />
diff --git a/src/components/friends_list/friends_list.js b/src/components/friends_list/friends_list.js
deleted file mode 100644
index d5c1837a..00000000
--- a/src/components/friends_list/friends_list.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import UserCard from '../user_card/user_card.vue'
-
-const FriendsList = {
-  data () {
-    return {
-      loading: false,
-      bottomedOut: false,
-      error: false
-    }
-  },
-  props: ['userId'],
-  created () {
-    window.addEventListener('scroll', this.scrollLoad)
-    if (this.user.followers.length === 0) {
-      this.fetchFriends()
-    }
-  },
-  destroyed () {
-    window.removeEventListener('scroll', this.scrollLoad)
-    this.$store.dispatch('clearFriendsAndFollowers', this.userId)
-  },
-  computed: {
-    user () {
-      return this.$store.getters.userById(this.userId)
-    },
-    friends () {
-      return this.user.friends
-    }
-  },
-  methods: {
-    fetchFriends () {
-      if (!this.loading) {
-        this.loading = true
-        this.$store.dispatch('addFriends', this.userId).then(friends => {
-          this.error = false
-          this.loading = false
-          this.bottomedOut = friends.length === 0
-        }).catch(() => {
-          this.error = true
-          this.loading = false
-        })
-      }
-    },
-    scrollLoad (e) {
-      const bodyBRect = document.body.getBoundingClientRect()
-      const height = Math.max(bodyBRect.height, -(bodyBRect.y))
-      if (this.loading === false &&
-        this.bottomedOut === false &&
-        this.$el.offsetHeight > 0 &&
-        (window.innerHeight + window.pageYOffset) >= (height - 750)
-      ) {
-        this.fetchFriends()
-      }
-    }
-  },
-  components: {
-    UserCard
-  }
-}
-
-export default FriendsList
diff --git a/src/components/friends_list/friends_list.vue b/src/components/friends_list/friends_list.vue
deleted file mode 100644
index 75657cc8..00000000
--- a/src/components/friends_list/friends_list.vue
+++ /dev/null
@@ -1,12 +0,0 @@
-<template>
-  <div>
-    <user-card v-for="friend in friends" :key="friend.id" :user="friend" :showFollows="true"></user-card>
-    <div @click="fetchFriends" class="new-status-notification text-center panel-footer">
-      <span v-if="error" class="alert error">Error loading follows</span>
-      <i v-else-if="loading" class="icon-spin3 animate-spin"/>
-      <span v-else-if="bottomedOut"></span>
-    </div>
-  </div>
-</template>
-
-<script src="./friends_list.js" />
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 0361d253..7b0ab705 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -1,8 +1,7 @@
 import UserCardContent from '../user_card_content/user_card_content.vue'
 import UserCard from '../user_card/user_card.vue'
 import Timeline from '../timeline/timeline.vue'
-import FriendsList from '../friends_list/friends_list.vue'
-import FollowersList from '../followers_list/followers_list.vue'
+import FollowList from '../follow_list/follow_list.vue'
 
 const UserProfile = {
   created () {
@@ -102,8 +101,7 @@ const UserProfile = {
     UserCardContent,
     UserCard,
     Timeline,
-    FriendsList,
-    FollowersList
+    FollowList
   }
 }
 
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index c431c729..6d5b00d1 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -16,13 +16,13 @@
         :user-id="fetchBy"
       />
       <div :label="$t('user_card.followees')">
-        <FriendsList v-if="user.friends_count > 0" :userId="userId" />
+        <FollowList v-if="user.friends_count > 0" :userId="userId" :showFollowers="false" />
         <div class="userlist-placeholder" v-else>
           <i class="icon-spin3 animate-spin"></i>
         </div>
       </div>
       <div :label="$t('user_card.followers')">
-        <FollowersList v-if="user.followers_count > 0" :userId="userId" />
+        <FollowList v-if="user.followers_count > 0" :userId="userId" :showFollowers="true" />
         <div class="userlist-placeholder" v-else>
           <i class="icon-spin3 animate-spin"></i>
         </div>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index d3b0e407..dc10fa7f 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -17,7 +17,9 @@
   },
   "general": {
     "apply": "Apply",
-    "submit": "Submit"
+    "submit": "Submit",
+    "more": "More",
+    "generic_error": "An error occured"
   },
   "login": {
     "login": "Log in",
@@ -365,9 +367,9 @@
   },
   "upload":{
     "error": {
-    "base": "Upload failed.",
-    "file_too_big": "File too big [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
-    "default": "Try again later"
+      "base": "Upload failed.",
+      "file_too_big": "File too big [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
+      "default": "Try again later"
     },
     "file_size_units": {
       "B": "B",
diff --git a/src/i18n/fi.json b/src/i18n/fi.json
index 0d62f295..5a0c1ea8 100644
--- a/src/i18n/fi.json
+++ b/src/i18n/fi.json
@@ -17,7 +17,9 @@
   },
   "general": {
     "apply": "Aseta",
-    "submit": "Lähetä"
+    "submit": "Lähetä",
+    "more": "Lisää",
+    "generic_error": "Virhe tapahtui"
   },
   "login": {
     "login": "Kirjaudu sisään",
-- 
cgit v1.2.3-70-g09d2

