| Server IP : 72.60.21.38 / Your IP : 216.73.216.25 Web 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 MySQL : OFF | cURL : ON | WGET : ON | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /home/u390967363/public_html/crm/ |
Upload File : |
<?php
session_start();
if (!isset($_SESSION['admin'])) {
header('Location: login.html');
exit();
}
require 'config.php';
include 'auth-guard.php';
// Handle deletion
if (isset($_GET['delete'])) {
$id = intval($_GET['delete']);
$conn->query("DELETE FROM crm_entries WHERE id = $id");
header('Location: leads.php');
exit();
}
// Handle conversion action
if (isset($_GET['convert'])) {
$id = intval($_GET['convert']);
// Fetch current status and follow_up_needed
$res = $conn->query("SELECT lead_status, follow_up_needed FROM crm_entries WHERE id=$id");
if ($res && $row = $res->fetch_assoc()) {
$statuses = explode(',', $row['lead_status']);
$statuses = array_map('trim', $statuses);
// Add "Converted" if not already in status
if (!in_array('Converted', $statuses)) {
$statuses[] = 'Converted';
}
// Remove "Follow-Up Needed" from status if exists
$statuses = array_filter($statuses, fn($s) => $s !== 'Follow-Up Needed');
// Set follow_up_needed to No
$newStatus = implode(', ', $statuses);
$conn->query("UPDATE crm_entries SET lead_status = '" . $conn->real_escape_string($newStatus) . "', follow_up_needed = 'No' WHERE id=$id");
}
header('Location: leads.php');
exit();
}
$result = $conn->query("SELECT * FROM crm_entries ORDER BY submitted_at DESC");
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>CRM Leads - Aiben CRM</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" />
<style>
/* Custom scrollbar for dropdown */
#filterDropdownOptions {
max-height: 300px;
overflow-y: auto;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex">
<!-- Sidebar -->
<aside class="fixed z-10 w-full md:w-64 bg-blue-800 text-white h-screen p-6 space-y-6 side" style="display:none;">
<div class="text-2xl font-bold text-white flex justify-between nowrap">
<img src="https://aibenproperties.com/wp-content/uploads/2024/09/logo-web.png" alt="Aiben Logo" class="h-7">
<button class="hover:cursor-pointer hover:text-red-400" id="close">
<i class="fas fa-close text-2xl cursor-pointer"></i>
</button>
</div>
<nav class="space-y-4">
<a href="dashboard_1.php" class="block py-2 px-3 rounded hover:bg-blue-700">Dashboard</a>
<a href="home-crm.php" class="block py-2 px-3 rounded hover:bg-blue-700">CRM Entries</a>
<a href="#" class="block py-2 px-3 rounded bg-blue-700">Leads</a>
<a href="logout.php" class="block py-2 px-3 rounded hover:bg-red-700 hover:text-white text-red-600 bg-white text-center font-semibold">Logout</a>
</nav>
</aside>
<!-- Main Content Area -->
<main class="flex-1 p-8 overflow-y-auto">
<h1 class="text-2xl font-bold text-gray-800 mb-4 flex items-center justify-between md:justify-end gap-4 md:flex-row-reverse">
CRM Leads
<button id="burger" class="block">
<i class="fas fa-bars text-2xl cursor-pointer"></i>
</button>
</h1>
<!-- Filter + Search -->
<div class="w-full md:flex items-center gap-4 mb-4 flex-nowrap justify-between">
<!-- Combined Dropdown Filter -->
<div class="relative inline-block text-left w-full md:w-72 flex-shrink-0 mb-4 md:mb-0">
<button id="filterDropdownBtn" type="button" class="inline-flex justify-between w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none" aria-expanded="true" aria-haspopup="true">
Filter Leads
<svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div id="filterDropdownOptions" class="origin-top-left absolute left-0 mt-2 w-full rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 hidden z-50">
<div class="p-4 space-y-4">
<div>
<h3 class="font-semibold mb-2">Purpose</h3>
<div id="purposeOptions" class="flex flex-col max-h-40 overflow-y-auto">
<!-- JS populate -->
</div>
</div>
<div>
<h3 class="font-semibold mb-2">Status</h3>
<div id="statusOptions" class="flex flex-col max-h-40 overflow-y-auto">
<!-- JS populate -->
</div>
</div>
<div>
<h3 class="font-semibold mb-2">Follow-Up Needed</h3>
<div id="followUpOptions" class="flex flex-col max-h-40 overflow-y-auto">
<!-- JS populate -->
</div>
</div>
</div>
</div>
</div>
<!-- Search Input -->
<input type="search" id="searchInput" placeholder="Search Name, Email, Phone..." class="px-4 py-2 border rounded w-full md:w-72 flex-shrink-0" />
</div>
<!-- Selected Filter Tags -->
<div id="selectedFilterTags" class="flex flex-wrap gap-2 w-full mb-4 flex-shrink overflow-hidden overflow-ellipsis whitespace-nowrap max-h-[20px] overflow-y-auto"></div>
<!-- Leads Table -->
<a href="download-leads.php" class="inline-block mb-4 px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700">
<i class="fas fa-file-csv mr-2"></i> Download CSV
</a>
<div class="overflow-auto">
<table id="leadsTable" class="min-w-full bg-white rounded-lg shadow-md">
<thead>
<tr class="bg-blue-800 text-white text-left">
<th class="p-3">#</th>
<th class="p-3">Name</th>
<th class="p-3">Email</th>
<th class="p-3">Phone</th>
<th class="p-3">Location</th>
<th class="p-3">Purpose</th>
<th class="p-3">Status</th>
<th class="p-3">F/U Needed</th>
<th class="p-3">F/U Date</th>
<th class="p-3">Assigned Staff</th>
<th class="p-3">Origin of Lead</th>
<th class="p-3">Caller Response</th>
<th class="p-3">Additional Info</th>
<th class="p-3">Date</th>
<th class="p-3">Actions</th>
</tr>
</thead>
<tbody>
<?php if ($result->num_rows > 0): ?>
<?php $i = 1; while($row = $result->fetch_assoc()): ?>
<tr class="border-t"
data-purpose="<?= htmlspecialchars($row['call_purpose']) ?>"
data-status="<?= htmlspecialchars($row['lead_status']) ?>"
data-followup="<?= htmlspecialchars($row['follow_up_needed']) ?>"
data-name="<?= htmlspecialchars(strtolower($row['caller_name'])) ?>"
data-email="<?= htmlspecialchars(strtolower($row['caller_email'])) ?>"
data-phone="<?= htmlspecialchars(strtolower($row['caller_phone'])) ?>"
>
<td class="p-3 text-sm text-gray-800"><?= $i++ ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['caller_name']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['caller_email']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['caller_phone']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['caller_location']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['call_purpose']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['lead_status']) ?></td>
<td>
<?php if ($row['follow_up_needed'] === 'Yes'): ?>
<span class="bg-yellow-200 text-yellow-800 px-2 py-1 rounded-full text-xs">Yes</span>
<?php else: ?>
<span class="bg-gray-200 text-gray-600 px-2 py-1 rounded-full text-xs">No</span>
<?php endif; ?>
</td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['follow_up_date']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['assigned_staff']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['source']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['caller_response']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['additional_info']) ?></td>
<td class="p-3 text-sm text-gray-800"><?= htmlspecialchars($row['submitted_at']) ?></td>
<td class="p-3 text-sm text-gray-800 space-x-2 flex items-center">
<?php
$statusesArray = array_map('trim', explode(',', $row['lead_status']));
if (!in_array('Converted', $statusesArray)):
?>
<a href="?convert=<?= $row['id'] ?>" onclick="return confirm('Mark this lead as converted?')" class="text-green-600 hover:underline">Convert</a>
<?php endif; ?>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="9" class="p-4 text-center text-gray-500">No leads found.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</main>
<script>
const filterBtn = document.getElementById('filterDropdownBtn');
const filterDropdown = document.getElementById('filterDropdownOptions');
const purposeOptionsDiv = document.getElementById('purposeOptions');
const statusOptionsDiv = document.getElementById('statusOptions');
const followUpOptionsDiv = document.getElementById('followUpOptions');
const selectedTagsDiv = document.getElementById('selectedFilterTags');
const searchInput = document.getElementById('searchInput');
const leadsTable = document.getElementById('leadsTable');
const leadsTbody = leadsTable.querySelector('tbody');
// Store selected filters
const selectedFilters = {
purpose: new Set(),
status: new Set(),
followup: new Set(),
};
// Utility to create checkbox option
function createOption(name, category) {
const id = `filter-${category}-${name.replace(/\s+/g,'_').toLowerCase()}`;
const label = document.createElement('label');
label.className = 'inline-flex items-center space-x-2 cursor-pointer mb-1';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = id;
checkbox.value = name;
checkbox.dataset.category = category;
checkbox.className = 'form-checkbox h-4 w-4 text-blue-600';
label.appendChild(checkbox);
const span = document.createElement('span');
span.textContent = name;
label.appendChild(span);
return label;
}
// Extract unique values from the table data attributes
function getUniqueValues(category) {
const rows = Array.from(leadsTbody.querySelectorAll('tr'));
const valuesSet = new Set();
rows.forEach(row => {
let val = row.dataset[category];
if (!val) return;
// For status and purpose, split by comma if multiple values
if (category === 'status' || category === 'purpose') {
val.split(',').forEach(v => valuesSet.add(v.trim()));
} else {
valuesSet.add(val.trim());
}
});
// Remove empty string entries
valuesSet.delete('');
return Array.from(valuesSet).sort();
}
// Populate options
function populateOptions() {
// Clear existing
purposeOptionsDiv.innerHTML = '';
statusOptionsDiv.innerHTML = '';
followUpOptionsDiv.innerHTML = '';
// Purpose
const purposes = getUniqueValues('purpose');
purposes.forEach(p => {
const option = createOption(p, 'purpose');
purposeOptionsDiv.appendChild(option);
});
// Status
const statuses = getUniqueValues('status');
statuses.forEach(s => {
const option = createOption(s, 'status');
statusOptionsDiv.appendChild(option);
});
// Follow-up needed (Yes, No)
['Yes', 'No'].forEach(fu => {
const option = createOption(fu, 'followup');
followUpOptionsDiv.appendChild(option);
});
}
// Render selected filter tags
function renderSelectedTags() {
selectedTagsDiv.innerHTML = '';
Object.entries(selectedFilters).forEach(([category, values]) => {
values.forEach(value => {
const tag = document.createElement('span');
tag.className = 'bg-blue-100 text-blue-800 px-3 py-1 rounded-full text-sm flex items-center space-x-1';
tag.textContent = `${capitalize(category)}: ${value}`;
const removeBtn = document.createElement('button');
removeBtn.innerHTML = '<i class="fas fa-times"></i>';
removeBtn.className = 'ml-1 hover:text-red-600';
removeBtn.title = 'Remove filter';
removeBtn.onclick = () => {
// Remove from selected filters
selectedFilters[category].delete(value);
// Uncheck checkbox in dropdown
const id = `filter-${category}-${value.replace(/\s+/g,'_').toLowerCase()}`;
const checkbox = document.getElementById(id);
if (checkbox) checkbox.checked = false;
renderSelectedTags();
filterTable();
};
tag.appendChild(removeBtn);
selectedTagsDiv.appendChild(tag);
});
});
}
// Capitalize first letter
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
// Filter table rows based on selected filters and search
function filterTable() {
const searchTerm = searchInput.value.trim().toLowerCase();
const rows = leadsTbody.querySelectorAll('tr');
rows.forEach(row => {
let show = true;
// Filter Purpose
if (selectedFilters.purpose.size > 0) {
const rowPurposes = row.dataset.purpose.toLowerCase().split(',').map(s => s.trim());
if (![...selectedFilters.purpose].some(f => rowPurposes.includes(f.toLowerCase()))) {
show = false;
}
}
// Filter Status
if (show && selectedFilters.status.size > 0) {
const rowStatuses = row.dataset.status.toLowerCase().split(',').map(s => s.trim());
if (![...selectedFilters.status].some(f => rowStatuses.includes(f.toLowerCase()))) {
show = false;
}
}
// Filter Follow-Up Needed
if (show && selectedFilters.followup.size > 0) {
const rowFollowUp = row.dataset.followup.toLowerCase();
if (![...selectedFilters.followup].some(f => f.toLowerCase() === rowFollowUp)) {
show = false;
}
}
// Filter Search by Name, Email, Phone
if (show && searchTerm.length > 0) {
const name = row.dataset.name || '';
const email = row.dataset.email || '';
const phone = row.dataset.phone || '';
if (!name.includes(searchTerm) && !email.includes(searchTerm) && !phone.includes(searchTerm)) {
show = false;
}
}
row.style.display = show ? '' : 'none';
});
}
// Event Listeners for filter checkbox changes
function setupCheckboxListeners() {
[purposeOptionsDiv, statusOptionsDiv, followUpOptionsDiv].forEach(container => {
container.addEventListener('change', e => {
if (e.target && e.target.type === 'checkbox') {
const category = e.target.dataset.category;
const val = e.target.value;
if (e.target.checked) {
selectedFilters[category].add(val);
} else {
selectedFilters[category].delete(val);
}
renderSelectedTags();
filterTable();
}
});
});
}
// Toggle dropdown
filterBtn.addEventListener('click', () => {
filterDropdown.classList.toggle('hidden');
});
// Close dropdown if clicked outside
document.addEventListener('click', (e) => {
if (!filterBtn.contains(e.target) && !filterDropdown.contains(e.target)) {
filterDropdown.classList.add('hidden');
}
});
// Search input listener
searchInput.addEventListener('input', () => {
filterTable();
});
// Initialize
populateOptions();
setupCheckboxListeners();
renderSelectedTags();
// Sidebar toggles (same as your original)
const closeBtn = document.getElementById('close');
const side = document.querySelector('aside');
const burger = document.getElementById('burger');
closeBtn.addEventListener('click', () => {
if (side.style.display === "none") {
side.style.display = "block";
} else {
side.style.display = "none";
burger.style.display = "flex";
}
});
burger.addEventListener('click', () => {
if (burger.style.display === "none") {
burger.style.display = "flex";
} else {
burger.style.display = "none";
side.style.display = "block";
}
});
</script>
</body>
</html>