diff --git a/src/components/basic_user_card/basic_user_card.vue b/src/components/basic_user_card/basic_user_card.vue
index 4ede15e9..77fb0aa0 100644
--- a/src/components/basic_user_card/basic_user_card.vue
+++ b/src/components/basic_user_card/basic_user_card.vue
@@ -1,26 +1,22 @@
-
+
-
-
-
- {{ user.name }}
-
-
-
- @{{user.screen_name}}
-
-
+
+
+ {{ user.name }}
-
-
+
+
+ @{{user.screen_name}}
+
+
@@ -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
index ed7fe30b..8eb56e25 100644
--- a/src/components/block_card/block_card.vue
+++ b/src/components/block_card/block_card.vue
@@ -1,6 +1,6 @@
-
+
-
+
-
\ No newline at end of file
+
+
+
diff --git a/src/components/follow_card/follow_card.js b/src/components/follow_card/follow_card.js
new file mode 100644
index 00000000..425c9c3e
--- /dev/null
+++ 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
new file mode 100644
index 00000000..6cb064eb
--- /dev/null
+++ b/src/components/follow_card/follow_card.vue
@@ -0,0 +1,53 @@
+
+
+
+
+ {{ isMe ? $t('user_card.its_you') : $t('user_card.follows_you') }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/follow_list/follow_list.js b/src/components/follow_list/follow_list.js
deleted file mode 100644
index 9777c87e..00000000
--- a/src/components/follow_list/follow_list.js
+++ /dev/null
@@ -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
deleted file mode 100644
index 27102edf..00000000
--- a/src/components/follow_list/follow_list.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js
new file mode 100644
index 00000000..1a00a1c1
--- /dev/null
+++ 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
new file mode 100644
index 00000000..4a3bbba4
--- /dev/null
+++ b/src/components/follow_request_card/follow_request_card.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/follow_requests/follow_requests.js b/src/components/follow_requests/follow_requests.js
index 11a228aa..d57dcbc7 100644
--- 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
index 87dc4194..b83c2d68 100644
--- a/src/components/follow_requests/follow_requests.vue
+++ b/src/components/follow_requests/follow_requests.vue
@@ -4,7 +4,7 @@
{{$t('nav.friend_requests')}}
-
+
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index 62536bc5..d986663e 100644
--- 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
deleted file mode 100644
index 28e22f09..00000000
--- a/src/components/user_card/user_card.js
+++ /dev/null
@@ -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
deleted file mode 100644
index ce4edb3c..00000000
--- a/src/components/user_card/user_card.vue
+++ /dev/null
@@ -1,159 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- {{ user.name }}
-
-
-
- @{{user.screen_name}}
-
-
-
-
-
- {{ currentUser.id == user.id ? $t('user_card.its_you') : $t('user_card.follows_you') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
index a3d24eb1..689b9ec6 100644
--- 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;
+ }
+}
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index ebf6c61a..7708141c 100644
--- 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
index ba1a7760..a3d2825f 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -18,16 +18,10 @@
:user-id="fetchBy"
/>
-
+
diff --git a/src/components/who_to_follow/who_to_follow.js b/src/components/who_to_follow/who_to_follow.js
index 82098fc2..be0b8827 100644
--- 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
index df2e03c8..1630f5ac 100644
--- 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')}}
-
+
diff --git a/src/hocs/with_load_more/with_load_more.js b/src/hocs/with_load_more/with_load_more.js
index e862a39b..74979b87 100644
--- 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
index 1ac67cba..679409cf 100644
--- 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
index eabfe5ae..093af497 100644
--- 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
+ })
},
- clearFriendsAndFollowers ({ commit }, userKey) {
- commit('clearFriendsAndFollowers', userKey)
+ clearFriends ({ commit }, userId) {
+ commit('clearFriends', userId)
+ },
+ 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
new file mode 100644
index 00000000..77ea14a1
--- /dev/null
+++ 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
+}