Sindbad~EG File Manager
<?php
require_once '../../config/config.php';
require_once '../../classes/DirectoryManager.php';
// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
header('Location: ../../login.php');
exit;
}
$page_title = "Members List";
$directoryManager = new DirectoryManager();
// Get filters
$filters = [
'search' => $_GET['search'] ?? '',
'district_id' => $_GET['district_id'] ?? '',
'assembly_id' => $_GET['assembly_id'] ?? ''
];
// Get members
$members = $directoryManager->searchMembers($filters['search'], $filters);
// Get database connection
$db = Database::getInstance()->getConnection();
// Get districts for filter
$districts_query = "SELECT * FROM districts ORDER BY district_name";
$stmt = $db->query($districts_query);
$districts = $stmt->fetchAll();
// Get assemblies for filter (filtered by district if selected)
if (!empty($filters['district_id'])) {
$assemblies_query = "SELECT * FROM assemblies WHERE district_id = :district_id ORDER BY assembly_name";
$stmt = $db->prepare($assemblies_query);
$stmt->execute([':district_id' => $filters['district_id']]);
$assemblies = $stmt->fetchAll();
} else {
$assemblies = [];
}
include '../../includes/header.php';
include '../../includes/sidebar.php';
?>
<!-- Main Content -->
<main class="main-content md:ml-64 pt-16">
<div class="min-h-screen bg-gray-50 py-8">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Header -->
<div class="mb-8">
<div class="gradient-bg rounded-xl shadow-lg p-8 text-white">
<div class="flex flex-col md:flex-row md:items-center md:justify-between">
<div>
<h1 class="text-3xl font-bold mb-2">Members List</h1>
<p class="text-blue-100">Complete directory of all members</p>
</div>
<div class="mt-4 md:mt-0 flex gap-3">
<a href="index.php" class="bg-white text-primary px-6 py-3 rounded-lg font-semibold hover:bg-blue-50 transition-all duration-300 shadow-md inline-flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
</svg>
Back to Search
</a>
</div>
</div>
</div>
</div>
<!-- Filters and Actions -->
<div class="bg-white rounded-xl shadow-md p-6 mb-6">
<form method="GET" action="" id="filterForm" class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<!-- Search -->
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Search</label>
<input type="text"
name="search"
value="<?= htmlspecialchars($filters['search']) ?>"
placeholder="Name, phone, email..."
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary">
</div>
<!-- District Filter -->
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">District</label>
<select name="district_id" id="districtFilter" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary">
<option value="">All Districts</option>
<?php foreach ($districts as $district): ?>
<option value="<?= $district['id'] ?>" <?= ($filters['district_id'] ?? '') == $district['id'] ? 'selected' : '' ?>>
<?= htmlspecialchars($district['district_name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- Assembly Filter -->
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Assembly</label>
<select name="assembly_id" id="assemblyFilter" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary">
<option value="">All Assemblies</option>
<?php foreach ($assemblies as $assembly): ?>
<option value="<?= $assembly['id'] ?>" <?= ($filters['assembly_id'] ?? '') == $assembly['id'] ? 'selected' : '' ?>>
<?= htmlspecialchars($assembly['assembly_name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- Filter Button -->
<div class="flex items-end">
<button type="submit" class="w-full btn-gradient px-6 py-2 rounded-lg font-semibold hover:shadow-lg transition-all duration-300">
Apply Filters
</button>
</div>
</div>
<?php if (!empty($filters['search']) || !empty($filters['district_id']) || !empty($filters['assembly_id'])): ?>
<div class="flex items-center justify-between bg-blue-50 border border-blue-200 rounded-lg p-3">
<span class="text-sm text-blue-800">
Showing <strong><?= count($members) ?></strong> filtered result(s)
</span>
<a href="members-list.php" class="text-blue-600 hover:text-blue-800 text-sm font-semibold">Clear Filters</a>
</div>
<?php endif; ?>
</form>
</div>
<!-- Export Actions -->
<div class="bg-white rounded-xl shadow-md p-4 mb-6">
<div class="flex flex-wrap gap-3">
<button onclick="exportToCSV()" class="bg-green-600 text-white px-6 py-2 rounded-lg font-semibold hover:bg-green-700 transition-all duration-300 inline-flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
Export CSV
</button>
<button onclick="exportToPDF()" class="bg-red-600 text-white px-6 py-2 rounded-lg font-semibold hover:bg-red-700 transition-all duration-300 inline-flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>
</svg>
Export PDF
</button>
<button onclick="window.print()" class="bg-gray-700 text-white px-6 py-2 rounded-lg font-semibold hover:bg-gray-800 transition-all duration-300 inline-flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"/>
</svg>
Print
</button>
</div>
</div>
<!-- Members Table -->
<div class="bg-white rounded-xl shadow-md overflow-hidden" id="membersTable">
<div class="px-6 py-4 bg-gradient-primary text-white">
<h2 class="text-xl font-bold">All Members (<?= count($members) ?>)</h2>
</div>
<div class="overflow-x-auto">
<table class="w-full" id="dataTable">
<thead class="bg-gray-50 border-b-2 border-gray-200">
<tr>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider cursor-pointer hover:bg-gray-100" onclick="sortTable(0)">
Member ID ↕
</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider cursor-pointer hover:bg-gray-100" onclick="sortTable(1)">
Full Name ↕
</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider cursor-pointer hover:bg-gray-100" onclick="sortTable(2)">
Phone ↕
</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider cursor-pointer hover:bg-gray-100" onclick="sortTable(3)">
Email ↕
</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider cursor-pointer hover:bg-gray-100" onclick="sortTable(4)">
Location ↕
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<?php if (count($members) > 0): ?>
<?php foreach ($members as $member): ?>
<tr class="hover:bg-gray-50 transition-colors duration-200">
<td class="px-6 py-4 whitespace-nowrap">
<span class="text-sm font-mono font-semibold text-primary"><?= htmlspecialchars($member['membershipcard_id'] ?? 'N/A') ?></span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-semibold text-gray-900">
<?= htmlspecialchars(trim(($member['title'] ?? '') . ' ' . $member['first_name'] . ' ' . ($member['middle_name'] ?? '') . ' ' . $member['last_name'])) ?>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm text-gray-900">
<?= !empty($member['phone']) ? htmlspecialchars($member['phone']) : '<span class="text-gray-400">N/A</span>' ?>
</div>
</td>
<td class="px-6 py-4">
<div class="text-sm text-gray-900">
<?= !empty($member['email']) ? htmlspecialchars($member['email']) : '<span class="text-gray-400">N/A</span>' ?>
</div>
</td>
<td class="px-6 py-4">
<div class="text-sm text-gray-700">
<?php
$location = array_filter([
$member['assembly_name'] ?? null,
$member['district_name'] ?? null,
$member['area_name'] ?? null
]);
echo !empty($location) ? htmlspecialchars(implode(', ', $location)) : '<span class="text-gray-400">N/A</span>';
?>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="5" class="px-6 py-12 text-center">
<div class="text-gray-400">
<svg class="w-16 h-16 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"/>
</svg>
<p class="text-lg font-semibold">No members found</p>
<p class="text-sm">Try adjusting your filters</p>
</div>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</main>
<!-- Print Styles -->
<style media="print">
.no-print { display: none !important; }
body { background: white; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; }
thead { background-color: #f3f4f6 !important; }
</style>
<script>
// Dynamic assembly loading
document.getElementById('districtFilter').addEventListener('change', function() {
const districtId = this.value;
const assemblyFilter = document.getElementById('assemblyFilter');
if (!districtId) {
assemblyFilter.innerHTML = '<option value="">All Assemblies</option>';
return;
}
fetch(`../../api/get-assemblies.php?district_id=${districtId}`)
.then(response => response.json())
.then(data => {
assemblyFilter.innerHTML = '<option value="">All Assemblies</option>';
data.forEach(assembly => {
assemblyFilter.innerHTML += `<option value="${assembly.id}">${assembly.assembly_name}</option>`;
});
});
});
// Table sorting
function sortTable(columnIndex) {
const table = document.getElementById('dataTable');
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
rows.sort((a, b) => {
const aText = a.cells[columnIndex].textContent.trim();
const bText = b.cells[columnIndex].textContent.trim();
return aText.localeCompare(bText);
});
rows.forEach(row => tbody.appendChild(row));
}
// Export to CSV
function exportToCSV() {
const table = document.getElementById('dataTable');
let csv = [];
// Headers
const headers = Array.from(table.querySelectorAll('thead th')).map(th =>
th.textContent.replace(' ↕', '').trim()
);
csv.push(headers.join(','));
// Rows
const rows = table.querySelectorAll('tbody tr');
rows.forEach(row => {
const cells = Array.from(row.querySelectorAll('td')).map(td => {
let text = td.textContent.trim();
// Remove N/A markers
text = text.replace(/N\/A/g, '');
// Escape quotes
text = text.replace(/"/g, '""');
return `"${text}"`;
});
if (cells.length > 0 && cells[0] !== '""') {
csv.push(cells.join(','));
}
});
// Download
const blob = new Blob([csv.join('\n')], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `members_directory_${new Date().toISOString().split('T')[0]}.csv`;
a.click();
}
// Export to PDF
function exportToPDF() {
window.print();
}
</script>
<?php include '../../includes/footer.php'; ?>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists