diff --git a/app/javascript/gabsocial/actions/groups.js b/app/javascript/gabsocial/actions/groups.js index 1c370ca6..8d27e8e7 100644 --- a/app/javascript/gabsocial/actions/groups.js +++ b/app/javascript/gabsocial/actions/groups.js @@ -133,20 +133,27 @@ export function fetchGroupRelationshipsFail(error) { }; export const fetchGroups = (tab) => (dispatch, getState) => { - if (!me) return; + if (!me) return - dispatch(fetchGroupsRequest()); + // Don't refetch or fetch when loading + const isLoading = getState().getIn(['group_lists', tab, 'loading']) + const isFetched = getState().getIn(['group_lists', tab, 'fetched']) + + if (isLoading || isFetched) return + + dispatch(fetchGroupsRequest(tab)) api(getState).get('/api/v1/groups?tab=' + tab) .then(({ data }) => { - dispatch(fetchGroupsSuccess(data, tab)); - dispatch(fetchGroupRelationships(data.map(item => item.id))); + dispatch(fetchGroupsSuccess(data, tab)) + dispatch(fetchGroupRelationships(data.map(item => item.id))) }) - .catch(err => dispatch(fetchGroupsFail(err))); -}; + .catch((err) => dispatch(fetchGroupsFail(err, tab))) +} -export const fetchGroupsRequest = () => ({ +export const fetchGroupsRequest = (tab) => ({ type: GROUPS_FETCH_REQUEST, + tab, }); export const fetchGroupsSuccess = (groups, tab) => ({ @@ -155,9 +162,10 @@ export const fetchGroupsSuccess = (groups, tab) => ({ tab, }); -export const fetchGroupsFail = error => ({ +export const fetchGroupsFail = (error, tab) => ({ type: GROUPS_FETCH_FAIL, error, + tab, }); export function joinGroup(id) { diff --git a/app/javascript/gabsocial/components/panel/groups_panel.js b/app/javascript/gabsocial/components/panel/groups_panel.js index b9c12054..f583a711 100644 --- a/app/javascript/gabsocial/components/panel/groups_panel.js +++ b/app/javascript/gabsocial/components/panel/groups_panel.js @@ -13,7 +13,7 @@ const messages = defineMessages({ }) const mapStateToProps = (state) => ({ - groupIds: state.getIn(['group_lists', 'member']), + groupIds: state.getIn(['group_lists', 'member', 'items']), }) const mapDispatchToProps = (dispatch) => ({ diff --git a/app/javascript/gabsocial/features/groups_collection.js b/app/javascript/gabsocial/features/groups_collection.js index 6a31d39d..1f2585a2 100644 --- a/app/javascript/gabsocial/features/groups_collection.js +++ b/app/javascript/gabsocial/features/groups_collection.js @@ -1,5 +1,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes' import ImmutablePureComponent from 'react-immutable-pure-component' +import { FormattedMessage } from 'react-intl' import { fetchGroups } from '../actions/groups' import { BREAKPOINT_EXTRA_SMALL } from '../constants' import Responsive from './ui/util/responsive_component' @@ -8,7 +9,9 @@ import ScrollableList from '../components/scrollable_list' import GroupCollectionItem from '../components/group_collection_item' const mapStateToProps = (state, { activeTab }) => ({ - groupIds: state.getIn(['group_lists', activeTab]), + groupIds: state.getIn(['group_lists', activeTab, 'items']), + isFetched: state.getIn(['group_lists', activeTab, 'isFetched']), + isLoading: state.getIn(['group_lists', activeTab, 'isLoading']), }) export default @@ -19,6 +22,8 @@ class GroupsCollection extends ImmutablePureComponent { activeTab: PropTypes.string.isRequired, dispatch: PropTypes.func.isRequired, groupIds: ImmutablePropTypes.list, + isFetched: PropTypes.bool.isRequired, + isLoading: PropTypes.bool.isRequired, } componentWillMount() { @@ -32,10 +37,16 @@ class GroupsCollection extends ImmutablePureComponent { } render() { - const { groupIds } = this.props + const { + groupIds, + isLoading, + isFetched, + } = this.props - if (!groupIds) { + if (isLoading && groupIds.size === 0) { return + } else if (isFetched && groupIds.size === 0) { + return } /> } const halfCount = parseInt(groupIds.size / 2) diff --git a/app/javascript/gabsocial/reducers/group_lists.js b/app/javascript/gabsocial/reducers/group_lists.js index ae10fa92..a65e8c32 100644 --- a/app/javascript/gabsocial/reducers/group_lists.js +++ b/app/javascript/gabsocial/reducers/group_lists.js @@ -1,22 +1,55 @@ import { Map as ImmutableMap, List as ImmutableList } from 'immutable' -import { GROUPS_FETCH_SUCCESS } from '../actions/groups' +import { + GROUPS_FETCH_REQUEST, + GROUPS_FETCH_SUCCESS, + GROUPS_FETCH_FAIL, +} from '../actions/groups' + +const tabs = ['new', 'featured', 'member', 'admin'] const initialState = ImmutableMap({ - new: ImmutableList(), - featured: ImmutableList(), - member: ImmutableList(), - admin: ImmutableList(), + new: ImmutableMap({ + fetched: false, + loading: false, + items: ImmutableList(), + }), + featured: ImmutableMap({ + fetched: false, + loading: false, + items: ImmutableList(), + }), + member: ImmutableMap({ + fetched: false, + loading: false, + items: ImmutableList(), + }), + admin: ImmutableMap({ + fetched: false, + loading: false, + items: ImmutableList(), + }), }) -const normalizeList = (state, type, id, groups) => { - return state.set(type, ImmutableList(groups.map(item => item.id))) -} - export default function groupLists(state = initialState, action) { + if (tabs.indexOf(action.tab) === -1) return state + switch(action.type) { + case GROUPS_FETCH_REQUEST: + return state.withMutations((mutable) => { + mutable.setIn([action.tab, 'loading'], true) + }); case GROUPS_FETCH_SUCCESS: - if (!action.tab) return state - return normalizeList(state, action.tab, action.id, action.groups) + return state.withMutations((mutable) => { + mutable.setIn([action.tab, 'items'], ImmutableList(action.groups.map(item => item.id))) + mutable.setIn([action.tab, 'loading'], false) + mutable.setIn([action.tab, 'fetched'], true) + }) + case GROUPS_FETCH_FAIL: + return state.withMutations((mutable) => { + mutable.setIn([action.tab, 'items'], ImmutableList()) + mutable.setIn([action.tab, 'loading'], false) + mutable.setIn([action.tab, 'fetched'], true) + }) default: return state }