[Chat] Prevent reactions when unavailable (#10615)

This commit is contained in:
Samuel Newman
2026-05-26 19:55:30 +03:00
committed by GitHub
parent 308b2e05f1
commit 1113686e30
5 changed files with 125 additions and 33 deletions
+39 -25
View File
@@ -1,8 +1,9 @@
import {useCallback, useRef, useState} from 'react'
import {Pressable, View} from 'react-native'
import {type ChatBskyConvoDefs} from '@atproto/api'
import {type ChatBskyConvoDefs, type ModerationOpts} from '@atproto/api'
import {useLingui} from '@lingui/react/macro'
import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
import {useConvoActive} from '#/state/messages/convo'
import {useSession} from '#/state/session'
import {atoms as a, useTheme} from '#/alf'
@@ -12,19 +13,21 @@ import {EmojiSmile_Stroke2_Corner0_Rounded as EmojiSmileIcon} from '#/components
import * as Toast from '#/components/Toast'
import type * as bsky from '#/types/bsky'
import {EmojiReactionPicker} from './EmojiReactionPicker'
import {hasReachedReactionLimit} from './util'
import {canReact, hasReachedReactionLimit} from './util'
export function ActionsWrapper({
message,
hasReactions,
isFromSelf,
senderProfile,
moderationOpts,
children,
}: {
message: ChatBskyConvoDefs.MessageView
hasReactions?: boolean
isFromSelf: boolean
senderProfile?: bsky.profile.AnyProfileView
moderationOpts: ModerationOpts | undefined
children: React.ReactNode
}) {
const viewRef = useRef(null)
@@ -32,6 +35,12 @@ export function ActionsWrapper({
const {t: l} = useLingui()
const convo = useConvoActive()
const {currentAccount} = useSession()
const primaryMember = useMaybeProfileShadow(convo.convo.primaryMember)
const reactionsAvailable = canReact({
convoState: convo,
primaryMember,
moderationOpts,
})
const [showActions, setShowActions] = useState(false)
@@ -93,29 +102,34 @@ export function ActionsWrapper({
: [a.ml_xs, {marginRight: 'auto'}],
hasReactions ? [a.mb_2xl] : undefined,
]}>
<EmojiReactionPicker message={message} onEmojiSelect={onEmojiSelect}>
{({props, state, IS_NATIVE, control}) => {
// always false, file is platform split
if (IS_NATIVE) return null
const showMenuTrigger = showActions || control.isOpen ? 1 : 0
return (
<Pressable
{...props}
style={[
{opacity: showMenuTrigger},
a.p_xs,
a.rounded_full,
(state.hovered || state.pressed) && t.atoms.bg_contrast_25,
]}>
<EmojiSmileIcon
size="md"
style={t.atoms.text_contrast_medium}
/>
</Pressable>
)
}}
</EmojiReactionPicker>
<MessageContextMenu message={message} senderProfile={senderProfile}>
{reactionsAvailable && (
<EmojiReactionPicker message={message} onEmojiSelect={onEmojiSelect}>
{({props, state, IS_NATIVE, control}) => {
// always false, file is platform split
if (IS_NATIVE) return null
const showMenuTrigger = showActions || control.isOpen ? 1 : 0
return (
<Pressable
{...props}
style={[
{opacity: showMenuTrigger},
a.p_xs,
a.rounded_full,
(state.hovered || state.pressed) && t.atoms.bg_contrast_25,
]}>
<EmojiSmileIcon
size="md"
style={t.atoms.text_contrast_medium}
/>
</Pressable>
)
}}
</EmojiReactionPicker>
)}
<MessageContextMenu
message={message}
senderProfile={senderProfile}
moderationOpts={moderationOpts}>
{({props, state, IS_NATIVE, control}) => {
// always false, file is platform split
if (IS_NATIVE) return null