Sindbad~EG File Manager
<?php
require_once 'config/config.php';
$pageTitle = "Bulk Member Search - " . APP_NAME;
// Get settings for theme colors
$db = Database::getInstance()->getConnection();
$stmt = $db->query("SELECT * FROM general_settings ORDER BY id DESC LIMIT 1");
$settings = $stmt->fetch();
// Default settings if none exist
$settings = array_merge([
'site_title' => 'Church Membership System',
'theme_primary_color' => '#1E40AF',
'theme_secondary_color' => '#F97316',
'header_text' => '',
'footer_text' => '',
'bulk_search_public' => 1 // Default to public access
], $settings ?: []);
// Check if bulk search requires login
$bulkSearchPublic = $settings['bulk_search_public'] ?? 1;
if (!$bulkSearchPublic && !isLoggedIn()) {
header('Location: bulk-search-restricted.php');
exit();
}
// Get areas, districts, assemblies for filters
$areas = $db->query("SELECT id, area_name FROM areas WHERE is_active = 1 ORDER BY area_name")->fetchAll();
$districts = $db->query("SELECT id, district_name, area_id FROM districts WHERE is_active = 1 ORDER BY district_name")->fetchAll();
$assemblies = $db->query("SELECT id, assembly_name, district_id FROM assemblies WHERE is_active = 1 ORDER BY assembly_name")->fetchAll();
// Initialize variables
$searchResults = [];
$uploadedNames = [];
$notFoundNames = [];
$totalResults = 0;
$error = '';
$success = '';
// Handle file upload and search
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$filterArea = $_POST['area_id'] ?? '';
$filterDistrict = $_POST['district_id'] ?? '';
$filterAssembly = $_POST['assembly_id'] ?? '';
// Check if file was uploaded
if (isset($_FILES['member_file']) && $_FILES['member_file']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['member_file'];
$fileName = $file['name'];
$fileTmp = $file['tmp_name'];
$fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
// Validate file type
if (!in_array($fileExt, ['csv', 'xlsx', 'xls'])) {
throw new Exception('Invalid file type. Please upload CSV or Excel file.');
}
$namesToSearch = [];
// Parse CSV file
if ($fileExt === 'csv') {
if (($handle = fopen($fileTmp, 'r')) !== false) {
$isFirstRow = true;
while (($data = fgetcsv($handle, 1000, ',')) !== false) {
// Skip header row if it looks like a header
if ($isFirstRow) {
$isFirstRow = false;
$firstCell = strtolower(trim($data[0] ?? ''));
if (in_array($firstCell, ['name', 'member name', 'full name', 'names', 'member', 'first name'])) {
continue;
}
}
// Get name from first column
$name = trim($data[0] ?? '');
if (!empty($name)) {
$namesToSearch[] = $name;
}
}
fclose($handle);
}
}
// Parse Excel file
elseif (in_array($fileExt, ['xlsx', 'xls'])) {
// Check if PhpSpreadsheet is available
$autoloadPath = __DIR__ . '/vendor/autoload.php';
if (file_exists($autoloadPath)) {
require_once $autoloadPath;
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($fileTmp);
$worksheet = $spreadsheet->getActiveSheet();
$isFirstRow = true;
foreach ($worksheet->getRowIterator() as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
$rowData = [];
foreach ($cellIterator as $cell) {
$rowData[] = $cell->getValue();
break; // Only get first column
}
// Skip header row
if ($isFirstRow) {
$isFirstRow = false;
$firstCell = strtolower(trim($rowData[0] ?? ''));
if (in_array($firstCell, ['name', 'member name', 'full name', 'names', 'member', 'first name'])) {
continue;
}
}
$name = trim($rowData[0] ?? '');
if (!empty($name)) {
$namesToSearch[] = $name;
}
}
} else {
throw new Exception('Excel support not available. Please upload a CSV file or install PhpSpreadsheet.');
}
}
$uploadedNames = $namesToSearch;
if (empty($namesToSearch)) {
throw new Exception('No names found in the uploaded file.');
}
// Search for each name in database
$foundMembers = [];
$notFoundNames = [];
foreach ($namesToSearch as $searchName) {
// Normalize search - trim and collapse multiple spaces
$normalizedSearch = preg_replace('/\s+/', ' ', trim($searchName));
$searchParam = '%' . $normalizedSearch . '%';
$searchWords = array_filter(explode(' ', $normalizedSearch));
$sql = "SELECT m.id, m.title, m.first_name, m.middle_name, m.last_name,
m.membershipcard_id, m.member_type, m.phone, m.email,
a.area_name, d.district_name, asm.assembly_name
FROM members m
LEFT JOIN areas a ON m.area_id = a.id
LEFT JOIN districts d ON m.district_id = d.id
LEFT JOIN assemblies asm ON m.assembly_id = asm.id
WHERE m.is_active = 1
AND (m.first_name LIKE :search1
OR m.middle_name LIKE :search2
OR m.last_name LIKE :search3";
$params = [
'search1' => $searchParam,
'search2' => $searchParam,
'search3' => $searchParam
];
// For multi-word search (full name), check if ALL words match any name field
if (count($searchWords) > 1) {
$sql .= " OR (1=1";
foreach ($searchWords as $idx => $word) {
$wordParam = '%' . $word . '%';
$sql .= " AND (m.first_name LIKE :wf{$idx} OR m.middle_name LIKE :wm{$idx} OR m.last_name LIKE :wl{$idx})";
$params["wf{$idx}"] = $wordParam;
$params["wm{$idx}"] = $wordParam;
$params["wl{$idx}"] = $wordParam;
}
$sql .= ")";
}
$sql .= ")";
// Apply location filters
if (!empty($filterArea)) {
$sql .= " AND m.area_id = :area_id";
$params['area_id'] = $filterArea;
}
if (!empty($filterDistrict)) {
$sql .= " AND m.district_id = :district_id";
$params['district_id'] = $filterDistrict;
}
if (!empty($filterAssembly)) {
$sql .= " AND m.assembly_id = :assembly_id";
$params['assembly_id'] = $filterAssembly;
}
$sql .= " ORDER BY m.first_name, m.last_name LIMIT 5";
$stmt = $db->prepare($sql);
$stmt->execute($params);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!empty($results)) {
foreach ($results as $member) {
$member['searched_name'] = $searchName;
$foundMembers[$member['id']] = $member; // Use ID as key to avoid duplicates
}
} else {
$notFoundNames[] = $searchName;
}
}
$searchResults = array_values($foundMembers);
$totalResults = count($searchResults);
$success = "Found {$totalResults} members from " . count($namesToSearch) . " searched names.";
} elseif (!empty($_POST['manual_names'])) {
// Handle manual text input
$manualNames = trim($_POST['manual_names']);
$namesToSearch = array_filter(array_map('trim', explode("\n", $manualNames)));
$uploadedNames = $namesToSearch;
if (empty($namesToSearch)) {
throw new Exception('Please enter at least one name to search.');
}
// Same search logic as file upload
$foundMembers = [];
$notFoundNames = [];
foreach ($namesToSearch as $searchName) {
// Normalize search - trim and collapse multiple spaces
$normalizedSearch = preg_replace('/\s+/', ' ', trim($searchName));
$searchParam = '%' . $normalizedSearch . '%';
$searchWords = array_filter(explode(' ', $normalizedSearch));
$sql = "SELECT m.id, m.title, m.first_name, m.middle_name, m.last_name,
m.membershipcard_id, m.member_type, m.phone, m.email,
a.area_name, d.district_name, asm.assembly_name
FROM members m
LEFT JOIN areas a ON m.area_id = a.id
LEFT JOIN districts d ON m.district_id = d.id
LEFT JOIN assemblies asm ON m.assembly_id = asm.id
WHERE m.is_active = 1
AND (m.first_name LIKE :search1
OR m.middle_name LIKE :search2
OR m.last_name LIKE :search3";
$params = [
'search1' => $searchParam,
'search2' => $searchParam,
'search3' => $searchParam
];
// For multi-word search (full name), check if ALL words match any name field
if (count($searchWords) > 1) {
$sql .= " OR (1=1";
foreach ($searchWords as $idx => $word) {
$wordParam = '%' . $word . '%';
$sql .= " AND (m.first_name LIKE :wf{$idx} OR m.middle_name LIKE :wm{$idx} OR m.last_name LIKE :wl{$idx})";
$params["wf{$idx}"] = $wordParam;
$params["wm{$idx}"] = $wordParam;
$params["wl{$idx}"] = $wordParam;
}
$sql .= ")";
}
$sql .= ")";
if (!empty($filterArea)) {
$sql .= " AND m.area_id = :area_id";
$params['area_id'] = $filterArea;
}
if (!empty($filterDistrict)) {
$sql .= " AND m.district_id = :district_id";
$params['district_id'] = $filterDistrict;
}
if (!empty($filterAssembly)) {
$sql .= " AND m.assembly_id = :assembly_id";
$params['assembly_id'] = $filterAssembly;
}
$sql .= " ORDER BY m.first_name, m.last_name LIMIT 5";
$stmt = $db->prepare($sql);
$stmt->execute($params);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!empty($results)) {
foreach ($results as $member) {
$member['searched_name'] = $searchName;
$foundMembers[$member['id']] = $member;
}
} else {
$notFoundNames[] = $searchName;
}
}
$searchResults = array_values($foundMembers);
$totalResults = count($searchResults);
$success = "Found {$totalResults} members from " . count($namesToSearch) . " searched names.";
}
} catch (Exception $e) {
$error = $e->getMessage();
}
}
// Handle export requests
if (isset($_GET['export']) && !empty($_SESSION['bulk_search_results'])) {
$exportType = $_GET['export'];
$results = $_SESSION['bulk_search_results'];
if ($exportType === 'csv') {
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="member_search_results_' . date('Y-m-d_His') . '.csv"');
$output = fopen('php://output', 'w');
// Header row
fputcsv($output, ['#', 'Title', 'First Name', 'Middle Name', 'Last Name', 'Member ID', 'Member Type', 'Area', 'District', 'Assembly']);
// Data rows
$i = 1;
foreach ($results as $member) {
fputcsv($output, [
$i++,
$member['title'] ?? '',
$member['first_name'],
$member['middle_name'] ?? '',
$member['last_name'],
$member['membershipcard_id'],
$member['member_type'] ?? '',
$member['area_name'] ?? '',
$member['district_name'] ?? '',
$member['assembly_name'] ?? ''
]);
}
fclose($output);
exit();
}
if ($exportType === 'pdf') {
// Generate PDF using simple HTML to PDF approach
header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html>
<head>
<title>Member Search Results</title>
<style>
body { font-family: Arial, sans-serif; font-size: 12px; margin: 20px; }
h1 { color: #1E40AF; font-size: 18px; margin-bottom: 10px; }
.info { color: #666; margin-bottom: 20px; }
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #1E40AF; color: white; }
tr:nth-child(even) { background-color: #f9f9f9; }
.print-btn { background: #1E40AF; color: white; padding: 10px 20px; border: none; cursor: pointer; margin-bottom: 20px; }
@media print { .print-btn { display: none; } }
</style>
</head>
<body>
<button class="print-btn" onclick="window.print()">Print / Save as PDF</button>
<h1><?php echo htmlspecialchars($settings['site_title']); ?> - Member Search Results</h1>
<p class="info">Generated on: <?php echo date('F j, Y g:i A'); ?> | Total Members: <?php echo count($results); ?></p>
<table>
<thead>
<tr>
<th>#</th>
<th>Full Name</th>
<th>Member ID</th>
<th>Type</th>
<th>District</th>
<th>Assembly</th>
</tr>
</thead>
<tbody>
<?php $i = 1; foreach ($results as $member): ?>
<tr>
<td><?php echo $i++; ?></td>
<td><?php echo htmlspecialchars(trim(($member['title'] ?? '') . ' ' . $member['first_name'] . ' ' . ($member['middle_name'] ?? '') . ' ' . $member['last_name'])); ?></td>
<td><?php echo htmlspecialchars($member['membershipcard_id']); ?></td>
<td><?php echo htmlspecialchars($member['member_type'] ?? 'N/A'); ?></td>
<td><?php echo htmlspecialchars($member['district_name'] ?? 'N/A'); ?></td>
<td><?php echo htmlspecialchars($member['assembly_name'] ?? 'N/A'); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<script>
// Auto-trigger print dialog
window.onload = function() {
// window.print();
};
</script>
</body>
</html>
<?php
exit();
}
}
// Store results in session for export
if (!empty($searchResults)) {
$_SESSION['bulk_search_results'] = $searchResults;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo $pageTitle; ?></title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
.hero-gradient {
background: linear-gradient(135deg, #1E40AF 0%, #9333EA 50%, #F97316 100%);
}
.card-hover:hover {
transform: translateY(-3px);
box-shadow: 0 15px 30px rgba(0,0,0,0.12);
}
.card-hover {
transition: all 0.3s ease;
}
.text-gradient {
background: linear-gradient(135deg, #1E40AF 0%, #F97316 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.btn-gradient {
background: linear-gradient(135deg, #1E40AF 0%, #9333EA 100%);
}
.btn-gradient-orange {
background: linear-gradient(135deg, #F97316 0%, #FBBF24 100%);
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-fadeIn { animation: fadeInUp 0.5s ease-out; }
.drop-zone { border: 2px dashed #cbd5e1; transition: all 0.3s ease; }
.drop-zone:hover, .drop-zone.dragover { border-color: #1E40AF; background-color: #eff6ff; }
</style>
</head>
<body class="bg-gray-50">
<!-- Header -->
<header class="bg-white shadow-lg sticky top-0 z-50">
<div class="container mx-auto px-4">
<div class="flex items-center justify-between h-16">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 rounded-xl flex items-center justify-center" style="background: linear-gradient(135deg, #1E40AF 0%, #F97316 100%);">
<i class="fas fa-church text-white text-xl"></i>
</div>
<div>
<h1 class="text-xl font-bold text-gradient"><?php echo htmlspecialchars($settings['site_title']); ?></h1>
<p class="text-xs text-gray-500">Bulk Member Search</p>
</div>
</div>
<nav class="hidden md:flex items-center space-x-6">
<a href="index.php" class="text-gray-700 hover:text-blue-700 font-medium transition">
<i class="fas fa-home mr-1"></i>Home
</a>
<a href="public-search.php" class="text-gray-700 hover:text-blue-700 font-medium transition">
<i class="fas fa-search mr-1"></i>Single Search
</a>
<a href="conference.php" class="text-gray-700 hover:text-orange-600 font-medium transition">
<i class="fas fa-calendar mr-1"></i>Events
</a>
<?php if (isLoggedIn()): ?>
<a href="dashboard.php" class="text-gray-700 hover:text-purple-600 font-medium transition">
<i class="fas fa-tachometer-alt mr-1"></i>Dashboard
</a>
<?php else: ?>
<a href="login.php" class="px-6 py-2 rounded-full text-white font-semibold transition hover:shadow-lg btn-gradient">
<i class="fas fa-sign-in-alt mr-1"></i>Login
</a>
<?php endif; ?>
</nav>
<button class="md:hidden text-gray-600" onclick="toggleMobileMenu()">
<i class="fas fa-bars text-xl"></i>
</button>
</div>
<div id="mobileMenu" class="md:hidden hidden border-t border-gray-200 py-4">
<div class="flex flex-col space-y-3">
<a href="index.php" class="text-gray-600 hover:text-blue-700 transition"><i class="fas fa-home mr-1"></i>Home</a>
<a href="public-search.php" class="text-gray-600 hover:text-blue-700 transition"><i class="fas fa-search mr-1"></i>Single Search</a>
<a href="conference.php" class="text-gray-600 hover:text-blue-700 transition"><i class="fas fa-calendar mr-1"></i>Events</a>
<?php if (isLoggedIn()): ?>
<a href="dashboard.php" class="text-blue-700 font-medium"><i class="fas fa-tachometer-alt mr-1"></i>Dashboard</a>
<?php else: ?>
<a href="login.php" class="text-blue-700 font-medium"><i class="fas fa-sign-in-alt mr-1"></i>Login</a>
<?php endif; ?>
</div>
</div>
</div>
</header>
<!-- Hero Section -->
<section class="hero-gradient text-white py-12">
<div class="container mx-auto px-4">
<div class="max-w-4xl mx-auto text-center">
<div class="mb-4">
<i class="fas fa-users text-5xl opacity-90"></i>
</div>
<h1 class="text-3xl md:text-4xl font-bold mb-3">Bulk Member Search</h1>
<p class="text-lg text-white/90">
Upload a list of names or enter them manually to find multiple members at once
</p>
</div>
</div>
</section>
<!-- Main Content -->
<section class="py-10">
<div class="container mx-auto px-4">
<div class="max-w-6xl mx-auto">
<?php if ($error): ?>
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded mb-6 animate-fadeIn">
<p class="font-bold"><i class="fas fa-exclamation-circle mr-2"></i>Error</p>
<p><?php echo htmlspecialchars($error); ?></p>
</div>
<?php endif; ?>
<?php if ($success): ?>
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 rounded mb-6 animate-fadeIn">
<p class="font-bold"><i class="fas fa-check-circle mr-2"></i>Success</p>
<p><?php echo htmlspecialchars($success); ?></p>
</div>
<?php endif; ?>
<!-- Search Form -->
<div class="bg-white rounded-xl shadow-lg p-6 mb-8 card-hover">
<form method="POST" enctype="multipart/form-data" id="bulkSearchForm">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left: File Upload -->
<div>
<h3 class="text-lg font-bold text-gray-800 mb-4">
<i class="fas fa-file-upload mr-2 text-blue-500"></i>Upload File
</h3>
<div class="drop-zone rounded-lg p-8 text-center cursor-pointer" id="dropZone" onclick="document.getElementById('member_file').click()">
<i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-3"></i>
<p class="text-gray-600 mb-2">Drag & drop your file here or click to browse</p>
<p class="text-sm text-gray-500">Supports CSV, XLSX, XLS files</p>
<p class="text-xs text-gray-400 mt-2">First column should contain member names</p>
<input type="file" name="member_file" id="member_file" accept=".csv,.xlsx,.xls" class="hidden" onchange="handleFileSelect(this)">
</div>
<p id="selectedFile" class="text-sm text-green-600 mt-2 hidden">
<i class="fas fa-check-circle mr-1"></i><span></span>
</p>
<div class="mt-4">
<a href="#" onclick="downloadTemplate('csv')" class="text-sm text-blue-600 hover:underline mr-4">
<i class="fas fa-download mr-1"></i>Download CSV Template
</a>
</div>
</div>
<!-- Right: Manual Entry -->
<div>
<h3 class="text-lg font-bold text-gray-800 mb-4">
<i class="fas fa-keyboard mr-2 text-purple-500"></i>Or Enter Names Manually
</h3>
<textarea name="manual_names" id="manual_names" rows="8"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="Enter one name per line: John Doe Jane Smith Michael Johnson"><?php echo htmlspecialchars($_POST['manual_names'] ?? ''); ?></textarea>
<p class="text-xs text-gray-500 mt-1">Enter one name per line</p>
</div>
</div>
<!-- Filters -->
<div class="border-t border-gray-200 mt-6 pt-6">
<h3 class="text-lg font-bold text-gray-800 mb-4">
<i class="fas fa-filter mr-2 text-orange-500"></i>Filter by Location (Optional)
</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Area</label>
<select name="area_id" id="area_id" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
<option value="">All Areas</option>
<?php foreach ($areas as $area): ?>
<option value="<?php echo $area['id']; ?>" <?php echo ($_POST['area_id'] ?? '') == $area['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($area['area_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">District</label>
<select name="district_id" id="district_id" 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 $district): ?>
<option value="<?php echo $district['id']; ?>" data-area="<?php echo $district['area_id']; ?>" <?php echo ($_POST['district_id'] ?? '') == $district['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($district['district_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Assembly</label>
<select name="assembly_id" id="assembly_id" 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 $assembly): ?>
<option value="<?php echo $assembly['id']; ?>" data-district="<?php echo $assembly['district_id']; ?>" <?php echo ($_POST['assembly_id'] ?? '') == $assembly['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($assembly['assembly_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<!-- Submit Button -->
<div class="mt-6 flex justify-center">
<button type="submit" class="btn-gradient text-white px-10 py-3 rounded-full font-semibold hover:shadow-lg transition">
<i class="fas fa-search mr-2"></i>Search Members
</button>
</div>
</form>
</div>
<!-- Results Section -->
<?php if (!empty($searchResults)): ?>
<div class="bg-white rounded-xl shadow-lg overflow-hidden animate-fadeIn">
<!-- Results Header -->
<div class="bg-gradient-to-r from-blue-500 to-purple-600 text-white p-4">
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
<div>
<h3 class="text-xl font-bold">
<i class="fas fa-check-circle mr-2"></i>Search Results
</h3>
<p class="text-white/90 text-sm">
Found <?php echo $totalResults; ?> members |
<?php echo count($notFoundNames); ?> names not found
</p>
</div>
<div class="flex gap-2">
<a href="?export=csv" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg text-sm font-medium transition">
<i class="fas fa-file-csv mr-1"></i>Export CSV
</a>
<a href="?export=pdf" target="_blank" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg text-sm font-medium transition">
<i class="fas fa-file-pdf mr-1"></i>Export PDF
</a>
</div>
</div>
</div>
<!-- Results Table -->
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">#</th>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">Full Name</th>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">Member ID</th>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">Type</th>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">District</th>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">Assembly</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<?php $i = 1; foreach ($searchResults as $member): ?>
<tr class="hover:bg-gray-50">
<td class="px-4 py-3 text-sm text-gray-600"><?php echo $i++; ?></td>
<td class="px-4 py-3">
<p class="font-semibold text-gray-800">
<?php echo htmlspecialchars(trim(($member['title'] ?? '') . ' ' . $member['first_name'] . ' ' . ($member['middle_name'] ?? '') . ' ' . $member['last_name'])); ?>
</p>
</td>
<td class="px-4 py-3">
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded text-sm font-medium">
<?php echo htmlspecialchars($member['membershipcard_id']); ?>
</span>
</td>
<td class="px-4 py-3 text-sm text-gray-600"><?php echo htmlspecialchars($member['member_type'] ?? 'N/A'); ?></td>
<td class="px-4 py-3 text-sm text-gray-600"><?php echo htmlspecialchars($member['district_name'] ?? 'N/A'); ?></td>
<td class="px-4 py-3 text-sm text-gray-600"><?php echo htmlspecialchars($member['assembly_name'] ?? 'N/A'); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Not Found Names -->
<?php if (!empty($notFoundNames)): ?>
<div class="bg-orange-50 rounded-xl shadow-lg p-6 mt-6 animate-fadeIn">
<h3 class="text-lg font-bold text-orange-800 mb-3">
<i class="fas fa-exclamation-triangle mr-2"></i>Names Not Found (<?php echo count($notFoundNames); ?>)
</h3>
<div class="flex flex-wrap gap-2">
<?php foreach ($notFoundNames as $name): ?>
<span class="bg-orange-100 text-orange-800 px-3 py-1 rounded-full text-sm">
<?php echo htmlspecialchars($name); ?>
</span>
<?php endforeach; ?>
</div>
<p class="text-sm text-orange-700 mt-3">
<i class="fas fa-info-circle mr-1"></i>
These names were not found in the database. They may be spelled differently or not yet registered.
</p>
</div>
<?php endif; ?>
<?php elseif ($_SERVER['REQUEST_METHOD'] !== 'POST'): ?>
<!-- Initial State -->
<div class="bg-white rounded-xl shadow-lg p-8 text-center">
<i class="fas fa-file-import text-6xl text-gray-300 mb-4"></i>
<h3 class="text-xl font-bold text-gray-800 mb-2">Ready to Search</h3>
<p class="text-gray-600 mb-6">
Upload a file with member names or enter them manually above to begin your bulk search.
</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-2xl mx-auto">
<div class="text-center">
<div class="w-14 h-14 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-2">
<i class="fas fa-upload text-blue-600 text-xl"></i>
</div>
<p class="text-sm text-gray-600">Upload CSV/Excel</p>
</div>
<div class="text-center">
<div class="w-14 h-14 bg-purple-100 rounded-full flex items-center justify-center mx-auto mb-2">
<i class="fas fa-search text-purple-600 text-xl"></i>
</div>
<p class="text-sm text-gray-600">Search Database</p>
</div>
<div class="text-center">
<div class="w-14 h-14 bg-orange-100 rounded-full flex items-center justify-center mx-auto mb-2">
<i class="fas fa-download text-orange-600 text-xl"></i>
</div>
<p class="text-sm text-gray-600">Export Results</p>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</section>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="flex items-center space-x-3 mb-4 md:mb-0">
<div class="w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center">
<i class="fas fa-church text-white text-lg"></i>
</div>
<div>
<h3 class="text-lg font-bold"><?php echo htmlspecialchars($settings['site_title']); ?></h3>
<p class="text-gray-400 text-sm">Bulk Member Search</p>
</div>
</div>
<div class="text-center md:text-right">
<p class="text-gray-400 text-sm mb-2">
© <?php echo date('Y'); ?> <?php echo htmlspecialchars($settings['site_title']); ?>
</p>
<div class="flex justify-center md:justify-end space-x-4">
<a href="index.php" class="text-gray-400 hover:text-white transition text-sm">Home</a>
<a href="public-search.php" class="text-gray-400 hover:text-white transition text-sm">Single Search</a>
<a href="login.php" class="text-gray-400 hover:text-white transition text-sm">Login</a>
</div>
</div>
</div>
</div>
</footer>
<script>
function toggleMobileMenu() {
document.getElementById('mobileMenu').classList.toggle('hidden');
}
// File drag and drop
const dropZone = document.getElementById('dropZone');
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, () => dropZone.classList.add('dragover'), false);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, () => dropZone.classList.remove('dragover'), false);
});
dropZone.addEventListener('drop', function(e) {
const files = e.dataTransfer.files;
if (files.length) {
document.getElementById('member_file').files = files;
handleFileSelect(document.getElementById('member_file'));
}
});
function handleFileSelect(input) {
if (input.files && input.files[0]) {
const fileName = input.files[0].name;
const fileInfo = document.getElementById('selectedFile');
fileInfo.querySelector('span').textContent = 'Selected: ' + fileName;
fileInfo.classList.remove('hidden');
}
}
// Cascading dropdowns
const areaSelect = document.getElementById('area_id');
const districtSelect = document.getElementById('district_id');
const assemblySelect = document.getElementById('assembly_id');
areaSelect.addEventListener('change', function() {
const selectedArea = this.value;
const districtOptions = districtSelect.querySelectorAll('option');
districtOptions.forEach(option => {
if (option.value === '') return;
const optionArea = option.getAttribute('data-area');
option.style.display = (!selectedArea || optionArea === selectedArea) ? '' : 'none';
});
if (districtSelect.value) {
const currentOption = districtSelect.querySelector(`option[value="${districtSelect.value}"]`);
if (currentOption && currentOption.style.display === 'none') {
districtSelect.value = '';
districtSelect.dispatchEvent(new Event('change'));
}
}
});
districtSelect.addEventListener('change', function() {
const selectedDistrict = this.value;
const assemblyOptions = assemblySelect.querySelectorAll('option');
assemblyOptions.forEach(option => {
if (option.value === '') return;
const optionDistrict = option.getAttribute('data-district');
option.style.display = (!selectedDistrict || optionDistrict === selectedDistrict) ? '' : 'none';
});
if (assemblySelect.value) {
const currentOption = assemblySelect.querySelector(`option[value="${assemblySelect.value}"]`);
if (currentOption && currentOption.style.display === 'none') {
assemblySelect.value = '';
}
}
});
// Download template
function downloadTemplate(type) {
if (type === 'csv') {
const csvContent = "Name\nJohn Doe\nJane Smith\nMichael Johnson";
const blob = new Blob([csvContent], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'member_search_template.csv';
a.click();
window.URL.revokeObjectURL(url);
}
}
</script>
<?php
if (file_exists(__DIR__ . '/includes/chat-hub-widget.php')) {
include 'includes/chat-hub-widget.php';
}
?>
</body>
</html>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists