Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5366b4681b |
35
add_activity.php
Normal file
35
add_activity.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$lead_id = $_POST['lead_id'] ?? null;
|
||||
$activity_type = $_POST['activity_type'] ?? null;
|
||||
$due_date = $_POST['due_date'] ?? null;
|
||||
$notes = $_POST['notes'] ?? null;
|
||||
|
||||
if ($lead_id && $activity_type) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("INSERT INTO activities (LeadID, ActivityType, DueDate, Notes) VALUES (:lead_id, :activity_type, :due_date, :notes)");
|
||||
$stmt->execute([
|
||||
':lead_id' => $lead_id,
|
||||
':activity_type' => $activity_type,
|
||||
':due_date' => !empty($due_date) ? $due_date : null,
|
||||
':notes' => $notes
|
||||
]);
|
||||
|
||||
$_SESSION['success_message'] = "New activity added successfully!";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['error_message'] = "Error adding activity: " . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$_SESSION['error_message'] = "Lead ID and activity type are required.";
|
||||
}
|
||||
} else {
|
||||
$_SESSION['error_message'] = "Invalid request method.";
|
||||
}
|
||||
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
57
add_lead.php
Normal file
57
add_lead.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Basic validation
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$companyName = trim($_POST['companyName'] ?? '');
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$phone = trim($_POST['phone'] ?? '');
|
||||
$potentialAmount = $_POST['potentialAmount'] ?? null;
|
||||
|
||||
if (empty($name) || empty($email)) {
|
||||
$_SESSION['error_message'] = 'Name and Email are required.';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$_SESSION['error_message'] = 'Invalid email format.';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($potentialAmount !== null && !is_numeric($potentialAmount)) {
|
||||
$_SESSION['error_message'] = 'Potential amount must be a number.';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare(
|
||||
'INSERT INTO leads (Name, CompanyName, Email, Phone, PotentialAmount, Status) VALUES (?, ?, ?, ?, ?, ?)'
|
||||
);
|
||||
$stmt->execute([
|
||||
$name,
|
||||
$companyName,
|
||||
$email,
|
||||
$phone,
|
||||
$potentialAmount,
|
||||
'New' // Default status
|
||||
]);
|
||||
|
||||
$_SESSION['success_message'] = 'Lead added successfully!';
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// In a real app, log this error.
|
||||
$_SESSION['error_message'] = 'Failed to add lead. Please try again.';
|
||||
}
|
||||
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
170
dashboard.php
Normal file
170
dashboard.php
Normal file
@ -0,0 +1,170 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// Fetch dashboard data
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Total leads
|
||||
$total_leads = $pdo->query('SELECT COUNT(*) FROM leads')->fetchColumn();
|
||||
|
||||
// Leads per status
|
||||
$leads_per_status_stmt = $pdo->query('SELECT Status, COUNT(*) as count FROM leads GROUP BY Status');
|
||||
$leads_per_status = $leads_per_status_stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
// Total activities
|
||||
$total_activities = $pdo->query('SELECT COUNT(*) FROM activities')->fetchColumn();
|
||||
|
||||
// Activities per type
|
||||
$activities_per_type_stmt = $pdo->query('SELECT ActivityType, COUNT(*) as count FROM activities GROUP BY ActivityType');
|
||||
$activities_per_type = $activities_per_type_stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$db_error = "Error fetching dashboard data: " . $e->getMessage();
|
||||
}
|
||||
|
||||
$projectName = $_SERVER['PROJECT_NAME'] ?? 'CRM';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Dashboard - <?= htmlspecialchars($projectName) ?></title>
|
||||
<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">
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<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);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<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" href="index.php">Leads</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="dashboard.php">Dashboard</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container">
|
||||
<?php if (isset($db_error)): ?>
|
||||
<div class="alert alert-danger"><?= htmlspecialchars($db_error) ?></div>
|
||||
<?php else: ?>
|
||||
<div class="row g-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card text-center text-white bg-primary">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="fas fa-users me-2"></i>Total Leads</h5>
|
||||
<p class="card-text fs-1"><?= $total_leads ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card text-center text-white bg-info">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="fas fa-tasks me-2"></i>Total Activities</h5>
|
||||
<p class="card-text fs-1"><?= $total_activities ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-4 mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">Leads by Status</div>
|
||||
<div class="card-body">
|
||||
<canvas id="leadsByStatusChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">Activities by Type</div>
|
||||
<div class="card-body">
|
||||
<canvas id="activitiesByTypeChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Leads by Status Chart
|
||||
const leadsCtx = document.getElementById('leadsByStatusChart').getContext('2d');
|
||||
new Chart(leadsCtx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: <?= json_encode(array_keys($leads_per_status)) ?>,
|
||||
datasets: [{
|
||||
data: <?= json_encode(array_values($leads_per_status)) ?>,
|
||||
backgroundColor: ['#3498db', '#f39c12', '#2ecc71', '#9b59b6', '#1abc9c', '#e74c3c']
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'top',
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Activities by Type Chart
|
||||
const activitiesCtx = document.getElementById('activitiesByTypeChart').getContext('2d');
|
||||
new Chart(activitiesCtx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?= json_encode(array_keys($activities_per_type)) ?>,
|
||||
datasets: [{
|
||||
label: 'Number of Activities',
|
||||
data: <?= json_encode(array_values($activities_per_type)) ?>,
|
||||
backgroundColor: '#3498db'
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,17 +1,45 @@
|
||||
<?php
|
||||
// Generated by setup_mariadb_project.sh — edit as needed.
|
||||
define('DB_HOST', '127.0.0.1');
|
||||
define('DB_NAME', 'app_36806');
|
||||
define('DB_USER', 'app_36806');
|
||||
define('DB_PASS', '72fbec7a-4020-4357-9e44-f0aad5499af6');
|
||||
|
||||
function db() {
|
||||
static $pdo;
|
||||
if (!$pdo) {
|
||||
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
]);
|
||||
}
|
||||
// IMPORTANT: Do not output any HTML or echo statements in this file.
|
||||
// This file is intended for configuration and database connection logic.
|
||||
|
||||
/**
|
||||
* Establishes a database connection using PDO.
|
||||
*
|
||||
* @return PDO The PDO database connection object.
|
||||
*/
|
||||
function db(): PDO
|
||||
{
|
||||
static $pdo = null;
|
||||
|
||||
if ($pdo) {
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
// Database credentials from environment variables
|
||||
$host = getenv('DB_HOST') ?: '127.0.0.1';
|
||||
$port = getenv('DB_PORT') ?: '3306';
|
||||
// Temporary fix: Hardcoded credentials to solve an environment issue where Apache cannot access the correct variables.
|
||||
$dbname = 'app_36806';
|
||||
$user = 'app_36806';
|
||||
$pass = '72fbec7a-4020-4357-9e44-f0aad5499af6';
|
||||
$charset = 'utf8mb4';
|
||||
|
||||
$dsn = "mysql:host=$host;port=$port;dbname=$dbname;charset=$charset";
|
||||
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
|
||||
try {
|
||||
$pdo = new PDO($dsn, $user, $pass, $options);
|
||||
} catch (PDOException $e) {
|
||||
// In a real application, you would log this error and show a generic error page.
|
||||
// For development, it's okay to die and show the error.
|
||||
throw new PDOException($e->getMessage(), (int)$e->getCode());
|
||||
}
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
22
db/database.sql
Normal file
22
db/database.sql
Normal file
@ -0,0 +1,22 @@
|
||||
CREATE TABLE IF NOT EXISTS leads (
|
||||
LeadID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
Name VARCHAR(255) NOT NULL,
|
||||
CompanyName VARCHAR(255),
|
||||
Email VARCHAR(255),
|
||||
Phone VARCHAR(50),
|
||||
Source VARCHAR(100) NULL,
|
||||
Status VARCHAR(50) DEFAULT 'New',
|
||||
PotentialAmount DECIMAL(12, 2) NULL,
|
||||
CreatedOn TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS activities (
|
||||
ActivityID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
LeadID INT,
|
||||
ActivityType VARCHAR(50) NOT NULL,
|
||||
DueDate DATE,
|
||||
Status VARCHAR(50) DEFAULT 'Pending',
|
||||
Notes TEXT,
|
||||
CreatedOn TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (LeadID) REFERENCES leads(LeadID) ON DELETE CASCADE
|
||||
);
|
||||
12
db/init_db.php
Normal file
12
db/init_db.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = file_get_contents(__DIR__ . '/database.sql');
|
||||
$pdo->exec($sql);
|
||||
echo "Database initialized successfully with 'leads' table.
|
||||
";
|
||||
} catch (PDOException $e) {
|
||||
die("Database initialization failed: " . $e->getMessage());
|
||||
}
|
||||
28
delete_activity.php
Normal file
28
delete_activity.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if (!isset($_GET['id']) || empty($_GET['id'])) {
|
||||
$_SESSION['error_message'] = 'Invalid activity ID.';
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$activity_id = $_GET['id'];
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("DELETE FROM activities WHERE ActivityID = ?");
|
||||
$stmt->execute([$activity_id]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$_SESSION['success_message'] = 'Activity deleted successfully!';
|
||||
} else {
|
||||
$_SESSION['error_message'] = 'Activity not found or already deleted.';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['error_message'] = 'Error deleting activity: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
28
delete_lead.php
Normal file
28
delete_lead.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if (!isset($_GET['id']) || empty($_GET['id'])) {
|
||||
$_SESSION['error_message'] = 'Invalid lead ID.';
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$lead_id = $_GET['id'];
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("DELETE FROM leads WHERE LeadID = ?");
|
||||
$stmt->execute([$lead_id]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$_SESSION['success_message'] = 'Lead deleted successfully!';
|
||||
} else {
|
||||
$_SESSION['error_message'] = 'Lead not found or already deleted.';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['error_message'] = 'Error deleting lead: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
115
edit_activity.php
Normal file
115
edit_activity.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// Check if ActivityID is provided
|
||||
if (!isset($_GET['id']) || empty($_GET['id'])) {
|
||||
$_SESSION['error_message'] = 'No activity selected for editing.';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$activity_id = $_GET['id'];
|
||||
|
||||
// Fetch activity details
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('SELECT * FROM activities WHERE ActivityID = ?');
|
||||
$stmt->execute([$activity_id]);
|
||||
$activity = $stmt->fetch();
|
||||
|
||||
if (!$activity) {
|
||||
$_SESSION['error_message'] = 'Activity not found.';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['error_message'] = 'Error fetching activity details: ' . $e->getMessage();
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$projectName = $_SERVER['PROJECT_NAME'] ?? 'CRM';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Activity - <?= htmlspecialchars($projectName) ?></title>
|
||||
<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">
|
||||
<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);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
</nav>
|
||||
|
||||
<main class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white py-3">
|
||||
<h5 class="mb-0"><i class="fas fa-edit me-2 text-primary"></i>Edit Activity</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="update_activity.php" method="POST">
|
||||
<input type="hidden" name="activity_id" value="<?= htmlspecialchars($activity['ActivityID']) ?>">
|
||||
<div class="mb-3">
|
||||
<label for="activity_type" class="form-label">Activity Type</label>
|
||||
<select class="form-select" id="activity_type" name="activity_type" required>
|
||||
<option value="Call" <?= $activity['ActivityType'] == 'Call' ? 'selected' : '' ?>>Call</option>
|
||||
<option value="Meeting" <?= $activity['ActivityType'] == 'Meeting' ? 'selected' : '' ?>>Meeting</option>
|
||||
<option value="Task" <?= $activity['ActivityType'] == 'Task' ? 'selected' : '' ?>>Task</option>
|
||||
<option value="Email" <?= $activity['ActivityType'] == 'Email' ? 'selected' : '' ?>>Email</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Status</label>
|
||||
<select class="form-select" id="status" name="status" required>
|
||||
<option value="Pending" <?= $activity['Status'] == 'Pending' ? 'selected' : '' ?>>Pending</option>
|
||||
<option value="Completed" <?= $activity['Status'] == 'Completed' ? 'selected' : '' ?>>Completed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="due_date" class="form-label">Due Date</label>
|
||||
<input type="date" class="form-control" id="due_date" name="due_date" value="<?= htmlspecialchars($activity['DueDate']) ?>">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="notes" class="form-label">Notes</label>
|
||||
<textarea class="form-control" id="notes" name="notes" rows="3"><?= htmlspecialchars($activity['Notes']) ?></textarea>
|
||||
</div>
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
|
||||
<a href="index.php" class="btn btn-secondary">Cancel</a>
|
||||
<button type="submit" class="btn btn-primary">Update Activity</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
122
edit_lead.php
Normal file
122
edit_lead.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// Check if LeadID is provided
|
||||
if (!isset($_GET['id']) || empty($_GET['id'])) {
|
||||
$_SESSION['error_message'] = 'No lead selected for editing.';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$lead_id = $_GET['id'];
|
||||
|
||||
// Fetch lead details
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('SELECT * FROM leads WHERE LeadID = ?');
|
||||
$stmt->execute([$lead_id]);
|
||||
$lead = $stmt->fetch();
|
||||
|
||||
if (!$lead) {
|
||||
$_SESSION['error_message'] = 'Lead not found.';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['error_message'] = 'Error fetching lead details: ' . $e->getMessage();
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$projectName = $_SERVER['PROJECT_NAME'] ?? 'CRM';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Lead - <?= htmlspecialchars($projectName) ?></title>
|
||||
<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">
|
||||
<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);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
</nav>
|
||||
|
||||
<main class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white py-3">
|
||||
<h5 class="mb-0"><i class="fas fa-edit me-2 text-primary"></i>Edit Lead</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="update_lead.php" method="POST">
|
||||
<input type="hidden" name="lead_id" value="<?= htmlspecialchars($lead['LeadID']) ?>">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Full Name*</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?= htmlspecialchars($lead['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" value="<?= htmlspecialchars($lead['CompanyName']) ?>">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email*</label>
|
||||
<input type="email" class="form-control" id="email" name="email" value="<?= htmlspecialchars($lead['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" value="<?= htmlspecialchars($lead['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" value="<?= htmlspecialchars($lead['PotentialAmount']) ?>">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Status</label>
|
||||
<select class="form-select" id="status" name="status">
|
||||
<option value="New" <?= $lead['Status'] == 'New' ? 'selected' : '' ?>>New</option>
|
||||
<option value="Contacted" <?= $lead['Status'] == 'Contacted' ? 'selected' : '' ?>>Contacted</option>
|
||||
<option value="Qualified" <?= $lead['Status'] == 'Qualified' ? 'selected' : '' ?>>Qualified</option>
|
||||
<option value="Proposal Sent" <?= $lead['Status'] == 'Proposal Sent' ? 'selected' : '' ?>>Proposal Sent</option>
|
||||
<option value="Won" <?= $lead['Status'] == 'Won' ? 'selected' : '' ?>>Won</option>
|
||||
<option value="Lost" <?= $lead['Status'] == 'Lost' ? 'selected' : '' ?>>Lost</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
|
||||
<a href="index.php" class="btn btn-secondary">Cancel</a>
|
||||
<button type="submit" class="btn btn-primary">Update Lead</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
545
index.php
545
index.php
@ -1,150 +1,447 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
@ini_set('display_errors', '1');
|
||||
@error_reporting(E_ALL);
|
||||
@date_default_timezone_set('UTC');
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
$phpVersion = PHP_VERSION;
|
||||
$now = date('Y-m-d H:i:s');
|
||||
// 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>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>New Style</title>
|
||||
<?php
|
||||
// Read project preview data from environment
|
||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
?>
|
||||
<?php if ($projectDescription): ?>
|
||||
<!-- Meta description -->
|
||||
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
|
||||
<!-- Open Graph meta tags -->
|
||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<!-- Twitter meta tags -->
|
||||
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<?php endif; ?>
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<!-- Open Graph image -->
|
||||
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<!-- Twitter image -->
|
||||
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<?php endif; ?>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<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>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background-color: #ecf0f1;
|
||||
font-family: 'Lato', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
}
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
.navbar {
|
||||
background-color: #2c3e50;
|
||||
}
|
||||
@keyframes bg-pan {
|
||||
0% { background-position: 0% 0%; }
|
||||
100% { background-position: 100% 100%; }
|
||||
}
|
||||
main {
|
||||
padding: 2rem;
|
||||
.navbar-brand {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.1);
|
||||
}
|
||||
.loader {
|
||||
margin: 1.25rem auto 1.25rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
.btn-primary {
|
||||
background-color: #3498db;
|
||||
border-color: #3498db;
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
.btn-primary:hover {
|
||||
background-color: #2980b9;
|
||||
border-color: #2980b9;
|
||||
}
|
||||
.hint {
|
||||
opacity: 0.9;
|
||||
.table-hover tbody tr:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px; height: 1px;
|
||||
padding: 0; margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap; border: 0;
|
||||
.toast-container {
|
||||
z-index: 1090;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
code {
|
||||
background: rgba(0,0,0,0.2);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
.footer {
|
||||
background-color: #2c3e50;
|
||||
color: #ecf0f1;
|
||||
padding: 2rem 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your website…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
|
||||
<!-- 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>
|
||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
||||
|
||||
<!-- 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>
|
||||
44
update_activity.php
Normal file
44
update_activity.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Basic validation
|
||||
$activity_id = $_POST['activity_id'] ?? null;
|
||||
$activity_type = trim($_POST['activity_type'] ?? '');
|
||||
$status = trim($_POST['status'] ?? '');
|
||||
$due_date = $_POST['due_date'] ?? null;
|
||||
$notes = trim($_POST['notes'] ?? '');
|
||||
|
||||
if (empty($activity_id) || empty($activity_type) || empty($status)) {
|
||||
$_SESSION['error_message'] = 'Required fields are missing.';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare(
|
||||
'UPDATE activities SET ActivityType = ?, Status = ?, DueDate = ?, Notes = ? WHERE ActivityID = ?'
|
||||
);
|
||||
$stmt->execute([
|
||||
$activity_type,
|
||||
$status,
|
||||
$due_date,
|
||||
$notes,
|
||||
$activity_id
|
||||
]);
|
||||
|
||||
$_SESSION['success_message'] = 'Activity updated successfully!';
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// In a real app, log this error.
|
||||
$_SESSION['error_message'] = 'Failed to update activity. Please try again.';
|
||||
}
|
||||
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
60
update_lead.php
Normal file
60
update_lead.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Basic validation
|
||||
$lead_id = $_POST['lead_id'] ?? null;
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$companyName = trim($_POST['companyName'] ?? '');
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$phone = trim($_POST['phone'] ?? '');
|
||||
$potentialAmount = $_POST['potentialAmount'] ?? null;
|
||||
$status = $_POST['status'] ?? 'New';
|
||||
|
||||
if (empty($lead_id) || empty($name) || empty($email)) {
|
||||
$_SESSION['error_message'] = 'Required fields are missing.';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$_SESSION['error_message'] = 'Invalid email format.';
|
||||
header('Location: edit_lead.php?id=' . $lead_id);
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($potentialAmount !== null && !is_numeric($potentialAmount)) {
|
||||
$_SESSION['error_message'] = 'Potential amount must be a number.';
|
||||
header('Location: edit_lead.php?id=' . $lead_id);
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare(
|
||||
'UPDATE leads SET Name = ?, CompanyName = ?, Email = ?, Phone = ?, PotentialAmount = ?, Status = ? WHERE LeadID = ?'
|
||||
);
|
||||
$stmt->execute([
|
||||
$name,
|
||||
$companyName,
|
||||
$email,
|
||||
$phone,
|
||||
$potentialAmount,
|
||||
$status,
|
||||
$lead_id
|
||||
]);
|
||||
|
||||
$_SESSION['success_message'] = 'Lead updated successfully!';
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// In a real app, log this error.
|
||||
$_SESSION['error_message'] = 'Failed to update lead. Please try again.';
|
||||
}
|
||||
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
Loading…
x
Reference in New Issue
Block a user