# Plan Management with Features Documentation

## 🚀 Plan CRUD Operations

Your backend now supports full plan management including features editing. Here's what's available:

## 📋 API Endpoints

### **1. Get All Plans**
```
GET /api/get-plans
```

### **2. Get Single Plan**
```
GET /api/plans/{id}
```

### **3. Create Plan**
```
POST /api/plans
```

### **4. Update Plan**
```
PUT /api/plans/{id}
```

### **5. Delete Plan**
```
DELETE /api/plans/{id}
```

## 📝 Plan Data Structure

### **Request/Response Format:**
```json
{
  "name": "Pro Plan",
  "description": "Professional plan for teams",
  "price": 29.99,
  "currency": "USD",
  "features": [
    "Unlimited presentations",
    "Advanced analytics",
    "Priority support",
    "Custom branding"
  ],
  "max_presentations": 100,
  "max_slides_per_presentation": 50
}
```

### **Field Descriptions:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | ✅ | Plan name |
| `description` | string | ✅ | Plan description |
| `price` | decimal | ✅ | Monthly price |
| `currency` | string | ✅ | 3-letter currency code |
| `features` | array | ❌ | List of plan features |
| `max_presentations` | integer | ❌ | Max presentations (null = unlimited) |
| `max_slides_per_presentation` | integer | ❌ | Max slides per presentation |

## 🎯 Features Field

### **How it Works:**
- **Type**: JSON array stored as text
- **Format**: Array of strings
- **Validation**: Each feature max 255 characters
- **Nullable**: Can be empty or null

### **Example Features:**
```json
{
  "features": [
    "Unlimited presentations",
    "Advanced analytics dashboard",
    "Priority email support",
    "Custom branding options",
    "API access",
    "White-label solutions",
    "Dedicated account manager",
    "99.9% uptime SLA"
  ]
}
```

### **Empty Features:**
```json
{
  "features": []
}
```

## 📱 Frontend Integration

### **JavaScript Example:**
```javascript
class PlanManager {
  // Get all plans
  async getAllPlans() {
    try {
      const response = await fetch('/api/get-plans');
      const data = await response.json();
      return data.data;
    } catch (error) {
      console.error('Failed to fetch plans:', error);
      throw error;
    }
  }

  // Get single plan
  async getPlan(id) {
    try {
      const response = await fetch(`/api/plans/${id}`);
      const data = await response.json();
      
      if (!response.ok) {
        throw new Error(data.message || 'Failed to get plan');
      }
      
      return data.data;
    } catch (error) {
      console.error('Failed to get plan:', error);
      throw error;
    }
  }

  // Create plan
  async createPlan(planData) {
    try {
      const response = await fetch('/api/plans', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(planData)
      });

      const data = await response.json();
      
      if (!response.ok) {
        if (data.errors) {
          throw new Error(this.formatValidationErrors(data.errors));
        }
        throw new Error(data.message || 'Failed to create plan');
      }
      
      return data.data;
    } catch (error) {
      console.error('Failed to create plan:', error);
      throw error;
    }
  }

  // Update plan
  async updatePlan(id, planData) {
    try {
      const response = await fetch(`/api/plans/${id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(planData)
      });

      const data = await response.json();
      
      if (!response.ok) {
        if (data.errors) {
          throw new Error(this.formatValidationErrors(data.errors));
        }
        throw new Error(data.message || 'Failed to update plan');
      }
      
      return data.data;
    } catch (error) {
      console.error('Failed to update plan:', error);
      throw error;
    }
  }

  // Delete plan
  async deletePlan(id) {
    try {
      const response = await fetch(`/api/plans/${id}`, {
        method: 'DELETE'
      });

      const data = await response.json();
      
      if (!response.ok) {
        throw new Error(data.message || 'Failed to delete plan');
      }
      
      return true;
    } catch (error) {
      console.error('Failed to delete plan:', error);
      throw error;
    }
  }

  // Format validation errors
  formatValidationErrors(errors) {
    return Object.values(errors).flat().join(', ');
  }
}
```

### **React Component Example:**
```javascript
import React, { useState, useEffect } from 'react';

