Auto commit: 2026-06-30T17:47:46.239Z

This commit is contained in:
Flatlogic Bot 2026-06-30 17:47:46 +00:00
parent 25bda934e0
commit 16f68f469d
6 changed files with 145 additions and 13 deletions

View File

@ -109,6 +109,53 @@ h1, h2, h3 { letter-spacing: -.04em; }
}
.status-row strong { color: var(--primary-dark); }
.payment-icons {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.payment-icons.compact { margin-top: 8px; }
.payment-card-icon {
min-width: 74px;
height: 34px;
border-radius: 9px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 10px;
font-size: .78rem;
font-weight: 900;
letter-spacing: .03em;
border: 1px solid rgba(18, 49, 31, .14);
box-shadow: 0 8px 16px rgba(18, 49, 31, .08);
}
.payment-card-icon.visa {
background: linear-gradient(135deg, #1434cb 0%, #1a4cff 100%);
color: #fff;
font-style: italic;
letter-spacing: .1em;
}
.payment-card-icon.mastercard {
position: relative;
justify-content: flex-end;
min-width: 112px;
padding-left: 42px;
background: #fff;
color: #231f20;
}
.payment-card-icon.mastercard::before,
.payment-card-icon.mastercard::after {
content: "";
position: absolute;
top: 8px;
width: 19px;
height: 19px;
border-radius: 999px;
}
.payment-card-icon.mastercard::before { left: 12px; background: rgba(235, 0, 27, .9); }
.payment-card-icon.mastercard::after { left: 25px; background: rgba(247, 158, 27, .9); mix-blend-mode: multiply; }
.section-heading { margin-bottom: 22px; max-width: 760px; }
.section-heading p { color: var(--muted); margin: 0; }
.product-card { overflow: hidden; transition: transform .18s ease, box-shadow .18s ease; }
@ -168,6 +215,45 @@ h1, h2, h3 { letter-spacing: -.04em; }
.whatsapp-float:hover { background: #0f8a43; color: #fff; transform: translateY(-2px); }
.cart-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 16px; }
.checkout-panel {
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
padding: 20px;
border-color: #ffc247;
}
.checkout-panel h2 {
margin: 10px 0 6px;
font-size: 1.35rem;
}
.checkout-panel p {
margin: 0;
color: var(--muted);
}
.checkout-panel-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
flex-wrap: wrap;
min-width: min(100%, 360px);
}
.accepted-cards {
border: 1px solid var(--border);
border-radius: 12px;
padding: 12px;
margin-bottom: 18px;
background: #fffaf0;
}
.accepted-cards > span {
display: block;
color: var(--muted);
font-size: .86rem;
font-weight: 800;
margin-bottom: 8px;
}
.total, .summary-total { font-size: 1.1rem; font-weight: 900; }
.form-panel, .summary { padding: 20px; }
.summary h2 { font-size: 1.25rem; }
@ -223,5 +309,8 @@ h1, h2, h3 { letter-spacing: -.04em; }
.product-visual.detail { height: 260px; }
.cart-actions { align-items: stretch; }
.cart-actions .btn { width: 100%; }
.checkout-panel { align-items: stretch; flex-direction: column; }
.checkout-panel-actions { justify-content: stretch; min-width: 100%; }
.checkout-panel-actions .btn { width: 100%; }
.total { width: 100%; }
}

View File

