返回 AiToEarn
ContextMenu.tsx
1 import type { AccountGroupItem, SocialAccount } from '@/api/accounts/account.types'
2
3 import { ChevronDown, ChevronUp, Trash2 } from 'lucide-react'
4 import { memo, useEffect } from 'react'
5 import { useTransClient } from '@/app/i18n/client'
6
7 interface ContextMenuProps {
8 open: boolean
9 x: number
10 y: number
11 target: 'account' | 'group'
12 data: SocialAccount | AccountGroupItem | null
13 sortedGroups: AccountGroupItem[]
14 onClose: () => void
15 onAccountDelete: (account: SocialAccount) => void
16 onGroupSort: (groupId: string, direction: 'up' | 'down') => void
17 }
18
19 const ContextMenu = memo(
20 ({
21 open,
22 x,
23 y,
24 target,
25 data,
26 sortedGroups,
27 onClose,
28 onAccountDelete,
29 onGroupSort,
30 }: ContextMenuProps) => {
31 const { t } = useTransClient('account')
32
33 useEffect(() => {
34 if (!open)
35 return
36
37 const handleClickOutside = () => {
38 onClose()
39 }
40
41 document.addEventListener('click', handleClickOutside)
42 return () => {
43 document.removeEventListener('click', handleClickOutside)
44 }
45 }, [open, onClose])
46
47 if (!open || !data)
48 return null
49
50 return (
51 <div
52 className="fixed z-[9999] min-w-[160px] rounded-md border bg-popover p-1 shadow-md"
53 style={{
54 left: x,
55 top: y,
56 }}
57 onClick={e => e.stopPropagation()}
58 >
59 {target === 'account' && (
60 <button
61 className="w-full flex items-center gap-2 px-2 py-1.5 text-sm hover:bg-muted rounded-sm text-destructive cursor-pointer"
62 onClick={() => {
63 onAccountDelete(data as SocialAccount)
64 onClose()
65 }}
66 >
67 <Trash2 className="h-4 w-4" />
68 {t('deleteAccount')}
69 </button>
70 )}
71 {target === 'group'
72 && (() => {
73 const group = data as AccountGroupItem
74 const isDefaultGroup = group.isDefault
75 const currentIndex = sortedGroups.findIndex(g => g.id === group.id)
76 const canMoveUp = !isDefaultGroup && currentIndex > 0
77 const canMoveDown = !isDefaultGroup && currentIndex < sortedGroups.length - 1
78
79 return (
80 <>
81 <button
82 className="w-full flex items-center gap-2 px-2 py-1.5 text-sm hover:bg-muted rounded-sm disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"
83 onClick={() => {
84 onGroupSort(group.id, 'up')
85 onClose()
86 }}
87 disabled={!canMoveUp}
88 >
89 <ChevronUp className="h-4 w-4" />
90 {t('sidebar.moveUp')}
91 </button>
92 <button
93 className="w-full flex items-center gap-2 px-2 py-1.5 text-sm hover:bg-muted rounded-sm disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"
94 onClick={() => {
95 onGroupSort(group.id, 'down')
96 onClose()
97 }}
98 disabled={!canMoveDown}
99 >
100 <ChevronDown className="h-4 w-4" />
101 {t('sidebar.moveDown')}
102 </button>
103 </>
104 )
105 })()}
106 </div>
107 )
108 },
109 )
110
111 ContextMenu.displayName = 'ContextMenu'
112
113 export default ContextMenu
114
114 lines Plain Text