Heray-Was-Here
Server : LiteSpeed
System : Linux uk-fast-web1372.main-hosting.eu 4.18.0-553.121.1.lve.el8.x86_64 #1 SMP Thu Apr 30 16:40:41 UTC 2026 x86_64
User : u390967363 ( 390967363)
PHP Version : 8.2.30
Disable Function : system, exec, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail
Directory :  /home/u390967363/domains/aibenproperties.com/public_html/app/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/u390967363/domains/aibenproperties.com/public_html/app/documents.php
<?php
session_start();
require_once 'includes/db.php';
require_once 'includes/functions.php';

// Check login
if (!isset($_SESSION['user_id'])) {
    header("Location: login.php");
    exit;
}

$user_id = $_SESSION['user_id'];
$user_role = $_SESSION['user_role'];
$companyId = getCurrentCompanyId();
$view = $_GET['view'] ?? 'list';

// --- DATA FETCHING ---

// 1. KPIs
try {
    $companyFilter = $companyId ? " WHERE company_id = {$companyId}" : "";
    $kpis = [
        'total_docs' => $pdo->query("SELECT COUNT(*) FROM documents" . $companyFilter)->fetchColumn(),
        'pending' => $pdo->query("SELECT COUNT(*) FROM documents" . ($companyFilter ? $companyFilter . " AND" : " WHERE") . " status = 'pending'")->fetchColumn(),
        'approved' => $pdo->query("SELECT COUNT(*) FROM documents" . ($companyFilter ? $companyFilter . " AND" : " WHERE") . " status = 'approved'")->fetchColumn(),
        'rejected' => $pdo->query("SELECT COUNT(*) FROM documents" . ($companyFilter ? $companyFilter . " AND" : " WHERE") . " status = 'rejected'")->fetchColumn(),
    ];
} catch (Exception $e) {
    $kpis = array_fill_keys(['total_docs', 'pending', 'approved', 'rejected'], 0);
}

// Handle New Version Upload
if (isset($_POST['upload_version'])) {
    $doc_id = $_POST['doc_id'];
    $changelog = trim($_POST['changelog']);
    
    // Check permissions (Owner or Admin/Manager)
    $check_query = "SELECT user_id, uploaded_by, version_number FROM documents d JOIN (SELECT document_id, MAX(version_number) as version_number FROM document_versions GROUP BY document_id) v ON d.id = v.document_id WHERE d.id = ?";
    $check_params = [$doc_id];
    
    if ($companyId) {
        $check_query .= " AND d.company_id = ?";
        $check_params[] = $companyId;
    }
    
    $check = $pdo->prepare($check_query);
    $check->execute($check_params);
    $doc_info = $check->fetch();
    
    if ($doc_info && ($doc_info['uploaded_by'] == $user_id || in_array($user_role, ['admin', 'super_admin', 'estate_manager']))) {
        
        $file_ext = strtolower(pathinfo($_FILES["version_file"]["name"], PATHINFO_EXTENSION));
        if (in_array($file_ext, ['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png'])) {
            $new_version = number_format($doc_info['version_number'] + 0.1, 1);
            $file_name = time() . '_v' . str_replace('.', '-', $new_version) . '_' . preg_replace("/[^a-zA-Z0-9.]/", "_", basename($_FILES["version_file"]["name"]));
            $target_file = "uploads/documents/" . $file_name;
            
            if (move_uploaded_file($_FILES["version_file"]["tmp_name"], $target_file)) {
                $pdo->beginTransaction();
                try {
                    // Insert Version
                    $stmt = $pdo->prepare("INSERT INTO document_versions (document_id, version_number, file_path, created_by, changelog) VALUES (?, ?, ?, ?, ?)");
                    $stmt->execute([$doc_id, $new_version, $target_file, $user_id, $changelog]);
                    
                    // Update Main Document Pointer (optional, but good for quick access)
                    $stmt = $pdo->prepare("UPDATE documents SET file_path = ?, updated_at = NOW(), status = 'pending' WHERE id = ?");
                    $stmt->execute([$target_file, $doc_id]);
                    
                    $pdo->commit();
                    $success_msg = "New version (v$new_version) uploaded successfully!";
                    logActivity($user_id, "Document Update", "Uploaded v$new_version for document #$doc_id");
                } catch (Exception $e) {
                    $pdo->rollBack();
                    $error_msg = "Database error: " . $e->getMessage();
                }
            } else {
                $error_msg = "File upload failed.";
            }
        } else {
            $error_msg = "Invalid file type.";
        }
    } else {
        $error_msg = "Permission denied.";
    }
}

// Handle File Upload
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['upload_document'])) {
    $title = trim($_POST['title']);
    $type = $_POST['type'];
    // Admin can select user, others upload for themselves or related context
    $target_user_id = (isset($_POST['user_id']) && in_array($user_role, ['admin','super_admin','estate_manager','contact_rep','customer_rep','marketing','sales'])) ? $_POST['user_id'] : $user_id;
    $property_id = !empty($_POST['property_id']) ? $_POST['property_id'] : null;

    // File Upload Logic
    $target_dir = "uploads/documents/";
    if (!file_exists($target_dir)) {
        mkdir($target_dir, 0777, true);
    }
    
    $file_ext = strtolower(pathinfo($_FILES["file"]["name"], PATHINFO_EXTENSION));
    $allowed_ext = ['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png'];
    
    if (in_array($file_ext, $allowed_ext)) {
        $file_name = time() . '_' . preg_replace("/[^a-zA-Z0-9.]/", "_", basename($_FILES["file"]["name"]));
        $target_file = $target_dir . $file_name;
        
        if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
            // Auto-approve Offer Letter uploads for immediate client visibility
            $status = (strtolower((string)$type) === 'offer_letter') ? 'approved' : (in_array($user_role, ['admin','super_admin','estate_manager']) ? 'approved' : 'pending');
            
            $pdo->beginTransaction();
            try {
                // Insert Main Document
                if ($companyId) {
                    $stmt = $pdo->prepare("INSERT INTO documents (company_id, user_id, property_id, title, type, file_path, uploaded_by, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
                    $stmt->execute([$companyId, $target_user_id, $property_id, $title, $type, $target_file, $user_id, $status]);
                } else {
                    $stmt = $pdo->prepare("INSERT INTO documents (user_id, property_id, title, type, file_path, uploaded_by, status) VALUES (?, ?, ?, ?, ?, ?, ?)");
                    $stmt->execute([$target_user_id, $property_id, $title, $type, $target_file, $user_id, $status]);
                }
                $doc_id = $pdo->lastInsertId();

                // Insert Initial Version (v1.0)
                $stmt = $pdo->prepare("INSERT INTO document_versions (document_id, version_number, file_path, created_by, changelog) VALUES (?, ?, ?, ?, ?)");
                $stmt->execute([$doc_id, '1.0', $target_file, $user_id, 'Initial Upload']);

                $pdo->commit();
                $success_msg = "Document uploaded successfully!";
                logActivity($user_id, "Document Upload", "Uploaded '$title' ($type)");
            } catch (Exception $e) {
                $pdo->rollBack();
                $error_msg = "Database error: " . $e->getMessage();
            }
        } else {
            $error_msg = "File upload failed.";
        }
    } else {
        $error_msg = "Invalid file type. Allowed: PDF, DOC, DOCX, JPG, PNG.";
    }
}

// Handle Approval/Rejection (Admin/Manager)
if (isset($_GET['action']) && isset($_GET['id']) && in_array($user_role, ['admin', 'super_admin', 'estate_manager'])) {
    $doc_id = $_GET['id'];
    $action = $_GET['action']; // approve or reject
    
    if ($action == 'approve') {
        $query = "UPDATE documents SET status = 'approved' WHERE id = ?";
        $params = [$doc_id];
        
        if ($companyId) {
            $query .= " AND company_id = ?";
            $params[] = $companyId;
        }
        
        $old = null;
        try {
            $chk = $pdo->prepare("SELECT status FROM documents WHERE id = ?" . ($companyId ? " AND company_id = ?" : ""));
            $p = [$doc_id];
            if ($companyId) $p[] = $companyId;
            $chk->execute($p);
            $old = $chk->fetchColumn();
        } catch (Exception $e) {}
        if (!hasApprovalRights($user_role, 'documents')) {
            header("Location: documents.php?notice=" . urlencode('Permission denied') . "&type=danger");
            exit;
        }
        $stmt = $pdo->prepare($query);
        $stmt->execute($params);
        if (function_exists('auditLogDetailed')) {
            auditLogDetailed('document', (int)$doc_id, $old, 'approved', 'List action');
        } else {
            logActivity($user_id, "Document Approved", "Approved document #$doc_id");
        }
        $success_msg = "Document approved.";
    } elseif ($action == 'reject') {
        $query = "UPDATE documents SET status = 'rejected' WHERE id = ?";
        $params = [$doc_id];
        
        if ($companyId) {
            $query .= " AND company_id = ?";
            $params[] = $companyId;
        }
        
        $old = null;
        try {
            $chk = $pdo->prepare("SELECT status FROM documents WHERE id = ?" . ($companyId ? " AND company_id = ?" : ""));
            $p = [$doc_id];
            if ($companyId) $p[] = $companyId;
            $chk->execute($p);
            $old = $chk->fetchColumn();
        } catch (Exception $e) {}
        if (!hasApprovalRights($user_role, 'documents')) {
            header("Location: documents.php?notice=" . urlencode('Permission denied') . "&type=danger");
            exit;
        }
        $stmt = $pdo->prepare($query);
        $stmt->execute($params);
        if (function_exists('auditLogDetailed')) {
            auditLogDetailed('document', (int)$doc_id, $old, 'rejected', 'List action');
        } else {
            logActivity($user_id, "Document Rejected", "Rejected document #$doc_id");
        }
        $success_msg = "Document rejected.";
    }
}

// Fetch Documents
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$limit = 10;
$offset = ($page - 1) * $limit;
$search_query = $_GET['search'] ?? '';

$query = "SELECT d.*, u.name as user_name, p.title as property_title, uploader.name as uploader_name,
                  (SELECT MAX(version_number) FROM document_versions WHERE document_id = d.id) as current_version
                  FROM documents d 
                  LEFT JOIN users u ON d.user_id = u.id 
                  LEFT JOIN properties p ON d.property_id = p.id
                  LEFT JOIN users uploader ON d.uploaded_by = uploader.id
                  WHERE 1=1";
$params = [];

if ($companyId) {
    $query .= " AND d.company_id = ?";
    $params[] = $companyId;
}

// Permissions
if (in_array($user_role, ['client', 'agent', 'sales_agent'])) {
    $query .= " AND (d.user_id = ? OR d.uploaded_by = ?)";
    $params[] = $user_id;
    $params[] = $user_id;
}

if (!empty($search_query)) {
    $query .= " AND (d.title LIKE ? OR u.name LIKE ? OR p.title LIKE ?)";
    $term = "%$search_query%";
    $params[] = $term; $params[] = $term; $params[] = $term;
}

$query .= " ORDER BY d.created_at DESC LIMIT $limit OFFSET $offset";
$stmt = $pdo->prepare($query);
$stmt->execute($params);
$documents = $stmt->fetchAll();

// Fetch Users/Properties for Upload Modal (Admin/Manager/Contact Centre/Marketing)
if (in_array($user_role, ['admin','super_admin','estate_manager','contact_rep','customer_rep','marketing','sales'])) {
    if ($companyId) {
        $users_stmt = $pdo->prepare("SELECT id, name, role FROM users WHERE company_id = ? ORDER BY name ASC");
        $users_stmt->execute([$companyId]);
        $users = $users_stmt->fetchAll();
        
        $props_stmt = $pdo->prepare("SELECT id, title FROM properties WHERE company_id = ? ORDER BY title ASC");
        $props_stmt->execute([$companyId]);
        $properties = $props_stmt->fetchAll();
    } else {
        $users = $pdo->query("SELECT id, name, role FROM users ORDER BY name ASC")->fetchAll();
        $properties = $pdo->query("SELECT id, title FROM properties ORDER BY title ASC")->fetchAll();
    }
}

include 'includes/header.php';
?>

<style>
    :root {
        --aiben-navy: #001F3F;
        --aiben-green: #2ECC40;
        --aiben-light-grey: #F8F9FA;
        --aiben-border: #E9ECEF;
    }

    body {
        background-color: #f4f6f9;
        font-family: 'Inter', system-ui, -apple-system, sans-serif;
    }

    /* KPI Cards */
    .kpi-card {
        background: white;
        border: 1px solid rgba(0,0,0,0.05);
        border-radius: 12px;
        padding: 1.25rem;
        transition: transform 0.2s, box-shadow 0.2s;
        height: 100%;
    }
    .kpi-card:hover {
        transform: translateY(-3px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.05);
    }
    .kpi-icon {
        width: 48px; height: 48px;
        border-radius: 12px;
        display: flex; align-items: center; justify-content: center;
        font-size: 1.25rem;
    }

    /* Table Styles */
    .table-card {
        background: white;
        border-radius: 12px;
        border: 1px solid rgba(0,0,0,0.05);
        overflow: hidden;
    }
    .table thead th {
        background-color: #f8f9fa;
        font-weight: 600;
        text-transform: uppercase;
        font-size: 0.75rem;
        letter-spacing: 0.5px;
        color: #6c757d;
        border-bottom: 1px solid #dee2e6;
        padding: 1rem;
    }
    .table tbody td {
        vertical-align: middle;
        padding: 1rem;
        border-bottom: 1px solid #f2f2f2;
    }
    .table-hover tbody tr:hover {
        background-color: #f8f9fa;
        cursor: pointer;
    }
    .avatar-circle {
        width: 36px; height: 36px;
        border-radius: 50%;
        display: flex; align-items: center; justify-content: center;
        font-weight: bold;
        font-size: 0.85rem;
    }
    
    /* Side Drawer */
    .side-drawer-backdrop {
        position: fixed;
        top: 0; left: 0; width: 100%; height: 100%;
        background: rgba(0,0,0,0.3);
        z-index: 1040;
        display: none;
        opacity: 0;
        transition: opacity 0.3s;
    }
    .side-drawer-backdrop.show {
        display: block;
        opacity: 1;
    }
    .side-drawer {
        position: fixed;
        top: 0; right: -500px;
        width: 500px; height: 100vh;
        background: white;
        z-index: 1050;
        box-shadow: -5px 0 30px rgba(0,0,0,0.1);
        transition: right 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
        overflow-y: auto;
    }
    .side-drawer.open {
        right: 0;
    }
    @media (max-width: 768px) {
        .side-drawer { width: 100%; right: -100%; }
    }
    .drawer-header {
        background: var(--aiben-navy);
        color: white;
        padding: 1.5rem;
    }
    .drawer-body {
        padding: 1.5rem;
    }

    /* Badge & Text Utilities */
    .text-navy { color: var(--aiben-navy) !important; }
    .bg-navy { background-color: var(--aiben-navy) !important; }
    .text-green { color: var(--aiben-green) !important; }
    .bg-green { background-color: var(--aiben-green) !important; }
    .doc-table-scroll{display:block;width:100%;max-width:100%;overflow:auto !important;overflow-x:auto !important;overflow-y:hidden;-webkit-overflow-scrolling:touch;touch-action:pan-x pan-y}
    .doc-table-scroll > table{width:max-content;min-width:980px}
    .doc-table-scroll th,.doc-table-scroll td{white-space:nowrap;vertical-align:middle}
    .doc-table-scroll td.doc-primary{white-space:normal;min-width:320px;max-width:520px}
    @media (max-width: 576px){
        .doc-header-actions{width:100%;justify-content:flex-start;flex-wrap:wrap}
        .doc-header-actions .btn{flex:1 1 auto}
    }
</style>

