import { useState, useEffect, useCallback, useRef } from "react"; import { useTranslation } from "react-i18next"; import { updateCommonConfigSnippet, hasCommonConfigSnippet, validateJsonConfig, } from "@/utils/providerConfigUtils"; import { configApi } from "@/lib/api"; const LEGACY_STORAGE_KEY = "cc-switch:common-config-snippet"; const DEFAULT_COMMON_CONFIG_SNIPPET = `{ "includeCoAuthoredBy": false }`; interface UseCommonConfigSnippetProps { settingsConfig: string; onConfigChange: (config: string) => void; initialData?: { settingsConfig?: Record; }; selectedPresetId?: string; /** When false, the hook skips all logic and returns disabled state. Default: true */ enabled?: boolean; } /** * 管理 Claude 通用配置片段 * 从 config.json 读取和保存,支持从 localStorage 平滑迁移 */ export function useCommonConfigSnippet({ settingsConfig, onConfigChange, initialData, selectedPresetId, enabled = true, }: UseCommonConfigSnippetProps) { const { t } = useTranslation(); const [useCommonConfig, setUseCommonConfig] = useState(false); const [commonConfigSnippet, setCommonConfigSnippetState] = useState( DEFAULT_COMMON_CONFIG_SNIPPET, ); const [commonConfigError, setCommonConfigError] = useState(""); const [isLoading, setIsLoading] = useState(true); const [isExtracting, setIsExtracting] = useState(false); // 用于跟踪是否正在通过通用配置更新 const isUpdatingFromCommonConfig = useRef(false); // 用于跟踪新建模式是否已初始化默认勾选 const hasInitializedNewMode = useRef(false); // 当预设变化时,重置初始化标记,使新预设能够重新触发初始化逻辑 useEffect(() => { if (!enabled) return; hasInitializedNewMode.current = false; }, [selectedPresetId, enabled]); // 初始化:从 config.json 加载,支持从 localStorage 迁移 useEffect(() => { if (!enabled) { setIsLoading(false); return; } let mounted = true; const loadSnippet = async () => { try { // 使用统一 API 加载 const snippet = await configApi.getCommonConfigSnippet("claude"); if (snippet && snippet.trim()) { if (mounted) { setCommonConfigSnippetState(snippet); } } else { // 如果 config.json 中没有,尝试从 localStorage 迁移 if (typeof window !== "undefined") { try { const legacySnippet = window.localStorage.getItem(LEGACY_STORAGE_KEY); if (legacySnippet && legacySnippet.trim()) { // 迁移到 config.json await configApi.setCommonConfigSnippet("claude", legacySnippet); if (mounted) { setCommonConfigSnippetState(legacySnippet); } // 清理 localStorage window.localStorage.removeItem(LEGACY_STORAGE_KEY); console.log( "[迁移] Claude 通用配置已从 localStorage 迁移到 config.json", ); } } catch (e) { console.warn("[迁移] 从 localStorage 迁移失败:", e); } } } } catch (error) { console.error("加载通用配置失败:", error); } finally { if (mounted) { setIsLoading(false); } } }; loadSnippet(); return () => { mounted = false; }; }, [enabled]); // 初始化时检查通用配置片段(编辑模式) useEffect(() => { if (!enabled) return; if (initialData && !isLoading) { const configString = JSON.stringify(initialData.settingsConfig, null, 2); const hasCommon = hasCommonConfigSnippet( configString, commonConfigSnippet, ); setUseCommonConfig(hasCommon); } }, [enabled, initialData, commonConfigSnippet, isLoading]); // 新建模式:如果通用配置片段存在且有效,默认启用 useEffect(() => { if (!enabled) return; // 仅新建模式、加载完成、尚未初始化过 if (!initialData && !isLoading && !hasInitializedNewMode.current) { hasInitializedNewMode.current = true; // 检查片段是否有实质内容 try { const snippetObj = JSON.parse(commonConfigSnippet); const hasContent = Object.keys(snippetObj).length > 0; if (hasContent) { setUseCommonConfig(true); // 合并通用配置到当前配置 const { updatedConfig, error } = updateCommonConfigSnippet( settingsConfig, commonConfigSnippet, true, ); if (!error) { isUpdatingFromCommonConfig.current = true; onConfigChange(updatedConfig); setTimeout(() => { isUpdatingFromCommonConfig.current = false; }, 0); } } } catch { // ignore parse error } } }, [ enabled, initialData, commonConfigSnippet, isLoading, settingsConfig, onConfigChange, ]); // 处理通用配置开关 const handleCommonConfigToggle = useCallback( (checked: boolean) => { const { updatedConfig, error: snippetError } = updateCommonConfigSnippet( settingsConfig, commonConfigSnippet, checked, ); if (snippetError) { setCommonConfigError(snippetError); setUseCommonConfig(false); return; } setCommonConfigError(""); setUseCommonConfig(checked); // 标记正在通过通用配置更新 isUpdatingFromCommonConfig.current = true; onConfigChange(updatedConfig); // 在下一个事件循环中重置标记 setTimeout(() => { isUpdatingFromCommonConfig.current = false; }, 0); }, [settingsConfig, commonConfigSnippet, onConfigChange], ); // 处理通用配置片段变化 const handleCommonConfigSnippetChange = useCallback( (value: string) => { const previousSnippet = commonConfigSnippet; setCommonConfigSnippetState(value); if (!value.trim()) { setCommonConfigError(""); // 保存到 config.json(清空) configApi.setCommonConfigSnippet("claude", "").catch((error) => { console.error("保存通用配置失败:", error); setCommonConfigError( t("claudeConfig.saveFailed", { error: String(error) }), ); }); if (useCommonConfig) { const { updatedConfig } = updateCommonConfigSnippet( settingsConfig, previousSnippet, false, ); onConfigChange(updatedConfig); setUseCommonConfig(false); } return; } // 验证JSON格式 const validationError = validateJsonConfig(value, "通用配置片段"); if (validationError) { setCommonConfigError(validationError); } else { setCommonConfigError(""); // 保存到 config.json configApi.setCommonConfigSnippet("claude", value).catch((error) => { console.error("保存通用配置失败:", error); setCommonConfigError( t("claudeConfig.saveFailed", { error: String(error) }), ); }); } // 若当前启用通用配置且格式正确,需要替换为最新片段 if (useCommonConfig && !validationError) { const removeResult = updateCommonConfigSnippet( settingsConfig, previousSnippet, false, ); if (removeResult.error) { setCommonConfigError(removeResult.error); return; } const addResult = updateCommonConfigSnippet( removeResult.updatedConfig, value, true, ); if (addResult.error) { setCommonConfigError(addResult.error); return; } // 标记正在通过通用配置更新,避免触发状态检查 isUpdatingFromCommonConfig.current = true; onConfigChange(addResult.updatedConfig); // 在下一个事件循环中重置标记 setTimeout(() => { isUpdatingFromCommonConfig.current = false; }, 0); } }, [commonConfigSnippet, settingsConfig, useCommonConfig, onConfigChange], ); // 当配置变化时检查是否包含通用配置(但避免在通过通用配置更新时检查) useEffect(() => { if (!enabled) return; if (isUpdatingFromCommonConfig.current || isLoading) { return; } const hasCommon = hasCommonConfigSnippet( settingsConfig, commonConfigSnippet, ); setUseCommonConfig(hasCommon); }, [enabled, settingsConfig, commonConfigSnippet, isLoading]); // 从编辑器当前内容提取通用配置片段 const handleExtract = useCallback(async () => { setIsExtracting(true); setCommonConfigError(""); try { const extracted = await configApi.extractCommonConfigSnippet("claude", { settingsConfig, }); if (!extracted || extracted === "{}") { setCommonConfigError(t("claudeConfig.extractNoCommonConfig")); return; } // 验证 JSON 格式 const validationError = validateJsonConfig(extracted, "提取的配置"); if (validationError) { setCommonConfigError(validationError); return; } // 更新片段状态 setCommonConfigSnippetState(extracted); // 保存到后端 await configApi.setCommonConfigSnippet("claude", extracted); } catch (error) { console.error("提取通用配置失败:", error); setCommonConfigError( t("claudeConfig.extractFailed", { error: String(error) }), ); } finally { setIsExtracting(false); } }, [settingsConfig, t]); return { useCommonConfig, commonConfigSnippet, commonConfigError, isLoading, isExtracting, handleCommonConfigToggle, handleCommonConfigSnippetChange, handleExtract, }; }