# Inbox

[![Commercial](https://img.shields.io/badge/License-Commercial-red.svg)](LICENSE.md)
[![Cockpit CMS](https://img.shields.io/badge/Cockpit%20CMS-Addon-blue.svg)](https://getcockpit.com)
[![Form Management](https://img.shields.io/badge/Feature-Form%20Management-green.svg)](#features)

> **Advanced form handling and submission management for Cockpit CMS**

Inbox is a commercial addon that transforms Cockpit CMS into a powerful form management system. Create secure contact forms, handle file uploads, manage submissions, and protect against spam with enterprise-grade security features and AI-powered language detection.

## ✨ Features

### 📝 **Form Management**
- **Unlimited Forms**: Create and manage multiple forms with unique tokens
- **Form Organization**: Group forms by categories and assign colors
- **Dynamic Fields**: Configure which fields to capture and validate
- **Form States**: Enable/disable forms with visibility controls
- **Token Security**: Each form gets a unique token for secure submissions

### 🔒 **Advanced Security**
- **Domain Restrictions**: Limit form submissions to specific domains
- **Honeypot Protection**: Invisible anti-bot fields to catch spam
- **Language Detection**: AI-powered content filtering by language
- **File Upload Security**: Comprehensive file type and MIME validation
- **Field Whitelisting**: Only capture specified form fields

### 📧 **Email Notifications**
- **Multi-Recipient**: Send notifications to multiple email addresses
- **Custom Templates**: Customize email notification layouts
- **Auto-Reply**: Automatic reply-to based on submission email
- **Attachment Support**: Include file attachments in notifications

### 📊 **Submission Management**
- **Centralized Dashboard**: View all forms and submission counts
- **Advanced Search**: Full-text search across submission data
- **Bulk Operations**: Delete multiple submissions at once
- **Export Capabilities**: Export submission data for analysis
- **File Management**: Organized file storage by form and date

### 🌐 **Language Detection**
- **73+ Languages**: Support for major world languages using AI detection
- **Content Filtering**: Filter submissions based on detected language
- **Spam Prevention**: Block submissions in unwanted languages
- **Multilingual Forms**: Handle international submissions intelligently

### 📁 **File Upload System**
- **Secure Upload Handling**: Safe file processing with validation
- **Organized Storage**: Files stored by form, date, and unique identifiers
- **Multiple File Support**: Handle single or multiple file uploads per field
- **File Type Restrictions**: Block dangerous file extensions and MIME types

## 🚀 Quick Start

### 1. Installation

Inbox is a commercial addon included with Cockpit CMS Pro licenses.

### 2. Install Dependencies

```bash
composer require nitotm/efficient-language-detector
```

### 3. Create Your First Form

1. Navigate to **Inbox** in the admin sidebar
2. Click **"Create Form"**
3. Configure your form:

```php
Form Configuration:
- Name: "Contact Form"
- Group: "Website"
- Token: auto-generated (e.g., "a1b2c3d4e5f6g7h8i9j0")
- Notify Emails: ["admin@yoursite.com"]
- Security Fields: ["name", "email", "message"]
```

### 4. Add Form to Your Website

Use the generated token to submit to your form:

**Important**: All form field names must be prefixed with `data[fieldname]` to be processed correctly.

```html
<form action="/api/inbox/submit/YOUR_FORM_TOKEN" method="POST">
    <input type="text" name="data[name]" placeholder="Your Name" required>
    <input type="email" name="data[email]" placeholder="Your Email" required>
    <textarea name="data[message]" placeholder="Your Message" required></textarea>
    <button type="submit">Send Message</button>
</form>
```

### 5. Handle File Uploads

**Important**: For file uploads, use `enctype="multipart/form-data"` and ensure file inputs also use the `data[fieldname]` naming convention.

```html
<form action="/api/inbox/submit/YOUR_FORM_TOKEN" method="POST" enctype="multipart/form-data">
    <input type="text" name="data[name]" placeholder="Your Name" required>
    <input type="email" name="data[email]" placeholder="Your Email" required>
    <input type="file" name="data[attachment]" accept=".pdf,.doc,.docx,.jpg,.png">
    <textarea name="data[message]" placeholder="Your Message" required></textarea>
    <button type="submit">Send Message</button>
</form>
```

## 📋 Form Configuration

### Data Structure Requirements

**Critical**: All form submissions must follow this data structure:

1. **Form Fields**: All input names must be prefixed with `data[fieldname]`
   ```html
   <input type="text" name="data[name]">        <!-- ✅ Correct -->
   <input type="text" name="name">              <!-- ❌ Wrong - will be ignored -->
   ```

2. **File Uploads**: Files must also use the `data[fieldname]` structure
   ```html
   <input type="file" name="data[attachment]">   <!-- ✅ Correct -->
   <input type="file" name="attachment">         <!-- ❌ Wrong - will be ignored -->
   ```

3. **JSON Submissions**: Wrap all fields in a `data` object
   ```json
   {
     "data": {
       "name": "John Doe",
       "email": "john@example.com"
     }
   }
   ```

4. **Security Fields**: Only fields listed in the form's security configuration will be processed
   ```php
   'security' => [
       'fields' => ['name', 'email', 'message']  // Only these fields will be captured
   ]
   ```

### Basic Form Setup

```php
// Form configuration options
$form = [
    'name' => 'Contact Form',           // Required: Form name
    'group' => 'Website',               // Optional: Form group/category
    'color' => '#3498db',              // Optional: Form color for UI
    'info' => 'Main contact form',     // Optional: Form description
    'token' => 'auto-generated',       // Auto: Unique form token
    '_state' => 1                      // 1 = active, 0 = disabled
];
```

### Email Notifications

```php
'notify' => [
    'emails' => [
        'admin@yoursite.com',
        'sales@yoursite.com',
        'support@yoursite.com'
    ]
]
```

### Security Configuration

```php
'security' => [
    // Only accept these form fields
    'fields' => ['name', 'email', 'phone', 'message'],
    
    // Only accept submissions from these domains
    'domains' => ['yourwebsite.com', 'www.yourwebsite.com'],
    
    // Honeypot field name (invisible to users)
    'honeypot' => 'url',
    
    // Only accept content in these languages
    'languages' => ['en', 'es', 'fr', 'de']
]
```

## 🔧 Advanced Configuration

### Multi-Step Contact Form

```html
<!-- Step 1: Basic Info -->
<form id="contact-form" action="/api/inbox/submit/YOUR_TOKEN" method="POST">
    <div class="step step-1">
        <input type="text" name="data[first_name]" placeholder="First Name" required>
        <input type="text" name="data[last_name]" placeholder="Last Name" required>
        <input type="email" name="data[email]" placeholder="Email" required>
        <button type="button" onclick="nextStep()">Next</button>
    </div>
    
    <!-- Step 2: Details -->
    <div class="step step-2" style="display:none">
        <input type="tel" name="data[phone]" placeholder="Phone Number">
        <input type="text" name="data[company]" placeholder="Company">
        <select name="data[industry]">
            <option value="">Select Industry</option>
            <option value="technology">Technology</option>
            <option value="healthcare">Healthcare</option>
            <option value="finance">Finance</option>
        </select>
        <button type="button" onclick="prevStep()">Previous</button>
        <button type="button" onclick="nextStep()">Next</button>
    </div>
    
    <!-- Step 3: Message -->
    <div class="step step-3" style="display:none">
        <textarea name="data[message]" placeholder="Your Message" required></textarea>
        <select name="data[budget]">
            <option value="">Budget Range</option>
            <option value="under-5k">Under $5,000</option>
            <option value="5k-15k">$5,000 - $15,000</option>
            <option value="15k-50k">$15,000 - $50,000</option>
            <option value="over-50k">Over $50,000</option>
        </select>
        
        <!-- Honeypot field (hidden) -->
        <input type="text" name="data[url]" style="display:none" tabindex="-1">
        
        <button type="button" onclick="prevStep()">Previous</button>
        <button type="submit">Send Message</button>
    </div>
</form>
```

### File Upload Form

```html
<form action="/api/inbox/submit/YOUR_TOKEN" method="POST" enctype="multipart/form-data">
    <h3>Job Application</h3>
    
    <input type="text" name="data[full_name]" placeholder="Full Name" required>
    <input type="email" name="data[email]" placeholder="Email" required>
    <input type="tel" name="data[phone]" placeholder="Phone Number">
    
    <label>Resume (PDF only)</label>
    <input type="file" name="data[resume]" accept=".pdf" required>
    
    <label>Portfolio (Images/PDFs)</label>
    <input type="file" name="data[portfolio]" accept=".pdf,.jpg,.jpeg,.png" multiple>
    
    <label>Cover Letter</label>
    <textarea name="data[cover_letter]" placeholder="Tell us about yourself..." required></textarea>
    
    <select name="data[position]" required>
        <option value="">Select Position</option>
        <option value="developer">Software Developer</option>
        <option value="designer">UI/UX Designer</option>
        <option value="manager">Project Manager</option>
    </select>
    
    <button type="submit">Submit Application</button>
</form>
```

### AJAX Form Submission

```javascript
// Modern AJAX form submission with file upload support
async function submitForm(formElement) {
    const formData = new FormData(formElement);
    const token = 'YOUR_FORM_TOKEN';
    
    try {
        const response = await fetch(`/api/inbox/submit/${token}`, {
            method: 'POST',
            body: formData
        });
        
        const result = await response.json();
        
        if (response.ok && result.success) {
            showSuccessMessage('Thank you! Your message has been sent.');
            formElement.reset();
        } else {
            showErrorMessage(result.error || 'Something went wrong. Please try again.');
        }
    } catch (error) {
        showErrorMessage('Network error. Please check your connection.');
    }
}

// Enhanced form with validation
document.getElementById('contact-form').addEventListener('submit', async function(e) {
    e.preventDefault();
    
    // Client-side validation
    const name = this.querySelector('[name="data[name]"]').value;
    const email = this.querySelector('[name="data[email]"]').value;
    const message = this.querySelector('[name="data[message]"]').value;
    
    if (!name || !email || !message) {
        showErrorMessage('Please fill in all required fields.');
        return;
    }
    
    if (!isValidEmail(email)) {
        showErrorMessage('Please enter a valid email address.');
        return;
    }
    
    // Show loading state
    const submitBtn = this.querySelector('button[type="submit"]');
    const originalText = submitBtn.textContent;
    submitBtn.textContent = 'Sending...';
    submitBtn.disabled = true;
    
    await submitForm(this);
    
    // Reset button state
    submitBtn.textContent = originalText;
    submitBtn.disabled = false;
});

function isValidEmail(email) {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function showSuccessMessage(message) {
    // Your success message implementation
    alert(message); // Replace with better UI
}

function showErrorMessage(message) {
    // Your error message implementation  
    alert(message); // Replace with better UI
}
```

## 🔒 Security Features

### Domain Restrictions

Limit form submissions to specific domains to prevent abuse:

```php
// Form security configuration
'security' => [
    'domains' => [
        'yourwebsite.com',
        'www.yourwebsite.com',
        'subdomain.yourwebsite.com'
    ]
]
```

### Honeypot Protection

Add invisible fields to catch bots:

```html
<!-- Add to your form (hidden from users) -->
<input type="text" name="data[url]" style="display:none; visibility:hidden; position:absolute; left:-9999px;" tabindex="-1" autocomplete="off">
```

```php
// Configure honeypot in form settings
'security' => [
    'honeypot' => 'url'  // Field name to check
]
```

### Language Detection

Filter submissions by detected language:

```php
// Only accept English, Spanish, and French content
'security' => [
    'languages' => ['en', 'es', 'fr']
]
```

**Supported Languages:**
```
Amharic (am), Arabic (ar), Azerbaijani (az), Belarusian (be), Bulgarian (bg),
Bengali (bn), Catalan (ca), Czech (cs), Danish (da), German (de), Greek (el),
English (en), Spanish (es), Estonian (et), Basque (eu), Persian (fa),
Finnish (fi), French (fr), Gujarati (gu), Hebrew (he), Hindi (hi),
Croatian (hr), Hungarian (hu), Armenian (hy), Icelandic (is), Italian (it),
Japanese (ja), Georgian (ka), Kannada (kn), Korean (ko), Kurdish (ku),
Lao (lo), Lithuanian (lt), Latvian (lv), Malayalam (ml), Marathi (mr),
Malay (ms), Dutch (nl), Norwegian (no), Oriya (or), Punjabi (pa),
Polish (pl), Portuguese (pt), Romanian (ro), Russian (ru), Slovak (sk),
Slovenian (sl), Albanian (sq), Serbian (sr), Swedish (sv), Tamil (ta),
Telugu (te), Thai (th), Filipino (tl), Turkish (tr), Ukrainian (uk),
Urdu (ur), Vietnamese (vi), Yoruba (yo), Chinese (zh)
```

### File Upload Security

Automatic protection against dangerous file types:

```php
// Blocked file extensions (automatic)
$forbidden = ['bat', 'exe', 'sh', 'php', 'phar', 'phtml', 'phps', 'htm', 'html', 'xhtml', 'htaccess'];

// Blocked MIME types (automatic)
$forbiddenMime = [
    'application/x-httpd-php', 'application/x-php', 'text/x-php',
    'text/html', 'application/xhtml+xml'
];
```

## 📧 Email Templates

### Custom Email Template

Create a custom email template at `config/inbox/layouts/email.php`:

```php
<?php
// config/inbox/layouts/email.php
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>New Form Submission</title>
    <style>
        body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
        .container { max-width: 600px; margin: 0 auto; padding: 20px; }
        .header { background: #3498db; color: white; padding: 20px; text-align: center; }
        .content { padding: 20px; background: #f9f9f9; }
        .field { margin: 10px 0; }
        .label { font-weight: bold; color: #2c3e50; }
        .value { margin-left: 10px; }
        .attachments { margin-top: 20px; }
        .footer { background: #34495e; color: white; padding: 10px; text-align: center; font-size: 12px; }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>New Submission: <?= $form['name'] ?></h1>
            <p>Received: <?= date('F j, Y g:i A') ?></p>
        </div>
        
        <div class="content">
            <h2>Submission Details</h2>
            
            <?php foreach ($data as $field => $value): ?>
                <?php if ($value): ?>
                    <div class="field">
                        <span class="label"><?= ucfirst(str_replace('_', ' ', $field)) ?>:</span>
                        <span class="value"><?= is_array($value) ? implode(', ', $value) : htmlspecialchars($value) ?></span>
                    </div>
                <?php endif ?>
            <?php endforeach ?>
            
            <?php if ($attachments): ?>
                <div class="attachments">
                    <h3>Attachments</h3>
                    <?php foreach ($attachments as $field => $files): ?>
                        <div class="field">
                            <span class="label"><?= ucfirst(str_replace('_', ' ', $field)) ?>:</span>
                            <ul>
                                <?php foreach ($files as $file): ?>
                                    <li><?= htmlspecialchars($file['name']) ?></li>
                                <?php endforeach ?>
                            </ul>
                        </div>
                    <?php endforeach ?>
                </div>
            <?php endif ?>
        </div>
        
        <div class="footer">
            <p>This email was generated automatically by your website's contact form.</p>
        </div>
    </div>
</body>
</html>
```

## 🎨 Frontend Integration

### Vue.js Component

```vue
<template>
    <form @submit.prevent="submitForm" class="contact-form">
        <div class="form-group">
            <label for="name">Name *</label>
            <input 
                type="text" 
                id="name" 
                v-model="form.name" 
                required
                :disabled="submitting"
            >
        </div>
        
        <div class="form-group">
            <label for="email">Email *</label>
            <input 
                type="email" 
                id="email" 
                v-model="form.email" 
                required
                :disabled="submitting"
            >
        </div>
        
        <div class="form-group">
            <label for="phone">Phone</label>
            <input 
                type="tel" 
                id="phone" 
                v-model="form.phone"
                :disabled="submitting"
            >
        </div>
        
        <div class="form-group">
            <label for="message">Message *</label>
            <textarea 
                id="message" 
                v-model="form.message" 
                required
                :disabled="submitting"
                rows="5"
            ></textarea>
        </div>
        
        <div class="form-group">
            <label for="attachment">Attachment</label>
            <input 
                type="file" 
                id="attachment" 
                @change="handleFileUpload"
                accept=".pdf,.doc,.docx,.jpg,.jpeg,.png"
                :disabled="submitting"
            >
        </div>
        
        <!-- Honeypot -->
        <input type="text" v-model="form.url" style="display:none" tabindex="-1">
        
        <button type="submit" :disabled="submitting" class="submit-btn">
            {{ submitting ? 'Sending...' : 'Send Message' }}
        </button>
        
        <div v-if="message" :class="messageClass" class="form-message">
            {{ message }}
        </div>
    </form>
</template>

<script>
export default {
    name: 'ContactForm',
    props: {
        formToken: {
            type: String,
            required: true
        }
    },
    data() {
        return {
            form: {
                name: '',
                email: '',
                phone: '',
                message: '',
                url: '', // Honeypot
                attachment: null
            },
            submitting: false,
            message: '',
            messageType: 'success'
        }
    },
    computed: {
        messageClass() {
            return `message-${this.messageType}`;
        }
    },
    methods: {
        handleFileUpload(event) {
            this.form.attachment = event.target.files[0];
        },
        
        async submitForm() {
            this.submitting = true;
            this.message = '';
            
            try {
                const formData = new FormData();
                
                // Add form data
                Object.keys(this.form).forEach(key => {
                    if (key === 'attachment' && this.form[key]) {
                        formData.append(`data[${key}]`, this.form[key]);
                    } else if (key !== 'attachment') {
                        formData.append(`data[${key}]`, this.form[key]);
                    }
                });
                
                const response = await fetch(`/api/inbox/submit/${this.formToken}`, {
                    method: 'POST',
                    body: formData
                });
                
                const result = await response.json();
                
                if (response.ok && result.success) {
                    this.message = 'Thank you! Your message has been sent successfully.';
                    this.messageType = 'success';
                    this.resetForm();
                } else {
                    this.message = result.error || 'Something went wrong. Please try again.';
                    this.messageType = 'error';
                }
            } catch (error) {
                this.message = 'Network error. Please check your connection and try again.';
                this.messageType = 'error';
            } finally {
                this.submitting = false;
            }
        },
        
        resetForm() {
            this.form = {
                name: '',
                email: '',
                phone: '',
                message: '',
                url: '',
                attachment: null
            };
            
            // Reset file input
            const fileInput = this.$el.querySelector('input[type="file"]');
            if (fileInput) {
                fileInput.value = '';
            }
        }
    }
}
</script>

<style scoped>
.contact-form {
    max-width: 500px;
    margin: 0 auto;
}

.form-group {
    margin-bottom: 20px;
}

label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
    color: #2c3e50;
}

input, textarea, select {
    width: 100%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 14px;
}

input:focus, textarea:focus, select:focus {
    outline: none;
    border-color: #3498db;
    box-shadow: 0 0 5px rgba(52, 152, 219, 0.3);
}

.submit-btn {
    background: #3498db;
    color: white;
    padding: 12px 30px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 16px;
    width: 100%;
}

.submit-btn:hover:not(:disabled) {
    background: #2980b9;
}

.submit-btn:disabled {
    background: #bdc3c7;
    cursor: not-allowed;
}

.form-message {
    margin-top: 15px;
    padding: 10px;
    border-radius: 4px;
}

.message-success {
    background: #d4edda;
    color: #155724;
    border: 1px solid #c3e6cb;
}

.message-error {
    background: #f8d7da;
    color: #721c24;
    border: 1px solid #f5c6cb;
}
</style>
```

### React Component

```jsx
import React, { useState } from 'react';

const ContactForm = ({ formToken }) => {
    const [form, setForm] = useState({
        name: '',
        email: '',
        phone: '',
        message: '',
        url: '', // Honeypot
        attachment: null
    });
    
    const [submitting, setSubmitting] = useState(false);
    const [message, setMessage] = useState('');
    const [messageType, setMessageType] = useState('success');
    
    const handleInputChange = (e) => {
        const { name, value, type, files } = e.target;
        setForm(prev => ({
            ...prev,
            [name]: type === 'file' ? files[0] : value
        }));
    };
    
    const submitForm = async (e) => {
        e.preventDefault();
        setSubmitting(true);
        setMessage('');
        
        try {
            const formData = new FormData();
            
            Object.keys(form).forEach(key => {
                if (key === 'attachment' && form[key]) {
                    formData.append(`data[${key}]`, form[key]);
                } else if (key !== 'attachment') {
                    formData.append(`data[${key}]`, form[key]);
                }
            });
            
            const response = await fetch(`/api/inbox/submit/${formToken}`, {
                method: 'POST',
                body: formData
            });
            
            const result = await response.json();
            
            if (response.ok && result.success) {
                setMessage('Thank you! Your message has been sent successfully.');
                setMessageType('success');
                setForm({
                    name: '',
                    email: '',
                    phone: '',
                    message: '',
                    url: '',
                    attachment: null
                });
            } else {
                setMessage(result.error || 'Something went wrong. Please try again.');
                setMessageType('error');
            }
        } catch (error) {
            setMessage('Network error. Please check your connection and try again.');
            setMessageType('error');
        } finally {
            setSubmitting(false);
        }
    };
    
    return (
        <form onSubmit={submitForm} className="contact-form">
            <div className="form-group">
                <label htmlFor="name">Name *</label>
                <input
                    type="text"
                    id="name"
                    name="name"
                    value={form.name}
                    onChange={handleInputChange}
                    required
                    disabled={submitting}
                />
            </div>
            
            <div className="form-group">
                <label htmlFor="email">Email *</label>
                <input
                    type="email"
                    id="email"
                    name="email"
                    value={form.email}
                    onChange={handleInputChange}
                    required
                    disabled={submitting}
                />
            </div>
            
            <div className="form-group">
                <label htmlFor="phone">Phone</label>
                <input
                    type="tel"
                    id="phone"
                    name="phone"
                    value={form.phone}
                    onChange={handleInputChange}
                    disabled={submitting}
                />
            </div>
            
            <div className="form-group">
                <label htmlFor="message">Message *</label>
                <textarea
                    id="message"
                    name="message"
                    value={form.message}
                    onChange={handleInputChange}
                    required
                    disabled={submitting}
                    rows="5"
                />
            </div>
            
            <div className="form-group">
                <label htmlFor="attachment">Attachment</label>
                <input
                    type="file"
                    id="attachment"
                    name="attachment"
                    onChange={handleInputChange}
                    accept=".pdf,.doc,.docx,.jpg,.jpeg,.png"
                    disabled={submitting}
                />
            </div>
            
            {/* Honeypot */}
            <input
                type="text"
                name="url"
                value={form.url}
                onChange={handleInputChange}
                style={{ display: 'none' }}
                tabIndex="-1"
            />
            
            <button type="submit" disabled={submitting} className="submit-btn">
                {submitting ? 'Sending...' : 'Send Message'}
            </button>
            
            {message && (
                <div className={`form-message message-${messageType}`}>
                    {message}
                </div>
            )}
        </form>
    );
};

export default ContactForm;
```

## 🔧 Advanced Features

### Webhook Integration

Set up webhooks to integrate with external services when forms are submitted:

```php
// Add to your theme or addon
$this->on('inbox.submit.after', function($form, $record) {
    
    // Send to CRM
    if ($form['name'] === 'Lead Generation Form') {
        $this->sendToCRM($record['data']);
    }
    
    // Send to Slack
    if ($form['group'] === 'Support') {
        $this->notifySlack($form, $record);
    }
    
    // Analytics tracking
    $this->trackConversion($form['name'], $record);
});

function sendToCRM($data) {
    // Your CRM integration
    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => 'https://api.yourcrm.com/leads',
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($data),
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Authorization: Bearer YOUR_API_KEY'
        ]
    ]);
    curl_exec($curl);
    curl_close($curl);
}
```

### Custom Success Pages

Redirect users to custom thank you pages:

```html
<form action="/api/inbox/submit/YOUR_TOKEN?success=/thank-you" method="POST">
    <!-- Your form fields -->
</form>
```

### Progressive Enhancement

Enhance forms with JavaScript while maintaining functionality without it:

```html
<form action="/api/inbox/submit/YOUR_TOKEN?success=/thank-you" method="POST" class="progressive-form">
    <input type="text" name="data[name]" placeholder="Name" required>
    <input type="email" name="data[email]" placeholder="Email" required>
    <textarea name="data[message]" placeholder="Message" required></textarea>
    <button type="submit">Send Message</button>
    
    <div class="form-status" style="display:none">
        <div class="success-message">Thank you! Your message has been sent.</div>
        <div class="error-message">Something went wrong. Please try again.</div>
    </div>
</form>

<script>
// Progressive enhancement
document.querySelectorAll('.progressive-form').forEach(form => {
    form.addEventListener('submit', async function(e) {
        e.preventDefault();
        
        const formData = new FormData(this);
        const action = this.action.split('?')[0]; // Remove success redirect
        
        try {
            const response = await fetch(action, {
                method: 'POST',
                body: formData
            });
            
            const result = await response.json();
            
            if (response.ok && result.success) {
                this.style.display = 'none';
                this.nextElementSibling.querySelector('.success-message').style.display = 'block';
            } else {
                this.nextElementSibling.querySelector('.error-message').style.display = 'block';
                this.nextElementSibling.querySelector('.error-message').textContent = 
                    result.error || 'Something went wrong. Please try again.';
            }
        } catch (error) {
            // Fall back to regular form submission
            this.submit();
        }
    });
});
</script>
```

## 📊 Submission Management

### Bulk Operations

```javascript
// Admin interface: Bulk delete submissions
async function bulkDeleteSubmissions(formId, submissionIds) {
    const response = await fetch(`/inbox/submissions/remove/${formId}`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
        },
        body: JSON.stringify({ ids: submissionIds })
    });
    
    return response.json();
}
```

### Export Submissions

```php
// Export submissions to CSV
public function exportSubmissions($formId) {
    $form = $this->app->dataStorage->findOne('inbox/forms', ['_id' => $formId]);
    $submissions = $this->app->dataStorage->find("inbox/form_{$formId}")->toArray();
    
    $filename = "submissions-{$form['name']}-" . date('Y-m-d') . '.csv';
    
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename="' . $filename . '"');
    
    $output = fopen('php://output', 'w');
    
    // Headers
    if (!empty($submissions)) {
        $headers = array_keys($submissions[0]['data']);
        fputcsv($output, array_merge(['Submitted'], $headers));
        
        // Data
        foreach ($submissions as $submission) {
            $row = [date('Y-m-d H:i:s', $submission['_created'])];
            foreach ($headers as $header) {
                $row[] = $submission['data'][$header] ?? '';
            }
            fputcsv($output, $row);
        }
    }
    
    fclose($output);
}
```

## 🔧 Troubleshooting

### Common Issues

**❌ "Form not found" Error**
- Verify the form token is correct
- Check that the form is active (`_state = 1`)
- Ensure the form exists in the database

**❌ "Not allowed" Domain Error**
- Check domain restrictions in form security settings
- Verify the referrer/origin header matches allowed domains
- Test from the correct domain

**❌ File Upload Failures**
- Check file size limits in PHP configuration
- Verify file types are not in the forbidden list
- Ensure proper `enctype="multipart/form-data"` on form

**❌ Language Detection Issues**
- Ensure content is at least 50 characters for reliable detection
- Check that detected language is in the allowed list
- Install the required language detection package

### Debug Mode

Enable debug logging to troubleshoot submission issues:

```php
// Enable debug mode in config/config.php
'debug' => true,

// Check logs in storage/logs/ directory
// Look for entries with channel 'inbox'
```

### Testing Forms

Test your forms with curl (note the `data[fieldname]` structure):

```bash
# Basic form submission
curl -X POST "https://yoursite.com/api/inbox/submit/YOUR_TOKEN" \
  -d "data[name]=Test User" \
  -d "data[email]=test@example.com" \
  -d "data[message]=Test message"

# File upload test (using -F for multipart/form-data)
curl -X POST "https://yoursite.com/api/inbox/submit/YOUR_TOKEN" \
  -F "data[name]=Test User" \
  -F "data[email]=test@example.com" \
  -F "data[message]=Test message" \
  -F "data[attachment]=@/path/to/test-file.pdf"

# JSON submission (alternative method)
curl -X POST "https://yoursite.com/api/inbox/submit/YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "name": "Test User",
      "email": "test@example.com", 
      "message": "Test message"
    }
  }'
```

## 📄 License

This is a commercial addon for Cockpit CMS. See [LICENSE.md](LICENSE.md) for full terms.

## 🙏 Credits

Inbox is developed by [Agentejo](https://agentejo.com) as part of the Cockpit CMS Pro ecosystem.

---

**Ready to capture leads and manage submissions?** Set up Inbox and start collecting form data with enterprise-grade security today!