<div class="container-fluid px-4 py-4">
    <!-- Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 fw-bold text-navy mb-1">Document Management</h1>
            <p class="text-muted small mb-0">Manage and track all system documents and files.</p>
        </div>
        <div class="d-flex gap-2 doc-header-actions">
            <div class="btn-group">
                <a href="documents.php?view=list" class="btn btn-outline-primary <?= $view == 'list' ? 'active' : '' ?>"><i class="fa-solid fa-list me-1"></i>List</a>
                <a href="documents.php?view=kanban" class="btn btn-outline-primary <?= $view == 'kanban' ? 'active' : '' ?>"><i class="fa-solid fa-table-columns me-1"></i>Board</a>
            </div>
            <button class="btn btn-primary bg-navy border-0" data-bs-toggle="modal" data-bs-target="#uploadModal">
                <i class="fa-solid fa-cloud-arrow-up me-2"></i>Upload Document
            </button>
        </div>
    </div>

    <!-- Alerts -->
    <?php if (isset($success_msg)): ?>
        <div class="alert alert-success alert-dismissible fade show" role="alert">
            <i class="fa-solid fa-check-circle me-2"></i><?= htmlspecialchars($success_msg) ?>
            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
        </div>
    <?php endif; ?>

    <?php if (isset($error_msg)): ?>
        <div class="alert alert-danger alert-dismissible fade show" role="alert">
            <i class="fa-solid fa-exclamation-circle me-2"></i><?= htmlspecialchars($error_msg) ?>
            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
        </div>
    <?php endif; ?>

    <!-- KPIs -->
    <div class="row g-3 mb-4">
        <div class="col-md-3">
            <div class="kpi-card d-flex align-items-center justify-content-between">
                <div>
                    <div class="text-muted small fw-bold text-uppercase">Total Documents</div>
                    <div class="h2 mb-0 fw-bold text-navy"><?= number_format($kpis['total_docs']) ?></div>
                </div>
                <div class="kpi-icon bg-light text-navy"><i class="fa-solid fa-folder"></i></div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="kpi-card d-flex align-items-center justify-content-between">
                <div>
                    <div class="text-muted small fw-bold text-uppercase">Pending Review</div>
                    <div class="h2 mb-0 fw-bold text-warning"><?= number_format($kpis['pending']) ?></div>
                </div>
                <div class="kpi-icon bg-warning-subtle text-warning"><i class="fa-solid fa-hourglass-half"></i></div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="kpi-card d-flex align-items-center justify-content-between">
                <div>
                    <div class="text-muted small fw-bold text-uppercase">Approved</div>
                    <div class="h2 mb-0 fw-bold text-success"><?= number_format($kpis['approved']) ?></div>
                </div>
                <div class="kpi-icon bg-success-subtle text-success"><i class="fa-solid fa-check-double"></i></div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="kpi-card d-flex align-items-center justify-content-between">
                <div>
                    <div class="text-muted small fw-bold text-uppercase">Rejected</div>
                    <div class="h2 mb-0 fw-bold text-danger"><?= number_format($kpis['rejected']) ?></div>
                </div>
                <div class="kpi-icon bg-danger-subtle text-danger"><i class="fa-solid fa-ban"></i></div>
            </div>
        </div>
    </div>

    <!-- Filters & Search -->
    <div class="row g-3 mb-4">
        <div class="col-md-8">
            <form action="" method="GET" class="d-flex gap-2">
                <input type="hidden" name="view" value="<?= $view ?>">
                <div class="input-group" style="max-width: 300px;">
                    <span class="input-group-text bg-white border-end-0"><i class="fa-solid fa-magnifying-glass text-muted"></i></span>
                    <input type="text" name="search" class="form-control border-start-0 ps-0" placeholder="Search documents..." value="<?= htmlspecialchars($search_query) ?>">
                </div>
                <button type="submit" class="btn btn-light border">Search</button>
            </form>
        </div>
        <div class="col-md-4 text-end">
            <!-- Filter Dropdown placeholder -->
        </div>
    </div>

    <!-- Content Area -->
    <?php if ($view === 'list'): ?>
    <div class="table-card shadow-sm">
        <div class="d-sm-none px-3 py-2 small text-muted border-bottom">Swipe left/right to see all columns.</div>
        <div class="table-responsive doc-table-scroll">
            <table class="table table-hover mb-0">
                <thead>
                    <tr>
                        <th class="ps-4">Document</th>
                        <th class="d-none d-md-table-cell">Type</th>
                        <th class="d-none d-lg-table-cell">Related To</th>
                        <th class="d-none d-md-table-cell">Uploaded By</th>
                        <th>Status</th>
                        <th class="d-none d-lg-table-cell">Date</th>
                        <th class="text-end pe-4">Actions</th>
                    </tr>
                </thead>
                <tbody>
                    <?php if (count($documents) > 0): ?>
                        <?php foreach ($documents as $doc): ?>
                            <tr onclick="openDocumentDetails(<?= $doc['id'] ?>)">
                                <td class="ps-4 doc-primary">
                                    <div class="d-flex align-items-center">
                                        <div class="me-3 text-danger fs-4">
                                            <i class="fa-solid fa-file-pdf"></i>
                                        </div>
                                        <div>
                                            <div class="fw-bold text-navy"><?= htmlspecialchars($doc['title']) ?></div>
                                            <div class="small text-muted">v<?= $doc['current_version'] ?? '1.0' ?></div>
                                            <div class="small text-muted d-md-none">
                                                <?= ucfirst(str_replace('_', ' ', $doc['type'])) ?>
                                                · <?= ucfirst((string)$doc['status']) ?>
                                                · <?= htmlspecialchars(formatDate($doc['created_at'])) ?>
                                            </div>
                                            <div class="small text-muted d-lg-none">
                                                <?php if ($doc['user_name']): ?>
                                                    <?= htmlspecialchars($doc['user_name']) ?>
                                                <?php endif; ?>
                                                <?php if ($doc['property_title']): ?>
                                                    <?= $doc['user_name'] ? ' · ' : '' ?><i class="fa-solid fa-building me-1"></i><?= htmlspecialchars($doc['property_title']) ?>
                                                <?php endif; ?>
                                            </div>
                                        </div>
                                    </div>
                                </td>
                                <td class="d-none d-md-table-cell"><span class="badge bg-light text-dark border"><?= ucfirst(str_replace('_', ' ', $doc['type'])) ?></span></td>
                                <td class="d-none d-lg-table-cell">
                                    <?php if ($doc['user_name']): ?>
                                        <div class="fw-bold small"><?= htmlspecialchars($doc['user_name']) ?></div>
                                    <?php endif; ?>
                                    <?php if ($doc['property_title']): ?>
                                        <div class="small text-muted"><i class="fa-solid fa-building me-1"></i><?= htmlspecialchars($doc['property_title']) ?></div>
                                    <?php endif; ?>
                                </td>
                                <td class="d-none d-md-table-cell">
                                    <div class="small"><?= htmlspecialchars($doc['uploader_name'] ?? 'System') ?></div>
                                </td>
                                <td>
                                    <span class="badge <?= getStatusBadgeClass($doc['status']) ?>"><?= ucfirst($doc['status']) ?></span>
                                </td>
                                <td class="d-none d-lg-table-cell">
                                    <div class="small text-muted"><?= formatDate($doc['created_at']) ?></div>
                                </td>
                                <td class="text-end pe-4" onclick="event.stopPropagation()">
                                    <div class="dropdown">
                                        <button class="btn btn-sm btn-light border" type="button" data-bs-toggle="dropdown">
                                            <i class="fa-solid fa-ellipsis"></i>
                                        </button>
                                        <ul class="dropdown-menu dropdown-menu-end shadow border-0">
                                            <li><a class="dropdown-item" href="<?= htmlspecialchars($doc['file_path']) ?>" target="_blank"><i class="fa-solid fa-eye me-2"></i>View</a></li>
                                            <li><a class="dropdown-item" href="<?= htmlspecialchars($doc['file_path']) ?>" download><i class="fa-solid fa-download me-2"></i>Download</a></li>
                                            <li><hr class="dropdown-divider"></li>
                                            <li><button class="dropdown-item" onclick="openDocumentDetails(<?= $doc['id'] ?>)"><i class="fa-solid fa-circle-info me-2"></i>Details</button></li>
                                            <li><button class="dropdown-item" data-bs-toggle="modal" data-bs-target="#versionModal" data-id="<?= $doc['id'] ?>" data-title="<?= htmlspecialchars($doc['title']) ?>"><i class="fa-solid fa-code-branch me-2"></i>New Version</button></li>
                                            
                                            <?php if (in_array($user_role, ['admin', 'super_admin', 'estate_manager']) && $doc['status'] == 'pending'): ?>
                                                <li><hr class="dropdown-divider"></li>
                                                <li><button class="dropdown-item text-success" onclick="openDocumentStatusModal(<?= (int)$doc['id'] ?>,'approved')"><i class="fa-solid fa-check me-2"></i>Approve</button></li>
                                                <li><button class="dropdown-item text-danger" onclick="openDocumentStatusModal(<?= (int)$doc['id'] ?>,'rejected')"><i class="fa-solid fa-xmark me-2"></i>Reject</button></li>
                                            <?php endif; ?>
                                        </ul>
                                    </div>
                                </td>
                            </tr>
                        <?php endforeach; ?>
                    <?php else: ?>
                        <tr>
                            <td colspan="7" class="text-center py-5 text-muted">
                                <i class="fa-solid fa-folder-open fa-2x mb-3 d-block opacity-25"></i>
                                No documents found matching your criteria.
                            </td>
                        </tr>
                    <?php endif; ?>
                </tbody>
            </table>
        </div>
    </div>
    <?php else: ?>
        <!-- Kanban View (Basic Improvement) -->
        <div class="d-flex gap-3 overflow-auto pb-4">
            <?php
            $statuses = ['pending', 'approved', 'rejected', 'archived'];
            foreach ($statuses as $status):
                $items = array_filter($documents, function($d) use ($status) { return $d['status'] === $status; });
            ?>
            <div class="flex-shrink-0" style="width: 300px;">
                <div class="fw-bold mb-3 text-uppercase small text-muted d-flex justify-content-between">
                    <?= ucfirst($status) ?>
                    <span class="badge bg-light text-dark border"><?= count($items) ?></span>
                </div>
                <div class="d-flex flex-column gap-3">
                    <?php foreach ($items as $doc): ?>
                    <div class="card shadow-sm border-0 cursor-pointer" onclick="openDocumentDetails(<?= $doc['id'] ?>)">
                        <div class="card-body p-3">
                            <div class="d-flex justify-content-between mb-2">
                                <span class="badge bg-light text-dark border">v<?= $doc['current_version'] ?? '1.0' ?></span>
                                <i class="fa-solid fa-file-pdf text-danger"></i>
                            </div>
                            <h6 class="fw-bold mb-1 text-truncate"><?= htmlspecialchars($doc['title']) ?></h6>
                            <div class="small text-muted mb-2"><?= htmlspecialchars($doc['property_title'] ?? 'No Property') ?></div>
                            <div class="d-flex align-items-center justify-content-between mt-3 pt-2 border-top">
                                <div class="small text-muted"><?= formatDate($doc['created_at']) ?></div>
                                <div class="avatar-circle bg-navy text-white" style="width: 24px; height: 24px; font-size: 10px;">
                                    <?= substr($doc['user_name'] ?? 'U', 0, 1) ?>
                                </div>
                            </div>
                        </div>
                    </div>
                    <?php endforeach; ?>
                </div>
            </div>
            <?php endforeach; ?>
        </div>
    <?php endif; ?>
