@ -2,7 +2,7 @@ import clsx from 'clsx';
import React , { useMemo } from 'react' ;
import { defineMessages , useIntl } from 'react-intl' ;
import { group DemoteAccount, group Kick, groupPromoteAccount } from 'soapbox/actions/groups' ;
import { group Kick } from 'soapbox/actions/groups' ;
import { openModal } from 'soapbox/actions/modals' ;
import Account from 'soapbox/components/account' ;
import DropdownMenu from 'soapbox/components/dropdown-menu/dropdown-menu' ;
@ -10,31 +10,29 @@ import { HStack } from 'soapbox/components/ui';
import { deleteEntities } from 'soapbox/entity-store/actions' ;
import { Entities } from 'soapbox/entity-store/entities' ;
import { useAccount , useAppDispatch , useFeatures } from 'soapbox/hooks' ;
import { useBlockGroupMember } from 'soapbox/hooks/api /groups/useBlockGroupMember ';
import { BaseGroupRoles, use GroupRoles } from 'soapbox/ hooks/useGroupRoles ';
import { useBlockGroupMember , useDemoteGroupMember , usePromoteGroupMember } from 'soapbox/hooks/api ';
import { GroupRoles } from 'soapbox/ schemas/group-member ';
import toast from 'soapbox/toast' ;
import type { Menu as IMenu } from 'soapbox/components/dropdown-menu' ;
import type { Account as AccountEntity , Group , GroupMember } from 'soapbox/types/entities' ;
const messages = defineMessages ( {
blockConfirm : { id : 'confirmations.block_from_group.confirm' , defaultMessage : 'B lock ' } ,
blockConfirm : { id : 'confirmations.block_from_group.confirm' , defaultMessage : 'B an ' } ,
blockFromGroupHeading : { id : 'confirmations.block_from_group.heading' , defaultMessage : 'Ban From Group' } ,
blockFromGroupMessage : { id : 'confirmations.block_from_group.message' , defaultMessage : 'Are you sure you want to ban @{name} from the group?' } ,
blocked : { id : 'group.group_mod_block.success' , defaultMessage : ' You have successfully blocked @{name} from the group ' } ,
demotedToUser : { id : 'group. group_mod_ demote.success', defaultMessage : ' Demoted @{name} to group us er' } ,
blocked : { id : 'group.group_mod_block.success' , defaultMessage : ' @{name} is banned ' } ,
demotedToUser : { id : 'group. demote.user .success', defaultMessage : ' @{name} is now a memb er' } ,
groupModBlock : { id : 'group.group_mod_block' , defaultMessage : 'Ban from group' } ,
groupModDemote : { id : 'group.group_mod_demote' , defaultMessage : ' Demote @{name} ' } ,
groupModDemote : { id : 'group.group_mod_demote' , defaultMessage : ' Remove {role} role ' } ,
groupModKick : { id : 'group.group_mod_kick' , defaultMessage : 'Kick @{name} from group' } ,
groupModPromoteAdmin : { id : 'group.group_mod_promote_admin' , defaultMessage : 'Promote @{name} to group administrator' } ,
groupModPromoteMod : { id : 'group.group_mod_promote_mod' , defaultMessage : 'Promote @{name} to group moderator' } ,
groupModPromoteMod : { id : 'group.group_mod_promote_mod' , defaultMessage : 'Assign {role} role' } ,
kickConfirm : { id : 'confirmations.kick_from_group.confirm' , defaultMessage : 'Kick' } ,
kickFromGroupMessage : { id : 'confirmations.kick_from_group.message' , defaultMessage : 'Are you sure you want to kick @{name} from this group?' } ,
kicked : { id : 'group.group_mod_kick.success' , defaultMessage : 'Kicked @{name} from group' } ,
promoteConfirm : { id : 'confirmations.promote_in_group.confirm' , defaultMessage : 'Promote' } ,
promoteConfirmMessage : { id : 'confirmations.promote_in_group.message' , defaultMessage : 'Are you sure you want to promote @{name}? You will not be able to demote them.' } ,
promotedToAdmin : { id : 'group.group_mod_promote_admin.success' , defaultMessage : 'Promoted @{name} to group administrator' } ,
promotedToMod : { id : 'group.group_mod_promote_mod.success' , defaultMessage : 'Promoted @{name} to group moderator' } ,
promoteConfirm : { id : 'group.promote.admin.confirmation.title' , defaultMessage : 'Assign Admin Role' } ,
promoteConfirmMessage : { id : 'group.promote.admin.confirmation.message' , defaultMessage : 'Are you sure you want to assign the admin role to @{name}?' } ,
promotedToAdmin : { id : 'group.promote.admin.success' , defaultMessage : '@{name} is now an admin' } ,
} ) ;
interface IGroupMemberListItem {
@ -49,19 +47,20 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => {
const features = useFeatures ( ) ;
const intl = useIntl ( ) ;
const { normalizeRole } = useGroupRoles ( ) ;
const blockGroupMember = useBlockGroupMember ( group , member ) ;
const promoteGroupMember = usePromoteGroupMember ( group , member ) ;
const demoteGroupMember = useDemoteGroupMember ( group , member ) ;
const account = useAccount ( member . account . id ) as AccountEntity ;
// Current user role
const isCurrentUser Admin = normalizeRole ( group . relationship ? . role as any ) === BaseGroupRoles . ADMIN ;
const isCurrentUser Moderator = normalizeRole ( group . relationship ? . role as any ) === BaseGroupRoles . MODERATOR ;
const isCurrentUser Owner = group . relationship ? . role === GroupRoles . OWNER ;
const isCurrentUser Admin = group . relationship ? . role === GroupRoles . ADMIN ;
// Member role
const isMember Admin = normalizeRole ( member . role as any ) === BaseGroupRoles . ADMIN ;
const isMember Moderator = normalizeRole ( member . role as any ) === BaseGroupRoles . MODERATOR ;
const isMemberUser = normalizeRole( member. role as any ) === Base GroupRoles. USER ;
const isMember Owner = member . role === GroupRoles . OWNER ;
const isMember Admin = member . role === GroupRoles . ADMIN ;
const isMemberUser = member. role === GroupRoles. USER ;
const handleKickFromGroup = ( ) = > {
dispatch ( openModal ( 'CONFIRM' , {
@ -78,39 +77,41 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => {
heading : intl.formatMessage ( messages . blockFromGroupHeading ) ,
message : intl.formatMessage ( messages . blockFromGroupMessage , { name : account.username } ) ,
confirm : intl.formatMessage ( messages . blockConfirm ) ,
onConfirm : ( ) = > blockGroupMember ( { account_ids : [ member . account . id ] } ) . then ( ( ) = > {
dispatch ( deleteEntities ( [ member . id ] , Entities . GROUP_MEMBERSHIPS ) ) ;
toast . success ( intl . formatMessage ( messages . blocked , { name : account.acct } ) ) ;
} ) ,
onConfirm : ( ) = > {
blockGroupMember ( { account_ids : [ member . account . id ] } , {
onSuccess() {
dispatch ( deleteEntities ( [ member . id ] , Entities . GROUP_MEMBERSHIPS ) ) ;
toast . success ( intl . formatMessage ( messages . blocked , { name : account.acct } ) ) ;
} ,
} ) ;
} ,
} ) ) ;
} ;
const onPromote = ( role : 'admin' | 'moderator' , warning? : boolean ) = > {
if ( warning ) {
return dispatch ( openModal ( 'CONFIRM' , {
message : intl.formatMessage ( messages . promoteConfirmMessage , { name : account.username } ) ,
confirm : intl.formatMessage ( messages . promoteConfirm ) ,
onConfirm : ( ) = > dispatch ( groupPromoteAccount ( group . id , account . id , role ) ) . then ( ( ) = >
toast . success ( intl . formatMessage ( role === 'admin' ? messages.promotedToAdmin : messages.promotedToMod , { name : account.acct } ) ) ,
) ,
} ) ) ;
} else {
return dispatch ( groupPromoteAccount ( group . id , account . id , role ) ) . then ( ( ) = >
toast . success ( intl . formatMessage ( role === 'admin' ? messages.promotedToAdmin : messages.promotedToMod , { name : account.acct } ) ) ,
) ;
}
} ;
const handlePromoteToGroupAdmin = ( ) = > onPromote ( 'admin' , true ) ;
const handlePromoteToGroupMod = ( ) = > {
onPromote ( 'moderator' , group . relationship ! . role === 'moderator' ) ;
const handleAdminAssignment = ( ) = > {
dispatch ( openModal ( 'CONFIRM' , {
heading : intl.formatMessage ( messages . promoteConfirm ) ,
message : intl.formatMessage ( messages . promoteConfirmMessage , { name : account.username } ) ,
confirm : intl.formatMessage ( messages . promoteConfirm ) ,
confirmationTheme : 'primary' ,
onConfirm : ( ) = > {
promoteGroupMember ( { role : GroupRoles.ADMIN , account_ids : [ account . id ] } , {
onSuccess() {
toast . success (
intl . formatMessage ( messages . promotedToAdmin , { name : account.acct } ) ,
) ;
} ,
} ) ;
} ,
} ) ) ;
} ;
const handleDemote = ( ) = > {
dispatch ( groupDemoteAccount ( group . id , account . id , 'user' ) ) . then ( ( ) = >
toast . success ( intl . formatMessage ( messages . demotedToUser , { name : account.acct } ) ) ,
) . catch ( ( ) = > { } ) ;
const handleUserAssignment = ( ) = > {
demoteGroupMember ( { role : GroupRoles.USER , account_ids : [ account . id ] } , {
onSuccess() {
toast . success ( intl . formatMessage ( messages . demotedToUser , { name : account.acct } ) ) ;
} ,
} ) ;
} ;
const menu : IMenu = useMemo ( ( ) = > {
@ -120,9 +121,26 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => {
return items ;
}
if ( isCurrentUserOwner ) {
if ( isMemberUser ) {
items . push ( {
text : intl.formatMessage ( messages . groupModPromoteMod , { role : GroupRoles.ADMIN } ) ,
icon : require ( '@tabler/icons/briefcase.svg' ) ,
action : handleAdminAssignment ,
} ) ;
} else if ( isMemberAdmin ) {
items . push ( {
text : intl.formatMessage ( messages . groupModDemote , { role : GroupRoles.ADMIN , name : account.username } ) ,
icon : require ( '@tabler/icons/briefcase.svg' ) ,
action : handleUserAssignment ,
destructive : true ,
} ) ;
}
}
if (
( isCurrentUserAdmin || isCurrentUserModerator ) &&
( isMemberModerator || isMemberUser ) &&
( isCurrentUser Owner || isCurrentUserAdmin ) &&
( isMember Admin || isMemberUser ) &&
member . role !== group . relationship . role
) {
if ( features . groupsKick ) {
@ -141,29 +159,6 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => {
} ) ;
}
if ( isCurrentUserAdmin && ! isMemberAdmin && account . acct === account . username ) {
items . push ( null ) ;
if ( isMemberModerator ) {
items . push ( {
text : intl.formatMessage ( messages . groupModPromoteAdmin , { name : account.username } ) ,
icon : require ( '@tabler/icons/arrow-up-circle.svg' ) ,
action : handlePromoteToGroupAdmin ,
} ) ;
items . push ( {
text : intl.formatMessage ( messages . groupModDemote , { name : account.username } ) ,
icon : require ( '@tabler/icons/arrow-down-circle.svg' ) ,
action : handleDemote ,
} ) ;
} else if ( isMemberUser ) {
items . push ( {
text : intl.formatMessage ( messages . groupModPromoteMod , { name : account.username } ) ,
icon : require ( '@tabler/icons/arrow-up-circle.svg' ) ,
action : handlePromoteToGroupMod ,
} ) ;
}
}
return items ;
} , [ group , account ] ) ;
@ -174,12 +169,12 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => {
< / div >
< HStack alignItems = 'center' space = { 2 } >
{ ( isMember Admin || isMemberModerator ) ? (
{ ( isMember Owner || isMemberAdmin ) ? (
< span
className = {
clsx ( 'inline-flex items-center rounded px-2 py-1 text-xs font-medium capitalize' , {
'bg-primary-200 text-primary-500' : isMember Admin ,
'bg-gray-200 text-gray-900' : isMember Moderator ,
'bg-primary-200 text-primary-500' : isMember Owner ,
'bg-gray-200 text-gray-900' : isMember Admin ,
} )
}
>