38438-vm/reports_media.php
2026-02-15 16:33:12 +00:00

227 lines
11 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/includes/media_helper.php';
$tenant_id = 1;
// Filters
$filter_author = $_GET['author'] ?? '';
$filter_project = (int)($_GET['project_id'] ?? 0);
$filter_evidence = (int)($_GET['evidence_type_id'] ?? 0);
$filter_start = $_GET['start_date'] ?? '';
$filter_end = $_GET['end_date'] ?? '';
$where = ["a.tenant_id = ?", "(a.mime_type LIKE 'image/%' OR a.mime_type LIKE 'video/%')"];
$params = [$tenant_id];
if ($filter_author) {
$where[] = "a.uploaded_by = ?";
$params[] = $filter_author;
}
if ($filter_project) {
$where[] = "COALESCE(le.project_id, ex.project_id) = ?";
$params[] = $filter_project;
}
if ($filter_evidence) {
$where[] = "le.evidence_type_id = ?";
$params[] = $filter_evidence;
}
if ($filter_start) {
$where[] = "DATE(a.created_at) >= ?";
$params[] = $filter_start;
}
if ($filter_end) {
$where[] = "DATE(a.created_at) <= ?";
$params[] = $filter_end;
}
$where_clause = implode(" AND ", $where);
$query = "
SELECT a.*,
p.name as project_name,
et.name as evidence_type_name
FROM attachments a
LEFT JOIN labour_entries le ON a.entity_type = 'labour_entry' AND a.entity_id = le.id
LEFT JOIN expenses ex ON a.entity_type = 'expense' AND a.entity_id = ex.id
LEFT JOIN projects p ON p.id = COALESCE(le.project_id, ex.project_id)
LEFT JOIN evidence_types et ON le.evidence_type_id = et.id
WHERE $where_clause
ORDER BY a.created_at DESC
";
$stmt = db()->prepare($query);
$stmt->execute($params);
$mediaItems = $stmt->fetchAll();
// Get filter options
$authors = db()->prepare("SELECT DISTINCT uploaded_by FROM attachments WHERE tenant_id = ? AND uploaded_by IS NOT NULL ORDER BY uploaded_by");
$authors->execute([$tenant_id]);
$authorList = $authors->fetchAll(PDO::FETCH_COLUMN);
$projects = db()->prepare("SELECT id, name FROM projects WHERE tenant_id = ? AND is_archived = 0 ORDER BY name");
$projects->execute([$tenant_id]);
$projectList = $projects->fetchAll();
$evidenceTypes = db()->prepare("SELECT id, name FROM evidence_types WHERE tenant_id = ? ORDER BY name");
$evidenceTypes->execute([$tenant_id]);
$evidenceTypeList = $evidenceTypes->fetchAll();
$pageTitle = "SR&ED Manager - Media Gallery";
include __DIR__ . '/includes/header.php';
?>
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<nav aria-label="breadcrumb">
<ol class="breadcrumb mb-1">
<li class="breadcrumb-item"><a href="reports.php" class="text-decoration-none text-muted">Reports</a></li>
<li class="breadcrumb-item active" aria-current="page">Media Gallery</li>
</ol>
</nav>
<h2 class="fw-bold mb-0">Media Gallery</h2>
</div>
<div class="text-muted small">
Total Items: <?= count($mediaItems) ?>
</div>
</div>
<!-- Filters -->
<div class="card border-0 shadow-sm mb-4">
<div class="card-body">
<form method="GET" class="row g-3 align-items-end">
<div class="col-md-3">
<label class="form-label small fw-bold">Project</label>
<select name="project_id" class="form-select form-select-sm">
<option value="">All Projects</option>
<?php foreach ($projectList as $p): ?>
<option value="<?= $p['id'] ?>" <?= $filter_project == $p['id'] ? 'selected' : '' ?>><?= htmlspecialchars($p['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<label class="form-label small fw-bold">Author</label>
<select name="author" class="form-select form-select-sm">
<option value="">All Authors</option>
<?php foreach ($authorList as $author): ?>
<option value="<?= htmlspecialchars($author) ?>" <?= $filter_author == $author ? 'selected' : '' ?>><?= htmlspecialchars($author) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<label class="form-label small fw-bold">Objective Evidence</label>
<select name="evidence_type_id" class="form-select form-select-sm">
<option value="">All Evidence</option>
<?php foreach ($evidenceTypeList as $et): ?>
<option value="<?= $et['id'] ?>" <?= $filter_evidence == $et['id'] ? 'selected' : '' ?>><?= htmlspecialchars($et['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<label class="form-label small fw-bold">From</label>
<input type="date" name="start_date" class="form-control form-control-sm" value="<?= htmlspecialchars($filter_start) ?>">
</div>
<div class="col-md-2">
<label class="form-label small fw-bold">To</label>
<input type="date" name="end_date" class="form-control form-control-sm" value="<?= htmlspecialchars($filter_end) ?>">
</div>
<div class="col-md-1">
<div class="d-flex gap-1">
<button type="submit" class="btn btn-sm btn-primary flex-grow-1">Filter</button>
<a href="reports_media.php" class="btn btn-sm btn-outline-secondary" title="Reset"><i class="bi bi-x-lg"></i></a>
</div>
</div>
</form>
</div>
</div>
<?php if (empty($mediaItems)): ?>
<div class="card border-0 shadow-sm text-center py-5">
<div class="card-body">
<i class="bi bi-images text-muted" style="font-size: 3rem;"></i>
<h5 class="mt-3 text-muted">No media files found</h5>
<p class="text-muted small">Try adjusting your filters or upload some images/videos.</p>
<a href="reports_media.php" class="btn btn-sm btn-outline-secondary">Reset All Filters</a>
</div>
</div>
<?php else: ?>
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 row-cols-xl-5 g-4">
<?php foreach ($mediaItems as $item):
$isImg = isImage($item['mime_type']);
$isVideo = isVideo($item['mime_type']);
$thumb = $item['thumbnail_path'] ?: $item['file_path'];
// If it's a video and no thumbnail, show a placeholder icon
$showThumb = true;
if ($isVideo && !$item['thumbnail_path']) {
$showThumb = false;
}
?>
<div class="col">
<div class="card h-100 border-0 shadow-sm overflow-hidden position-relative group">
<div class="ratio ratio-1x1 bg-light">
<?php if ($showThumb): ?>
<img src="<?= htmlspecialchars($thumb) ?>" class="object-fit-cover w-100 h-100 transition" alt="<?= htmlspecialchars($item['file_name']) ?>">
<?php else: ?>
<div class="d-flex align-items-center justify-content-center bg-dark">
<i class="bi bi-play-circle text-white" style="font-size: 2.5rem;"></i>
</div>
<?php endif; ?>
<div class="overlay d-flex align-items-center justify-content-center bg-dark bg-opacity-50 opacity-0 transition">
<div class="d-flex gap-2">
<a href="<?= htmlspecialchars($item['file_path']) ?>" target="_blank" class="btn btn-sm btn-light rounded-circle shadow-sm" title="View Full">
<i class="bi bi-eye"></i>
</a>
<a href="<?= htmlspecialchars($item['file_path']) ?>" download class="btn btn-sm btn-light rounded-circle shadow-sm" title="Download">
<i class="bi bi-download"></i>
</a>
</div>
</div>
</div>
<div class="card-body p-2">
<div class="d-flex justify-content-between align-items-start mb-1">
<span class="badge <?= $isImg ? 'bg-primary' : 'bg-danger' ?> extra-small">
<?= $isImg ? 'IMAGE' : 'VIDEO' ?>
</span>
<small class="text-muted extra-small"><?= date('M j, Y', strtotime($item['created_at'])) ?></small>
</div>
<div class="text-truncate small fw-bold text-dark" title="<?= htmlspecialchars($item['file_name']) ?>">
<?= htmlspecialchars($item['file_name']) ?>
</div>
<div class="extra-small text-muted text-truncate mt-1">
<i class="bi bi-folder2 me-1"></i> <?= htmlspecialchars($item['project_name'] ?: 'No Project') ?>
</div>
<?php if ($item['evidence_type_name']): ?>
<div class="extra-small text-muted text-truncate">
<i class="bi bi-shield-check me-1"></i> <?= htmlspecialchars($item['evidence_type_name']) ?>
</div>
<?php endif; ?>
<div class="d-flex align-items-center mt-2 pt-2 border-top">
<div class="bg-light rounded-circle p-1 me-2" style="width: 20px; height: 20px; display: flex; align-items: center; justify-content: center;">
<i class="bi bi-person extra-small"></i>
</div>
<span class="extra-small text-muted"><?= htmlspecialchars($item['uploaded_by'] ?: 'System') ?></span>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<style>
.group:hover .overlay { opacity: 1 !important; }
.transition { transition: all 0.3s ease; }
.extra-small { font-size: 0.7rem; }
.object-fit-cover { object-fit: cover; }
.bg-opacity-50 { background-color: rgba(0,0,0,0.5) !important; }
.opacity-0 { opacity: 0; }
</style>
<?php include __DIR__ . '/includes/footer.php'; ?>