返回 AiToEarn
useNewWork.ts
根目录 / project / aitoearn-web / src / app / [lng] / accounts / hooks / useNewWork.ts
1 /**
2 * useNewWork Hook
3 *
4 * 功能描述: 统一处理"新建作品"逻辑,包括默认账号选择、发布弹窗打开
5 */
6
7 import type { RefObject } from 'react'
8 import type { SocialAccount } from '@/api/accounts/account.types'
9 import type { IPublishDialogRef } from '@/components/PublishDialog'
10 import { useCallback, useMemo } from 'react'
11 import { useShallow } from 'zustand/react/shallow'
12 import { AccountStatus } from '@/app/config/accountConfig'
13 import { useAccountStore } from '@/store/account'
14
15 export interface UseNewWorkOptions {
16 /** 发布弹窗 ref */
17 publishDialogRef?: RefObject<IPublishDialogRef | null>
18 /** 设置发布弹窗打开状态 */
19 setPublishDialogOpen: (open: boolean) => void
20 /** 设置默认选中的账号 ID 列表 */
21 setDefaultAccountIds?: (ids: string[] | undefined) => void
22 }
23
24 export interface OpenNewWorkOptions {
25 /** 指定发布日期(ISO 格式字符串) */
26 date?: string
27 }
28
29 /**
30 * 统一处理新建作品逻辑的 Hook
31 *
32 * @param options Hook 配置选项
33 * @returns 包含 openNewWork 方法的对象
34 *
35 * @example
36 * ```tsx
37 * const { openNewWork, hasUsableAccounts } = useNewWork({
38 * publishDialogRef,
39 * setPublishDialogOpen,
40 * setDefaultAccountIds,
41 * })
42 *
43 * // 基础用法:打开新建作品弹窗
44 * <Button onClick={() => openNewWork()}>新建作品</Button>
45 *
46 * // 带日期参数:从日历点击某天创建作品
47 * <Button onClick={() => openNewWork({ date: selectedDate })}>创建</Button>
48 * ```
49 */
50 export function useNewWork(options: UseNewWorkOptions) {
51 const { publishDialogRef, setPublishDialogOpen, setDefaultAccountIds } = options
52
53 // 账户相关状态
54 const { accountActive, accountGroupList, activeSpaceId, accountList } = useAccountStore(
55 useShallow(state => ({
56 accountActive: state.accountActive,
57 accountGroupList: state.accountGroupList,
58 activeSpaceId: state.activeSpaceId,
59 accountList: state.accountList,
60 })),
61 )
62
63 // 获取所有账号列表(扁平化)
64 const allAccounts = useMemo(() => {
65 const groupedAccounts = accountGroupList.reduce<SocialAccount[]>((acc, group) => {
66 return [...acc, ...group.children]
67 }, [])
68
69 return groupedAccounts.length > 0 ? groupedAccounts : accountList
70 }, [accountGroupList, accountList])
71
72 // 是否有可用账户
73 const hasUsableAccounts = useMemo(() => {
74 return allAccounts.some(account => account.status === AccountStatus.USABLE)
75 }, [allAccounts])
76
77 // 根据选中空间计算默认选中的账号ID列表(过滤离线账号)
78 const spaceDefaultAccountIds = useMemo(() => {
79 if (!activeSpaceId)
80 return undefined
81
82 const space = accountGroupList.find(g => g.id === activeSpaceId)
83 if (!space)
84 return undefined
85
86 // 过滤在线账号
87 const onlineAccountIds = space.children
88 .filter(account => account.status === AccountStatus.USABLE)
89 .map(account => account.id)
90
91 return onlineAccountIds.length > 0 ? onlineAccountIds : undefined
92 }, [activeSpaceId, accountGroupList])
93
94 /**
95 * 计算默认选中的账号 ID 列表
96 * 优先级:
97 * 1. 当前选中的单个账号(如果在线)
98 * 2. 当前选中空间下的在线账号
99 * 3. 所有在线账号
100 */
101 const getDefaultAccountIds = useCallback((): string[] | undefined => {
102 // 1. 如果选中了单个账号,优先使用该账号
103 if (accountActive && accountActive.status === AccountStatus.USABLE) {
104 return [accountActive.id]
105 }
106
107 // 2. 如果选中了空间,使用该空间下的在线账号
108 if (spaceDefaultAccountIds) {
109 return spaceDefaultAccountIds
110 }
111
112 // 3. "全部频道" - 默认选择所有在线账号
113 const allOnlineAccountIds = allAccounts
114 .filter(account => account.status === AccountStatus.USABLE)
115 .map(account => account.id)
116
117 return allOnlineAccountIds.length > 0 ? allOnlineAccountIds : undefined
118 }, [accountActive, spaceDefaultAccountIds, allAccounts])
119
120 /**
121 * 打开新建作品弹窗
122 * 会自动设置默认账号,并打开弹窗
123 */
124 const openNewWork = useCallback(
125 (workOptions?: OpenNewWorkOptions) => {
126 const { date } = workOptions || {}
127
128 // 设置默认选中的账号
129 if (setDefaultAccountIds) {
130 const defaultIds = getDefaultAccountIds()
131 setDefaultAccountIds(defaultIds)
132 }
133
134 // 如果指定了日期,设置发布时间
135 if (date && publishDialogRef?.current) {
136 publishDialogRef.current.setPubTime(date)
137 }
138
139 // 打开发布弹窗
140 setPublishDialogOpen(true)
141 },
142 [
143 setDefaultAccountIds,
144 getDefaultAccountIds,
145 publishDialogRef,
146 setPublishDialogOpen,
147 ],
148 )
149
150 return {
151 /** 打开新建作品弹窗 */
152 openNewWork,
153 /** 是否有可用账户 */
154 hasUsableAccounts,
155 /** 所有账号列表 */
156 allAccounts,
157 /** 获取默认选中的账号 ID 列表 */
158 getDefaultAccountIds,
159 }
160 }
161
161 lines TYPESCRIPT