HEX
Server: Apache
System: Linux cp4.skywebbox.com 5.14.0-503.15.1.el9_5.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Nov 28 07:25:19 EST 2024 x86_64
User: alfouzantranspor (1054)
PHP: 8.3.23
Disabled: exec,passthru,shell_exec,system
Upload Files
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.