pl-fe: migrate group members
Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
parent
05bb838577
commit
72523df008
15 changed files with 52 additions and 107 deletions
|
@ -27,4 +27,4 @@ const groupMemberSchema = v.object({
|
|||
*/
|
||||
type GroupMember = v.InferOutput<typeof groupMemberSchema>;
|
||||
|
||||
export { groupMemberSchema, type GroupMember, GroupRoles, type GroupRole };
|
||||
export { groupMemberSchema, type GroupMember, type GroupRoles, type GroupRole };
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
import { GroupRoles } from 'pl-api';
|
||||
|
||||
import { __stub } from 'pl-fe/api';
|
||||
import { buildGroupMember } from 'pl-fe/jest/factory';
|
||||
import { renderHook, waitFor } from 'pl-fe/jest/test-helpers';
|
||||
|
||||
import { useGroupMembers } from './use-group-members';
|
||||
|
||||
const groupMember = buildGroupMember();
|
||||
const groupId = '1';
|
||||
|
||||
describe('useGroupMembers hook', () => {
|
||||
describe('with a successful request', () => {
|
||||
beforeEach(() => {
|
||||
__stub((mock) => {
|
||||
mock.onGet(`/api/v1/groups/${groupId}/memberships?role=${GroupRoles.ADMIN}`).reply(200, [groupMember]);
|
||||
});
|
||||
});
|
||||
|
||||
it('is successful', async () => {
|
||||
const { result } = renderHook(() => useGroupMembers(groupId, GroupRoles.ADMIN));
|
||||
|
||||
await waitFor(() => expect(result.current.isFetching).toBe(false));
|
||||
|
||||
expect(result.current.groupMembers.length).toBe(1);
|
||||
expect(result.current.groupMembers[0].id).toBe(groupMember.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with an unsuccessful query', () => {
|
||||
beforeEach(() => {
|
||||
__stub((mock) => {
|
||||
mock.onGet(`/api/v1/groups/${groupId}/memberships?role=${GroupRoles.ADMIN}`).networkError();
|
||||
});
|
||||
});
|
||||
|
||||
it('is has error state', async() => {
|
||||
const { result } = renderHook(() => useGroupMembers(groupId, GroupRoles.ADMIN));
|
||||
|
||||
await waitFor(() => expect(result.current.isFetching).toBe(false));
|
||||
|
||||
expect(result.current.groupMembers.length).toBe(0);
|
||||
expect(result.current.isError).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,23 +0,0 @@
|
|||
import { Entities } from 'pl-fe/entity-store/entities';
|
||||
import { useEntities } from 'pl-fe/entity-store/hooks/use-entities';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { normalizeGroupMember, type GroupMember } from 'pl-fe/normalizers/group-member';
|
||||
|
||||
import type { GroupMember as BaseGroupMember, GroupRoles } from 'pl-api';
|
||||
|
||||
const useGroupMembers = (groupId: string, role: GroupRoles) => {
|
||||
const client = useClient();
|
||||
|
||||
const { entities, ...result } = useEntities<BaseGroupMember, GroupMember>(
|
||||
[Entities.GROUP_MEMBERSHIPS, groupId, role],
|
||||
() => client.experimental.groups.getGroupMemberships(groupId, role),
|
||||
{ transform: normalizeGroupMember },
|
||||
);
|
||||
|
||||
return {
|
||||
...result,
|
||||
groupMembers: entities,
|
||||
};
|
||||
};
|
||||
|
||||
export { useGroupMembers };
|
|
@ -20,7 +20,7 @@ import toast from 'pl-fe/toast';
|
|||
|
||||
import type { Menu as IMenu } from 'pl-fe/components/dropdown-menu';
|
||||
import type { Group } from 'pl-fe/normalizers/group';
|
||||
import type { GroupMember } from 'pl-fe/normalizers/group-member';
|
||||
import type { MinifiedGroupMember } from 'pl-fe/queries/groups/use-group-members';
|
||||
|
||||
const messages = defineMessages({
|
||||
adminLimitTitle: { id: 'group.member.admin.limit.title', defaultMessage: 'Admin limit reached' },
|
||||
|
@ -44,7 +44,7 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
interface IGroupMemberListItem {
|
||||
member: GroupMember;
|
||||
member: MinifiedGroupMember;
|
||||
group: Pick<Group, 'id' | 'relationship'>;
|
||||
}
|
||||
|
||||
|
@ -53,11 +53,11 @@ const GroupMemberListItem = ({ member, group }: IGroupMemberListItem) => {
|
|||
const intl = useIntl();
|
||||
const { openModal } = useModalsStore();
|
||||
|
||||
const { mutate: blockGroupMember } = useBlockGroupUserMutation(group.id, member.account.id);
|
||||
const { mutate: blockGroupMember } = useBlockGroupUserMutation(group.id, member.account_id);
|
||||
const promoteGroupMember = usePromoteGroupMember(group, member);
|
||||
const demoteGroupMember = useDemoteGroupMember(group, member);
|
||||
|
||||
const { account, isLoading } = useAccount(member.account.id);
|
||||
const { account, isLoading } = useAccount(member.account_id);
|
||||
|
||||
// Current user role
|
||||
const isCurrentUserOwner = group.relationship?.role === GroupRoles.OWNER;
|
||||
|
@ -102,7 +102,7 @@ const GroupMemberListItem = ({ member, group }: IGroupMemberListItem) => {
|
|||
confirm: intl.formatMessage(messages.promoteConfirm),
|
||||
confirmationTheme: 'primary',
|
||||
onConfirm: () => {
|
||||
promoteGroupMember({ role: GroupRoles.ADMIN, account_ids: [member.account.id] }, {
|
||||
promoteGroupMember({ role: GroupRoles.ADMIN, account_ids: [member.account_id] }, {
|
||||
onSuccess() {
|
||||
toast.success(
|
||||
intl.formatMessage(messages.promotedToAdmin, { name: account?.acct }),
|
||||
|
@ -114,7 +114,7 @@ const GroupMemberListItem = ({ member, group }: IGroupMemberListItem) => {
|
|||
};
|
||||
|
||||
const handleUserAssignment = () => {
|
||||
demoteGroupMember({ role: GroupRoles.USER, account_ids: [member.account.id] }, {
|
||||
demoteGroupMember({ role: GroupRoles.USER, account_ids: [member.account_id] }, {
|
||||
onSuccess() {
|
||||
toast.success(intl.formatMessage(messages.demotedToUser, { name: account?.acct }));
|
||||
},
|
||||
|
@ -167,7 +167,7 @@ const GroupMemberListItem = ({ member, group }: IGroupMemberListItem) => {
|
|||
return items;
|
||||
}, [group, account?.id]);
|
||||
|
||||
if (isLoading) {
|
||||
if (isLoading || !account) {
|
||||
return <PlaceholderAccount />;
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ const GroupMemberListItem = ({ member, group }: IGroupMemberListItem) => {
|
|||
data-testid='group-member-list-item'
|
||||
>
|
||||
<div className='w-full'>
|
||||
<Account account={member.account} withRelationship={false} />
|
||||
<Account account={account} withRelationship={false} />
|
||||
</div>
|
||||
|
||||
<HStack alignItems='center' space={2}>
|
||||
|
|
|
@ -3,10 +3,10 @@ import { GroupRoles } from 'pl-api';
|
|||
import React, { useMemo } from 'react';
|
||||
|
||||
import { useGroup } from 'pl-fe/api/hooks/groups/use-group';
|
||||
import { useGroupMembers } from 'pl-fe/api/hooks/groups/use-group-members';
|
||||
import { useGroupMembershipRequests } from 'pl-fe/api/hooks/groups/use-group-membership-requests';
|
||||
import { PendingItemsRow } from 'pl-fe/components/pending-items-row';
|
||||
import ScrollableList from 'pl-fe/components/scrollable-list';
|
||||
import { useGroupMembers } from 'pl-fe/queries/groups/use-group-members';
|
||||
|
||||
import PlaceholderAccount from '../placeholder/components/placeholder-account';
|
||||
|
||||
|
@ -20,17 +20,17 @@ const GroupMembers: React.FC<IGroupMembers> = (props) => {
|
|||
const { groupId } = props.params;
|
||||
|
||||
const { group, isFetching: isFetchingGroup } = useGroup(groupId);
|
||||
const { groupMembers: owners, isFetching: isFetchingOwners } = useGroupMembers(groupId, GroupRoles.OWNER);
|
||||
const { groupMembers: admins, isFetching: isFetchingAdmins } = useGroupMembers(groupId, GroupRoles.ADMIN);
|
||||
const { groupMembers: users, isFetching: isFetchingUsers, fetchNextPage, hasNextPage } = useGroupMembers(groupId, GroupRoles.USER);
|
||||
const { data: owners, isFetching: isFetchingOwners } = useGroupMembers(groupId, GroupRoles.OWNER);
|
||||
const { data: admins, isFetching: isFetchingAdmins } = useGroupMembers(groupId, GroupRoles.ADMIN);
|
||||
const { data: users, isFetching: isFetchingUsers, fetchNextPage, hasNextPage } = useGroupMembers(groupId, GroupRoles.USER);
|
||||
const { isFetching: isFetchingPending, count: pendingCount } = useGroupMembershipRequests(groupId);
|
||||
|
||||
const isLoading = isFetchingGroup || isFetchingOwners || isFetchingAdmins || isFetchingUsers || isFetchingPending;
|
||||
|
||||
const members = useMemo(() => [
|
||||
...owners,
|
||||
...admins,
|
||||
...users,
|
||||
...(owners || []),
|
||||
...(admins || []),
|
||||
...(users || []),
|
||||
], [owners, admins, users]);
|
||||
|
||||
return (
|
||||
|
@ -57,7 +57,7 @@ const GroupMembers: React.FC<IGroupMembers> = (props) => {
|
|||
<GroupMemberListItem
|
||||
group={group!}
|
||||
member={member}
|
||||
key={member.account.id}
|
||||
key={member.account_id}
|
||||
/>
|
||||
))}
|
||||
</ScrollableList>
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { GroupRoles } from 'pl-api';
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { useGroup } from 'pl-fe/api/hooks/groups/use-group';
|
||||
import { useGroupMembers } from 'pl-fe/api/hooks/groups/use-group-members';
|
||||
import { useGroupMembershipRequests } from 'pl-fe/api/hooks/groups/use-group-membership-requests';
|
||||
import Account from 'pl-fe/components/account';
|
||||
import { AuthorizeRejectButtons } from 'pl-fe/components/authorize-reject-buttons';
|
||||
|
@ -64,11 +62,6 @@ const GroupMembershipRequests: React.FC<IGroupMembershipRequests> = ({ params })
|
|||
const { group } = useGroup(groupId);
|
||||
|
||||
const { accounts, authorize, reject, refetch, isLoading } = useGroupMembershipRequests(groupId);
|
||||
const { invalidate } = useGroupMembers(groupId, GroupRoles.USER);
|
||||
|
||||
useEffect(() => () => {
|
||||
invalidate();
|
||||
}, []);
|
||||
|
||||
if (!group || !group.relationship || isLoading) {
|
||||
return (
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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';
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { minifyAccountList } from 'pl-fe/queries/utils/minify-list';
|
||||
|
||||
import type { PaginatedResponse, PlApiClient } from 'pl-api';
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
import { type InfiniteData, useMutation } from '@tanstack/react-query';
|
||||
|
||||
import { importEntities } from 'pl-fe/actions/importer';
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/api/utils/make-paginated-response-query';
|
||||
import { minifyList } from 'pl-fe/api/utils/minify-list';
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { minifyList } from 'pl-fe/queries/utils/minify-list';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { queryClient } from 'pl-fe/queries/client';
|
||||
import { store } from 'pl-fe/store';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { makePaginatedResponseQuery } from 'pl-fe/api/utils/make-paginated-response-query';
|
||||
import { minifyAccountList } from 'pl-fe/api/utils/minify-list';
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { minifyAccountList } from 'pl-fe/queries/utils/minify-list';
|
||||
|
||||
const useEventParticipations = makePaginatedResponseQuery(
|
||||
(statusId: string) => ['accountsLists', 'eventParticipations', statusId],
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
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 { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { minifyAccountList } from 'pl-fe/queries/utils/minify-list';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
import { queryClient } from 'pl-fe/queries/client';
|
||||
|
||||
|
|
21
packages/pl-fe/src/queries/groups/use-group-members.ts
Normal file
21
packages/pl-fe/src/queries/groups/use-group-members.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { GroupMember, GroupRole, PaginatedResponse } from 'pl-api';
|
||||
|
||||
import { importEntities } from 'pl-fe/actions/importer';
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { store } from 'pl-fe/store';
|
||||
|
||||
import { minifyList } from '../utils/minify-list';
|
||||
|
||||
const minifyGroupMembersList = (response: PaginatedResponse<GroupMember>): PaginatedResponse<Omit<GroupMember, 'account'> & { account_id: string }> =>
|
||||
minifyList(response, ({ account, ...groupMember }) => ({ ...groupMember, account_id: account.id }), (groupMembers) => {
|
||||
store.dispatch(importEntities({ accounts: groupMembers.map(({ account }) => account) }) as any);
|
||||
});
|
||||
|
||||
const useGroupMembers = makePaginatedResponseQuery(
|
||||
(groupId: string, role?: GroupRole) => ['accountsLists', 'groupMembers', groupId, role],
|
||||
(client, [groupId, role]) => client.experimental.groups.getGroupMemberships(groupId, role).then(minifyGroupMembersList),
|
||||
);
|
||||
|
||||
type MinifiedGroupMember = ReturnType<typeof minifyGroupMembersList>['items'][0];
|
||||
|
||||
export { useGroupMembers, type MinifiedGroupMember };
|
|
@ -1,8 +1,8 @@
|
|||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { importEntities } from 'pl-fe/actions/importer';
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/api/utils/make-paginated-response-query';
|
||||
import { minifyAccountList } from 'pl-fe/api/utils/minify-list';
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { minifyAccountList } from 'pl-fe/queries/utils/minify-list';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useClient } from 'pl-fe/hooks/use-client';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { makePaginatedResponseQuery } from 'pl-fe/api/utils/make-paginated-response-query';
|
||||
import { minifyStatusList } from 'pl-fe/api/utils/minify-list';
|
||||
import { makePaginatedResponseQuery } from 'pl-fe/queries/utils/make-paginated-response-query';
|
||||
import { minifyStatusList } from 'pl-fe/queries/utils/minify-list';
|
||||
|
||||
const useStatusQuotes = makePaginatedResponseQuery(
|
||||
(statusId: string) => ['statusLists', 'quotes', statusId],
|
||||
|
|
|
@ -5,7 +5,7 @@ import { useClient } from 'pl-fe/hooks/use-client';
|
|||
import type { PaginatedResponse, PlApiClient } from 'pl-api';
|
||||
|
||||
const makePaginatedResponseQuery = <T1 extends Array<any>, T2, T3 = Array<T2>>(
|
||||
queryKey: (...params: T1) => string[],
|
||||
queryKey: (...params: T1) => Array<string | undefined>,
|
||||
queryFn: (client: PlApiClient, params: T1) => Promise<PaginatedResponse<T2>>,
|
||||
select?: (data: InfiniteData<PaginatedResponse<T2>>) => T3,
|
||||
) => (...params: T1) => {
|
Loading…
Reference in a new issue