This commit is contained in:
Flatlogic Bot 2026-02-15 01:02:26 +00:00
parent 10ea0441d5
commit 444cd73cc6
4 changed files with 635 additions and 48 deletions

View File

@ -157,3 +157,60 @@ body {
font-size: 0.7rem;
}
/* Calendar Styles */
.calendar-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 1px;
background-color: #e2e8f0;
border: 1px solid #e2e8f0;
border-radius: 0.375rem;
overflow: hidden;
}
.calendar-day {
background-color: #ffffff;
min-height: 100px;
padding: 0.75rem;
position: relative;
transition: background-color 0.2s;
}
.calendar-day:hover {
background-color: #f8fafc;
}
.calendar-header-day {
background-color: #f1f5f9;
text-align: center;
padding: 0.75rem;
font-weight: 700;
text-transform: uppercase;
font-size: 0.75rem;
color: #64748b;
letter-spacing: 0.05em;
}
.day-number {
font-weight: 600;
color: #94a3b8;
font-size: 0.875rem;
}
.day-hours {
position: absolute;
bottom: 0.75rem;
right: 0.75rem;
font-size: 1.125rem;
font-weight: 700;
color: #3b82f6;
}
.other-month {
background-color: #f8fafc;
}
.other-month .day-number {
color: #e2e8f0;
}

View File

@ -0,0 +1,7 @@
-- Add new fields to projects table
ALTER TABLE projects
ADD COLUMN owner_id INT NULL AFTER tenant_id,
ADD COLUMN estimated_completion_date DATE NULL AFTER start_date,
ADD COLUMN type ENUM('Internal', 'SRED') NOT NULL DEFAULT 'Internal' AFTER code,
ADD COLUMN estimated_hours DECIMAL(10,2) NOT NULL DEFAULT 0.00 AFTER type,
ADD CONSTRAINT fk_project_owner FOREIGN KEY (owner_id) REFERENCES employees(id) ON DELETE SET NULL;

256
index.php
View File

