File: /home/alfouzantranspor/www/wp-content/plugins_backup/templately/docs/AI_CONTENT_WORKFLOW_README.md
# AI Content Sidebar & Full Site Import Workflow System
## Table of Contents
1. [System Overview](#system-overview)
2. [Architecture Components](#architecture-components)
3. [FullSiteImport Component Workflow](#fullsiteimport-component-workflow)
4. [AI Content Workflow Documentation](#ai-content-workflow-documentation)
5. [Redux State Management](#redux-state-management)
6. [Recent Accomplishments](#recent-accomplishments)
7. [Technical Implementation Details](#technical-implementation-details)
8. [Code Examples](#code-examples)
9. [Improvement Suggestions](#improvement-suggestions)
## System Overview
The AI Content Sidebar and Full Site Import system provides two distinct workflows for importing website templates:
1. **Traditional Full Site Import**: Direct template import with customization options
2. **AI-Enhanced Import**: AI-powered content generation followed by template import
Both workflows converge at the customizer stage, providing a unified user experience for template customization and preview.
### Key Components
- **FullSiteImport.js**: Entry point component managing workflow selection
- **AiContentSidebar**: AI conversation interface for content generation
- **ImportingParts**: Multi-step import workflow (Dependencies → Customizer → Results)
- **Customizer**: Template preview and customization interface
## Architecture Components
### AI Content Sidebar (`react-src/app/components/core/AiContentSidebar`)
```
AiContentSidebar/
├── index.js # Main sidebar container with animations
├── AIConversation.js # Conversation flow and AI workflow execution
├── Utils.js # AI utilities (executeAIContentWorkflow, polling)
├── CreditHelpPopover.js # Credit information display
├── MoreCategoryPopover.js # Category selection interface
└── packInfoUtils.js # Pack information processing
```
### Import Parts (`react-src/app/components/core/itemDetails/Packs/import-parts`)
```
import-parts/
├── index.js # Main workflow orchestrator
├── AIContent.js # AI content configuration (legacy)
├── Dependencies.js # Plugin dependency management
├── DependencyInstalling.js # Installation progress tracking
├── DependencyInstalled.js # Installation completion
├── Customizer.js # Template preview and customization
├── ColorPicker.js # Color customization component
├── Typography.js # Typography customization
└── Utils.js # Shared utilities and caching
```
## FullSiteImport Component Workflow
### Entry Point: `FullSiteImport.js`
The component provides two import options:
```javascript
// Traditional Import
if (!isWithAI) {
dispatch(showFSIModal());
}
// AI-Enhanced Import
else {
dispatch(showAiSidebar({id: props.id}));
}
```
### Traditional Workflow
```
User Click "Build Full Website"
↓
showFSIModal() → Redux State Update
↓
Modal Opens → ImportingParts Component
↓
Step 1: Dependencies Check/Install
↓
Step 2: Customizer (Template Preview)
↓
Step 3: Import Execution
↓
Step 4: Results Display
```
### AI-Enhanced Workflow
```
User Click "Build with Templately AI"
↓
showAiSidebar() → Redux State Update
↓
AI Sidebar Opens → AIConversation Component
↓
User Conversation (Category → Description → Contact Info)
↓
executeAIContentWorkflow() → Parallel AJAX Calls
↓
AI Content Generation Complete
↓
showFSIModal({aiTemplates}) + hideAiSidebar()
↓
FSI Modal Opens → Customizer with AI Data
↓
sendAIDataToIframe() + pollAIContent()
↓
Continue Traditional Workflow
```
## AI Content Workflow Documentation
### Phase 1: AI Conversation
**Component**: `AIConversation.js`
1. **Category Selection**: User selects business niche
2. **Description Input**: User provides business description
3. **Contact Information**: Optional contact details collection
### Phase 2: AI Content Generation
**Function**: `executeAIContentWorkflow()`
```javascript
const workflowResult = await executeAIContentWorkflow(aiRequestData, {
onSessionCreated: (sessionResult) => { /* Session created */ },
onAIContentStarted: (aiResult) => { /* AI generation started */ },
onBothCompleted: ({ sessionResult, aiContentResult }) => { /* Both calls done */ },
onWorkflowComplete: (result) => { /* Workflow finished */ }
});
```
**Parallel AJAX Calls**:
1. `createSessionAndDownloadPack()` - Downloads template pack
2. `startModifyAiContent()` - Initiates AI content generation
### Phase 3: Modal Transition
```javascript
const aiTemplates = {
templates: workflowResult.templates,
process_id: workflowResult.process_id,
ai_page_ids: aiRequestData.ai_page_ids,
};
// Store in Redux and transition modals
dispatch(showFSIModal({ aiTemplates }));
handleSidebarSubmit(); // Closes AI sidebar
```
### Phase 4: Customizer Integration
**Component**: `Customizer.js`
```javascript
// Monitor Redux state for AI templates
const aiTemplates = useSelector(
(state) => state?.general?.fullSiteImport?.fsiModalContext?.aiTemplates
);
// When AI templates detected
useEffect(() => {
if (aiTemplates && iframeLoaded) {
// Prepare URL arguments and body with both AI templates and image mappings
const urlArgs = {
plugin_preview: version,
has_ai_json: 'true',
platform: platform,
dev_mode: window.templately.dev_mode || false,
log: window.templately.log || false,
ai_page_ids: JSON.stringify(ai_page_ids),
};
const body = {
templates: aiTemplates.templates
};
// Add image mappings if available
if (aiTemplates.imageMappings && Object.keys(aiTemplates.imageMappings).length > 0) {
body.imageMappings = aiTemplates.imageMappings;
}
// Send consolidated AI data to iframe
sendAIDataToIframe(live_url, urlArgs, body);
// Start polling for AI content updates
pollAIContent(processId, aiPageIds, onUpdate, onComplete, onError);
}
}, [aiTemplates, iframeLoaded]);
```
## Redux State Management
### State Structure
```javascript
state.general.fullSiteImport = {
currentStep: 1,
results: null,
aiSidebarContext: {
id: null,
show: false,
content: {},
expanded: false
},
fsiModalContext: {
show: false,
aiTemplates: null // AI workflow results
},
packInfo: { data, loading, error },
googleFonts: { data, loading, error }
}
```
### AI Sidebar Actions
The AI sidebar has multiple action creators for different purposes, each designed to preserve state while updating specific properties:
```javascript
// Show/Hide Sidebar (preserves expanded and content state)
showAiSidebar(args = {}) → SHOW_AI_SIDEBAR
hideAiSidebar(args = {}) → HIDE_AI_SIDEBAR
// Expand/Collapse Sidebar (preserves show, id, and content state)
expandAiSidebar(args = {}) → EXPAND_AI_SIDEBAR
collapseAiSidebar(args = {}) → COLLAPSE_AI_SIDEBAR
// Update Entire Context (replaces entire aiSidebarContext)
setAiSidebarContext(payload) → SET_AI_SIDEBAR_CONTEXT
```
#### Action Behavior Details
**`showAiSidebar(args = {})`**
- Sets `show: true` and `id: args?.id ?? null`
- Preserves existing `expanded` and `content` state
- Only updates `expanded` and `content` if explicitly passed in args
- Example: `showAiSidebar({ id: 'pack-123', content: { step: 1 } })`
**`hideAiSidebar(args = {})`**
- Sets `show: false` and `id: null` (always resets pack association)
- Preserves existing `expanded` and `content` state
- Only updates `expanded` and `content` if explicitly passed in args
- The `id` is always set to `null` and cannot be overridden by args
- Example: `hideAiSidebar({ content: {} })` // clears content while hiding
**`expandAiSidebar(args = {})`**
- Sets `expanded: true`
- Preserves existing `show`, `id`, and `content` state
- Only updates other properties if explicitly passed in args
- Example: `expandAiSidebar({ content: { newData: true } })`
**`collapseAiSidebar(args = {})`**
- Sets `expanded: false`
- Preserves existing `show`, `id`, and `content` state
- Only updates other properties if explicitly passed in args
- Example: `collapseAiSidebar()` // just collapses, preserves everything else
**`setAiSidebarContext(payload)`**
- Replaces entire `aiSidebarContext` object
- Use when you need to update multiple properties at once
- Example: `setAiSidebarContext({ id: 'pack-123', show: true, expanded: true, content: { step: 2 } })`
### Other Key Actions
```javascript
// FSI Modal Management
showFSIModal(args) → SHOW_FSI_MODAL
hideFSIModal() → HIDE_FSI_MODAL
// Pack Information
fetchPackImportInfoRequest(packId, isAi) → FETCH_PACK_IMPORT_INFO_REQUEST
```
### Usage Examples
```javascript
// Common usage patterns
import { showAiSidebar, hideAiSidebar, expandAiSidebar, collapseAiSidebar } from '../redux/actions';
// Show sidebar for a specific pack (preserves expanded state)
dispatch(showAiSidebar({ id: 'pack-123' }));
// Hide sidebar and reset pack association (id becomes null)
dispatch(hideAiSidebar());
// Expand sidebar without affecting visibility
dispatch(expandAiSidebar());
// Collapse and hide in one action
dispatch(collapseAiSidebar({ show: false }));
// Chain actions (each preserves other properties)
dispatch(showAiSidebar({ id: 'pack-123' }));
dispatch(expandAiSidebar());
// Update content while showing
dispatch(showAiSidebar({
id: 'pack-123',
content: { step: 1, data: 'initial' }
}));
// Clear content when hiding (id is always set to null)
dispatch(hideAiSidebar({ content: {} }));
// Note: hideAiSidebar always resets id to null, even if passed in args
dispatch(hideAiSidebar({ id: 'pack-123' })); // id will still be null
```
### State Validation
```javascript
// Verify state preservation
const currentState = state.general.fullSiteImport.aiSidebarContext;
// After showAiSidebar({ id: 'pack-123' })
// ✅ show: true, id: 'pack-123'
// ✅ expanded: preserved from previous state
// ✅ content: preserved from previous state
// After hideAiSidebar()
// ✅ show: false, id: null (always reset)
// ✅ expanded: preserved from previous state
// ✅ content: preserved from previous state
// After expandAiSidebar()
// ✅ expanded: true
// ✅ show: preserved from previous state
// ✅ id: preserved from previous state
// ✅ content: preserved from previous state
```
### Action Flow
```
User Action → Component Dispatch → Redux Reducer → State Update → Component Re-render
```
## Recent Accomplishments
### 1. Redux State Conversion
- **Before**: Local state `useState(showFSIModal)`
- **After**: Redux actions `showFSIModal()` / `hideFSIModal()`
- **Benefit**: Centralized state management, better debugging
### 2. AI Workflow Completion Handling
- **Implementation**: Automatic transition from AI Sidebar to FSI Modal
- **Redux Integration**: AI templates stored in `fsiModalContext.aiTemplates`
- **Seamless UX**: No manual intervention required for modal transitions
### 3. AJAX Calls Refactoring
- **Shared Session Management**: UUID coordination between parallel calls
- **Consistent Patterns**: All pack operations use AJAX with WordPress nonces
- **Error Handling**: Proper retry mechanisms and error states
### 4. Customizer AI Integration
- **Automatic Detection**: Monitors Redux state for AI templates
- **Iframe Communication**: `sendAIDataToIframe()` for consolidated preview data (templates + image mappings)
- **Polling System**: `pollAIContent()` for real-time updates
### 5. Code Architecture Improvements
- **Separation of Concerns**: AI logic moved to dedicated utility functions
- **Reusable Components**: Common patterns extracted and shared
- **Type Safety**: Consistent data structures throughout workflow
## Technical Implementation Details
### Component Communication Patterns
1. **Redux-First**: All major state changes go through Redux
2. **Props Drilling**: Minimal, only for immediate parent-child communication
3. **Event-Driven**: useEffect hooks respond to state changes
4. **Callback Patterns**: Async operations use callback functions
### State Management Best Practices
1. **Immutable Updates**: All Redux reducers use immutable patterns
2. **Normalized State**: Complex data structures are flattened
3. **Selective Updates**: useSelector with shallowEqual for performance
4. **Cleanup Patterns**: Proper cleanup in useEffect return functions
### Error Handling
1. **Try-Catch Blocks**: All async operations wrapped in error handling
2. **User Feedback**: Error states displayed to users appropriately
3. **Graceful Degradation**: Fallback behaviors for failed operations
4. **Logging**: Comprehensive console logging for debugging
5. **Abort Error Handling**: Proper detection and handling of intentionally cancelled requests
#### AbortController Error Handling Pattern
The ImageReplacePanel implements comprehensive abort error detection to prevent false error messages when requests are intentionally cancelled:
```javascript
} catch (error) {
// Check if error is due to request cancellation
if (
error?.name === 'AbortError' ||
error?.message?.includes('abort') ||
error?.message?.includes('cancelled') ||
abortController.signal.aborted
) {
// Don't show error message for user-initiated cancellation
return;
}
// Handle genuine errors
setSearchError(error.message || __('Failed to search images. Please try again.', 'templately'));
}
```
**Key Benefits:**
- Prevents "You are probably offline" messages for intentional request cancellations
- Allows new search results to display properly without interference from aborted requests
- Maintains clean error state management during rapid user interactions
### Performance Optimizations
1. **Throttled Updates**: iframe communication throttled to 500ms
2. **Memoized Selectors**: useSelector with proper dependency arrays
3. **Lazy Loading**: Components loaded only when needed
4. **Cleanup Intervals**: Polling intervals properly cleaned up
## Code Examples
### Redux Action Usage
```javascript
// Show AI Sidebar
dispatch(showAiSidebar({id: packId}));
// Transition to FSI Modal with AI data
dispatch(showFSIModal({
aiTemplates: {
templates: workflowResult.templates,
process_id: workflowResult.process_id,
ai_page_ids: aiRequestData.ai_page_ids
}
}));
// Hide modals
dispatch(hideAiSidebar());
dispatch(hideFSIModal());
```
### State Monitoring
```javascript
// Monitor AI templates in Customizer
const aiTemplates = useSelector(
(state) => state?.general?.fullSiteImport?.fsiModalContext?.aiTemplates,
shallowEqual
);
useEffect(() => {
if (aiTemplates && iframeLoaded) {
// Process AI templates
handleAITemplates(aiTemplates);
}
}, [aiTemplates, iframeLoaded]);
```
### AI Workflow Execution
```javascript
const workflowResult = await executeAIContentWorkflow(aiRequestData, {
onSessionCreated: (result) => console.log('Session:', result.session_id),
onAIContentStarted: (result) => console.log('Process:', result.process_id),
onWorkflowComplete: (result) => {
// Store results and transition
const aiTemplates = {
templates: result.templates,
process_id: result.process_id,
ai_page_ids: aiRequestData.ai_page_ids
};
dispatch(showFSIModal({ aiTemplates }));
}
});
```
## Improvement Suggestions
### 1. Data Flow Optimization
- **Recommendation**: Implement Redux-Saga for complex async workflows
- **Benefit**: Better error handling and flow control
- **Implementation**: Replace manual async/await with saga patterns
### 2. State Management Patterns
- **Recommendation**: Use Redux Toolkit for reducer logic
- **Benefit**: Reduced boilerplate and better TypeScript support
- **Implementation**: Migrate existing reducers to createSlice
### 3. Performance Optimization
- **Recommendation**: Implement React.memo for expensive components
- **Benefit**: Reduced unnecessary re-renders
- **Implementation**: Wrap Customizer and AIConversation components
### 4. Code Maintainability
- **Recommendation**: Extract business logic into custom hooks
- **Benefit**: Better testability and reusability
- **Implementation**: Create useAIWorkflow, useCustomizer hooks
### 5. Alternative Architectural Approaches
- **Recommendation**: Consider state machines for complex workflows
- **Benefit**: More predictable state transitions
- **Implementation**: Use XState for workflow orchestration
### 6. Error Handling Improvements
- **Recommendation**: Implement global error boundaries
- **Benefit**: Better user experience during failures
- **Implementation**: Add ErrorBoundary components around major sections
### 7. Testing Strategy
- **Recommendation**: Add comprehensive unit and integration tests
- **Benefit**: Improved reliability and easier refactoring
- **Implementation**: Jest + React Testing Library for component tests
## Detailed Workflow Diagrams
### AI Content Generation Flow
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ User Clicks │ │ AI Sidebar │ │ Conversation │
│ "Import with AI"│───▶│ Opens │───▶│ Flow │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ executeAI │◀───│ User Completes │◀───│ 3 Steps: │
│ ContentWorkflow │ │ Conversation │ │ Category/Desc/ │
└─────────────────┘ └──────────────────┘ │ Contact │
│ └─────────────────┘
▼
┌─────────────────────────────────────────────────────────────────┐
│ Parallel AJAX Calls │
│ ┌─────────────────────┐ ┌─────────────────────────────────┐ │
│ │createSessionAnd │ │startModifyAiContent │ │
│ │DownloadPack() │ │(REST API) │ │
│ │(AJAX) │ │ │ │
│ └─────────────────────┘ └─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Store aiTemplates│───▶│showFSIModal() │───▶│ FSI Modal Opens │
│ in Redux State │ │hideAiSidebar() │ │ with AI Data │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Customizer │───▶│sendAIDataToIframe│───▶│ pollAIContent │
│ Detects AI │ │ () │ │ () │
│ Templates │ └──────────────────┘ └─────────────────┘
└─────────────────┘
```
### Traditional Import Flow
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ User Clicks │ │ FSI Modal │ │ Dependencies │
│"Import Full Site"│───▶│ Opens │───▶│ Check │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Customizer │◀───│ Dependencies │◀───│ Install │
│ (Preview) │ │ Installed │ │ Dependencies │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ User Customizes│───▶│ Import Process │───▶│ Results │
│ Template │ │ Execution │ │ Display │
└─────────────────┘ └──────────────────┘ └─────────────────┘
```
## File Structure and Dependencies
### Core Dependencies
```javascript
// Redux State Management
import { useSelector, useDispatch } from 'react-redux';
import { showFSIModal, hideAiSidebar } from '../../../../redux/actions';
// AI Utilities
import { executeAIContentWorkflow, sendAIDataToIframe, pollAIContent } from './Utils';
// WordPress Integration
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
```
### Component Hierarchy
```
FullSiteImport.js (Entry Point)
├── Modal (react-modal)
│ └── ImportingParts/index.js (Workflow Orchestrator)
│ ├── AIContent.js (Step 0 - Legacy)
│ ├── Dependencies.js (Step 2)
│ ├── DependencyInstalling.js (Step 3)
│ ├── Customizer.js (Step 1 & Main)
│ └── DependencyInstalled.js (Step 4)
│
└── AiContentSidebar/index.js (AI Workflow)
└── AIConversation.js (Conversation Flow)
├── CreditHelpPopover.js
├── MoreCategoryPopover.js
└── Utils.js (AI Workflow Functions)
```
## API Integration Points
### WordPress AJAX Actions
```php
// Pack Operations (AJAX)
'templately_pack_create_session_and_download' // Session creation + pack download
'templately_pack_import_settings' // Import configuration
'templately_pack_import' // Main import process
'templately_pack_ai_get_json' // AI content polling
// AI Content Operations (REST API)
'/templately/v1/ai-content/modify-content' // AI content generation
'/templately/v1/ai-content/ai-update' // AI content updates
```
### Data Flow Between Frontend and Backend
```javascript
// Frontend → Backend (AI Content)
const aiRequestData = {
pack_id: packId,
platform: platform,
business_niches: category,
prompt: description,
phone: contactNumber,
address: businessAddress,
email: email,
ai_page_ids: processedPackData?.aiPageIDs,
session_id: sessionId // Shared UUID for coordination
};
// Backend → Frontend (AI Response)
{
status: 'success',
process_id: 'uuid-process-id',
templates: { /* AI generated content */ },
ai_page_ids: { /* page mappings */ }
}
```
## Debugging and Troubleshooting
### Common Issues and Solutions
1. **AI Sidebar Not Opening**
- Check Redux state: `state.general.fullSiteImport.aiSidebarContext.show`
- Verify pack ID is passed correctly to `showAiSidebar({id})`
2. **Modal Transition Fails**
- Check `aiTemplates` in Redux: `state.general.fullSiteImport.fsiModalContext.aiTemplates`
- Verify `executeAIContentWorkflow` completes successfully
3. **Customizer Not Detecting AI Data**
- Check `iframeLoaded` state in Customizer component
- Verify `sendAIDataToIframe` function is called
- Check browser console for iframe communication errors
4. **Polling Not Working**
- Verify `process_id` and `ai_page_ids` are present in aiTemplates
- Check network tab for `templately_pack_ai_get_json` requests
- Ensure polling interval is properly cleaned up
### Debug Console Commands
```javascript
// Check Redux state
console.log(store.getState().general.fullSiteImport);
// Monitor AI workflow
window.templately_debug_ai = true;
// Check iframe communication
window.addEventListener('message', (e) => {
if (e.data?.type?.includes('templately')) {
console.log('Iframe message:', e.data);
}
});
```
## Performance Considerations
### Memory Management
1. **Cleanup Patterns**: All useEffect hooks include proper cleanup
2. **Interval Management**: Polling intervals are cleared on component unmount
3. **Event Listeners**: Window event listeners are properly removed
### Optimization Strategies
1. **Throttled Updates**: Iframe communication throttled to prevent excessive calls
2. **Selective Re-renders**: useSelector with shallowEqual comparison
3. **Lazy Loading**: Components loaded only when needed
4. **Memoization**: Expensive calculations memoized with useMemo
## Implementation Examples
### Adding a New AI Conversation Step
```javascript
// 1. Add to conversation steps array in AIConversation.js
const newStep = {
key: 'new_step',
question: '<p>Your question here?</p>',
answer: null,
result: null,
skip: false,
done: false,
editable: true,
};
// 2. Add handling in handleAnswerSubmit
const handleAnswerSubmit = useCallback((answer) => {
if (currentStep === 'new_step') {
// Process new step answer
setConversationSteps(prev => prev.map(step =>
step.key === 'new_step'
? { ...step, answer, result: processAnswer(answer), done: true }
: step
));
setCurrentStep('next_step');
}
}, [currentStep]);
// 3. Add to aiRequestData object
const aiRequestData = {
// ... existing fields
new_field: conversationResults.newStep || '',
};
```
### Creating a Custom Redux Action
```javascript
// 1. Add constant to constants.js
const FULL_SITE_IMPORT = {
// ... existing constants
SET_CUSTOM_DATA: 'FULL_SITE_IMPORT_SET_CUSTOM_DATA',
};
// 2. Add action creator to fullSiteImport.js
export const setCustomData = (payload) => ({
type: FULL_SITE_IMPORT.SET_CUSTOM_DATA,
payload
});
// 3. Add reducer case to generalReducer.js
case FULL_SITE_IMPORT.SET_CUSTOM_DATA:
return {
...state,
fullSiteImport: {
...state.fullSiteImport,
customData: payload.payload
}
};
// 4. Use in component
const dispatch = useDispatch();
const customData = useSelector(state => state.general.fullSiteImport.customData);
dispatch(setCustomData({ key: 'value' }));
```
### Extending the Customizer with New Features
```javascript
// 1. Add new state
const [newFeature, setNewFeature] = useState(false);
// 2. Add to throttled post message
const throttledPostMessage = throttle((color, logoSize, typography, aiData, newFeature) => {
const message = {
type: 'templately_css_variable',
platform,
color,
logoSize,
typography,
aiData,
newFeature, // Add new feature data
};
iframe.contentWindow?.postMessage(message, '*');
}, 500);
// 3. Update useEffect dependencies
useEffect(() => {
throttledPostMessage(color, logoSize, normalizedTypography, aiData, newFeature);
}, [color, logoSize, normalizedTypography, aiData, newFeature, throttledPostMessage]);
// 4. Add UI controls
<div className="new-feature-control">
<label>
<input
type="checkbox"
checked={newFeature}
onChange={(e) => setNewFeature(e.target.checked)}
/>
Enable New Feature
</label>
</div>
```
## Best Practices and Conventions
### Redux State Management
1. **Action Naming**: Use descriptive, hierarchical names
```javascript
// Good
FULL_SITE_IMPORT_SET_AI_TEMPLATES
// Bad
SET_TEMPLATES
```
2. **Payload Structure**: Keep payloads flat and predictable
```javascript
// Good
{ type: 'ACTION', payload: { show: true, data: {...} } }
// Bad
{ type: 'ACTION', show: true, data: {...} }
```
3. **Selector Usage**: Use shallowEqual for object comparisons
```javascript
const data = useSelector(
state => state.complex.nested.object,
shallowEqual
);
```
### Component Architecture
1. **Single Responsibility**: Each component should have one clear purpose
2. **Props Interface**: Define clear prop interfaces with defaults
3. **Error Boundaries**: Wrap complex components in error boundaries
4. **Cleanup**: Always cleanup effects, intervals, and listeners
### Async Operations
1. **Error Handling**: Wrap all async operations in try-catch
2. **Loading States**: Provide user feedback during operations
3. **Cancellation**: Support operation cancellation where appropriate
4. **Retry Logic**: Implement retry for transient failures
### Performance Guidelines
1. **Memoization**: Use React.memo for expensive components
2. **Throttling**: Throttle high-frequency operations
3. **Lazy Loading**: Load components only when needed
4. **Bundle Splitting**: Split large features into separate bundles
## Migration Guide
### From Local State to Redux
```javascript
// Before (Local State)
const [showModal, setShowModal] = useState(false);
const openModal = () => setShowModal(true);
const closeModal = () => setShowModal(false);
// After (Redux)
const showModal = useSelector(state => state.ui.modal.show);
const dispatch = useDispatch();
const openModal = () => dispatch(showUIModal());
const closeModal = () => dispatch(hideUIModal());
```
### From Callback Props to Redux Actions
```javascript
// Before (Callback Props)
<ChildComponent onAction={(data) => handleAction(data)} />
// After (Redux Actions)
<ChildComponent />
// In ChildComponent
const dispatch = useDispatch();
const handleAction = (data) => dispatch(performAction(data));
```
## Testing Strategies
### Component Testing
```javascript
import { render, screen, fireEvent } from '@testing-library/react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import AIConversation from './AIConversation';
const mockStore = createStore(() => ({
general: {
fullSiteImport: {
aiSidebarContext: { id: null, show: true, content: {} }
}
}
}));
test('renders conversation steps', () => {
render(
<Provider store={mockStore}>
<AIConversation />
</Provider>
);
expect(screen.getByText(/Ready to build/)).toBeInTheDocument();
});
```
### Redux Testing
```javascript
import { showAiSidebar, hideAiSidebar, expandAiSidebar, collapseAiSidebar } from './actions';
import reducer from './reducer';
// Test state preservation with AI sidebar actions
test('AI sidebar state preservation', () => {
const initialState = {
fullSiteImport: {
aiSidebarContext: {
id: 'pack-123',
show: false,
content: { step: 2, data: 'preserved' },
expanded: true
}
}
};
// Test showAiSidebar preserves expanded and content
const showAction = showAiSidebar({ id: 'pack-456' });
const afterShow = reducer(initialState, showAction);
expect(afterShow.fullSiteImport.aiSidebarContext).toEqual({
id: 'pack-456',
show: true,
content: { step: 2, data: 'preserved' }, // preserved
expanded: true // preserved
});
// Test hideAiSidebar resets id and preserves expanded and content
const hideAction = hideAiSidebar();
const afterHide = reducer(afterShow, hideAction);
expect(afterHide.fullSiteImport.aiSidebarContext).toEqual({
id: null, // always reset to null
show: false,
content: { step: 2, data: 'preserved' }, // preserved
expanded: true // preserved
});
// Test expandAiSidebar preserves other properties
const expandAction = expandAiSidebar();
const afterExpand = reducer(afterHide, expandAction);
expect(afterExpand.fullSiteImport.aiSidebarContext).toEqual({
id: 'pack-456', // preserved
show: false, // preserved
content: { step: 2, data: 'preserved' }, // preserved
expanded: true
});
// Test collapseAiSidebar preserves other properties
const collapseAction = collapseAiSidebar();
const afterCollapse = reducer(afterExpand, collapseAction);
expect(afterCollapse.fullSiteImport.aiSidebarContext).toEqual({
id: null, // was reset by hideAiSidebar
show: false, // preserved
content: { step: 2, data: 'preserved' }, // preserved
expanded: false
});
});
// Test action chaining
test('AI sidebar action chaining', () => {
const initialState = {
fullSiteImport: {
aiSidebarContext: {
id: null,
show: false,
content: {},
expanded: false
}
}
};
// Chain: show → expand → update content → hide
let state = initialState;
state = reducer(state, showAiSidebar({ id: 'pack-123' }));
expect(state.fullSiteImport.aiSidebarContext.show).toBe(true);
expect(state.fullSiteImport.aiSidebarContext.id).toBe('pack-123');
state = reducer(state, expandAiSidebar({ content: { step: 1 } }));
expect(state.fullSiteImport.aiSidebarContext.expanded).toBe(true);
expect(state.fullSiteImport.aiSidebarContext.content).toEqual({ step: 1 });
expect(state.fullSiteImport.aiSidebarContext.show).toBe(true); // preserved
state = reducer(state, hideAiSidebar());
expect(state.fullSiteImport.aiSidebarContext.show).toBe(false);
expect(state.fullSiteImport.aiSidebarContext.id).toBe(null); // always reset
expect(state.fullSiteImport.aiSidebarContext.expanded).toBe(true); // preserved
expect(state.fullSiteImport.aiSidebarContext.content).toEqual({ step: 1 }); // preserved
});
```
### Integration Testing
```javascript
import { renderWithProviders } from '../test-utils';
import FullSiteImport from './FullSiteImport';
test('AI workflow integration', async () => {
const { user } = renderWithProviders(<FullSiteImport id="123" />);
// Click AI import button
await user.click(screen.getByText(/Import with AI/));
// Verify AI sidebar opens
expect(screen.getByText(/Ready to build/)).toBeInTheDocument();
// Complete conversation flow
// ... test steps
// Verify transition to FSI modal
expect(screen.getByText(/Customizer/)).toBeInTheDocument();
});
```
---
This comprehensive documentation covers the complete AI Content Sidebar and Full Site Import workflow system. It serves as both a reference guide and implementation handbook for developers working with this system. For the most up-to-date implementation details, always refer to the actual source code and inline documentation.