Sindbad~EG File Manager

Current Path : /home/copmadinaarea/thecopmadinaarea.org/portal/modules/member-codes/
Upload File :
Current File : /home/copmadinaarea/thecopmadinaarea.org/portal/modules/member-codes/index.php

<?php
require_once '../../config/config.php';
checkLogin();

$pageTitle = "Member Codes - " . APP_NAME;
$db = Database::getInstance()->getConnection();
$success = '';
$error = '';

// Get access level and filters
$accessLevel = getUserAccessLevel();
$areaId = getUserAreaId();
$districtId = getUserDistrictId();
$assemblyId = getUserAssemblyId();

// Handle CRUD operations
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        // Regenerate code
        if (isset($_POST['regenerate_code'])) {
            $memberId = $_POST['member_id'];
            $stmt = $db->prepare("SELECT * FROM members WHERE id = :id");
            $stmt->execute(['id' => $memberId]);
            $member = $stmt->fetch();
            
            if (!$member) {
                throw new Exception("Member not found");
            }
            
            $success = "Code regenerated: <strong>MEM-" . str_pad($member['id'], 6, '0', STR_PAD_LEFT) . "</strong>";
        }
        
        // Update custom code (if you want to allow custom codes)
        if (isset($_POST['update_code'])) {
            $memberId = $_POST['member_id'];
            $customCode = $_POST['custom_code'] ?? '';
            
            // For now, we'll just confirm the action
            $success = "Member code updated successfully!";
        }
        
        // Download codes (bulk export)
        if (isset($_POST['export_codes'])) {
            // Set headers for CSV download
            header('Content-Type: text/csv');
            header('Content-Disposition: attachment; filename="member_codes_' . date('Y-m-d') . '.csv"');
            
            $output = fopen('php://output', 'w');
            fputcsv($output, ['Member ID', 'Name', 'Code', 'District', 'Assembly']);
            
            // Get all members based on filters
            $exportQuery = "SELECT m.*, d.district_name, a.assembly_name 
                          FROM members m
                          LEFT JOIN districts d ON m.district_id = d.id
                          LEFT JOIN assemblies a ON m.assembly_id = a.id
                          WHERE m.is_active = 1";
            $exportParams = [];
            
            if (!empty($_POST['filter_district'])) {
                $exportQuery .= " AND m.district_id = :district_id";
                $exportParams['district_id'] = $_POST['filter_district'];
            }
            if (!empty($_POST['filter_assembly'])) {
                $exportQuery .= " AND m.assembly_id = :assembly_id";
                $exportParams['assembly_id'] = $_POST['filter_assembly'];
            }
            
            $exportStmt = $db->prepare($exportQuery);
            $exportStmt->execute($exportParams);
            $exportMembers = $exportStmt->fetchAll();
            
            foreach ($exportMembers as $member) {
                fputcsv($output, [
                    $member['id'],
                    $member['first_name'] . ' ' . $member['last_name'],
                    'MEM-' . str_pad($member['id'], 6, '0', STR_PAD_LEFT),
                    $member['district_name'] ?? 'N/A',
                    $member['assembly_name'] ?? 'N/A'
                ]);
            }
            
            fclose($output);
            exit;
        }
        
    } catch (Exception $e) {
        $error = $e->getMessage();
    }
}

// Get filter parameters
$filterDistrict = $_GET['district'] ?? '';
$filterAssembly = $_GET['assembly'] ?? '';
$searchTerm = $_GET['search'] ?? '';

// Get members based on access level and filters
$query = "SELECT m.*, d.district_name, a.assembly_name, ar.area_name 
          FROM members m
          LEFT JOIN districts d ON m.district_id = d.id
          LEFT JOIN assemblies a ON m.assembly_id = a.id
          LEFT JOIN areas ar ON m.area_id = ar.id
          WHERE m.is_active = 1";
$params = [];

// Access level restrictions
if ($accessLevel === 'assembly') {
    $query .= " AND m.assembly_id = :user_assembly_id";
    $params['user_assembly_id'] = $assemblyId;
} elseif ($accessLevel === 'district') {
    $query .= " AND m.district_id = :user_district_id";
    $params['user_district_id'] = $districtId;
} elseif ($accessLevel === 'area') {
    $query .= " AND m.area_id = :user_area_id";
    $params['user_area_id'] = $areaId;
}

// Apply filters
if (!empty($filterDistrict)) {
    $query .= " AND m.district_id = :filter_district";
    $params['filter_district'] = $filterDistrict;
}

if (!empty($filterAssembly)) {
    $query .= " AND m.assembly_id = :filter_assembly";
    $params['filter_assembly'] = $filterAssembly;
}

// Search functionality
if (!empty($searchTerm)) {
    $query .= " AND (m.first_name LIKE :search OR m.last_name LIKE :search OR m.email LIKE :search)";
    $params['search'] = '%' . $searchTerm . '%';
}

$query .= " ORDER BY m.first_name, m.last_name LIMIT 500";

$stmt = $db->prepare($query);
$stmt->execute($params);
$members = $stmt->fetchAll();

// Get districts and assemblies for filters
$districts = $db->query("SELECT * FROM districts ORDER BY district_name")->fetchAll();
$assemblies = $db->query("SELECT a.*, d.district_name FROM assemblies a LEFT JOIN districts d ON a.district_id = d.id ORDER BY a.assembly_name")->fetchAll();

// Statistics
$stats = [
    'total' => count($members),
    'with_email' => count(array_filter($members, fn($m) => !empty($m['email']))),
    'districts' => count(array_unique(array_column($members, 'district_id'))),
];

include '../../includes/header.php';
?>

<?php include '../../includes/sidebar.php'; ?>

<!-- Main Content -->
<main class="flex-1 md:ml-64 mt-16">
    <div class="container mx-auto px-4 py-8">
        <div class="max-w-6xl mx-auto">
            
            <!-- Header -->
            <div class="mb-8">
                <h1 class="text-3xl font-bold text-gray-800 mb-2">Member Codes</h1>
                <p class="text-gray-600">Generate and manage unique member identification codes</p>
            </div>
            
            <!-- Success/Error Messages -->
            <?php if ($success): ?>
                <div class="mb-6 bg-green-100 border-l-4 border-green-500 text-green-700 p-4 rounded-lg shadow-md">
                    <div class="flex items-center">
                        <i class="fas fa-check-circle mr-3 text-xl"></i>
                        <p><?php echo $success; ?></p>
                    </div>
                </div>
            <?php endif; ?>
            
            <?php if ($error): ?>
                <div class="mb-6 bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded-lg shadow-md">
                    <div class="flex items-center">
                        <i class="fas fa-exclamation-circle mr-3 text-xl"></i>
                        <p><?php echo htmlspecialchars($error); ?></p>
                    </div>
                </div>
            <?php endif; ?>
            
            <!-- Statistics Cards -->
            <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
                <div class="bg-white rounded-lg shadow p-4 border-l-4 border-blue-500">
                    <div class="flex items-center justify-between">
                        <div>
                            <p class="text-sm text-gray-600">Total Members</p>
                            <p class="text-2xl font-bold text-gray-800"><?php echo $stats['total']; ?></p>
                        </div>
                        <i class="fas fa-users text-3xl text-blue-500"></i>
                    </div>
                </div>
                <div class="bg-white rounded-lg shadow p-4 border-l-4 border-green-500">
                    <div class="flex items-center justify-between">
                        <div>
                            <p class="text-sm text-gray-600">With Email</p>
                            <p class="text-2xl font-bold text-gray-800"><?php echo $stats['with_email']; ?></p>
                        </div>
                        <i class="fas fa-envelope text-3xl text-green-500"></i>
                    </div>
                </div>
                <div class="bg-white rounded-lg shadow p-4 border-l-4 border-purple-500">
                    <div class="flex items-center justify-between">
                        <div>
                            <p class="text-sm text-gray-600">Districts</p>
                            <p class="text-2xl font-bold text-gray-800"><?php echo $stats['districts']; ?></p>
                        </div>
                        <i class="fas fa-map-marked-alt text-3xl text-purple-500"></i>
                    </div>
                </div>
            </div>
            
            <!-- Filters and Actions -->
            <div class="bg-white rounded-lg shadow p-6 mb-6">
                <form method="GET" class="grid grid-cols-1 md:grid-cols-4 gap-4">
                    <!-- Search -->
                    <div>
                        <input type="text" name="search" value="<?php echo htmlspecialchars($searchTerm); ?>"
                               placeholder="Search members..."
                               class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
                    </div>
                    
                    <!-- District Filter -->
                    <div>
                        <select name="district" id="filterDistrict" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
                            <option value="">All Districts</option>
                            <?php foreach ($districts as $dist): ?>
                                <option value="<?php echo $dist['id']; ?>" <?php echo $filterDistrict == $dist['id'] ? 'selected' : ''; ?>>
                                    <?php echo htmlspecialchars($dist['district_name']); ?>
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    
                    <!-- Assembly Filter -->
                    <div>
                        <select name="assembly" id="filterAssembly" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
                            <option value="">All Assemblies</option>
                            <?php foreach ($assemblies as $asm): ?>
                                <option value="<?php echo $asm['id']; ?>" 
                                        data-district="<?php echo $asm['district_id']; ?>"
                                        <?php echo $filterAssembly == $asm['id'] ? 'selected' : ''; ?>>
                                    <?php echo htmlspecialchars($asm['assembly_name']); ?>
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    
                    <!-- Actions -->
                    <div class="flex gap-2">
                        <button type="submit" class="flex-1 bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600">
                            <i class="fas fa-filter mr-2"></i>Filter
                        </button>
                        <a href="?" class="bg-gray-200 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-300 flex items-center">
                            <i class="fas fa-times"></i>
                        </a>
                    </div>
                </form>
                
                <!-- Export Button -->
                <div class="mt-4 flex justify-end">
                    <form method="POST" class="inline">
                        <input type="hidden" name="filter_district" value="<?php echo htmlspecialchars($filterDistrict); ?>">
                        <input type="hidden" name="filter_assembly" value="<?php echo htmlspecialchars($filterAssembly); ?>">
                        <button type="submit" name="export_codes" class="bg-green-500 text-white px-4 py-2 rounded-lg hover:bg-green-600">
                            <i class="fas fa-download mr-2"></i>Export to CSV
                        </button>
                    </form>
                </div>
            </div>
            
            <!-- Members Table -->
            <div class="bg-white rounded-xl shadow-lg overflow-hidden">
                <div class="p-6 border-b border-gray-200 flex justify-between items-center">
                    <h2 class="text-xl font-semibold text-gray-800">
                        <i class="fas fa-list mr-2"></i>Members List
                    </h2>
                    <span class="text-sm text-gray-600">
                        Showing <strong><?php echo count($members); ?></strong> member(s)
                    </span>
                </div>
                
                <?php if (empty($members)): ?>
                    <div class="p-8 text-center text-gray-500">
                        <i class="fas fa-users text-4xl mb-4 opacity-50"></i>
                        <p class="text-lg">No members found</p>
                        <p class="text-sm">Try adjusting your filters or search term</p>
                    </div>
                <?php else: ?>
                <div class="overflow-x-auto">
                    <table class="min-w-full divide-y divide-gray-200">
                        <thead class="bg-gray-50">
                            <tr>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Member</th>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Code</th>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">District</th>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Assembly</th>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
                            </tr>
                        </thead>
                        <tbody class="bg-white divide-y divide-gray-200">
                            <?php foreach ($members as $member): ?>
                                <tr class="hover:bg-gray-50">
                                    <td class="px-6 py-4 whitespace-nowrap">
                                        <div class="flex items-center">
                                            <div class="h-10 w-10 flex-shrink-0">
                                                <div class="h-10 w-10 rounded-full bg-gradient-to-r from-blue-500 to-purple-500 flex items-center justify-center text-white font-bold">
                                                    <?php echo strtoupper(substr($member['first_name'], 0, 1) . substr($member['last_name'], 0, 1)); ?>
                                                </div>
                                            </div>
                                            <div class="ml-4">
                                                <div class="text-sm font-medium text-gray-900">
                                                    <?php echo htmlspecialchars($member['first_name'] . ' ' . $member['last_name']); ?>
                                                </div>
                                                <div class="text-sm text-gray-500">
                                                    <?php echo htmlspecialchars($member['email'] ?? 'No email'); ?>
                                                </div>
                                            </div>
                                        </div>
                                    </td>
                                    <td class="px-6 py-4 whitespace-nowrap">
                                        <span class="px-3 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800">
                                            MEM-<?php echo str_pad($member['id'], 6, '0', STR_PAD_LEFT); ?>
                                        </span>
                                    </td>
                                    <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
                                        <?php echo htmlspecialchars($member['district_name'] ?? 'N/A'); ?>
                                    </td>
                                    <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
                                        <?php echo htmlspecialchars($member['assembly_name'] ?? 'N/A'); ?>
                                    </td>
                                    <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
                                        <div class="flex gap-2">
                                            <button onclick="copyCode('MEM-<?php echo str_pad($member['id'], 6, '0', STR_PAD_LEFT); ?>')" 
                                                    class="text-blue-600 hover:text-blue-900" title="Copy Code">
                                                <i class="fas fa-copy"></i>
                                            </button>
                                            <button onclick="viewMemberQR(<?php echo $member['id']; ?>)" 
                                                    class="text-green-600 hover:text-green-900" title="View QR Code">
                                                <i class="fas fa-qrcode"></i>
                                            </button>
                                            <button onclick="regenerateCode(<?php echo $member['id']; ?>)" 
                                                    class="text-orange-600 hover:text-orange-900" title="Regenerate Code">
                                                <i class="fas fa-sync"></i>
                                            </button>
                                            <a href="../membership/view.php?id=<?php echo $member['id']; ?>" 
                                               class="text-purple-600 hover:text-purple-900" title="View Member">
                                                <i class="fas fa-eye"></i>
                                            </a>
                                        </div>
                                    </td>
                                </tr>
                            <?php endforeach; ?>
                        </tbody>
                    </table>
                </div>
                <?php endif; ?>
            </div>
            
        </div>
    </div>
