import { Map as ImmutableMap, List as ImmutableList, } from 'immutable' import debounce from 'lodash.debounce' import api, { getLinks } from '../api' import { me } from '../initial_state' import { importFetchedAccounts } from './importer' import { fetchRelationships } from './accounts' import { updateStatusStats } from './statuses' import { ACCEPTED_GROUP_TABS, GROUP_LIST_SORTING_TYPE_ALPHABETICAL, GROUP_LIST_SORTING_TYPE_MOST_POPULAR, } from '../constants' export const GROUP_FETCH_REQUEST = 'GROUP_FETCH_REQUEST' export const GROUP_FETCH_SUCCESS = 'GROUP_FETCH_SUCCESS' export const GROUP_FETCH_FAIL = 'GROUP_FETCH_FAIL' export const GROUP_RELATIONSHIPS_FETCH_REQUEST = 'GROUP_RELATIONSHIPS_FETCH_REQUEST' export const GROUP_RELATIONSHIPS_FETCH_SUCCESS = 'GROUP_RELATIONSHIPS_FETCH_SUCCESS' export const GROUP_RELATIONSHIPS_FETCH_FAIL = 'GROUP_RELATIONSHIPS_FETCH_FAIL' export const GROUPS_FETCH_REQUEST = 'GROUPS_FETCH_REQUEST' export const GROUPS_FETCH_SUCCESS = 'GROUPS_FETCH_SUCCESS' export const GROUPS_FETCH_FAIL = 'GROUPS_FETCH_FAIL' export const GROUP_JOIN_REQUEST = 'GROUP_JOIN_REQUEST' export const GROUP_JOIN_SUCCESS = 'GROUP_JOIN_SUCCESS' export const GROUP_JOIN_FAIL = 'GROUP_JOIN_FAIL' export const GROUP_LEAVE_REQUEST = 'GROUP_LEAVE_REQUEST' export const GROUP_LEAVE_SUCCESS = 'GROUP_LEAVE_SUCCESS' export const GROUP_LEAVE_FAIL = 'GROUP_LEAVE_FAIL' // export const GROUP_MEMBERS_FETCH_REQUEST = 'GROUP_MEMBERS_FETCH_REQUEST' export const GROUP_MEMBERS_FETCH_SUCCESS = 'GROUP_MEMBERS_FETCH_SUCCESS' export const GROUP_MEMBERS_FETCH_FAIL = 'GROUP_MEMBERS_FETCH_FAIL' export const GROUP_MEMBERS_EXPAND_REQUEST = 'GROUP_MEMBERS_EXPAND_REQUEST' export const GROUP_MEMBERS_EXPAND_SUCCESS = 'GROUP_MEMBERS_EXPAND_SUCCESS' export const GROUP_MEMBERS_EXPAND_FAIL = 'GROUP_MEMBERS_EXPAND_FAIL' export const GROUP_MEMBERS_SEARCH_SUCCESS = 'GROUP_MEMBERS_SEARCH_SUCCESS' export const CLEAR_GROUP_MEMBERS_SEARCH = 'CLEAR_GROUP_MEMBERS_SEARCH' // export const GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST = 'GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST' export const GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS' export const GROUP_REMOVED_ACCOUNTS_FETCH_FAIL = 'GROUP_REMOVED_ACCOUNTS_FETCH_FAIL' export const GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST = 'GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST' export const GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS' export const GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL = 'GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL' export const GROUP_REMOVED_ACCOUNTS_SEARCH_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_SEARCH_SUCCESS' export const CLEAR_GROUP_REMOVED_ACCOUNTS_SEARCH = 'CLEAR_GROUP_REMOVED_ACCOUNTS_SEARCH' // export const GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST = 'GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST' export const GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS' export const GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL = 'GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL' export const GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST = 'GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST' export const GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS' export const GROUP_REMOVED_ACCOUNTS_CREATE_FAIL = 'GROUP_REMOVED_ACCOUNTS_CREATE_FAIL' // export const GROUP_JOIN_REQUESTS_FETCH_REQUEST = 'GROUP_JOIN_REQUESTS_FETCH_REQUEST' export const GROUP_JOIN_REQUESTS_FETCH_SUCCESS = 'GROUP_JOIN_REQUESTS_FETCH_SUCCESS' export const GROUP_JOIN_REQUESTS_FETCH_FAIL = 'GROUP_JOIN_REQUESTS_FETCH_FAIL' export const GROUP_JOIN_REQUESTS_EXPAND_REQUEST = 'GROUP_JOIN_REQUESTS_EXPAND_REQUEST' export const GROUP_JOIN_REQUESTS_EXPAND_SUCCESS = 'GROUP_JOIN_REQUESTS_EXPAND_SUCCESS' export const GROUP_JOIN_REQUESTS_EXPAND_FAIL = 'GROUP_JOIN_REQUESTS_EXPAND_FAIL' export const GROUP_JOIN_REQUESTS_APPROVE_SUCCESS = 'GROUP_JOIN_REQUESTS_APPROVE_SUCCESS' export const GROUP_JOIN_REQUESTS_APPROVE_FAIL = 'GROUP_JOIN_REQUESTS_APPROVE_FAIL' export const GROUP_JOIN_REQUESTS_REJECT_SUCCESS = 'GROUP_JOIN_REQUESTS_REJECT_SUCCESS' export const GROUP_JOIN_REQUESTS_REJECT_FAIL = 'GROUP_JOIN_REQUESTS_REJECT_FAIL' export const GROUP_REMOVE_STATUS_REQUEST = 'GROUP_REMOVE_STATUS_REQUEST' export const GROUP_REMOVE_STATUS_SUCCESS = 'GROUP_REMOVE_STATUS_SUCCESS' export const GROUP_REMOVE_STATUS_FAIL = 'GROUP_REMOVE_STATUS_FAIL' export const GROUP_UPDATE_ROLE_REQUEST = 'GROUP_UPDATE_ROLE_REQUEST' export const GROUP_UPDATE_ROLE_SUCCESS = 'GROUP_UPDATE_ROLE_SUCCESS' export const GROUP_UPDATE_ROLE_FAIL = 'GROUP_UPDATE_ROLE_FAIL' export const GROUP_CHECK_PASSWORD_RESET = 'GROUP_CHECK_PASSWORD_RESET' export const GROUP_CHECK_PASSWORD_REQUEST = 'GROUP_CHECK_PASSWORD_REQUEST' export const GROUP_CHECK_PASSWORD_SUCCESS = 'GROUP_CHECK_PASSWORD_SUCCESS' export const GROUP_CHECK_PASSWORD_FAIL = 'GROUP_CHECK_PASSWORD_FAIL' export const GROUP_PIN_STATUS_REQUEST = 'GROUP_PIN_STATUS_REQUEST' export const GROUP_PIN_STATUS_SUCCESS = 'GROUP_PIN_STATUS_SUCCESS' export const GROUP_PIN_STATUS_FAIL = 'GROUP_PIN_STATUS_FAIL' export const GROUP_UNPIN_STATUS_REQUEST = 'GROUP_UNPIN_STATUS_REQUEST' export const GROUP_UNPIN_STATUS_SUCCESS = 'GROUP_UNPIN_STATUS_SUCCESS' export const GROUP_UNPIN_STATUS_FAIL = 'GROUP_UNPIN_STATUS_FAIL' export const IS_PINNED_GROUP_STATUS_REQUEST = 'IS_PINNED_GROUP_STATUS_REQUEST' export const IS_PINNED_GROUP_STATUS_SUCCESS = 'IS_PINNED_GROUP_STATUS_SUCCESS' export const IS_PINNED_GROUP_STATUS_FAIL = 'IS_PINNED_GROUP_STATUS_FAIL' export const GROUPS_BY_CATEGORY_FETCH_REQUEST = 'GROUPS_BY_CATEGORY_FETCH_REQUEST' export const GROUPS_BY_CATEGORY_FETCH_SUCCESS = 'GROUPS_BY_CATEGORY_FETCH_SUCCESS' export const GROUPS_BY_CATEGORY_FETCH_FAIL = 'GROUPS_BY_CATEGORY_FETCH_FAIL' export const GROUPS_BY_TAG_FETCH_REQUEST = 'GROUPS_BY_TAG_FETCH_REQUEST' export const GROUPS_BY_TAG_FETCH_SUCCESS = 'GROUPS_BY_TAG_FETCH_SUCCESS' export const GROUPS_BY_TAG_FETCH_FAIL = 'GROUPS_BY_TAG_FETCH_FAIL' export const GROUP_TIMELINE_SORT = 'GROUP_TIMELINE_SORT' export const GROUP_TIMELINE_TOP_SORT = 'GROUP_TIMELINE_TOP_SORT' export const GROUP_SORT = 'GROUP_SORT' /** * @description Import a group into redux * @param {ImmutableMap} group */ export const importGroup = (group) => (dispatch) => { dispatch(fetchGroupSuccess(group)) } export const importGroups = (groups) => (dispatch) => { if (!Array.isArray(groups)) return groups.map((group) => dispatch(fetchGroupSuccess(group))) } /** * @description Fetch a group with the given groupId * @param {string} groupId */ export const fetchGroup = (groupId) => (dispatch, getState) => { if (!groupId) return dispatch(fetchGroupRelationships([groupId])) // Check if exists already if (getState().getIn(['groups', groupId])) return dispatch(fetchGroupRequest(groupId)) api(getState).get(`/api/v1/groups/${groupId}`) .then((response) => dispatch(fetchGroupSuccess(response.data))) .catch((err) => dispatch(fetchGroupFail(groupId, err))) } const fetchGroupRequest = (groupId) => ({ type: GROUP_FETCH_REQUEST, groupId, }) const fetchGroupSuccess = (group) => ({ type: GROUP_FETCH_SUCCESS, group, }) const fetchGroupFail = (groupId, error) => ({ type: GROUP_FETCH_FAIL, showToast: true, groupId, error, }) /** * @description Fetch relationships for the given groupIds and current user. For example * if the current user is a member, admin, mod or not. * @param {Array} groupIds */ export const fetchGroupRelationships = (groupIds) => (dispatch, getState) => { if (!me || !Array.isArray(groupIds)) return const loadedRelationships = getState().get('group_relationships') const newGroupIds = groupIds.filter((id) => loadedRelationships.get(id, null) === null) if (newGroupIds.length === 0) return dispatch(fetchGroupRelationshipsRequest(newGroupIds)) api(getState).get(`/api/v1/groups/${newGroupIds[0]}/relationships?${newGroupIds.map(id => `id[]=${id}`).join('&')}`).then((response) => { dispatch(fetchGroupRelationshipsSuccess(response.data)) }).catch((error) => { dispatch(fetchGroupRelationshipsFail(error)) }) } const fetchGroupRelationshipsRequest = (groupIds) => ({ type: GROUP_RELATIONSHIPS_FETCH_REQUEST, groupIds, }) const fetchGroupRelationshipsSuccess = (relationships) => ({ type: GROUP_RELATIONSHIPS_FETCH_SUCCESS, relationships, }) const fetchGroupRelationshipsFail = (error) => ({ type: GROUP_RELATIONSHIPS_FETCH_FAIL, error, }) /** * @description Fetch all groups (limited uniquely per tab, non paginated) by tab. Import * groups and fetch relationships for each if tab !== member. * @param {String} tab */ export const fetchGroupsByTab = (tab) => (dispatch, getState) => { if (!me && tab !== 'featured' || ACCEPTED_GROUP_TABS.indexOf(tab) === -1) return // Don't refetch or fetch when loading const isLoading = getState().getIn(['group_lists', tab, 'isLoading']) const isFetched = getState().getIn(['group_lists', tab, 'isFetched']) if (isLoading || isFetched) return dispatch(fetchGroupsRequest(tab)) api(getState).get(`/api/v1/groups?tab=${tab}`) .then((response) => { dispatch(fetchGroupsSuccess(response.data, tab)) if (tab !== 'member') { dispatch(fetchGroupRelationships(response.data.map(item => item.id))) } }) .catch((err) => dispatch(fetchGroupsFail(err, tab))) } const fetchGroupsRequest = (tab) => ({ type: GROUPS_FETCH_REQUEST, tab, }) export const fetchGroupsSuccess = (groups, tab) => ({ type: GROUPS_FETCH_SUCCESS, groups, tab, }) const fetchGroupsFail = (error, tab) => ({ type: GROUPS_FETCH_FAIL, showToast: true, error, tab, }) /** * @description Fetch all groups (limited to 100, non paginated) by category. Import groups * and fetch relationships for each. * @param {String} category */ export const fetchGroupsByCategory = (category) => (dispatch, getState) => { if (!category) return // Don't refetch or fetch when loading const isLoading = getState().getIn(['group_lists', 'by_category', category, 'isLoading'], false) if (isLoading) return dispatch(fetchGroupsByCategoryRequest(category)) api(getState).get(`/api/v1/groups/_/category/${category}`) .then((response) => { dispatch(fetchGroupsByCategorySuccess(response.data, category)) dispatch(fetchGroupRelationships(response.data.map(item => item.id))) }) .catch((err) => dispatch(fetchGroupsByCategoryFail(err, category))) } const fetchGroupsByCategoryRequest = (category) => ({ type: GROUPS_BY_CATEGORY_FETCH_REQUEST, category, }) const fetchGroupsByCategorySuccess = (groups, category) => ({ type: GROUPS_BY_CATEGORY_FETCH_SUCCESS, groups, category, }) const fetchGroupsByCategoryFail = (error, category) => ({ type: GROUPS_BY_CATEGORY_FETCH_FAIL, showToast: true, error, category, }) /** * @description Fetch all groups (limited to 100, non paginated) by tag. Import groups * and fetch relationships for each. * @param {String} tag */ export const fetchGroupsByTag = (tag) => (dispatch, getState) => { if (!tag) return // Don't refetch or fetch when loading const isLoading = getState().getIn(['group_lists', 'by_tag', tag, 'isLoading'], false) if (isLoading) return dispatch(fetchGroupsByTagRequest(tag)) api(getState).get(`/api/v1/groups/_/tag/${tag}`) .then((response) => { dispatch(fetchGroupsByTagSuccess(response.data, tag)) dispatch(fetchGroupRelationships(response.data.map(item => item.id))) }) .catch((err) => dispatch(fetchGroupsByTagFail(err, tag))) } export const fetchGroupsByTagRequest = (tag) => ({ type: GROUPS_BY_TAG_FETCH_REQUEST, tag, }) export const fetchGroupsByTagSuccess = (groups, tag) => ({ type: GROUPS_BY_TAG_FETCH_SUCCESS, groups, tag, }) export const fetchGroupsByTagFail = (error, tag) => ({ type: GROUPS_BY_TAG_FETCH_FAIL, showToast: true, error, tag, }) /** * @description Join group with the given groupId and return group relationships * @param {String} groupId */ export const joinGroup = (groupId) => (dispatch, getState) => { if (!me || !groupId) return dispatch(joinGroupRequest(groupId)) api(getState).post(`/api/v1/groups/${groupId}/accounts`).then((response) => { dispatch(joinGroupSuccess(response.data)) }).catch((error) => { dispatch(joinGroupFail(groupId, error)) }) } const joinGroupRequest = (groupId) => ({ type: GROUP_JOIN_REQUEST, groupId, }) const joinGroupSuccess = (relationship) => ({ type: GROUP_JOIN_SUCCESS, showToast: true, relationship }) const joinGroupFail = (error) => ({ type: GROUP_JOIN_FAIL, showToast: true, error, }) /** * @description Leave group with the given groupId and return group relationships * @param {String} groupId */ export const leaveGroup = (groupId) => (dispatch, getState) => { if (!me || !groupId) return dispatch(leaveGroupRequest(groupId)) api(getState).delete(`/api/v1/groups/${groupId}/accounts`).then((response) => { dispatch(leaveGroupSuccess(response.data)) }).catch((error) => { dispatch(leaveGroupFail(groupId, error)) }) } const leaveGroupRequest = (groupId) => ({ type: GROUP_LEAVE_REQUEST, groupId, }) const leaveGroupSuccess = (relationship) => ({ type: GROUP_LEAVE_SUCCESS, showToast: true, relationship, }) const leaveGroupFail = (error) => ({ type: GROUP_LEAVE_FAIL, showToast: true, error, }) /** * @description Fetch members for the given groupId and imports paginated accounts * and sets in user_lists reducer. * @param {String} groupId */ export const fetchMembers = (groupId) => (dispatch, getState) => { if (!me || !groupId) return dispatch(fetchMembersRequest(groupId)) api(getState).get(`/api/v1/groups/${groupId}/accounts`).then((response) => { const next = getLinks(response).refs.find(link => link.rel === 'next') dispatch(importFetchedAccounts(response.data)) dispatch(fetchMembersSuccess(groupId, response.data, next ? next.uri : null)) dispatch(fetchRelationships(response.data.map(item => item.id))) }).catch((error) => { dispatch(fetchMembersFail(groupId, error)) }) } const fetchMembersRequest = (groupId) => ({ type: GROUP_MEMBERS_FETCH_REQUEST, groupId, }) const fetchMembersSuccess = (groupId, accounts, next) => ({ type: GROUP_MEMBERS_FETCH_SUCCESS, groupId, accounts, next, }) const fetchMembersFail = (groupId, error) => ({ type: GROUP_MEMBERS_FETCH_FAIL, showToast: true, groupId, error, }) /** * @description Expand members for the given groupId and imports paginated accounts * and sets in user_lists reducer. * @param {String} groupId */ export const expandMembers = (groupId) => (dispatch, getState) => { if (!me || !groupId) return const url = getState().getIn(['user_lists', 'groups', groupId, 'next']) const isLoading = getState().getIn(['user_lists', 'groups', groupId, 'isLoading']) if (url === null || isLoading) return dispatch(expandMembersRequest(groupId)) api(getState).get(url).then((response) => { const next = getLinks(response).refs.find(link => link.rel === 'next') dispatch(importFetchedAccounts(response.data)) dispatch(expandMembersSuccess(groupId, response.data, next ? next.uri : null)) dispatch(fetchRelationships(response.data.map(item => item.id))) }).catch((error) => { dispatch(expandMembersFail(groupId, error)) }) } const expandMembersRequest = (groupId) => ({ type: GROUP_MEMBERS_EXPAND_REQUEST, groupId, }) const expandMembersSuccess = (groupId, accounts, next) => ({ type: GROUP_MEMBERS_EXPAND_SUCCESS, groupId, accounts, next, }) const expandMembersFail = (groupId, error) => ({ type: GROUP_MEMBERS_EXPAND_FAIL, showToast: true, groupId, error, }) /** * */ export const fetchGroupMembersAdminSearch = (groupId, query) => (dispatch, getState) => { if (!groupId || !query) return debouncedFetchGroupMembersAdminSearch(groupId, query, dispatch, getState) } export const debouncedFetchGroupMembersAdminSearch = debounce((groupId, query, dispatch, getState) => { if (!groupId || !query) return api(getState).get(`/api/v1/groups/${groupId}/member_search`, { params: { q: query }, }).then((response) => { dispatch(importFetchedAccounts(response.data)) dispatch(fetchGroupMembersAdminSearchSuccess(response.data)) }).catch((error) => { // }) }, 650, { leading: true }) const fetchGroupMembersAdminSearchSuccess = (accounts) => ({ type: GROUP_MEMBERS_SEARCH_SUCCESS, accounts, }) /** * */ export const clearGroupMembersAdminSearch = () => (dispatch) => { dispatch({ type: CLEAR_GROUP_MEMBERS_SEARCH }) } /** * @description Fetch removed accounts for the given groupId and imports paginated * accounts and sets in user_lists reducer. * @param {String} groupId */ export const fetchRemovedAccounts = (groupId) => (dispatch, getState) => { if (!me || !groupId) return dispatch(fetchRemovedAccountsRequest(groupId)) api(getState).get(`/api/v1/groups/${groupId}/removed_accounts`).then((response) => { const next = getLinks(response).refs.find(link => link.rel === 'next') dispatch(importFetchedAccounts(response.data)) dispatch(fetchRemovedAccountsSuccess(groupId, response.data, next ? next.uri : null)) dispatch(fetchRelationships(response.data.map(item => item.id))) }).catch((error) => { dispatch(fetchRemovedAccountsFail(groupId, error)) }) } const fetchRemovedAccountsRequest = (groupId) => ({ type: GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST, groupId, }) const fetchRemovedAccountsSuccess = (groupId, accounts, next) => ({ type: GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS, groupId, accounts, next, }) const fetchRemovedAccountsFail = (groupId, error) => ({ type: GROUP_REMOVED_ACCOUNTS_FETCH_FAIL, showToast: true, groupId, error, }) /** * @description Expand likes for the given statusId and imports paginated accounts * and sets in user_lists reducer. * @param {String} statusId */ export const expandRemovedAccounts = (groupId) => (dispatch, getState) => { if (!me || !groupId) return const url = getState().getIn(['user_lists', 'group_removed_accounts', groupId, 'next']) const isLoading = getState().getIn(['user_lists', 'group_removed_accounts', groupId, 'isLoading']) if (url === null || isLoading) return dispatch(expandRemovedAccountsRequest(groupId)) api(getState).get(url).then((response) => { const next = getLinks(response).refs.find(link => link.rel === 'next') dispatch(importFetchedAccounts(response.data)) dispatch(expandRemovedAccountsSuccess(groupId, response.data, next ? next.uri : null)) dispatch(fetchRelationships(response.data.map(item => item.id))) }).catch((error) => { dispatch(expandRemovedAccountsFail(groupId, error)) }) } const expandRemovedAccountsRequest = (groupId) => ({ type: GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST, groupId, }) const expandRemovedAccountsSuccess = (groupId, accounts, next) => ({ type: GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS, groupId, accounts, next, }) const expandRemovedAccountsFail = (groupId, error) => ({ type: GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL, showToast: true, groupId, error, }) /** * */ export const fetchGroupRemovedAccountsAdminSearch = (groupId, query) => (dispatch, getState) => { if (!groupId || !query) return debouncedFetchGroupRemovedAccountsAdminSearch(groupId, query, dispatch, getState) } export const debouncedFetchGroupRemovedAccountsAdminSearch = debounce((groupId, query, dispatch, getState) => { if (!groupId || !query) return api(getState).get(`/api/v1/groups/${groupId}/removed_accounts_search`, { params: { q: query }, }).then((response) => { dispatch(importFetchedAccounts(response.data)) dispatch(fetchGroupRemovedAccountsAdminSearchSuccess(response.data)) }).catch((error) => { // }) }, 650, { leading: true }) const fetchGroupRemovedAccountsAdminSearchSuccess = (accounts) => ({ type: GROUP_REMOVED_ACCOUNTS_SEARCH_SUCCESS, accounts, }) /** * */ export const clearGroupRemovedAccountsAdminSearch = () => (dispatch) => { dispatch({ type: CLEAR_GROUP_REMOVED_ACCOUNTS_SEARCH }) } /** * @description Remove a "removed account" from a group with the given groupId and accountId. * @param {String} groupId * @param {String} accountId */ export const removeRemovedAccount = (groupId, accountId) => (dispatch, getState) => { if (!me || !groupId || !accountId) return dispatch(removeRemovedAccountRequest(groupId, accountId)) api(getState).delete(`/api/v1/groups/${groupId}/removed_accounts?account_id=${accountId}`).then((response) => { dispatch(removeRemovedAccountSuccess(groupId, accountId)) }).catch((error) => { dispatch(removeRemovedAccountFail(groupId, accountId, error)) }) } const removeRemovedAccountRequest = (groupId, accountId) => ({ type: GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST, groupId, accountId, }) const removeRemovedAccountSuccess = (groupId, accountId) => ({ type: GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS, showToast: true, groupId, accountId, }) const removeRemovedAccountFail = (groupId, accountId, error) => ({ type: GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL, showToast: true, groupId, accountId, error, }) /** * @description Remove an account with given accountId from group with given groupId * @param {String} groupId * @param {String} accountId */ export const createRemovedAccount = (groupId, accountId) => (dispatch, getState) => { if (!me) return dispatch(createRemovedAccountRequest(groupId, accountId)) api(getState).post(`/api/v1/groups/${groupId}/removed_accounts?account_id=${accountId}`).then((response) => { dispatch(createRemovedAccountSuccess(groupId, accountId)) }).catch((error) => { dispatch(createRemovedAccountFail(groupId, accountId, error)) }) } const createRemovedAccountRequest = (groupId, accountId) => ({ type: GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST, groupId, accountId, }) const createRemovedAccountSuccess = (groupId, accountId) => ({ type: GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS, showToast: true, groupId, accountId, }) const createRemovedAccountFail = (groupId, accountId, error) => ({ type: GROUP_REMOVED_ACCOUNTS_CREATE_FAIL, showToast: true, groupId, accountId, error, }) /** * @description Remove a status from a group with given groupId and statusId. Then * remove the status from the group timeline on success. * @param {String} groupId * @param {String} statusId */ export const groupRemoveStatus = (groupId, statusId) => (dispatch, getState) => { if (!me || !groupId || !statusId) return dispatch(groupRemoveStatusRequest(groupId, statusId)) api(getState).delete(`/api/v1/groups/${groupId}/statuses/${statusId}`).then((response) => { dispatch(groupRemoveStatusSuccess(groupId, statusId)) }).catch((error) => { dispatch(groupRemoveStatusFail(groupId, statusId, error)) }) } const groupRemoveStatusRequest = (groupId, statusId) => ({ type: GROUP_REMOVE_STATUS_REQUEST, groupId, statusId, }) const groupRemoveStatusSuccess = (groupId, statusId) => ({ type: GROUP_REMOVE_STATUS_SUCCESS, showToast: true, groupId, statusId, }) const groupRemoveStatusFail = (groupId, statusId, error) => ({ type: GROUP_REMOVE_STATUS_FAIL, showToast: true, groupId, statusId, error, }) /** * @description Update role to admin, moderator for given accountId in given groupId * @param {String} groupId * @param {String} accountId * @param {String} role */ export const updateRole = (groupId, accountId, role) => (dispatch, getState) => { if (!me || !groupId || !accountId || !role) return dispatch(updateRoleRequest(groupId, accountId)) api(getState).patch(`/api/v1/groups/${groupId}/accounts?account_id=${accountId}`, { role }).then((response) => { dispatch(updateRoleSuccess(groupId, accountId)) }).catch((error) => { dispatch(updateRoleFail(groupId, accountId, error)) }) } const updateRoleRequest = (groupId, accountId) => ({ type: GROUP_UPDATE_ROLE_REQUEST, groupId, accountId, }) const updateRoleSuccess = (groupId, accountId) => ({ type: GROUP_UPDATE_ROLE_SUCCESS, showToast: true, groupId, accountId, }) const updateRoleFail = (groupId, accountId, error) => ({ type: GROUP_UPDATE_ROLE_FAIL, showToast: true, groupId, accountId, error, }) /** * @description Reset the group password check map when group password model opens */ export const checkGroupPasswordReset = () => ({ type: GROUP_CHECK_PASSWORD_RESET, }) /** * */ export const checkGroupPassword = (groupId, password) => (dispatch, getState) => { if (!me || !groupId) return dispatch(checkGroupPasswordRequest()) api(getState).post(`/api/v1/groups/${groupId}/password`, { password }).then((response) => { dispatch(joinGroupSuccess(response.data)) dispatch(checkGroupPasswordSuccess()) }).catch((error) => { dispatch(checkGroupPasswordFail(error)) }) } const checkGroupPasswordRequest = () => ({ type: GROUP_CHECK_PASSWORD_REQUEST, }) const checkGroupPasswordSuccess = () => ({ type: GROUP_CHECK_PASSWORD_SUCCESS, }) export const checkGroupPasswordFail = (error) => ({ type: GROUP_CHECK_PASSWORD_FAIL, error, }) /** * */ export const fetchJoinRequests = (id) => (dispatch, getState) => { if (!me) return dispatch(fetchJoinRequestsRequest(id)) api(getState).get(`/api/v1/groups/${id}/join_requests`).then((response) => { const next = getLinks(response).refs.find(link => link.rel === 'next') dispatch(importFetchedAccounts(response.data)) dispatch(fetchJoinRequestsSuccess(id, response.data, next ? next.uri : null)) dispatch(fetchRelationships(response.data.map(item => item.id))) }).catch((error) => { dispatch(fetchJoinRequestsFail(id, error)) }) } const fetchJoinRequestsRequest = (id) => ({ type: GROUP_JOIN_REQUESTS_FETCH_REQUEST, id, }) const fetchJoinRequestsSuccess = (id, accounts, next) => ({ type: GROUP_JOIN_REQUESTS_FETCH_SUCCESS, id, accounts, next, }) const fetchJoinRequestsFail = (id, error) => ({ type: GROUP_JOIN_REQUESTS_FETCH_FAIL, showToast: true, id, error, }) /** * */ export const expandJoinRequests = (id) => (dispatch, getState) => { if (!me) return const url = getState().getIn(['user_lists', 'group_join_requests', id, 'next']) const isLoading = getState().getIn(['user_lists', 'group_join_requests', id, 'isLoading']) if (url === null || isLoading) return dispatch(expandJoinRequestsRequest(id)) api(getState).get(url).then((response) => { const next = getLinks(response).refs.find(link => link.rel === 'next') dispatch(importFetchedAccounts(response.data)) dispatch(expandJoinRequestsSuccess(id, response.data, next ? next.uri : null)) dispatch(fetchRelationships(response.data.map(item => item.id))) }).catch((error) => { dispatch(expandJoinRequestsFail(id, error)) }) } const expandJoinRequestsRequest = (id) => ({ type: GROUP_JOIN_REQUESTS_EXPAND_REQUEST, id, }) const expandJoinRequestsSuccess = (id, accounts, next) => ({ type: GROUP_JOIN_REQUESTS_EXPAND_SUCCESS, id, accounts, next, }) const expandJoinRequestsFail = (id, error) => ({ type: GROUP_JOIN_REQUESTS_EXPAND_FAIL, showToast: true, id, error, }) /** * */ export const approveJoinRequest = (accountId, groupId) => (dispatch, getState) => { if (!me) return api(getState).post(`/api/v1/groups/${groupId}/join_requests/respond`, { accountId, type: 'approve' }).then((response) => { dispatch(approveJoinRequestSuccess(response.data.accountId, groupId)) }).catch((error) => { dispatch(approveJoinRequestFail(accountId, groupId, error)) }) } const approveJoinRequestSuccess = (accountId, groupId) => ({ type: GROUP_JOIN_REQUESTS_APPROVE_SUCCESS, showToast: true, accountId, groupId, }) const approveJoinRequestFail = (accountId, groupId, error) => ({ type: GROUP_JOIN_REQUESTS_APPROVE_FAIL, showToast: true, accountId, groupId, error, }) /** * */ export const rejectJoinRequest = (accountId, groupId) => (dispatch, getState) => { if (!me) return api(getState).post(`/api/v1/groups/${groupId}/join_requests/respond`, { accountId, type: 'reject' }).then((response) => { dispatch(rejectJoinRequestSuccess(response.data.accountId, groupId)) }).catch((error) => { dispatch(rejectJoinRequestFail(accountId, groupId, error)) }) } const rejectJoinRequestSuccess = (accountId, groupId) => ({ type: GROUP_JOIN_REQUESTS_REJECT_SUCCESS, showToast: true, accountId, groupId, }) const rejectJoinRequestFail = (accountId, groupId, error) => ({ type: GROUP_JOIN_REQUESTS_REJECT_FAIL, showToast: true, accountId, groupId, error, }) /** * */ export const pinGroupStatus = (groupId, statusId) => (dispatch, getState) => { if (!me || !groupId || !statusId) return dispatch(pinGroupStatusRequest(groupId)) api(getState).post(`/api/v1/groups/${groupId}/pin`, { statusId }).then((response) => { dispatch(updateStatusStats(response.data)) dispatch(pinGroupStatusSuccess(groupId, statusId)) }).catch((error) => { dispatch(pinGroupStatusFail(groupId, statusId, error)) }) } const pinGroupStatusRequest = (groupId) => ({ type: GROUP_PIN_STATUS_REQUEST, groupId, }) const pinGroupStatusSuccess = (groupId, statusId) => ({ type: GROUP_PIN_STATUS_SUCCESS, showToast: true, groupId, statusId, }) const pinGroupStatusFail = (groupId, statusId, error) => ({ type: GROUP_PIN_STATUS_FAIL, showToast: true, groupId, statusId, error, }) /** * */ export const unpinGroupStatus = (groupId, statusId) =>(dispatch, getState) => { if (!me || !groupId || !statusId) return dispatch(unpinGroupStatusRequest(groupId)) api(getState).post(`/api/v1/groups/${groupId}/unpin`, { statusId }).then((response) => { dispatch(updateStatusStats(response.data)) dispatch(unpinGroupStatusSuccess(groupId, statusId)) }).catch((error) => { dispatch(unpinGroupStatusFail(groupId, statusId, error)) }) } const unpinGroupStatusRequest = (groupId) => ({ type: GROUP_UNPIN_STATUS_REQUEST, groupId, }) const unpinGroupStatusSuccess = (groupId, statusId) => ({ type: GROUP_UNPIN_STATUS_SUCCESS, showToast: true, groupId, statusId, }) const unpinGroupStatusFail = (groupId, statusId, error) => ({ type: GROUP_UNPIN_STATUS_FAIL, showToast: true, groupId, statusId, error, }) /** * */ export const isPinnedGroupStatus = (groupId, statusId) => (dispatch, getState) => { if (!me || !groupId || !statusId) return dispatch(isPinnedGroupStatusRequest(groupId, statusId)) api(getState).get(`/api/v1/groups/${groupId}/pin?statusId=${statusId}`).then((response) => { dispatch(updateStatusStats(response.data)) }).catch((error) => { dispatch(isPinnedGroupStatusFail(groupId, statusId, error)) }) } const isPinnedGroupStatusRequest = (groupId, statusId) => ({ type: IS_PINNED_GROUP_STATUS_REQUEST, groupId, statusId, }) const isPinnedGroupStatusSuccess = (groupId, statusId) => ({ type: IS_PINNED_GROUP_STATUS_SUCCESS, groupId, statusId, }) const isPinnedGroupStatusFail = (groupId, statusId, error) => ({ type: IS_PINNED_GROUP_STATUS_FAIL, groupId, statusId, error, }) /** * */ export const sortGroups = (tab, sortType) => (dispatch, getState) => { const groupIdsByTab = getState().getIn(['group_lists', tab, 'items'], ImmutableList()).toJS() const allGroups = getState().get('groups', ImmutableMap()).toJS() let groupsByTab = [] for (const key in allGroups) { const block = allGroups[key] if (groupIdsByTab.indexOf(block.id > -1)) { groupsByTab.push(block) } } if (sortType === GROUP_LIST_SORTING_TYPE_ALPHABETICAL) { groupsByTab.sort((a, b) => a.title.localeCompare(b.title)) } else if (sortType === GROUP_LIST_SORTING_TYPE_MOST_POPULAR) { groupsByTab.sort((a, b) => (a.member_count < b.member_count) ? 1 : -1) } const sortedGroupsIdsByTab = groupsByTab.map((group) => group.id) dispatch(groupsSort(tab, sortedGroupsIdsByTab)) } export const groupsSort = (tab, groupIds) =>({ type: GROUP_SORT, tab, groupIds, }) export const setGroupTimelineSort = (sortValue) => (dispatch) => { dispatch({ type: GROUP_TIMELINE_SORT, sortValue, }) } export const setGroupTimelineTopSort = (sortValue) => (dispatch) => { dispatch({ type: GROUP_TIMELINE_TOP_SORT, sortValue, }) }