function PlanEditor({ planId, onSave, onCancel }) {
  const [plan, setPlan] = useState({
    name: '',
    description: '',
    price: 0,
    currency: 'USD',
    features: [],
    max_presentations: null,
    max_slides_per_presentation: null
  });
  const [loading, setLoading] = useState(false);
  const [errors, setErrors] = useState({});

  useEffect(() => {
    if (planId) {
      loadPlan();
    }
  }, [planId]);

  const loadPlan = async () => {
    try {
      const planData = await new PlanManager().getPlan(planId);
      setPlan(planData);
    } catch (error) {
      console.error('Failed to load plan:', error);
    }
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);
    setErrors({});

    try {
      const manager = new PlanManager();
      let savedPlan;
      
      if (planId) {
        savedPlan = await manager.updatePlan(planId, plan);
      } else {
        savedPlan = await manager.createPlan(plan);
      }
      
      onSave(savedPlan);
    } catch (error) {
      setErrors({ general: error.message });
    } finally {
      setLoading(false);
    }
  };

  const addFeature = () => {
    setPlan({
      ...plan,
      features: [...plan.features, '']
    });
  };

  const updateFeature = (index, value) => {
    const newFeatures = [...plan.features];
    newFeatures[index] = value;
    setPlan({ ...plan, features: newFeatures });
  };

  const removeFeature = (index) => {
    const newFeatures = plan.features.filter((_, i) => i !== index);
    setPlan({ ...plan, features: newFeatures });
  };

  return (
    <form onSubmit={handleSubmit} className="plan-editor">
      <div className="form-group">
        <label>Plan Name</label>
        <input
          type="text"
          value={plan.name}
          onChange={(e) => setPlan({ ...plan, name: e.target.value })}
          required
        />
      </div>

      <div className="form-group">
        <label>Description</label>
        <textarea
          value={plan.description}
          onChange={(e) => setPlan({ ...plan, description: e.target.value })}
          required
        />
      </div>

      <div className="form-row">
        <div className="form-group">
          <label>Price</label>
          <input
            type="number"
            step="0.01"
            min="0"
            value={plan.price}
            onChange={(e) => setPlan({ ...plan, price: parseFloat(e.target.value) })}
            required
          />
        </div>

        <div className="form-group">
          <label>Currency</label>
          <input
            type="text"
            maxLength="3"
            value={plan.currency}
            onChange={(e) => setPlan({ ...plan, currency: e.target.value.toUpperCase() })}
            required
          />
        </div>
      </div>

      <div className="form-group">
        <label>Features</label>
        {plan.features.map((feature, index) => (
          <div key={index} className="feature-input-group">
            <input
              type="text"
              value={feature}
              onChange={(e) => updateFeature(index, e.target.value)}
              placeholder="Enter feature"
              maxLength="255"
            />
            <button
              type="button"
              onClick={() => removeFeature(index)}
              className="btn-remove"
            >
              Remove
            </button>
          </div>
        ))}
        <button
          type="button"
          onClick={addFeature}
          className="btn-add-feature"
        >
          Add Feature
        </button>
      </div>

      <div className="form-row">
        <div className="form-group">
          <label>Max Presentations</label>
          <input
            type="number"
            min="1"
            value={plan.max_presentations || ''}
            onChange={(e) => setPlan({ 
              ...plan, 
              max_presentations: e.target.value ? parseInt(e.target.value) : null 
            })}
            placeholder="Unlimited if empty"
          />
        </div>

        <div className="form-group">
          <label>Max Slides per Presentation</label>
          <input
            type="number"
            min="1"
            value={plan.max_slides_per_presentation || ''}
            onChange={(e) => setPlan({ 
              ...plan, 
              max_slides_per_presentation: e.target.value ? parseInt(e.target.value) : null 
            })}
            placeholder="Unlimited if empty"
          />
        </div>
      </div>

      {errors.general && (
        <div className="error-message">{errors.general}</div>
      )}

      <div className="form-actions">
        <button type="submit" disabled={loading}>
          {loading ? 'Saving...' : (planId ? 'Update Plan' : 'Create Plan')}
        </button>
        <button type="button" onClick={onCancel}>
          Cancel
        </button>
      </div>
    </form>
  );
}
```

## 🎨 UI Components

### **Features Text Area Component:**
```javascript
function FeaturesEditor({ features, onChange }) {
  const addFeature = () => {
    onChange([...features, '']);
  };

  const updateFeature = (index, value) => {
    const newFeatures = [...features];
    newFeatures[index] = value;
    onChange(newFeatures);
  };

  const removeFeature = (index) => {
    onChange(features.filter((_, i) => i !== index));
  };

  return (
    <div className="features-editor">
      <label>Plan Features</label>
      {features.map((feature, index) => (
        <div key={index} className="feature-row">
          <input
            type="text"
            value={feature}
            onChange={(e) => updateFeature(index, e.target.value)}
            placeholder="Enter a feature"
            className="feature-input"
          />
          <button
            type="button"
            onClick={() => removeFeature(index)}
            className="btn-remove-feature"
          >
            ×
          </button>
        </div>
      ))}
      <button
        type="button"
        onClick={addFeature}
        className="btn-add-feature"
      >
        + Add Feature
      </button>
    </div>
  );
}
```

### **CSS Styling:**
```css
.features-editor {
  border: 1px solid #ddd;
  padding: 15px;
  border-radius: 5px;
  background: #f9f9f9;
}

.feature-row {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}

.feature-input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 3px;
  margin-right: 10px;
}

.btn-remove-feature {
  background: #dc3545;
  color: white;
  border: none;
  border-radius: 3px;
  padding: 5px 10px;
  cursor: pointer;
}

.btn-add-feature {
  background: #28a745;
  color: white;
  border: none;
  border-radius: 3px;
  padding: 8px 15px;
  cursor: pointer;
  margin-top: 10px;
}
```

## 🧪 Testing

### **Test Scenarios Covered:**
- ✅ Create plan with features
- ✅ Update plan features
- ✅ Create plan without features
- ✅ Validation for invalid data
- ✅ Get single plan
- ✅ Delete plan (without subscriptions)
- ✅ Features stored as array

### **Run Tests:**
```bash
php artisan test tests/Feature/PlanManagementTest.php
```

## 🎯 Best Practices

### **Frontend:**
1. **Validate features length** (max 255 chars each)
2. **Show feature count** to users
3. **Allow drag-and-drop reordering** of features
4. **Provide feature templates** for common features

### **Backend:**
1. **Validate features array** properly
2. **Handle empty features** gracefully
3. **Sanitize feature text** if needed
4. **Use proper HTTP status codes**

### **User Experience:**
1. **Auto-save** draft features
2. **Feature suggestions** based on other plans
3. **Preview** how features will display
4. **Bulk import** features from text

Your plan management now supports full features editing! 🚀
