OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

index.php

12 KB
<?php
$this->layout('layouts/main', [
    'page_title'    => $page_title,
    'current_route' => $current_route,
    'full_width'    => true,
]);

$statusLabels = [
    'available'   => [$this->te('Verfügbar'),    'status-pill--success'],
    'lent'        => [$this->te('Ausgeliehen'),  'status-pill--danger'],
    'reserved'    => [$this->te('Reserviert'),   'status-pill--warning'],
    'maintenance' => [$this->te('Wartung'),      'status-pill--purple'],
    'retired'     => [$this->te('Ausgemustert'), 'status-pill--neutral'],
];
?>
<style>
a { text-decoration: none; }
a:hover { text-decoration: none; }
.ldv-wrap { padding: 0; }
.ldv-tab-bar { display:flex; gap:0.25rem; padding:0 1rem; border-bottom:2px solid var(--gray-200); background:var(--color-bg); }
.ldv-tab { padding:0.6rem 1rem; font-size:0.85rem; font-weight:600; color:var(--gray-500); text-decoration:none;
           border-bottom:2px solid transparent; margin-bottom:-2px; transition:color 0.15s,border-color 0.15s; }
.ldv-tab:hover { color:var(--color-primary); }
.ldv-tab.active { color:var(--color-primary); border-bottom-color:var(--color-primary); }

/* Body */

/* Device grid */
.ldv-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(260px,1fr)); gap:1.25rem; }
.ldv-card {
    background:var(--color-bg);
    border:1px solid var(--gray-200);
    border-radius:0.25rem;
    overflow:hidden;
    transition:box-shadow 0.15s, transform 0.15s;
    text-decoration:none;
    color:inherit;
    display:flex; flex-direction:column;
    position:relative;
}
.ldv-card:hover { box-shadow:0 4px 20px rgba(0,0,0,0.1); }
.ldv-card-title { color:var(--gray-900); display:block; }
/* Stretched-Link: ganze Karte klickbar, aber als echter, fokussierbarer Link */
.ldv-card-titlelink::after { content:''; position:absolute; inset:0; z-index:1; }
.ldv-card-titlelink:focus-visible { outline:2px solid var(--color-primary); outline-offset:2px; }
.ldv-card-img {
    width:100%; height:160px; object-fit:cover; background:var(--gray-100);
    display:flex; align-items:center; justify-content:center;
}
.ldv-card-img img { width:100%; height:100%; object-fit:cover; }
.ldv-card-img-placeholder { color:var(--gray-300); }
.ldv-card-body { padding:1rem; flex:1; display:flex; flex-direction:column; gap:0.35rem; }
.ldv-card-title { font-size:0.95rem; font-weight:700; color:var(--gray-900); }
.ldv-card-type  { font-size:0.78rem; color:var(--gray-500); }
.ldv-card-serial { font-size:0.75rem; color:var(--gray-400); font-family:monospace; }
.ldv-pending-badge {
    display:inline-flex; align-items:center; gap:0.35rem; margin-top:0.5rem;
    font-size:0.72rem; font-weight:700; padding:0.2rem 0.55rem; border-radius:9999px;
    background:var(--blue-50); color:var(--blue-700); border:1px solid var(--blue-200); text-decoration:none;
}
.ldv-pending-badge:hover { background:var(--blue-100); }
.ldv-card-footer { padding:0.65rem 1rem; border-top:1px solid var(--gray-100); display:flex; align-items:center; justify-content:space-between; }
.ldv-card-actions { display:flex; gap:0.4rem; }

/* Empty */
.ldv-empty { text-align:center; padding:4rem 1rem; color:var(--gray-400); }
.ldv-empty svg { display:block; margin:0 auto 1rem; opacity:0.35; }

@media(max-width:768px){
    .filter-card-body form { flex-direction:column; gap:0.5rem; }
    .filter-card-body input, .filter-card-body select, .filter-card-body button { width:100%; box-sizing:border-box; }
    .ldv-tab-bar { padding:0 1rem; overflow-x:auto; white-space:nowrap; }
    .ldv-grid { grid-template-columns:1fr; }
}
@media(max-width:480px){
    .ldv-card-actions { flex-direction:column; }
}
</style>

