返回 AiToEarn
SpaceGroupItem.tsx
1 import type { SocialAccount } from '@/api/accounts/account.types'
2 import type { AccountGroup } from '@/store/account'
3 import { DownOutlined, RightOutlined } from '@ant-design/icons'
4 import { Check } from 'lucide-react'
5 import { memo } from 'react'
6 import { useTransClient } from '@/app/i18n/client'
7 import { cn } from '@/utils/className'
8 import AccountItem from './AccountItem'
9
10 interface SpaceGroupItemProps {
11 group: AccountGroup
12 accounts: SocialAccount[]
13 isCollapsed: boolean
14 isDefaultGroup: boolean
15 canMoveUp: boolean
16 canMoveDown: boolean
17 activeAccountId?: string
18 /** 当前选中的空间 ID */
19 activeSpaceId?: string
20 sortLoading?: string | null
21 deleteLoading?: string | null
22 onToggleCollapse: (groupId: string) => void
23 onSelectAccount: (account: SocialAccount) => void
24 onGroupSort: (groupId: string, direction: 'up' | 'down') => void
25 /** 选择空间的回调 */
26 onSpaceSelect?: (spaceId: string | undefined) => void
27 }
28
29 const SpaceGroupItem = memo(
30 ({
31 group,
32 accounts,
33 isCollapsed,
34 isDefaultGroup,
35 canMoveUp,
36 canMoveDown,
37 activeAccountId,
38 activeSpaceId,
39 sortLoading,
40 deleteLoading,
41 onToggleCollapse,
42 onSelectAccount,
43 onGroupSort,
44 onSpaceSelect,
45 }: SpaceGroupItemProps) => {
46 const { t } = useTransClient('account')
47 const isSorting = sortLoading === group.id
48 const isSpaceActive = activeSpaceId === group.id
49
50 // 点击空间名称区域 - 选择/取消选择空间
51 const handleSpaceClick = (e: React.MouseEvent) => {
52 e.stopPropagation()
53 if (onSpaceSelect) {
54 // 如果已选中,取消选择;否则选择该空间
55 onSpaceSelect(isSpaceActive ? undefined : group.id)
56 }
57 }
58
59 // 点击箭头 - 展开/折叠
60 const handleToggleClick = (e: React.MouseEvent) => {
61 e.stopPropagation()
62 onToggleCollapse(group.id)
63 }
64
65 // 右键点击 - 展开/折叠
66 const handleContextMenu = (e: React.MouseEvent) => {
67 e.preventDefault()
68 e.stopPropagation()
69 onToggleCollapse(group.id)
70 }
71
72 return (
73 <div className="mb-1">
74 {/* 空间标题行 */}
75 <div
76 data-testid="accounts-selector-space-group"
77 className={cn(
78 'flex items-center gap-2 px-3 py-2 transition-colors cursor-pointer',
79 isSpaceActive ? 'bg-primary/10 hover:bg-primary/15' : 'hover:bg-muted/50',
80 )}
81 onClick={handleSpaceClick}
82 onContextMenu={handleContextMenu}
83 >
84 {/* 箭头区域 - 点击展开/折叠 */}
85 <div className="p-0.5 rounded hover:bg-muted" onClick={handleToggleClick}>
86 {isCollapsed ? (
87 <RightOutlined className="text-xs text-muted-foreground" />
88 ) : (
89 <DownOutlined className="text-xs text-muted-foreground" />
90 )}
91 </div>
92
93 {/* 空间名称 */}
94 <span
95 className={cn(
96 'text-xs font-semibold flex-1',
97 isSpaceActive ? 'text-primary' : 'text-muted-foreground',
98 )}
99 >
100 {group.name || t('defaultSpace')}
101 </span>
102
103 {/* 选中图标 */}
104 {isSpaceActive && <Check className="w-4 h-4 text-primary" />}
105
106 {/* 账号数量 */}
107 <span className="text-xs text-muted-foreground">{accounts.length}</span>
108 </div>
109
110 {/* 频道列表 */}
111 {!isCollapsed
112 && accounts.map((account) => {
113 const isActive = activeAccountId === account.id
114 return (
115 <AccountItem
116 key={account.id}
117 account={account}
118 isActive={isActive}
119 onSelect={onSelectAccount}
120 indent
121 />
122 )
123 })}
124 </div>
125 )
126 },
127 )
128
129 SpaceGroupItem.displayName = 'SpaceGroupItem'
130
131 export default SpaceGroupItem
132
132 lines Plain Text