From 05bb8385771c3c058cef6a7dbc3c30c78dee9ead Mon Sep 17 00:00:00 2001 From: mkljczk Date: Thu, 5 Dec 2024 10:39:11 +0100 Subject: [PATCH] pl-fe: remove user lists reducer Signed-off-by: mkljczk --- packages/pl-fe/src/actions/groups.ts | 87 ------------------- .../hooks/groups/use-block-group-member.ts | 19 ---- .../src/components/status-action-bar.tsx | 8 +- .../components/group-member-list-item.tsx | 6 +- .../features/group/group-blocked-members.tsx | 21 ++--- .../src/queries/groups/use-group-blocks.ts | 53 +++++++++++ packages/pl-fe/src/reducers/index.ts | 2 - .../pl-fe/src/reducers/user-lists.test.ts | 9 -- packages/pl-fe/src/reducers/user-lists.ts | 68 --------------- 9 files changed, 68 insertions(+), 205 deletions(-) delete mode 100644 packages/pl-fe/src/api/hooks/groups/use-block-group-member.ts create mode 100644 packages/pl-fe/src/queries/groups/use-group-blocks.ts delete mode 100644 packages/pl-fe/src/reducers/user-lists.test.ts delete mode 100644 packages/pl-fe/src/reducers/user-lists.ts diff --git a/packages/pl-fe/src/actions/groups.ts b/packages/pl-fe/src/actions/groups.ts index a1cbb49df..3db7161d5 100644 --- a/packages/pl-fe/src/actions/groups.ts +++ b/packages/pl-fe/src/actions/groups.ts @@ -1,99 +1,12 @@ import { getClient } from '../api'; -import { importEntities } from './importer'; - -import type { Account, PaginatedResponse } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; -const GROUP_BLOCKS_FETCH_REQUEST = 'GROUP_BLOCKS_FETCH_REQUEST' as const; -const GROUP_BLOCKS_FETCH_SUCCESS = 'GROUP_BLOCKS_FETCH_SUCCESS' as const; -const GROUP_BLOCKS_FETCH_FAIL = 'GROUP_BLOCKS_FETCH_FAIL' as const; - -const GROUP_UNBLOCK_REQUEST = 'GROUP_UNBLOCK_REQUEST' as const; -const GROUP_UNBLOCK_SUCCESS = 'GROUP_UNBLOCK_SUCCESS' as const; -const GROUP_UNBLOCK_FAIL = 'GROUP_UNBLOCK_FAIL' as const; - const groupKick = (groupId: string, accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => { return getClient(getState).experimental.groups.kickGroupUsers(groupId, [accountId]); }; -const fetchGroupBlocks = (groupId: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(fetchGroupBlocksRequest(groupId)); - - return getClient(getState).experimental.groups.getGroupBlocks(groupId).then(response => { - dispatch(importEntities({ accounts: response.items })); - dispatch(fetchGroupBlocksSuccess(groupId, response.items, response.next)); - }).catch(error => { - dispatch(fetchGroupBlocksFail(groupId, error)); - }); - }; - -const fetchGroupBlocksRequest = (groupId: string) => ({ - type: GROUP_BLOCKS_FETCH_REQUEST, - groupId, -}); - -const fetchGroupBlocksSuccess = (groupId: string, accounts: Array, next: (() => Promise>) | null) => ({ - type: GROUP_BLOCKS_FETCH_SUCCESS, - groupId, - accounts, - next, -}); - -const fetchGroupBlocksFail = (groupId: string, error: unknown) => ({ - type: GROUP_BLOCKS_FETCH_FAIL, - groupId, - error, - skipNotFound: true, -}); - -const groupUnblock = (groupId: string, accountId: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(groupUnblockRequest(groupId, accountId)); - - return getClient(getState).experimental.groups.unblockGroupUsers(groupId, [accountId]) - .then(() => dispatch(groupUnblockSuccess(groupId, accountId))) - .catch(err => dispatch(groupUnblockFail(groupId, accountId, err))); - }; - -const groupUnblockRequest = (groupId: string, accountId: string) => ({ - type: GROUP_UNBLOCK_REQUEST, - groupId, - accountId, -}); - -const groupUnblockSuccess = (groupId: string, accountId: string) => ({ - type: GROUP_UNBLOCK_SUCCESS, - groupId, - accountId, -}); - -const groupUnblockFail = (groupId: string, accountId: string, error: unknown) => ({ - type: GROUP_UNBLOCK_FAIL, - groupId, - accountId, - error, -}); - -type GroupsAction = - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - export { - GROUP_BLOCKS_FETCH_REQUEST, - GROUP_BLOCKS_FETCH_SUCCESS, - GROUP_BLOCKS_FETCH_FAIL, - GROUP_UNBLOCK_REQUEST, - GROUP_UNBLOCK_SUCCESS, - GROUP_UNBLOCK_FAIL, groupKick, - fetchGroupBlocks, - groupUnblock, - type GroupsAction, }; diff --git a/packages/pl-fe/src/api/hooks/groups/use-block-group-member.ts b/packages/pl-fe/src/api/hooks/groups/use-block-group-member.ts deleted file mode 100644 index 673b261dd..000000000 --- a/packages/pl-fe/src/api/hooks/groups/use-block-group-member.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Entities } from 'pl-fe/entity-store/entities'; -import { useCreateEntity } from 'pl-fe/entity-store/hooks/use-create-entity'; -import { useClient } from 'pl-fe/hooks/use-client'; - -import type { Group } from 'pl-api'; -import type { Account } from 'pl-fe/normalizers/account'; - -const useBlockGroupMember = (group: Pick, account: Pick) => { - const client = useClient(); - - const { createEntity } = useCreateEntity( - [Entities.GROUP_MEMBERSHIPS, account.id], - (accountIds: string[]) => client.experimental.groups.blockGroupUsers(group.id, accountIds), - ); - - return createEntity; -}; - -export { useBlockGroupMember }; diff --git a/packages/pl-fe/src/components/status-action-bar.tsx b/packages/pl-fe/src/components/status-action-bar.tsx index 1171584ab..cb8174599 100644 --- a/packages/pl-fe/src/components/status-action-bar.tsx +++ b/packages/pl-fe/src/components/status-action-bar.tsx @@ -13,7 +13,6 @@ import { initReport, ReportableEntities } from 'pl-fe/actions/reports'; import { changeSetting } from 'pl-fe/actions/settings'; import { deleteStatus, editStatus, toggleMuteStatus } from 'pl-fe/actions/statuses'; import { deleteFromTimelines } from 'pl-fe/actions/timelines'; -import { useBlockGroupMember } from 'pl-fe/api/hooks/groups/use-block-group-member'; import { useDeleteGroupStatus } from 'pl-fe/api/hooks/groups/use-delete-group-status'; import { useGroup } from 'pl-fe/api/hooks/groups/use-group'; import { useGroupRelationship } from 'pl-fe/api/hooks/groups/use-group-relationship'; @@ -30,6 +29,7 @@ import { useInstance } from 'pl-fe/hooks/use-instance'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useChats } from 'pl-fe/queries/chats'; +import { useBlockGroupUserMutation } from 'pl-fe/queries/groups/use-group-blocks'; import { useTranslationLanguages } from 'pl-fe/queries/instance/use-translation-languages'; import { RootState } from 'pl-fe/store'; import { useModalsStore } from 'pl-fe/stores/modals'; @@ -590,7 +590,7 @@ const MenuButton: React.FC = ({ const { openModal } = useModalsStore(); const { group } = useGroup((status.group as Group)?.id as string); const deleteGroupStatus = useDeleteGroupStatus(group as Group, status.id); - const blockGroupMember = useBlockGroupMember(group as Group, status.account); + const { mutate: blockGroupMember } = useBlockGroupUserMutation(status.group?.id as string, status.account.id); const { getOrCreateChatByAccountId } = useChats(); const { groupRelationship } = useGroupRelationship(status.group_id || undefined); @@ -762,8 +762,8 @@ const MenuButton: React.FC = ({ message: intl.formatMessage(messages.groupBlockFromGroupMessage, { name: status.account.username }), confirm: intl.formatMessage(messages.groupBlockConfirm), onConfirm: () => { - blockGroupMember([status.account_id], { - onSuccess() { + blockGroupMember(undefined, { + onSuccess: () => { toast.success(intl.formatMessage(messages.blocked, { name: account?.acct })); }, }); diff --git a/packages/pl-fe/src/features/group/components/group-member-list-item.tsx b/packages/pl-fe/src/features/group/components/group-member-list-item.tsx index e8a79ee23..98e0decc8 100644 --- a/packages/pl-fe/src/features/group/components/group-member-list-item.tsx +++ b/packages/pl-fe/src/features/group/components/group-member-list-item.tsx @@ -5,7 +5,6 @@ import { defineMessages, useIntl } from 'react-intl'; import { groupKick } from 'pl-fe/actions/groups'; import { useAccount } from 'pl-fe/api/hooks/accounts/use-account'; -import { useBlockGroupMember } from 'pl-fe/api/hooks/groups/use-block-group-member'; import { useDemoteGroupMember } from 'pl-fe/api/hooks/groups/use-demote-group-member'; import { usePromoteGroupMember } from 'pl-fe/api/hooks/groups/use-promote-group-member'; import Account from 'pl-fe/components/account'; @@ -15,6 +14,7 @@ import { deleteEntities } from 'pl-fe/entity-store/actions'; import { Entities } from 'pl-fe/entity-store/entities'; import PlaceholderAccount from 'pl-fe/features/placeholder/components/placeholder-account'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; +import { useBlockGroupUserMutation } from 'pl-fe/queries/groups/use-group-blocks'; import { useModalsStore } from 'pl-fe/stores/modals'; import toast from 'pl-fe/toast'; @@ -53,7 +53,7 @@ const GroupMemberListItem = ({ member, group }: IGroupMemberListItem) => { const intl = useIntl(); const { openModal } = useModalsStore(); - const blockGroupMember = useBlockGroupMember(group, member.account); + const { mutate: blockGroupMember } = useBlockGroupUserMutation(group.id, member.account.id); const promoteGroupMember = usePromoteGroupMember(group, member); const demoteGroupMember = useDemoteGroupMember(group, member); @@ -85,7 +85,7 @@ const GroupMemberListItem = ({ member, group }: IGroupMemberListItem) => { message: intl.formatMessage(messages.blockFromGroupMessage, { name: account?.username }), confirm: intl.formatMessage(messages.blockConfirm), onConfirm: () => { - blockGroupMember([member.account.id], { + blockGroupMember(undefined, { onSuccess() { dispatch(deleteEntities([member.id], Entities.GROUP_MEMBERSHIPS)); toast.success(intl.formatMessage(messages.blocked, { name: account?.acct })); diff --git a/packages/pl-fe/src/features/group/group-blocked-members.tsx b/packages/pl-fe/src/features/group/group-blocked-members.tsx index 3884ec5e6..b795bcdc8 100644 --- a/packages/pl-fe/src/features/group/group-blocked-members.tsx +++ b/packages/pl-fe/src/features/group/group-blocked-members.tsx @@ -1,7 +1,6 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; -import { fetchGroupBlocks, groupUnblock } from 'pl-fe/actions/groups'; import { useAccount } from 'pl-fe/api/hooks/accounts/use-account'; import { useGroup } from 'pl-fe/api/hooks/groups/use-group'; import Account from 'pl-fe/components/account'; @@ -10,8 +9,7 @@ import Button from 'pl-fe/components/ui/button'; import Column from 'pl-fe/components/ui/column'; import HStack from 'pl-fe/components/ui/hstack'; import Spinner from 'pl-fe/components/ui/spinner'; -import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; +import { useGroupBlocks, useUnblockGroupUserMutation } from 'pl-fe/queries/groups/use-group-blocks'; import toast from 'pl-fe/toast'; import ColumnForbidden from '../ui/components/column-forbidden'; @@ -31,14 +29,16 @@ interface IBlockedMember { const BlockedMember: React.FC = ({ accountId, groupId }) => { const intl = useIntl(); - const dispatch = useAppDispatch(); const { account } = useAccount(accountId); + const { mutate: unblockGroupUser } = useUnblockGroupUserMutation(groupId, accountId); + if (!account) return null; const handleUnblock = () => - dispatch(groupUnblock(groupId, accountId)) - .then(() => toast.success(intl.formatMessage(messages.unblocked, { name: account.acct }))); + unblockGroupUser(undefined, { + onSuccess: () => toast.success(intl.formatMessage(messages.unblocked, { name: account.acct })), + }); return ( @@ -61,16 +61,11 @@ interface IGroupBlockedMembers { const GroupBlockedMembers: React.FC = ({ params }) => { const intl = useIntl(); - const dispatch = useAppDispatch(); const groupId = params?.groupId; const { group } = useGroup(groupId); - const accountIds = useAppSelector((state) => state.user_lists.group_blocks[groupId]?.items); - - useEffect(() => { - dispatch(fetchGroupBlocks(groupId)); - }, [groupId]); + const { data: accountIds } = useGroupBlocks(groupId); if (!group || !group.relationship || !accountIds) { return ( diff --git a/packages/pl-fe/src/queries/groups/use-group-blocks.ts b/packages/pl-fe/src/queries/groups/use-group-blocks.ts new file mode 100644 index 000000000..f40373178 --- /dev/null +++ b/packages/pl-fe/src/queries/groups/use-group-blocks.ts @@ -0,0 +1,53 @@ +import { useMutation, type InfiniteData } from '@tanstack/react-query'; + +import { makePaginatedResponseQuery } from 'pl-fe/api/utils/make-paginated-response-query'; +import { minifyAccountList } from 'pl-fe/api/utils/minify-list'; +import { useClient } from 'pl-fe/hooks/use-client'; +import { queryClient } from 'pl-fe/queries/client'; + +const appendGroupBlock = (groupId: string, accountId: string) => + queryClient.setQueryData>>(['accountsLists', 'groupBlocks', groupId], (data) => { + if (!data || data.pages.some(page => page.items.includes(accountId))) return data; + + return { + ...data, + pages: data.pages.map((page, index) => index === 0 ? ({ ...page, items: [accountId, ...page.items] }) : page), + }; + }); + +const removeGroupBlock = (groupId: string, accountId: string) => + queryClient.setQueryData>>(['accountsLists', 'groupBlocks', groupId], (data) => data ? { + ...data, + pages: data.pages.map(({ items, ...page }) => ({ ...page, items: items.filter((id) => id !== accountId) })), + } : undefined); + +const useGroupBlocks = makePaginatedResponseQuery( + (groupId: string) => ['accountsLists', 'groupBlocks', groupId], + (client, [groupId]) => client.experimental.groups.getGroupBlocks(groupId).then(minifyAccountList), +); + +const useBlockGroupUserMutation = (groupId: string, accountId: string) => { + const client = useClient(); + + return useMutation({ + mutationKey: ['accountsLists', 'groupBlocks', groupId, accountId], + mutationFn: () => client.experimental.groups.blockGroupUsers(groupId, [accountId]), + onSettled: () => appendGroupBlock(groupId, accountId), + }); +}; + +const useUnblockGroupUserMutation = (groupId: string, accountId: string) => { + const client = useClient(); + + return useMutation({ + mutationKey: ['accountsLists', 'groupBlocks', groupId, accountId], + mutationFn: () => client.experimental.groups.unblockGroupUsers(groupId, [accountId]), + onSettled: () => removeGroupBlock(groupId, accountId), + }); +}; + +export { + useGroupBlocks, + useBlockGroupUserMutation, + useUnblockGroupUserMutation, +}; diff --git a/packages/pl-fe/src/reducers/index.ts b/packages/pl-fe/src/reducers/index.ts index 945556710..d27b43292 100644 --- a/packages/pl-fe/src/reducers/index.ts +++ b/packages/pl-fe/src/reducers/index.ts @@ -36,7 +36,6 @@ import status_lists from './status-lists'; import statuses from './statuses'; import tags from './tags'; import timelines from './timelines'; -import user_lists from './user-lists'; const reducers = { accounts_meta, @@ -72,7 +71,6 @@ const reducers = { statuses, tags, timelines, - user_lists, }; const appReducer = combineReducers(reducers); diff --git a/packages/pl-fe/src/reducers/user-lists.test.ts b/packages/pl-fe/src/reducers/user-lists.test.ts deleted file mode 100644 index bcb2bfa8f..000000000 --- a/packages/pl-fe/src/reducers/user-lists.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import reducer from './user-lists'; - -describe('user_lists reducer', () => { - it('should return the initial state', () => { - expect(reducer(undefined, {} as any)).toMatchObject({ - group_blocks: {}, - }); - }); -}); diff --git a/packages/pl-fe/src/reducers/user-lists.ts b/packages/pl-fe/src/reducers/user-lists.ts deleted file mode 100644 index 857d7d810..000000000 --- a/packages/pl-fe/src/reducers/user-lists.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { create } from 'mutative'; - -import { - GROUP_BLOCKS_FETCH_REQUEST, - GROUP_BLOCKS_FETCH_SUCCESS, - GROUP_BLOCKS_FETCH_FAIL, - GROUP_UNBLOCK_SUCCESS, - type GroupsAction, -} from 'pl-fe/actions/groups'; - -import type { Account, PaginatedResponse } from 'pl-api'; - -interface List { - next: (() => Promise>) | null; - items: Array; - isLoading: boolean; -} - -type NestedListKey = 'group_blocks'; - -type State = Record>; - -const initialState: State = { - group_blocks: {}, -}; - -type NestedListPath = [NestedListKey, string]; - -const normalizeList = (state: State, path: NestedListPath, accounts: Array>, next: (() => Promise>) | null = null) => - create(state, (draft) => { - const list = draft[path[0]][path[1]]; - const newList = { ...list, next, items: accounts.map(item => item.id), isLoading: false }; - draft[path[0]][path[1]] = newList; - }); - -const userLists = (state = initialState, action: GroupsAction): State => { - switch (action.type) { - case GROUP_BLOCKS_FETCH_SUCCESS: - return normalizeList(state, ['group_blocks', action.groupId], action.accounts, action.next); - case GROUP_BLOCKS_FETCH_REQUEST: - return create(state, (draft) => { - draft.group_blocks[action.groupId] = { - items: [], - next: null, - isLoading: true, - }; - }); - case GROUP_BLOCKS_FETCH_FAIL: - return create(state, (draft) => { - draft.group_blocks[action.groupId] = { - items: [], - next: null, - isLoading: false, - }; - }); - case GROUP_UNBLOCK_SUCCESS: - return create(state, (draft) => { - const list = draft.group_blocks[action.groupId]; - if (list.items) list.items = list.items.filter(item => item !== action.accountId); - }); - default: - return state; - } -}; - -export { - userLists as default, -};