From 287fda6d6cd0334138ab5e29d568e47d4cf3d6ce Mon Sep 17 00:00:00 2001 From: Chewbacca Date: Mon, 6 Mar 2023 08:11:58 -0500 Subject: [PATCH 1/4] Improve error handling for Groups Discover page --- .../components/discover/popular-groups.tsx | 78 +++++++++++-------- .../components/discover/search/blankslate.tsx | 20 +++++ .../discover/search/no-results-blankslate.tsx | 22 ------ .../components/discover/search/search.tsx | 41 +++++++++- .../components/discover/suggested-groups.tsx | 78 +++++++++++-------- app/soapbox/locales/en.json | 6 ++ 6 files changed, 156 insertions(+), 89 deletions(-) create mode 100644 app/soapbox/features/groups/components/discover/search/blankslate.tsx delete mode 100644 app/soapbox/features/groups/components/discover/search/no-results-blankslate.tsx diff --git a/app/soapbox/features/groups/components/discover/popular-groups.tsx b/app/soapbox/features/groups/components/discover/popular-groups.tsx index 8ac7d7387f..5b30905f28 100644 --- a/app/soapbox/features/groups/components/discover/popular-groups.tsx +++ b/app/soapbox/features/groups/components/discover/popular-groups.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Carousel, Stack, Text } from 'soapbox/components/ui'; import PlaceholderGroupDiscover from 'soapbox/features/placeholder/components/placeholder-group-discover'; @@ -7,46 +8,59 @@ import { usePopularGroups } from 'soapbox/queries/groups'; import Group from './group'; const PopularGroups = () => { - const { groups, isFetching } = usePopularGroups(); + const { groups, isFetching, isFetched, isError } = usePopularGroups(); + const isEmpty = (isFetched && groups.length === 0) || isError; const [groupCover, setGroupCover] = useState(null); return ( - Popular Groups + - - {({ width }: { width: number }) => ( - <> - {isFetching ? ( - new Array(20).fill(0).map((_, idx) => ( -
- -
- )) - ) : ( - groups.map((group) => ( - - )) - )} - - )} -
+ {isEmpty ? ( + + + + ) : ( + + {({ width }: { width: number }) => ( + <> + {isFetching ? ( + new Array(20).fill(0).map((_, idx) => ( +
+ +
+ )) + ) : ( + groups.map((group) => ( + + )) + )} + + )} +
+ )}
); }; diff --git a/app/soapbox/features/groups/components/discover/search/blankslate.tsx b/app/soapbox/features/groups/components/discover/search/blankslate.tsx new file mode 100644 index 0000000000..efc179bd49 --- /dev/null +++ b/app/soapbox/features/groups/components/discover/search/blankslate.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +import { Stack, Text } from 'soapbox/components/ui'; + +interface Props { + title: React.ReactNode | string + subtitle: React.ReactNode | string +} + +export default ({ title, subtitle }: Props) => ( + + + {title} + + + + {subtitle} + + +); \ No newline at end of file diff --git a/app/soapbox/features/groups/components/discover/search/no-results-blankslate.tsx b/app/soapbox/features/groups/components/discover/search/no-results-blankslate.tsx deleted file mode 100644 index 1713488468..0000000000 --- a/app/soapbox/features/groups/components/discover/search/no-results-blankslate.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import { FormattedMessage } from 'react-intl'; - -import { Stack, Text } from 'soapbox/components/ui'; - -export default () => ( - - - - - - - - - -); \ No newline at end of file diff --git a/app/soapbox/features/groups/components/discover/search/search.tsx b/app/soapbox/features/groups/components/discover/search/search.tsx index 083dab8d57..ef86054354 100644 --- a/app/soapbox/features/groups/components/discover/search/search.tsx +++ b/app/soapbox/features/groups/components/discover/search/search.tsx @@ -1,4 +1,5 @@ import React, { useEffect } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Stack } from 'soapbox/components/ui'; import PlaceholderGroupSearch from 'soapbox/features/placeholder/components/placeholder-group-search'; @@ -6,7 +7,7 @@ import { useDebounce, useOwnAccount } from 'soapbox/hooks'; import { useGroupSearch } from 'soapbox/queries/groups/search'; import { saveGroupSearch } from 'soapbox/utils/groups'; -import NoResultsBlankslate from './no-results-blankslate'; +import Blankslate from './blankslate'; import RecentSearches from './recent-searches'; import Results from './results'; @@ -25,7 +26,7 @@ export default (props: Props) => { const debouncedValueToSave = debounce(searchValue as string, 1000); const groupSearchResult = useGroupSearch(debouncedValue); - const { groups, isFetching, isFetched } = groupSearchResult; + const { groups, isFetching, isFetched, isError } = groupSearchResult; const hasSearchResults = isFetched && groups.length > 0; const hasNoSearchResults = isFetched && groups.length === 0; @@ -46,8 +47,42 @@ export default (props: Props) => { ); } + if (isError) { + return ( + + } + subtitle={ + + } + /> + ); + } + if (hasNoSearchResults) { - return ; + return ( + + } + subtitle={ + + } + /> + ); } if (hasSearchResults) { diff --git a/app/soapbox/features/groups/components/discover/suggested-groups.tsx b/app/soapbox/features/groups/components/discover/suggested-groups.tsx index bf441a0aea..5c70b6b165 100644 --- a/app/soapbox/features/groups/components/discover/suggested-groups.tsx +++ b/app/soapbox/features/groups/components/discover/suggested-groups.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import { FormattedMessage } from 'react-intl'; import { Carousel, Stack, Text } from 'soapbox/components/ui'; import PlaceholderGroupDiscover from 'soapbox/features/placeholder/components/placeholder-group-discover'; @@ -7,46 +8,59 @@ import { useSuggestedGroups } from 'soapbox/queries/groups'; import Group from './group'; const SuggestedGroups = () => { - const { groups, isFetching } = useSuggestedGroups(); + const { groups, isFetching, isFetched, isError } = useSuggestedGroups(); + const isEmpty = (isFetched && groups.length === 0) || isError; const [groupCover, setGroupCover] = useState(null); return ( - Suggested For You + - - {({ width }: { width: number }) => ( - <> - {isFetching ? ( - new Array(20).fill(0).map((_, idx) => ( -
- -
- )) - ) : ( - groups.map((group) => ( - - )) - )} - - )} -
+ {isEmpty ? ( + + + + ) : ( + + {({ width }: { width: number }) => ( + <> + {isFetching ? ( + new Array(20).fill(0).map((_, idx) => ( +
+ +
+ )) + ) : ( + groups.map((group) => ( + + )) + )} + + )} +
+ )}
); }; diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index 782234a371..a6e6a4ba04 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -803,6 +803,8 @@ "group.user_subheading": "Users", "groups.discover.search.no_results.subtitle": "Try searching for another group.", "groups.discover.search.no_results.title": "No matches found", + "groups.discover.search.error.subtitle": "Please try again later.", + "groups.discover.search.error.title": "An error occurred", "groups.discover.search.placeholder": "Search", "groups.discover.search.recent_searches.blankslate.subtitle": "Search group names, topics or keywords", "groups.discover.search.recent_searches.blankslate.title": "No recent searches", @@ -810,6 +812,10 @@ "groups.discover.search.recent_searches.title": "Recent searches", "groups.discover.search.results.groups": "Groups", "groups.discover.search.results.member_count": "{members, plural, one {member} other {members}}", + "groups.discover.popular.title": "Popular Groups", + "groups.discover.popular.empty": "Unable to fetch popular groups at this time. Please check back later.", + "groups.discover.suggested.title": "Suggested For You", + "groups.discover.suggested.empty": "Unable to fetch suggested groups at this time. Please check back later.", "groups.empty.subtitle": "Start discovering groups to join or create your own.", "groups.empty.title": "No Groups yet", "hashtag.column_header.tag_mode.all": "and {additional}", From 7ad2696f85548d5de41baf5a3c41b42e026300f8 Mon Sep 17 00:00:00 2001 From: Chewbacca Date: Mon, 6 Mar 2023 10:30:25 -0500 Subject: [PATCH 2/4] Move Join / Leave / Cancel group/request to mutations --- app/soapbox/actions/groups.ts | 86 ------------ .../group/components/group-action-button.tsx | 19 ++- .../group/components/group-header.tsx | 2 +- app/soapbox/locales/en.json | 2 +- app/soapbox/normalizers/group-relationship.ts | 2 + app/soapbox/pages/group-page.tsx | 3 +- app/soapbox/queries/groups.ts | 126 ++++++++++++++---- app/soapbox/reducers/group-relationships.ts | 17 --- 8 files changed, 117 insertions(+), 140 deletions(-) diff --git a/app/soapbox/actions/groups.ts b/app/soapbox/actions/groups.ts index 9715396f3e..974bd5ebb2 100644 --- a/app/soapbox/actions/groups.ts +++ b/app/soapbox/actions/groups.ts @@ -40,14 +40,6 @@ const GROUP_RELATIONSHIPS_FETCH_REQUEST = 'GROUP_RELATIONSHIPS_FETCH_REQUEST'; const GROUP_RELATIONSHIPS_FETCH_SUCCESS = 'GROUP_RELATIONSHIPS_FETCH_SUCCESS'; const GROUP_RELATIONSHIPS_FETCH_FAIL = 'GROUP_RELATIONSHIPS_FETCH_FAIL'; -const GROUP_JOIN_REQUEST = 'GROUP_JOIN_REQUEST'; -const GROUP_JOIN_SUCCESS = 'GROUP_JOIN_SUCCESS'; -const GROUP_JOIN_FAIL = 'GROUP_JOIN_FAIL'; - -const GROUP_LEAVE_REQUEST = 'GROUP_LEAVE_REQUEST'; -const GROUP_LEAVE_SUCCESS = 'GROUP_LEAVE_SUCCESS'; -const GROUP_LEAVE_FAIL = 'GROUP_LEAVE_FAIL'; - const GROUP_DELETE_STATUS_REQUEST = 'GROUP_DELETE_STATUS_REQUEST'; const GROUP_DELETE_STATUS_SUCCESS = 'GROUP_DELETE_STATUS_SUCCESS'; const GROUP_DELETE_STATUS_FAIL = 'GROUP_DELETE_STATUS_FAIL'; @@ -312,70 +304,6 @@ const fetchGroupRelationshipsFail = (error: AxiosError) => ({ skipNotFound: true, }); -const joinGroup = (id: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - const locked = (getState().groups.items.get(id) as any).locked || false; - - dispatch(joinGroupRequest(id, locked)); - - return api(getState).post(`/api/v1/groups/${id}/join`).then(response => { - dispatch(joinGroupSuccess(response.data)); - toast.success(locked ? messages.joinRequestSuccess : messages.joinSuccess); - }).catch(error => { - dispatch(joinGroupFail(error, locked)); - }); - }; - -const leaveGroup = (id: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(leaveGroupRequest(id)); - - return api(getState).post(`/api/v1/groups/${id}/leave`).then(response => { - dispatch(leaveGroupSuccess(response.data)); - toast.success(messages.leaveSuccess); - }).catch(error => { - dispatch(leaveGroupFail(error)); - }); - }; - -const joinGroupRequest = (id: string, locked: boolean) => ({ - type: GROUP_JOIN_REQUEST, - id, - locked, - skipLoading: true, -}); - -const joinGroupSuccess = (relationship: APIEntity) => ({ - type: GROUP_JOIN_SUCCESS, - relationship, - skipLoading: true, -}); - -const joinGroupFail = (error: AxiosError, locked: boolean) => ({ - type: GROUP_JOIN_FAIL, - error, - locked, - skipLoading: true, -}); - -const leaveGroupRequest = (id: string) => ({ - type: GROUP_LEAVE_REQUEST, - id, - skipLoading: true, -}); - -const leaveGroupSuccess = (relationship: APIEntity) => ({ - type: GROUP_LEAVE_SUCCESS, - relationship, - skipLoading: true, -}); - -const leaveGroupFail = (error: AxiosError) => ({ - type: GROUP_LEAVE_FAIL, - error, - skipLoading: true, -}); - const groupDeleteStatus = (groupId: string, statusId: string) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch(groupDeleteStatusRequest(groupId, statusId)); @@ -895,12 +823,6 @@ export { GROUP_RELATIONSHIPS_FETCH_REQUEST, GROUP_RELATIONSHIPS_FETCH_SUCCESS, GROUP_RELATIONSHIPS_FETCH_FAIL, - GROUP_JOIN_REQUEST, - GROUP_JOIN_SUCCESS, - GROUP_JOIN_FAIL, - GROUP_LEAVE_REQUEST, - GROUP_LEAVE_SUCCESS, - GROUP_LEAVE_FAIL, GROUP_DELETE_STATUS_REQUEST, GROUP_DELETE_STATUS_SUCCESS, GROUP_DELETE_STATUS_FAIL, @@ -973,14 +895,6 @@ export { fetchGroupRelationshipsRequest, fetchGroupRelationshipsSuccess, fetchGroupRelationshipsFail, - joinGroup, - leaveGroup, - joinGroupRequest, - joinGroupSuccess, - joinGroupFail, - leaveGroupRequest, - leaveGroupSuccess, - leaveGroupFail, groupDeleteStatus, groupDeleteStatusRequest, groupDeleteStatusSuccess, diff --git a/app/soapbox/features/group/components/group-action-button.tsx b/app/soapbox/features/group/components/group-action-button.tsx index 53f27f7099..8705846fc0 100644 --- a/app/soapbox/features/group/components/group-action-button.tsx +++ b/app/soapbox/features/group/components/group-action-button.tsx @@ -1,10 +1,10 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { joinGroup, leaveGroup } from 'soapbox/actions/groups'; import { openModal } from 'soapbox/actions/modals'; import { Button } from 'soapbox/components/ui'; import { useAppDispatch } from 'soapbox/hooks'; +import { useCancelMembershipRequest, useJoinGroup, useLeaveGroup } from 'soapbox/queries/groups'; import { Group } from 'soapbox/types/entities'; interface IGroupActionButton { @@ -21,25 +21,32 @@ const GroupActionButton = ({ group }: IGroupActionButton) => { const dispatch = useAppDispatch(); const intl = useIntl(); - const isNonMember = !group.relationship || !group.relationship.member; + const joinGroup = useJoinGroup(); + const leaveGroup = useLeaveGroup(); + const cancelRequest = useCancelMembershipRequest(); + const isRequested = group.relationship?.requested; + const isNonMember = !group.relationship?.member && !isRequested; const isAdmin = group.relationship?.role === 'admin'; - const onJoinGroup = () => dispatch(joinGroup(group.id)); + const onJoinGroup = () => joinGroup.mutate(group); const onLeaveGroup = () => dispatch(openModal('CONFIRM', { heading: intl.formatMessage(messages.confirmationHeading), message: intl.formatMessage(messages.confirmationMessage), confirm: intl.formatMessage(messages.confirmationConfirm), - onConfirm: () => dispatch(leaveGroup(group.id)), + onConfirm: () => leaveGroup.mutate(group), })); + const onCancelRequest = () => cancelRequest.mutate(group); + if (isNonMember) { return ( @@ -74,6 +82,7 @@ const GroupActionButton = ({ group }: IGroupActionButton) => { diff --git a/app/soapbox/features/group/components/group-header.tsx b/app/soapbox/features/group/components/group-header.tsx index 7b532ddccc..4e1c50160d 100644 --- a/app/soapbox/features/group/components/group-header.tsx +++ b/app/soapbox/features/group/components/group-header.tsx @@ -125,7 +125,7 @@ const GroupHeader: React.FC = ({ group }) => { dangerouslySetInnerHTML={{ __html: group.display_name_html }} /> - + diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index a6e6a4ba04..00d7835392 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -789,7 +789,7 @@ "group.join.private": "Request Access", "group.join.public": "Join Group", "group.join.request_success": "Requested to join the group", - "group.join.success": "Joined the group", + "group.join.success": "Group joined successfully!", "group.leave": "Leave Group", "group.leave.success": "Left the group", "group.manage": "Manage Group", diff --git a/app/soapbox/normalizers/group-relationship.ts b/app/soapbox/normalizers/group-relationship.ts index 6f2f473106..c9326db916 100644 --- a/app/soapbox/normalizers/group-relationship.ts +++ b/app/soapbox/normalizers/group-relationship.ts @@ -10,7 +10,9 @@ import { export const GroupRelationshipRecord = ImmutableRecord({ id: '', + blocked_by: false, member: false, + notifying: null, requested: false, role: null as 'admin' | 'moderator' | 'user' | null, }); diff --git a/app/soapbox/pages/group-page.tsx b/app/soapbox/pages/group-page.tsx index f617b8bd7b..e15d9efcc6 100644 --- a/app/soapbox/pages/group-page.tsx +++ b/app/soapbox/pages/group-page.tsx @@ -37,7 +37,7 @@ const GroupPage: React.FC = ({ params, children }) => { const { group } = useGroup(id); - const isNonMember = !group?.relationship || !group.relationship.member; + const isNonMember = !group?.relationship?.member; const isPrivate = group?.locked; // if ((group as any) === false) { @@ -80,7 +80,6 @@ const GroupPage: React.FC = ({ params, children }) => { Content is only visible to group members - ) : children} diff --git a/app/soapbox/queries/groups.ts b/app/soapbox/queries/groups.ts index 5fb8ed2dc5..32b4189c4e 100644 --- a/app/soapbox/queries/groups.ts +++ b/app/soapbox/queries/groups.ts @@ -1,13 +1,21 @@ -import { useInfiniteQuery, useQuery } from '@tanstack/react-query'; +import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query'; +import { defineMessages, useIntl } from 'react-intl'; -import { fetchGroupRelationships } from 'soapbox/actions/groups'; -import { importFetchedGroups } from 'soapbox/actions/importer'; import { getNextLink } from 'soapbox/api'; -import { useApi, useAppDispatch, useFeatures, useOwnAccount } from 'soapbox/hooks'; -import { normalizeGroup } from 'soapbox/normalizers'; -import { Group } from 'soapbox/types/entities'; +import { useApi, useFeatures, useOwnAccount } from 'soapbox/hooks'; +import { normalizeGroup, normalizeGroupRelationship } from 'soapbox/normalizers'; +import toast from 'soapbox/toast'; +import { Group, GroupRelationship } from 'soapbox/types/entities'; import { flattenPages, PaginatedResult } from 'soapbox/utils/queries'; +import { queryClient } from './client'; + +const messages = defineMessages({ + joinSuccess: { id: 'group.join.success', defaultMessage: 'Group joined successfully!' }, + joinRequestSuccess: { id: 'group.join.request_success', defaultMessage: 'Requested to join the group' }, + leaveSuccess: { id: 'group.leave.success', defaultMessage: 'Left the group' }, +}); + const GroupKeys = { group: (id: string) => ['groups', 'group', id] as const, myGroups: (userId: string) => ['groups', userId] as const, @@ -15,29 +23,54 @@ const GroupKeys = { suggestedGroups: ['groups', 'suggested'] as const, }; -const useGroups = () => { +const useGroupsApi = () => { const api = useApi(); + + const getGroupRelationships = async (ids: string[]) => { + const queryString = ids.map((id) => `id[]=${id}`).join('&'); + const { data } = await api.get(`/api/v1/groups/relationships?${queryString}`); + + return data; + }; + + const fetchGroups = async (endpoint: string) => { + const response = await api.get(endpoint); + const groups = [response.data].flat(); + const relationships = await getGroupRelationships(groups.map((group) => group.id)); + const result = groups.map((group) => { + const relationship = relationships.find((relationship) => relationship.id === group.id); + + return normalizeGroup({ + ...group, + relationship: relationship ? normalizeGroupRelationship(relationship) : null, + }); + }); + + return { + response, + groups: result, + }; + }; + + return { fetchGroups }; +}; + +const useGroups = () => { const account = useOwnAccount(); - const dispatch = useAppDispatch(); const features = useFeatures(); + const { fetchGroups } = useGroupsApi(); const getGroups = async (pageParam?: any): Promise> => { const endpoint = '/api/v1/groups'; const nextPageLink = pageParam?.link; const uri = nextPageLink || endpoint; - const response = await api.get(uri); - const { data } = response; + const { response, groups } = await fetchGroups(uri); const link = getNextLink(response); const hasMore = !!link; - const result = data.map(normalizeGroup); - - // Note: Temporary while part of Groups is using Redux - dispatch(importFetchedGroups(result)); - dispatch(fetchGroupRelationships(result.map((item) => item.id))); return { - result, + result: groups, hasMore, link, }; @@ -67,14 +100,13 @@ const useGroups = () => { }; const usePopularGroups = () => { - const api = useApi(); const features = useFeatures(); + const { fetchGroups } = useGroupsApi(); const getQuery = async () => { - const { data } = await api.get('/api/v1/groups/search?q=group'); // '/api/v1/truth/trends/groups' - const result = data.map(normalizeGroup); + const { groups } = await fetchGroups('/api/v1/groups/search?q=group'); // '/api/v1/truth/trends/groups' - return result; + return groups; }; const queryInfo = useQuery(GroupKeys.popularGroups, getQuery, { @@ -89,14 +121,13 @@ const usePopularGroups = () => { }; const useSuggestedGroups = () => { - const api = useApi(); const features = useFeatures(); + const { fetchGroups } = useGroupsApi(); const getQuery = async () => { - const { data } = await api.get('/api/mock/groups'); // /api/v1/truth/suggestions/groups - const result = data.map(normalizeGroup); + const { groups } = await fetchGroups('/api/v1/groups/search?q=group'); // /api/v1/truth/suggestions/groups - return result; + return groups; }; const queryInfo = useQuery(GroupKeys.suggestedGroups, getQuery, { @@ -111,12 +142,12 @@ const useSuggestedGroups = () => { }; const useGroup = (id: string) => { - const api = useApi(); const features = useFeatures(); + const { fetchGroups } = useGroupsApi(); const getGroup = async () => { - const { data } = await api.get(`/api/v1/groups/${id}`); - return normalizeGroup(data); + const { groups } = await fetchGroups(`/api/v1/groups/${id}`); // /api/v1/truth/suggestions/groups + return groups[0]; }; const queryInfo = useQuery(GroupKeys.group(id), getGroup, { @@ -129,4 +160,43 @@ const useGroup = (id: string) => { }; }; -export { useGroups, useGroup, usePopularGroups, useSuggestedGroups }; +const useJoinGroup = () => { + const api = useApi(); + const intl = useIntl(); + + return useMutation((group: Group) => api.post(`/api/v1/groups/${group.id}/join`), { + onSuccess(_response, group) { + queryClient.invalidateQueries(['groups']); + toast.success( + group.locked + ? intl.formatMessage(messages.joinRequestSuccess) + : intl.formatMessage(messages.joinSuccess), + ); + }, + }); +}; + +const useLeaveGroup = () => { + const api = useApi(); + const intl = useIntl(); + + return useMutation((group: Group) => api.post(`/api/v1/groups/${group.id}/leave`), { + onSuccess() { + queryClient.invalidateQueries({ queryKey: ['groups'] }); + toast.success(intl.formatMessage(messages.leaveSuccess)); + }, + }); +}; + +const useCancelMembershipRequest = () => { + const api = useApi(); + const me = useOwnAccount(); + + return useMutation((group: Group) => api.post(`/api/v1/groups/${group.id}/membership_requests/${me?.id}/reject`), { + onSuccess() { + queryClient.invalidateQueries({ queryKey: ['groups'] }); + }, + }); +}; + +export { useGroups, useGroup, usePopularGroups, useSuggestedGroups, useJoinGroup, useLeaveGroup, useCancelMembershipRequest }; diff --git a/app/soapbox/reducers/group-relationships.ts b/app/soapbox/reducers/group-relationships.ts index 90b9d802cf..eb61ae9535 100644 --- a/app/soapbox/reducers/group-relationships.ts +++ b/app/soapbox/reducers/group-relationships.ts @@ -5,12 +5,6 @@ import { GROUP_UPDATE_SUCCESS, GROUP_DELETE_SUCCESS, GROUP_RELATIONSHIPS_FETCH_SUCCESS, - GROUP_JOIN_REQUEST, - GROUP_JOIN_SUCCESS, - GROUP_JOIN_FAIL, - GROUP_LEAVE_REQUEST, - GROUP_LEAVE_SUCCESS, - GROUP_LEAVE_FAIL, } from 'soapbox/actions/groups'; import { normalizeGroupRelationship } from 'soapbox/normalizers'; @@ -37,17 +31,6 @@ export default function groupRelationships(state: State = ImmutableMap(), action return state.set(action.group.id, normalizeGroupRelationship({ id: action.group.id, member: true, requested: false, role: 'admin' })); case GROUP_DELETE_SUCCESS: return state.delete(action.id); - case GROUP_JOIN_REQUEST: - return state.getIn([action.id, 'member']) ? state : state.setIn([action.id, action.locked ? 'requested' : 'member'], true); - case GROUP_JOIN_FAIL: - return state.setIn([action.id, action.locked ? 'requested' : 'member'], false); - case GROUP_LEAVE_REQUEST: - return state.setIn([action.id, 'member'], false); - case GROUP_LEAVE_FAIL: - return state.setIn([action.id, 'member'], true); - case GROUP_JOIN_SUCCESS: - case GROUP_LEAVE_SUCCESS: - return normalizeRelationships(state, [action.relationship]); case GROUP_RELATIONSHIPS_FETCH_SUCCESS: return normalizeRelationships(state, action.relationships); default: From bd4c99b697d622f4e490807059db5edcf71d2205 Mon Sep 17 00:00:00 2001 From: Chewbacca Date: Wed, 8 Mar 2023 14:11:40 -0500 Subject: [PATCH 3/4] Fix tests --- .../hooks/__tests__/useGroupsPath.test.ts | 23 +++++++------------ app/soapbox/queries/groups.ts | 6 ++--- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/app/soapbox/hooks/__tests__/useGroupsPath.test.ts b/app/soapbox/hooks/__tests__/useGroupsPath.test.ts index de123d2111..c3ec1e169a 100644 --- a/app/soapbox/hooks/__tests__/useGroupsPath.test.ts +++ b/app/soapbox/hooks/__tests__/useGroupsPath.test.ts @@ -2,7 +2,7 @@ import { Map as ImmutableMap } from 'immutable'; import { __stub } from 'soapbox/api'; import { renderHook, waitFor } from 'soapbox/jest/test-helpers'; -import { normalizeAccount, normalizeGroup, normalizeInstance } from 'soapbox/normalizers'; +import { normalizeAccount, normalizeGroup, normalizeGroupRelationship, normalizeInstance } from 'soapbox/normalizers'; import { useGroupsPath } from '../useGroupsPath'; @@ -58,23 +58,16 @@ describe('useGroupsPath()', () => { id: '1', }), ]); + + mock.onGet('/api/v1/groups/relationships?id[]=1').reply(200, [ + normalizeGroupRelationship({ + id: '1', + }), + ]); }); }); - test('should default to the discovery page', async () => { - const store = { - entities: { - Groups: { - store: { - '1': normalizeGroup({}), - }, - lists: { - '': new Set(['1']), - }, - }, - }, - }; - + test('should default to the "My Groups" page', async () => { const { result } = renderHook(useGroupsPath, undefined, store); await waitFor(() => { diff --git a/app/soapbox/queries/groups.ts b/app/soapbox/queries/groups.ts index 32b4189c4e..93fb23661e 100644 --- a/app/soapbox/queries/groups.ts +++ b/app/soapbox/queries/groups.ts @@ -104,7 +104,7 @@ const usePopularGroups = () => { const { fetchGroups } = useGroupsApi(); const getQuery = async () => { - const { groups } = await fetchGroups('/api/v1/groups/search?q=group'); // '/api/v1/truth/trends/groups' + const { groups } = await fetchGroups('/api/v1/truth/trends/groups'); return groups; }; @@ -125,7 +125,7 @@ const useSuggestedGroups = () => { const { fetchGroups } = useGroupsApi(); const getQuery = async () => { - const { groups } = await fetchGroups('/api/v1/groups/search?q=group'); // /api/v1/truth/suggestions/groups + const { groups } = await fetchGroups('/api/v1/truth/suggestions/groups'); return groups; }; @@ -146,7 +146,7 @@ const useGroup = (id: string) => { const { fetchGroups } = useGroupsApi(); const getGroup = async () => { - const { groups } = await fetchGroups(`/api/v1/groups/${id}`); // /api/v1/truth/suggestions/groups + const { groups } = await fetchGroups(`/api/v1/groups/${id}`); return groups[0]; }; From a71aaca719f178a5e53655c2355559f946c17307 Mon Sep 17 00:00:00 2001 From: Chewbacca Date: Thu, 9 Mar 2023 12:04:53 -0500 Subject: [PATCH 4/4] Fix translations --- app/soapbox/locales/en.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index 00d7835392..5d6261d3f6 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -801,10 +801,12 @@ "group.tabs.all": "All", "group.tabs.members": "Members", "group.user_subheading": "Users", - "groups.discover.search.no_results.subtitle": "Try searching for another group.", - "groups.discover.search.no_results.title": "No matches found", + "groups.discover.popular.empty": "Unable to fetch popular groups at this time. Please check back later.", + "groups.discover.popular.title": "Popular Groups", "groups.discover.search.error.subtitle": "Please try again later.", "groups.discover.search.error.title": "An error occurred", + "groups.discover.search.no_results.subtitle": "Try searching for another group.", + "groups.discover.search.no_results.title": "No matches found", "groups.discover.search.placeholder": "Search", "groups.discover.search.recent_searches.blankslate.subtitle": "Search group names, topics or keywords", "groups.discover.search.recent_searches.blankslate.title": "No recent searches", @@ -812,10 +814,8 @@ "groups.discover.search.recent_searches.title": "Recent searches", "groups.discover.search.results.groups": "Groups", "groups.discover.search.results.member_count": "{members, plural, one {member} other {members}}", - "groups.discover.popular.title": "Popular Groups", - "groups.discover.popular.empty": "Unable to fetch popular groups at this time. Please check back later.", - "groups.discover.suggested.title": "Suggested For You", "groups.discover.suggested.empty": "Unable to fetch suggested groups at this time. Please check back later.", + "groups.discover.suggested.title": "Suggested For You", "groups.empty.subtitle": "Start discovering groups to join or create your own.", "groups.empty.title": "No Groups yet", "hashtag.column_header.tag_mode.all": "and {additional}",