227 lines
11 KiB
PHP
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'; ?>
|