diff --git a/src/screens/Messages/components/MessagesList.tsx b/src/screens/Messages/components/MessagesList.tsx index 81b2331f06..aa7ed07d6c 100644 --- a/src/screens/Messages/components/MessagesList.tsx +++ b/src/screens/Messages/components/MessagesList.tsx @@ -65,6 +65,7 @@ import {ChatStatusInfo} from './ChatStatusInfo' import {groupSystemMessages, type RenderItem} from './groupSystemMessages' import {InviteLinkDialogProvider} from './InviteLinkDialogProvider' import {MessageInputEmbed, useMessageEmbed} from './MessageInputEmbed' +import {MessagesListGroupInfoPanel} from './MessagesListGroupInfoPanel' import {MessagesListInfoPanel} from './MessagesListInfoPanel' import {KeyboardStickyView} from './vendor/KeyboardStickyView' @@ -509,9 +510,12 @@ export function MessagesList({ ListHeaderComponent={ <> - {convoState.convo?.kind === 'group' && - convoState.hasAllHistory ? ( - + {convoState.hasAllHistory ? ( + convoState.convo?.kind === 'group' ? ( + + ) : ( + + ) ) : null} } diff --git a/src/screens/Messages/components/MessagesListGroupInfoPanel.tsx b/src/screens/Messages/components/MessagesListGroupInfoPanel.tsx new file mode 100644 index 0000000000..78c61ac313 --- /dev/null +++ b/src/screens/Messages/components/MessagesListGroupInfoPanel.tsx @@ -0,0 +1,176 @@ +import {View} from 'react-native' +import {Plural, Trans, useLingui} from '@lingui/react/macro' + +import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name' +import {logger} from '#/logger' +import {useModerationOpts} from '#/state/preferences/moderation-opts' +import {useAddGroupMembers} from '#/state/queries/messages/add-group-members' +import {useSession} from '#/state/session' +import {atoms as a, useTheme} from '#/alf' +import {AvatarBubbles} from '#/components/AvatarBubbles' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import * as Dialog from '#/components/Dialog' +import {AddMembersFlow} from '#/components/dms/AddMembersFlow' +import {type ConvoWithDetails} from '#/components/dms/util' +import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' +import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' +import * as Toast from '#/components/Toast' +import {Text} from '#/components/Typography' +import {InviteLinkDialog} from './InviteLinkDialog' + +export function MessagesListGroupInfoPanel({ + convo, +}: { + convo: Extract +}) { + const t = useTheme() + const {t: l} = useLingui() + const moderationOpts = useModerationOpts() + const convoId = convo.view.id + + const addMembersControl = Dialog.useDialogControl() + const inviteLinkControl = Dialog.useDialogControl() + + const {currentAccount} = useSession() + + const {mutate: addGroupMembers} = useAddGroupMembers(convoId, { + onSuccess: () => { + addMembersControl.close() + }, + onError: e => { + logger.error('Failed to add group chat members', {message: e}) + Toast.show(l`Failed to add members`, {type: 'error'}) + }, + }) + + // TODO Enable this once the feature is working end-to-end. -dsb + // const joinLink = groupConvo?.details.joinLink + const isJoinLinkEnabled = false + // (isOwner && groupConvo) || + // (!isOwner && groupConvo && joinLink?.enabledStatus === 'enabled') + + const isOwner = convo.primaryMember?.did === currentAccount?.did + + const members = (convo.members ?? []).filter( + profile => profile.did !== currentAccount?.did, + ) + + let names: React.ReactNode = null + if (members.length === 1) { + names = ( + New chat with {createSanitizedDisplayName(members[0])} + ) + } else if (members.length === 2) { + names = ( + + New chat with {createSanitizedDisplayName(members[0])} and{' '} + {createSanitizedDisplayName(members[1])} + + ) + } else if (members.length > 2) { + const memberCount = convo.details.memberCount - 2 + names = ( + + New chat with {createSanitizedDisplayName(members[0])},{' '} + {createSanitizedDisplayName(members[1])}, and{' '} + + . + + ) + } + + const showButtons = isOwner || isJoinLinkEnabled + + return ( + <> + + + {convo.details.name ? ( + + {convo.details.name} + + ) : null} + {names ? ( + + {names} + + ) : null} + {showButtons ? ( + + {isOwner ? ( + + ) : null} + {isJoinLinkEnabled ? ( + + ) : null} + + ) : null} + + {convo.primaryMember && moderationOpts && ( + + )} + + + + addGroupMembers({members, profiles}) + } + /> + + + ) +} diff --git a/src/screens/Messages/components/MessagesListInfoPanel.tsx b/src/screens/Messages/components/MessagesListInfoPanel.tsx index 6a4ce31510..695fc74d37 100644 --- a/src/screens/Messages/components/MessagesListInfoPanel.tsx +++ b/src/screens/Messages/components/MessagesListInfoPanel.tsx @@ -1,176 +1,99 @@ import {View} from 'react-native' -import {Plural, Trans, useLingui} from '@lingui/react/macro' +import {moderateProfile} from '@atproto/api' +import {Trans, useLingui} from '@lingui/react/macro' +import {useNavigation} from '@react-navigation/native' import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name' -import {logger} from '#/logger' +import {type NavigationProp} from '#/lib/routes/types' +import {isInvalidHandle, sanitizeHandle} from '#/lib/strings/handles' import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {useAddGroupMembers} from '#/state/queries/messages/add-group-members' import {useSession} from '#/state/session' +import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useTheme} from '#/alf' -import {AvatarBubbles} from '#/components/AvatarBubbles' import {Button, ButtonIcon, ButtonText} from '#/components/Button' -import * as Dialog from '#/components/Dialog' -import {AddMembersFlow} from '#/components/dms/AddMembersFlow' import {type ConvoWithDetails} from '#/components/dms/util' -import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' -import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' -import * as Toast from '#/components/Toast' +import {Person_Stroke2_Corner2_Rounded as PersonIcon} from '#/components/icons/Person' +import {ProfileBadges} from '#/components/ProfileBadges' +import * as ProfileCard from '#/components/ProfileCard' import {Text} from '#/components/Typography' -import {InviteLinkDialog} from './InviteLinkDialog' export function MessagesListInfoPanel({ convo, }: { - convo: Extract + convo: Extract }) { + const navigation = useNavigation() const t = useTheme() const {t: l} = useLingui() - const moderationOpts = useModerationOpts() - const convoId = convo.view.id - - const addMembersControl = Dialog.useDialogControl() - const inviteLinkControl = Dialog.useDialogControl() const {currentAccount} = useSession() + const moderationOpts = useModerationOpts() - const {mutate: addGroupMembers} = useAddGroupMembers(convoId, { - onSuccess: () => { - addMembersControl.close() - }, - onError: e => { - logger.error('Failed to add group chat members', {message: e}) - Toast.show(l`Failed to add members`, {type: 'error'}) - }, - }) - - // TODO Enable this once the feature is working end-to-end. -dsb - // const joinLink = groupConvo?.details.joinLink - const isJoinLinkEnabled = false - // (isOwner && groupConvo) || - // (!isOwner && groupConvo && joinLink?.enabledStatus === 'enabled') - - const isOwner = convo.primaryMember?.did === currentAccount?.did - - const members = (convo.members ?? []).filter( + const profile = convo.members.filter( profile => profile.did !== currentAccount?.did, - ) - - let names: React.ReactNode = null - if (members.length === 1) { - names = ( - New chat with {createSanitizedDisplayName(members[0])} - ) - } else if (members.length === 2) { - names = ( - - New chat with {createSanitizedDisplayName(members[0])} and{' '} - {createSanitizedDisplayName(members[1])} - - ) - } else if (members.length > 2) { - const memberCount = convo.details.memberCount - 2 - names = ( - - New chat with {createSanitizedDisplayName(members[0])},{' '} - {createSanitizedDisplayName(members[1])}, and{' '} - - . - - ) - } - - const showButtons = isOwner || isJoinLinkEnabled + )[0] + const handle = sanitizeHandle(profile.handle, '@') + const displayName = moderationOpts + ? createSanitizedDisplayName( + profile, + true, + moderateProfile(profile, moderationOpts).ui('displayName'), + ) + : handle + const profileLink = + profile.handle && !isInvalidHandle(profile.handle) + ? profile.handle + : profile.did return ( - <> - - - {convo.details.name ? ( - - {convo.details.name} - - ) : null} - {names ? ( - - {names} - - ) : null} - {showButtons ? ( - - {isOwner ? ( - - ) : null} - {isJoinLinkEnabled ? ( - - ) : null} - - ) : null} + + + + + {displayName} + + - {convo.primaryMember && moderationOpts && ( - - )} - - - - addGroupMembers({members, profiles}) - } - /> - - + + {handle} + + {moderationOpts ? ( + + + + ) : null} + + + + ) }