</div>

<!-- Upload Modal -->
<div class="modal fade" id="uploadModal" tabindex="-1">
    <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-fullscreen-sm-down">
        <form method="POST" enctype="multipart/form-data" class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title fw-bold">Upload Document</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body">
                <input type="hidden" name="upload_document" value="1">
                <div class="mb-3">
                    <label class="form-label">Title</label>
                    <input type="text" name="title" class="form-control" required placeholder="e.g. Lease Agreement">
                </div>
                <div class="mb-3">
                    <label class="form-label">Type</label>
                    <select name="type" class="form-select" required>
                        <option value="offer_letter">Offer Letter</option>
                        <option value="contract">Contract</option>
                        <option value="invoice">Invoice</option>
                        <option value="receipt">Receipt</option>
                        <option value="id_proof">ID Proof</option>
                        <option value="allocation_letter">Allocation Letter</option>
                        <option value="deed">Deed of Assignment</option>
                        <option value="survey">Survey Plan</option>
                        <option value="other">Other</option>
                    </select>
                </div>
                
                <?php if (isset($users)): ?>
                <div class="mb-3">
                    <label class="form-label">Related User (Optional)</label>
                    <select name="user_id" class="form-select">
                        <option value="">-- Select User --</option>
                        <?php foreach ($users as $u): ?>
                            <option value="<?= $u['id'] ?>"><?= htmlspecialchars($u['name']) ?> (<?= $u['role'] ?>)</option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <div class="mb-3">
                    <label class="form-label">Related Property (Optional)</label>
                    <select name="property_id" class="form-select">
                        <option value="">-- Select Property --</option>
                        <?php foreach ($properties as $p): ?>
                            <option value="<?= $p['id'] ?>"><?= htmlspecialchars($p['title']) ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <?php endif; ?>

                <div class="mb-3">
                    <label class="form-label">File</label>
                    <input type="file" name="file" class="form-control" required>
                    <div class="form-text">Allowed: PDF, DOCX, JPG, PNG</div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
                <button type="submit" class="btn btn-primary bg-navy">Upload</button>
            </div>
        </form>
    </div>