</main>

<!-- QR Code Modal -->
<div id="qrModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center">
    <div class="bg-white rounded-lg max-w-md w-full p-6 m-4">
        <div class="flex justify-between items-center mb-4">
            <h3 class="text-lg font-semibold">Member QR Code</h3>
            <button onclick="closeQRModal()" class="text-gray-400 hover:text-gray-600">
                <i class="fas fa-times"></i>
            </button>
        </div>
        <div id="qrCodeContainer" class="flex flex-col items-center">
            <div id="qrcode" class="mb-4"></div>
            <p id="qrMemberName" class="text-lg font-semibold mb-2"></p>
            <p id="qrMemberCode" class="text-sm text-gray-600 mb-4"></p>
            <button onclick="downloadQR()" class="bg-blue-500 text-white px-4 py-2 rounded-lg hover:bg-blue-600">
                <i class="fas fa-download mr-2"></i>Download QR
            </button>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script>
<script>
// Copy code to clipboard
function copyCode(code) {
    navigator.clipboard.writeText(code).then(function() {
        // Show toast notification
        const toast = document.createElement('div');
        toast.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg z-50';
        toast.innerHTML = '<i class="fas fa-check-circle mr-2"></i>Code copied: ' + code;
        document.body.appendChild(toast);
        
        setTimeout(() => {
            toast.remove();
        }, 3000);
    }, function(err) {
        alert('Could not copy code');
    });
}

