about summary refs log tree commit diff
path: root/src/components/dms/EmojiReactionPicker.tsx
blob: a98cebf9a2a8e591536dca245d1e3b27f6f7428a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import {useMemo, useState} from 'react'
import {Alert, useWindowDimensions, View} from 'react-native'
import {type ChatBskyConvoDefs} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'

import {useSession} from '#/state/session'
import {atoms as a, tokens, useTheme} from '#/alf'
import * as ContextMenu from '#/components/ContextMenu'
import {
  useContextMenuContext,
  useContextMenuMenuContext,
} from '#/components/ContextMenu/context'
import {
  EmojiHeartEyes_Stroke2_Corner0_Rounded as EmojiHeartEyesIcon,
  EmojiSmile_Stroke2_Corner0_Rounded as EmojiSmileIcon,
} from '#/components/icons/Emoji'
import {type TriggerProps} from '#/components/Menu/types'
import {Text} from '#/components/Typography'
import {EmojiPopup} from './EmojiPopup'

export function EmojiReactionPicker({
  message,
}: {
  message: ChatBskyConvoDefs.MessageView
  children?: TriggerProps['children']
}) {
  const {_} = useLingui()
  const {currentAccount} = useSession()
  const t = useTheme()
  const isFromSelf = message.sender?.did === currentAccount?.did
  const {measurement, close} = useContextMenuContext()
  const {align} = useContextMenuMenuContext()
  const [layout, setLayout] = useState({width: 0, height: 0})
  const {width: screenWidth} = useWindowDimensions()

  // 1 in 100 chance of showing heart eyes icon
  const EmojiIcon = useMemo(() => {
    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,
      y: (measurement?.y ?? 0) - tokens.space.xs - layout.height,
      height: layout.height,
      width: layout.width,
    }
  }, [measurement, align, screenWidth, layout])

  return (
    <View
      onLayout={evt => setLayout(evt.nativeEvent.layout)}
      style={[
        a.rounded_full,
        a.absolute,
        {bottom: '100%'},
        isFromSelf ? a.right_0 : a.left_0,
        t.scheme === 'light' ? t.atoms.bg : t.atoms.bg_contrast_25,
        a.flex_row,
        a.p_xs,
        a.gap_xs,
        a.mb_xs,
        a.z_20,
        a.border,
        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>
      ))}
      <EmojiPopup
        onEmojiSelected={emoji => {
          close()
          handleEmojiSelect(emoji)
        }}>
        <View
          style={[
            a.rounded_full,
            t.scheme === 'light'
              ? t.atoms.bg_contrast_25
              : t.atoms.bg_contrast_50,
            {height: 40, width: 40},
            a.justify_center,
            a.align_center,
            a.border,
            t.atoms.border_contrast_low,
          ]}>
          <EmojiIcon size="xl" fill={t.palette.contrast_400} />
        </View>
      </EmojiPopup>
    </View>
  )
}