447 lines
22 KiB
PHP
447 lines
22 KiB
PHP
<?php
|
|
session_start();
|
|
require_once __DIR__ . '/db/config.php';
|
|
|
|
// Fetch all leads
|
|
try {
|
|
$pdo = db();
|
|
|
|
$sql = 'SELECT LeadID, Name, CompanyName, Email, Phone, PotentialAmount, Status, CreatedOn FROM leads';
|
|
$params = [];
|
|
$where_clauses = [];
|
|
|
|
if (isset($_GET['status']) && !empty($_GET['status'])) {
|
|
$where_clauses[] = 'Status = ?';
|
|
$params[] = $_GET['status'];
|
|
}
|
|
|
|
if (isset($_GET['search']) && !empty($_GET['search'])) {
|
|
$search_term = '%' . $_GET['search'] . '%';
|
|
$where_clauses[] = '(Name LIKE ? OR Email LIKE ? OR CompanyName LIKE ?)';
|
|
$params[] = $search_term;
|
|
$params[] = $search_term;
|
|
$params[] = $search_term;
|
|
}
|
|
|
|
if (!empty($where_clauses)) {
|
|
$sql .= ' WHERE ' . implode(' AND ', $where_clauses);
|
|
}
|
|
|
|
$sql .= ' ORDER BY CreatedOn DESC';
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$leads = $stmt->fetchAll();
|
|
|
|
// Fetch all activities
|
|
$stmt = $pdo->query('SELECT ActivityID, LeadID, ActivityType, DueDate, Status, Notes, CreatedOn FROM activities ORDER BY DueDate ASC');
|
|
$all_activities = $stmt->fetchAll();
|
|
|
|
// Group activities by LeadID for easy lookup
|
|
$activitiesByLead = [];
|
|
foreach ($all_activities as $activity) {
|
|
$activitiesByLead[$activity['LeadID']][] = $activity;
|
|
}
|
|
|
|
} catch (PDOException $e) {
|
|
$leads = [];
|
|
$activitiesByLead = [];
|
|
$db_error = "Error fetching data: " . $e->getMessage();
|
|
}
|
|
|
|
$success_message = $_SESSION['success_message'] ?? null;
|
|
$error_message = $_SESSION['error_message'] ?? null;
|
|
|
|
// Clear session messages
|
|
unset($_SESSION['success_message'], $_SESSION['error_message']);
|
|
|
|
$projectName = $_SERVER['PROJECT_NAME'] ?? 'CRM';
|
|
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'A simple and powerful CRM for your business.';
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title><?= htmlspecialchars($projectName) ?> - Leads</title>
|
|
|
|
<!-- SEO Meta Tags -->
|
|
<meta name="description" content="<?= htmlspecialchars($projectDescription) ?>">
|
|
<meta name="robots" content="index, follow">
|
|
|
|
<!-- Open Graph / Twitter -->
|
|
<meta property="og:title" content="<?= htmlspecialchars($projectName) ?>">
|
|
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>">
|
|
<meta property="og:image" content="<?= $_SERVER['PROJECT_IMAGE_URL'] ?? '' ?>">
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
|
|
<!-- Stylesheets -->
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
|
|
<!-- Favicon -->
|
|
<link rel="icon" href="/favicon.ico" sizes="any">
|
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
|
|
<style>
|
|
body {
|
|
background-color: #ecf0f1;
|
|
font-family: 'Lato', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
}
|
|
.navbar {
|
|
background-color: #2c3e50;
|
|
}
|
|
.navbar-brand {
|
|
font-weight: bold;
|
|
color: #fff;
|
|
}
|
|
.card {
|
|
border: none;
|
|
border-radius: 0.5rem;
|
|
box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.1);
|
|
}
|
|
.btn-primary {
|
|
background-color: #3498db;
|
|
border-color: #3498db;
|
|
}
|
|
.btn-primary:hover {
|
|
background-color: #2980b9;
|
|
border-color: #2980b9;
|
|
}
|
|
.table-hover tbody tr:hover {
|
|
background-color: #f8f9fa;
|
|
}
|
|
.toast-container {
|
|
z-index: 1090;
|
|
}
|
|
.footer {
|
|
background-color: #2c3e50;
|
|
color: #ecf0f1;
|
|
padding: 2rem 0;
|
|
font-size: 0.9rem;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<!-- Navigation -->
|
|
<nav class="navbar navbar-expand-lg navbar-dark mb-4">
|
|
<div class="container">
|
|
<a class="navbar-brand" href="index.php"><i class="fas fa-chart-line me-2"></i><?= htmlspecialchars($projectName) ?></a>
|
|
<div class="collapse navbar-collapse">
|
|
<ul class="navbar-nav ms-auto">
|
|
<li class="nav-item">
|
|
<a class="nav-link active" href="index.php">Leads</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="dashboard.php">Dashboard</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Main Content -->
|
|
<main class="container">
|
|
<div class="row g-4">
|
|
|
|
<!-- Add Lead Form -->
|
|
<div class="col-lg-4">
|
|
<div class="card">
|
|
<div class="card-header bg-white py-3">
|
|
<h5 class="mb-0"><i class="fas fa-plus-circle me-2 text-primary"></i>Add New Lead</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form action="add_lead.php" method="POST">
|
|
<div class="mb-3">
|
|
<label for="name" class="form-label">Full Name*</label>
|
|
<input type="text" class="form-control" id="name" name="name" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="companyName" class="form-label">Company Name</label>
|
|
<input type="text" class="form-control" id="companyName" name="companyName">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="email" class="form-label">Email*</label>
|
|
<input type="email" class="form-control" id="email" name="email" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="phone" class="form-label">Phone</label>
|
|
<input type="tel" class="form-control" id="phone" name="phone">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="potentialAmount" class="form-label">Potential Amount ($)</label>
|
|
<input type="number" step="0.01" class="form-control" id="potentialAmount" name="potentialAmount">
|
|
</div>
|
|
<div class="d-grid">
|
|
<button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane me-2"></i>Submit Lead</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Leads List -->
|
|
<div class="col-lg-8">
|
|
<div class="card">
|
|
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0"><i class="fas fa-users me-2"></i>Current Leads</h5>
|
|
<div class="d-flex">
|
|
<form action="index.php" method="GET" class="d-flex">
|
|
<div class="input-group me-2">
|
|
<input type="text" class="form-control" name="search" placeholder="Search..." value="<?= htmlspecialchars($_GET['search'] ?? '') ?>">
|
|
<button class="btn btn-outline-secondary" type="submit"><i class="fas fa-search"></i></button>
|
|
</div>
|
|
<select class="form-select me-2" name="status" onchange="this.form.submit()">
|
|
<option value="">All Statuses</option>
|
|
<option value="New" <?= (isset($_GET['status']) && $_GET['status'] == 'New') ? 'selected' : '' ?>>New</option>
|
|
<option value="Contacted" <?= (isset($_GET['status']) && $_GET['status'] == 'Contacted') ? 'selected' : '' ?>>Contacted</option>
|
|
<option value="Qualified" <?= (isset($_GET['status']) && $_GET['status'] == 'Qualified') ? 'selected' : '' ?>>Qualified</option>
|
|
<option value="Proposal Sent" <?= (isset($_GET['status']) && $_GET['status'] == 'Proposal Sent') ? 'selected' : '' ?>>Proposal Sent</option>
|
|
<option value="Won" <?= (isset($_GET['status']) && $_GET['status'] == 'Won') ? 'selected' : '' ?>>Won</option>
|
|
<option value="Lost" <?= (isset($_GET['status']) && $_GET['status'] == 'Lost') ? 'selected' : '' ?>>Lost</option>
|
|
</select>
|
|
</form>
|
|
<a href="index.php" class="btn btn-secondary">Clear</a>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<?php if (isset($db_error)): ?>
|
|
<div class="alert alert-danger"><?= htmlspecialchars($db_error) ?></div>
|
|
<?php elseif (empty($leads)): ?>
|
|
<div class="text-center p-4">
|
|
<p class="mb-0 text-muted">No leads yet. Add one using the form!</p>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Company</th>
|
|
<th>Contact</th>
|
|
<th>Potential</th>
|
|
<th>Status</th>
|
|
<th>Date</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($leads as $lead): ?>
|
|
<tr>
|
|
<td><?= htmlspecialchars($lead['Name']) ?></td>
|
|
<td><?= htmlspecialchars($lead['CompanyName']) ?></td>
|
|
<td>
|
|
<a href="mailto:<?= htmlspecialchars($lead['Email']) ?>" class="text-decoration-none"><?= htmlspecialchars($lead['Email']) ?></a>
|
|
</td>
|
|
<td>$<?= number_format($lead['PotentialAmount'], 2) ?></td>
|
|
<td>
|
|
<?php
|
|
$status_color = 'bg-secondary';
|
|
switch ($lead['Status']) {
|
|
case 'New':
|
|
$status_color = 'bg-primary';
|
|
break;
|
|
case 'Contacted':
|
|
$status_color = 'bg-info';
|
|
break;
|
|
case 'Qualified':
|
|
$status_color = 'bg-success';
|
|
break;
|
|
case 'Proposal Sent':
|
|
$status_color = 'bg-warning';
|
|
break;
|
|
case 'Won':
|
|
$status_color = 'bg-success';
|
|
break;
|
|
case 'Lost':
|
|
$status_color = 'bg-danger';
|
|
break;
|
|
}
|
|
?>
|
|
<span class="badge <?= $status_color ?>"><?= htmlspecialchars($lead['Status']) ?></span>
|
|
</td>
|
|
<td><?= date('M d, Y', strtotime($lead['CreatedOn'])) ?></td>
|
|
<td>
|
|
<a href="edit_lead.php?id=<?= $lead['LeadID'] ?>" class="btn btn-sm btn-outline-secondary">
|
|
<i class="fas fa-edit me-1"></i> Edit
|
|
</a>
|
|
<a href="delete_lead.php?id=<?= $lead['LeadID'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this lead?');">
|
|
<i class="fas fa-trash-alt me-1"></i> Delete
|
|
</a>
|
|
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#activitiesModal" data-lead-id="<?= $lead['LeadID'] ?>" data-lead-name="<?= htmlspecialchars($lead['Name']) ?>">
|
|
<i class="fas fa-tasks me-1"></i> View Activities
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Activities Modal -->
|
|
<div class="modal fade" id="activitiesModal" tabindex="-1" aria-labelledby="activitiesModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="activitiesModalLabel">Activities for <span id="leadName"></span></h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div id="activitiesList">
|
|
<!-- Activities will be loaded here dynamically -->
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addActivityModal">
|
|
<i class="fas fa-plus-circle me-1"></i> Add Activity
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Activity Modal -->
|
|
<div class="modal fade" id="addActivityModal" tabindex="-1" aria-labelledby="addActivityModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="addActivityModalLabel">Add New Activity</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form action="add_activity.php" method="POST">
|
|
<input type="hidden" id="leadIdField" name="lead_id">
|
|
<div class="mb-3">
|
|
<label for="activityType" class="form-label">Activity Type</label>
|
|
<select class="form-select" id="activityType" name="activity_type" required>
|
|
<option value="Call">Call</option>
|
|
<option value="Meeting">Meeting</option>
|
|
<option value="Task">Task</option>
|
|
<option value="Email">Email</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="dueDate" class="form-label">Due Date</label>
|
|
<input type="date" class="form-control" id="dueDate" name="due_date">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="notes" class="form-label">Notes</label>
|
|
<textarea class="form-control" id="notes" name="notes" rows="3"></textarea>
|
|
</div>
|
|
<div class="d-grid">
|
|
<button type="submit" class="btn btn-primary">Save Activity</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Footer -->
|
|
<footer class="footer mt-5">
|
|
<div class="container text-center">
|
|
<p>© <?= date('Y') ?> <?= htmlspecialchars($projectName) ?>. All Rights Reserved.</p>
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- Toast Notifications -->
|
|
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
|
<?php if ($success_message): ?>
|
|
<div id="successToast" class="toast align-items-center text-white bg-success border-0" role="alert" aria-live="assertive" aria-atomic="true">
|
|
<div class="d-flex">
|
|
<div class="toast-body"><?= htmlspecialchars($success_message) ?></div>
|
|
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($error_message): ?>
|
|
<div id="errorToast" class="toast align-items-center text-white bg-danger border-0" role="alert" aria-live="assertive" aria-atomic="true">
|
|
<div class="d-flex">
|
|
<div class="toast-body"><?= htmlspecialchars($error_message) ?></div>
|
|
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Scripts -->
|
|
<script>
|
|
const activitiesByLead = <?= json_encode($activitiesByLead) ?>;
|
|
const activitiesModal = document.getElementById('activitiesModal');
|
|
const addActivityModal = document.getElementById('addActivityModal');
|
|
|
|
activitiesModal.addEventListener('show.bs.modal', function (event) {
|
|
const button = event.relatedTarget;
|
|
const leadId = button.getAttribute('data-lead-id');
|
|
const leadName = button.getAttribute('data-lead-name');
|
|
|
|
// Update modal title
|
|
const modalTitle = activitiesModal.querySelector('#leadName');
|
|
modalTitle.textContent = leadName;
|
|
|
|
// Populate activities list
|
|
const activitiesList = activitiesModal.querySelector('#activitiesList');
|
|
const activities = activitiesByLead[leadId] || [];
|
|
|
|
if (activities.length > 0) {
|
|
let html = '<ul class="list-group">';
|
|
activities.forEach(activity => {
|
|
html += `<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h6 class="mb-1">${activity.ActivityType}</h6>
|
|
<small class="text-muted">Due: ${activity.DueDate ? new Date(activity.DueDate).toLocaleDateString() : 'N/A'}</small>
|
|
<p class="mb-0">${activity.Notes || ''}</p>
|
|
</div>
|
|
<div class="d-flex align-items-center">
|
|
<span class="badge bg-info rounded-pill me-3">${activity.Status}</span>
|
|
<div>
|
|
<a href="edit_activity.php?id=${activity.ActivityID}" class="btn btn-sm btn-outline-secondary">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
<a href="delete_activity.php?id=${activity.ActivityID}" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this activity?');">
|
|
<i class="fas fa-trash-alt"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</li>`;
|
|
});
|
|
html += '</ul>';
|
|
activitiesList.innerHTML = html;
|
|
} else {
|
|
activitiesList.innerHTML = '<p class="text-center text-muted">No activities scheduled for this lead.</p>';
|
|
}
|
|
|
|
// Set lead ID for the 'Add Activity' modal
|
|
const leadIdField = addActivityModal.querySelector('#leadIdField');
|
|
leadIdField.value = leadId;
|
|
});
|
|
|
|
</script>
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
var successToastEl = document.getElementById('successToast');
|
|
if (successToastEl) {
|
|
var successToast = new bootstrap.Toast(successToastEl);
|
|
successToast.show();
|
|
}
|
|
|
|
var errorToastEl = document.getElementById('errorToast');
|
|
if (errorToastEl) {
|
|
var errorToast = new bootstrap.Toast(errorToastEl);
|
|
errorToast.show();
|
|
}
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|