11'use client'
22
3- import { useCallback , useState } from 'react'
3+ import { useCallback , useEffect , useRef , useState } from 'react'
44import { Check , Copy , Ellipsis , Hash } from 'lucide-react'
55import {
6- Popover ,
7- PopoverContent ,
8- PopoverItem ,
9- PopoverScrollArea ,
10- PopoverTrigger ,
6+ DropdownMenu ,
7+ DropdownMenuContent ,
8+ DropdownMenuItem ,
9+ DropdownMenuTrigger ,
10+ Tooltip ,
1111} from '@/components/emcn'
1212
1313interface MessageActionsProps {
@@ -16,60 +16,75 @@ interface MessageActionsProps {
1616}
1717
1818export function MessageActions ( { content, requestId } : MessageActionsProps ) {
19- const [ open , setOpen ] = useState ( false )
2019 const [ copied , setCopied ] = useState < 'message' | 'request' | null > ( null )
20+ const resetTimeoutRef = useRef < number | null > ( null )
21+
22+ useEffect ( ( ) => {
23+ return ( ) => {
24+ if ( resetTimeoutRef . current !== null ) {
25+ window . clearTimeout ( resetTimeoutRef . current )
26+ }
27+ }
28+ } , [ ] )
2129
2230 const copyToClipboard = useCallback ( async ( text : string , type : 'message' | 'request' ) => {
2331 try {
2432 await navigator . clipboard . writeText ( text )
2533 setCopied ( type )
26- setTimeout ( ( ) => setCopied ( null ) , 1500 )
34+ if ( resetTimeoutRef . current !== null ) {
35+ window . clearTimeout ( resetTimeoutRef . current )
36+ }
37+ resetTimeoutRef . current = window . setTimeout ( ( ) => setCopied ( null ) , 1500 )
2738 } catch {
28- // Silently fail
39+ return
2940 }
30- setOpen ( false )
3141 } , [ ] )
3242
43+ if ( ! content && ! requestId ) {
44+ return null
45+ }
46+
3347 return (
34- < Popover variant = 'default' size = 'sm' open = { open } onOpenChange = { setOpen } >
35- < PopoverTrigger asChild >
36- < button
37- type = 'button'
38- className = 'rounded-md p-1 text-[var(--text-icon)] opacity-0 transition-opacity hover:bg-[var(--surface-3)] group-hover/msg:opacity-100 data-[state=open]:opacity-100'
39- onClick = { ( e ) => e . stopPropagation ( ) }
48+ < DropdownMenu modal = { false } >
49+ < Tooltip . Root >
50+ < Tooltip . Trigger asChild >
51+ < DropdownMenuTrigger asChild >
52+ < button
53+ type = 'button'
54+ aria-label = 'More options'
55+ className = 'flex h-5 w-5 items-center justify-center rounded-sm text-[var(--text-icon)] opacity-0 transition-colors transition-opacity hover:bg-[var(--surface-3)] hover:text-[var(--text-primary)] focus-visible:opacity-100 focus-visible:outline-none group-hover/msg:opacity-100 data-[state=open]:opacity-100'
56+ onClick = { ( event ) => event . stopPropagation ( ) }
57+ >
58+ < Ellipsis className = 'h-3 w-3' strokeWidth = { 2 } />
59+ </ button >
60+ </ DropdownMenuTrigger >
61+ </ Tooltip . Trigger >
62+ < Tooltip . Content side = 'top' > More options</ Tooltip . Content >
63+ </ Tooltip . Root >
64+ < DropdownMenuContent align = 'end' side = 'top' sideOffset = { 4 } >
65+ < DropdownMenuItem
66+ disabled = { ! content }
67+ onSelect = { ( event ) => {
68+ event . stopPropagation ( )
69+ void copyToClipboard ( content , 'message' )
70+ } }
71+ >
72+ { copied === 'message' ? < Check /> : < Copy /> }
73+ < span > Copy Message</ span >
74+ </ DropdownMenuItem >
75+ < DropdownMenuItem
76+ disabled = { ! requestId }
77+ onSelect = { ( event ) => {
78+ event . stopPropagation ( )
79+ if ( requestId ) {
80+ void copyToClipboard ( requestId , 'request' )
81+ }
82+ } }
4083 >
41- < Ellipsis className = 'h-[14px] w-[14px]' strokeWidth = { 2 } />
42- </ button >
43- </ PopoverTrigger >
44- < PopoverContent
45- side = 'bottom'
46- align = 'end'
47- sideOffset = { 4 }
48- maxHeight = { 120 }
49- style = { { width : '160px' , minWidth : '160px' } }
50- >
51- < PopoverScrollArea >
52- < PopoverItem onClick = { ( ) => copyToClipboard ( content , 'message' ) } disabled = { ! content } >
53- { copied === 'message' ? (
54- < Check className = 'h-[13px] w-[13px]' />
55- ) : (
56- < Copy className = 'h-[13px] w-[13px]' />
57- ) }
58- < span > Copy Message</ span >
59- </ PopoverItem >
60- < PopoverItem
61- onClick = { ( ) => requestId && copyToClipboard ( requestId , 'request' ) }
62- disabled = { ! requestId }
63- >
64- { copied === 'request' ? (
65- < Check className = 'h-[13px] w-[13px]' />
66- ) : (
67- < Hash className = 'h-[13px] w-[13px]' />
68- ) }
69- < span > Copy Request ID</ span >
70- </ PopoverItem >
71- </ PopoverScrollArea >
72- </ PopoverContent >
73- </ Popover >
84+ { copied === 'request' ? < Check /> : < Hash /> }
85+ < span > Copy Request ID</ span >
86+ </ DropdownMenuItem >
87+ </ DropdownMenuContent >
88+ </ DropdownMenu >
7489 )
7590}
0 commit comments