Allow Admins to manage/leave Group
This commit is contained in:
parent
c045a6630d
commit
e78bbf4e19
8 changed files with 58 additions and 22 deletions
|
@ -11,24 +11,22 @@ interface IIconButton extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|||
src: string
|
||||
/** Text to display next ot the button. */
|
||||
text?: string
|
||||
/** Don't render a background behind the icon. */
|
||||
transparent?: boolean
|
||||
/** Predefined styles to display for the button. */
|
||||
theme?: 'seamless' | 'outlined' | 'secondary'
|
||||
theme?: 'seamless' | 'outlined' | 'secondary' | 'transparent'
|
||||
/** Override the data-testid */
|
||||
'data-testid'?: string
|
||||
}
|
||||
|
||||
/** A clickable icon. */
|
||||
const IconButton = React.forwardRef((props: IIconButton, ref: React.ForwardedRef<HTMLButtonElement>): JSX.Element => {
|
||||
const { src, className, iconClassName, text, transparent = false, theme = 'seamless', ...filteredProps } = props;
|
||||
const { src, className, iconClassName, text, theme = 'seamless', ...filteredProps } = props;
|
||||
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
type='button'
|
||||
className={clsx('flex items-center space-x-2 rounded-full p-1 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 dark:ring-offset-0', {
|
||||
'bg-white dark:bg-transparent': !transparent,
|
||||
'bg-white dark:bg-transparent': theme === 'seamless',
|
||||
'border border-solid bg-transparent border-gray-400 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 focus:border-primary-500 text-gray-900 dark:text-gray-100 focus:ring-primary-500': theme === 'outlined',
|
||||
'border-transparent bg-primary-100 dark:bg-primary-800 hover:bg-primary-50 dark:hover:bg-primary-700 focus:bg-primary-100 dark:focus:bg-primary-800 text-primary-500 dark:text-primary-200': theme === 'secondary',
|
||||
'opacity-50': filteredProps.disabled,
|
||||
|
|
|
@ -20,7 +20,6 @@ const Tag: React.FC<ITag> = ({ tag, onDelete }) => {
|
|||
iconClassName='h-4 w-4'
|
||||
src={require('@tabler/icons/x.svg')}
|
||||
onClick={() => onDelete(tag)}
|
||||
transparent
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -40,10 +40,11 @@ describe('<GroupOptionsButton />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should render null', () => {
|
||||
it('should render one option for leaving the group', () => {
|
||||
render(<GroupOptionsButton group={group} />);
|
||||
|
||||
expect(screen.queryAllByTestId('dropdown-menu-button')).toHaveLength(0);
|
||||
// Leave group option only
|
||||
expect(screen.queryAllByTestId('dropdown-menu-button')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ const GroupActionButton = ({ group }: IGroupActionButton) => {
|
|||
const isRequested = group.relationship?.requested;
|
||||
const isNonMember = !group.relationship?.member && !isRequested;
|
||||
const isOwner = group.relationship?.role === GroupRoles.OWNER;
|
||||
const isAdmin = group.relationship?.role === GroupRoles.ADMIN;
|
||||
const isBlocked = group.relationship?.blocked_by;
|
||||
|
||||
const onJoinGroup = () => joinGroup.mutate({}, {
|
||||
|
@ -73,7 +74,7 @@ const GroupActionButton = ({ group }: IGroupActionButton) => {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (isOwner) {
|
||||
if (isOwner || isAdmin) {
|
||||
return (
|
||||
<Button
|
||||
theme='secondary'
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import { initReport, ReportableEntities } from 'soapbox/actions/reports';
|
||||
import DropdownMenu, { Menu } from 'soapbox/components/dropdown-menu';
|
||||
import { IconButton } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useOwnAccount } from 'soapbox/hooks';
|
||||
import { useLeaveGroup } from 'soapbox/hooks/api';
|
||||
import { GroupRoles } from 'soapbox/schemas/group-member';
|
||||
import toast from 'soapbox/toast';
|
||||
|
||||
import type { Account, Group } from 'soapbox/types/entities';
|
||||
|
||||
const messages = defineMessages({
|
||||
confirmationConfirm: { id: 'confirmations.leave_group.confirm', defaultMessage: 'Leave' },
|
||||
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?' },
|
||||
leave: { id: 'group.leave.label', defaultMessage: 'Leave' },
|
||||
leaveSuccess: { id: 'group.leave.success', defaultMessage: 'Left the group' },
|
||||
report: { id: 'group.report.label', defaultMessage: 'Report' },
|
||||
});
|
||||
|
||||
|
@ -21,19 +29,48 @@ const GroupOptionsButton = ({ group }: IGroupActionButton) => {
|
|||
const account = useOwnAccount();
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
const leaveGroup = useLeaveGroup(group);
|
||||
|
||||
const isMember = group.relationship?.role === GroupRoles.USER;
|
||||
const isAdmin = group.relationship?.role === GroupRoles.ADMIN;
|
||||
const isBlocked = group.relationship?.blocked_by;
|
||||
|
||||
const menu: Menu = useMemo(() => ([
|
||||
{
|
||||
text: intl.formatMessage(messages.report),
|
||||
icon: require('@tabler/icons/flag.svg'),
|
||||
action: () => dispatch(initReport(ReportableEntities.GROUP, account as Account, { group })),
|
||||
},
|
||||
]), []);
|
||||
const onLeaveGroup = () =>
|
||||
dispatch(openModal('CONFIRM', {
|
||||
heading: intl.formatMessage(messages.confirmationHeading),
|
||||
message: intl.formatMessage(messages.confirmationMessage),
|
||||
confirm: intl.formatMessage(messages.confirmationConfirm),
|
||||
onConfirm: () => leaveGroup.mutate(group.relationship?.id as string, {
|
||||
onSuccess() {
|
||||
leaveGroup.invalidate();
|
||||
toast.success(intl.formatMessage(messages.leaveSuccess));
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
if (isBlocked || !isMember || menu.length === 0) {
|
||||
const menu: Menu = useMemo(() => {
|
||||
const items = [];
|
||||
|
||||
if (isMember) {
|
||||
items.push({
|
||||
text: intl.formatMessage(messages.report),
|
||||
icon: require('@tabler/icons/flag.svg'),
|
||||
action: () => dispatch(initReport(ReportableEntities.GROUP, account as Account, { group })),
|
||||
});
|
||||
}
|
||||
|
||||
if (isAdmin) {
|
||||
items.push({
|
||||
text: intl.formatMessage(messages.leave),
|
||||
icon: require('@tabler/icons/logout.svg'),
|
||||
action: onLeaveGroup,
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}, [isMember, isAdmin]);
|
||||
|
||||
if (isBlocked || menu.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ type RouteParams = { id: string };
|
|||
const messages = defineMessages({
|
||||
heading: { id: 'column.manage_group', defaultMessage: 'Manage group' },
|
||||
editGroup: { id: 'manage_group.edit_group', defaultMessage: 'Edit group' },
|
||||
pendingRequests: { id: 'manage_group.pending_requests', defaultMessage: 'Pending requests' },
|
||||
blockedMembers: { id: 'manage_group.blocked_members', defaultMessage: 'Banned members' },
|
||||
pendingRequests: { id: 'manage_group.pending_requests', defaultMessage: 'Pending Requests' },
|
||||
blockedMembers: { id: 'manage_group.blocked_members', defaultMessage: 'Banned Members' },
|
||||
deleteGroup: { id: 'manage_group.delete_group', defaultMessage: 'Delete group' },
|
||||
deleteConfirm: { id: 'confirmations.delete_group.confirm', defaultMessage: 'Delete' },
|
||||
deleteHeading: { id: 'confirmations.delete_group.heading', defaultMessage: 'Delete group' },
|
||||
|
|
|
@ -147,7 +147,6 @@ const Header = () => {
|
|||
src={require('@tabler/icons/help.svg')}
|
||||
className='cursor-pointer bg-transparent text-gray-700 hover:text-gray-800 dark:text-gray-600 dark:hover:text-gray-500'
|
||||
iconClassName='h-5 w-5'
|
||||
transparent
|
||||
/>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
|
|
|
@ -786,6 +786,7 @@
|
|||
"group.join.request_success": "Request sent to group owner",
|
||||
"group.join.success": "Group joined successfully!",
|
||||
"group.leave": "Leave Group",
|
||||
"group.leave.label": "Leave",
|
||||
"group.leave.success": "Left the group",
|
||||
"group.manage": "Manage Group",
|
||||
"group.popover.action": "View Group",
|
||||
|
@ -933,7 +934,7 @@
|
|||
"login_external.errors.instance_fail": "The instance returned an error.",
|
||||
"login_external.errors.network_fail": "Connection failed. Is a browser extension blocking it?",
|
||||
"login_form.header": "Sign In",
|
||||
"manage_group.blocked_members": "Banned members",
|
||||
"manage_group.blocked_members": "Banned Members",
|
||||
"manage_group.confirmation.copy": "Copy link",
|
||||
"manage_group.confirmation.info_1": "As the owner of this group, you can assign staff, delete posts and much more.",
|
||||
"manage_group.confirmation.info_2": "Post the group's first post and get the conversation started.",
|
||||
|
@ -954,7 +955,7 @@
|
|||
"manage_group.fields.name_placeholder": "Group Name",
|
||||
"manage_group.get_started": "Let’s get started!",
|
||||
"manage_group.next": "Next",
|
||||
"manage_group.pending_requests": "Pending requests",
|
||||
"manage_group.pending_requests": "Pending Requests",
|
||||
"manage_group.privacy.hint": "These settings cannot be changed later.",
|
||||
"manage_group.privacy.label": "Privacy settings",
|
||||
"manage_group.privacy.private.hint": "Discoverable. Users can join after their request is approved.",
|
||||
|
|
Loading…
Reference in a new issue