Sindbad~EG File Manager
<?php
require_once '../../config/config.php';
require_once '../../classes/MembershipCard.php';
checkLogin();
$pageTitle = 'Special Upload - ' . APP_NAME;
$db = Database::getInstance()->getConnection();
$successMessage = '';
$errorMessage = '';
$uploadResults = [];
// Access
$accessLevel = $_SESSION['access_level'] ?? 'assembly';
$areaId = $_SESSION['area_id'] ?? null;
$districtId = $_SESSION['district_id'] ?? null;
$assemblyId = $_SESSION['assembly_id'] ?? null;
// Helpers from upload.php
if (!function_exists('generateMembershipId')) {
function generateMembershipId() {
return 'MEM' . date('Y') . str_pad(mt_rand(1, 999999), 6, '0', STR_PAD_LEFT);
}
}
if (!function_exists('generateTrackingCode')) {
function generateTrackingCode($type = 'member') {
$prefix = $type === 'member' ? 'MEM' : 'USR';
return $prefix . date('Y') . str_pad(mt_rand(1, 999999), 6, '0', STR_PAD_LEFT);
}
}
if (!function_exists('generateBarcode')) {
function generateBarcode($code) {
$width = 200;
$height = 50;
$image = imagecreate($width, $height);
$white = imagecolorallocate($image, 255, 255, 255);
$black = imagecolorallocate($image, 0, 0, 0);
imagefill($image, 0, 0, $white);
$codeLength = strlen($code);
$x = 10;
for ($i = 0; $i < $codeLength; $i++) {
$char = ord($code[$i]);
$pattern = $char % 4;
for ($j = 0; $j < 3; $j++) {
$barWidth = ($pattern & (1 << $j)) ? 3 : 1;
imagefilledrectangle($image, $x, 5, $x + $barWidth, 35, $black);
$x += $barWidth + 1;
}
}
imagestring($image, 2, 10, 37, substr($code, 0, 20), $black);
ob_start();
imagepng($image);
$imageData = ob_get_contents();
ob_end_clean();
imagedestroy($image);
return 'data:image/png;base64,' . base64_encode($imageData);
}
}
if (!function_exists('generateQRCode')) {
function generateQRCode($code) {
$size = 100;
$image = imagecreate($size, $size);
$white = imagecolorallocate($image, 255, 255, 255);
$black = imagecolorallocate($image, 0, 0, 0);
imagefill($image, 0, 0, $white);
$codeHash = md5($code);
$blockSize = 5;
imagefilledrectangle($image, 5, 5, 30, 30, $black);
imagefilledrectangle($image, 70, 5, 95, 30, $black);
imagefilledrectangle($image, 5, 70, 30, 95, $black);
imagefilledrectangle($image, 10, 10, 25, 25, $white);
imagefilledrectangle($image, 75, 10, 90, 25, $white);
imagefilledrectangle($image, 10, 75, 25, 90, $white);
imagefilledrectangle($image, 15, 15, 20, 20, $black);
imagefilledrectangle($image, 80, 15, 85, 20, $black);
imagefilledrectangle($image, 15, 80, 20, 85, $black);
for ($i = 0; $i < 32; $i++) {
$hexChar = hexdec($codeHash[$i]);
for ($bit = 0; $bit < 4; $bit++) {
if ($hexChar & (1 << $bit)) {
$x = 35 + (($i * 2 + $bit) % 6) * $blockSize;
$y = 35 + floor(($i * 2 + $bit) / 6) * $blockSize;
if ($x < 95 && $y < 95) {
imagefilledrectangle($image, $x, $y, $x + $blockSize - 1, $y + $blockSize - 1, $black);
}
}
}
}
ob_start();
imagepng($image);
$imageData = ob_get_contents();
ob_end_clean();
imagedestroy($image);
return 'data:image/png;base64,' . base64_encode($imageData);
}
}
if (!function_exists('createMemberUserCode')) {
function createMemberUserCode(PDO $db, $memberId, $createdBy) {
try {
$memberId = (int)$memberId;
if ($memberId <= 0) {
return;
}
$existingStmt = $db->prepare('SELECT id FROM memberuser_codes WHERE member_id = :member_id LIMIT 1');
$existingStmt->execute(['member_id' => $memberId]);
if ($existingStmt->fetch()) {
return;
}
do {
$trackingCode = generateTrackingCode('member');
$checkStmt = $db->prepare('SELECT id FROM memberuser_codes WHERE tracking_code = :code');
$checkStmt->execute(['code' => $trackingCode]);
} while ($checkStmt->fetch());
$code = 'MC' . date('Ymd') . str_pad($memberId, 4, '0', STR_PAD_LEFT) . mt_rand(100, 999);
$barcode = generateBarcode($trackingCode);
$qrcode = generateQRCode($trackingCode);
$eventStmt = $db->prepare("SELECT id FROM events WHERE name = 'Attendance' AND is_active = 1 LIMIT 1");
$eventStmt->execute();
$defaultEvent = $eventStmt->fetch();
$eventId = $defaultEvent ? $defaultEvent['id'] : null;
$codeStmt = $db->prepare('
INSERT INTO memberuser_codes (
code, description, member_id, event_id, code_type, tracking_code,
barcode, qrcode, created_by, is_active
) VALUES (
:code, :description, :member_id, :event_id, \'member\', :tracking_code,
:barcode, :qrcode, :created_by, 1
)
');
$codeStmt->execute([
'code' => $code,
'description' => 'Auto-generated member tracking code',
'member_id' => $memberId,
'event_id' => $eventId,
'tracking_code' => $trackingCode,
'barcode' => $barcode,
'qrcode' => $qrcode,
'created_by' => $createdBy
]);
} catch (Exception $e) {
}
}
}
// Step 2: finalize upload using stored rows and chosen location
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['finalize_upload'])) {
$selectedAreaId = (int)($_POST['area_id'] ?? 0);
$selectedDistrictId = (int)($_POST['district_id'] ?? 0);
$selectedAssemblyId = (int)($_POST['assembly_id'] ?? 0);
if ($selectedAreaId <= 0 || $selectedDistrictId <= 0 || $selectedAssemblyId <= 0) {
$errorMessage = 'Please select Area, District and Assembly before uploading.';
} elseif (empty($_SESSION['special_upload_rows']) || empty($_SESSION['special_upload_headers'])) {
$errorMessage = 'No uploaded data found. Please upload a file again.';
} else {
$rows = $_SESSION['special_upload_rows'];
$headers = $_SESSION['special_upload_headers'];
$successCount = 0;
$errorCount = 0;
try {
$db->beginTransaction();
foreach ($rows as $index => $data) {
$rowNum = $index + 2; // assuming first data row after header
$memberData = is_array($data) && array_keys($data) !== range(0, count($data) - 1)
? $data
: array_combine($headers, $data);
// Basic required fields
if (empty($memberData['first_name']) || empty($memberData['last_name']) || empty($memberData['gender'])) {
$errorCount++;
$uploadResults[] = [
'row' => $rowNum,
'name' => trim(($memberData['first_name'] ?? '') . ' ' . ($memberData['last_name'] ?? '')),
'status' => 'error',
'message' => 'Missing required fields (first_name, last_name, gender).'
];
continue;
}
// Auto email if empty
if (empty($memberData['email']) || stripos((string)$memberData['email'], 'leave empty') !== false || stripos((string)$memberData['email'], '@email.com') !== false) {
$firstName = strtolower(trim($memberData['first_name']));
$lastName = strtolower(trim($memberData['last_name']));
$memberData['email'] = $firstName . '.' . $lastName . '@church.auto';
}
// Use globally-selected location for ALL rows
$memberAreaId = $selectedAreaId;
$memberDistrictId = $selectedDistrictId;
$memberAssemblyId = $selectedAssemblyId;
try {
// Check if member already exists (same name and DOB)
$duplicateCheckStmt = $db->prepare('
SELECT id, membershipcard_id FROM members
WHERE first_name = :first_name
AND last_name = :last_name
AND COALESCE(date_of_birth, "0000-00-00") = :date_of_birth
LIMIT 1
');
$duplicateCheckStmt->execute([
'first_name' => $memberData['first_name'],
'last_name' => $memberData['last_name'],
'date_of_birth' => !empty($memberData['date_of_birth']) ? $memberData['date_of_birth'] : '0000-00-00'
]);
if ($existingMember = $duplicateCheckStmt->fetch()) {
$errorCount++;
$uploadResults[] = [
'row' => $rowNum,
'name' => $memberData['first_name'] . ' ' . $memberData['last_name'],
'status' => 'error',
'message' => 'Member already exists in database with card number: ' . $existingMember['membershipcard_id']
];
continue;
}
// Unique membershipcard_id
$tempCardGen = new MembershipCard();
do {
$membershipCardId = $tempCardGen->generateCardNumber();
$checkStmt = $db->prepare('SELECT id FROM members WHERE membershipcard_id = :membershipcard_id');
$checkStmt->execute(['membershipcard_id' => $membershipCardId]);
} while ($checkStmt->fetch());
// Unique membership_id
do {
$membershipId = generateMembershipId();
$checkMidStmt = $db->prepare('SELECT id FROM members WHERE membership_id = :membership_id');
$checkMidStmt->execute(['membership_id' => $membershipId]);
} while ($checkMidStmt->fetch());
$stmt = $db->prepare('
INSERT INTO members (
area_id, district_id, assembly_id, membershipcard_id, membership_id, family_id, title,
first_name, middle_name, last_name, gender, date_of_birth,
place_of_birth, phone, email, member_type, marital_status,
address_line1, gps_address, street_name, city, hometown,
water_baptism, date_of_baptism, place_of_baptism, officiating_minister_baptism,
officiating_ministers_district, holyghost_baptism, date_of_holyspirit_baptism,
communicant, dedicated, dedication_date, name_of_officiating_minister,
church_where_dedication_done, date_of_conversion, date_of_joining,
occupation, level_of_education, parent_name, parent_relationship,
created_by, is_active, created_at
) VALUES (
:area_id, :district_id, :assembly_id, :membershipcard_id, :membership_id, :family_id, :title,
:first_name, :middle_name, :last_name, :gender, :date_of_birth,
:place_of_birth, :phone, :email, :member_type, :marital_status,
:address_line1, :gps_address, :street_name, :city, :hometown,
:water_baptism, :date_of_baptism, :place_of_baptism, :officiating_minister_baptism,
:officiating_ministers_district, :holyghost_baptism, :date_of_holyspirit_baptism,
:communicant, :dedicated, :dedication_date, :name_of_officiating_minister,
:church_where_dedication_done, :date_of_conversion, :date_of_joining,
:occupation, :level_of_education, :parent_name, :parent_relationship,
:created_by, 1, NOW()
)
');
$stmt->execute([
'area_id' => $memberAreaId,
'district_id' => $memberDistrictId,
'assembly_id' => $memberAssemblyId,
'membershipcard_id' => $membershipCardId,
'membership_id' => $membershipId,
'family_id' => !empty($memberData['family_id']) ? $memberData['family_id'] : null,
'title' => $memberData['title'] ?? null,
'first_name' => $memberData['first_name'],
'middle_name' => $memberData['middle_name'] ?? null,
'last_name' => $memberData['last_name'],
'gender' => $memberData['gender'],
'date_of_birth' => !empty($memberData['date_of_birth']) ? $memberData['date_of_birth'] : null,
'place_of_birth' => $memberData['place_of_birth'] ?? null,
'phone' => $memberData['phone'] ?? null,
'email' => $memberData['email'],
'member_type' => $memberData['member_type'] ?? 'Full Member',
'marital_status' => $memberData['marital_status'] ?? null,
'address_line1' => $memberData['address_line1'] ?? null,
'gps_address' => $memberData['gps_address'] ?? null,
'street_name' => $memberData['street_name'] ?? null,
'city' => $memberData['city'] ?? null,
'hometown' => $memberData['hometown'] ?? null,
'water_baptism' => ($memberData['water_baptism'] ?? '0') == '1' ? 1 : 0,
'date_of_baptism' => !empty($memberData['date_of_baptism']) ? $memberData['date_of_baptism'] : null,
'place_of_baptism' => $memberData['place_of_baptism'] ?? null,
'officiating_minister_baptism' => $memberData['officiating_minister_baptism'] ?? null,
'officiating_ministers_district' => $memberData['officiating_ministers_district'] ?? null,
'holyghost_baptism' => ($memberData['holyghost_baptism'] ?? '0') == '1' ? 1 : 0,
'date_of_holyspirit_baptism' => !empty($memberData['date_of_holyspirit_baptism']) ? $memberData['date_of_holyspirit_baptism'] : null,
'communicant' => ($memberData['communicant'] ?? '0') == '1' ? 1 : 0,
'dedicated' => ($memberData['dedicated'] ?? '0') == '1' ? 1 : 0,
'dedication_date' => !empty($memberData['dedication_date']) ? $memberData['dedication_date'] : null,
'name_of_officiating_minister' => $memberData['name_of_officiating_minister'] ?? null,
'church_where_dedication_done' => $memberData['church_where_dedication_done'] ?? null,
'date_of_conversion' => !empty($memberData['date_of_conversion']) ? $memberData['date_of_conversion'] : null,
'date_of_joining' => !empty($memberData['date_of_joining']) ? $memberData['date_of_joining'] : null,
'occupation' => $memberData['occupation'] ?? null,
'level_of_education' => $memberData['level_of_education'] ?? null,
'parent_name' => $memberData['parent_name'] ?? null,
'parent_relationship' => $memberData['parent_relationship'] ?? null,
'created_by' => $_SESSION['user_id']
]);
$newMemberId = $db->lastInsertId();
// Tracking code
createMemberUserCode($db, $newMemberId, $_SESSION['user_id']);
// Card + account
try {
$membershipCard = new MembershipCard();
$cardResult = $membershipCard->createCard($newMemberId);
$cardNumber = $cardResult['card_number'] ?? null;
try {
// Generate unique username to avoid duplicates
$baseUsername = strtolower($memberData['first_name']) . '.' . strtolower($memberData['last_name']);
$username = $baseUsername;
$counter = 1;
// Check if username already exists and make it unique
do {
$checkUsernameStmt = $db->prepare('SELECT id FROM member_accounts WHERE username = :username');
$checkUsernameStmt->execute(['username' => $username]);
if ($checkUsernameStmt->fetch()) {
$username = $baseUsername . $counter;
$counter++;
} else {
break;
}
} while (true);
$defaultPassword = 'Member@' . date('Y');
$passwordHash = password_hash($defaultPassword, PASSWORD_DEFAULT);
$fullName = trim(($memberData['title'] ?? '') . ' ' . $memberData['first_name'] . ' ' . ($memberData['middle_name'] ?? '') . ' ' . $memberData['last_name']);
$accountStmt = $db->prepare('
INSERT INTO member_accounts (
member_id, username, email, password_hash, full_name, phone,
access_level, area_id, district_id, assembly_id, is_active
) VALUES (
:member_id, :username, :email, :password_hash, :full_name, :phone,
\'member\', :area_id, :district_id, :assembly_id, 1
)
');
// Check if email already exists in member_accounts
$emailToUse = $memberData['email'];
$checkEmailStmt = $db->prepare('SELECT id FROM member_accounts WHERE email = :email');
$checkEmailStmt->execute(['email' => $emailToUse]);
if ($checkEmailStmt->fetch()) {
// Email exists, make it unique by appending member ID
$emailParts = explode('@', $emailToUse);
$emailToUse = $emailParts[0] . '.' . $newMemberId . '@' . $emailParts[1];
}
$accountStmt->execute([
'member_id' => $newMemberId,
'username' => $username,
'email' => $emailToUse,
'password_hash' => $passwordHash,
'full_name' => $fullName,
'phone' => $memberData['phone'] ?? null,
'area_id' => $memberAreaId,
'district_id' => $memberDistrictId,
'assembly_id' => $memberAssemblyId
]);
$uploadResults[] = [
'row' => $rowNum,
'name' => $memberData['first_name'] . ' ' . $memberData['last_name'],
'status' => 'success',
'card_number' => $cardNumber,
'message' => 'Member, Card & Account created. Username: ' . $username . ', Password: ' . $defaultPassword
];
} catch (Exception $accountError) {
error_log('Account creation failed for member ID ' . $newMemberId . ': ' . $accountError->getMessage());
$uploadResults[] = [
'row' => $rowNum,
'name' => $memberData['first_name'] . ' ' . $memberData['last_name'],
'status' => 'warning',
'card_number' => $cardNumber ?? null,
'message' => 'Member & Card created, but account creation failed: ' . $accountError->getMessage()
];
}
$successCount++;
} catch (Exception $cardError) {
$uploadResults[] = [
'row' => $rowNum,
'name' => $memberData['first_name'] . ' ' . $memberData['last_name'],
'status' => 'warning',
'message' => 'Member created but card generation failed: ' . $cardError->getMessage()
];
$successCount++;
}
} catch (Exception $rowError) {
$errorCount++;
$uploadResults[] = [
'row' => $rowNum,
'name' => trim(($memberData['first_name'] ?? '') . ' ' . ($memberData['last_name'] ?? '')),
'status' => 'error',
'message' => $rowError->getMessage()
];
}
}
$db->commit();
$_SESSION['upload_results'] = $uploadResults;
$_SESSION['upload_date'] = date('Y-m-d H:i:s');
unset($_SESSION['special_upload_rows'], $_SESSION['special_upload_headers']);
$successMessage = "Successfully uploaded {$successCount} members with membership cards and accounts!";
if ($errorCount > 0) {
$errorMessage = "{$errorCount} rows had errors and were skipped.";
}
} catch (Exception $e) {
$db->rollBack();
$errorMessage = 'Special upload failed: ' . $e->getMessage();
}
}
}
// Step 1: upload file and store rows in session for preview
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['member_file']) && !isset($_POST['finalize_upload'])) {
try {
$file = $_FILES['member_file'];
if ($file['error'] !== UPLOAD_ERR_OK) {
throw new Exception('File upload error');
}
$fileExt = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($fileExt, ['csv', 'xlsx', 'xls'])) {
throw new Exception('Please upload a CSV or Excel file');
}
$headers = [];
$rows = [];
if ($fileExt === 'csv') {
$handle = fopen($file['tmp_name'], 'r');
if ($handle === false) {
throw new Exception('Could not open file');
}
$headers = fgetcsv($handle);
if ($headers === false) {
throw new Exception('Could not read file headers');
}
$row = 1;
while (($data = fgetcsv($handle)) !== false) {
$row++;
$isEmptyRow = true;
foreach ($data as $value) {
if (trim((string)$value) !== '') {
$isEmptyRow = false;
break;
}
}
if ($isEmptyRow) {
continue;
}
if (isset($data[0]) && stripos((string)$data[0], 'Mr/Mrs') !== false) {
continue;
}
$rows[] = array_combine($headers, $data);
}
fclose($handle);
} else {
require_once '../../vendor/autoload.php';
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file['tmp_name']);
$sheet = $spreadsheet->getActiveSheet();
$allRows = $sheet->toArray();
if (empty($allRows)) {
throw new Exception('Excel file is empty');
}
$headers = array_shift($allRows);
$rowNum = 1;
foreach ($allRows as $data) {
$rowNum++;
$isEmptyRow = true;
foreach ($data as $value) {
if (trim((string)$value) !== '') {
$isEmptyRow = false;
break;
}
}
if ($isEmptyRow) {
continue;
}
if (isset($data[0]) && (stripos((string)$data[0], 'Mr/Mrs') !== false || $data[0] == 'Mr')) {
continue;
}
$rows[] = array_combine($headers, $data);
}
}
if (empty($rows)) {
throw new Exception('No valid data rows found in file');
}
$_SESSION['special_upload_headers'] = $headers;
$_SESSION['special_upload_rows'] = $rows;
$successMessage = 'File loaded successfully. Please choose Area, District and Assembly, review preview and click Final Upload.';
} catch (Exception $e) {
$errorMessage = 'Failed to load file: ' . $e->getMessage();
}
}
// Load areas/districts/assemblies for global location selection
$areas = [];
$districts = [];
$assemblies = [];
try {
$areasQuery = 'SELECT id, area_name FROM areas WHERE is_active = 1';
if ($accessLevel === 'area' && $areaId) {
$areasQuery .= ' AND id = ' . (int)$areaId;
}
$areasQuery .= ' ORDER BY area_name';
$areas = $db->query($areasQuery)->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
}
try {
$districtsStmt = $db->query('SELECT id, district_name, area_id FROM districts WHERE is_active = 1 ORDER BY district_name');
$districts = $districtsStmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
}
try {
$assembliesStmt = $db->query('SELECT id, assembly_name, district_id FROM assemblies WHERE is_active = 1 ORDER BY assembly_name');
$assemblies = $assembliesStmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
}
$previewHeaders = $_SESSION['special_upload_headers'] ?? [];
$previewRows = $_SESSION['special_upload_rows'] ?? [];
include '../../includes/header.php';
include '../../includes/sidebar.php';
?>
<main class="flex-1 md:ml-64 mt-16 min-h-screen bg-gray-50">
<div class="container mx-auto px-4 py-8">
<!-- Page Header -->
<div class="gradient-bg rounded-2xl shadow-2xl p-8 mb-8 text-white">
<div class="flex items-center justify-between flex-wrap gap-4">
<div>
<h1 class="text-4xl font-bold mb-2">
<i class="fas fa-upload mr-3"></i>Special Upload
</h1>
<p class="text-white/90 text-lg">Bulk import members and force a single Area/District/Assembly for all rows</p>
</div>
<div class="flex items-center gap-3">
<a href="upload.php" class="px-6 py-3 bg-white/20 hover:bg-white/30 text-white rounded-full font-semibold transition backdrop-blur-sm">
<i class="fas fa-arrow-left mr-2"></i>Standard Upload
</a>
<a href="index.php" class="px-6 py-3 bg-white/20 hover:bg-white/30 text-white rounded-full font-semibold transition backdrop-blur-sm">
<i class="fas fa-users mr-2"></i>Back to Members
</a>
</div>
</div>
</div>
<?php if ($successMessage): ?>
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-6 rounded-lg mb-6">
<div class="flex items-center">
<i class="fas fa-check-circle text-3xl mr-4"></i>
<div>
<p class="font-bold text-lg"><?php echo $successMessage; ?></p>
</div>
</div>
</div>
<?php endif; ?>
<?php if ($errorMessage): ?>
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-6 rounded-lg mb-6">
<div class="flex items-center">
<i class="fas fa-exclamation-circle text-3xl mr-4"></i>
<p class="font-bold text-lg"><?php echo $errorMessage; ?></p>
</div>
</div>
<?php endif; ?>
<?php if (!empty($uploadResults)): ?>
<div class="bg-white rounded-2xl shadow-lg p-6 mb-8">
<div class="flex items-center justify-between mb-4">
<h3 class="text-2xl font-bold text-gray-800">
<i class="fas fa-list-check mr-2 text-gradient"></i>Special Upload Results
</h3>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-gray-100">
<tr>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Row</th>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Member Name</th>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Status</th>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Card Number</th>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Message</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<?php foreach ($uploadResults as $result): ?>
<tr>
<td class="px-4 py-3 text-sm"><?php echo $result['row']; ?></td>
<td class="px-4 py-3 text-sm font-medium"><?php echo htmlspecialchars($result['name']); ?></td>
<td class="px-4 py-3 text-sm">
<?php if ($result['status'] == 'success'): ?>
<span class="px-3 py-1 rounded-full text-xs font-semibold bg-green-100 text-green-800">
<i class="fas fa-check mr-1"></i>Success
</span>
<?php elseif ($result['status'] == 'warning'): ?>
<span class="px-3 py-1 rounded-full text-xs font-semibold bg-yellow-100 text-yellow-800">
<i class="fas fa-exclamation-triangle mr-1"></i>Warning
</span>
<?php else: ?>
<span class="px-3 py-1 rounded-full text-xs font-semibold bg-red-100 text-red-800">
<i class="fas fa-times mr-1"></i>Error
</span>
<?php endif; ?>
</td>
<td class="px-4 py-3 text-sm font-mono"><?php echo $result['card_number'] ?? '-'; ?></td>
<td class="px-4 py-3 text-sm text-gray-600"><?php echo $result['message'] ?? '-'; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Left: Upload file -->
<div class="bg-white rounded-2xl shadow-lg p-8">
<h2 class="text-2xl font-bold text-gray-800 mb-6">
<i class="fas fa-cloud-upload-alt mr-2 text-green-600"></i>Step 1: Upload File
</h2>
<form method="POST" enctype="multipart/form-data" class="space-y-6">
<div>
<label class="block text-sm font-bold text-gray-700 mb-3">Select CSV or Excel File</label>
<div class="border-2 border-dashed border-gray-300 rounded-xl p-8 text-center hover:border-blue-500 transition">
<i class="fas fa-file-upload text-5xl text-gray-400 mb-4"></i>
<input type="file"
name="member_file"
accept=".csv,.xlsx,.xls"
required
class="block w-full text-sm text-gray-500 file:mr-4 file:py-3 file:px-6 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100 cursor-pointer">
<p class="text-sm text-gray-500 mt-2">CSV, XLSX or XLS (Max 10MB)</p>
</div>
</div>
<button type="submit" class="btn-gradient w-full text-white px-8 py-4 rounded-full font-bold text-lg shadow-xl hover:shadow-2xl transition">
<i class="fas fa-eye mr-2"></i>Load & Preview
</button>
</form>
</div>
<!-- Right: Global location + preview -->
<div class="bg-white rounded-2xl shadow-lg p-8">
<h2 class="text-2xl font-bold text-gray-800 mb-4">
<i class="fas fa-map-marker-alt mr-2 text-blue-600"></i>Step 2: Set Location & Final Upload
</h2>
<p class="text-sm text-gray-600 mb-4">Choose the Area, District and Assembly that should be applied to <strong>all</strong> rows in this upload.</p>
<form method="POST" class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Area</label>
<select name="area_id" id="areaSelect" class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm" required>
<option value="">Select Area</option>
<?php foreach ($areas as $area): ?>
<option value="<?php echo $area['id']; ?>" <?php echo ($areaId && $areaId == $area['id']) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($area['area_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">District</label>
<select name="district_id" id="districtSelect" class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm" required>
<option value="">Select District</option>
<?php foreach ($districts as $dist): ?>
<option value="<?php echo $dist['id']; ?>" data-area-id="<?php echo $dist['area_id']; ?>" <?php echo ($districtId && $districtId == $dist['id']) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($dist['district_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Assembly</label>
<select name="assembly_id" id="assemblySelect" class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm" required>
<option value="">Select Assembly</option>
<?php foreach ($assemblies as $asm): ?>
<option value="<?php echo $asm['id']; ?>" data-district-id="<?php echo $asm['district_id']; ?>" <?php echo ($assemblyId && $assemblyId == $asm['id']) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($asm['assembly_name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="mt-4">
<h3 class="text-sm font-semibold text-gray-800 mb-2">Preview (first 10 rows)</h3>
<?php if (empty($previewRows)): ?>
<p class="text-xs text-gray-500">Upload a file in Step 1 to see the preview here.</p>
<?php else: ?>
<div class="border border-gray-200 rounded-lg max-h-64 overflow-auto text-xs">
<table class="min-w-full">
<thead class="bg-gray-100">
<tr>
<?php foreach ($previewHeaders as $h): ?>
<th class="px-2 py-1 text-left font-semibold text-gray-700"><?php echo htmlspecialchars($h); ?></th>
<?php endforeach; ?>
</tr>
</thead>
<tbody>
<?php $maxPreview = min(10, count($previewRows)); ?>
<?php for ($i = 0; $i < $maxPreview; $i++): $row = $previewRows[$i]; ?>
<tr class="border-t border-gray-100">
<?php foreach ($previewHeaders as $h): ?>
<td class="px-2 py-1 text-gray-700"><?php echo htmlspecialchars($row[$h] ?? ''); ?></td>
<?php endforeach; ?>
</tr>
<?php endfor; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<div class="mt-4">
<button type="submit" name="finalize_upload" value="1" class="btn-gradient w-full text-white px-8 py-4 rounded-full font-bold text-lg shadow-xl hover:shadow-2xl transition" <?php echo empty($previewRows) ? 'disabled' : ''; ?>>
<i class="fas fa-upload mr-2"></i>Final Upload with Selected Location
</button>
<?php if (empty($previewRows)): ?>
<p class="text-xs text-gray-500 mt-1">Load a file first before final upload.</p>
<?php endif; ?>
</div>
</form>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var areaSelect = document.getElementById('areaSelect');
var districtSelect = document.getElementById('districtSelect');
var assemblySelect = document.getElementById('assemblySelect');
function filterDistricts() {
var areaId = areaSelect.value;
var options = districtSelect.querySelectorAll('option');
options.forEach(function(opt) {
if (!opt.dataset.areaId) { opt.style.display = ''; return; }
if (!areaId || opt.dataset.areaId === areaId) {
opt.style.display = '';
} else {
opt.style.display = 'none';
}
});
}
function filterAssemblies() {
var districtId = districtSelect.value;
var options = assemblySelect.querySelectorAll('option');
options.forEach(function(opt) {
if (!opt.dataset.districtId) { opt.style.display = ''; return; }
if (!districtId || opt.dataset.districtId === districtId) {
opt.style.display = '';
} else {
opt.style.display = 'none';
}
});
}
if (areaSelect && districtSelect && assemblySelect) {
filterDistricts();
filterAssemblies();
areaSelect.addEventListener('change', function() {
districtSelect.value = '';
assemblySelect.value = '';
filterDistricts();
filterAssemblies();
});
districtSelect.addEventListener('change', function() {
assemblySelect.value = '';
filterAssemblies();
});
}
});
</script>
</main>
<?php include '../../includes/footer.php'; ?>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists