> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rocky.global/llms.txt
> Use this file to discover all available pages before exploring further.

# FRONTEND DOCUMENTATION

# Frontend Components & JavaScript API Documentation

## Table of Contents

1. [Overview](#overview)
2. [JavaScript Dependencies](#javascript-dependencies)
3. [UI Components](#ui-components)
4. [DataTables Integration](#datatables-integration)
5. [AJAX Patterns](#ajax-patterns)
6. [Form Handling](#form-handling)
7. [File Upload Components](#file-upload-components)
8. [Notification System](#notification-system)
9. [Payment Integration](#payment-integration)
10. [Responsive Design](#responsive-design)

## Overview

The frontend of the event management system is built using modern web technologies with a focus on user experience and performance. The system uses jQuery for DOM manipulation, Bootstrap for responsive design, and various specialized libraries for enhanced functionality.

## JavaScript Dependencies

### Core Libraries

#### jQuery (v3.7.1)

Primary JavaScript library for DOM manipulation and AJAX requests.

```javascript theme={null}
// Basic jQuery usage
$(document).ready(function() {
    // DOM ready code
});

// AJAX requests
$.ajax({
    url: '/api/eventos',
    method: 'GET',
    success: function(data) {
        console.log(data);
    }
});
```

#### Bootstrap (v5.3.2)

CSS framework for responsive design and UI components.

```html theme={null}
<!-- Bootstrap components -->
<div class="container">
    <div class="row">
        <div class="col-md-6">
            <div class="card">
                <div class="card-body">
                    <h5 class="card-title">Event Title</h5>
                    <p class="card-text">Event description</p>
                </div>
            </div>
        </div>
    </div>
</div>
```

### Data Management Libraries

#### DataTables (v1.13.8)

Advanced table functionality with sorting, filtering, and pagination.

```javascript theme={null}
// Initialize DataTable
$('#events-table').DataTable({
    processing: true,
    serverSide: true,
    ajax: {
        url: '/api/eventos',
        data: function(d) {
            d.search = $('#search-input').val();
            d.category = $('#category-filter').val();
        }
    },
    columns: [
        { data: 'name', title: 'Event Name' },
        { data: 'date_from_format', title: 'Start Date' },
        { data: 'participants', title: 'Participants' },
        { 
            data: null,
            title: 'Actions',
            render: function(data, type, row) {
                return `
                    <button class="btn btn-sm btn-primary edit-event" data-id="${row.id}">
                        Edit
                    </button>
                    <button class="btn btn-sm btn-danger delete-event" data-id="${row.id}">
                        Delete
                    </button>
                `;
            }
        }
    ],
    order: [[1, 'desc']],
    pageLength: 25,
    responsive: true
});
```

#### Tabulator (v5.5.2)

Advanced table library with additional features.

```javascript theme={null}
// Initialize Tabulator
var table = new Tabulator("#events-table", {
    ajaxURL: "/api/eventos",
    layout: "fitColumns",
    pagination: true,
    paginationSize: 25,
    columns: [
        {title: "Name", field: "name", sorter: "string"},
        {title: "Date", field: "date_from", sorter: "date"},
        {title: "Participants", field: "participants", sorter: "number"},
        {
            title: "Actions",
            formatter: function(cell, formatterParams) {
                var row = cell.getRow();
                var data = row.getData();
                return `
                    <button class="btn btn-sm btn-primary" onclick="editEvent(${data.id})">
                        Edit
                    </button>
                `;
            }
        }
    ]
});
```

### UI Enhancement Libraries

#### Swiper (v11.2.6)

Touch slider for carousels and galleries.

```javascript theme={null}
// Initialize Swiper
const swiper = new Swiper('.swiper-container', {
    slidesPerView: 1,
    spaceBetween: 30,
    loop: true,
    pagination: {
        el: '.swiper-pagination',
        clickable: true,
    },
    navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
    },
    breakpoints: {
        768: {
            slidesPerView: 2,
        },
        1024: {
            slidesPerView: 3,
        }
    }
});
```

#### Toastr (v2.1.4)

Notification system for user feedback.

```javascript theme={null}
// Success notification
toastr.success('Event created successfully!', 'Success');

// Error notification
toastr.error('Failed to create event', 'Error');

// Warning notification
toastr.warning('Please check your input', 'Warning');

// Info notification
toastr.info('Processing your request...', 'Info');

// Configure toastr options
toastr.options = {
    closeButton: true,
    progressBar: true,
    positionClass: "toast-top-right",
    timeOut: 5000
};
```

### Utility Libraries

#### Moment.js (v2.30.1)

Date and time manipulation library.

```javascript theme={null}
// Format dates
moment().format('YYYY-MM-DD HH:mm:ss');
moment(event.date_from).format('MMMM Do YYYY');

// Date calculations
moment().add(7, 'days');
moment(event.date_from).diff(moment(), 'days');

// Timezone handling
moment.tz(event.date_from, event.timezone).format('YYYY-MM-DD HH:mm:ss');
```

#### Lodash (v4.17.19)

Utility library for common JavaScript operations.

```javascript theme={null}
// Array operations
_.filter(events, { status: 'active' });
_.map(events, 'name');
_.groupBy(events, 'category');

// Object operations
_.pick(event, ['name', 'date_from', 'participants']);
_.omit(event, ['created_at', 'updated_at']);
```

## UI Components

### Modal Components

#### Event Creation Modal

```html theme={null}
<div class="modal fade" id="createEventModal" tabindex="-1">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Create New Event</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body">
                <form id="createEventForm">
                    <div class="row">
                        <div class="col-md-6">
                            <div class="mb-3">
                                <label class="form-label">Event Name</label>
                                <input type="text" class="form-control" name="name" required>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="mb-3">
                                <label class="form-label">Category</label>
                                <select class="form-select" name="category" required>
                                    <option value="">Select Category</option>
                                </select>
                            </div>
                        </div>
                    </div>
                    <!-- More form fields -->
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                <button type="button" class="btn btn-primary" id="saveEvent">Save Event</button>
            </div>
        </div>
    </div>
</div>
```

#### Confirmation Modal

```html theme={null}
<div class="modal fade" id="confirmModal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Confirm Action</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body">
                <p id="confirmMessage">Are you sure you want to perform this action?</p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                <button type="button" class="btn btn-danger" id="confirmAction">Confirm</button>
            </div>
        </div>
    </div>
</div>
```

### Form Components

#### Dynamic Form Builder

```javascript theme={null}
class FormBuilder {
    constructor(container, fields) {
        this.container = container;
        this.fields = fields;
        this.init();
    }

    init() {
        this.fields.forEach(field => {
            this.createField(field);
        });
    }

    createField(field) {
        const fieldElement = this.createFieldElement(field);
        this.container.appendChild(fieldElement);
    }

    createFieldElement(field) {
        const wrapper = document.createElement('div');
        wrapper.className = 'mb-3';

        const label = document.createElement('label');
        label.className = 'form-label';
        label.textContent = field.label;
        if (field.required) {
            label.innerHTML += ' <span class="text-danger">*</span>';
        }

        const input = this.createInput(field);
        
        wrapper.appendChild(label);
        wrapper.appendChild(input);
        return wrapper;
    }

    createInput(field) {
        switch (field.type) {
            case 'text':
            case 'email':
            case 'number':
                return this.createTextInput(field);
            case 'select':
                return this.createSelectInput(field);
            case 'textarea':
                return this.createTextareaInput(field);
            case 'checkbox':
                return this.createCheckboxInput(field);
            case 'radio':
                return this.createRadioInput(field);
            default:
                return this.createTextInput(field);
        }
    }

    createTextInput(field) {
        const input = document.createElement('input');
        input.type = field.type || 'text';
        input.className = 'form-control';
        input.name = field.name;
        input.required = field.required || false;
        
        if (field.placeholder) {
            input.placeholder = field.placeholder;
        }
        
        return input;
    }

    createSelectInput(field) {
        const select = document.createElement('select');
        select.className = 'form-select';
        select.name = field.name;
        select.required = field.required || false;

        if (field.options) {
            field.options.forEach(option => {
                const optionElement = document.createElement('option');
                optionElement.value = option.value;
                optionElement.textContent = option.label;
                select.appendChild(optionElement);
            });
        }

        return select;
    }

    getFormData() {
        const formData = new FormData();
        const inputs = this.container.querySelectorAll('input, select, textarea');
        
        inputs.forEach(input => {
            if (input.type === 'checkbox') {
                formData.append(input.name, input.checked);
            } else {
                formData.append(input.name, input.value);
            }
        });

        return formData;
    }
}
```

## DataTables Integration

### Server-Side Processing

```javascript theme={null}
// Advanced DataTable with server-side processing
$('#events-table').DataTable({
    processing: true,
    serverSide: true,
    ajax: {
        url: '/api/eventos',
        type: 'GET',
        data: function(d) {
            // Add custom filters
            d.search = $('#search-input').val();
            d.category = $('#category-filter').val();
            d.status = $('#status-filter').val();
            d.date_from = $('#date-from-filter').val();
            d.date_to = $('#date-to-filter').val();
        },
        dataSrc: function(json) {
            return json.data || [];
        }
    },
    columns: [
        { 
            data: 'name',
            render: function(data, type, row) {
                if (type === 'display') {
                    return `<a href="/eventos/${row.id}" class="text-decoration-none">${data}</a>`;
                }
                return data;
            }
        },
        { 
            data: 'date_from',
            render: function(data, type, row) {
                if (type === 'display') {
                    return moment(data).format('DD/MM/YYYY HH:mm');
                }
                return data;
            }
        },
        { 
            data: 'participants',
            className: 'text-center'
        },
        { 
            data: 'enrolled',
            className: 'text-center',
            render: function(data, type, row) {
                const percentage = row.participants > 0 ? 
                    Math.round((data / row.participants) * 100) : 0;
                return `
                    <div class="progress" style="height: 20px;">
                        <div class="progress-bar" style="width: ${percentage}%">
                            ${data}/${row.participants} (${percentage}%)
                        </div>
                    </div>
                `;
            }
        },
        { 
            data: 'status',
            render: function(data, type, row) {
                const statusClasses = {
                    'active': 'success',
                    'inactive': 'warning',
                    'draft': 'secondary'
                };
                return `<span class="badge bg-${statusClasses[data] || 'secondary'}">${data}</span>`;
            }
        },
        { 
            data: null,
            orderable: false,
            render: function(data, type, row) {
                return `
                    <div class="btn-group" role="group">
                        <button type="button" class="btn btn-sm btn-outline-primary" 
                                onclick="editEvent(${row.id})">
                            <i class="fas fa-edit"></i>
                        </button>
                        <button type="button" class="btn btn-sm btn-outline-info" 
                                onclick="viewEvent(${row.id})">
                            <i class="fas fa-eye"></i>
                        </button>
                        <button type="button" class="btn btn-sm btn-outline-danger" 
                                onclick="deleteEvent(${row.id})">
                            <i class="fas fa-trash"></i>
                        </button>
                    </div>
                `;
            }
        }
    ],
    order: [[1, 'desc']],
    pageLength: 25,
    responsive: true,
    dom: '<"row"<"col-sm-12 col-md-6"l><"col-sm-12 col-md-6"f>>' +
         '<"row"<"col-sm-12"tr>>' +
         '<"row"<"col-sm-12 col-md-5"i><"col-sm-12 col-md-7"p>>',
    language: {
        url: '/js/datatables-es.json'
    }
});
```

### Export Functionality

```javascript theme={null}
// Add export buttons to DataTable
$('#events-table').DataTable({
    // ... other options
    dom: 'Bfrtip',
    buttons: [
        {
            extend: 'copy',
            text: '<i class="fas fa-copy"></i> Copy',
            className: 'btn btn-secondary btn-sm'
        },
        {
            extend: 'csv',
            text: '<i class="fas fa-file-csv"></i> CSV',
            className: 'btn btn-secondary btn-sm'
        },
        {
            extend: 'excel',
            text: '<i class="fas fa-file-excel"></i> Excel',
            className: 'btn btn-secondary btn-sm'
        },
        {
            extend: 'pdf',
            text: '<i class="fas fa-file-pdf"></i> PDF',
            className: 'btn btn-secondary btn-sm'
        },
        {
            extend: 'print',
            text: '<i class="fas fa-print"></i> Print',
            className: 'btn btn-secondary btn-sm'
        }
    ]
});
```

## AJAX Patterns

### Standard AJAX Request Pattern

```javascript theme={null}
class ApiClient {
    constructor(baseUrl = '/api') {
        this.baseUrl = baseUrl;
        this.setupAjaxDefaults();
    }

    setupAjaxDefaults() {
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
            error: function(xhr, status, error) {
                this.handleError(xhr, status, error);
            }.bind(this)
        });
    }

    handleError(xhr, status, error) {
        let message = 'An error occurred';
        
        if (xhr.responseJSON && xhr.responseJSON.message) {
            message = xhr.responseJSON.message;
        } else if (xhr.status === 422) {
            message = 'Validation error. Please check your input.';
        } else if (xhr.status === 401) {
            message = 'Unauthorized. Please log in again.';
            window.location.href = '/login';
        } else if (xhr.status === 403) {
            message = 'Access denied.';
        } else if (xhr.status === 404) {
            message = 'Resource not found.';
        } else if (xhr.status === 500) {
            message = 'Server error. Please try again later.';
        }

        toastr.error(message, 'Error');
    }

    get(url, params = {}) {
        return $.ajax({
            url: this.baseUrl + url,
            method: 'GET',
            data: params
        });
    }

    post(url, data = {}) {
        return $.ajax({
            url: this.baseUrl + url,
            method: 'POST',
            data: data
        });
    }

    put(url, data = {}) {
        return $.ajax({
            url: this.baseUrl + url,
            method: 'PUT',
            data: data
        });
    }

    delete(url) {
        return $.ajax({
            url: this.baseUrl + url,
            method: 'DELETE'
        });
    }

    upload(url, formData) {
        return $.ajax({
            url: this.baseUrl + url,
            method: 'POST',
            data: formData,
            processData: false,
            contentType: false
        });
    }
}

// Usage
const api = new ApiClient();

// Get events
api.get('/eventos', { category: 1, status: 'active' })
    .done(function(data) {
        console.log('Events:', data);
    });

// Create event
api.post('/eventos', {
    name: 'New Event',
    description: 'Event description',
    date_from: '2024-06-15'
}).done(function(response) {
    toastr.success('Event created successfully');
    location.reload();
});
```

### Promise-based AJAX Wrapper

```javascript theme={null}
class PromiseApiClient {
    constructor(baseUrl = '/api') {
        this.baseUrl = baseUrl;
    }

    request(method, url, data = null) {
        return new Promise((resolve, reject) => {
            $.ajax({
                url: this.baseUrl + url,
                method: method,
                data: data,
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                },
                success: function(response) {
                    resolve(response);
                },
                error: function(xhr, status, error) {
                    reject({ xhr, status, error });
                }
            });
        });
    }

    get(url, params = {}) {
        return this.request('GET', url, params);
    }

    post(url, data = {}) {
        return this.request('POST', url, data);
    }

    put(url, data = {}) {
        return this.request('PUT', url, data);
    }

    delete(url) {
        return this.request('DELETE', url);
    }
}

// Usage with async/await
const api = new PromiseApiClient();

async function loadEvents() {
    try {
        const events = await api.get('/eventos');
        displayEvents(events);
    } catch (error) {
        toastr.error('Failed to load events');
        console.error(error);
    }
}

async function createEvent(eventData) {
    try {
        const response = await api.post('/eventos', eventData);
        toastr.success('Event created successfully');
        return response;
    } catch (error) {
        toastr.error('Failed to create event');
        throw error;
    }
}
```

## Form Handling

### Form Validation

```javascript theme={null}
class FormValidator {
    constructor(formSelector) {
        this.form = $(formSelector);
        this.rules = {};
        this.messages = {};
        this.init();
    }

    init() {
        this.setupValidation();
        this.bindEvents();
    }

    setupValidation() {
        this.form.validate({
            rules: this.rules,
            messages: this.messages,
            errorElement: 'span',
            errorClass: 'text-danger',
            highlight: function(element) {
                $(element).addClass('is-invalid');
            },
            unhighlight: function(element) {
                $(element).removeClass('is-invalid');
            },
            errorPlacement: function(error, element) {
                error.insertAfter(element);
            }
        });
    }

    bindEvents() {
        this.form.on('submit', (e) => {
            if (!this.form.valid()) {
                e.preventDefault();
                toastr.error('Please correct the errors in the form');
            }
        });
    }

    addRule(fieldName, rule, message) {
        this.rules[fieldName] = rule;
        this.messages[fieldName] = message;
    }

    validate() {
        return this.form.valid();
    }

    reset() {
        this.form[0].reset();
        this.form.find('.is-invalid').removeClass('is-invalid');
        this.form.find('.text-danger').remove();
    }
}

// Usage
const eventForm = new FormValidator('#createEventForm');
eventForm.addRule('name', 'required', 'Event name is required');
eventForm.addRule('email', {
    required: true,
    email: true
}, 'Please enter a valid email address');
```

### Dynamic Form Fields

```javascript theme={null}
class DynamicForm {
    constructor(container) {
        this.container = container;
        this.fieldCounter = 0;
        this.init();
    }

    init() {
        this.bindEvents();
    }

    bindEvents() {
        $(this.container).on('click', '.add-field', (e) => {
            e.preventDefault();
            this.addField();
        });

        $(this.container).on('click', '.remove-field', (e) => {
            e.preventDefault();
            $(e.target).closest('.field-group').remove();
        });
    }

    addField() {
        this.fieldCounter++;
        const fieldHtml = this.createFieldHtml(this.fieldCounter);
        $(this.container).find('.fields-container').append(fieldHtml);
    }

    createFieldHtml(index) {
        return `
            <div class="field-group border rounded p-3 mb-3">
                <div class="row">
                    <div class="col-md-4">
                        <label class="form-label">Field Label</label>
                        <input type="text" class="form-control" name="fields[${index}][label]" required>
                    </div>
                    <div class="col-md-3">
                        <label class="form-label">Field Type</label>
                        <select class="form-select" name="fields[${index}][type]" required>
                            <option value="text">Text</option>
                            <option value="email">Email</option>
                            <option value="number">Number</option>
                            <option value="select">Select</option>
                            <option value="textarea">Textarea</option>
                        </select>
                    </div>
                    <div class="col-md-3">
                        <label class="form-label">Required</label>
                        <div class="form-check mt-2">
                            <input class="form-check-input" type="checkbox" name="fields[${index}][required]">
                            <label class="form-check-label">Required field</label>
                        </div>
                    </div>
                    <div class="col-md-2">
                        <button type="button" class="btn btn-danger remove-field mt-4">
                            <i class="fas fa-trash"></i>
                        </button>
                    </div>
                </div>
            </div>
        `;
    }

    getFormData() {
        const formData = new FormData();
        const fields = [];

        $(this.container).find('.field-group').each(function() {
            const field = {
                label: $(this).find('input[name*="[label]"]').val(),
                type: $(this).find('select[name*="[type]"]').val(),
                required: $(this).find('input[name*="[required]"]').is(':checked')
            };
            fields.push(field);
        });

        formData.append('fields', JSON.stringify(fields));
        return formData;
    }
}
```

## File Upload Components

### Image Upload with Preview

```javascript theme={null}
class ImageUploader {
    constructor(inputSelector, previewSelector) {
        this.input = $(inputSelector);
        this.preview = $(previewSelector);
        this.maxSize = 5 * 1024 * 1024; // 5MB
        this.allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
        this.init();
    }

    init() {
        this.bindEvents();
    }

    bindEvents() {
        this.input.on('change', (e) => {
            this.handleFileSelect(e.target.files[0]);
        });

        this.preview.on('click', '.remove-image', (e) => {
            e.preventDefault();
            this.removeImage();
        });
    }

    handleFileSelect(file) {
        if (!file) return;

        // Validate file type
        if (!this.allowedTypes.includes(file.type)) {
            toastr.error('Please select a valid image file (JPEG, PNG, GIF)');
            return;
        }

        // Validate file size
        if (file.size > this.maxSize) {
            toastr.error('File size must be less than 5MB');
            return;
        }

        // Show preview
        this.showPreview(file);
    }

    showPreview(file) {
        const reader = new FileReader();
        reader.onload = (e) => {
            this.preview.html(`
                <div class="position-relative d-inline-block">
                    <img src="${e.target.result}" class="img-thumbnail" style="max-width: 200px;">
                    <button type="button" class="btn btn-danger btn-sm position-absolute top-0 end-0 remove-image">
                        <i class="fas fa-times"></i>
                    </button>
                </div>
            `);
        };
        reader.readAsDataURL(file);
    }

    removeImage() {
        this.input.val('');
        this.preview.empty();
    }

    upload(url, additionalData = {}) {
        const file = this.input[0].files[0];
        if (!file) {
            toastr.error('Please select a file to upload');
            return Promise.reject('No file selected');
        }

        const formData = new FormData();
        formData.append('image', file);
        
        // Add additional data
        Object.keys(additionalData).forEach(key => {
            formData.append(key, additionalData[key]);
        });

        return $.ajax({
            url: url,
            method: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            xhr: () => {
                const xhr = new window.XMLHttpRequest();
                xhr.upload.addEventListener('progress', (e) => {
                    if (e.lengthComputable) {
                        const percentComplete = (e.loaded / e.total) * 100;
                        this.updateProgress(percentComplete);
                    }
                });
                return xhr;
            }
        });
    }

    updateProgress(percent) {
        // Update progress bar or show upload progress
        console.log(`Upload progress: ${percent}%`);
    }
}

// Usage
const imageUploader = new ImageUploader('#image-input', '#image-preview');

$('#upload-btn').on('click', () => {
    imageUploader.upload('/api/upload-image', { product_id: 1 })
        .done((response) => {
            toastr.success('Image uploaded successfully');
        })
        .fail((error) => {
            toastr.error('Failed to upload image');
        });
});
```

### Drag and Drop File Upload

```javascript theme={null}
class DragDropUploader {
    constructor(dropZoneSelector) {
        this.dropZone = $(dropZoneSelector);
        this.init();
    }

    init() {
        this.bindEvents();
    }

    bindEvents() {
        this.dropZone.on('dragover', (e) => {
            e.preventDefault();
            this.dropZone.addClass('dragover');
        });

        this.dropZone.on('dragleave', (e) => {
            e.preventDefault();
            this.dropZone.removeClass('dragover');
        });

        this.dropZone.on('drop', (e) => {
            e.preventDefault();
            this.dropZone.removeClass('dragover');
            
            const files = e.originalEvent.dataTransfer.files;
            this.handleFiles(files);
        });

        this.dropZone.on('click', () => {
            this.createFileInput();
        });
    }

    handleFiles(files) {
        Array.from(files).forEach(file => {
            if (file.type.startsWith('image/')) {
                this.uploadFile(file);
            }
        });
    }

    createFileInput() {
        const input = $('<input type="file" multiple accept="image/*" style="display: none;">');
        input.on('change', (e) => {
            this.handleFiles(e.target.files);
        });
        input.click();
    }

    uploadFile(file) {
        const formData = new FormData();
        formData.append('file', file);

        $.ajax({
            url: '/api/upload-file',
            method: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: (response) => {
                this.addFileToList(response);
            },
            error: (xhr) => {
                toastr.error('Failed to upload file');
            }
        });
    }

    addFileToList(fileData) {
        const fileHtml = `
            <div class="uploaded-file">
                <img src="${fileData.url}" class="img-thumbnail" style="max-width: 100px;">
                <span class="file-name">${fileData.name}</span>
                <button type="button" class="btn btn-sm btn-danger remove-file" data-id="${fileData.id}">
                    <i class="fas fa-trash"></i>
                </button>
            </div>
        `;
        this.dropZone.find('.uploaded-files').append(fileHtml);
    }
}
```

## Notification System

### Custom Notification Manager

```javascript theme={null}
class NotificationManager {
    constructor() {
        this.notifications = [];
        this.container = this.createContainer();
        this.init();
    }

    createContainer() {
        const container = $('<div id="notification-container"></div>');
        container.css({
            position: 'fixed',
            top: '20px',
            right: '20px',
            zIndex: 9999,
            maxWidth: '400px'
        });
        $('body').append(container);
        return container;
    }

    init() {
        // Configure toastr
        toastr.options = {
            closeButton: true,
            progressBar: true,
            positionClass: "toast-top-right",
            timeOut: 5000,
            extendedTimeOut: 1000,
            preventDuplicates: true
        };
    }

    show(message, type = 'info', options = {}) {
        const defaultOptions = {
            title: this.getTitle(type),
            icon: this.getIcon(type)
        };

        const finalOptions = { ...defaultOptions, ...options };

        switch (type) {
            case 'success':
                toastr.success(message, finalOptions.title);
                break;
            case 'error':
                toastr.error(message, finalOptions.title);
                break;
            case 'warning':
                toastr.warning(message, finalOptions.title);
                break;
            case 'info':
            default:
                toastr.info(message, finalOptions.title);
                break;
        }
    }

    getTitle(type) {
        const titles = {
            success: 'Success',
            error: 'Error',
            warning: 'Warning',
            info: 'Information'
        };
        return titles[type] || 'Information';
    }

    getIcon(type) {
        const icons = {
            success: 'fas fa-check-circle',
            error: 'fas fa-exclamation-circle',
            warning: 'fas fa-exclamation-triangle',
            info: 'fas fa-info-circle'
        };
        return icons[type] || 'fas fa-info-circle';
    }

    // Custom notification methods
    showLoading(message = 'Loading...') {
        const loadingHtml = `
            <div class="alert alert-info d-flex align-items-center">
                <div class="spinner-border spinner-border-sm me-2" role="status">
                    <span class="visually-hidden">Loading...</span>
                </div>
                ${message}
            </div>
        `;
        this.container.append(loadingHtml);
    }

    hideLoading() {
        this.container.find('.alert-info').remove();
    }

    showConfirm(message, onConfirm, onCancel) {
        const confirmHtml = `
            <div class="alert alert-warning">
                <p>${message}</p>
                <div class="btn-group">
                    <button type="button" class="btn btn-sm btn-primary confirm-yes">Yes</button>
                    <button type="button" class="btn btn-sm btn-secondary confirm-no">No</button>
                </div>
            </div>
        `;
        
        const confirmElement = $(confirmHtml);
        this.container.append(confirmElement);

        confirmElement.find('.confirm-yes').on('click', () => {
            confirmElement.remove();
            if (onConfirm) onConfirm();
        });

        confirmElement.find('.confirm-no').on('click', () => {
            confirmElement.remove();
            if (onCancel) onCancel();
        });
    }
}

// Usage
const notifications = new NotificationManager();

notifications.show('Operation completed successfully', 'success');
notifications.show('Please check your input', 'warning');
notifications.show('An error occurred', 'error');

notifications.showConfirm(
    'Are you sure you want to delete this item?',
    () => {
        // Handle confirmation
        deleteItem();
    },
    () => {
        // Handle cancellation
        console.log('Operation cancelled');
    }
);
```

## Payment Integration

### Payment Form Handler

```javascript theme={null}
class PaymentFormHandler {
    constructor(formSelector) {
        this.form = $(formSelector);
        this.init();
    }

    init() {
        this.bindEvents();
        this.setupValidation();
    }

    bindEvents() {
        this.form.on('submit', (e) => {
            e.preventDefault();
            this.processPayment();
        });

        // Real-time card validation
        this.form.find('#card-number').on('input', (e) => {
            this.validateCardNumber(e.target.value);
        });

        this.form.find('#card-cvv').on('input', (e) => {
            this.validateCVV(e.target.value);
        });
    }

    setupValidation() {
        this.form.validate({
            rules: {
                'card-number': {
                    required: true,
                    creditcard: true
                },
                'card-expiry': {
                    required: true,
                    pattern: /^(0[1-9]|1[0-2])\/([0-9]{2})$/
                },
                'card-cvv': {
                    required: true,
                    minlength: 3,
                    maxlength: 4
                }
            },
            messages: {
                'card-number': {
                    required: 'Card number is required',
                    creditcard: 'Please enter a valid card number'
                },
                'card-expiry': {
                    required: 'Expiry date is required',
                    pattern: 'Please enter expiry date in MM/YY format'
                },
                'card-cvv': {
                    required: 'CVV is required',
                    minlength: 'CVV must be at least 3 digits',
                    maxlength: 'CVV cannot exceed 4 digits'
                }
            }
        });
    }

    validateCardNumber(number) {
        // Remove spaces and dashes
        number = number.replace(/\s+/g, '').replace(/[^0-9]/gi, '');
        
        // Luhn algorithm validation
        let sum = 0;
        let isEven = false;
        
        for (let i = number.length - 1; i >= 0; i--) {
            let digit = parseInt(number[i]);
            
            if (isEven) {
                digit *= 2;
                if (digit > 9) {
                    digit -= 9;
                }
            }
            
            sum += digit;
            isEven = !isEven;
        }
        
        const isValid = sum % 10 === 0;
        this.updateCardValidation(isValid);
        return isValid;
    }

    validateCVV(cvv) {
        const isValid = /^\d{3,4}$/.test(cvv);
        this.updateCVVValidation(isValid);
        return isValid;
    }

    updateCardValidation(isValid) {
        const field = this.form.find('#card-number');
        if (isValid) {
            field.removeClass('is-invalid').addClass('is-valid');
        } else {
            field.removeClass('is-valid').addClass('is-invalid');
        }
    }

    updateCVVValidation(isValid) {
        const field = this.form.find('#card-cvv');
        if (isValid) {
            field.removeClass('is-invalid').addClass('is-valid');
        } else {
            field.removeClass('is-valid').addClass('is-invalid');
        }
    }

    processPayment() {
        if (!this.form.valid()) {
            toastr.error('Please correct the errors in the form');
            return;
        }

        const formData = this.form.serialize();
        
        // Show loading state
        this.form.find('button[type="submit"]').prop('disabled', true).html(
            '<span class="spinner-border spinner-border-sm me-2"></span>Processing...'
        );

        $.ajax({
            url: this.form.attr('action'),
            method: 'POST',
            data: formData,
            success: (response) => {
                if (response.success) {
                    toastr.success('Payment processed successfully');
                    window.location.href = response.redirect_url;
                } else {
                    toastr.error(response.message || 'Payment failed');
                }
            },
            error: (xhr) => {
                toastr.error('Payment failed. Please try again.');
            },
            complete: () => {
                // Reset button state
                this.form.find('button[type="submit"]').prop('disabled', false).html('Pay Now');
            }
        });
    }
}
```

## Responsive Design

### Responsive Table Handler

```javascript theme={null}
class ResponsiveTableHandler {
    constructor(tableSelector) {
        this.table = $(tableSelector);
        this.init();
    }

    init() {
        this.setupResponsive();
        this.bindEvents();
    }

    setupResponsive() {
        // Add responsive wrapper
        this.table.wrap('<div class="table-responsive"></div>');
        
        // Add responsive classes
        this.table.addClass('table-responsive');
        
        // Handle small screens
        if (window.innerWidth < 768) {
            this.convertToCards();
        }
    }

    bindEvents() {
        $(window).on('resize', () => {
            this.handleResize();
        });
    }

    handleResize() {
        if (window.innerWidth < 768) {
            this.convertToCards();
        } else {
            this.convertToTable();
        }
    }

    convertToCards() {
        if (this.table.hasClass('converted-to-cards')) return;
        
        this.table.addClass('converted-to-cards');
        const headers = this.table.find('thead th').map(function() {
            return $(this).text();
        }).get();
        
        this.table.find('tbody tr').each((index, row) => {
            const card = this.createCard($(row), headers);
            this.table.after(card);
        });
        
        this.table.hide();
    }

    createCard(row, headers) {
        const card = $('<div class="card mb-3"></div>');
        const cardBody = $('<div class="card-body"></div>');
        
        row.find('td').each((index, cell) => {
            if (headers[index]) {
                const field = $(`
                    <div class="row mb-2">
                        <div class="col-4"><strong>${headers[index]}:</strong></div>
                        <div class="col-8">${$(cell).html()}</div>
                    </div>
                `);
                cardBody.append(field);
            }
        });
        
        card.append(cardBody);
        return card;
    }

    convertToTable() {
        if (!this.table.hasClass('converted-to-cards')) return;
        
        this.table.removeClass('converted-to-cards');
        this.table.siblings('.card').remove();
        this.table.show();
    }
}

// Usage
const tableHandler = new ResponsiveTableHandler('#events-table');
```

This comprehensive frontend documentation covers all the major JavaScript components, UI libraries, and integration patterns used in the event management system. The documentation includes practical examples and usage patterns that developers can follow when working with the frontend components.