</div>

<!-- Version Modal -->
<div class="modal fade" id="versionModal" tabindex="-1">
    <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-fullscreen-sm-down">
        <form method="POST" enctype="multipart/form-data" class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title fw-bold">Upload New Version</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body">
                <input type="hidden" name="upload_version" value="1">
                <input type="hidden" name="doc_id" id="versionDocId">
                <div class="mb-3">
                    <label class="form-label">Document: <span id="versionDocTitle" class="fw-bold"></span></label>
                </div>
                <div class="mb-3">
                    <label class="form-label">Changelog / Note</label>
                    <textarea name="changelog" class="form-control" required placeholder="What changed?"></textarea>
                </div>
                <div class="mb-3">
                    <label class="form-label">New File</label>
                    <input type="file" name="version_file" class="form-control" required>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
                <button type="submit" class="btn btn-primary bg-navy">Upload Version</button>
            </div>
        </form>
    </div>
</div>

<!-- Side Drawer -->
<div class="side-drawer-backdrop" id="drawerBackdrop"></div>
<div class="side-drawer" id="sideDrawer">
    <div class="drawer-header d-flex justify-content-between align-items-center">
        <h5 class="mb-0 fw-bold">Document Details</h5>
        <button type="button" class="btn-close btn-close-white" onclick="closeDrawer()"></button>
    </div>
    <div class="drawer-body" id="drawerContent">
        <div class="text-center py-5">
            <div class="spinner-border text-navy" role="status">
                <span class="visually-hidden">Loading...</span>
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="docStatusModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
        <form class="modal-content" onsubmit="return submitDocumentStatusModal(event)">
            <div class="modal-header bg-white">
                <h6 class="modal-title">Update Document Status</h6>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <input type="hidden" id="doc_status_id" value="">
                <input type="hidden" id="doc_status_value" value="">
                <div class="mb-3">
                    <label class="form-label">Reason</label>
                    <textarea id="doc_status_reason" class="form-control" rows="4" required placeholder="Provide a reason for this status change"></textarea>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
                <button type="submit" class="btn btn-primary">Update Status</button>
            </div>
        </form>
    </div>
</div>

<script>
// Auto-open upload modal with prefilled values (wait until Bootstrap is available)
document.addEventListener('DOMContentLoaded', function(){
  var params = new URLSearchParams(window.location.search);
  if (params.get('open_upload') !== '1') return;
  document.cookie = 'allow_upload_nav=1; path=/; max-age=900';
  var clientId = params.get('client_id');
  var preTitle = params.get('prefill_title') || 'Offer Letter';
  var preType = params.get('prefill_type') || 'offer_letter';
  var propId = params.get('property_id');
  var titleEl = document.querySelector('#uploadModal input[name="title"]');
  var typeEl = document.querySelector('#uploadModal select[name="type"]');
  if (titleEl) titleEl.value = preTitle;
  if (typeEl) typeEl.value = preType;
  var userSel = document.querySelector('#uploadModal select[name="user_id"]');
  if (userSel && clientId) { userSel.value = clientId; }
  var propSel = document.querySelector('#uploadModal select[name="property_id"]');
  if (propSel && propId) { propSel.value = propId; }
  var modalEl = document.getElementById('uploadModal');
  function tryShowModal(){
    if (window.bootstrap && bootstrap.Modal) {
      var m = new bootstrap.Modal(modalEl);
      m.show();
      return true;
    }
    return false;
  }
  if (modalEl) {
    if (!tryShowModal()) {
      var attempts = 0;
      var iv = setInterval(function(){
        attempts++;
        if (tryShowModal() || attempts > 40) { clearInterval(iv); }
      }, 100);
    }
  }
});

// Server-side fallback to show upload modal without relying on Bootstrap
<?php if (isset($_GET['open_upload']) && $_GET['open_upload'] === '1'): ?>
document.addEventListener('DOMContentLoaded', function(){
  var el = document.getElementById('uploadModal');
  if (!el) return;
  el.classList.add('show');
  el.style.display = 'block';
  document.body.classList.add('modal-open');
  var bd = document.createElement('div');
  bd.className = 'modal-backdrop fade show';
  document.body.appendChild(bd);
});
<?php endif; ?>

// Ensure header Upload button opens the modal even if data attributes fail
document.addEventListener('DOMContentLoaded', function(){
  var btns = document.querySelectorAll('button[data-bs-target="#uploadModal"], a[data-bs-target="#uploadModal"]');
  var modalEl = document.getElementById('uploadModal');
  if (!modalEl || btns.length === 0) return;
  btns.forEach(function(btn){
    btn.addEventListener('click', function(){
      if (window.bootstrap && bootstrap.Modal) {
        var m = new bootstrap.Modal(modalEl);
        m.show();
      }
    });
  });
});

document.addEventListener('DOMContentLoaded', function(){
  var ok = <?= json_encode(isset($success_msg) && $success_msg ? true : false) ?>;
  if (!ok) return;
  // Keep modal open and act as a normal popup; do not auto-close
  document.cookie = 'allow_upload_nav=1; path=/; max-age=900';
  var modalEl = document.getElementById('uploadModal');
  if (modalEl) {
    // Optionally set focus back to Title input to continue uploading more
    var titleEl = modalEl.querySelector('input[name="title"]');
    if (titleEl) { try { titleEl.focus(); } catch(e){} }
  }
});

document.addEventListener('DOMContentLoaded', function(){
  var modalEl = document.getElementById('uploadModal');
  if (!modalEl) return;
  function hideModal() {
    modalEl.classList.remove('show');
    modalEl.style.display = 'none';
    document.body.classList.remove('modal-open');
    var bd2 = document.querySelector('.modal-backdrop');
    if (bd2 && bd2.parentNode) bd2.parentNode.removeChild(bd2);
  }
  var dismissEls = modalEl.querySelectorAll('[data-bs-dismiss="modal"]');
  dismissEls.forEach(function(btn){
    btn.addEventListener('click', function(){
      if (window.bootstrap && bootstrap.Modal) {
        var m = bootstrap.Modal.getInstance(modalEl) || new bootstrap.Modal(modalEl);
        m.hide();
      } else {
        hideModal();
      }
    });
  });
  document.addEventListener('click', function(e){
    var bd = document.querySelector('.modal-backdrop');
    if (bd && e.target === bd) hideModal();
  });
  document.addEventListener('keydown', function(e){
    if (e.key === 'Escape') {
      if (window.bootstrap && bootstrap.Modal) {
        var m = bootstrap.Modal.getInstance(modalEl) || new bootstrap.Modal(modalEl);
        m.hide();
      } else {
        hideModal();
      }
    }
  });
});
// Pass modal data
var versionModal = document.getElementById('versionModal');
versionModal.addEventListener('show.bs.modal', function (event) {
  var button = event.relatedTarget;
  var id = button.getAttribute('data-id');
  var title = button.getAttribute('data-title');
  document.getElementById('versionDocId').value = id;
  document.getElementById('versionDocTitle').textContent = title;
});

// Drawer Logic
function openDocumentDetails(id) {
    document.getElementById('drawerBackdrop').classList.add('show');
    document.getElementById('sideDrawer').classList.add('open');
    document.body.style.overflow = 'hidden';

    fetch(`ajax_get_document_details.php?id=${id}`)
        .then(response => response.json())
        .then(data => {
            if(data.success) {
                renderDetails(data);
            } else {
                document.getElementById('drawerContent').innerHTML = `<div class="alert alert-danger">${data.error}</div>`;
            }
        })
        .catch(err => {
            document.getElementById('drawerContent').innerHTML = `<div class="alert alert-danger">Failed to load details.</div>`;
        });
}

