Files
wp-agentic-writer/FINAL_FRONTEND_CODE.md
2026-01-28 00:26:00 +07:00

10 KiB

Final Frontend Implementation Code

This document contains all the JavaScript and CSS code to be added to complete the implementation.


JavaScript Functions to Add to sidebar.js

1. Writing Mode Empty State Check

// Add after state declarations (around line 100)
const shouldShowWritingEmptyState = () => {
    return agentMode === 'writing' && !currentPlanRef.current;
};

2. Summarize Chat History Function

// Add with other utility functions
const summarizeChatHistory = async () => {
    const chatMessages = messages.filter(m => m.role !== 'system');
    
    if (chatMessages.length < 4) {
        return { summary: '', useFullHistory: true, cost: 0 };
    }
    
    try {
        const response = await fetch(wpAgenticWriter.apiUrl + '/summarize-context', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': wpAgenticWriter.nonce,
            },
            body: JSON.stringify({
                chatHistory: chatMessages,
                postId: postId,
            }),
        });
        
        if (!response.ok) {
            throw new Error('Summarization failed');
        }
        
        const data = await response.json();
        
        if (data.tokens_saved > 0) {
            console.log(`💡 Context optimized: ~${data.tokens_saved} tokens saved (~$${(data.tokens_saved * 0.0000002).toFixed(4)})`);
        }
        
        return {
            summary: data.summary || '',
            useFullHistory: data.use_full_history || false,
            cost: data.cost || 0,
            tokensSaved: data.tokens_saved || 0,
        };
    } catch (error) {
        console.error('Summarization error:', error);
        return { summary: '', useFullHistory: true, cost: 0 };
    }
};

3. Detect User Intent Function

// Add with other utility functions
const detectUserIntent = async (lastMessage) => {
    if (!lastMessage || lastMessage.trim().length === 0) {
        return { intent: 'continue_chat', cost: 0 };
    }
    
    try {
        const response = await fetch(wpAgenticWriter.apiUrl + '/detect-intent', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': wpAgenticWriter.nonce,
            },
            body: JSON.stringify({
                lastMessage: lastMessage,
                hasPlan: Boolean(currentPlanRef.current),
                currentMode: agentMode,
                postId: postId,
            }),
        });
        
        if (!response.ok) {
            throw new Error('Intent detection failed');
        }
        
        const data = await response.json();
        return {
            intent: data.intent || 'continue_chat',
            cost: data.cost || 0,
        };
    } catch (error) {
        console.error('Intent detection error:', error);
        return { intent: 'continue_chat', cost: 0 };
    }
};

4. Build Optimized Context Function

// Add with other utility functions
const buildOptimizedContext = async () => {
    const result = await summarizeChatHistory();
    
    if (result.useFullHistory) {
        return {
            type: 'full',
            messages: messages.filter(m => m.role !== 'system'),
            cost: 0,
        };
    }
    
    return {
        type: 'summary',
        summary: result.summary,
        cost: result.cost,
        tokensSaved: result.tokensSaved,
    };
};

5. Handle Reset Command

// Add with other command handlers
const handleResetCommand = async () => {
    if (!confirm('Clear all conversation history? This cannot be undone.')) {
        return;
    }
    
    try {
        // Clear frontend state
        setMessages([]);
        currentPlanRef.current = null;
        
        // Clear backend chat history
        await fetch(wpAgenticWriter.apiUrl + '/clear-context', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': wpAgenticWriter.nonce,
            },
            body: JSON.stringify({ postId: postId }),
        });
        
        setMessages([{
            role: 'system',
            type: 'info',
            content: '✅ Context cleared. Starting fresh conversation.'
        }]);
    } catch (error) {
        console.error('Reset error:', error);
        setMessages(prev => [...prev, {
            role: 'system',
            type: 'error',
            content: 'Failed to clear context. Please try again.'
        }]);
    }
};

Modifications to Existing Functions

Modify handleSendMessage (detect /reset command)

Find the message sending logic and add at the beginning:

// Check for reset command
if (/^\s*(\/reset|\/clear)\s*$/i.test(userMessage)) {
    setInput('');
    await handleResetCommand();
    return;
}

