pl-fe: remove user lists reducer
Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
parent
105c87c64d
commit
05bb838577
9 changed files with 68 additions and 205 deletions
|
@ -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<Account>, next: (() => Promise<PaginatedResponse<Account>>) | 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<typeof fetchGroupBlocksRequest>
|
||||
| ReturnType<typeof fetchGroupBlocksSuccess>
|
||||
| ReturnType<typeof fetchGroupBlocksFail>
|
||||
| ReturnType<typeof groupUnblockRequest>
|
||||
| ReturnType<typeof groupUnblockSuccess>
|
||||
| ReturnType<typeof groupUnblockFail>
|
||||
|
||||
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,
|
||||
};
|
||||
|
|
|
@ -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<Group, 'id'>, account: Pick<Account, 'id'>) => {
|
||||
const client = useClient();
|
||||
|
||||
const { createEntity } = useCreateEntity(
|
||||
[Entities.GROUP_MEMBERSHIPS, account.id],
|
||||
(accountIds: string[]) => client.experimental.groups.blockGroupUsers(group.id, accountIds),
|
||||
);
|
||||
|
||||
return createEntity;
|
||||
};
|
||||
|
||||
export { useBlockGroupMember };
|
|
@ -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<IMenuButton> = ({
|
|||
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<IMenuButton> = ({
|
|||
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 }));
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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 }));
|
||||
|
|
|
@ -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<IBlockedMember> = ({ 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 (
|
||||
<HStack space={1} alignItems='center' justifyContent='between' className='p-2.5'>
|
||||
|
@ -61,16 +61,11 @@ interface IGroupBlockedMembers {
|
|||
|
||||
const GroupBlockedMembers: React.FC<IGroupBlockedMembers> = ({ 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 (
|
||||
|
|
53
packages/pl-fe/src/queries/groups/use-group-blocks.ts
Normal file
53
packages/pl-fe/src/queries/groups/use-group-blocks.ts
Normal file
|
@ -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<InfiniteData<ReturnType<typeof minifyAccountList>>>(['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<InfiniteData<ReturnType<typeof minifyAccountList>>>(['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,
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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: {},
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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<PaginatedResponse<Account>>) | null;
|
||||
items: Array<string>;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
type NestedListKey = 'group_blocks';
|
||||
|
||||
type State = Record<NestedListKey, Record<string, List>>;
|
||||
|
||||
const initialState: State = {
|
||||
group_blocks: {},
|
||||
};
|
||||
|
||||
type NestedListPath = [NestedListKey, string];
|
||||
|
||||
const normalizeList = (state: State, path: NestedListPath, accounts: Array<Pick<Account, 'id'>>, next: (() => Promise<PaginatedResponse<any>>) | 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,
|
||||
};
|
Loading…
Reference in a new issue