|
|
|
@ -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<GroupRelationship[]>(`/api/v1/groups/relationships?${queryString}`);
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fetchGroups = async (endpoint: string) => {
|
|
|
|
|
const response = await api.get<Group[]>(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<PaginatedResult<Group>> => {
|
|
|
|
|
const endpoint = '/api/v1/groups';
|
|
|
|
|
const nextPageLink = pageParam?.link;
|
|
|
|
|
const uri = nextPageLink || endpoint;
|
|
|
|
|
const response = await api.get<Group[]>(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<Group[]>('/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<Group[]>(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<Group[]>('/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<Group[]>(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<GroupRelationship>(`/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<GroupRelationship>(`/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 };
|
|
|
|
|