39888-vm/loan.php
2026-05-04 10:15:32 +00:00

337 lines
15 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/lending_app.php';
lending_ensure_schema();
$loanId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
$loan = $loanId > 0 ? fetch_loan($loanId) : null;
$returnValues = default_return_form();
$returnErrors = [];
if ($loan && $_SERVER['REQUEST_METHOD'] === 'POST') {
$action = trim((string) ($_POST['action'] ?? ''));
if ($action === 'mark_reminder_sent') {
if ($loan['is_returned']) {
set_flash('secondary', 'Pinjaman sudah selesai sehingga reminder tidak diperlukan.');
} else {
mark_reminder_sent($loanId);
set_flash('success', 'Waktu reminder terakhir sudah dicatat.');
}
header('Location: loan.php?id=' . $loanId);
exit;
}
if ($action === 'record_return') {
if ($loan['is_returned']) {
set_flash('secondary', 'Pengembalian sudah pernah dicatat sebelumnya.');
header('Location: loan.php?id=' . $loanId);
exit;
}
[$returnValues, $returnErrors] = validate_return_input($_POST, $loan);
if ($returnErrors === []) {
record_return($loanId, $returnValues);
set_flash('success', 'Pengembalian berhasil dicatat dan riwayat telah diperbarui.');
header('Location: loan.php?id=' . $loanId);
exit;
}
}
}
$loan = $loanId > 0 ? fetch_loan($loanId) : null;
$flashes = pull_flashes();
$cssVersion = asset_version('assets/css/custom.css');
$jsVersion = asset_version('assets/js/main.js');
if (!$loan):
http_response_code(404);
?>
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<?= render_head_meta('Pinjaman tidak ditemukan', 'Detail pinjaman tidak tersedia atau sudah dihapus dari sistem.') ?>
<meta name="robots" content="noindex, nofollow" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="assets/css/custom.css?v=<?= e($cssVersion) ?>" />
</head>
<body class="app-body">
<main class="py-5">
<div class="container app-container">
<section class="section-card not-found-card text-center">
<span class="eyebrow">404</span>
<h1 class="hero-title mt-2">Pinjaman tidak ditemukan</h1>
<p class="hero-copy mb-4">Periksa kembali tautan detail pinjaman atau kembali ke dashboard untuk membuka transaksi lain.</p>
<a href="index.php" class="btn btn-primary btn-app">Kembali ke dashboard</a>
</section>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
<script src="assets/js/main.js?v=<?= e($jsVersion) ?>" defer></script>
</body>
</html>
<?php
return;
endif;
?>
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<?= render_head_meta('Detail ' . $loan['reference'], 'Lihat detail transaksi peminjaman, copy pengingat, dan catat pengembalian barang.') ?>
<meta name="robots" content="index, follow" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="assets/css/custom.css?v=<?= e($cssVersion) ?>" />
</head>
<body class="app-body">
<div class="toast-container position-fixed top-0 end-0 p-3">
<div id="appToast" class="toast border-0 shadow-sm" role="status" aria-live="polite" aria-atomic="true">
<div class="toast-body"></div>
</div>
</div>
<nav class="navbar navbar-expand-lg app-navbar sticky-top">
<div class="container app-container">
<a class="navbar-brand" href="index.php">
<span class="brand-mark">LP</span>
<span>
<strong><?= e(project_name()) ?></strong>
<small class="d-block text-muted">Loan detail</small>
</span>
</a>
<div class="d-flex align-items-center gap-2 ms-auto">
<a href="index.php#loan-board" class="btn btn-sm btn-outline-secondary btn-app">Kembali ke board</a>
<?php if (!$loan['is_returned']): ?>
<button type="button" class="btn btn-sm btn-primary btn-app copy-trigger" data-copy-text="<?= e($loan['reminder_message']) ?>" data-copy-success="Teks reminder <?= e($loan['reference']) ?> disalin.">Salin reminder</button>
<?php endif; ?>
</div>
</div>
</nav>
<main class="py-4 py-lg-5">
<div class="container app-container d-grid gap-4">
<?php foreach ($flashes as $flash): ?>
<div class="alert alert-<?= e($flash['type'] === 'success' ? 'success' : 'secondary') ?> alert-dismissible fade show app-alert auto-dismiss-alert" role="alert">
<?= e($flash['message'] ?? '') ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endforeach; ?>
<section class="section-card hero-card">
<div class="d-flex flex-column flex-lg-row justify-content-between align-items-start gap-4">
<div>
<span class="eyebrow">Detail transaksi</span>
<h1 class="hero-title mt-2 mb-2"><?= e($loan['reference']) ?> — <?= e($loan['item_name']) ?></h1>
<p class="hero-copy mb-3">Pinjaman atas nama <?= e($loan['borrower_name']) ?> dengan qty <?= e((string) $loan['quantity']) ?>. Gunakan halaman ini untuk reminder dan penutupan transaksi.</p>
<div class="d-flex flex-wrap gap-2">
<span class="status-badge <?= e($loan['status_badge_class']) ?>"><?= e($loan['status_label']) ?></span>
<span class="status-badge badge-status-neutral"><?= e($loan['due_note']) ?></span>
</div>
</div>
<div class="hero-summary-list loan-detail-summary">
<div>
<span class="summary-label">Jatuh tempo</span>
<strong><?= e($loan['due_at_label']) ?></strong>
</div>
<div>
<span class="summary-label">Reminder terakhir</span>
<strong><?= e($loan['last_reminder_at_label'] ?: 'Belum ada') ?></strong>
</div>
<div>
<span class="summary-label">Status pengembalian</span>
<strong><?= e($loan['is_returned'] ? $loan['returned_at_label'] : 'Belum kembali') ?></strong>
</div>
</div>
</div>
</section>
<section class="row g-4 align-items-start">
<div class="col-xl-7 d-grid gap-4">
<div class="section-card">
<div class="section-header">
<div>
<h2>Ringkasan pinjaman</h2>
<p>Data inti transaksi untuk follow-up dan audit internal.</p>
</div>
<a href="index.php#new-loan" class="btn btn-sm btn-outline-secondary btn-app">Transaksi baru</a>
</div>
<dl class="detail-grid mb-0">
<div>
<dt>Peminjam</dt>
<dd><?= e($loan['borrower_name']) ?></dd>
</div>
<div>
<dt>Kontak</dt>
<dd><?= e($loan['borrower_contact'] ?: 'Belum diisi') ?></dd>
</div>
<div>
<dt>Divisi</dt>
<dd><?= e($loan['department'] ?: 'Tanpa divisi') ?></dd>
</div>
<div>
<dt>Kode barang</dt>
<dd><?= e($loan['item_code'] ?: 'Tanpa kode') ?></dd>
</div>
<div>
<dt>Tanggal pinjam</dt>
<dd><?= e($loan['loaned_at_label']) ?></dd>
</div>
<div>
<dt>Jatuh tempo</dt>
<dd><?= e($loan['due_at_label']) ?></dd>
</div>
<div>
<dt>Jumlah</dt>
<dd><?= e((string) $loan['quantity']) ?></dd>
</div>
<div>
<dt>Catatan awal</dt>
<dd><?= e($loan['notes'] ?: 'Tidak ada catatan tambahan') ?></dd>
</div>
</dl>
</div>
<div class="section-card">
<div class="section-header">
<div>
<h2>Template reminder</h2>
<p>Salin pesan untuk WhatsApp, email, atau chat internal.</p>
</div>
<?php if (!$loan['is_returned']): ?>
<form method="post">
<input type="hidden" name="action" value="mark_reminder_sent" />
<button type="submit" class="btn btn-sm btn-outline-secondary btn-app">Catat reminder terkirim</button>
</form>
<?php endif; ?>
</div>
<div class="message-preview"><?= e($loan['reminder_message']) ?></div>
<div class="d-flex flex-wrap gap-2 pt-3">
<button type="button" class="btn btn-outline-secondary btn-app copy-trigger" data-copy-text="<?= e($loan['reminder_message']) ?>" data-copy-success="Pesan reminder disalin.">Salin teks reminder</button>
<a href="index.php#loan-board" class="btn btn-primary btn-app">Kembali ke daftar</a>
</div>
</div>
</div>
<div class="col-xl-5 d-grid gap-4">
<?php if (!$loan['is_returned']): ?>
<div class="section-card" id="return-form">
<div class="section-header">
<div>
<h2>Proses pengembalian</h2>
<p>Catat kapan barang kembali dan bagaimana kondisinya.</p>
</div>
<span class="section-chip">Close transaction</span>
</div>
<form method="post" novalidate class="row g-3">
<input type="hidden" name="action" value="record_return" />
<div class="col-12">
<label class="form-label" for="returned_at">Waktu kembali</label>
<input type="datetime-local" class="form-control <?= isset($returnErrors['returned_at']) ? 'is-invalid' : '' ?>" id="returned_at" name="returned_at" value="<?= e($returnValues['returned_at']) ?>" />
<?php if (isset($returnErrors['returned_at'])): ?><div class="invalid-feedback"><?= e($returnErrors['returned_at']) ?></div><?php endif; ?>
</div>
<div class="col-12">
<label class="form-label" for="return_condition">Kondisi barang saat kembali</label>
<select class="form-select <?= isset($returnErrors['return_condition']) ? 'is-invalid' : '' ?>" id="return_condition" name="return_condition">
<?php foreach (['baik' => 'Baik', 'catatan' => 'Ada catatan', 'rusak' => 'Rusak'] as $optionValue => $optionLabel): ?>
<option value="<?= e($optionValue) ?>" <?= $returnValues['return_condition'] === $optionValue ? 'selected' : '' ?>><?= e($optionLabel) ?></option>
<?php endforeach; ?>
</select>
<?php if (isset($returnErrors['return_condition'])): ?><div class="invalid-feedback"><?= e($returnErrors['return_condition']) ?></div><?php endif; ?>
</div>
<div class="col-12">
<label class="form-label" for="return_notes">Catatan pengembalian</label>
<textarea class="form-control <?= isset($returnErrors['return_notes']) ? 'is-invalid' : '' ?>" id="return_notes" name="return_notes" rows="4" placeholder="Misalnya charger lengkap, tas hilang, atau ada kerusakan ringan."><?= e($returnValues['return_notes']) ?></textarea>
<?php if (isset($returnErrors['return_notes'])): ?><div class="invalid-feedback"><?= e($returnErrors['return_notes']) ?></div><?php endif; ?>
</div>
<div class="col-12 d-flex justify-content-between align-items-center gap-3 pt-1">
<p class="form-helper mb-0">Status board akan berubah otomatis setelah pengembalian disimpan.</p>
<button type="submit" class="btn btn-primary btn-app">Catat pengembalian</button>
</div>
</form>
</div>
<?php else: ?>
<div class="section-card">
<div class="section-header">
<div>
<h2>Pengembalian tercatat</h2>
<p>Transaksi ini sudah ditutup dan tersimpan di riwayat.</p>
</div>
<span class="section-chip">Closed</span>
</div>
<dl class="detail-grid mb-0">
<div>
<dt>Waktu kembali</dt>
<dd><?= e($loan['returned_at_label']) ?></dd>
</div>
<div>
<dt>Kondisi barang</dt>
<dd><?= e($loan['return_condition_label']) ?></dd>
</div>
<div>
<dt>Ketepatan</dt>
<dd><?= e($loan['due_note']) ?></dd>
</div>
<div>
<dt>Catatan akhir</dt>
<dd><?= e($loan['return_notes'] ?: 'Tidak ada catatan tambahan') ?></dd>
</div>
</dl>
</div>
<?php endif; ?>
<div class="section-card">
<div class="section-header">
<div>
<h2>Riwayat aktivitas</h2>
<p>Titik audit sederhana untuk staff dan admin.</p>
</div>
</div>
<ul class="timeline-list mb-0">
<li>
<strong>Transaksi dibuat</strong>
<span><?= e(format_date_id($loan['created_at'], true)) ?></span>
</li>
<li>
<strong>Reminder terakhir</strong>
<span><?= e($loan['last_reminder_at_label'] ?: 'Belum dicatat') ?></span>
</li>
<li>
<strong>Status saat ini</strong>
<span><?= e($loan['status_label'] . ' · ' . $loan['due_note']) ?></span>
</li>
<?php if ($loan['is_returned']): ?>
<li>
<strong>Pengembalian selesai</strong>
<span><?= e($loan['returned_at_label']) ?></span>
</li>
<?php endif; ?>
</ul>
</div>
</div>
</section>
</div>
</main>
<footer class="app-footer">
<div class="container app-container d-flex flex-column flex-sm-row justify-content-between gap-2">
<span><?= e($loan['reference']) ?> · <?= e($loan['item_name']) ?></span>
<span><a href="healthz.php">/healthz</a> tersedia untuk monitoring.</span>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
<script src="assets/js/main.js?v=<?= e($jsVersion) ?>" defer></script>
</body>
</html>