/** * useChatState Hook * Centralized state management for all 47+ useState hooks from AIChatPanel */ import { useState, useEffect } from 'react'; import { ChatState, ChatActions, PanelTab, ChatPartner, TasksSourceConfig, FilesSourceConfig, PanelMode, AgentMode, SettingsTab, UserTypeFilter, SortOption, VoiceInputMode, AgentChat, MessageReaction } from '../types'; import { MentionUser } from '../../../components/MentionInput'; import { BoundRow } from '../../../components/RowBindingV2'; import { Participant } from '../../../components/ParticipantSelector'; const DEFAULT_QUICK_EMOJIS = ['👍', '❤️', '😂', '🔥', '💯', '🙏', '😍', '😮']; export function useChatState() { // UI State const [activePanel, setActivePanel] = useState('none'); const [chatMode, setChatMode] = useState<'ai' | 'people'>('ai'); const [chatPartner, setChatPartner] = useState(null); const [inputValue, setInputValue] = useState(''); const [attachments, setAttachments] = useState([]); const [previewFile, setPreviewFile] = useState<{ url: string; name: string } | null>(null); const [dragOver, setDragOver] = useState(false); const [mentionedUsers, setMentionedUsers] = useState([]); const [boundRows, setBoundRows] = useState([]); const [messageBoundRows, setMessageBoundRows] = useState([]); const [chatParticipants, setChatParticipants] = useState([]); const [tasksSource, setTasksSource] = useState(); const [filesSource, setFilesSource] = useState(); const [showFilePicker, setShowFilePicker] = useState(false); const [attachTab, setAttachTab] = useState<'files' | 'rows'>('files'); // Panel sizing and layout const [panelHeight, setPanelHeight] = useState('auto'); const [panelMode, setPanelMode] = useState('default'); const [isResizing, setIsResizing] = useState(false); const [panelWidth, setPanelWidth] = useState(420); const [isResizingWidth, setIsResizingWidth] = useState(false); const [sidebarWidth, setSidebarWidth] = useState(256); const [isResizingSidebar, setIsResizingSidebar] = useState(false); const [isMobile, setIsMobile] = useState(() => typeof window !== 'undefined' && window.innerWidth < 768); const [mobileKeyboardHeight, setMobileKeyboardHeight] = useState(0); // Processing elapsed time (for stuck state detection) const [processingElapsed, setProcessingElapsed] = useState(0); // Settings and modes const [markdownEnabled, setMarkdownEnabled] = useState(true); const [agentMode, setAgentMode] = useState('agent'); const [thinkingEnabled, setThinkingEnabled] = useState(false); const [settingsTab, setSettingsTab] = useState('ai'); const [localError, setLocalError] = useState(null); const [showTerminal, setShowTerminal] = useState(false); const [terminalFocusSessionId, setTerminalFocusSessionId] = useState(); // Search states const [contactsSearch, setContactsSearch] = useState(''); const [agentsSearch, setAgentsSearch] = useState(''); const [historySearch, setHistorySearch] = useState(''); const [filesSearch, setFilesSearch] = useState(''); const [tasksSearch, setTasksSearch] = useState(''); const [userTypeFilter, setUserTypeFilter] = useState('all'); const [showFavorites, setShowFavorites] = useState(false); const [favorites, setFavorites] = useState([]); const [showRowBinding, setShowRowBinding] = useState(false); const [showBoundRowsBar, setShowBoundRowsBar] = useState(false); const [showMessageRowPicker, setShowMessageRowPicker] = useState(false); const [showTasksSelector, setShowTasksSelector] = useState(false); const [expandedTaskChats, setExpandedTaskChats] = useState(null); const [showAllContacts, setShowAllContacts] = useState(false); const [taskProjectId, setTaskProjectId] = useState(null); // Chat-specific settings const [chatOperatorId, setChatOperatorId] = useState(null); const [chatModelId, setChatModelId] = useState(''); const [chatSystemPrompt, setChatSystemPrompt] = useState(''); const [isSavingAgentSettings, setIsSavingAgentSettings] = useState(false); // Sorting and sub-agents const [sortOption, setSortOption] = useState('date'); const [subAgents, setSubAgents] = useState([]); // Agent management const [editingAgentId, setEditingAgentId] = useState(null); const [defaultAgentId, setDefaultAgentId] = useState(null); const [isSavingDefaultAgent, setIsSavingDefaultAgent] = useState(false); const [favoriteAgents, setFavoriteAgents] = useState([]); const [showFavoriteAgents, setShowFavoriteAgents] = useState(false); const [expandedAgentId, setExpandedAgentId] = useState(null); // Vector search const [isVectorSearching, setIsVectorSearching] = useState(false); const [vectorSearchResults, setVectorSearchResults] = useState(null); // Agent chats cache const [agentChats, setAgentChats] = useState>({}); // Quick reactions const [quickEmojis, setQuickEmojis] = useState(DEFAULT_QUICK_EMOJIS); const [isSavingEmojis, setIsSavingEmojis] = useState(false); // Message reactions cache const [messageReactions, setMessageReactions] = useState>>({}); // Voice input const [voiceMode, setVoiceMode] = useState('webSpeech'); // Scroll-to-bottom arrow visibility (Ticket #37259) const [showScrollToBottom, setShowScrollToBottom] = useState(false); // New message counter — tracks only human-visible messages (not tool_call/tool_result/thinking) const [newMessageCount, setNewMessageCount] = useState(0); // Agent working indicator — shown when agent is processing (tool calls arriving, no final text yet) const [agentWorking, setAgentWorking] = useState(false); // User/group chat conversation id (ADR-024) const [userConversationId, setUserConversationId] = useState(null); // Mobile detection effect useEffect(() => { const handleResize = () => { setIsMobile(window.innerWidth < 768); }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); // Combine all state into a single object const state: ChatState = { activePanel, chatMode, chatPartner, inputValue, attachments, previewFile, dragOver, mentionedUsers, boundRows, messageBoundRows, chatParticipants, tasksSource, filesSource, showFilePicker, attachTab, panelHeight, panelMode, isResizing, panelWidth, isResizingWidth, sidebarWidth, isResizingSidebar, isMobile, mobileKeyboardHeight, processingElapsed, markdownEnabled, agentMode, thinkingEnabled, settingsTab, localError, showTerminal, terminalFocusSessionId, contactsSearch, agentsSearch, historySearch, filesSearch, tasksSearch, userTypeFilter, showFavorites, favorites, showRowBinding, showBoundRowsBar, showMessageRowPicker, showTasksSelector, expandedTaskChats, showAllContacts, taskProjectId, chatOperatorId, chatModelId, chatSystemPrompt, isSavingAgentSettings, sortOption, subAgents, editingAgentId, defaultAgentId, isSavingDefaultAgent, favoriteAgents, showFavoriteAgents, expandedAgentId, isVectorSearching, vectorSearchResults, agentChats, quickEmojis, isSavingEmojis, messageReactions, voiceMode, showScrollToBottom, newMessageCount, agentWorking, userConversationId }; // Combine all actions into a single object const actions: ChatActions = { setActivePanel, setChatMode, setChatPartner, setInputValue, setAttachments, setPreviewFile, setDragOver, setMentionedUsers, setBoundRows, setMessageBoundRows, setChatParticipants, setTasksSource, setFilesSource, setShowFilePicker, setAttachTab, setPanelHeight, setPanelMode, setIsResizing, setPanelWidth, setIsResizingWidth, setSidebarWidth, setIsResizingSidebar, setMobileKeyboardHeight, setProcessingElapsed, setMarkdownEnabled, setAgentMode, setThinkingEnabled, setSettingsTab, setLocalError, setShowTerminal, setTerminalFocusSessionId, setContactsSearch, setAgentsSearch, setHistorySearch, setFilesSearch, setTasksSearch, setUserTypeFilter, setShowFavorites, setFavorites, setShowRowBinding, setShowBoundRowsBar, setShowMessageRowPicker, setShowTasksSelector, setExpandedTaskChats, setShowAllContacts, setTaskProjectId, setChatOperatorId, setChatModelId, setChatSystemPrompt, setIsSavingAgentSettings, setSortOption, setSubAgents, setEditingAgentId, setDefaultAgentId, setIsSavingDefaultAgent, setFavoriteAgents, setShowFavoriteAgents, setExpandedAgentId, setIsVectorSearching, setVectorSearchResults, setAgentChats, setQuickEmojis, setIsSavingEmojis, setMessageReactions, setVoiceMode, setShowScrollToBottom, setNewMessageCount, setAgentWorking, setUserConversationId }; return { state, actions }; }