logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe
commit: 88c7c8b1140aaa719e9c9314a8ce9fd04ef3baf1
parent: dc01f90dde55e2babf58878177308c11aa965006
Author: Shpuld Shpludson <shp@cock.li>
Date:   Thu, 28 Feb 2019 17:53:40 +0000

Merge branch '398-rewrite-follow-list' into 'develop'

Split UserCard into FollowCard/FollowRequestCard and Rewrite FollowList using HOCs

Closes #398

See merge request pleroma/pleroma-fe!616

Diffstat:

Msrc/components/basic_user_card/basic_user_card.vue47+++++++++++++++++------------------------------
Msrc/components/block_card/block_card.vue17+++++++++++++----
Asrc/components/follow_card/follow_card.js45+++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/follow_card/follow_card.vue53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/components/follow_list/follow_list.js68--------------------------------------------------------------------
Dsrc/components/follow_list/follow_list.vue33---------------------------------
Asrc/components/follow_request_card/follow_request_card.js20++++++++++++++++++++
Asrc/components/follow_request_card/follow_request_card.vue29+++++++++++++++++++++++++++++
Msrc/components/follow_requests/follow_requests.js4++--
Msrc/components/follow_requests/follow_requests.vue2+-
Msrc/components/timeline/timeline.js4+---
Dsrc/components/user_card/user_card.js64----------------------------------------------------------------
Dsrc/components/user_card/user_card.vue159-------------------------------------------------------------------------------
Msrc/components/user_card_content/user_card_content.vue27+++++++++++++++++++++++++++
Msrc/components/user_profile/user_profile.js32++++++++++++++++++++++++++++----
Msrc/components/user_profile/user_profile.vue10++--------
Msrc/components/user_search/user_search.js4++--
Msrc/components/user_search/user_search.vue2+-
Msrc/components/who_to_follow/who_to_follow.js4++--
Msrc/components/who_to_follow/who_to_follow.vue2+-
Msrc/hocs/with_load_more/with_load_more.js11+++++++----
Msrc/hocs/with_subscription/with_subscription.js12++++++------
Msrc/modules/users.js37+++++++++++++++++++++----------------
Asrc/services/component_utils/component_utils.js10++++++++++
24 files changed, 288 insertions(+), 408 deletions(-)