// View member QR code
let currentQRCode = null;
function viewMemberQR(memberId) {
    const code = 'MEM-' + String(memberId).padStart(6, '0');
    
    // Clear previous QR code
    document.getElementById('qrcode').innerHTML = '';
    
    // Generate new QR code
    currentQRCode = new QRCode(document.getElementById('qrcode'), {
        text: code,
        width: 256,
        height: 256,
        colorDark: '#000000',
        colorLight: '#ffffff',
        correctLevel: QRCode.CorrectLevel.H
    });
    
    // Set member info
    document.getElementById('qrMemberCode').textContent = code;
    
    // Show modal
    document.getElementById('qrModal').classList.remove('hidden');
}

// Close QR modal
function closeQRModal() {
    document.getElementById('qrModal').classList.add('hidden');
}

// Download QR code
function downloadQR() {
    const canvas = document.querySelector('#qrcode canvas');
    if (canvas) {
        const url = canvas.toDataURL('image/png');
        const link = document.createElement('a');
        link.download = document.getElementById('qrMemberCode').textContent + '_QR.png';
        link.href = url;
        link.click();
    }
}

// Regenerate code
function regenerateCode(memberId) {
    if (confirm('Regenerate code for this member?')) {
        const form = document.createElement('form');
        form.method = 'POST';
        form.innerHTML = '<input type="hidden" name="regenerate_code" value="1">' +
                        '<input type="hidden" name="member_id" value="' + memberId + '">';
        document.body.appendChild(form);
        form.submit();
    }
}

// Cascading District -> Assembly filter
const filterDistrict = document.getElementById('filterDistrict');
const filterAssembly = document.getElementById('filterAssembly');

if (filterDistrict && filterAssembly) {
    filterDistrict.addEventListener('change', function() {
        const selectedDistrict = this.value;
        const assemblyOptions = filterAssembly.querySelectorAll('option');
        
        assemblyOptions.forEach(option => {
            if (option.value === '') {
                option.style.display = '';
                return;
            }
            
            const optionDistrict = option.getAttribute('data-district');
            if (!selectedDistrict || optionDistrict === selectedDistrict) {
                option.style.display = '';
            } else {
                option.style.display = 'none';
            }
        });
        
        // Reset assembly selection if current selection is not visible
        if (filterAssembly.value) {
            const currentOption = filterAssembly.querySelector(`option[value="${filterAssembly.value}"]`);
            if (currentOption && currentOption.style.display === 'none') {
                filterAssembly.value = '';
            }
        }
    });
    
    // Trigger on page load to handle pre-selected values
    if (filterDistrict.value) {
        filterDistrict.dispatchEvent(new Event('change'));
    }
}

// Close modal when clicking outside
document.getElementById('qrModal')?.addEventListener('click', function(e) {
    if (e.target === this) {
        closeQRModal();
    }
});
</script>

<?php include '../../includes/footer.php'; ?>

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists