import { useMemo } from "react"; import { Pressable, Text, View } from "react-native"; import { Plus } from "lucide-react-native"; import * as Haptics from "expo-haptics"; import { REACTION_EMOJIS, type Reactions } from "@/api/types"; import type { Human } from "@/api/types"; import { resolveHumanDisplay } from "@/lib/humans"; import { cn } from "@/lib/utils"; const EMOJI_SET = new Set(REACTION_EMOJIS); interface ReactionStackProps { reactions: Reactions; currentHumanId: string; humans: Human[] | undefined; /** Toggle a reaction (emoji or text) — same contract as ReactionSheet's onToggle. */ onToggle: (key: string) => void; /** Open the full reaction sheet for emoji + custom-text picking. */ onOpenSheet: () => void; } /** * Right-edge reaction stack — mobile counterpart of desktop's ReactionBar. * Sits vertically centered on the right side of the canvas so the user can * see existing reactions at a glance and tap to toggle their own. The "+" * affordance opens the ReactionSheet for the full picker (emoji or text). */ export function ReactionStack({ reactions, currentHumanId, humans, onToggle, onOpenSheet, }: ReactionStackProps) { const activeEmojis = REACTION_EMOJIS.filter( (emoji) => reactions?.[emoji] && (reactions[emoji]?.length ?? 0) > 0, ); const activeTextKeys = useMemo( () => Object.keys(reactions ?? {}).filter( (k) => !EMOJI_SET.has(k) && (reactions?.[k]?.length ?? 0) > 0, ), [reactions], ); const handleToggle = (key: string) => { void Haptics.selectionAsync(); onToggle(key); }; return ( {activeEmojis.map((emoji) => { const reactors = reactions?.[emoji] ?? []; const isMine = reactors.includes(currentHumanId); return ( handleToggle(emoji)} className={cn( "flex-row items-center gap-1 rounded-full px-2 py-1", isMine ? "bg-white/25" : "bg-black/45", )} style={ isMine ? { borderWidth: 1, borderColor: "rgba(255,255,255,0.4)" } : undefined } > {emoji} {reactors.length} ); })} {activeTextKeys.map((text) => { const reactors = reactions?.[text] ?? []; const isMine = reactors.includes(currentHumanId); const firstReactor = resolveHumanDisplay(reactors[0], humans); return ( handleToggle(text)} className={cn( "flex-row items-center gap-1.5 rounded-full py-1 pl-1 pr-2.5", isMine ? "bg-white/25" : "bg-black/45", )} style={[ { maxWidth: 200 }, isMine ? { borderWidth: 1, borderColor: "rgba(255,255,255,0.4)" } : null, ]} > {firstReactor.initials} {text} {reactors.length > 1 ? ( {reactors.length} ) : null} ); })} ); }