import { Drawer, DrawerContent, DrawerOverlay } from '@/components/ui/drawer' import { Popover, PopoverAnchor, PopoverContent } from '@/components/ui/popover' import { LONG_PRESS_THRESHOLD } from '@/constants' import { useStuff } from '@/hooks/useStuff' import { useStuffStatsById } from '@/hooks/useStuffStatsById' import { createExternalContentReactionDraftEvent, createReactionDraftEvent } from '@/lib/draft-event' import { useNostr } from '@/providers/NostrProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useUserPreferences } from '@/providers/UserPreferencesProvider' import { useUserTrust } from '@/providers/UserTrustProvider' import client from '@/services/client.service' import stuffStatsService from '@/services/stuff-stats.service' import { TEmoji } from '@/types' import { Loader, SmilePlus } from 'lucide-react' import { Event } from 'nostr-tools' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import Emoji from '../Emoji' import EmojiPicker from '../EmojiPicker' import SuggestedEmojis from '../SuggestedEmojis' import KeyboardShortcut from './KeyboardShortcut' import { formatCount } from './utils' export default function LikeButton({ stuff }: { stuff: Event | string }) { const { t } = useTranslation() const { isSmallScreen } = useScreenSize() const { pubkey, publish, checkLogin } = useNostr() const { hideUntrustedInteractions, isUserTrusted } = useUserTrust() const { quickReaction, quickReactionEmoji } = useUserPreferences() const { event, externalContent, stuffKey } = useStuff(stuff) const [liking, setLiking] = useState(false) const [isEmojiReactionsOpen, setIsEmojiReactionsOpen] = useState(false) const [isPickerOpen, setIsPickerOpen] = useState(false) const longPressTimerRef = useRef(null) const isLongPressRef = useRef(false) const noteStats = useStuffStatsById(stuffKey) const { myLastEmoji, likeCount } = useMemo(() => { const stats = noteStats || {} const myLike = stats.likes?.find((like) => like.pubkey === pubkey) const likes = hideUntrustedInteractions ? stats.likes?.filter((like) => isUserTrusted(like.pubkey)) : stats.likes return { myLastEmoji: myLike?.emoji, likeCount: likes?.length } }, [noteStats, pubkey, hideUntrustedInteractions]) useEffect(() => { setTimeout(() => setIsPickerOpen(false), 100) }, [isEmojiReactionsOpen]) const like = async (emoji: string | TEmoji) => { checkLogin(async () => { if (liking || !pubkey) return setLiking(true) const timer = setTimeout(() => setLiking(false), 10_000) try { if (!noteStats?.updatedAt) { await stuffStatsService.fetchStuffStats(stuffKey, pubkey) } const reaction = event ? createReactionDraftEvent(event, emoji) : createExternalContentReactionDraftEvent(externalContent, emoji) const seenOn = event ? client.getSeenEventRelayUrls(event.id) : client.currentRelays const evt = await publish(reaction, { additionalRelayUrls: seenOn }) stuffStatsService.updateStuffStatsByEvents([evt]) } catch (error) { console.error('like failed', error) } finally { setLiking(false) clearTimeout(timer) } }) } const handleLongPressStart = () => { if (!quickReaction) return isLongPressRef.current = false longPressTimerRef.current = setTimeout(() => { isLongPressRef.current = true setIsEmojiReactionsOpen(true) }, LONG_PRESS_THRESHOLD) } const handleLongPressEnd = () => { if (longPressTimerRef.current) { clearTimeout(longPressTimerRef.current) longPressTimerRef.current = null } } const handleClick = (e: React.MouseEvent | React.TouchEvent) => { if (quickReaction) { // If it was a long press, don't trigger the click action if (isLongPressRef.current) { isLongPressRef.current = false return } // Quick reaction mode: click to react with default emoji // Prevent dropdown from opening e.preventDefault() e.stopPropagation() like(quickReactionEmoji) } else { setIsEmojiReactionsOpen(true) } } const trigger = ( ) if (isSmallScreen) { return ( <> {trigger} setIsEmojiReactionsOpen(false)} /> { setIsEmojiReactionsOpen(false) if (!emoji) return like(emoji) }} /> ) } return ( setIsEmojiReactionsOpen(open)}> {trigger} {isPickerOpen ? ( { e.stopPropagation() setIsEmojiReactionsOpen(false) if (!emoji) return like(emoji) }} /> ) : ( { setIsEmojiReactionsOpen(false) like(emoji) }} onMoreButtonClick={() => { setIsPickerOpen(true) }} onClose={() => setIsEmojiReactionsOpen(false)} /> )} ) }