<?php
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/includes/crud_config.php';
require_login();
$moduleKey = $_GET['module'] ?? '';
$module = crud_module($moduleKey);
if (!$module) {
http_response_code(404);
die('Unknown module.');
}
$pageTitle = $module['title'];
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'delete' && csrf_verify()) {
$id = (int) ($_POST['id'] ?? 0);
$stmt = db()->prepare("DELETE FROM {$module['table']} WHERE id = ?");
$stmt->execute([$id]);
flash_set('success', $module['singular'] . ' deleted.');
redirect('crud.php?module=' . urlencode($moduleKey));
}
$rows = db()->query("SELECT * FROM {$module['table']} ORDER BY {$module['order_by']}")->fetchAll();
// Resolve select_dynamic option labels for list display.
$dynamicLabels = [];
foreach ($module['fields'] as $fkey => $f) {
if (($f['type'] ?? '') === 'select_dynamic') {
$opts = db()->query($f['options_query'])->fetchAll();
foreach ($opts as $o) {
$dynamicLabels[$fkey][$o['id']] = $o['name'] ?? $o[array_key_last($o)];
}
}
}
require __DIR__ . '/partials/header.php';
require __DIR__ . '/partials/sidebar.php';
require __DIR__ . '/partials/topbar.php';
?>
<div class="flex items-center justify-between mb-5">
<p class="text-gray-500 text-sm"><?= count($rows) ?> total <?= e(strtolower($module['singular'])) ?>(s)</p>
<a href="crud_form.php?module=<?= urlencode($moduleKey) ?>" class="bg-gradient-to-r from-brand-red to-brand-green text-white text-sm font-semibold px-5 py-2.5 rounded-xl hover:brightness-110 transition">
<i class="fa-solid fa-plus mr-1"></i> Add New <?= e($module['singular']) ?>
</a>
</div>
<div class="bg-white rounded-2xl shadow-sm overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-gray-50">
<tr class="text-left text-gray-400">
<?php foreach ($module['list_columns'] as $col): ?>
<th class="px-5 py-3 font-medium"><?= e($module['fields'][$col]['label'] ?? ucfirst(str_replace('_', ' ', $col))) ?></th>
<?php endforeach; ?>
<th class="px-5 py-3 font-medium text-right">Actions</th>
</tr>
</thead>
<tbody>
<?php if (!$rows): ?>
<tr><td colspan="<?= count($module['list_columns']) + 1 ?>" class="px-5 py-8 text-center text-gray-400">No records yet. Click "Add New" to create one.</td></tr>
<?php endif; ?>
<?php foreach ($rows as $row): ?>
<tr class="border-t border-gray-100 hover:bg-gray-50/60">
<?php foreach ($module['list_columns'] as $col):
$ftype = $module['fields'][$col]['type'] ?? 'text';
$val = $row[$col] ?? '';
?>
<td class="px-5 py-3">
<?php if ($ftype === 'image' && $val): ?>
<img src="<?= e(resolve_image($val)) ?>" class="h-10 w-16 object-cover rounded-lg">
<?php elseif ($ftype === 'select_dynamic'): ?>
<?= e($dynamicLabels[$col][$val] ?? '—') ?>
<?php elseif ($col === 'status'): ?>
<span class="px-2.5 py-1 rounded-full text-xs font-medium <?= $val === 'active' ? 'bg-brand-green/10 text-brand-green' : 'bg-gray-200 text-gray-500' ?>"><?= e(ucfirst($val)) ?></span>
<?php elseif ($col === 'rating'): ?>
<?= str_repeat('★', (int) $val) ?>
<?php else: ?>
<?= e(mb_strimwidth((string) $val, 0, 60, '…')) ?>
<?php endif; ?>
</td>
<?php endforeach; ?>
<td class="px-5 py-3 text-right whitespace-nowrap">
<a href="crud_form.php?module=<?= urlencode($moduleKey) ?>&id=<?= (int) $row['id'] ?>" class="text-brand-green hover:text-green-700 mr-3"><i class="fa-solid fa-pen-to-square"></i></a>
<form method="post" class="inline" onsubmit="return confirm('Delete this <?= e(strtolower($module['singular'])) ?>?');">
<?= csrf_field() ?>
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= (int) $row['id'] ?>">
<button type="submit" class="text-brand-red hover:text-red-700"><i class="fa-solid fa-trash"></i></button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php require __DIR__ . '/partials/footer.php'; ?>