update consumers for ConvoWithDetails and relatedProfiles

- use convoState.convo.view for raw ConvoView fields
- use convoState.convo.kind === 'group' instead of isGroup()
- use item.relatedProfiles for sender/reaction profile lookups
- pass relatedProfiles into getSystemMessageInfo for display names
- add relatedProfiles to pending-message items

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-04-22 21:42:12 +03:00
parent 2a8c0a9dce
commit 21b494e5ab
9 changed files with 34 additions and 32 deletions
+2 -2
View File
@@ -183,7 +183,7 @@ export let MessageContextMenu = ({
control={reportControl}
subject={{
view: 'message',
convoId: convo.convo.id,
convoId: convo.convo.view.id,
message,
}}
onAfterSubmit={() => {
@@ -197,7 +197,7 @@ export let MessageContextMenu = ({
control={blockOrDeleteControl}
currentScreen="conversation"
params={{
convoId: convo.convo.id,
convoId: convo.convo.view.id,
message,
}}
/>
+1 -1
View File
@@ -9,7 +9,7 @@ import {Text} from '#/components/Typography'
export function SystemMessageItem({
item,
}: {
item: ConvoItem & {type: 'system-message'}
item: Extract<ConvoItem, {type: 'system-message'}>
}) {
const t = useTheme()
const {i18n} = useLingui()
+4 -3
View File
@@ -1,4 +1,4 @@
import {type ChatBskyActorDefs, ChatBskyConvoDefs} from '@atproto/api'
import {ChatBskyConvoDefs} from '@atproto/api'
import {type MessageDescriptor} from '@lingui/core'
import {msg} from '@lingui/core/macro'
@@ -15,6 +15,7 @@ import {
Unlock_Stroke2_Corner2_Rounded as UnlockIcon,
} from '#/components/icons/Lock'
import {PencilLine_Stroke2_Corner0_Rounded as PencilIcon} from '#/components/icons/Pencil'
import type * as bsky from '#/types/bsky'
export type SystemMessageInfo = {
message: MessageDescriptor
@@ -23,7 +24,7 @@ export type SystemMessageInfo = {
function getReferredDisplayName(
user: ChatBskyConvoDefs.SystemMessageReferredUser,
relatedProfiles: ChatBskyActorDefs.ProfileViewBasic[],
relatedProfiles: bsky.profile.AnyProfileView[],
): string | null {
const profile = relatedProfiles.find(p => p.did === user.did)
return profile ? createSanitizedDisplayName(profile) : null
@@ -31,7 +32,7 @@ function getReferredDisplayName(
export function getSystemMessageInfo(
data: ChatBskyConvoDefs.SystemMessageView['data'],
relatedProfiles: ChatBskyActorDefs.ProfileViewBasic[],
relatedProfiles: bsky.profile.AnyProfileView[],
): SystemMessageInfo | null {
if (ChatBskyConvoDefs.isSystemMessageDataAddMember(data)) {
const name = getReferredDisplayName(data.member, relatedProfiles)
@@ -34,7 +34,7 @@ import {AvatarBubbles} from '#/components/AvatarBubbles'
import {Button, type ButtonColor, ButtonIcon} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {AddMembersFlow} from '#/components/dms/AddMembersFlow'
import {type ConvoWithDetails, parseConvoView} from '#/components/dms/util'
import {type ConvoWithDetails} from '#/components/dms/util'
import {Error} from '#/components/Error'
import * as TextField from '#/components/forms/TextField'
import {useInteractionState} from '#/components/hooks/useInteractionState'
@@ -129,8 +129,6 @@ function SettingsInner() {
const {currentAccount} = useSession()
const convo = convoState.convo
? parseConvoView(convoState.convo, currentAccount?.did)
: null
const primaryMember = convo?.primaryMember
const isOwner = !!primaryMember && primaryMember.did === currentAccount?.did
@@ -5,7 +5,6 @@ import {useLingui} from '@lingui/react'
import {type ActiveConvoStates} from '#/state/messages/convo'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useSession} from '#/state/session'
import {atoms as a, useTheme} from '#/alf'
import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
import {KnownFollowers} from '#/components/KnownFollowers'
@@ -16,16 +15,16 @@ export function ChatStatusInfo({convoState}: {convoState: ActiveConvoStates}) {
const t = useTheme()
const {_} = useLingui()
const moderationOpts = useModerationOpts()
const {currentAccount} = useSession()
const leaveConvoControl = usePromptControl()
const onAcceptChat = useCallback(() => {
convoState.markConvoAccepted()
}, [convoState])
const otherUser = convoState.recipients.find(
user => user.did !== currentAccount?.did,
)
const otherUser =
convoState.convo.kind === 'direct'
? convoState.convo.primaryMember
: undefined
if (!moderationOpts) {
return null
@@ -44,7 +43,7 @@ export function ChatStatusInfo({convoState}: {convoState: ActiveConvoStates}) {
{otherUser && (
<RejectMenu
label={_(msg`Block or report`)}
convo={convoState.convo}
convo={convoState.convo.view}
profile={otherUser}
color="negative_subtle"
size="small"
@@ -53,14 +52,14 @@ export function ChatStatusInfo({convoState}: {convoState: ActiveConvoStates}) {
)}
<DeleteChatButton
label={_(msg`Delete`)}
convo={convoState.convo}
convo={convoState.convo.view}
color="secondary"
size="small"
currentScreen="conversation"
onPress={leaveConvoControl.open}
/>
<LeaveConvoPrompt
convoId={convoState.convo.id}
convoId={convoState.convo.view.id}
control={leaveConvoControl}
currentScreen="conversation"
hasMessages={false}
@@ -69,7 +68,7 @@ export function ChatStatusInfo({convoState}: {convoState: ActiveConvoStates}) {
<View style={[a.w_full, a.flex_row]}>
<AcceptChatButton
onAcceptConvo={onAcceptChat}
convo={convoState.convo}
convo={convoState.convo.view}
color="primary_subtle"
size="small"
currentScreen="conversation"
@@ -373,13 +373,14 @@ export function MessagesList({
const renderItem = ({item}: {item: ConvoItem}) => {
if (item.type === 'message' || item.type === 'pending-message') {
const profile = item.relatedProfiles.find(
p => p.did === item.message.sender.did,
)
return (
<MessageItem
item={item}
profile={convoState.convo.members.find(
member => member.did === item.message.sender.did,
)}
isGroupChat={convoState.isGroup()}
profile={profile}
isGroupChat={convoState.convo.kind === 'group'}
/>
)
} else if (item.type === 'deleted-message') {
@@ -448,7 +449,8 @@ export function MessagesList({
ListHeaderComponent={
<>
<MaybeLoader isLoading={convoState.isFetchingHistory} />
{convoState.isGroup() && convoState.hasAllHistory ? (
{convoState.convo.kind === 'group' &&
convoState.hasAllHistory ? (
<MessagesListInfoPanel convoState={convoState} />
) : null}
</>
@@ -577,7 +579,7 @@ function getFooterState(
}
}
if (convoState.convo.status === 'request' && !hasAcceptOverride) {
if (convoState.convo.view.status === 'request' && !hasAcceptOverride) {
return 'request'
}
@@ -20,16 +20,19 @@ export function MessagesListInfoPanel({convoState}: {convoState: ConvoState}) {
const {currentAccount} = useSession()
const convo = convoState.convo
const isGroup = convo?.kind === 'group'
const isOwner =
currentAccount?.did == null
currentAccount?.did == null || !isGroup
? false
: convoState.getPrimaryMember?.()?.did === currentAccount.did
: convo.primaryMember.did === currentAccount.did
// TODO Get this from @api/atproto - dsb
const isLinkEnabled = false
const groupName = convoState.getGroupInfo?.()?.name
const groupName = isGroup ? convo.details.name : undefined
const members = (convoState?.convo?.members ?? []).filter(
const members = (convo?.members ?? []).filter(
profile => profile.did !== currentAccount?.did,
)
+2 -4
View File
@@ -1133,6 +1133,7 @@ export class Convo {
})
this.pendingMessages.forEach(m => {
const senderProfile = this.relatedProfiles.get(this.senderUserDid)
items.push({
type: 'pending-message',
key: m.id,
@@ -1143,15 +1144,12 @@ export class Convo {
id: nanoid(),
rev: '__fake__',
sentAt: new Date().toISOString(),
/*
* `getItems` is only run in "active" status states, where
* `this.sender` is defined
*/
sender: {
$type: 'chat.bsky.convo.defs#messageViewSender',
did: this.senderUserDid,
},
},
relatedProfiles: senderProfile ? [senderProfile] : [],
nextMessage: null,
prevMessage: null,
failed: this.pendingMessageFailure !== null,
+1
View File
@@ -103,6 +103,7 @@ export type ConvoItem =
type: 'pending-message'
key: string
message: ChatBskyConvoDefs.MessageView
relatedProfiles: bsky.profile.AnyProfileView[]
nextMessage:
| ChatBskyConvoDefs.MessageView
| ChatBskyConvoDefs.DeletedMessageView