Groups: make authorize/reject use component state, update designs
This commit is contained in:
@ -24,7 +24,7 @@ const GroupMembers: React.FC<IGroupMembers> = (props) => {
|
||||
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 { entities: pending, isFetching: isFetchingPending } = useGroupMembershipRequests(groupId);
|
||||
const { accounts: pending, isFetching: isFetchingPending } = useGroupMembershipRequests(groupId);
|
||||
|
||||
const isLoading = isFetchingGroup || isFetchingOwners || isFetchingAdmins || isFetchingUsers || isFetchingPending;
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { authorizeGroupMembershipRequest, rejectGroupMembershipRequest } from 'soapbox/actions/groups';
|
||||
import Account from 'soapbox/components/account';
|
||||
import { AuthorizeRejectButtons } from 'soapbox/components/authorize-reject-buttons';
|
||||
import ScrollableList from 'soapbox/components/scrollable-list';
|
||||
import { Button, Column, HStack, Spinner } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useGroup } from 'soapbox/hooks';
|
||||
import { Column, HStack, Spinner } from 'soapbox/components/ui';
|
||||
import { useGroup } from 'soapbox/hooks';
|
||||
import { useGroupMembershipRequests } from 'soapbox/hooks/api/groups/useGroupMembershipRequests';
|
||||
import toast from 'soapbox/toast';
|
||||
|
||||
@ -19,50 +19,44 @@ const messages = defineMessages({
|
||||
heading: { id: 'column.group_pending_requests', defaultMessage: 'Pending requests' },
|
||||
authorize: { id: 'group.group_mod_authorize', defaultMessage: 'Accept' },
|
||||
authorized: { id: 'group.group_mod_authorize.success', defaultMessage: 'Accepted @{name} to group' },
|
||||
authorizeFail: { id: 'group.group_mod_authorize.fail', defaultMessage: 'Failed to approve @{name}' },
|
||||
reject: { id: 'group.group_mod_reject', defaultMessage: 'Reject' },
|
||||
rejected: { id: 'group.group_mod_reject.success', defaultMessage: 'Rejected @{name} from group' },
|
||||
rejectFail: { id: 'group.group_mod_reject.fail', defaultMessage: 'Failed to reject @{name}' },
|
||||
});
|
||||
|
||||
interface IMembershipRequest {
|
||||
account: AccountEntity
|
||||
groupId: string
|
||||
onAuthorize(accountId: string): Promise<unknown>
|
||||
onReject(accountId: string): Promise<unknown>
|
||||
}
|
||||
|
||||
const MembershipRequest: React.FC<IMembershipRequest> = ({ account, groupId }) => {
|
||||
const MembershipRequest: React.FC<IMembershipRequest> = ({ account, onAuthorize, onReject }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
const handleAuthorize = () =>
|
||||
dispatch(authorizeGroupMembershipRequest(groupId, account.id)).then(() => {
|
||||
toast.success(intl.formatMessage(messages.authorized, { name: account.acct }));
|
||||
});
|
||||
function handleAuthorize(accountId: string) {
|
||||
return onAuthorize(accountId)
|
||||
.catch(() => toast.error(intl.formatMessage(messages.authorizeFail, { name: account.username })));
|
||||
}
|
||||
|
||||
const handleReject = () =>
|
||||
dispatch(rejectGroupMembershipRequest(groupId, account.id)).then(() => {
|
||||
toast.success(intl.formatMessage(messages.rejected, { name: account.acct }));
|
||||
});
|
||||
function handleReject(accountId: string) {
|
||||
return onReject(accountId)
|
||||
.catch(() => toast.error(intl.formatMessage(messages.rejectFail, { name: account.username })));
|
||||
}
|
||||
|
||||
return (
|
||||
<HStack space={1} alignItems='center' justifyContent='between' className='p-2.5'>
|
||||
<div className='w-full'>
|
||||
<Account account={account} withRelationship={false} />
|
||||
</div>
|
||||
<HStack space={2}>
|
||||
<Button
|
||||
theme='secondary'
|
||||
size='sm'
|
||||
text={intl.formatMessage(messages.authorize)}
|
||||
onClick={handleAuthorize}
|
||||
/>
|
||||
<Button
|
||||
theme='danger'
|
||||
size='sm'
|
||||
text={intl.formatMessage(messages.reject)}
|
||||
onClick={handleReject}
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
<AuthorizeRejectButtons
|
||||
id={account.id}
|
||||
onAuthorize={handleAuthorize}
|
||||
onReject={handleReject}
|
||||
/>
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
@ -77,7 +71,7 @@ const GroupMembershipRequests: React.FC<IGroupMembershipRequests> = ({ params })
|
||||
const id = params?.id;
|
||||
|
||||
const { group } = useGroup(id);
|
||||
const { entities: accounts, isLoading } = useGroupMembershipRequests(id);
|
||||
const { accounts, isLoading, authorize, reject } = useGroupMembershipRequests(id);
|
||||
|
||||
if (!group || !group.relationship || isLoading) {
|
||||
return (
|
||||
@ -91,17 +85,23 @@ const GroupMembershipRequests: React.FC<IGroupMembershipRequests> = ({ params })
|
||||
return (<ColumnForbidden />);
|
||||
}
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.group_membership_requests' defaultMessage='There are no pending membership requests for this group.' />;
|
||||
const handleAuthorize = (accountId: string) => authorize(accountId);
|
||||
const handleReject = (accountId: string) => reject(accountId);
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)} backHref={`/groups/${id}/manage`}>
|
||||
<ScrollableList
|
||||
scrollKey='group_membership_requests'
|
||||
emptyMessage={emptyMessage}
|
||||
emptyMessage={<FormattedMessage id='empty_column.group_membership_requests' defaultMessage='There are no pending membership requests for this group.' />}
|
||||
>
|
||||
{accounts.map((account) =>
|
||||
<MembershipRequest key={account.id} account={account} groupId={id} />,
|
||||
)}
|
||||
{accounts.map((account) => (
|
||||
<MembershipRequest
|
||||
key={account.id}
|
||||
account={account}
|
||||
onAuthorize={handleAuthorize}
|
||||
onReject={handleReject}
|
||||
/>
|
||||
))}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
|
||||
@ -1,13 +1,31 @@
|
||||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { useEntities } from 'soapbox/entity-store/hooks';
|
||||
import { useApi } from 'soapbox/hooks/useApi';
|
||||
import { accountSchema } from 'soapbox/schemas';
|
||||
|
||||
function useGroupMembershipRequests(groupId: string) {
|
||||
return useEntities(
|
||||
const api = useApi();
|
||||
|
||||
function authorize(accountId: string) {
|
||||
return api.post(`/api/v1/groups/${groupId}/membership_requests/${accountId}/authorize`);
|
||||
}
|
||||
|
||||
function reject(accountId: string) {
|
||||
return api.post(`/api/v1/groups/${groupId}/membership_requests/${accountId}/reject`);
|
||||
}
|
||||
|
||||
const { entities, ...rest } = useEntities(
|
||||
[Entities.ACCOUNTS, 'membership_requests', groupId],
|
||||
`/api/v1/groups/${groupId}/membership_requests`,
|
||||
{ schema: accountSchema },
|
||||
);
|
||||
|
||||
return {
|
||||
accounts: entities,
|
||||
authorize,
|
||||
reject,
|
||||
...rest,
|
||||
};
|
||||
}
|
||||
|
||||
export { useGroupMembershipRequests };
|
||||
Reference in New Issue
Block a user