diff --git a/assets/css/custom.css b/assets/css/custom.css index b16900a..33dbcdd 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -289,3 +289,31 @@ table th { color: white; } +/* --- Charts --- */ +.dashboard-charts { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); + gap: 1.5rem; + margin-top: 2rem; +} + +.chart-container { + background-color: var(--color-surface-light); + padding: 1.5rem; + border-radius: var(--border-radius); + border: 1px solid var(--border-color); +} + +.chart-title { + margin-top: 0; + margin-bottom: 1.5rem; + font-weight: 600; + font-size: 1.1rem; + text-align: center; +} + +body.dark-mode .chart-container { + background-color: var(--color-surface-light); + border-color: var(--border-color); +} + diff --git a/assets/js/main.js b/assets/js/main.js index cf3dffd..2c64d19 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -45,4 +45,83 @@ document.addEventListener('DOMContentLoaded', () => { if (typeof feather !== 'undefined') { feather.replace(); } + + // -- CHARTS INITIALIZATION -- + // Check if chartData is defined (it's passed from index.php) + if (typeof chartData !== 'undefined') { + const pieCtx = document.getElementById('loadsByStatusChart'); + const barCtx = document.getElementById('monthlyLoadsChart'); + + // Define colors that work with the theme + const chartColors = { + primary: 'rgba(184, 134, 11, 0.8)', // Golden + secondary: 'rgba(169, 169, 169, 0.8)', // Gray + accent: 'rgba(212, 175, 55, 0.8)', // Lighter Gold + success: 'rgba(40, 167, 69, 0.8)', + danger: 'rgba(220, 53, 69, 0.8)', + info: 'rgba(23, 162, 184, 0.8)', + }; + + if (pieCtx) { + new Chart(pieCtx, { + type: 'pie', + data: { + labels: chartData.loadsByStatus.labels, + datasets: [{ + label: 'Loads', + data: chartData.loadsByStatus.counts, + backgroundColor: [ + chartColors.info, + chartColors.primary, + chartColors.success, + chartColors.danger, + chartColors.secondary + ], + borderWidth: 1 + }] + }, + options: { + responsive: true, + plugins: { + legend: { + position: 'top', + } + } + } + }); + } + + if (barCtx) { + new Chart(barCtx, { + type: 'bar', + data: { + labels: chartData.monthlyLoads.labels, + datasets: [{ + label: 'Loads Created', + data: chartData.monthlyLoads.counts, + backgroundColor: chartColors.primary, + borderColor: chartColors.accent, + borderWidth: 1 + }] + }, + options: { + responsive: true, + scales: { + y: { + beginAtZero: true, + ticks: { // Make sure Y-axis ticks are integers + stepSize: 1, + callback: function(value) { if (Number.isInteger(value)) { return value; } } + } + } + }, + plugins: { + legend: { + display: false + } + } + } + }); + } + } }); diff --git a/drivers.php b/drivers.php index 2e1d8dc..a8eca2c 100644 --- a/drivers.php +++ b/drivers.php @@ -1,16 +1,132 @@ - +prepare($sql); + $stmt->execute(['name' => $name, 'email' => $email, 'phone' => $phone, 'status' => $status]); + // Redirect to avoid form resubmission + header("Location: drivers.php"); + exit; + } catch (PDOException $e) { + $error_message = "Database error: " . $e->getMessage(); + } + } +} + +// Create drivers table if it doesn't exist +try { + $pdo = db(); + $pdo->exec("CREATE TABLE IF NOT EXISTS drivers ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL, + phone VARCHAR(50) NOT NULL, + status VARCHAR(50) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )"); +} catch (PDOException $e) { + die("Could not create table: " . $e->getMessage()); +} + +// Fetch all drivers +try { + $pdo = db(); + $stmt = $pdo->query("SELECT id, name, email, phone, status, created_at FROM drivers ORDER BY created_at DESC"); + $drivers = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + $error_message = "Database error: " . $e->getMessage(); +} + +include 'includes/header.php'; +?>
-

Drivers

+

Manage Drivers

-
-

Driver management content will go here.

+
+

Add New Driver

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ +
+

All Drivers

+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NameContactStatusJoined
No drivers found.
+
+ +
+
- + \ No newline at end of file diff --git a/includes/footer.php b/includes/footer.php index 635d499..7b6b92a 100644 --- a/includes/footer.php +++ b/includes/footer.php @@ -1,5 +1,6 @@ + diff --git a/index.php b/index.php index acf65ce..c8fe36d 100644 --- a/index.php +++ b/index.php @@ -1,38 +1,102 @@ - + +// --- DATA FETCHING --- +$pdo = db(); + +// Card metrics +$total_loads = $pdo->query('SELECT count(*) FROM loads')->fetchColumn(); +$total_drivers = $pdo->query('SELECT count(*) FROM drivers')->fetchColumn(); +$in_transit_loads = $pdo->query('SELECT count(*) FROM loads WHERE status = "In-Transit"')->fetchColumn(); +$delivered_loads = $pdo->query('SELECT count(*) FROM loads WHERE status = "Delivered"')->fetchColumn(); + +// Pie Chart: Loads by Status +$loads_by_status_stmt = $pdo->query('SELECT status, count(*) as count FROM loads GROUP BY status'); +$loads_by_status = $loads_by_status_stmt->fetchAll(PDO::FETCH_ASSOC); +$status_labels = []; +$status_counts = []; +foreach ($loads_by_status as $row) { + $status_labels[] = $row['status']; + $status_counts[] = $row['count']; +} + +// Bar Chart: Loads per month +// Using a default of 0 for all months of the current year +$monthly_counts = array_fill(1, 12, 0); +$loads_by_month_stmt = $pdo->query(" + SELECT + CAST(strftime('%m', pickup_date) AS INTEGER) as month, + count(*) as count + FROM loads + WHERE strftime('%Y', pickup_date) = strftime('%Y', 'now') + GROUP BY month +"); +$loads_by_month = $loads_by_month_stmt->fetchAll(PDO::FETCH_ASSOC); + +foreach ($loads_by_month as $row) { + $monthly_counts[$row['month']] = $row['count']; +} +$monthly_labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; +$monthly_values = array_values($monthly_counts); + + +include 'includes/header.php'; +include 'includes/sidebar.php'; +?>
-

Dashboard Overview

- +

Reports & Analytics

-
ACTIVE LOADS
-
42
-
+2 since yesterday
+
TOTAL LOADS
+
+
All time
-
DRIVERS ON-ROUTE
-
35
-
+5.2%
+
TOTAL DRIVERS
+
+
All time
-
REVENUE TODAY
-
$18,450
-
+12% vs avg.
+
IN-TRANSIT NOW
+
+
 
-
PENDING ISSUES
-
3
-
1 new alert
+
COMPLETED LOADS
+
+
 
- +
+
+

Loads by Status

+ +
+
+

Monthly Load Volume (This Year)

+ +
+
- + + + \ No newline at end of file