function closeDrawer() {
    document.getElementById('drawerBackdrop').classList.remove('show');
    document.getElementById('sideDrawer').classList.remove('open');
    document.body.style.overflow = 'auto';
    setTimeout(() => {
        document.getElementById('drawerContent').innerHTML = `
            <div class="text-center py-5">
                <div class="spinner-border text-navy" role="status">
                    <span class="visually-hidden">Loading...</span>
                </div>
            </div>`;
    }, 300);
}

document.getElementById('drawerBackdrop').addEventListener('click', closeDrawer);

function renderDetails(data) {
    const doc = data.document;
    const versions = data.versions;
    const history = data.history;

    let html = `
        <div class="text-center mb-4">
            <div class="bg-light rounded p-4 d-inline-block mb-3">
                <i class="fa-solid fa-file-pdf text-danger" style="font-size: 3rem;"></i>
            </div>
            <h5 class="fw-bold mb-1">${doc.title}</h5>
            <div class="text-muted small">v${doc.current_version || '1.0'} &bull; ${new Date(doc.created_at).toLocaleDateString()}</div>
            <div class="mt-3">
                <a href="${doc.file_path}" target="_blank" class="btn btn-primary btn-sm bg-navy"><i class="fa-solid fa-eye me-2"></i>View</a>
                <a href="${doc.file_path}" download class="btn btn-outline-secondary btn-sm"><i class="fa-solid fa-download me-2"></i>Download</a>
            </div>
        </div>

        <div class="card bg-light border-0 mb-4">
            <div class="card-body">
                <div class="row g-3">
                    <div class="col-6">
                        <div class="text-muted small">Type</div>
                        <div class="fw-bold">${doc.type.replace('_', ' ').toUpperCase()}</div>
                    </div>
                    <div class="col-6">
                        <div class="text-muted small">Status</div>
                        <div><span class="badge ${getStatusBadgeClass(doc.status)}">${doc.status.toUpperCase()}</span></div>
                    </div>
                    <div class="col-12">
                        <div class="text-muted small">Related To</div>
                        <div class="fw-bold">${doc.user_name || 'N/A'}</div>
                        <div class="small text-muted">${doc.property_title || 'No Property Linked'}</div>
                    </div>
                </div>
            </div>
        </div>

        <h6 class="fw-bold border-bottom pb-2 mb-3">Version History</h6>
        <div class="mb-4">
    `;

    if (versions.length > 0) {
        versions.forEach(v => {
            html += `
                <div class="d-flex gap-3 mb-3">
                    <div class="text-center" style="width: 40px;">
                        <div class="badge bg-secondary">v${v.version_number}</div>
                    </div>
                    <div>
                        <div class="small fw-bold">Uploaded by ${v.created_by_name}</div>
                        <div class="small text-muted">${new Date(v.created_at).toLocaleString()}</div>
                        <div class="small text-dark mt-1 fst-italic">"${v.changelog}"</div>
                        <a href="${v.file_path}" target="_blank" class="small text-primary text-decoration-none">View File</a>
                    </div>
                </div>
            `;
        });
    } else {
        html += `<div class="text-muted small">No version history available.</div>`;
    }

    html += `</div>`; // Close Versions

    // Actions
    // (Only show approve/reject if admin and pending)
    /* 
    if (doc.status === 'pending') {
        html += `
            <div class="d-grid gap-2 mt-4">
                <a href="?action=approve&id=${doc.id}" class="btn btn-success">Approve Document</a>
                <a href="?action=reject&id=${doc.id}" class="btn btn-outline-danger">Reject Document</a>
            </div>
        `;
    } 
    */
    // Since this is JS rendering, we'd normally check user role in JS or pass it in data.
    // For now, simpler to not duplicate complex permission logic in JS rendering without passing role.

    document.getElementById('drawerContent').innerHTML = html;
    
    // Helper function for status badge class
    function getStatusBadgeClass(status) {
        switch (status) {
            case 'approved': return 'bg-success';
            case 'pending': return 'bg-warning text-dark';
            case 'rejected': return 'bg-danger';
            default: return 'bg-secondary';
        }
    }
}

function openDocumentStatusModal(id, status) {
    var m = document.getElementById('docStatusModal');
    if (!m) return;
    document.getElementById('doc_status_id').value = id;
    document.getElementById('doc_status_value').value = status;
    document.getElementById('doc_status_reason').value = '';
    var modal = new bootstrap.Modal(m);
    modal.show();
}

async function submitDocumentStatusModal(e) {
    e.preventDefault();
    var id = document.getElementById('doc_status_id').value;
    var status = document.getElementById('doc_status_value').value;
    var reason = document.getElementById('doc_status_reason').value.trim();
    if (!reason) return false;
    const btns = document.querySelectorAll('button, a.btn');
    btns.forEach(b => b.disabled = true);
    try {
        const res = await fetch('ajax_update_document_status.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ id: Number(id), status: status, comment: reason })
        });
        const data = await res.json();
        if (data.success) {
            var m = bootstrap.Modal.getInstance(document.getElementById('docStatusModal'));
            if (m) m.hide();
            window.location.reload();
        } else {
            alert(data.message || 'Failed to update status');
        }
    } catch (e) {
        alert('Network error while updating status');
    } finally {
        btns.forEach(b => b.disabled = false);
    }
    return false;
}
</script>

Hry