<div class="ldv-wrap">
    <!-- Content Header -->
    <div class="content-header">
        <div>
            <h1><?= $this->te('Leihgeräte') ?></h1>
            <ol class="breadcrumb">
                <li class="breadcrumb-item"><a href="/"><?= $this->te('Home') ?></a></li>
                <li class="breadcrumb-item"><a href="/loans"><?= $this->te('Leihgeräte') ?></a></li>
                <li class="breadcrumb-item active"><?= $this->te('Geräteliste') ?></li>
            </ol>
        </div>
        <div class="content-header-actions">
            <a href="/loans" class="btn btn-default"><?= $this->te('Kalender') ?></a>
            <a href="/loans/lendings" class="btn btn-default"><?= $this->te('Ausleihen') ?></a>
            <?php if ($can_manage): ?>
            <a href="/loans/devices/create" class="btn btn-warning"><?= $this->te('Neues Gerät') ?></a>
            <?php endif; ?>
        </div>
    </div>

    <!-- KPI Small Boxes -->
    <div class="page-body" style="padding-bottom:0;">
        <div class="kpi-row">
            <div class="kpi-col">
                <div class="small-box bg-info">
                    <div class="inner"><h3><?= (int)$summary['total'] ?></h3><p><?= $this->te('Gesamt') ?></p></div>
                    <div class="icon"><i class="fas fa-laptop"></i></div>
                </div>
            </div>
            <div class="kpi-col">
                <div class="small-box bg-success">
                    <div class="inner"><h3><?= (int)$summary['available'] ?></h3><p><?= $this->te('Verfügbar') ?></p></div>
                    <div class="icon"><i class="fas fa-check"></i></div>
                </div>
            </div>
            <div class="kpi-col">
                <div class="small-box <?= (int)$summary['lent'] > 0 ? 'bg-warning' : 'bg-secondary' ?>">
                    <div class="inner"><h3><?= (int)$summary['lent'] ?></h3><p><?= $this->te('Ausgeliehen') ?></p></div>
                    <div class="icon"><i class="fas fa-share-square"></i></div>
                </div>
            </div>
            <div class="kpi-col">
                <div class="small-box bg-secondary">
                    <div class="inner"><h3><?= (int)$summary['reserved'] ?></h3><p><?= $this->te('Reserviert') ?></p></div>
                    <div class="icon"><i class="fas fa-clock"></i></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Filter -->
    <div class="page-body" style="padding-bottom:0;padding-top:0;">
        <div class="card card-outline card-primary mb-0">
            <div class="filter-card-body">
                <form method="GET" action="/loans/devices" style="display:flex;gap:0.75rem;flex-wrap:wrap;width:100%;align-items:center;">
                    <input type="search" name="q" value="<?= $this->e($search) ?>" placeholder="<?= $this->te('Ger&auml;t suchen…') ?>" class="form-control form-control-sm" style="min-width:200px;width:auto;" autocomplete="off">
                    <select name="type" class="form-control form-control-sm" style="width:auto;" onchange="this.form.submit()">
                        <option value=""><?= $this->te('Alle Typen') ?></option>
                        <?php foreach ($types as $t): ?>
                            <option value="<?= $this->e($t['type']) ?>" <?= $type_filter === $t['type'] ? 'selected' : '' ?>><?= $this->e($t['type']) ?></option>
                        <?php endforeach; ?>
                    </select>
                    <select name="status" class="form-control form-control-sm" style="width:auto;" onchange="this.form.submit()">
                        <option value=""><?= $this->te('Alle Status') ?></option>
                        <?php foreach ($statusLabels as $val => [$label, $col]): ?>
                            <option value="<?= $val ?>" <?= $status_filter === $val ? 'selected' : '' ?>><?= $label ?></option>
                        <?php endforeach; ?>
                    </select>
                    <button type="submit" class="btn btn-sm btn-primary"><?= $this->te('Suchen') ?></button>
                    <?php if ($search || $status_filter || $type_filter): ?>
                        <a href="/loans/devices" class="btn btn-sm btn-default"><?= $this->te('Zur&uuml;cksetzen') ?></a>
                    <?php endif; ?>
                    <span style="margin-left:auto;font-size:0.82rem;color:var(--gray-500);"><?= count($devices) ?> Ger&auml;t<?= count($devices) !== 1 ? 'e' : '' ?></span>
                </form>
            </div>
        </div>
    </div>

    <!-- Body -->
    <div class="page-body" style="padding-top:0.75rem;">
        <?php if (empty($devices)): ?>
            <div class="ldv-empty">
                <svg width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
                <p style="font-weight:600;margin-bottom:0.5rem;"><?= $this->te('Keine Ger&auml;te gefunden') ?></p>
                <?php if ($can_manage): ?>
                    <a href="/loans/devices/create" style="color:var(--amber-600);font-weight:600;font-size:0.85rem;"><?= $this->te('Erstes Ger&auml;t anlegen &rarr;') ?></a>
                <?php endif; ?>
            </div>
        <?php else: ?>
            <div class="ldv-grid">
                <?php foreach ($devices as $device):
                    [$slabel, $scol] = $statusLabels[$device['status']] ?? ['Unbekannt','status-pill--neutral'];
                ?>
                <div class="ldv-card">
                    <div class="ldv-card-img">
                        <?php if (!empty($device['image_path'])): ?>
                            <img src="<?= $this->e($device['image_path']) ?>" alt="<?= $this->e($device['title']) ?>">
                        <?php else: ?>
                            <svg class="ldv-card-img-placeholder" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
                        <?php endif; ?>
                    </div>
                    <div class="ldv-card-body">
                        <a href="/loans/devices/<?= $device['id'] ?>" class="ldv-card-title ldv-card-titlelink"><?= $this->e($device['title']) ?></a>
                        <?php if ($device['type']): ?><div class="ldv-card-type"><?= $this->e($device['type']) ?></div><?php endif; ?>
                        <?php if ($device['serial_number']): ?><div class="ldv-card-serial">S/N: <?= $this->e($device['serial_number']) ?></div><?php endif; ?>
                        <?php if (!empty($device['pending_count'])): ?>
                            <a href="/loans" class="ldv-pending-badge" title="<?= $this->te('Offene Self-Service-Anfrage(n) – warten auf Freigabe') ?>">
                                <i class="fas fa-hourglass-half"></i>
                                <?= (int)$device['pending_count'] ?> Anfrage<?= (int)$device['pending_count'] !== 1 ? 'n' : '' ?> offen
                            </a>
                        <?php endif; ?>
                    </div>
                    <div class="ldv-card-footer">
                        <span class="status-pill <?= $scol ?>"><?= $slabel ?></span>
                        <?php if ($can_issue && $device['status'] === 'available'): ?>
                            <a href="/loans/issue/<?= $device['id'] ?>" class="btn btn-sm btn-primary" style="position:relative;z-index:2;"><?= $this->te('Ausgeben') ?></a>
                        <?php elseif ($can_issue && $device['status'] === 'reserved' && !empty($device['current_lending_id'])): ?>
                            <a href="/loans/lendings/<?= (int)$device['current_lending_id'] ?>" class="btn btn-sm btn-default" style="position:relative;z-index:2;"><?= $this->te('Herausgeben') ?></a>
                        <?php elseif ($can_issue && $device['status'] === 'lent' && !empty($device['current_lending_id'])): ?>
                            <a href="/loans/lendings/<?= (int)$device['current_lending_id'] ?>/return" class="btn btn-sm btn-default" style="position:relative;z-index:2;"><?= $this->te('Zurücknehmen') ?></a>
                        <?php endif; ?>
                    </div>
                </div>
                <?php endforeach; ?>
            </div>
        <?php endif; ?>
    </div>
</div>