7310426ea7
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
136 lines
3.9 KiB
TypeScript
136 lines
3.9 KiB
TypeScript
import {
|
|
AppBskyEmbedRecord,
|
|
type ChatBskyActorDefs,
|
|
ChatBskyConvoDefs,
|
|
ChatBskyEmbedJoinLink,
|
|
} from '@atproto/api'
|
|
import {type I18n} from '@lingui/core'
|
|
import {msg} from '@lingui/core/macro'
|
|
|
|
import {isBlockedOrBlocking} from '#/lib/moderation/blocked-and-muted'
|
|
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
|
import {
|
|
postUriToRelativePath,
|
|
toBskyAppUrl,
|
|
toShortUrl,
|
|
} from '#/lib/strings/url-helpers'
|
|
import type * as bsky from '#/types/bsky'
|
|
|
|
export type UserMessageInfo = {
|
|
message: string | null
|
|
sentAt: string
|
|
reportableMessage?: ChatBskyConvoDefs.MessageView
|
|
isBlockedMessage: boolean
|
|
}
|
|
|
|
/**
|
|
* Resolves whether the given did is blocked (in either direction) within a
|
|
* convo. Prefers the passed-in shadowed `primaryProfile` so optimistic blocks
|
|
* reflect immediately, before the convo list refetches - the raw `members`
|
|
* fetched with the convo are invisible to the profile shadow cache. Group
|
|
* members other than the owner fall back to the raw (potentially stale) member.
|
|
*/
|
|
export function isDidBlockedInConvo({
|
|
did,
|
|
members,
|
|
primaryProfile,
|
|
}: {
|
|
did: string | undefined
|
|
members: ChatBskyActorDefs.ProfileViewBasic[]
|
|
primaryProfile?: bsky.profile.AnyProfileView
|
|
}): boolean {
|
|
if (!did) return false
|
|
if (primaryProfile && primaryProfile.did === did) {
|
|
return isBlockedOrBlocking(primaryProfile)
|
|
}
|
|
const member = members.find(m => m.did === did)
|
|
return member ? isBlockedOrBlocking(member) : false
|
|
}
|
|
|
|
export function getMessageInfo({
|
|
convo,
|
|
currentAccountDid,
|
|
primaryProfile,
|
|
i18n,
|
|
}: {
|
|
convo: ChatBskyConvoDefs.ConvoView
|
|
currentAccountDid: string | undefined
|
|
primaryProfile?: bsky.profile.AnyProfileView
|
|
i18n: I18n
|
|
}): UserMessageInfo | null {
|
|
if (!ChatBskyConvoDefs.isMessageView(convo.lastMessage)) {
|
|
return null
|
|
}
|
|
|
|
const lastMessage = convo.lastMessage
|
|
const isFromMe = lastMessage.sender?.did === currentAccountDid
|
|
const senderDid = lastMessage.sender?.did
|
|
const sender = convo.members.find(m => m.did === senderDid)
|
|
const name = sender ? createSanitizedDisplayName(sender) : null
|
|
const isGroup = ChatBskyConvoDefs.isGroupConvo(convo.kind)
|
|
|
|
const reportableMessage = isFromMe ? undefined : lastMessage
|
|
const isBlockedMessage = isDidBlockedInConvo({
|
|
did: senderDid,
|
|
members: convo.members,
|
|
primaryProfile,
|
|
})
|
|
|
|
const prefix = (message: string) => {
|
|
if (isFromMe) {
|
|
return i18n._(
|
|
msg({
|
|
message: `You: ${message}`,
|
|
comment: 'When the last message in a chat was made by you.',
|
|
}),
|
|
)
|
|
} else if (isGroup && name) {
|
|
return i18n._(
|
|
msg({
|
|
message: `${name}: ${message}`,
|
|
comment:
|
|
'When the last message in a group chat came from someone other than you.',
|
|
}),
|
|
)
|
|
}
|
|
return message
|
|
}
|
|
|
|
let message: string | null = null
|
|
|
|
if (lastMessage.text) {
|
|
message = prefix(lastMessage.text)
|
|
} else if (lastMessage.embed) {
|
|
const defaultEmbeddedContentMessage = i18n._(
|
|
msg`(contains embedded content)`,
|
|
)
|
|
|
|
if (AppBskyEmbedRecord.isView(lastMessage.embed)) {
|
|
const embed = lastMessage.embed
|
|
|
|
if (AppBskyEmbedRecord.isViewRecord(embed.record)) {
|
|
const record = embed.record
|
|
const path = postUriToRelativePath(record.uri, {
|
|
handle: record.author.handle,
|
|
})
|
|
const href = path ? toBskyAppUrl(path) : undefined
|
|
const short = href ? toShortUrl(href) : defaultEmbeddedContentMessage
|
|
message = prefix(short)
|
|
} else {
|
|
message = prefix(defaultEmbeddedContentMessage)
|
|
}
|
|
} else if (ChatBskyEmbedJoinLink.isView(lastMessage.embed)) {
|
|
message = prefix(i18n._(msg`(chat invite link)`))
|
|
} else {
|
|
message = prefix(defaultEmbeddedContentMessage)
|
|
}
|
|
}
|
|
|
|
return {
|
|
message,
|
|
sentAt: lastMessage.sentAt,
|
|
reportableMessage,
|
|
isBlockedMessage,
|
|
}
|
|
}
|