252 lines
13 KiB
PHP
252 lines
13 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
|
||
require_once __DIR__ . '/archive_bootstrap.php';
|
||
|
||
ensure_archive_schema();
|
||
require_auth();
|
||
|
||
$documentId = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||
$document = $documentId > 0 ? get_document($documentId) : null;
|
||
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'validate_document' && $document) {
|
||
validate_document($documentId, current_user(), trim((string)($_POST['validation_notes'] ?? '')));
|
||
header('Location: document.php?id=' . $documentId);
|
||
exit;
|
||
}
|
||
|
||
$document = $documentId > 0 ? get_document($documentId) : null;
|
||
if (!$document) {
|
||
http_response_code(404);
|
||
}
|
||
|
||
$meta = page_meta('Detail Arsip – KBRI Harare', 'Detail arsip digital, validasi, dan akses pratinjau aman KBRI Harare.');
|
||
$flashes = get_flashes();
|
||
$user = current_user();
|
||
$activity = $document ? document_activity($document) : [];
|
||
$canAccessFile = $document ? can_access_document_file($document) : false;
|
||
$canPreview = $document ? ($canAccessFile && can_preview_inline($document)) : false;
|
||
?>
|
||
<!doctype html>
|
||
<html lang="id" data-bs-theme="light">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title><?= h($meta['title']) ?></title>
|
||
<?php if ($meta['description'] !== ''): ?>
|
||
<meta name="description" content="<?= h($meta['description']) ?>" />
|
||
<meta property="og:description" content="<?= h($meta['description']) ?>" />
|
||
<meta property="twitter:description" content="<?= h($meta['description']) ?>" />
|
||
<?php endif; ?>
|
||
<?php if ($meta['image'] !== ''): ?>
|
||
<meta property="og:image" content="<?= h($meta['image']) ?>" />
|
||
<meta property="twitter:image" content="<?= h($meta['image']) ?>" />
|
||
<?php endif; ?>
|
||
<meta property="og:title" content="<?= h($meta['title']) ?>" />
|
||
<meta property="twitter:title" content="<?= h($meta['title']) ?>" />
|
||
<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;500;600;700;800&display=swap" rel="stylesheet">
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||
<link rel="stylesheet" href="assets/css/custom.css?v=<?= urlencode((string)filemtime(__DIR__ . '/assets/css/custom.css')) ?>">
|
||
</head>
|
||
<body class="archive-app app-authenticated detail-page">
|
||
<div class="toast-container position-fixed top-0 end-0 p-3">
|
||
<?php foreach ($flashes as $flash): ?>
|
||
<div class="toast align-items-center text-bg-<?= h($flash['type']) ?> border-0 mb-2" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="4500">
|
||
<div class="d-flex">
|
||
<div class="toast-body"><?= h($flash['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 endforeach; ?>
|
||
</div>
|
||
|
||
<header class="topbar topbar-static">
|
||
<div class="d-flex align-items-center gap-3">
|
||
<a href="index.php" class="btn btn-outline-secondary btn-sm"><i class="bi bi-arrow-left me-2"></i>Kembali</a>
|
||
<div>
|
||
<p class="section-kicker mb-1">Detail arsip</p>
|
||
<h1 class="h4 mb-0">Pusat validasi & pratinjau dokumen</h1>
|
||
</div>
|
||
</div>
|
||
<div class="d-flex align-items-center gap-2 gap-lg-3">
|
||
<button class="btn btn-outline-secondary btn-sm theme-toggle" type="button" data-theme-toggle>
|
||
<i class="bi bi-moon-stars"></i>
|
||
</button>
|
||
<div class="profile-chip static-chip">
|
||
<span class="avatar"><?= h($user['avatar'] ?? 'U') ?></span>
|
||
<span class="text-start d-none d-md-inline-block">
|
||
<strong class="d-block"><?= h($user['name']) ?></strong>
|
||
<small class="text-secondary"><?= h($user['role_label'] ?? '') ?></small>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="detail-layout container-fluid px-3 px-lg-4 py-4">
|
||
<?php if (!$document): ?>
|
||
<section class="card border-0 shadow-sm">
|
||
<div class="card-body p-5 text-center">
|
||
<i class="bi bi-file-earmark-x display-5 text-secondary"></i>
|
||
<h2 class="h4 mt-3">Dokumen tidak ditemukan</h2>
|
||
<p class="text-secondary">ID arsip tidak tersedia atau telah berubah.</p>
|
||
<a href="index.php" class="btn btn-primary">Kembali ke dashboard</a>
|
||
</div>
|
||
</section>
|
||
<?php else: ?>
|
||
<div class="row g-4 align-items-start">
|
||
<div class="col-12 col-xl-8">
|
||
<section class="card border-0 shadow-sm mb-4">
|
||
<div class="card-body p-4">
|
||
<div class="d-flex flex-column flex-lg-row justify-content-between gap-3 mb-3">
|
||
<div>
|
||
<div class="d-flex flex-wrap gap-2 align-items-center mb-2">
|
||
<span class="status-pill <?= $document['status'] === 'validated' ? 'validated' : 'pending' ?>"><?= $document['status'] === 'validated' ? 'Tervalidasi' : 'Menunggu Validasi' ?></span>
|
||
<span class="badge text-bg-secondary-subtle text-secondary-emphasis border"><?= h($document['category']) ?></span>
|
||
</div>
|
||
<h2 class="h3 mb-1"><?= h($document['title']) ?></h2>
|
||
<p class="text-secondary mb-0"><?= h($document['folder_path']) ?></p>
|
||
</div>
|
||
<div class="detail-actions d-flex flex-wrap gap-2">
|
||
<?php if ($canAccessFile): ?>
|
||
<a href="file.php?id=<?= (int)$document['id'] ?>&disposition=download" class="btn btn-outline-secondary"><i class="bi bi-download me-2"></i>Unduh</a>
|
||
<?php if ($canPreview): ?>
|
||
<a href="file.php?id=<?= (int)$document['id'] ?>&disposition=inline" class="btn btn-outline-secondary" target="_blank" rel="noopener"><i class="bi bi-eye me-2"></i>Pratinjau</a>
|
||
<button class="btn btn-primary" type="button" onclick="window.print()"><i class="bi bi-printer me-2"></i>Cetak</button>
|
||
<?php endif; ?>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row g-3 detail-meta">
|
||
<div class="col-6 col-lg-3">
|
||
<span class="meta-label">Tanggal dokumen</span>
|
||
<strong><?= h(date('d M Y', strtotime((string)$document['document_date']))) ?></strong>
|
||
</div>
|
||
<div class="col-6 col-lg-3">
|
||
<span class="meta-label">Departemen</span>
|
||
<strong><?= h($document['department']) ?></strong>
|
||
</div>
|
||
<div class="col-6 col-lg-3">
|
||
<span class="meta-label">Diunggah oleh</span>
|
||
<strong><?= h($document['created_by']) ?></strong>
|
||
</div>
|
||
<div class="col-6 col-lg-3">
|
||
<span class="meta-label">Lampiran</span>
|
||
<strong><?= h(strtoupper((string)$document['attachment_ext'])) ?> · <?= h(format_filesize((int)$document['attachment_size'])) ?></strong>
|
||
</div>
|
||
</div>
|
||
|
||
<?php if ($document['notes']): ?>
|
||
<div class="annotation-box mt-4">
|
||
<span class="meta-label">Catatan dokumen</span>
|
||
<p class="mb-0"><?= nl2br(h($document['notes'])) ?></p>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="card border-0 shadow-sm">
|
||
<div class="card-body p-4">
|
||
<div class="d-flex justify-content-between align-items-start gap-3 mb-3">
|
||
<div>
|
||
<p class="section-kicker mb-2">Pratinjau aman</p>
|
||
<h2 class="h5 mb-1">Akses file sesuai status validasi</h2>
|
||
</div>
|
||
<span class="badge text-bg-dark"><?= $canAccessFile ? 'Akses dibuka' : 'Terkunci' ?></span>
|
||
</div>
|
||
|
||
<?php if ($canPreview): ?>
|
||
<div class="preview-frame">
|
||
<?php if (in_array(strtolower((string)$document['attachment_ext']), ['jpg', 'jpeg', 'png'], true)): ?>
|
||
<img src="file.php?id=<?= (int)$document['id'] ?>&disposition=inline" alt="Pratinjau <?= h($document['title']) ?>" class="img-fluid rounded-3 w-100">
|
||
<?php elseif (strtolower((string)$document['attachment_ext']) === 'mp4'): ?>
|
||
<video controls class="w-100 rounded-3" preload="metadata">
|
||
<source src="file.php?id=<?= (int)$document['id'] ?>&disposition=inline" type="video/mp4">
|
||
</video>
|
||
<?php else: ?>
|
||
<iframe src="file.php?id=<?= (int)$document['id'] ?>&disposition=inline" title="Pratinjau dokumen" class="preview-iframe"></iframe>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php elseif ($canAccessFile): ?>
|
||
<div class="empty-panel tall">
|
||
<i class="bi bi-file-earmark-lock2"></i>
|
||
<p class="mb-1 fw-semibold">Jenis file tidak mendukung pratinjau inline.</p>
|
||
<p class="mb-0 text-secondary small">Unduh lampiran untuk membuka dokumen ini.</p>
|
||
</div>
|
||
<?php else: ?>
|
||
<div class="empty-panel tall">
|
||
<i class="bi bi-shield-lock"></i>
|
||
<p class="mb-1 fw-semibold">Pratinjau dikunci sampai validasi selesai.</p>
|
||
<p class="mb-0 text-secondary small">Setelah disetujui Super Admin, staf dapat pratinjau, unduh, dan cetak dari halaman ini.</p>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
<div class="col-12 col-xl-4">
|
||
<?php if (is_super_admin() && $document['status'] !== 'validated'): ?>
|
||
<section class="card border-0 shadow-sm mb-4">
|
||
<div class="card-body p-4">
|
||
<p class="section-kicker mb-2">Aksi Super Admin</p>
|
||
<h2 class="h5 mb-1">Validasi dokumen</h2>
|
||
<p class="text-secondary small">Setelah disetujui, dokumen terbuka untuk pratinjau, unduh, dan cetak oleh staf terkait.</p>
|
||
<form method="post" class="vstack gap-3 mt-3">
|
||
<input type="hidden" name="csrf_token" value="<?= h(csrf_token()) ?>">
|
||
<input type="hidden" name="action" value="validate_document">
|
||
<div>
|
||
<label class="form-label" for="validation_notes">Catatan validasi</label>
|
||
<textarea id="validation_notes" class="form-control" name="validation_notes" rows="4" placeholder="Contoh: Metadata sesuai, siap diakses unit kerja."></textarea>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary"><i class="bi bi-patch-check me-2"></i>Validasi dokumen</button>
|
||
</form>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<section class="card border-0 shadow-sm mb-4">
|
||
<div class="card-body p-4">
|
||
<p class="section-kicker mb-2">Status akses</p>
|
||
<h2 class="h5 mb-1">Ringkasan kepatuhan</h2>
|
||
<ul class="list-unstyled security-list mb-0">
|
||
<li><i class="bi bi-check2-circle"></i><span>Password user demo diproses dengan verifikasi Bcrypt.</span></li>
|
||
<li><i class="bi bi-check2-circle"></i><span>Form terlindungi CSRF token dan prepared statements PDO.</span></li>
|
||
<li><i class="bi bi-check2-circle"></i><span>File hanya di-stream melalui gerbang aplikasi, bukan tautan publik langsung.</span></li>
|
||
<li><i class="bi bi-check2-circle"></i><span><?= $document['status'] === 'validated' ? 'Dokumen siap diakses sesuai hak role.' : 'Dokumen menunggu otorisasi Super Admin.' ?></span></li>
|
||
</ul>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="card border-0 shadow-sm">
|
||
<div class="card-body p-4">
|
||
<p class="section-kicker mb-2">Audit trail</p>
|
||
<h2 class="h5 mb-1">Riwayat aktivitas</h2>
|
||
<div class="timeline mt-3">
|
||
<?php foreach ($activity as $entry): ?>
|
||
<article class="timeline-item">
|
||
<span class="timeline-dot"></span>
|
||
<div>
|
||
<strong class="d-block text-capitalize"><?= h($entry['action'] ?? '') ?></strong>
|
||
<small class="text-secondary d-block"><?= h($entry['actor'] ?? '') ?> · <?= h($entry['timestamp'] ?? '') ?></small>
|
||
<?php if (!empty($entry['notes'])): ?>
|
||
<p class="mb-0 mt-2 text-secondary small"><?= h($entry['notes']) ?></p>
|
||
<?php endif; ?>
|
||
</div>
|
||
</article>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
</main>
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||
<script src="assets/js/main.js?v=<?= urlencode((string)filemtime(__DIR__ . '/assets/js/main.js')) ?>"></script>
|
||
</body>
|
||
</html>
|