diff --git a/app/gabsocial/components/more_follows.js b/app/gabsocial/components/more_follows.js new file mode 100644 index 000000000..86bc4ee45 --- /dev/null +++ b/app/gabsocial/components/more_follows.js @@ -0,0 +1,93 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import PropTypes from 'prop-types'; + +export default class MoreFollows extends React.PureComponent { + + static propTypes = { + visible: PropTypes.bool, + moreFollows: PropTypes.number, + isFollowing: PropTypes.bool, + } + + static defaultProps = { + visible: true, + } + + render() { + const { moreFollows, isFollowing, visible } = this.props; + + if (isFollowing === true && moreFollows === 1) { + return ( +
+
+
+ {moreFollows}, + }} + /> +
+
+
+ ); + } else if (isFollowing && moreFollows > 1) { + return ( +
+
+
+ {moreFollows}, + }} + /> +
+
+
+ ); + } else if (!isFollowing && moreFollows === 1) { + return ( +
+
+
+ {moreFollows}, + }} + /> +
+
+
+ ); + } else if (!isFollowing && moreFollows > 1) { + return ( +
+
+
+ {moreFollows}, + }} + /> +
+
+
+ ); + } else { + return (null); + } + } + +} diff --git a/app/gabsocial/components/scrollable_list.js b/app/gabsocial/components/scrollable_list.js index d9445c44f..ae796f16e 100644 --- a/app/gabsocial/components/scrollable_list.js +++ b/app/gabsocial/components/scrollable_list.js @@ -2,6 +2,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import IntersectionObserverArticleContainer from '../containers/intersection_observer_article_container'; import LoadMore from './load_more'; +import MoreFollows from './more_follows'; import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper'; import { throttle } from 'lodash'; import { List as ImmutableList } from 'immutable'; @@ -21,16 +22,18 @@ export default class ScrollableList extends PureComponent { isLoading: PropTypes.bool, showLoading: PropTypes.bool, hasMore: PropTypes.bool, + hasMoreFollows: PropTypes.number, prepend: PropTypes.node, alwaysPrepend: PropTypes.bool, emptyMessage: PropTypes.node, children: PropTypes.node, onScrollToTop: PropTypes.func, onScroll: PropTypes.func, + isFollowing: PropTypes.bool, }; state = { - cachedMediaWidth: 250, // Default media/card width using default Gab Social theme + cachedMediaWidth: 250, // Default media/card width using default theme }; intersectionObserverWrapper = new IntersectionObserverWrapper(); @@ -205,12 +208,13 @@ export default class ScrollableList extends PureComponent { } render() { - const { children, scrollKey, showLoading, isLoading, hasMore, prepend, alwaysPrepend, emptyMessage, onLoadMore } = this.props; + const { children, scrollKey, showLoading, isLoading, hasMore, hasMoreFollows, isFollowing, prepend, alwaysPrepend, emptyMessage, onLoadMore } = this.props; const childrenCount = React.Children.count(children); const trackScroll = true; //placeholder const loadMore = (hasMore && onLoadMore) ? : null; + const moreFollows = (hasMoreFollows !== undefined && isFollowing !== undefined) ? : null; let scrollableArea = null; if (showLoading) { @@ -248,7 +252,7 @@ export default class ScrollableList extends PureComponent { })} ))} - + {moreFollows} {loadMore} diff --git a/app/gabsocial/features/followers/index.js b/app/gabsocial/features/followers/index.js index 93a57cf4d..7fe3106c4 100644 --- a/app/gabsocial/features/followers/index.js +++ b/app/gabsocial/features/followers/index.js @@ -16,6 +16,7 @@ import AccountContainer from '../../containers/account_container'; import Column from '../ui/components/column'; import ScrollableList from '../../components/scrollable_list'; import MissingIndicator from 'gabsocial/components/missing_indicator'; +import { getHasMoreFollowsCount } from 'gabsocial/utils/accounts'; const mapStateToProps = (state, { params: { username }, withReplies = false }) => { const me = state.get('me'); @@ -30,6 +31,7 @@ const mapStateToProps = (state, { params: { username }, withReplies = false }) = accountId = account ? account.getIn(['id'], null) : -1; } + const hasMoreFollows = getHasMoreFollowsCount(state, accountId, false); const isBlocked = state.getIn(['relationships', accountId, 'blocked_by'], false); const isLocked = state.getIn(['accounts', accountId, 'locked'], false); const isFollowing = state.getIn(['relationships', accountId, 'following'], false); @@ -41,6 +43,7 @@ const mapStateToProps = (state, { params: { username }, withReplies = false }) = isAccount: !!state.getIn(['accounts', accountId]), accountIds: state.getIn(['user_lists', 'followers', accountId, 'items']), hasMore: !!state.getIn(['user_lists', 'followers', accountId, 'next']), + hasMoreFollows, }; }; @@ -52,6 +55,7 @@ class Followers extends ImmutablePureComponent { dispatch: PropTypes.func.isRequired, accountIds: ImmutablePropTypes.list, hasMore: PropTypes.bool, + hasMoreFollows: PropTypes.number, isAccount: PropTypes.bool, unavailable: PropTypes.bool, }; @@ -81,7 +85,8 @@ class Followers extends ImmutablePureComponent { }, 300, { leading: true }); render() { - const { accountIds, hasMore, isAccount, accountId, unavailable } = this.props; + const { accountIds, hasMore, hasMoreFollows, isAccount, accountId, unavailable } = this.props; + const isFollowing = false; if (!isAccount && accountId !== -1) { return ( @@ -114,6 +119,8 @@ class Followers extends ImmutablePureComponent { } > diff --git a/app/gabsocial/features/following/index.js b/app/gabsocial/features/following/index.js index 40befdd91..2952d7995 100644 --- a/app/gabsocial/features/following/index.js +++ b/app/gabsocial/features/following/index.js @@ -16,6 +16,7 @@ import AccountContainer from '../../containers/account_container'; import Column from '../ui/components/column'; import ScrollableList from '../../components/scrollable_list'; import MissingIndicator from 'gabsocial/components/missing_indicator'; +import { getHasMoreFollowsCount } from 'gabsocial/utils/accounts'; const mapStateToProps = (state, { params: { username }, withReplies = false }) => { const me = state.get('me'); @@ -30,6 +31,7 @@ const mapStateToProps = (state, { params: { username }, withReplies = false }) = accountId = account ? account.getIn(['id'], null) : -1; } + const hasMoreFollows = getHasMoreFollowsCount(state, accountId, true); const isBlocked = state.getIn(['relationships', accountId, 'blocked_by'], false); const isLocked = state.getIn(['accounts', accountId, 'locked'], false); const isFollowing = state.getIn(['relationships', accountId, 'following'], false); @@ -41,6 +43,7 @@ const mapStateToProps = (state, { params: { username }, withReplies = false }) = isAccount: !!state.getIn(['accounts', accountId]), accountIds: state.getIn(['user_lists', 'following', accountId, 'items']), hasMore: !!state.getIn(['user_lists', 'following', accountId, 'next']), + hasMoreFollows, }; }; @@ -54,6 +57,7 @@ class Following extends ImmutablePureComponent { hasMore: PropTypes.bool, isAccount: PropTypes.bool, unavailable: PropTypes.bool, + hasMoreFollows: PropTypes.number, }; componentWillMount() { @@ -81,7 +85,8 @@ class Following extends ImmutablePureComponent { }, 300, { leading: true }); render() { - const { accountIds, hasMore, isAccount, accountId, unavailable } = this.props; + const { accountIds, hasMore, isAccount, hasMoreFollows, accountId, unavailable } = this.props; + const isFollowing = true; if (!isAccount && accountId !== -1) { return ( @@ -114,6 +119,8 @@ class Following extends ImmutablePureComponent { } > diff --git a/app/gabsocial/utils/accounts.js b/app/gabsocial/utils/accounts.js index adc029981..2558d4357 100644 --- a/app/gabsocial/utils/accounts.js +++ b/app/gabsocial/utils/accounts.js @@ -1,4 +1,5 @@ import { Map as ImmutableMap } from 'immutable'; +import { List as ImmutableList } from 'immutable'; export const getDomain = account => { let re = /https?:\/\/(.*?)\//i; @@ -28,3 +29,18 @@ export const isAdmin = account => ( export const isModerator = account => ( account.getIn(['pleroma', 'is_moderator']) === true ); + +export const getHasMoreFollowsCount = (state, accountId, isFollowing) => { + let moreFollowsCount = undefined; //variable text in defaultMessage with null value preventing rendering + let emptyList = ImmutableList(); + if (isFollowing) { + let followingList = ImmutableList(); + followingList = state.getIn(['user_lists', 'following', accountId, 'items'], emptyList); + moreFollowsCount = parseInt(state.getIn(['accounts_counters', accountId, 'following_count']), 0) - followingList.size; + } else { + let followersList = ImmutableList(); + followersList = state.getIn(['user_lists', 'followers', accountId, 'items'], emptyList); + moreFollowsCount = parseInt(state.getIn(['accounts_counters', accountId, 'followers_count']), 0) - followersList.size; + } + return moreFollowsCount; +}; diff --git a/app/styles/gabsocial/components.scss b/app/styles/gabsocial/components.scss index 0d67b566f..28f9fb638 100644 --- a/app/styles/gabsocial/components.scss +++ b/app/styles/gabsocial/components.scss @@ -2339,6 +2339,34 @@ a.status-card.compact:hover { } } +.morefollows-indicator { + text-align: center; + font-size: 16px; + font-weight: 500; + color: $dark-text-color; + background: $ui-base-color; + cursor: default; + display: flex; + flex: 1 1 auto; + align-items: center; + justify-content: center; + padding: 20px; + + & > div { + width: 100%; + background: transparent; + padding-top: 0; + } + + &__label { + strong { + display: block; + margin-bottom: 10px; + color: $dark-text-color; + } + } +} + .columns-area--mobile .column {@include gab-container-standards();} .column-header__wrapper { position: relative;