diff --git a/src/components/basic_user_card/basic_user_card.vue b/src/components/basic_user_card/basic_user_card.vue @@ -1,26 +1,22 @@ <template> <div class="user-card"> <router-link :to="userProfileLink(user)"> - <UserAvatar class="avatar" :compact="true" @click.prevent.native="toggleUserExpanded" :src="user.profile_image_url"/> + <UserAvatar class="avatar" @click.prevent.native="toggleUserExpanded" :src="user.profile_image_url"/> </router-link> <div class="user-card-expanded-content" v-if="userExpanded"> <user-card-content :user="user" :switcher="false"></user-card-content> </div> <div class="user-card-collapsed-content" v-else> - <div class="user-card-primary-area"> - <div :title="user.name" class="user-name"> - <span v-if="user.name_html" v-html="user.name_html"></span> - <span v-else>{{ user.name }}</span> - </div> - <div> - <router-link class='user-screen-name' :to="userProfileLink(user)"> - @{{user.screen_name}} - </router-link> - </div> + <div :title="user.name" class="user-card-user-name"> + <span v-if="user.name_html" v-html="user.name_html"></span> + <span v-else>{{ user.name }}</span> </div> - <div class="user-card-secondary-area"> - <slot name="secondary-area"></slot> + <div> + <router-link class="user-card-screen-name" :to="userProfileLink(user)"> + @{{user.screen_name}} + </router-link> </div> + <slot></slot> </div> </div> </template> @@ -46,30 +42,21 @@ margin-left: 0.7em; text-align: left; flex: 1; - display: flex; - align-items: flex-start; - justify-content: space-between; + min-width: 0; } - &-primary-area { - flex: 1; - .user-name { - img { - object-fit: contain; - height: 16px; - width: 16px; - vertical-align: middle; - } + &-user-name { + img { + object-fit: contain; + height: 16px; + width: 16px; + vertical-align: middle; } } - &-secondary-area { - flex: none; - } - &-expanded-content { flex: 1; - margin: 0.2em 0 0 0.7em; + margin-left: 0.7em; border-radius: $fallback--panelRadius; border-radius: var(--panelRadius, $fallback--panelRadius); border-style: solid; diff --git a/src/components/block_card/block_card.vue b/src/components/block_card/block_card.vue @@ -1,6 +1,6 @@ <template> <basic-user-card :user="user"> - <template slot="secondary-area"> + <div class="block-card-content-container"> <button class="btn btn-default" @click="unblockUser" :disabled="progress" v-if="blocked"> <template v-if="progress"> {{ $t('user_card.unblock_progress') }} @@ -17,8 +17,18 @@ {{ $t('user_card.block') }} </template> </button> - </template> + </div> </basic-user-card> </template> -<script src="./block_card.js"></script>- \ No newline at end of file +<script src="./block_card.js"></script> + +<style lang="scss"> +.block-card-content-container { + margin-top: 0.5em; + text-align: right; + button { + width: 10em; + } +} +</style> diff --git a/src/components/follow_card/follow_card.js b/src/components/follow_card/follow_card.js @@ -0,0 +1,45 @@ +import BasicUserCard from '../basic_user_card/basic_user_card.vue' +import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate' + +const FollowCard = { + props: [ + 'user', + 'noFollowsYou' + ], + data () { + return { + inProgress: false, + requestSent: false, + updated: false + } + }, + components: { + BasicUserCard + }, + computed: { + isMe () { return this.$store.state.users.currentUser.id === this.user.id }, + following () { return this.updated ? this.updated.following : this.user.following }, + showFollow () { + return !this.following || this.updated && !this.updated.following + } + }, + methods: { + followUser () { + this.inProgress = true + requestFollow(this.user, this.$store).then(({ sent, updated }) => { + this.inProgress = false + this.requestSent = sent + this.updated = updated + }) + }, + unfollowUser () { + this.inProgress = true + requestUnfollow(this.user, this.$store).then(({ updated }) => { + this.inProgress = false + this.updated = updated + }) + } + } +} + +export default FollowCard diff --git a/src/components/follow_card/follow_card.vue b/src/components/follow_card/follow_card.vue @@ -0,0 +1,53 @@ +<template> + <basic-user-card :user="user"> + <div class="follow-card-content-container"> + <span class="faint" v-if="!noFollowsYou && user.follows_you"> + {{ isMe ? $t('user_card.its_you') : $t('user_card.follows_you') }} + </span> + <button + v-if="showFollow" + class="btn btn-default" + @click="followUser" + :disabled="inProgress" + :title="requestSent ? $t('user_card.follow_again') : ''" + > + <template v-if="inProgress"> + {{ $t('user_card.follow_progress') }} + </template> + <template v-else-if="requestSent"> + {{ $t('user_card.follow_sent') }} + </template> + <template v-else> + {{ $t('user_card.follow') }} + </template> + </button> + <button v-if="following" class="btn btn-default pressed" @click="unfollowUser" :disabled="inProgress"> + <template v-if="inProgress"> + {{ $t('user_card.follow_progress') }} + </template> + <template v-else> + {{ $t('user_card.follow_unfollow') }} + </template> + </button> + </div> + </basic-user-card> +</template> + +<script src="./follow_card.js"></script> + +<style lang="scss"> +.follow-card-content-container { + flex-shrink: 0; + display: flex; + flex-direction: row; + justify-content: space-between; + flex-wrap: wrap; + line-height: 1.5em; + + .btn { + margin-top: 0.5em; + margin-left: auto; + width: 10em; + } +} +</style> diff --git a/src/components/follow_list/follow_list.js b/src/components/follow_list/follow_list.js @@ -1,68 +0,0 @@ -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 - }, - showFollowsYou () { - return !this.showFollowers || (this.showFollowers && this.userId !== this.$store.state.users.currentUser.id) - } - }, - 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() - } - } - }, - watch: { - 'user': 'fetchEntries' - }, - components: { - UserCard - } -} - -export default FollowList diff --git a/src/components/follow_list/follow_list.vue b/src/components/follow_list/follow_list.vue @@ -1,33 +0,0 @@ -<template> - <div class="follow-list"> - <user-card - v-for="entry in entries" - :key="entry.id" :user="entry" - :noFollowsYou="!showFollowsYou" - /> - <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/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js @@ -0,0 +1,20 @@ +import BasicUserCard from '../basic_user_card/basic_user_card.vue' + +const FollowRequestCard = { + props: ['user'], + components: { + BasicUserCard + }, + methods: { + approveUser () { + this.$store.state.api.backendInteractor.approveUser(this.user.id) + this.$store.dispatch('removeFollowRequest', this.user) + }, + denyUser () { + this.$store.state.api.backendInteractor.denyUser(this.user.id) + this.$store.dispatch('removeFollowRequest', this.user) + } + } +} + +export default FollowRequestCard diff --git a/src/components/follow_request_card/follow_request_card.vue b/src/components/follow_request_card/follow_request_card.vue @@ -0,0 +1,29 @@ +<template> + <basic-user-card :user="user"> + <div class="follow-request-card-content-container"> + <button class="btn btn-default" @click="approveUser">{{ $t('user_card.approve') }}</button> + <button class="btn btn-default" @click="denyUser">{{ $t('user_card.deny') }}</button> + </div> + </basic-user-card> +</template> + +<script src="./follow_request_card.js"></script> + +<style lang="scss"> +.follow-request-card-content-container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + button { + margin-top: 0.5em; + margin-right: 0.5em; + flex: 1 1; + max-width: 12em; + min-width: 8em; + + &:last-child { + margin-right: 0; + } + } +} +</style> diff --git a/src/components/follow_requests/follow_requests.js b/src/components/follow_requests/follow_requests.js @@ -1,8 +1,8 @@ -import UserCard from '../user_card/user_card.vue' +import FollowRequestCard from '../follow_request_card/follow_request_card.vue' const FollowRequests = { components: { - UserCard + FollowRequestCard }, created () { this.updateRequests() diff --git a/src/components/follow_requests/follow_requests.vue b/src/components/follow_requests/follow_requests.vue @@ -4,7 +4,7 @@ {{$t('nav.friend_requests')}} </div> <div class="panel-body"> - <user-card v-for="request in requests" :key="request.id" :user="request" :showFollows="false" :showApproval="true"></user-card> + <FollowRequestCard v-for="request in requests" :key="request.id" :user="request"/> </div> </div> </template> diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js @@ -1,7 +1,6 @@ import Status from '../status/status.vue' import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js' import StatusOrConversation from '../status_or_conversation/status_or_conversation.vue' -import UserCard from '../user_card/user_card.vue' import { throttle } from 'lodash' const Timeline = { @@ -44,8 +43,7 @@ const Timeline = { }, components: { Status, - StatusOrConversation, - UserCard + StatusOrConversation }, created () { const store = this.$store diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js @@ -1,64 +0,0 @@ -import UserCardContent from '../user_card_content/user_card_content.vue' -import UserAvatar from '../user_avatar/user_avatar.vue' -import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' -import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate' - -const UserCard = { - props: [ - 'user', - 'noFollowsYou', - 'showApproval' - ], - data () { - return { - userExpanded: false, - followRequestInProgress: false, - followRequestSent: false, - updated: false - } - }, - components: { - UserCardContent, - UserAvatar - }, - computed: { - currentUser () { return this.$store.state.users.currentUser }, - following () { return this.updated ? this.updated.following : this.user.following }, - showFollow () { - return !this.showApproval && (!this.following || this.updated && !this.updated.following) - } - }, - methods: { - toggleUserExpanded () { - this.userExpanded = !this.userExpanded - }, - approveUser () { - this.$store.state.api.backendInteractor.approveUser(this.user.id) - this.$store.dispatch('removeFollowRequest', this.user) - }, - denyUser () { - this.$store.state.api.backendInteractor.denyUser(this.user.id) - this.$store.dispatch('removeFollowRequest', this.user) - }, - userProfileLink (user) { - return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) - }, - followUser () { - this.followRequestInProgress = true - requestFollow(this.user, this.$store).then(({ sent, updated }) => { - this.followRequestInProgress = false - this.followRequestSent = sent - this.updated = updated - }) - }, - unfollowUser () { - this.followRequestInProgress = true - requestUnfollow(this.user, this.$store).then(({ updated }) => { - this.followRequestInProgress = false - this.updated = updated - }) - } - } -} - -export default UserCard diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue @@ -1,159 +0,0 @@ -<template> - <div class="card"> - <router-link :to="userProfileLink(user)"> - <UserAvatar class="avatar" @click.prevent.native="toggleUserExpanded" :src="user.profile_image_url"/> - </router-link> - <div class="user-card-main-content"> - <div class="usercard" v-if="userExpanded"> - <user-card-content :user="user" :switcher="false"></user-card-content> - </div> - <div class="name-and-screen-name" v-if="!userExpanded"> - <div :title="user.name" class="user-name"> - <span v-if="user.name_html" v-html="user.name_html"></span> - <span v-else>{{ user.name }}</span> - </div> - <div class="user-link-action"> - <router-link class='user-screen-name' :to="userProfileLink(user)"> - @{{user.screen_name}} - </router-link> - </div> - </div> - <div class="follow-box" v-if="!userExpanded"> - <span class="faint" v-if="!noFollowsYou && user.follows_you"> - {{ currentUser.id == user.id ? $t('user_card.its_you') : $t('user_card.follows_you') }} - </span> - <button - v-if="showFollow" - class="btn btn-default" - @click="followUser" - :disabled="followRequestInProgress" - :title="followRequestSent ? $t('user_card.follow_again') : ''" - > - <template v-if="followRequestInProgress"> - {{ $t('user_card.follow_progress') }} - </template> - <template v-else-if="followRequestSent"> - {{ $t('user_card.follow_sent') }} - </template> - <template v-else> - {{ $t('user_card.follow') }} - </template> - </button> - <button v-if="following" class="btn btn-default pressed" @click="unfollowUser" :disabled="followRequestInProgress"> - <template v-if="followRequestInProgress"> - {{ $t('user_card.follow_progress') }} - </template> - <template v-else> - {{ $t('user_card.follow_unfollow') }} - </template> - </button> - </div> - <div class="approval" v-if="showApproval"> - <button class="btn btn-default" @click="approveUser">{{ $t('user_card.approve') }}</button> - <button class="btn btn-default" @click="denyUser">{{ $t('user_card.deny') }}</button> - </div> - </div> - </div> -</template> - -<script src="./user_card.js"></script> - -<style lang="scss"> -@import '../../_variables.scss'; - -.user-card-main-content { - display: flex; - flex-direction: column; - flex: 1 1 100%; - margin-left: 0.7em; - min-width: 0; -} - -.name-and-screen-name { - text-align: left; - width: 100%; - - .user-name { - img { - object-fit: contain; - height: 16px; - width: 16px; - vertical-align: middle; - } - } - - .user-link-action { - display: flex; - align-items: flex-start; - justify-content: space-between; - } -} - - -.card { - display: flex; - flex: 1 0; - padding-top: 0.6em; - padding-right: 1em; - padding-bottom: 0.6em; - padding-left: 1em; - border-bottom: 1px solid; - margin: 0; - border-bottom-color: $fallback--border; - border-bottom-color: var(--border, $fallback--border); - - .avatar { - padding: 0; - } - - .follow-box { - text-align: center; - flex-shrink: 0; - display: flex; - flex-direction: row; - justify-content: space-between; - flex-wrap: wrap; - line-height: 1.5em; - - .btn { - margin-top: 0.5em; - margin-left: auto; - width: 10em; - } - } -} - -.usercard { - width: fill-available; - border-radius: $fallback--panelRadius; - border-radius: var(--panelRadius, $fallback--panelRadius); - border-style: solid; - border-color: $fallback--border; - border-color: var(--border, $fallback--border); - border-width: 1px; - overflow: hidden; - - .panel-heading { - background: transparent; - flex-direction: column; - align-items: stretch; - } - - p { - margin-bottom: 0; - } -} - -.approval { - display: flex; - flex-direction: row; - flex-wrap: wrap; - button { - margin-top: 0.5em; - margin-right: 0.5em; - flex: 1 1; - max-width: 12em; - min-width: 8em; - } -} -</style> diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue @@ -222,6 +222,13 @@ overflow: hidden; flex: 1 1 auto; margin-right: 1em; + + img { + object-fit: contain; + height: 16px; + width: 16px; + vertical-align: middle; + } } .user-screen-name { @@ -386,4 +393,24 @@ } } +.usercard { + width: fill-available; + border-radius: $fallback--panelRadius; + border-radius: var(--panelRadius, $fallback--panelRadius); + border-style: solid; + border-color: $fallback--border; + border-color: var(--border, $fallback--border); + border-width: 1px; + overflow: hidden; + + .panel-heading { + background: transparent; + flex-direction: column; + align-items: stretch; + } + + p { + margin-bottom: 0; + } +} </style> diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js @@ -1,8 +1,32 @@ +import { compose } from 'vue-compose' import get from 'lodash/get' import UserCardContent from '../user_card_content/user_card_content.vue' -import UserCard from '../user_card/user_card.vue' +import FollowCard from '../follow_card/follow_card.vue' import Timeline from '../timeline/timeline.vue' -import FollowList from '../follow_list/follow_list.vue' +import withLoadMore from '../../hocs/with_load_more/with_load_more' +import withList from '../../hocs/with_list/with_list' + +const FollowerList = compose( + withLoadMore({ + fetch: (props, $store) => $store.dispatch('addFollowers', props.userId), + select: (props, $store) => get($store.getters.userById(props.userId), 'followers', []), + destory: (props, $store) => $store.dispatch('clearFollowers', props.userId), + childPropName: 'entries', + additionalPropNames: ['userId'] + }), + withList({ getEntryProps: user => ({ user }) }) +)(FollowCard) + +const FriendList = compose( + withLoadMore({ + fetch: (props, $store) => $store.dispatch('addFriends', props.userId), + select: (props, $store) => get($store.getters.userById(props.userId), 'friends', []), + destory: (props, $store) => $store.dispatch('clearFriends', props.userId), + childPropName: 'entries', + additionalPropNames: ['userId'] + }), + withList({ getEntryProps: user => ({ user }) }) +)(FollowCard) const UserProfile = { data () { @@ -121,9 +145,9 @@ const UserProfile = { }, components: { UserCardContent, - UserCard, Timeline, - FollowList + FollowerList, + FriendList } } diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue @@ -18,16 +18,10 @@ :user-id="fetchBy" /> <div :label="$t('user_card.followees')" v-if="followsTabVisible" :disabled="!user.friends_count"> - <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> + <FriendList :userId="userId" /> </div> <div :label="$t('user_card.followers')" v-if="followersTabVisible" :disabled="!user.followers_count"> - <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> + <FollowerList :userId="userId" :entryProps="{noFollowsYou: isUs}" /> </div> <Timeline :label="$t('user_card.media')" diff --git a/src/components/user_search/user_search.js b/src/components/user_search/user_search.js @@ -1,8 +1,8 @@ -import UserCard from '../user_card/user_card.vue' +import FollowCard from '../follow_card/follow_card.vue' import userSearchApi from '../../services/new_api/user_search.js' const userSearch = { components: { - UserCard + FollowCard }, props: [ 'query' diff --git a/src/components/user_search/user_search.vue b/src/components/user_search/user_search.vue @@ -13,7 +13,7 @@ <i class="icon-spin3 animate-spin"/> </div> <div v-else class="panel-body"> - <user-card v-for="user in users" :key="user.id" :user="user" :showFollows="true"></user-card> + <FollowCard v-for="user in users" :key="user.id" :user="user"/> </div> </div> </template> diff --git a/src/components/who_to_follow/who_to_follow.js b/src/components/who_to_follow/who_to_follow.js @@ -1,9 +1,9 @@ import apiService from '../../services/api/api.service.js' -import UserCard from '../user_card/user_card.vue' +import FollowCard from '../follow_card/follow_card.vue' const WhoToFollow = { components: { - UserCard + FollowCard }, data () { return { diff --git a/src/components/who_to_follow/who_to_follow.vue b/src/components/who_to_follow/who_to_follow.vue @@ -4,7 +4,7 @@ {{$t('who_to_follow.who_to_follow')}} </div> <div class="panel-body"> - <user-card v-for="user in users" :key="user.id" :user="user" :showFollows="true"></user-card> + <FollowCard v-for="user in users" :key="user.id" :user="user"/> </div> </div> </template> diff --git a/src/hocs/with_load_more/with_load_more.js b/src/hocs/with_load_more/with_load_more.js @@ -1,15 +1,17 @@ import Vue from 'vue' -import filter from 'lodash/filter' import isEmpty from 'lodash/isEmpty' +import { getComponentProps } from '../../services/component_utils/component_utils' import './with_load_more.scss' const withLoadMore = ({ fetch, // function to fetch entries and return a promise select, // function to select data from store - childPropName = 'entries' // name of the prop to be passed into the wrapped component + destroy, // function called at "destroyed" lifecycle + childPropName = 'entries', // name of the prop to be passed into the wrapped component + additionalPropNames = [] // additional prop name list of the wrapper component }) => (WrappedComponent) => { - const originalProps = WrappedComponent.props || [] - const props = filter(originalProps, v => v !== 'entries') + const originalProps = Object.keys(getComponentProps(WrappedComponent)) + const props = originalProps.filter(v => v !== childPropName).concat(additionalPropNames) return Vue.component('withLoadMore', { render (createElement) { @@ -56,6 +58,7 @@ const withLoadMore = ({ }, destroyed () { window.removeEventListener('scroll', this.scrollLoad) + destroy && destroy(this.$props, this.$store) }, methods: { fetchEntries () { diff --git a/src/hocs/with_subscription/with_subscription.js b/src/hocs/with_subscription/with_subscription.js @@ -1,16 +1,16 @@ import Vue from 'vue' -import reject from 'lodash/reject' import isEmpty from 'lodash/isEmpty' -import omit from 'lodash/omit' +import { getComponentProps } from '../../services/component_utils/component_utils' import './with_subscription.scss' const withSubscription = ({ fetch, // function to fetch entries and return a promise select, // function to select data from store - childPropName = 'content' // name of the prop to be passed into the wrapped component + childPropName = 'content', // name of the prop to be passed into the wrapped component + additionalPropNames = [] // additional prop name list of the wrapper component }) => (WrappedComponent) => { - const originalProps = WrappedComponent.props || [] - const props = reject(originalProps, v => v === 'content') + const originalProps = Object.keys(getComponentProps(WrappedComponent)) + const props = originalProps.filter(v => v !== childPropName).concat(additionalPropNames) return Vue.component('withSubscription', { props: [ @@ -21,7 +21,7 @@ const withSubscription = ({ if (!this.error && !this.loading) { const props = { props: { - ...omit(this.$props, 'refresh'), + ...this.$props, [childPropName]: this.fetchedData }, on: this.$listeners, diff --git a/src/modules/users.js b/src/modules/users.js @@ -72,14 +72,20 @@ export const mutations = { }, // 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] + clearFriends (state, userId) { + const user = state.usersObject[userId] if (!user) { return } user.friends = [] - user.followers = [] user.friendsPage = 0 + }, + clearFollowers (state, userId) { + const user = state.usersObject[userId] + if (!user) { + return + } + user.followers = [] user.followersPage = 0 }, addNewUsers (state, users) { @@ -189,20 +195,19 @@ const users = { }) }, 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() - }) - }) + const user = rootState.users.usersObject[fetchBy] + const page = user.followersPage || 1 + return rootState.api.backendInteractor.fetchFollowers({ id: user.id, page }) + .then((followers) => { + commit('addFollowers', { id: user.id, followers, page }) + return followers + }) + }, + clearFriends ({ commit }, userId) { + commit('clearFriends', userId) }, - clearFriendsAndFollowers ({ commit }, userKey) { - commit('clearFriendsAndFollowers', userKey) + clearFollowers ({ commit }, userId) { + commit('clearFollowers', userId) }, registerPushNotifications (store) { const token = store.state.currentUser.credentials diff --git a/src/services/component_utils/component_utils.js b/src/services/component_utils/component_utils.js @@ -0,0 +1,10 @@ +import isFunction from 'lodash/isFunction' + +const getComponentOptions = (Component) => (isFunction(Component)) ? Component.options : Component + +const getComponentProps = (Component) => getComponentOptions(Component).props + +export { + getComponentOptions, + getComponentProps +}