feat: admin testimonials management

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Gestoría LP
2026-03-02 00:38:56 +00:00
parent 3e12204828
commit 1ae40bf071

302
admin/testimonios.php Normal file
View File

@@ -0,0 +1,302 @@
<?php
$pageTitle = 'Testimonios';
require_once __DIR__ . '/../includes/db.php';
require_once __DIR__ . '/includes/admin-header.php';
$db = getDB();
$errors = [];
$success = '';
// ── Handle POST actions ─────────────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrfValidate()) {
$action = $_POST['action'] ?? '';
switch ($action) {
// ── Add testimonial ─────────────────────────────────────
case 'add_testimonial':
$nombre = trim($_POST['nombre_cliente'] ?? '');
$texto = trim($_POST['texto'] ?? '');
$calificacion = (int)($_POST['calificacion'] ?? 0);
if ($nombre === '') {
$errors[] = 'El nombre del cliente es obligatorio.';
}
if ($texto === '') {
$errors[] = 'El texto del testimonio es obligatorio.';
}
if ($calificacion < 1 || $calificacion > 5) {
$errors[] = 'La calificaci&oacute;n debe ser entre 1 y 5.';
}
if (empty($errors)) {
$stmt = $db->prepare("INSERT INTO testimonios
(nombre_cliente, texto, calificacion, activo, created_at)
VALUES (?, ?, ?, 1, NOW())");
$stmt->execute([$nombre, $texto, $calificacion]);
header('Location: testimonios.php?added=1');
exit;
}
break;
// ── Edit testimonial ────────────────────────────────────
case 'edit_testimonial':
$id = (int)($_POST['testimonial_id'] ?? 0);
$nombre = trim($_POST['nombre_cliente'] ?? '');
$texto = trim($_POST['texto'] ?? '');
$calificacion = (int)($_POST['calificacion'] ?? 0);
if ($nombre === '') {
$errors[] = 'El nombre del cliente es obligatorio.';
}
if ($texto === '') {
$errors[] = 'El texto del testimonio es obligatorio.';
}
if ($calificacion < 1 || $calificacion > 5) {
$errors[] = 'La calificaci&oacute;n debe ser entre 1 y 5.';
}
if (empty($errors) && $id > 0) {
$stmt = $db->prepare("UPDATE testimonios
SET nombre_cliente = ?, texto = ?, calificacion = ?
WHERE id = ?");
$stmt->execute([$nombre, $texto, $calificacion, $id]);
header('Location: testimonios.php?updated=1');
exit;
}
break;
// ── Toggle active ───────────────────────────────────────
case 'toggle_active':
$id = (int)($_POST['testimonial_id'] ?? 0);
if ($id > 0) {
$stmt = $db->prepare("UPDATE testimonios SET activo = !activo WHERE id = ?");
$stmt->execute([$id]);
}
header('Location: testimonios.php?toggled=1');
exit;
// ── Delete testimonial ──────────────────────────────────
case 'delete_testimonial':
$id = (int)($_POST['testimonial_id'] ?? 0);
if ($id > 0) {
$stmt = $db->prepare("DELETE FROM testimonios WHERE id = ?");
$stmt->execute([$id]);
}
header('Location: testimonios.php?deleted=1');
exit;
}
}
// ── Flash messages from redirect ────────────────────────────────
if (isset($_GET['added'])) $success = 'Testimonio creado correctamente.';
if (isset($_GET['updated'])) $success = 'Testimonio actualizado correctamente.';
if (isset($_GET['toggled'])) $success = 'Estado del testimonio actualizado.';
if (isset($_GET['deleted'])) $success = 'Testimonio eliminado correctamente.';
// ── Load testimonial for editing ────────────────────────────────
$editing = false;
$editData = null;
$editId = (int)($_GET['edit'] ?? 0);
if ($editId > 0) {
$stmt = $db->prepare("SELECT * FROM testimonios WHERE id = ?");
$stmt->execute([$editId]);
$editData = $stmt->fetch();
if ($editData) {
$editing = true;
}
}
// ── Fetch all testimonials ──────────────────────────────────────
$stmt = $db->query("SELECT * FROM testimonios ORDER BY created_at DESC");
$testimonios = $stmt->fetchAll();
$totalTestimonios = count($testimonios);
$totalActivos = 0;
foreach ($testimonios as $t) {
if ((int)$t['activo'] === 1) $totalActivos++;
}
?>
<div class="admin-content__header">
<h1>
<i class="fas fa-star"></i> Testimonios
</h1>
<p>Gestiona los testimonios de clientes que se muestran en el sitio p&uacute;blico</p>
</div>
<!-- Success / Error messages -->
<?php if ($success !== ''): ?>
<div class="alert alert--success" style="padding: 0.75rem 1rem; margin-bottom: 1rem; border-radius: 0.5rem; background: var(--admin-success-light); color: #155724; border: 1px solid #C3E6CB;">
<i class="fas fa-check-circle"></i> <?= $success ?>
</div>
<?php endif; ?>
<?php if (!empty($errors)): ?>
<div class="alert alert--danger" style="padding: 0.75rem 1rem; margin-bottom: 1rem; border-radius: 0.5rem; background: var(--admin-danger-light); color: #721C24; border: 1px solid #F5C6CB;">
<i class="fas fa-exclamation-circle"></i>
<ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">
<?php foreach ($errors as $e): ?>
<li><?= $e ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<!-- Add / Edit Testimonial Form -->
<div class="card" style="margin-bottom: 1.5rem;">
<div class="card__header" style="padding: 1rem 1.25rem; border-bottom: 1px solid var(--admin-gray-200); font-weight: 600;">
<i class="fas fa-<?= $editing ? 'edit' : 'plus-circle' ?>"></i>
<?= $editing ? 'Editar Testimonio' : 'Nuevo Testimonio' ?>
<?php if ($editing): ?>
<a href="testimonios.php" style="float: right; font-size: var(--admin-font-sm); font-weight: 400; color: var(--admin-gray-600); text-decoration: none;">
<i class="fas fa-times"></i> Cancelar edici&oacute;n
</a>
<?php endif; ?>
</div>
<div class="card__body">
<form method="POST" action="testimonios.php">
<?= csrfField() ?>
<input type="hidden" name="action" value="<?= $editing ? 'edit_testimonial' : 'add_testimonial' ?>">
<?php if ($editing): ?>
<input type="hidden" name="testimonial_id" value="<?= (int)$editData['id'] ?>">
<?php endif; ?>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; margin-bottom: 1rem;">
<div class="form-group" style="margin-bottom: 0;">
<label>Nombre del cliente <span class="required">*</span></label>
<input type="text" name="nombre_cliente" class="form-control" required
maxlength="150"
value="<?= htmlspecialchars($editing ? $editData['nombre_cliente'] : ($_POST['nombre_cliente'] ?? '')) ?>"
placeholder="Ej: Mar&iacute;a Garc&iacute;a">
</div>
<div class="form-group" style="margin-bottom: 0;">
<label>Calificaci&oacute;n <span class="required">*</span></label>
<?php
$currentRating = $editing ? (int)$editData['calificacion'] : (int)($_POST['calificacion'] ?? 0);
?>
<div style="display: flex; gap: 1rem; padding-top: 0.4rem;">
<?php for ($i = 1; $i <= 5; $i++): ?>
<label style="display: flex; align-items: center; gap: 0.25rem; cursor: pointer; font-size: var(--admin-font-sm);">
<input type="radio" name="calificacion" value="<?= $i ?>"
<?= $currentRating === $i ? 'checked' : '' ?>
required style="margin: 0;">
<?= $i ?> <i class="fas fa-star" style="color: var(--admin-accent);"></i>
</label>
<?php endfor; ?>
</div>
</div>
</div>
<div class="form-group" style="margin-bottom: 1rem;">
<label>Texto del testimonio <span class="required">*</span></label>
<textarea name="texto" class="form-control" rows="3" required
placeholder="Escribe el testimonio del cliente..."><?= htmlspecialchars($editing ? $editData['texto'] : ($_POST['texto'] ?? '')) ?></textarea>
</div>
<button type="submit" class="btn btn--primary">
<i class="fas fa-<?= $editing ? 'save' : 'plus' ?>"></i>
<?= $editing ? 'Guardar Cambios' : 'Agregar Testimonio' ?>
</button>
</form>
</div>
</div>
<!-- Stats bar -->
<div class="toolbar">
<div class="toolbar__left">
<span style="color: var(--admin-gray-600); font-size: var(--admin-font-sm);">
<?= $totalTestimonios ?> testimonio<?= $totalTestimonios !== 1 ? 's' : '' ?> en total
&middot; <?= $totalActivos ?> activo<?= $totalActivos !== 1 ? 's' : '' ?> en el sitio
</span>
</div>
</div>
<!-- Testimonials Cards Grid -->
<?php if (empty($testimonios)): ?>
<div class="card">
<div class="card__body">
<div class="table-empty">
<i class="fas fa-star"></i>
<p>No hay testimonios registrados a&uacute;n.</p>
</div>
</div>
</div>
<?php else: ?>
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 1.25rem;">
<?php foreach ($testimonios as $t):
$isActive = (int)$t['activo'] === 1;
$rating = (int)$t['calificacion'];
?>
<div class="card" style="position: relative; opacity: <?= $isActive ? '1' : '0.65' ?>; border-left: 4px solid <?= $isActive ? 'var(--admin-accent)' : 'var(--admin-gray-400)' ?>;">
<div class="card__body" style="padding: 1.25rem;">
<!-- Header: name + status -->
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.75rem;">
<div>
<h3 style="margin: 0; font-size: 1rem; color: var(--admin-gray-900);">
<i class="fas fa-user-circle" style="color: var(--admin-primary); margin-right: 0.25rem;"></i>
<?= htmlspecialchars($t['nombre_cliente']) ?>
</h3>
<div style="margin-top: 0.35rem;">
<?php for ($i = 1; $i <= 5; $i++): ?>
<?php if ($i <= $rating): ?>
<i class="fas fa-star" style="color: var(--admin-accent); font-size: 0.85rem;"></i>
<?php else: ?>
<i class="far fa-star" style="color: var(--admin-gray-400); font-size: 0.85rem;"></i>
<?php endif; ?>
<?php endfor; ?>
</div>
</div>
<span class="badge badge--<?= $isActive ? 'success' : 'secondary' ?>" style="font-size: 0.7rem;">
<?= $isActive ? 'Activo' : 'Inactivo' ?>
</span>
</div>
<!-- Testimonial text -->
<p style="margin: 0 0 1rem 0; color: var(--admin-gray-700); font-size: var(--admin-font-sm); line-height: 1.6; font-style: italic;">
&ldquo;<?= htmlspecialchars($t['texto']) ?>&rdquo;
</p>
<!-- Date -->
<div style="font-size: var(--admin-font-xs); color: var(--admin-gray-500); margin-bottom: 0.75rem;">
<i class="fas fa-calendar-alt"></i> <?= date('d/m/Y', strtotime($t['created_at'])) ?>
</div>
<!-- Actions -->
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap; border-top: 1px solid var(--admin-gray-200); padding-top: 0.75rem;">
<!-- Toggle active -->
<form method="POST" action="testimonios.php" style="display: inline;">
<?= csrfField() ?>
<input type="hidden" name="action" value="toggle_active">
<input type="hidden" name="testimonial_id" value="<?= (int)$t['id'] ?>">
<button type="submit" class="btn btn--sm btn--<?= $isActive ? 'warning' : 'success' ?>"
title="<?= $isActive ? 'Desactivar' : 'Activar' ?>">
<i class="fas fa-<?= $isActive ? 'eye-slash' : 'eye' ?>"></i>
<?= $isActive ? 'Desactivar' : 'Activar' ?>
</button>
</form>
<!-- Edit -->
<a href="testimonios.php?edit=<?= (int)$t['id'] ?>" class="btn btn--sm btn--secondary" title="Editar">
<i class="fas fa-edit"></i> Editar
</a>
<!-- Delete -->
<form method="POST" action="testimonios.php" style="display: inline;"
onsubmit="return confirm('&iquest;Eliminar este testimonio?');">
<?= csrfField() ?>
<input type="hidden" name="action" value="delete_testimonial">
<input type="hidden" name="testimonial_id" value="<?= (int)$t['id'] ?>">
<button type="submit" class="btn btn--sm btn--danger" title="Eliminar">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php require_once __DIR__ . '/includes/admin-footer.php'; ?>