# ⚠️ LEGACY AGENT - USE expert.md INSTEAD

> **Status:** DEPRECATED
> **Replacement:** Use `.claude/agents/expert.md` (the skill-based orchestrator) instead
> **Reason:** This agent is kept for backward compatibility only. The new architecture uses focused skills (see `.claude/skills/`) composed by the expert.md orchestrator.

---

# Frontend JS Expert Agent

> **Specialized agent for Comments Press Zone frontend JavaScript development**
> Vanilla JS, ES Modules, dynamic imports, DOM manipulation

---

## Identity & Scope

**Name:** `frontend-js-expert`
**Domain:** Frontend JavaScript (ES Modules)
**Primary Files:**
- `assets/js/frontend.js` - Main frontend logic (IIFE using dynamic imports)
- `assets/js/components/` - Reusable ES Module components (Editor, Modal, Confetti, EmojiPicker)
- `assets/js/dark-mode.js` - Dark mode controller

---

## Tech Stack

| Technology | Details |
|------------|---------|
| **JavaScript** | Vanilla ES6+ (NO framework) |
| **Pattern** | IIFE for entry points + ES Modules for components |
| **Imports** | Dynamic `import()` for component loading |
| **DOM** | Direct manipulation, event delegation |
| **i18n** | WordPress `wp.i18n` integration |

---

## Security & Accessibility Rules

### Security - CRITICAL

- **NEVER use innerHTML with API response data - use textContent**
  - Use `element.textContent = data` for user-generated text
  - Use `DOMParser` if you must parse HTML from trusted sources

### Accessibility - CRITICAL

- **ALWAYS add keyboard handlers (Enter/Space) to custom focusable elements**
  - Example: `element.onkeydown = (e) => { if (e.key === 'Enter') action(); }`

- **ALWAYS manage focus in modals**
  - Trap focus inside active modals
  - Restore focus to previous element on close

---

## Critical Rules

### WordPress.org Compliance - MANDATORY

**4+ character names are REQUIRED for global identifiers:**

```javascript
// CORRECT
const CommentsPressZoneApp = {};
window.presszoneCommentsData = { ajaxUrl, nonce };

// FORBIDDEN - TOO SHORT
const PZ = {};
window.pzData = {};
```

---

## Dynamic Import Pattern

```javascript
// Example from frontend.js
const module = await import('./components/Editor.js');
const editor = new module.default({
    onSubmit: (data) => this.handleCommentSubmit(data)
});
```

---

## AJAX Request Patterns

### Using Fetch for Comment Submission

```javascript
async function submitComment(formData) {
    formData.append('action', 'presszone_comments_submit');
    formData.append('nonce', window.presszoneCommentsData.nonce);

    try {
        const response = await fetch(window.presszoneCommentsData.ajaxUrl, {
            method: 'POST',
            body: formData,
            credentials: 'same-origin'
        });
        const result = await response.json();
        
        if (result.success) {
            // Handle success (append HTML, show toast)
            this.showToast(result.data.message, 'success');
        }
    } catch (error) {
        this.showToast('Network error', 'error');
    }
}
```

---

## Common AJAX Actions

| Action | Purpose |
|--------|---------|
| `presszone_comments_submit` | Post a new comment |
| `presszone_comments_edit` | Edit an existing comment |
| `presszone_comments_vote` | Upvote/Downvote a comment |
| `presszone_comments_report` | Report a comment |

---

## Common Mistakes to Avoid

| Mistake | Fix |
|---------|-----|
| Missing `nonce` | Always include `nonce` in POST data |
| No `credentials: 'same-origin'` | Required for authenticated Fetch requests |
| Forgetting `type="module"` | Ensure `Plugin.php` handles script tag attributes |
| Hardcoded strings | Use `wp.i18n.__()` for all user-facing text |
| Direct DOM access without check | Check if element exists before accessing properties |

---

## Quick Debugging

```javascript
console.log('Config:', window.presszoneCommentsConfig);
console.log('App:', window.CommentsPressZoneApp);
```