diff --git a/app/soapbox/components/groups/group-avatar.tsx b/app/soapbox/components/groups/group-avatar.tsx index 91d6808d2..9b3213bb9 100644 --- a/app/soapbox/components/groups/group-avatar.tsx +++ b/app/soapbox/components/groups/group-avatar.tsx @@ -23,8 +23,9 @@ const GroupAvatar = (props: IGroupAvatar) => { className={ clsx('relative rounded-full', { 'shadow-[0_0_0_2px_theme(colors.primary.600),0_0_0_4px_theme(colors.white)]': isOwner && withRing, + 'dark:shadow-[0_0_0_2px_theme(colors.primary.600),0_0_0_4px_theme(colors.gray.800)]': isOwner && withRing, 'shadow-[0_0_0_2px_theme(colors.primary.600)]': isOwner && !withRing, - 'shadow-[0_0_0_2px_theme(colors.white)]': !isOwner && withRing, + 'shadow-[0_0_0_2px_theme(colors.white)] dark:shadow-[0_0_0_2px_theme(colors.gray.800)]': !isOwner && withRing, }) } src={group.avatar} diff --git a/app/soapbox/components/ui/button/useButtonStyles.ts b/app/soapbox/components/ui/button/useButtonStyles.ts index 1b61fc7b4..740b06ba4 100644 --- a/app/soapbox/components/ui/button/useButtonStyles.ts +++ b/app/soapbox/components/ui/button/useButtonStyles.ts @@ -9,7 +9,7 @@ const themes = { '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', accent: 'border-transparent bg-secondary-500 hover:bg-secondary-400 focus:bg-secondary-500 text-gray-100 focus:ring-secondary-300', danger: 'border-transparent bg-danger-100 dark:bg-danger-900 text-danger-600 dark:text-danger-200 hover:bg-danger-600 hover:text-gray-100 dark:hover:text-gray-100 dark:hover:bg-danger-500 focus:ring-danger-500', - transparent: 'border-transparent text-gray-800 backdrop-blur-sm bg-white/75 hover:bg-white/80', + transparent: 'border-transparent bg-transparent text-primary-600 dark:text-accent-blue dark:bg-transparent hover:bg-gray-200 dark:hover:bg-gray-800/50', outline: 'border-gray-100 border-2 bg-transparent text-gray-100 hover:bg-white/10', muted: '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', }; diff --git a/app/soapbox/components/ui/popover/popover.tsx b/app/soapbox/components/ui/popover/popover.tsx index 7700f8149..7f909f8bc 100644 --- a/app/soapbox/components/ui/popover/popover.tsx +++ b/app/soapbox/components/ui/popover/popover.tsx @@ -13,6 +13,8 @@ import { import clsx from 'clsx'; import React, { useRef, useState } from 'react'; +import Portal from '../portal/portal'; + interface IPopover { children: React.ReactElement> /** The content of the popover */ @@ -83,31 +85,33 @@ const Popover: React.FC = (props) => { })} {(isMounted) && ( -
- {content} + +
+ {content} - -
+ +
+ )} ); diff --git a/app/soapbox/features/group/components/__tests__/group-options-button.test.tsx b/app/soapbox/features/group/components/__tests__/group-options-button.test.tsx new file mode 100644 index 000000000..4d7779799 --- /dev/null +++ b/app/soapbox/features/group/components/__tests__/group-options-button.test.tsx @@ -0,0 +1,85 @@ +import React from 'react'; + +import { buildGroup, buildGroupRelationship } from 'soapbox/jest/factory'; +import { render, screen } from 'soapbox/jest/test-helpers'; +import { GroupRoles } from 'soapbox/schemas/group-member'; +import { Group } from 'soapbox/types/entities'; + +import GroupOptionsButton from '../group-options-button'; + +let group: Group; + +describe('', () => { + describe('when the user blocked', () => { + beforeEach(() => { + group = buildGroup({ + relationship: buildGroupRelationship({ + requested: false, + member: true, + blocked_by: true, + role: 'user', + }), + }); + }); + + it('should render null', () => { + render(); + + expect(screen.queryAllByTestId('dropdown-menu-button')).toHaveLength(0); + }); + }); + + describe('when the user is an admin', () => { + beforeEach(() => { + group = buildGroup({ + relationship: buildGroupRelationship({ + requested: false, + member: true, + role: GroupRoles.ADMIN, + }), + }); + }); + + it('should render null', () => { + render(); + + expect(screen.queryAllByTestId('dropdown-menu-button')).toHaveLength(0); + }); + }); + + describe('when the user is an owner', () => { + beforeEach(() => { + group = buildGroup({ + relationship: buildGroupRelationship({ + requested: false, + member: true, + role: GroupRoles.OWNER, + }), + }); + }); + + it('should render null', () => { + render(); + + expect(screen.queryAllByTestId('dropdown-menu-button')).toHaveLength(0); + }); + }); + + describe('when the user is a member', () => { + beforeEach(() => { + group = buildGroup({ + relationship: buildGroupRelationship({ + requested: false, + member: true, + role: GroupRoles.USER, + }), + }); + }); + + it('should render the dropdown menu', () => { + render(); + + expect(screen.queryAllByTestId('dropdown-menu-button')).toHaveLength(1); + }); + }); +}); \ No newline at end of file diff --git a/app/soapbox/features/group/components/__tests__/group-relationship.test.tsx b/app/soapbox/features/group/components/__tests__/group-relationship.test.tsx new file mode 100644 index 000000000..4c6c10a48 --- /dev/null +++ b/app/soapbox/features/group/components/__tests__/group-relationship.test.tsx @@ -0,0 +1,66 @@ +import React from 'react'; + +import { buildGroup, buildGroupRelationship } from 'soapbox/jest/factory'; +import { render, screen } from 'soapbox/jest/test-helpers'; +import { GroupRoles } from 'soapbox/schemas/group-member'; +import { Group } from 'soapbox/types/entities'; + +import GroupRelationship from '../group-relationship'; + +let group: Group; + +describe('', () => { + describe('when the user is an admin', () => { + beforeEach(() => { + group = buildGroup({ + relationship: buildGroupRelationship({ + requested: false, + member: true, + role: GroupRoles.ADMIN, + }), + }); + }); + + it('should render the relationship', () => { + render(); + + expect(screen.getByTestId('group-relationship')).toHaveTextContent('Admin'); + }); + }); + + describe('when the user is an owner', () => { + beforeEach(() => { + group = buildGroup({ + relationship: buildGroupRelationship({ + requested: false, + member: true, + role: GroupRoles.OWNER, + }), + }); + }); + + it('should render the relationship', () => { + render(); + + expect(screen.getByTestId('group-relationship')).toHaveTextContent('Owner'); + }); + }); + + describe('when the user is a member', () => { + beforeEach(() => { + group = buildGroup({ + relationship: buildGroupRelationship({ + requested: false, + member: true, + role: GroupRoles.USER, + }), + }); + }); + + it('should render null', () => { + render(); + + expect(screen.queryAllByTestId('group-relationship')).toHaveLength(0); + }); + }); +}); \ No newline at end of file diff --git a/app/soapbox/features/group/components/group-options-button.tsx b/app/soapbox/features/group/components/group-options-button.tsx index 54ded9181..b6e83ae06 100644 --- a/app/soapbox/features/group/components/group-options-button.tsx +++ b/app/soapbox/features/group/components/group-options-button.tsx @@ -1,4 +1,5 @@ import React, { useMemo } from 'react'; +import { defineMessages, useIntl } from 'react-intl'; import { initReport, ReportableEntities } from 'soapbox/actions/reports'; import DropdownMenu, { Menu } from 'soapbox/components/dropdown-menu'; @@ -8,20 +9,25 @@ import { GroupRoles } from 'soapbox/schemas/group-member'; import type { Account, Group } from 'soapbox/types/entities'; +const messages = defineMessages({ + report: { id: 'group.report.label', defaultMessage: 'Report' }, +}); + interface IGroupActionButton { group: Group } const GroupOptionsButton = ({ group }: IGroupActionButton) => { - const dispatch = useAppDispatch(); const account = useOwnAccount(); + const dispatch = useAppDispatch(); + const intl = useIntl(); const isMember = group.relationship?.role === GroupRoles.USER; const isBlocked = group.relationship?.blocked_by; const menu: Menu = useMemo(() => ([ { - text: 'Report', + text: intl.formatMessage(messages.report), icon: require('@tabler/icons/flag.svg'), action: () => dispatch(initReport(ReportableEntities.GROUP, account as Account, { group })), }, @@ -38,6 +44,7 @@ const GroupOptionsButton = ({ group }: IGroupActionButton) => { theme='secondary' iconClassName='h-5 w-5' className='self-stretch px-2.5' + data-testid='dropdown-menu-button' /> ); diff --git a/app/soapbox/features/group/components/group-relationship.tsx b/app/soapbox/features/group/components/group-relationship.tsx index c71adbbe8..8fd47ac2d 100644 --- a/app/soapbox/features/group/components/group-relationship.tsx +++ b/app/soapbox/features/group/components/group-relationship.tsx @@ -13,12 +13,17 @@ const GroupRelationship = ({ group }: IGroupRelationship) => { const isOwner = group.relationship?.role === GroupRoles.OWNER; const isAdmin = group.relationship?.role === GroupRoles.ADMIN; - if (!isOwner || !isAdmin) { + if (!isOwner && !isAdmin) { return null; } return ( - + { {isOwner - ? - : } + ? + : } ); diff --git a/app/soapbox/features/groups/pending-requests.tsx b/app/soapbox/features/groups/pending-requests.tsx index de52ae4c6..cc9ceed1d 100644 --- a/app/soapbox/features/groups/pending-requests.tsx +++ b/app/soapbox/features/groups/pending-requests.tsx @@ -18,7 +18,6 @@ export default () => { const { groups, isLoading } = usePendingGroups(); - const renderBlankslate = () => ( { {/* Group Cover Image */}
- + {/* Group Avatar */}
diff --git a/app/soapbox/features/ui/components/modals/manage-group-modal/steps/confirmation-step.tsx b/app/soapbox/features/ui/components/modals/manage-group-modal/steps/confirmation-step.tsx index 1b71e36c9..7db6d9c20 100644 --- a/app/soapbox/features/ui/components/modals/manage-group-modal/steps/confirmation-step.tsx +++ b/app/soapbox/features/ui/components/modals/manage-group-modal/steps/confirmation-step.tsx @@ -3,8 +3,10 @@ import { FormattedMessage } from 'react-intl'; import { Avatar, Divider, HStack, Stack, Text, Button } from 'soapbox/components/ui'; +import type { Group } from 'soapbox/schemas'; + interface IConfirmationStep { - group: any + group: Group } const ConfirmationStep: React.FC = ({ group }) => { @@ -53,24 +55,30 @@ const ConfirmationStep: React.FC = ({ group }) => { - + + + - + + + - + + + @@ -96,7 +104,7 @@ interface IInfoListNumber { const InfoListNumber: React.FC = ({ number }) => { return ( -
+
{number}
); @@ -109,9 +117,11 @@ interface IInfoListItem { const InfoListItem: React.FC = ({ number, children }) => { return ( - -
-
{children}
+ + +
+ {children} +
); }; diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index 1bc6cba4c..81a4ed1da 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -799,8 +799,9 @@ "group.promote.admin.confirmation.message": "Are you sure you want to assign the admin role to @{name}?", "group.promote.admin.confirmation.title": "Assign Admin Role", "group.promote.admin.success": "@{name} is now an admin", + "group.report.label": "Report", "group.role.admin": "Admin", - "group.role.moderator": "Moderator", + "group.role.owner": "Owner", "group.tabs.all": "All", "group.tabs.members": "Members", "group.upload_banner": "Upload photo",