index.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. require_once __DIR__ . '/../config.php';
  3. require_once __DIR__ . '/../includes/functions.php';
  4. require_once __DIR__ . '/../includes/manage.php';
  5. // Check admin login
  6. if (!isset($_SESSION['admin_logged_in']) || !$_SESSION['admin_logged_in']) {
  7. header('Location: login.php');
  8. exit;
  9. }
  10. $pageTitle = 'Admin Dashboard';
  11. // Get statistics
  12. $products = getProducts();
  13. $reservations = getReservations();
  14. // Expire old reservations
  15. expireOldReservations();
  16. $reservations = getReservations(); // Refresh after expiry
  17. // This host has no cron, so the weekly backup is triggered here - the dashboard
  18. // is the admin page loaded most reliably, and manageBackupCreateAutomaticIfDue()
  19. // returns immediately unless MANAGE_BACKUP_AUTO_INTERVAL_SECONDS has elapsed.
  20. // A failing backup must never take the dashboard down with it.
  21. $backupNotice = null;
  22. try {
  23. $automaticBackup = manageBackupCreateAutomaticIfDue();
  24. if ($automaticBackup !== null) {
  25. $backupNotice = [
  26. 'type' => 'success',
  27. 'text' => 'Automatisches Backup erstellt: ' . $automaticBackup['filename'] .
  28. ' (' . manageFormatBytes((int) $automaticBackup['size']) . ').'
  29. ];
  30. }
  31. } catch (Throwable $exception) {
  32. manageClientLog('ERROR', 'Automatic backup from dashboard failed', [
  33. 'error' => $exception->getMessage(),
  34. ]);
  35. $backupNotice = [
  36. 'type' => 'warning',
  37. 'text' => 'Das automatische Backup ist fehlgeschlagen: ' . $exception->getMessage()
  38. ];
  39. }
  40. $regularReservations = array_filter($reservations, function($r) {
  41. return (!isset($r['type']) || $r['type'] !== 'backorder') && !isReservationHidden($r);
  42. });
  43. $backorderReservations = array_filter($reservations, function($r) {
  44. return isset($r['type']) && $r['type'] === 'backorder' && !isReservationHidden($r);
  45. });
  46. $totalProducts = count($products);
  47. $totalStock = 0;
  48. foreach ($products as $product) {
  49. $totalStock += getTotalStock($product);
  50. }
  51. $openReservations = count(array_filter($regularReservations, function($r) {
  52. return $r['status'] === 'open' && !$r['picked_up'];
  53. }));
  54. $pickedUpReservations = count(array_filter($regularReservations, function($r) {
  55. return $r['picked_up'];
  56. }));
  57. $openRegularReservations = array_values(array_filter($regularReservations, function($r) {
  58. return $r['status'] === 'open' && !$r['picked_up'];
  59. }));
  60. $openPreorders = array_values(array_filter($backorderReservations, function($r) {
  61. return !isset($r['backorder_status']) || $r['backorder_status'] !== 'notified';
  62. }));
  63. $openBackorders = count($openPreorders);
  64. $bodyClass = 'admin-page';
  65. include __DIR__ . '/../includes/header.php';
  66. ?>
  67. <?php if ($backupNotice !== null): ?>
  68. <div class="alert alert-<?php echo htmlspecialchars($backupNotice['type']); ?>">
  69. <?php echo htmlspecialchars($backupNotice['text']); ?>
  70. </div>
  71. <?php endif; ?>
  72. <div class="admin-header">
  73. <h2>Admin Dashboard</h2>
  74. <div class="admin-dashboard-actions">
  75. <a href="reservations.php" class="btn">Reservierungen</a>
  76. <a href="backorders.php" class="btn">Vorbestellungen</a>
  77. <details class="admin-actions-dropdown">
  78. <summary class="btn btn-secondary">Verwaltung</summary>
  79. <div class="admin-actions-menu">
  80. <a href="products.php">Produkte verwalten</a>
  81. <a href="categories.php">Kategorien verwalten</a>
  82. <a href="faq.php">FAQ bearbeiten</a>
  83. <a href="settings.php">Einstellungen</a>
  84. <a href="login.php?logout=1">Abmelden</a>
  85. </div>
  86. </details>
  87. </div>
  88. </div>
  89. <div class="admin-stats">
  90. <div class="stat-card">
  91. <h3>Produkte</h3>
  92. <div class="stat-value"><?php echo $totalProducts; ?></div>
  93. </div>
  94. <div class="stat-card">
  95. <h3>Gesamtbestand</h3>
  96. <div class="stat-value"><?php echo $totalStock; ?></div>
  97. </div>
  98. <div class="stat-card">
  99. <h3>Offene Reservierungen</h3>
  100. <div class="stat-value"><?php echo $openReservations; ?></div>
  101. </div>
  102. <div class="stat-card">
  103. <h3>Abgeholt</h3>
  104. <div class="stat-value"><?php echo $pickedUpReservations; ?></div>
  105. </div>
  106. <div class="stat-card">
  107. <h3>Offene Vorbestellungen</h3>
  108. <div class="stat-value"><?php echo $openBackorders; ?></div>
  109. </div>
  110. </div>
  111. <h3 style="margin-top: 2rem;">Offene Reservierungen</h3>
  112. <?php
  113. $openReservationsList = array_slice(array_reverse($openRegularReservations), 0, 5);
  114. if (empty($openReservationsList)):
  115. ?>
  116. <p>Keine offenen Reservierungen vorhanden.</p>
  117. <?php else: ?>
  118. <div class="table-responsive">
  119. <table class="responsive-table">
  120. <thead>
  121. <tr>
  122. <th>Bestellnummer</th>
  123. <th>Kunde</th>
  124. <th>Erstellt</th>
  125. <th>Status</th>
  126. <th>Aktionen</th>
  127. </tr>
  128. </thead>
  129. <tbody>
  130. <?php foreach ($openReservationsList as $reservation): ?>
  131. <tr>
  132. <td data-label="Bestellnummer"><strong><?php echo htmlspecialchars($reservation['id']); ?></strong></td>
  133. <td data-label="Kunde"><?php echo htmlspecialchars($reservation['customer_name']); ?></td>
  134. <td data-label="Erstellt"><?php echo formatDate($reservation['created']); ?></td>
  135. <td data-label="Status">
  136. <?php
  137. if ($reservation['picked_up']) {
  138. echo '<span class="status status-picked">Abgeholt</span>';
  139. } elseif ($reservation['status'] === 'expired') {
  140. echo '<span class="status status-expired">Abgelaufen</span>';
  141. } else {
  142. echo '<span class="status status-open">Offen</span>';
  143. }
  144. ?>
  145. </td>
  146. <td data-label="Aktionen">
  147. <a href="reservations.php?order_number=<?php echo urlencode($reservation['id']); ?>" class="btn btn-small">Details</a>
  148. </td>
  149. </tr>
  150. <?php endforeach; ?>
  151. </tbody>
  152. </table>
  153. </div>
  154. <?php endif; ?>
  155. <h3 style="margin-top: 2rem;">Offene Vorbestellungen</h3>
  156. <?php
  157. $openPreordersList = array_slice(array_reverse($openPreorders), 0, 5);
  158. if (empty($openPreordersList)):
  159. ?>
  160. <p>Keine offenen Vorbestellungen vorhanden.</p>
  161. <?php else: ?>
  162. <div class="table-responsive">
  163. <table class="responsive-table">
  164. <thead>
  165. <tr>
  166. <th>Bestellnummer</th>
  167. <th>Kunde</th>
  168. <th>Erstellt</th>
  169. <th>Status</th>
  170. <th>Aktionen</th>
  171. </tr>
  172. </thead>
  173. <tbody>
  174. <?php foreach ($openPreordersList as $reservation): ?>
  175. <tr>
  176. <td data-label="Bestellnummer"><strong><?php echo htmlspecialchars($reservation['id']); ?></strong></td>
  177. <td data-label="Kunde"><?php echo htmlspecialchars($reservation['customer_name']); ?></td>
  178. <td data-label="Erstellt"><?php echo formatDate($reservation['created']); ?></td>
  179. <td data-label="Status">
  180. <?php
  181. if (isset($reservation['backorder_status']) && $reservation['backorder_status'] === 'notified') {
  182. echo '<span class="status status-notified">Informiert</span>';
  183. } else {
  184. echo '<span class="status status-open">Offen</span>';
  185. }
  186. ?>
  187. </td>
  188. <td data-label="Aktionen">
  189. <a href="backorders.php?order_number=<?php echo urlencode($reservation['id']); ?>" class="btn btn-small">Details</a>
  190. </td>
  191. </tr>
  192. <?php endforeach; ?>
  193. </tbody>
  194. </table>
  195. </div>
  196. <?php endif; ?>
  197. <?php include __DIR__ . '/../includes/footer.php'; ?>