[DMs] Reactions - link up API (attempt 2) (#8074)

* update package

* wire up APIs

* get reactions to display

* allow removing emoji

* handle limits better

* listen to reactions in log

* update convo list with reactions

* tweaks to reaction display

* Handle empty message fallback case

* update package

* shift reacts up by 2px

---------

Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
Samuel Newman
2025-03-28 16:34:07 +02:00
committed by GitHub
parent 55a40c2436
commit 152bc3c1ec
17 changed files with 659 additions and 123 deletions
+46 -29
View File
@@ -1,5 +1,5 @@
import {useMemo, useState} from 'react'
import {Alert, useWindowDimensions, View} from 'react-native'
import {useWindowDimensions, View} from 'react-native'
import {type ChatBskyConvoDefs} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
@@ -18,12 +18,15 @@ import {
import {type TriggerProps} from '#/components/Menu/types'
import {Text} from '#/components/Typography'
import {EmojiPopup} from './EmojiPopup'
import {hasAlreadyReacted, hasReachedReactionLimit} from './util'
export function EmojiReactionPicker({
message,
onEmojiSelect,
}: {
message: ChatBskyConvoDefs.MessageView
children?: TriggerProps['children']
onEmojiSelect: (emoji: string) => void
}) {
const {_} = useLingui()
const {currentAccount} = useSession()
@@ -39,10 +42,6 @@ export function EmojiReactionPicker({
return Math.random() < 0.01 ? EmojiHeartEyesIcon : EmojiSmileIcon
}, [])
const handleEmojiSelect = (emoji: string) => {
Alert.alert(emoji)
}
const position = useMemo(() => {
return {
x: align === 'left' ? 12 : screenWidth - layout.width - 12,
@@ -52,6 +51,8 @@ export function EmojiReactionPicker({
}
}, [measurement, align, screenWidth, layout])
const limitReacted = hasReachedReactionLimit(message, currentAccount?.did)
return (
<View
onLayout={evt => setLayout(evt.nativeEvent.layout)}
@@ -70,33 +71,49 @@ export function EmojiReactionPicker({
t.atoms.border_contrast_low,
a.shadow_md,
]}>
{['👍', '😆', '❤️', '👀', '😢'].map(emoji => (
<ContextMenu.Item
position={position}
label={_(msg`React with ${emoji}`)}
key={emoji}
onPress={() => handleEmojiSelect(emoji)}
unstyled>
{hovered => (
<View
style={[
a.rounded_full,
hovered && {backgroundColor: t.palette.primary_500},
{height: 40, width: 40},
a.justify_center,
a.align_center,
]}>
<Text style={[a.text_center, {fontSize: 30}]} emoji>
{emoji}
</Text>
</View>
)}
</ContextMenu.Item>
))}
{['👍', '😆', '❤️', '👀', '😢'].map(emoji => {
const alreadyReacted = hasAlreadyReacted(
message,
currentAccount?.did,
emoji,
)
return (
<ContextMenu.Item
position={position}
label={_(msg`React with ${emoji}`)}
key={emoji}
onPress={() => onEmojiSelect(emoji)}
unstyled
disabled={limitReacted ? !alreadyReacted : false}>
{hovered => (
<View
style={[
a.rounded_full,
hovered
? {
backgroundColor: alreadyReacted
? t.palette.negative_100
: t.palette.primary_500,
}
: alreadyReacted && {
backgroundColor: t.palette.primary_200,
},
{height: 40, width: 40},
a.justify_center,
a.align_center,
]}>
<Text style={[a.text_center, {fontSize: 30}]} emoji>
{emoji}
</Text>
</View>
)}
</ContextMenu.Item>
)
})}
<EmojiPopup
onEmojiSelected={emoji => {
close()
handleEmojiSelect(emoji)
onEmojiSelect(emoji)
}}>
<View
style={[