Move Group mutations to entities
This commit is contained in:
parent
4a6433433f
commit
e42e0577f4
|
@ -1,3 +1,4 @@
|
||||||
|
import { useState } from 'react';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { useApi, useAppDispatch, useGetState } from 'soapbox/hooks';
|
import { useApi, useAppDispatch, useGetState } from 'soapbox/hooks';
|
||||||
|
@ -42,9 +43,13 @@ function useEntityActions<TEntity extends Entity = Entity, P = any>(
|
||||||
const getState = useGetState();
|
const getState = useGetState();
|
||||||
const [entityType, listKey] = path;
|
const [entityType, listKey] = path;
|
||||||
|
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
function createEntity(params: P, callbacks: EntityCallbacks = {}): Promise<CreateEntityResult<TEntity>> {
|
function createEntity(params: P, callbacks: EntityCallbacks = {}): Promise<CreateEntityResult<TEntity>> {
|
||||||
if (!endpoints.post) return Promise.reject(endpoints);
|
if (!endpoints.post) return Promise.reject(endpoints);
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
return api.post(endpoints.post, params).then((response) => {
|
return api.post(endpoints.post, params).then((response) => {
|
||||||
const schema = opts.schema || z.custom<TEntity>();
|
const schema = opts.schema || z.custom<TEntity>();
|
||||||
const entity = schema.parse(response.data);
|
const entity = schema.parse(response.data);
|
||||||
|
@ -56,6 +61,8 @@ function useEntityActions<TEntity extends Entity = Entity, P = any>(
|
||||||
callbacks.onSuccess(entity);
|
callbacks.onSuccess(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsLoading(false);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response,
|
response,
|
||||||
entity,
|
entity,
|
||||||
|
@ -89,6 +96,7 @@ function useEntityActions<TEntity extends Entity = Entity, P = any>(
|
||||||
return {
|
return {
|
||||||
createEntity: createEntity,
|
createEntity: createEntity,
|
||||||
deleteEntity: endpoints.delete ? deleteEntity : undefined,
|
deleteEntity: endpoints.delete ? deleteEntity : undefined,
|
||||||
|
isLoading,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,11 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { openModal } from 'soapbox/actions/modals';
|
import { openModal } from 'soapbox/actions/modals';
|
||||||
import { Button } from 'soapbox/components/ui';
|
import { Button } from 'soapbox/components/ui';
|
||||||
|
import { deleteEntities } from 'soapbox/entity-store/actions';
|
||||||
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
import { useAppDispatch } from 'soapbox/hooks';
|
import { useAppDispatch } from 'soapbox/hooks';
|
||||||
import { useCancelMembershipRequest, useJoinGroup, useLeaveGroup } from 'soapbox/queries/groups';
|
import { useCancelMembershipRequest, useJoinGroup, useLeaveGroup } from 'soapbox/hooks/api';
|
||||||
|
import toast from 'soapbox/toast';
|
||||||
import { Group } from 'soapbox/types/entities';
|
import { Group } from 'soapbox/types/entities';
|
||||||
|
|
||||||
interface IGroupActionButton {
|
interface IGroupActionButton {
|
||||||
|
@ -12,35 +15,54 @@ interface IGroupActionButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
confirmationConfirm: { id: 'confirmations.leave_group.confirm', defaultMessage: 'Leave' },
|
||||||
confirmationHeading: { id: 'confirmations.leave_group.heading', defaultMessage: 'Leave group' },
|
confirmationHeading: { id: 'confirmations.leave_group.heading', defaultMessage: 'Leave group' },
|
||||||
confirmationMessage: { id: 'confirmations.leave_group.message', defaultMessage: 'You are about to leave the group. Do you want to continue?' },
|
confirmationMessage: { id: 'confirmations.leave_group.message', defaultMessage: 'You are about to leave the group. Do you want to continue?' },
|
||||||
confirmationConfirm: { id: 'confirmations.leave_group.confirm', defaultMessage: 'Leave' },
|
joinRequestSuccess: { id: 'group.join.request_success', defaultMessage: 'Requested to join the group' },
|
||||||
|
joinSuccess: { id: 'group.join.success', defaultMessage: 'Group joined successfully!' },
|
||||||
|
leaveSuccess: { id: 'group.leave.success', defaultMessage: 'Left the group' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const GroupActionButton = ({ group }: IGroupActionButton) => {
|
const GroupActionButton = ({ group }: IGroupActionButton) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const joinGroup = useJoinGroup();
|
const joinGroup = useJoinGroup(group);
|
||||||
const leaveGroup = useLeaveGroup();
|
const leaveGroup = useLeaveGroup(group);
|
||||||
const cancelRequest = useCancelMembershipRequest();
|
const cancelRequest = useCancelMembershipRequest(group);
|
||||||
|
|
||||||
const isRequested = group.relationship?.requested;
|
const isRequested = group.relationship?.requested;
|
||||||
const isNonMember = !group.relationship?.member && !isRequested;
|
const isNonMember = !group.relationship?.member && !isRequested;
|
||||||
const isAdmin = group.relationship?.role === 'owner';
|
const isAdmin = group.relationship?.role === 'owner';
|
||||||
const isBlocked = group.relationship?.blocked_by;
|
const isBlocked = group.relationship?.blocked_by;
|
||||||
|
|
||||||
const onJoinGroup = () => joinGroup.mutate(group);
|
const onJoinGroup = () => joinGroup.mutate({}, {
|
||||||
|
onSuccess() {
|
||||||
|
toast.success(
|
||||||
|
group.locked
|
||||||
|
? intl.formatMessage(messages.joinRequestSuccess)
|
||||||
|
: intl.formatMessage(messages.joinSuccess),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const onLeaveGroup = () =>
|
const onLeaveGroup = () =>
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
heading: intl.formatMessage(messages.confirmationHeading),
|
heading: intl.formatMessage(messages.confirmationHeading),
|
||||||
message: intl.formatMessage(messages.confirmationMessage),
|
message: intl.formatMessage(messages.confirmationMessage),
|
||||||
confirm: intl.formatMessage(messages.confirmationConfirm),
|
confirm: intl.formatMessage(messages.confirmationConfirm),
|
||||||
onConfirm: () => leaveGroup.mutate(group),
|
onConfirm: () => leaveGroup.mutate({}, {
|
||||||
|
onSuccess() {
|
||||||
|
toast.success(intl.formatMessage(messages.leaveSuccess));
|
||||||
|
},
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const onCancelRequest = () => cancelRequest.mutate(group);
|
const onCancelRequest = () => cancelRequest.mutate({}, {
|
||||||
|
onSuccess() {
|
||||||
|
dispatch(deleteEntities([group.id], Entities.GROUP_RELATIONSHIPS));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (isBlocked) {
|
if (isBlocked) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import GroupAvatar from 'soapbox/components/groups/group-avatar';
|
||||||
import { Button, HStack, Stack, Text } from 'soapbox/components/ui';
|
import { Button, HStack, Stack, Text } from 'soapbox/components/ui';
|
||||||
import GroupMemberCount from 'soapbox/features/group/components/group-member-count';
|
import GroupMemberCount from 'soapbox/features/group/components/group-member-count';
|
||||||
import GroupPrivacy from 'soapbox/features/group/components/group-privacy';
|
import GroupPrivacy from 'soapbox/features/group/components/group-privacy';
|
||||||
import { useJoinGroup } from 'soapbox/queries/groups';
|
import { useJoinGroup } from 'soapbox/hooks/api';
|
||||||
import { Group as GroupEntity } from 'soapbox/types/entities';
|
import { Group as GroupEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
interface IGroup {
|
interface IGroup {
|
||||||
|
@ -17,7 +17,7 @@ interface IGroup {
|
||||||
const GroupGridItem = forwardRef((props: IGroup, ref: React.ForwardedRef<HTMLDivElement>) => {
|
const GroupGridItem = forwardRef((props: IGroup, ref: React.ForwardedRef<HTMLDivElement>) => {
|
||||||
const { group, width = 'auto' } = props;
|
const { group, width = 'auto' } = props;
|
||||||
|
|
||||||
const joinGroup = useJoinGroup();
|
const joinGroup = useJoinGroup(group);
|
||||||
|
|
||||||
const onJoinGroup = () => joinGroup.mutate(group);
|
const onJoinGroup = () => joinGroup.mutate(group);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import GroupAvatar from 'soapbox/components/groups/group-avatar';
|
import GroupAvatar from 'soapbox/components/groups/group-avatar';
|
||||||
import { Button, HStack, Icon, Stack, Text } from 'soapbox/components/ui';
|
import { Button, HStack, Icon, Stack, Text } from 'soapbox/components/ui';
|
||||||
import { useJoinGroup } from 'soapbox/queries/groups';
|
import { useJoinGroup } from 'soapbox/hooks/api';
|
||||||
import { Group as GroupEntity } from 'soapbox/types/entities';
|
import { Group as GroupEntity } from 'soapbox/types/entities';
|
||||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ interface IGroup {
|
||||||
const GroupListItem = (props: IGroup) => {
|
const GroupListItem = (props: IGroup) => {
|
||||||
const { group, withJoinAction = true } = props;
|
const { group, withJoinAction = true } = props;
|
||||||
|
|
||||||
const joinGroup = useJoinGroup();
|
const joinGroup = useJoinGroup(group);
|
||||||
|
|
||||||
const onJoinGroup = () => joinGroup.mutate(group);
|
const onJoinGroup = () => joinGroup.mutate(group);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
|
import { useEntityActions } from 'soapbox/entity-store/hooks';
|
||||||
|
import { useOwnAccount } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
import type { Group, GroupRelationship } from 'soapbox/schemas';
|
||||||
|
|
||||||
|
function useCancelMembershipRequest(group: Group) {
|
||||||
|
const me = useOwnAccount();
|
||||||
|
|
||||||
|
const { createEntity, isLoading } = useEntityActions<GroupRelationship>(
|
||||||
|
[Entities.GROUP_RELATIONSHIPS, group.id],
|
||||||
|
{ post: `/api/v1/groups/${group.id}/membership_requests/${me?.id}/reject` },
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mutate: createEntity,
|
||||||
|
isLoading,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useCancelMembershipRequest };
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
|
import { useEntityActions } from 'soapbox/entity-store/hooks';
|
||||||
|
import { groupRelationshipSchema } from 'soapbox/schemas';
|
||||||
|
|
||||||
|
import type { Group, GroupRelationship } from 'soapbox/schemas';
|
||||||
|
|
||||||
|
function useJoinGroup(group: Group) {
|
||||||
|
const { createEntity, isLoading } = useEntityActions<GroupRelationship>(
|
||||||
|
[Entities.GROUP_RELATIONSHIPS, group.id],
|
||||||
|
{ post: `/api/v1/groups/${group.id}/join` },
|
||||||
|
{ schema: groupRelationshipSchema },
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mutate: createEntity,
|
||||||
|
isLoading,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useJoinGroup };
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
|
import { useEntityActions } from 'soapbox/entity-store/hooks';
|
||||||
|
import { Group, GroupRelationship, groupRelationshipSchema } from 'soapbox/schemas';
|
||||||
|
|
||||||
|
function useLeaveGroup(group: Group) {
|
||||||
|
const { createEntity, isLoading } = useEntityActions<GroupRelationship>(
|
||||||
|
[Entities.GROUP_RELATIONSHIPS, group.id],
|
||||||
|
{ post: `/api/v1/groups/${group.id}/leave` },
|
||||||
|
{ schema: groupRelationshipSchema },
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mutate: createEntity,
|
||||||
|
isLoading,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useLeaveGroup };
|
|
@ -2,5 +2,8 @@
|
||||||
* Groups
|
* Groups
|
||||||
*/
|
*/
|
||||||
export { useBlockGroupMember } from './groups/useBlockGroupMember';
|
export { useBlockGroupMember } from './groups/useBlockGroupMember';
|
||||||
|
export { useCancelMembershipRequest } from './groups/useCancelMembershipRequest';
|
||||||
export { useDemoteGroupMember } from './groups/useDemoteGroupMember';
|
export { useDemoteGroupMember } from './groups/useDemoteGroupMember';
|
||||||
|
export { useJoinGroup } from './groups/useJoinGroup';
|
||||||
|
export { useLeaveGroup } from './groups/useLeaveGroup';
|
||||||
export { usePromoteGroupMember } from './groups/usePromoteGroupMember';
|
export { usePromoteGroupMember } from './groups/usePromoteGroupMember';
|
|
@ -1,22 +1,12 @@
|
||||||
import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query';
|
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
|
||||||
import { AxiosRequestConfig } from 'axios';
|
import { AxiosRequestConfig } from 'axios';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
|
||||||
|
|
||||||
import { getNextLink } from 'soapbox/api';
|
import { getNextLink } from 'soapbox/api';
|
||||||
import { useApi, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
import { useApi, useFeatures, useOwnAccount } from 'soapbox/hooks';
|
||||||
import { normalizeGroup, normalizeGroupRelationship } from 'soapbox/normalizers';
|
import { normalizeGroup, normalizeGroupRelationship } from 'soapbox/normalizers';
|
||||||
import toast from 'soapbox/toast';
|
|
||||||
import { Group, GroupRelationship } from 'soapbox/types/entities';
|
import { Group, GroupRelationship } from 'soapbox/types/entities';
|
||||||
import { flattenPages, PaginatedResult } from 'soapbox/utils/queries';
|
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 = {
|
const GroupKeys = {
|
||||||
group: (id: string) => ['groups', 'group', id] as const,
|
group: (id: string) => ['groups', 'group', id] as const,
|
||||||
myGroups: (userId: string) => ['groups', userId] as const,
|
myGroups: (userId: string) => ['groups', userId] as const,
|
||||||
|
@ -168,50 +158,8 @@ const useGroup = (id: string) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
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 {
|
export {
|
||||||
useCancelMembershipRequest,
|
|
||||||
useGroup,
|
useGroup,
|
||||||
useGroups,
|
useGroups,
|
||||||
useJoinGroup,
|
|
||||||
useLeaveGroup,
|
|
||||||
usePendingGroups,
|
usePendingGroups,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue