Spaces:
Sleeping
Sleeping
| import { useState } from 'react'; | |
| export const useChunkNavigation = (documentData, clearTypingAnimation) => { | |
| const [chunkStates, setChunkStates] = useState({}); | |
| const [currentChunkIndex, setCurrentChunkIndex] = useState(0); | |
| const [chunkExpanded, setChunkExpanded] = useState(true); | |
| const [globalChatHistory, setGlobalChatHistory] = useState([]); | |
| const [showChat, setShowChat] = useState(true); | |
| const [isTransitioning, setIsTransitioning] = useState(false); | |
| const [completedChunks, setCompletedChunks] = useState(new Set()); | |
| const goToNextChunk = () => { | |
| if (documentData && currentChunkIndex < documentData.chunks.length - 1) { | |
| if (clearTypingAnimation) { | |
| clearTypingAnimation(); | |
| } | |
| setCurrentChunkIndex(currentChunkIndex + 1); | |
| setChunkExpanded(true); | |
| } | |
| }; | |
| const goToPrevChunk = () => { | |
| if (currentChunkIndex > 0) { | |
| if (clearTypingAnimation) { | |
| clearTypingAnimation(); | |
| } | |
| setCurrentChunkIndex(currentChunkIndex - 1); | |
| setChunkExpanded(true); | |
| } | |
| }; | |
| const sendAutomatedMessage = async (action) => { | |
| if (!documentData || currentChunkIndex >= documentData.chunks.length - 1) return; | |
| setIsTransitioning(true); | |
| const nextChunkIndex = currentChunkIndex + 1; | |
| const nextChunk = documentData.chunks[nextChunkIndex]; | |
| // Mark current chunk as completed | |
| setCompletedChunks(prev => new Set(prev).add(currentChunkIndex)); | |
| // Update chunk index immediately for UI feedback | |
| setCurrentChunkIndex(nextChunkIndex); | |
| setChunkExpanded(true); | |
| // Check if we already have messages for this chunk | |
| if (hasChunkMessages(nextChunkIndex)) { | |
| // Don't generate new response, just navigate | |
| setIsTransitioning(false); | |
| return; | |
| } | |
| try { | |
| const response = await fetch('/api/chat', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ | |
| messages: globalChatHistory, | |
| currentChunk: documentData.chunks[currentChunkIndex]?.text || '', | |
| nextChunk: nextChunk.text, | |
| action: action, | |
| document: documentData ? JSON.stringify(documentData) : '' | |
| }) | |
| }); | |
| const data = await response.json(); | |
| addMessageToChunk( | |
| { role: 'assistant', content: data.content || 'Let\'s continue to the next section.' }, | |
| nextChunkIndex | |
| ); | |
| // Clear any animations after successful response | |
| if (clearTypingAnimation) { | |
| clearTypingAnimation(); | |
| } | |
| } catch (error) { | |
| console.error('Error in automated transition:', error); | |
| // Clear animations on error too | |
| if (clearTypingAnimation) { | |
| clearTypingAnimation(); | |
| } | |
| } finally { | |
| setIsTransitioning(false); | |
| } | |
| }; | |
| const skipChunk = () => { | |
| return sendAutomatedMessage('skip'); | |
| }; | |
| const markChunkUnderstood = () => { | |
| return sendAutomatedMessage('understood'); | |
| }; | |
| const startInteractiveLesson = (startChunkLessonFn) => { | |
| setChunkStates(prev => ({ | |
| ...prev, | |
| [currentChunkIndex]: 'interactive' | |
| })); | |
| startChunkLessonFn(currentChunkIndex); | |
| }; | |
| const setChunkAsInteractive = () => { | |
| // No longer tracking status - this is just for compatibility | |
| }; | |
| const updateGlobalChatHistory = (messages) => { | |
| setGlobalChatHistory(messages); | |
| }; | |
| const getGlobalChatHistory = () => { | |
| return globalChatHistory; | |
| }; | |
| const addMessageToChunk = (message, chunkIndex) => { | |
| const messageWithChunk = { ...message, chunkIndex }; | |
| setGlobalChatHistory(prev => [...prev, messageWithChunk]); | |
| }; | |
| const getCurrentChunkMessages = () => { | |
| return globalChatHistory.filter(msg => msg.chunkIndex === currentChunkIndex); | |
| }; | |
| const hasChunkMessages = (chunkIndex) => { | |
| return globalChatHistory.some(msg => msg.chunkIndex === chunkIndex); | |
| }; | |
| const isChunkCompleted = (chunkIndex) => { | |
| return completedChunks.has(chunkIndex); | |
| }; | |
| const canEditChunk = (chunkIndex) => { | |
| return chunkIndex === currentChunkIndex && !isChunkCompleted(chunkIndex); | |
| }; | |
| return { | |
| chunkStates, | |
| currentChunkIndex, | |
| chunkExpanded, | |
| showChat, | |
| isTransitioning, | |
| goToNextChunk, | |
| goToPrevChunk, | |
| skipChunk, | |
| markChunkUnderstood, | |
| startInteractiveLesson, | |
| setChunkExpanded, | |
| setShowChat, | |
| setChunkAsInteractive, | |
| updateGlobalChatHistory, | |
| getGlobalChatHistory, | |
| addMessageToChunk, | |
| getCurrentChunkMessages, | |
| hasChunkMessages, | |
| isChunkCompleted, | |
| canEditChunk | |
| }; | |
| }; |