@ -87,10 +87,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_project'])) {
$name = $_POST['name'] ?? '';
$code = $_POST['code'] ?? '';
$start_date = $_POST['start_date'] ?? date('Y-m-d');
$owner_id = !empty($_POST['owner_id']) ? (int)$_POST['owner_id'] : null;
$est_completion = !empty($_POST['estimated_completion_date']) ? $_POST['estimated_completion_date'] : null;
$type = $_POST['type'] ?? 'Internal';
$est_hours = (float)($_POST['estimated_hours'] ?? 0);
if ($name && $code) {
$stmt = db()->prepare("INSERT INTO projects (tenant_id, name, code, start_date) VALUES (?, ?, ?, ?)");
$stmt->execute([$tenant_id, $name, $code, $start_date]);
$stmt = db()->prepare("INSERT INTO projects (tenant_id, name, code, start_date, owner_id, estimated_completion_date, type, estimated_hours) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$tenant_id, $name, $code, $start_date, $owner_id, $est_completion, $type, $est_hours]);
// Log Activity
$stmt = db()->prepare("INSERT INTO activity_log (tenant_id, action, details) VALUES (?, ?, ?)");
@ -206,51 +210,57 @@ $date_preset = $_GET['date_preset'] ?? '';
$start_from = $_GET['start_from'] ?? '';
$start_to = $_GET['start_to'] ?? '';
$query = "SELECT * FROM projects WHERE tenant_id = ?";
$query = "
SELECT p.*,
CONCAT(e.first_name, ' ', e.last_name) as owner_name,
COALESCE((SELECT SUM(hours) FROM labour_entries WHERE project_id = p.id), 0) as total_hours
FROM projects p
LEFT JOIN employees e ON p.owner_id = e.id
WHERE p.tenant_id = ?";
$params = [$tenant_id];
if ($search) {
$query .= " AND (name LIKE ? OR code LIKE ?)";
$query .= " AND (p.name LIKE ? OR p.code LIKE ?)";
$params[] = "%$search%";
$params[] = "%$search%";
}
if ($status_filter) {
$query .= " AND status = ?";
$query .= " AND p.status = ?";
$params[] = $status_filter;
}
if ($date_preset && $date_preset !== 'custom') {
switch ($date_preset) {
case 'today':
$query .= " AND start_date = CURRENT_DATE";
$query .= " AND p.start_date = CURRENT_DATE";
break;
case 'this_week':
$query .= " AND start_date >= DATE_SUB(CURRENT_DATE, INTERVAL WEEKDAY(CURRENT_DATE) DAY)";
$query .= " AND p.start_date >= DATE_SUB(CURRENT_DATE, INTERVAL WEEKDAY(CURRENT_DATE) DAY)";
break;
case 'last_week':
$query .= " AND start_date >= DATE_SUB(CURRENT_DATE, INTERVAL WEEKDAY(CURRENT_DATE) + 7 DAY) AND start_date < DATE_SUB(CURRENT_DATE, INTERVAL WEEKDAY(CURRENT_DATE) DAY)";
$query .= " AND p.start_date >= DATE_SUB(CURRENT_DATE, INTERVAL WEEKDAY(CURRENT_DATE) + 7 DAY) AND p.start_date < DATE_SUB(CURRENT_DATE, INTERVAL WEEKDAY(CURRENT_DATE) DAY)";
break;
case 'this_month':
$query .= " AND start_date >= DATE_FORMAT(CURRENT_DATE, '%Y-%m-01')";
$query .= " AND p.start_date >= DATE_FORMAT(CURRENT_DATE, '%Y-%m-01')";
break;
case 'last_month':
$query .= " AND start_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH), '%Y-%m-01') AND start_date < DATE_FORMAT(CURRENT_DATE, '%Y-%m-01')";
$query .= " AND p.start_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH), '%Y-%m-01') AND p.start_date < DATE_FORMAT(CURRENT_DATE, '%Y-%m-01')";
break;
case 'this_year':
$query .= " AND start_date >= DATE_FORMAT(CURRENT_DATE, '%Y-01-01')";
$query .= " AND p.start_date >= DATE_FORMAT(CURRENT_DATE, '%Y-01-01')";
break;
case 'last_year':
$query .= " AND start_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR), '%Y-01-01') AND start_date < DATE_FORMAT(CURRENT_DATE, '%Y-01-01')";
$query .= " AND p.start_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR), '%Y-01-01') AND p.start_date < DATE_FORMAT(CURRENT_DATE, '%Y-01-01')";
break;
}
} elseif ($date_preset === 'custom' && $start_from && $start_to) {
$query .= " AND start_date BETWEEN ? AND ?";
$query .= " AND p.start_date BETWEEN ? AND ?";
$params[] = $start_from;
$params[] = $start_to;
}
$query .= " ORDER BY created_at DESC";
$query .= " ORDER BY p.created_at DESC";
$projects = db()->prepare($query);
$projects->execute($params);
$projectList = $projects->fetchAll();
@ -310,6 +320,29 @@ $expenseEntries = db()->prepare("
$expenseEntries->execute([$tenant_id]);
$expenseList = $expenseEntries->fetchAll();
// Fetch Chart Data
$chart_days = isset($_GET['chart_days']) ? (int)$_GET['chart_days'] : 7;
if (!in_array($chart_days, [7, 14, 30])) $chart_days = 7;
$chartDataQuery = db()->prepare("
SELECT entry_date, SUM(hours) as total_hours
FROM labour_entries
WHERE tenant_id = ? AND entry_date > DATE_SUB(CURRENT_DATE, INTERVAL ? DAY)
GROUP BY entry_date
ORDER BY entry_date ASC
");
$chartDataQuery->execute([$tenant_id, $chart_days]);
$rawChartData = $chartDataQuery->fetchAll(PDO::FETCH_KEY_PAIR);
// Fill missing dates
$chartLabels = [];
$chartValues = [];
for ($i = $chart_days - 1; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-$i days"));
$chartLabels[] = date('M d', strtotime($date));
$chartValues[] = (float)($rawChartData[$date] ?? 0);
}
$activities = db()->prepare("SELECT * FROM activity_log WHERE tenant_id = ? ORDER BY created_at DESC LIMIT 10");
$activities->execute([$tenant_id]);
$activityList = $activities->fetchAll();
@ -326,6 +359,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'SR&ED Project Tracking
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link href="assets/css/custom.css?v=<?= time() ?>" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
@ -373,7 +407,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'SR&ED Project Tracking
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">Reports</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Labour Summary</a></li>
<li><a class="dropdown-item" href="reports.php?report_type=labour_export">Labour Export</a></li>
<li><a class="dropdown-item" href="reports.php?report_type=calendar">Monthly Calendar</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Project Expenses</a></li>
<li><a class="dropdown-item" href="#">SR&ED Claim Export</a></li>
</ul>
@ -388,8 +424,29 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'SR&ED Project Tracking
</nav>
<div class="container-fluid py-4">
<!-- Dashboard Chart Section -->
<div class="row mb-4">
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white d-flex justify-content-between align-items-center py-3">
<h5 class="mb-0 fw-bold">Labour Hours Overview</h5>
<div class="btn-group btn-group-sm">
<a href="?chart_days=7" class="btn btn-outline-primary <?= $chart_days == 7 ? 'active' : '' ?>">7 Days</a>
<a href="?chart_days=14" class="btn btn-outline-primary <?= $chart_days == 14 ? 'active' : '' ?>">14 Days</a>
<a href="?chart_days=30" class="btn btn-outline-primary <?= $chart_days == 30 ? 'active' : '' ?>">30 Days</a>
</div>
</div>
<div class="card-body">
<div style="height: 300px;">
<canvas id="hoursChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-9">
<div class="col-lg-12">
<?php if (isset($_GET['success'])): ?>
<div class="alert alert-success alert-dismissible fade show border-0 shadow-sm mb-4" role="alert">
<?php
@ -422,21 +479,40 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'SR&ED Project Tracking
<thead>
<tr>
<th>Project Name</th>
<th>Code</th>
<th>Start Date</th>
<th>Owner</th>
<th>Type</th>
<th>Hours (Logged/Est)</th>
<th>Variance</th>
<th>Status</th>
<th class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($projectList)): ?>
<tr><td colspan="5" class="text-center py-4 text-muted">No projects found matching the filters.</td></tr>
<tr><td colspan="7" class="text-center py-4 text-muted">No projects found matching the filters.</td></tr>
<?php endif; ?>
<?php foreach ($projectList as $p): ?>
<?php foreach ($projectList as $p):
$total_hours = (float)$p['total_hours'];
$est_hours = (float)$p['estimated_hours'];
$variance = $est_hours - $total_hours;
$is_over = $total_hours > $est_hours && $est_hours > 0;
?>
<tr>
<td><strong><?= htmlspecialchars($p['name']) ?></strong></td>
<td><code class="text-primary"><?= htmlspecialchars($p['code']) ?></code></td>
<td><?= $p['start_date'] ?></td>
<td>
<strong><?= htmlspecialchars($p['name']) ?></strong><br>
<code class="extra-small text-primary"><?= htmlspecialchars($p['code']) ?></code>
</td>
<td><small><?= htmlspecialchars($p['owner_name'] ?: 'Unassigned') ?></small></td>
<td><span class="badge bg-light text-dark border"><?= $p['type'] ?></span></td>
<td>
<span class="fw-bold <?= $is_over ? 'text-danger' : '' ?>"><?= number_format($total_hours, 1) ?></span>
<span class="text-muted">/ <?= number_format($est_hours, 1) ?></span>
</td>
<td>
<span class="fw-bold <?= $is_over ? 'text-danger' : 'text-success' ?>">
<?= ($variance >= 0 ? '+' : '') . number_format($variance, 1) ?>
</span>
</td>
<td><span class="status-badge status-<?= str_replace('_', '-', $p['status']) ?>"><?= ucfirst(str_replace('_', ' ', $p['status'])) ?></span></td>
<td class="text-end">
<button class="btn btn-sm btn-outline-secondary">Edit</button>
@ -627,29 +703,46 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'SR&ED Project Tracking
</div>
</div>
</div>
</div>
<div class="col-lg-3">
<div class="card">
<div class="card-header">Activity Hub</div>
<div class="card-body p-3">
<ul class="activity-feed">
<?php foreach ($activityList as $a): ?>
<li class="activity-item">
<div class="fw-bold small"><?= htmlspecialchars($a['action']) ?></div>
<div class="text-muted extra-small"><?= htmlspecialchars($a['details']) ?></div>
<div class="activity-time mt-1"><?= date('M d, H:i', strtotime($a['created_at'])) ?></div>
</li>
<?php endforeach; ?>
</ul>
<!-- Recent Activity Section -->
<div class="row mt-4">
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white py-3">
<h5 class="mb-0 fw-bold">Recent Activity</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead>
<tr>
<th style="width: 200px;">Time</th>
<th>Action</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<?php foreach ($activityList as $a): ?>
<tr>
<td class="text-muted small"><?= date('M d, Y H:i', strtotime($a['created_at'])) ?></td>
<td><span class="badge bg-light text-primary border"><?= htmlspecialchars($a['action']) ?></span></td>
<td class="small"><?= htmlspecialchars($a['details']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modals -->
<div class="modal fade" id="addProjectModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title fw-bold">Add New Project</h5>
@ -657,17 +750,46 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'SR&ED Project Tracking
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label small fw-bold">Project Name</label>
<input type="text" name="name" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Project Code</label>
<input type="text" name="code" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label small fw-bold">Start Date</label>
<input type="date" name="start_date" class="form-control" value="<?= date('Y-m-d') ?>">
<div class="row">
<div class="col-md-8 mb-3">
<label class="form-label small fw-bold">Project Name</label>
<input type="text" name="name" class="form-control" placeholder="e.g. 5G Network Optimization" required>
</div>
<div class="col-md-4 mb-3">
<label class="form-label small fw-bold">Project Code</label>
<input type="text" name="code" class="form-control" placeholder="PRJ-001" required>
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold">Project Owner</label>
<select name="owner_id" class="form-select">
<option value="">Select Owner...</option>
<?php foreach ($employeeList as $e): ?>
<option value="<?= $e['id'] ?>"><?= htmlspecialchars($e['first_name'] . ' ' . $e['last_name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold">Project Type</label>
<select name="type" class="form-select">
<option value="Internal">Internal</option>
<option value="SRED">SR&ED</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold">Start Date</label>
<input type="date" name="start_date" class="form-control" value="<?= date('Y-m-d') ?>">
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold">Est. Completion Date</label>
<input type="date" name="estimated_completion_date" class="form-control">
</div>
<div class="col-md-6 mb-3">
<label class="form-label small fw-bold">Estimated Hours</label>
<div class="input-group">
<input type="number" name="estimated_hours" class="form-control" step="0.5" min="0" value="0">
<span class="input-group-text">hours</span>
</div>
</div>
</div>
</div>
<div class="modal-footer border-0">
@ -979,6 +1101,44 @@ function handleDatePreset(value) {
if (window.innerWidth < 992) {
document.getElementById('projectFilterSidebar').classList.add('collapsed');
}
// Hours Chart
const ctx = document.getElementById('hoursChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: <?= json_encode($chartLabels) ?>,
datasets: [{
label: 'Logged Hours',
data: <?= json_encode($chartValues) ?>,
borderColor: '#3b82f6',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderWidth: 3,
fill: true,
tension: 0.4,
pointRadius: 4,
pointBackgroundColor: '#3b82f6'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false }
},
scales: {
y: {
beginAtZero: true,
grid: { color: '#f1f5f9' },
ticks: { font: { size: 11 } }
},
x: {
grid: { display: false },
ticks: { font: { size: 11 } }
}
}
}
});
</script>
</body>
</html>

363
reports.php Normal file
View File

@ -0,0 +1,363 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/db/config.php';
// Simulate Tenant Context
$tenant_id = 1;
$report_type = $_GET['report_type'] ?? 'labour_export';
// Filter Data for Export Report
$f_employee = $_GET['employee_id'] ?? '';
$f_team = $_GET['team_id'] ?? '';
$f_start = $_GET['start_date'] ?? date('Y-m-01');
$f_end = $_GET['end_date'] ?? date('Y-m-t');
$f_projects = $_GET['projects'] ?? []; // Array
$f_activity = $_GET['activity_type_id'] ?? '';
// Handle Results for Labour Export
$exportResults = [];
$chartData = [];
if ($report_type === 'labour_export') {
$query = "
SELECT le.*, p.name as project_name, e.name as employee_name, lt.name as labour_type
FROM labour_entries le
JOIN projects p ON le.project_id = p.id
JOIN employees e ON le.employee_id = e.id
LEFT JOIN labour_types lt ON le.labour_type_id = lt.id
WHERE le.tenant_id = ? AND le.entry_date BETWEEN ? AND ?
";
$params = [$tenant_id, $f_start, $f_end];
if ($f_employee) {
$query .= " AND le.employee_id = ?";
$params[] = $f_employee;
}
if ($f_team) {
$query .= " AND le.employee_id IN (SELECT employee_id FROM employee_teams WHERE team_id = ?)";
$params[] = $f_team;
}
if (!empty($f_projects)) {
$placeholders = implode(',', array_fill(0, count($f_projects), '?'));
$query .= " AND le.project_id IN ($placeholders)";
foreach ($f_projects as $pid) $params[] = $pid;
}
if ($f_activity) {
$query .= " AND le.labour_type_id = ?";
$params[] = $f_activity;
}
$query .= " ORDER BY le.entry_date ASC";
$stmt = db()->prepare($query);
$stmt->execute($params);
$exportResults = $stmt->fetchAll();
// Group for Chart (Hours per Day)
$grouped = [];
foreach ($exportResults as $row) {
$grouped[$row['entry_date']] = ($grouped[$row['entry_date']] ?? 0) + (float)$row['hours'];
}
ksort($grouped);
$chartData = [
'labels' => array_keys($grouped),
'values' => array_values($grouped)
];
}
// Handle Calendar Report
$cal_month = $_GET['month'] ?? date('Y-m');
$calendarData = [];
if ($report_type === 'calendar') {
$stmt = db()->prepare("
SELECT entry_date, SUM(hours) as total_hours
FROM labour_entries
WHERE tenant_id = ? AND DATE_FORMAT(entry_date, '%Y-%m') = ?
GROUP BY entry_date
");
$stmt->execute([$tenant_id, $cal_month]);
$calendarData = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
}
// Fetch helper data
$employees = db()->prepare("SELECT id, name FROM employees WHERE tenant_id = ? ORDER BY name");
$employees->execute([$tenant_id]);
$employeeList = $employees->fetchAll();
$teams = db()->prepare("SELECT id, name FROM teams WHERE tenant_id = ? ORDER BY name");
$teams->execute([$tenant_id]);
$teamList = $teams->fetchAll();
$projects = db()->prepare("SELECT id, name FROM projects WHERE tenant_id = ? ORDER BY name");
$projects->execute([$tenant_id]);
$projectList = $projects->fetchAll();
$labourTypes = db()->prepare("SELECT id, name FROM labour_types WHERE tenant_id = ? ORDER BY name");
$labourTypes->execute([$tenant_id]);
$labourTypeList = $labourTypes->fetchAll();
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SR&ED Manager - Reports</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link href="assets/css/custom.css?v=<?= time() ?>" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-lg sticky-top">
<div class="container-fluid">
<a class="navbar-brand" href="index.php">SR&ED MANAGER</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item"><a class="nav-link" href="index.php">Dashboard</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">Projects</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="index.php">List Projects</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown">Reports</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="reports.php?report_type=labour_export">Labour Export</a></li>
<li><a class="dropdown-item" href="reports.php?report_type=calendar">Monthly Calendar</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid py-4">
<div class="row mb-4">
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-body">
<ul class="nav nav-pills mb-3">
<li class="nav-item">
<a class="nav-link <?= $report_type === 'labour_export' ? 'active' : '' ?>" href="reports.php?report_type=labour_export">Labour Export</a>
</li>
<li class="nav-item">
<a class="nav-link <?= $report_type === 'calendar' ? 'active' : '' ?>" href="reports.php?report_type=calendar">Monthly Calendar</a>
</li>
</ul>
<?php if ($report_type === 'labour_export'): ?>
<form method="GET" class="row g-3 align-items-end">
<input type="hidden" name="report_type" value="labour_export">
<div class="col-md-3">
<label class="form-label small fw-bold">Employee</label>
<select name="employee_id" class="form-select form-select-sm">
<option value="">All Employees</option>
<?php foreach ($employeeList as $e): ?>
<option value="<?= $e['id'] ?>" <?= $f_employee == $e['id'] ? 'selected' : '' ?>><?= htmlspecialchars($e['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Team</label>
<select name="team_id" class="form-select form-select-sm">
<option value="">All Teams</option>
<?php foreach ($teamList as $t): ?>
<option value="<?= $t['id'] ?>" <?= $f_team == $t['id'] ? 'selected' : '' ?>><?= htmlspecialchars($t['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Start Date</label>
<input type="date" name="start_date" class="form-control form-control-sm" value="<?= $f_start ?>">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">End Date</label>
<input type="date" name="end_date" class="form-control form-control-sm" value="<?= $f_end ?>">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Projects (Multi-select)</label>
<select name="projects[]" class="form-select form-select-sm" multiple style="height: 100px;">
<?php foreach ($projectList as $p): ?>
<option value="<?= $p['id'] ?>" <?= in_array($p['id'], $f_projects) ? 'selected' : '' ?>><?= htmlspecialchars($p['name']) ?></option>
<?php endforeach; ?>
</select>
<div class="extra-small text-muted">Hold Ctrl/Cmd to select multiple</div>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Activity Type</label>
<select name="activity_type_id" class="form-select form-select-sm">
<option value="">All Activities</option>
<?php foreach ($labourTypeList as $lt): ?>
<option value="<?= $lt['id'] ?>" <?= $f_activity == $lt['id'] ? 'selected' : '' ?>><?= htmlspecialchars($lt['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-sm btn-primary w-100">Generate Report</button>
</div>
</form>
<?php else: ?>
<form method="GET" class="row g-3 align-items-end">
<input type="hidden" name="report_type" value="calendar">
<div class="col-md-3">
<label class="form-label small fw-bold">Select Month</label>
<input type="month" name="month" class="form-control form-control-sm" value="<?= $cal_month ?>">
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-sm btn-primary w-100">View Calendar</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php if ($report_type === 'labour_export'): ?>
<div class="row">
<div class="col-lg-8">
<div class="card border-0 shadow-sm mb-4">
<div class="card-header bg-white d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-bold">Detailed Labour Records</h6>
<button class="btn btn-sm btn-outline-secondary" onclick="window.print()"><i class="bi bi-printer"></i> Print / PDF</button>
</div>
<div class="table-responsive">
<table class="table align-middle mb-0">
<thead class="bg-light">
<tr>
<th>Date</th>
<th>Employee</th>
<th>Project</th>
<th>Activity</th>
<th class="text-end">Hours</th>
</tr>
</thead>
<tbody>
<?php if (empty($exportResults)): ?>
<tr><td colspan="5" class="text-center py-5 text-muted">No records found for the selected criteria.</td></tr>
<?php endif; ?>
<?php $total = 0; foreach ($exportResults as $row): $total += (float)$row['hours']; ?>
<tr>
<td><?= $row['entry_date'] ?></td>
<td><strong><?= htmlspecialchars($row['employee_name']) ?></strong></td>
<td><?= htmlspecialchars($row['project_name']) ?></td>
<td><span class="badge bg-light text-dark border"><?= htmlspecialchars($row['labour_type'] ?? 'Uncategorized') ?></span></td>
<td class="text-end fw-bold"><?= number_format((float)$row['hours'], 2) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<?php if (!empty($exportResults)): ?>
<tfoot class="bg-light">
<tr>
<td colspan="4" class="text-end fw-bold">Total Hours:</td>
<td class="text-end fw-bold text-primary"><?= number_format($total, 2) ?></td>
</tr>
</tfoot>
<?php endif; ?>
</table>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white">
<h6 class="mb-0 fw-bold">Hours Breakdown</h6>
</div>
<div class="card-body">
<canvas id="exportChart" style="height: 300px;"></canvas>
</div>
</div>
</div>
</div>
<script>
const ctx = document.getElementById('exportChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: <?= json_encode($chartData['labels']) ?>,
datasets: [{
label: 'Hours',
data: <?= json_encode($chartData['values']) ?>,
backgroundColor: 'rgba(13, 110, 253, 0.2)',
borderColor: '#0d6efd',
borderWidth: 2,
borderRadius: 5
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
y: { beginAtZero: true, grid: { display: false } },
x: { grid: { display: false } }
}
}
});
</script>
<?php elseif ($report_type === 'calendar'): ?>
<div class="card border-0 shadow-sm">
<div class="card-header bg-white">
<h6 class="mb-0 fw-bold">Monthly Labour Calendar - <?= date('F Y', strtotime($cal_month)) ?></h6>
</div>
<div class="card-body p-0">
<div class="calendar-grid">
<div class="calendar-header-day">Sun</div>
<div class="calendar-header-day">Mon</div>
<div class="calendar-header-day">Tue</div>
<div class="calendar-header-day">Wed</div>
<div class="calendar-header-day">Thu</div>
<div class="calendar-header-day">Fri</div>
<div class="calendar-header-day">Sat</div>
<?php
$first_day = date('Y-m-01', strtotime($cal_month));
$days_in_month = date('t', strtotime($cal_month));
$start_day_of_week = (int)date('w', strtotime($first_day));
// Fill empty days before first of month
for ($i = 0; $i < $start_day_of_week; $i++) {
echo '<div class="calendar-day other-month"></div>';
}
// Days of month
for ($day = 1; $day <= $days_in_month; $day++) {
$current_date = date('Y-m-', strtotime($cal_month)) . str_pad((string)$day, 2, '0', STR_PAD_LEFT);
$hours = $calendarData[$current_date] ?? 0;
?>
<div class="calendar-day">
<span class="day-number"><?= $day ?></span>
<?php if ($hours > 0): ?>
<span class="day-hours"><?= number_format((float)$hours, 1) ?><small class="ms-1 h6 mb-0" style="font-size: 0.6rem;">h</small></span>
<?php endif; ?>
</div>
<?php
}
// Fill remaining days to complete grid
$total_cells = ceil(($start_day_of_week + $days_in_month) / 7) * 7;
for ($i = ($start_day_of_week + $days_in_month); $i < $total_cells; $i++) {
echo '<div class="calendar-day other-month"></div>';
}
?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>