// Check for Writing mode notes warning
if (agentMode === 'writing' && currentPlanRef.current) {
    setMessages(prev => [...prev, 
        { role: 'user', content: userMessage },
        {
            role: 'system',
            type: 'info',
            content: '💡 Note: Messages in Writing mode are for discussion only. To modify the outline, switch to Planning mode.'
        }
    ]);
}

Modify handleExecuteArticle (add plan check)

Add at the very beginning of the function:

// Check if plan exists
if (!currentPlanRef.current) {
    setMessages(prev => [...prev, {
        role: 'system',
        type: 'error',
        content: '⚠️ No outline found. Please create an outline first by switching to Planning mode.'
    }]);
    setIsLoading(false);
    return;
}

UI Components to Add

Render Writing Empty State

Add this component function:

const renderWritingEmptyState = () => {
    return wp.element.createElement('div', { className: 'wpaw-writing-empty-state' },
        wp.element.createElement('div', { className: 'wpaw-empty-state-content' },
            wp.element.createElement('span', { className: 'wpaw-empty-state-icon' }, '📝'),
            wp.element.createElement('h3', null, 'No Outline Yet'),
            wp.element.createElement('p', null, 'Writing mode requires an outline to structure your article.'),
            wp.element.createElement(Button, {
                isPrimary: true,
                onClick: () => setAgentMode('planning'),
                className: 'wpaw-empty-state-button'
            }, '📝 Create Outline First'),
            wp.element.createElement('p', { className: 'wpaw-empty-state-hint' },
                'Or switch to ',
                wp.element.createElement('button', {
                    onClick: () => setAgentMode('chat'),
                    className: 'wpaw-link-button'
                }, 'Chat mode'),
                ' to discuss your ideas.'
            )
        )
    );
};

Render Context Indicator

Add this component function:

const renderContextIndicator = () => {
    const chatMessages = messages.filter(m => m.role !== 'system');
    const messageCount = chatMessages.length;
    const estimatedTokens = messageCount * 500; // Rough estimate
    
    if (messageCount === 0) return null;
    
    return wp.element.createElement('div', { className: 'wpaw-context-indicator' },
        wp.element.createElement('div', { className: 'wpaw-context-info' },
            wp.element.createElement('span', { className: 'wpaw-context-count' }, 
                `💬 ${messageCount} messages`
            ),
            wp.element.createElement('span', { className: 'wpaw-context-tokens' }, 
                `~${estimatedTokens} tokens`
            )
        ),
        wp.element.createElement('button', {
            className: 'wpaw-context-clear',
            onClick: handleResetCommand,
            title: 'Clear conversation history'
        }, '🗑️ Clear')
    );
};

Render Contextual Action

Add this component function:

const renderContextualAction = (intent) => {
    if (!intent || intent === 'continue_chat') return null;
    
    const actions = {
        create_outline: {
            icon: '📝',
            title: 'Ready to create an outline?',
            description: 'I can help you structure your article.',
            button: 'Create Outline',
            onClick: () => setAgentMode('planning')
        },
        start_writing: {
            icon: '✍️',
            title: 'Ready to start writing?',
            description: 'Let\'s turn your outline into a full article.',
            button: 'Start Writing',
            onClick: async () => {
                setAgentMode('writing');
                if (currentPlanRef.current) {
                    await handleExecuteArticle();
                }
            }
        },
        refine_content: {
            icon: '✨',
            title: 'Want to refine your content?',
            description: 'I can help improve specific sections.',
            button: 'Show Options',
            onClick: () => {} // Could open refinement options
        }
    };
    
    const action = actions[intent];
    if (!action) return null;
    
    return wp.element.createElement('div', { className: 'wpaw-contextual-action' },
        wp.element.createElement('div', { className: 'wpaw-action-icon' }, action.icon),
        wp.element.createElement('div', { className: 'wpaw-action-content' },
            wp.element.createElement('h4', null, action.title),
            wp.element.createElement('p', null, action.description),
            wp.element.createElement(Button, {
                isPrimary: true,
                onClick: action.onClick
            }, action.button)
        )
    );
};

Integration Points

In Main Render (where messages are displayed)

Add before the message list:

{shouldShowWritingEmptyState() && renderWritingEmptyState()}
{renderContextIndicator()}

In Message Loop (after assistant messages)

Add intent detection display:

{message.detectedIntent && renderContextualAction(message.detectedIntent)}

This completes all the JavaScript logic needed for the frontend implementation.