2023-03-13 06:47:23 -07:00
import clsx from 'clsx' ;
import React , { useMemo } from 'react' ;
import { defineMessages , useIntl } from 'react-intl' ;
2023-03-17 11:20:03 -07:00
import { groupKick } from 'soapbox/actions/groups' ;
2023-03-13 06:47:23 -07:00
import { openModal } from 'soapbox/actions/modals' ;
2023-05-01 11:58:40 -07:00
import { useAccount , useBlockGroupMember , useDemoteGroupMember , usePromoteGroupMember } from 'soapbox/api/hooks' ;
2023-03-13 06:47:23 -07:00
import Account from 'soapbox/components/account' ;
2023-03-15 11:53:17 -07:00
import DropdownMenu from 'soapbox/components/dropdown-menu/dropdown-menu' ;
import { HStack } from 'soapbox/components/ui' ;
import { deleteEntities } from 'soapbox/entity-store/actions' ;
import { Entities } from 'soapbox/entity-store/entities' ;
2023-04-04 05:11:03 -07:00
import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder-account' ;
import { useAppDispatch , useFeatures } from 'soapbox/hooks' ;
2023-03-20 05:53:38 -07:00
import { GroupRoles } from 'soapbox/schemas/group-member' ;
2023-03-13 06:47:23 -07:00
import toast from 'soapbox/toast' ;
2023-04-04 11:05:08 -07:00
import { MAX_ADMIN_COUNT } from '../group-members' ;
2023-03-13 06:47:23 -07:00
import type { Menu as IMenu } from 'soapbox/components/dropdown-menu' ;
2023-04-04 05:11:03 -07:00
import type { Group , GroupMember } from 'soapbox/types/entities' ;
2023-03-13 06:47:23 -07:00
const messages = defineMessages ( {
2023-04-04 11:05:08 -07:00
adminLimitTitle : { id : 'group.member.admin.limit.title' , defaultMessage : 'Admin limit reached' } ,
2023-06-03 11:31:21 -07:00
adminLimitSummary : { id : 'group.member.admin.limit.summary' , defaultMessage : 'You can assign up to {count, plural, one {admin} other {admins}} for the group at this time.' } ,
2023-03-20 05:53:38 -07:00
blockConfirm : { id : 'confirmations.block_from_group.confirm' , defaultMessage : 'Ban' } ,
2023-03-15 11:53:17 -07:00
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?' } ,
2023-03-20 05:53:38 -07:00
blocked : { id : 'group.group_mod_block.success' , defaultMessage : '@{name} is banned' } ,
demotedToUser : { id : 'group.demote.user.success' , defaultMessage : '@{name} is now a member' } ,
2023-03-15 11:53:17 -07:00
groupModBlock : { id : 'group.group_mod_block' , defaultMessage : 'Ban from group' } ,
2023-03-17 11:20:03 -07:00
groupModDemote : { id : 'group.group_mod_demote' , defaultMessage : 'Remove {role} role' } ,
2023-03-13 06:47:23 -07:00
groupModKick : { id : 'group.group_mod_kick' , defaultMessage : 'Kick @{name} from group' } ,
2023-03-17 11:20:03 -07:00
groupModPromoteMod : { id : 'group.group_mod_promote_mod' , defaultMessage : 'Assign {role} role' } ,
2023-03-13 06:47:23 -07:00
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' } ,
2023-03-20 05:53:38 -07:00
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' } ,
2023-03-13 06:47:23 -07:00
} ) ;
interface IGroupMemberListItem {
member : GroupMember
group : Group
2023-04-04 11:05:08 -07:00
canPromoteToAdmin : boolean
2023-03-13 06:47:23 -07:00
}
const GroupMemberListItem = ( props : IGroupMemberListItem ) = > {
2023-04-04 11:05:08 -07:00
const { canPromoteToAdmin , member , group } = props ;
2023-03-13 06:47:23 -07:00
const dispatch = useAppDispatch ( ) ;
2023-03-15 11:53:17 -07:00
const features = useFeatures ( ) ;
2023-03-13 06:47:23 -07:00
const intl = useIntl ( ) ;
2023-03-15 11:53:17 -07:00
const blockGroupMember = useBlockGroupMember ( group , member ) ;
2023-03-17 11:20:03 -07:00
const promoteGroupMember = usePromoteGroupMember ( group , member ) ;
const demoteGroupMember = useDemoteGroupMember ( group , member ) ;
2023-03-13 06:47:23 -07:00
2023-04-04 05:11:03 -07:00
const { account , isLoading } = useAccount ( member . account . id ) ;
2023-03-13 06:47:23 -07:00
// Current user role
2023-03-20 05:53:38 -07:00
const isCurrentUserOwner = group . relationship ? . role === GroupRoles . OWNER ;
const isCurrentUserAdmin = group . relationship ? . role === GroupRoles . ADMIN ;
2023-03-13 06:47:23 -07:00
// Member role
2023-03-20 05:53:38 -07:00
const isMemberOwner = member . role === GroupRoles . OWNER ;
const isMemberAdmin = member . role === GroupRoles . ADMIN ;
const isMemberUser = member . role === GroupRoles . USER ;
2023-03-13 06:47:23 -07:00
const handleKickFromGroup = ( ) = > {
dispatch ( openModal ( 'CONFIRM' , {
2023-04-04 05:11:03 -07:00
message : intl.formatMessage ( messages . kickFromGroupMessage , { name : account?.username } ) ,
2023-03-13 06:47:23 -07:00
confirm : intl.formatMessage ( messages . kickConfirm ) ,
2023-04-04 05:11:03 -07:00
onConfirm : ( ) = > dispatch ( groupKick ( group . id , account ? . id as string ) ) . then ( ( ) = >
toast . success ( intl . formatMessage ( messages . kicked , { name : account?.acct } ) ) ,
2023-03-13 06:47:23 -07:00
) ,
} ) ) ;
} ;
const handleBlockFromGroup = ( ) = > {
dispatch ( openModal ( 'CONFIRM' , {
2023-03-15 11:53:17 -07:00
heading : intl.formatMessage ( messages . blockFromGroupHeading ) ,
2023-04-04 05:11:03 -07:00
message : intl.formatMessage ( messages . blockFromGroupMessage , { name : account?.username } ) ,
2023-03-13 06:47:23 -07:00
confirm : intl.formatMessage ( messages . blockConfirm ) ,
2023-03-17 11:20:03 -07:00
onConfirm : ( ) = > {
blockGroupMember ( { account_ids : [ member . account . id ] } , {
onSuccess() {
dispatch ( deleteEntities ( [ member . id ] , Entities . GROUP_MEMBERSHIPS ) ) ;
2023-04-04 05:11:03 -07:00
toast . success ( intl . formatMessage ( messages . blocked , { name : account?.acct } ) ) ;
2023-03-17 11:20:03 -07:00
} ,
} ) ;
} ,
2023-03-13 06:47:23 -07:00
} ) ) ;
} ;
2023-03-20 05:53:38 -07:00
const handleAdminAssignment = ( ) = > {
2023-04-04 11:05:08 -07:00
if ( ! canPromoteToAdmin ) {
toast . error ( intl . formatMessage ( messages . adminLimitTitle ) , {
summary : intl.formatMessage ( messages . adminLimitSummary , { count : MAX_ADMIN_COUNT } ) ,
} ) ;
return ;
}
2023-03-20 05:53:38 -07:00
dispatch ( openModal ( 'CONFIRM' , {
heading : intl.formatMessage ( messages . promoteConfirm ) ,
2023-04-04 05:11:03 -07:00
message : intl.formatMessage ( messages . promoteConfirmMessage , { name : account?.username } ) ,
2023-03-20 05:53:38 -07:00
confirm : intl.formatMessage ( messages . promoteConfirm ) ,
confirmationTheme : 'primary' ,
onConfirm : ( ) = > {
2023-04-04 05:11:03 -07:00
promoteGroupMember ( { role : GroupRoles.ADMIN , account_ids : [ account ? . id ] } , {
2023-03-20 05:53:38 -07:00
onSuccess() {
toast . success (
2023-04-04 05:11:03 -07:00
intl . formatMessage ( messages . promotedToAdmin , { name : account?.acct } ) ,
2023-03-20 05:53:38 -07:00
) ;
} ,
} ) ;
} ,
} ) ) ;
2023-03-13 06:47:23 -07:00
} ;
2023-03-20 05:53:38 -07:00
const handleUserAssignment = ( ) = > {
2023-04-04 05:11:03 -07:00
demoteGroupMember ( { role : GroupRoles.USER , account_ids : [ account ? . id ] } , {
2023-03-17 11:20:03 -07:00
onSuccess() {
2023-04-04 05:11:03 -07:00
toast . success ( intl . formatMessage ( messages . demotedToUser , { name : account?.acct } ) ) ;
2023-03-17 11:20:03 -07:00
} ,
} ) ;
2023-03-13 06:47:23 -07:00
} ;
const menu : IMenu = useMemo ( ( ) = > {
const items : IMenu = [ ] ;
if ( ! group || ! account || ! group . relationship ? . role ) {
return items ;
}
2023-03-20 05:53:38 -07:00
if ( isCurrentUserOwner ) {
if ( isMemberUser ) {
2023-03-17 11:20:03 -07:00
items . push ( {
2023-03-20 05:53:38 -07:00
text : intl.formatMessage ( messages . groupModPromoteMod , { role : GroupRoles.ADMIN } ) ,
2023-03-17 11:20:03 -07:00
icon : require ( '@tabler/icons/briefcase.svg' ) ,
2023-03-20 05:53:38 -07:00
action : handleAdminAssignment ,
2023-03-17 11:20:03 -07:00
} ) ;
2023-03-20 05:53:38 -07:00
} else if ( isMemberAdmin ) {
2023-03-17 11:20:03 -07:00
items . push ( {
2023-03-20 05:53:38 -07:00
text : intl.formatMessage ( messages . groupModDemote , { role : GroupRoles.ADMIN , name : account.username } ) ,
2023-03-17 11:20:03 -07:00
icon : require ( '@tabler/icons/briefcase.svg' ) ,
2023-03-20 05:53:38 -07:00
action : handleUserAssignment ,
destructive : true ,
2023-03-17 11:20:03 -07:00
} ) ;
}
}
2023-03-13 06:47:23 -07:00
if (
2023-03-20 05:53:38 -07:00
( isCurrentUserOwner || isCurrentUserAdmin ) &&
( isMemberAdmin || isMemberUser ) &&
2023-03-13 06:47:23 -07:00
member . role !== group . relationship . role
) {
2023-03-15 11:53:17 -07:00
if ( features . groupsKick ) {
items . push ( {
text : intl.formatMessage ( messages . groupModKick , { name : account.username } ) ,
icon : require ( '@tabler/icons/user-minus.svg' ) ,
action : handleKickFromGroup ,
} ) ;
}
2023-03-13 06:47:23 -07:00
items . push ( {
text : intl.formatMessage ( messages . groupModBlock , { name : account.username } ) ,
icon : require ( '@tabler/icons/ban.svg' ) ,
action : handleBlockFromGroup ,
2023-03-15 11:53:17 -07:00
destructive : true ,
2023-03-13 06:47:23 -07:00
} ) ;
}
return items ;
2023-04-04 05:11:03 -07:00
} , [ group , account ? . id ] ) ;
if ( isLoading ) {
return < PlaceholderAccount / > ;
}
2023-03-13 06:47:23 -07:00
return (
2023-05-05 05:35:11 -07:00
< HStack
alignItems = 'center'
justifyContent = 'between'
data - testid = 'group-member-list-item'
>
2023-03-13 06:47:23 -07:00
< div className = 'w-full' >
< Account account = { member . account } withRelationship = { false } / >
< / div >
< HStack alignItems = 'center' space = { 2 } >
2023-03-20 05:53:38 -07:00
{ ( isMemberOwner || isMemberAdmin ) ? (
2023-03-13 06:47:23 -07:00
< span
2023-05-05 05:35:11 -07:00
data - testid = 'role-badge'
2023-03-13 06:47:23 -07:00
className = {
clsx ( 'inline-flex items-center rounded px-2 py-1 text-xs font-medium capitalize' , {
2023-06-01 09:44:11 -07:00
'bg-primary-200 text-primary-500 dark:bg-primary-800 dark:text-primary-200' : isMemberOwner ,
'bg-gray-200 text-gray-900 dark:bg-gray-800 dark:text-gray-100' : isMemberAdmin ,
2023-03-13 06:47:23 -07:00
} )
}
>
{ member . role }
< / span >
) : null }
2023-03-15 11:53:17 -07:00
< DropdownMenu items = { menu } / >
2023-03-13 06:47:23 -07:00
< / HStack >
< / HStack >
) ;
} ;
2023-06-03 11:31:21 -07:00
export default GroupMemberListItem ;