@ -16,11 +16,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
header('Location: cart.php'); exit;
}
$items = cart_items();
$addedProduct = isset($_GET['added']) ? get_product((string)$_GET['added']) : null;
layout_header('Carrito', 'Carrito de compra LA BORGUITA con precios en dólares.');
?>
<section class="py-5">
<div class="container">
<div class="section-heading"><span class="eyebrow">Carrito</span><h1>Revisa tu compra</h1><p>Ajusta cantidades antes de subir el comprobante de pago.</p></div>
<?php if ($addedProduct): ?><div class="alert alert-success alert-dismissible fade show" role="alert"><strong><?= h($addedProduct['name']) ?></strong> se agregó al carrito. Ya puedes continuar al pago o seguir comprando.<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Cerrar"></button></div><?php endif; ?>
<?php if (!$items): ?>
<div class="empty-state"><h2>Tu carrito está vacío</h2><p>Agrega productos del catálogo para iniciar un pedido.</p><a class="btn btn-dark" href="index.php#catalogo">Ir al catálogo</a></div>
<?php else: ?>
@ -29,8 +31,20 @@ layout_header('Carrito', 'Carrito de compra LA BORGUITA con precios en dólares.
<div class="table-responsive surface"><table class="table align-middle mb-0"><thead><tr><th>Producto</th><th>Precio</th><th>Cantidad</th><th>Total</th></tr></thead><tbody>
<?php foreach ($items as $item): ?><tr><td><strong><?= h($item['name']) ?></strong><br><small class="text-secondary">Stock <?= (int)$item['stock'] ?></small></td><td><?= h(money((float)$item['price'])) ?></td><td><input class="form-control qty" type="number" name="qty[<?= h($item['id']) ?>]" value="<?= (int)$item['qty'] ?>" min="0" max="<?= (int)$item['stock'] ?>"></td><td><?= h(money((float)$item['line_total'])) ?></td></tr><?php endforeach; ?>
</tbody></table></div>
<div class="cart-actions"><button class="btn btn-outline-dark" type="submit">Actualizar</button><button class="btn btn-outline-secondary" type="submit" name="action" value="clear">Vaciar</button><div class="ms-md-auto total">Total: <?= h(money(cart_total())) ?></div><a class="btn btn-dark btn-lg" href="checkout.php">Continuar al pago</a></div>
<div class="cart-actions"><button class="btn btn-outline-dark" type="submit">Actualizar cantidades</button><button class="btn btn-outline-secondary" type="submit" name="action" value="clear">Vaciar carrito</button><a class="btn btn-outline-dark" href="index.php#catalogo">Seguir comprando</a></div>
</form>
<div class="checkout-panel surface mt-3">
<div>
<span class="eyebrow">Carrito activo</span>
<h2>Listo para elegir forma de pago</h2>
<p>Tu carrito ya tiene productos. Continúa para seleccionar QR, Visa, Mastercard o transferencia.</p>
<?= payment_icons_html('mt-2') ?>
</div>
<div class="checkout-panel-actions">
<div class="total">Total: <?= h(money(cart_total())) ?></div>
<a class="btn btn-dark btn-lg" href="checkout.php">Continuar al pago</a>
</div>
</div>
<?php endif; ?>
</div>
</section>

View File

@ -56,6 +56,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$successId = isset($_GET['success']) ? (int)$_GET['success'] : 0;
$order = $successId ? get_order($successId) : null;
$selectedMethod = (string)($_POST['payment_method'] ?? 'qr');
layout_header('Checkout', 'Checkout con QR, tarjeta, transferencia y comprobante manual para LA BORGUITA.');
?>
<section class="py-5">
@ -74,7 +75,15 @@ layout_header('Checkout', 'Checkout con QR, tarjeta, transferencia y comprobante
<div class="col-md-6"><label class="form-label">Nombre</label><input class="form-control" name="customer_name" required value="<?= h((string)($_POST['customer_name'] ?? '')) ?>"></div>
<div class="col-md-6"><label class="form-label">Email</label><input class="form-control" type="email" name="customer_email" required value="<?= h((string)($_POST['customer_email'] ?? '')) ?>"></div>
<div class="col-md-6"><label class="form-label">WhatsApp / teléfono</label><input class="form-control" name="customer_phone" required value="<?= h((string)($_POST['customer_phone'] ?? '')) ?>"></div>
<div class="col-md-6"><label class="form-label">Método</label><select class="form-select" name="payment_method"><option value="qr">QR de pago</option><option value="card">Visa/Mastercard MX/US</option><option value="transfer">Transferencia</option></select></div>
<div class="col-md-6">
<label class="form-label">Método</label>
<select class="form-select" name="payment_method">
<option value="qr" <?= $selectedMethod === 'qr' ? 'selected' : '' ?>>QR de pago</option>
<option value="card" <?= $selectedMethod === 'card' ? 'selected' : '' ?>>Visa/Mastercard MX/US</option>
<option value="transfer" <?= $selectedMethod === 'transfer' ? 'selected' : '' ?>>Transferencia</option>
</select>
<?= payment_icons_html('mt-2') ?>
</div>
<div class="col-12"><label class="form-label">Notas de entrega</label><textarea class="form-control" name="delivery_notes" rows="3"><?= h((string)($_POST['delivery_notes'] ?? '')) ?></textarea></div>
<div class="col-12"><label class="form-label">Comprobante de pago</label><input class="form-control" type="file" name="proof" accept="image/png,image/jpeg,application/pdf" required><div class="form-text">JPG, PNG o PDF hasta 8 MB. El admin aprobará manualmente.</div></div>
</div>
@ -82,7 +91,7 @@ layout_header('Checkout', 'Checkout con QR, tarjeta, transferencia y comprobante
</form>
</div>
<div class="col-lg-5">
<aside class="surface summary"><div class="scan-box compact"><span>QR de pago</span><small>Coloca el QR real aquí más adelante.</small></div><h2>Resumen</h2><?php foreach ($items as $item): ?><div class="summary-line"><span><?= h($item['name']) ?> × <?= (int)$item['qty'] ?></span><strong><?= h(money((float)$item['line_total'])) ?></strong></div><?php endforeach; ?><div class="summary-total"><span>Total</span><strong><?= h(money(cart_total())) ?></strong></div></aside>
<aside class="surface summary"><div class="scan-box compact"><span>QR de pago</span><small>Coloca el QR real aquí más adelante.</small></div><div class="accepted-cards"><span>Aceptamos tarjetas</span><?= payment_icons_html('compact') ?></div><h2>Resumen</h2><?php foreach ($items as $item): ?><div class="summary-line"><span><?= h($item['name']) ?> × <?= (int)$item['qty'] ?></span><strong><?= h(money((float)$item['line_total'])) ?></strong></div><?php endforeach; ?><div class="summary-total"><span>Total</span><strong><?= h(money(cart_total())) ?></strong></div></aside>
</div>
</div>
<?php endif; ?>

View File

@ -75,6 +75,11 @@ function money(float $amount): string {
return '$' . number_format($amount, 2) . ' USD';
}
function payment_icons_html(string $extraClass = ''): string {
$class = trim('payment-icons ' . $extraClass);
return '<div class="' . h($class) . '" aria-label="Tarjetas aceptadas"><span class="payment-card-icon visa" aria-label="Visa">VISA</span><span class="payment-card-icon mastercard" aria-label="Mastercard">Mastercard</span></div>';
}
function ensure_orders_table(): void {
db()->exec("CREATE TABLE IF NOT EXISTS lb_orders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

View File

@ -10,8 +10,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'add')
$product = get_product($id);
if ($product) {
$_SESSION['cart'][$id] = min((int)$product['stock'], (int)($_SESSION['cart'][$id] ?? 0) + $qty);
$notice = $product['name'] . ' añadido al carrito.';
$next = (string)($_POST['next'] ?? 'cart');
if ($next === 'checkout') {
header('Location: checkout.php');
exit;
}
header('Location: cart.php?added=' . rawurlencode($id));
exit;
}
$notice = 'No pudimos agregar el producto. Inténtalo de nuevo.';
}
layout_header('Tienda virtual', 'LA BORGUITA: tienda virtual con catálogo, carrito, QR de pago y confirmación manual.');
@ -33,7 +40,7 @@ $logoPath = store_logo_path();
</div>
<div class="col-lg-5">
<div class="market-card">
<div class="market-top"><span class="brand-logo lg"><img src="<?= h($logoPath) ?>" alt="" width="64" height="64"></span><div><strong>LA BORGUITA</strong><small>Pagos Visa · Mastercard · Transferencia</small></div></div>
<div class="market-top"><span class="brand-logo lg"><img src="<?= h($logoPath) ?>" alt="" width="64" height="64"></span><div><strong>LA BORGUITA</strong><small>Pagos Visa · Mastercard · Transferencia</small><?= payment_icons_html('compact') ?></div></div>
<div class="scan-box"><span>Espacio para QR de pago</span><small>Sube aquí tu QR definitivo desde el editor cuando lo tengas listo.</small></div>
<div class="status-row"><span>Pedidos pendientes</span><strong>Revisión manual</strong></div>
</div>
@ -59,12 +66,15 @@ $logoPath = store_logo_path();
<h3><?= h($product['name']) ?></h3>
<p><?= h($product['description']) ?></p>
<div class="price"><?= h(money((float)$product['price'])) ?></div>
<form method="post" class="d-flex gap-2 mt-3">
<form method="post" class="product-actions mt-3">
<input type="hidden" name="action" value="add">
<input type="hidden" name="product_id" value="<?= h($product['id']) ?>">
<input class="form-control qty" type="number" name="qty" value="1" min="1" max="<?= (int)$product['stock'] ?>" aria-label="Cantidad">
<button class="btn btn-dark" type="submit">Agregar</button>
<a class="btn btn-outline-secondary" href="product.php?id=<?= h($product['id']) ?>">Detalle</a>
<div class="d-flex gap-2 align-items-center flex-wrap">
<input class="form-control qty" type="number" name="qty" value="1" min="1" max="<?= (int)$product['stock'] ?>" aria-label="Cantidad">
<button class="btn btn-dark" type="submit" name="next" value="cart">Agregar</button>
<button class="btn btn-outline-dark" type="submit" name="next" value="checkout">Pagar</button>
<a class="btn btn-outline-secondary" href="product.php?id=<?= h($product['id']) ?>">Detalle</a>
</div>
</form>
</div>
</article>
@ -78,7 +88,7 @@ $logoPath = store_logo_path();
<div class="container">
<div class="row g-3">
<div class="col-md-4"><div class="feature"><strong>QR reservado</strong><span>Bloque visual listo para colocar el código real.</span></div></div>
<div class="col-md-4"><div class="feature"><strong>Visa/Mastercard</strong><span>Método visible para integrar pasarelas MX/US.</span></div></div>
<div class="col-md-4"><div class="feature"><strong>Visa/Mastercard</strong><span>Método visible para integrar pasarelas MX/US.</span><?= payment_icons_html('mt-2') ?></div></div>
<div class="col-md-4"><div class="feature"><strong>Admin aprueba</strong><span>Los comprobantes quedan pendientes hasta revisión.</span></div></div>
</div>
</div>

View File

@ -7,7 +7,11 @@ if (!$product) { http_response_code(404); layout_header('Producto no encontrado'
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$qty = max(1, min((int)$product['stock'], (int)($_POST['qty'] ?? 1)));
$_SESSION['cart'][$product['id']] = min((int)$product['stock'], (int)($_SESSION['cart'][$product['id']] ?? 0) + $qty);
header('Location: cart.php');
if (($_POST['next'] ?? 'cart') === 'checkout') {
header('Location: checkout.php');
exit;
}
header('Location: cart.php?added=' . rawurlencode((string)$product['id']));
exit;
}
layout_header($product['name'], $product['description']);
@ -23,9 +27,10 @@ layout_header($product['name'], $product['description']);
<p class="lead text-secondary"><?= h($product['description']) ?></p>
<div class="price big"><?= h(money((float)$product['price'])) ?></div>
<p class="stock mt-2">Disponible en almacén: <?= (int)$product['stock'] ?> unidades</p>
<form method="post" class="d-flex gap-2 mt-4 checkout-strip">
<form method="post" class="d-flex gap-2 mt-4 checkout-strip flex-wrap">
<input class="form-control" type="number" name="qty" value="1" min="1" max="<?= (int)$product['stock'] ?>" aria-label="Cantidad">
<button class="btn btn-dark btn-lg" type="submit">Agregar al carrito</button>
<button class="btn btn-dark btn-lg" type="submit" name="next" value="cart">Agregar al carrito</button>
<button class="btn btn-outline-dark btn-lg" type="submit" name="next" value="checkout">Pagar ahora</button>
</form>
</div>
</div>