From 7a69e52c1e2c71da2ccd4c1380979ef148932e4a Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Tue, 30 Jun 2026 16:12:24 +0000 Subject: [PATCH] Auto commit: 2026-06-30T16:12:24.678Z --- admin.php | 36 ++++ assets/css/custom.css | 404 +----------------------------------------- assets/js/main.js | 40 +---- cart.php | 37 ++++ checkout.php | 91 ++++++++++ healthz | 1 + includes/store.php | 152 ++++++++++++++++ index.php | 223 +++++++++-------------- product.php | 34 ++++ 9 files changed, 432 insertions(+), 586 deletions(-) create mode 100644 admin.php create mode 100644 cart.php create mode 100644 checkout.php create mode 100644 healthz create mode 100644 includes/store.php create mode 100644 product.php diff --git a/admin.php b/admin.php new file mode 100644 index 0000000..e88932b --- /dev/null +++ b/admin.php @@ -0,0 +1,36 @@ + +
+
+ +
Admin

Pagos y pedidos

Primera versión del panel: revisión de comprobantes, estado del pago y total vendido.

+ +

Sin pedidos todavía

Cuando un cliente suba comprobante aparecerá aquí para aprobarlo.

Crear pedido de prueba
+ +
+ +
+

+
+
Cliente


Método

·

+
ProductoCant.Subtotal
+ Ver comprobante +
+
+
+ +
+ +
+
+ diff --git a/assets/css/custom.css b/assets/css/custom.css index 789132e..030b6f8 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -1,403 +1 @@ -body { - background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); - background-size: 400% 400%; - animation: gradient 15s ease infinite; - color: #212529; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; - font-size: 14px; - margin: 0; - min-height: 100vh; -} - -.main-wrapper { - display: flex; - align-items: center; - justify-content: center; - min-height: 100vh; - width: 100%; - padding: 20px; - box-sizing: border-box; - position: relative; - z-index: 1; -} - -@keyframes gradient { - 0% { - background-position: 0% 50%; - } - 50% { - background-position: 100% 50%; - } - 100% { - background-position: 0% 50%; - } -} - -.chat-container { - width: 100%; - max-width: 600px; - background: rgba(255, 255, 255, 0.85); - border: 1px solid rgba(255, 255, 255, 0.3); - border-radius: 20px; - display: flex; - flex-direction: column; - height: 85vh; - box-shadow: 0 20px 40px rgba(0,0,0,0.2); - backdrop-filter: blur(15px); - -webkit-backdrop-filter: blur(15px); - overflow: hidden; -} - -.chat-header { - padding: 1.5rem; - border-bottom: 1px solid rgba(0, 0, 0, 0.05); - background: rgba(255, 255, 255, 0.5); - font-weight: 700; - font-size: 1.1rem; - display: flex; - justify-content: space-between; - align-items: center; -} - -.chat-messages { - flex: 1; - overflow-y: auto; - padding: 1.5rem; - display: flex; - flex-direction: column; - gap: 1.25rem; -} - -/* Custom Scrollbar */ -::-webkit-scrollbar { - width: 6px; -} - -::-webkit-scrollbar-track { - background: transparent; -} - -::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.3); - border-radius: 10px; -} - -::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.5); -} - -.message { - max-width: 85%; - padding: 0.85rem 1.1rem; - border-radius: 16px; - line-height: 1.5; - font-size: 0.95rem; - box-shadow: 0 4px 15px rgba(0,0,0,0.05); - animation: fadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -@keyframes fadeIn { - from { opacity: 0; transform: translateY(20px) scale(0.95); } - to { opacity: 1; transform: translateY(0) scale(1); } -} - -.message.visitor { - align-self: flex-end; - background: linear-gradient(135deg, #212529 0%, #343a40 100%); - color: #fff; - border-bottom-right-radius: 4px; -} - -.message.bot { - align-self: flex-start; - background: #ffffff; - color: #212529; - border-bottom-left-radius: 4px; -} - -.chat-input-area { - padding: 1.25rem; - background: rgba(255, 255, 255, 0.5); - border-top: 1px solid rgba(0, 0, 0, 0.05); -} - -.chat-input-area form { - display: flex; - gap: 0.75rem; -} - -.chat-input-area input { - flex: 1; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 12px; - padding: 0.75rem 1rem; - outline: none; - background: rgba(255, 255, 255, 0.9); - transition: all 0.3s ease; -} - -.chat-input-area input:focus { - border-color: #23a6d5; - box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.2); -} - -.chat-input-area button { - background: #212529; - color: #fff; - border: none; - padding: 0.75rem 1.5rem; - border-radius: 12px; - cursor: pointer; - font-weight: 600; - transition: all 0.3s ease; -} - -.chat-input-area button:hover { - background: #000; - transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(0,0,0,0.2); -} - -/* Background Animations */ -.bg-animations { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 0; - overflow: hidden; - pointer-events: none; -} - -.blob { - position: absolute; - width: 500px; - height: 500px; - background: rgba(255, 255, 255, 0.2); - border-radius: 50%; - filter: blur(80px); - animation: move 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1); -} - -.blob-1 { - top: -10%; - left: -10%; - background: rgba(238, 119, 82, 0.4); -} - -.blob-2 { - bottom: -10%; - right: -10%; - background: rgba(35, 166, 213, 0.4); - animation-delay: -7s; - width: 600px; - height: 600px; -} - -.blob-3 { - top: 40%; - left: 30%; - background: rgba(231, 60, 126, 0.3); - animation-delay: -14s; - width: 450px; - height: 450px; -} - -@keyframes move { - 0% { transform: translate(0, 0) rotate(0deg) scale(1); } - 33% { transform: translate(150px, 100px) rotate(120deg) scale(1.1); } - 66% { transform: translate(-50px, 200px) rotate(240deg) scale(0.9); } - 100% { transform: translate(0, 0) rotate(360deg) scale(1); } -} - -.header-link { - font-size: 14px; - color: #fff; - text-decoration: none; - background: rgba(0, 0, 0, 0.2); - padding: 0.5rem 1rem; - border-radius: 8px; - transition: all 0.3s ease; -} - -.header-link:hover { - background: rgba(0, 0, 0, 0.4); - text-decoration: none; -} - -/* Admin Styles */ -.admin-container { - max-width: 900px; - margin: 3rem auto; - padding: 2.5rem; - background: rgba(255, 255, 255, 0.85); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border-radius: 24px; - box-shadow: 0 20px 50px rgba(0,0,0,0.15); - border: 1px solid rgba(255, 255, 255, 0.4); - position: relative; - z-index: 1; -} - -.admin-container h1 { - margin-top: 0; - color: #212529; - font-weight: 800; -} - -.table { - width: 100%; - border-collapse: separate; - border-spacing: 0 8px; - margin-top: 1.5rem; -} - -.table th { - background: transparent; - border: none; - padding: 1rem; - color: #6c757d; - font-weight: 600; - text-transform: uppercase; - font-size: 0.75rem; - letter-spacing: 1px; -} - -.table td { - background: #fff; - padding: 1rem; - border: none; -} - -.table tr td:first-child { border-radius: 12px 0 0 12px; } -.table tr td:last-child { border-radius: 0 12px 12px 0; } - -.form-group { - margin-bottom: 1.25rem; -} - -.form-group label { - display: block; - margin-bottom: 0.5rem; - font-weight: 600; - font-size: 0.9rem; -} - -.form-control { - width: 100%; - padding: 0.75rem 1rem; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 12px; - background: #fff; - transition: all 0.3s ease; - box-sizing: border-box; -} - -.form-control:focus { - outline: none; - border-color: #23a6d5; - box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.1); -} - -.header-container { - display: flex; - justify-content: space-between; - align-items: center; -} - -.header-links { - display: flex; - gap: 1rem; -} - -.admin-card { - background: rgba(255, 255, 255, 0.6); - padding: 2rem; - border-radius: 20px; - border: 1px solid rgba(255, 255, 255, 0.5); - margin-bottom: 2.5rem; - box-shadow: 0 10px 30px rgba(0,0,0,0.05); -} - -.admin-card h3 { - margin-top: 0; - margin-bottom: 1.5rem; - font-weight: 700; -} - -.btn-delete { - background: #dc3545; - color: white; - border: none; - padding: 0.25rem 0.5rem; - border-radius: 4px; - cursor: pointer; -} - -.btn-add { - background: #212529; - color: white; - border: none; - padding: 0.5rem 1rem; - border-radius: 4px; - cursor: pointer; - margin-top: 1rem; -} - -.btn-save { - background: #0088cc; - color: white; - border: none; - padding: 0.8rem 1.5rem; - border-radius: 12px; - cursor: pointer; - font-weight: 600; - width: 100%; - transition: all 0.3s ease; -} - -.webhook-url { - font-size: 0.85em; - color: #555; - margin-top: 0.5rem; -} - -.history-table-container { - overflow-x: auto; - background: rgba(255, 255, 255, 0.4); - padding: 1rem; - border-radius: 12px; - border: 1px solid rgba(255, 255, 255, 0.3); -} - -.history-table { - width: 100%; -} - -.history-table-time { - width: 15%; - white-space: nowrap; - font-size: 0.85em; - color: #555; -} - -.history-table-user { - width: 35%; - background: rgba(255, 255, 255, 0.3); - border-radius: 8px; - padding: 8px; -} - -.history-table-ai { - width: 50%; - background: rgba(255, 255, 255, 0.5); - border-radius: 8px; - padding: 8px; -} - -.no-messages { - text-align: center; - color: #777; -} \ No newline at end of file +:root{--bg:#f8fafc;--surface:#fff;--surface-2:#f1f5f9;--text:#0f172a;--muted:#64748b;--border:#e2e8f0;--primary:#111827;--accent:#16a34a;--danger:#dc2626;--radius:10px;--shadow:0 12px 32px rgba(15,23,42,.08)}*{box-sizing:border-box}html{scroll-behavior:smooth}body{font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:var(--bg);color:var(--text);font-size:15px}.site-header{background:rgba(255,255,255,.94);border-bottom:1px solid var(--border);backdrop-filter:blur(10px)}.brand{font-weight:800;letter-spacing:-.03em;display:flex;align-items:center;gap:.6rem}.brand-logo{display:inline-grid;place-items:center;width:34px;height:34px;border-radius:8px;background:var(--primary);color:#fff;font-size:.78rem;font-weight:800}.brand-logo.lg{width:46px;height:46px;font-size:1rem}.nav-link{font-weight:600;color:var(--text)}.hero{background:#fff}.eyebrow{text-transform:uppercase;letter-spacing:.12em;font-size:.74rem;font-weight:800;color:var(--accent)}h1,h2,h3{letter-spacing:-.04em}.lead{max-width:680px}.market-card,.surface,.product-card,.feature,.empty-state,.confirmation{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow)}.market-card{padding:18px}.market-top{display:flex;align-items:center;gap:12px;margin-bottom:16px}.market-top small{display:block;color:var(--muted)}.scan-box{border:1px dashed #94a3b8;border-radius:8px;min-height:190px;display:grid;place-items:center;text-align:center;background:#f8fafc;color:var(--text);padding:18px}.scan-box span{display:block;font-weight:800}.scan-box small{display:block;color:var(--muted);max-width:260px}.scan-box.compact{min-height:140px;margin-bottom:20px}.status-row{display:flex;justify-content:space-between;gap:12px;border-top:1px solid var(--border);padding-top:14px;margin-top:14px;color:var(--muted)}.status-row strong{color:var(--text)}.section-heading{margin-bottom:22px;max-width:760px}.section-heading p{color:var(--muted);margin:0}.product-card{overflow:hidden}.product-visual{height:152px;background:#0f172a;color:#fff;display:grid;place-items:center}.product-visual span{font-size:2.4rem;font-weight:800;letter-spacing:-.08em}.product-visual.detail{height:420px;border-radius:var(--radius);box-shadow:var(--shadow)}.product-body{padding:18px}.product-body h3{font-size:1.16rem;margin:14px 0 8px}.product-body p{color:var(--muted);min-height:68px}.badge.subtle{background:#ecfdf5;color:#166534;border:1px solid #bbf7d0}.stock{font-size:.86rem;color:var(--muted);font-weight:700}.price{font-weight:800;font-size:1.25rem}.price.big{font-size:2rem}.qty{max-width:84px}.feature{padding:18px;display:flex;flex-direction:column;gap:4px;min-height:112px}.feature span{color:var(--muted)}.footer{border-top:1px solid var(--border);padding:24px 0;color:var(--muted);font-size:.9rem}.whatsapp-float{position:fixed;right:18px;bottom:18px;z-index:20;width:52px;height:52px;border-radius:12px;background:#128c7e;color:#fff;display:grid;place-items:center;text-decoration:none;font-weight:900;box-shadow:var(--shadow)}.whatsapp-float:hover{background:#0f766e;color:#fff}.cart-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:16px}.total,.summary-total{font-size:1.1rem;font-weight:800}.form-panel,.summary{padding:20px}.summary h2{font-size:1.25rem}.summary-line,.summary-total{display:flex;justify-content:space-between;gap:12px;border-top:1px solid var(--border);padding:12px 0}.summary-total{border-bottom:1px solid var(--border)}.empty-state,.confirmation{padding:30px;text-align:center}.confirmation{max-width:760px;margin:auto}.back-link{color:var(--text);font-weight:700;text-decoration:none}.checkout-strip{max-width:420px}.status{font-size:.72rem;border-radius:999px;padding:3px 8px;background:#fef3c7;color:#92400e}.status.approved{background:#dcfce7;color:#166534}.tech-loader{position:fixed;inset:0;background:#f8fafc;z-index:9999;display:grid;place-items:center;transition:opacity .28s ease,visibility .28s ease}.tech-loader.is-hidden{opacity:0;visibility:hidden}.loader-card{width:min(300px,90vw);background:#fff;border:1px solid var(--border);border-radius:12px;padding:22px;text-align:center;box-shadow:var(--shadow)}.loader-mark{width:42px;height:42px;border-radius:8px;background:#111827;color:#fff;display:grid;place-items:center;font-weight:900;margin:0 auto 14px}.loader-line{height:3px;background:#e2e8f0;overflow:hidden;border-radius:99px}.loader-line:before{content:"";display:block;width:40%;height:100%;background:#16a34a;animation:loadline 1s ease-in-out infinite}.loader-card p{margin:12px 0 0;color:var(--muted);font-size:.9rem}@keyframes loadline{0%{transform:translateX(-110%)}100%{transform:translateX(260%)}}.btn{border-radius:8px;font-weight:700}.form-control,.form-select{border-radius:8px;border-color:var(--border)}.form-control:focus,.form-select:focus{border-color:#111827;box-shadow:0 0 0 .2rem rgba(17,24,39,.12)}@media(max-width:767px){.display-5{font-size:2.1rem}.product-visual.detail{height:260px}.cart-actions{align-items:stretch}.cart-actions .btn{width:100%}.total{width:100%}} diff --git a/assets/js/main.js b/assets/js/main.js index d349598..2d5227d 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,39 +1 @@ -document.addEventListener('DOMContentLoaded', () => { - const chatForm = document.getElementById('chat-form'); - const chatInput = document.getElementById('chat-input'); - const chatMessages = document.getElementById('chat-messages'); - - const appendMessage = (text, sender) => { - const msgDiv = document.createElement('div'); - msgDiv.classList.add('message', sender); - msgDiv.textContent = text; - chatMessages.appendChild(msgDiv); - chatMessages.scrollTop = chatMessages.scrollHeight; - }; - - chatForm.addEventListener('submit', async (e) => { - e.preventDefault(); - const message = chatInput.value.trim(); - if (!message) return; - - appendMessage(message, 'visitor'); - chatInput.value = ''; - - try { - const response = await fetch('api/chat.php', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ message }) - }); - const data = await response.json(); - - // Artificial delay for realism - setTimeout(() => { - appendMessage(data.reply, 'bot'); - }, 500); - } catch (error) { - console.error('Error:', error); - appendMessage("Sorry, something went wrong. Please try again.", 'bot'); - } - }); -}); +window.addEventListener('load',()=>{setTimeout(()=>{document.getElementById('loader')?.classList.add('is-hidden')},350)});document.querySelectorAll('input[type="number"]').forEach(input=>{input.addEventListener('change',()=>{const min=Number(input.min||0);const max=Number(input.max||999);let value=Number(input.value||min);if(valuemax)value=max;input.value=String(value)})}); diff --git a/cart.php b/cart.php new file mode 100644 index 0000000..ed2ca01 --- /dev/null +++ b/cart.php @@ -0,0 +1,37 @@ + $qty) { + $product = get_product((string)$id); + if ($product) { + $qty = max(0, min((int)$product['stock'], (int)$qty)); + if ($qty === 0) { unset($_SESSION['cart'][$id]); } else { $_SESSION['cart'][$id] = $qty; } + } + } + } + header('Location: cart.php'); exit; +} +$items = cart_items(); +layout_header('Carrito', 'Carrito de compra LA BORGUITA con precios en dólares.'); +?> +
+
+
Carrito

Revisa tu compra

Ajusta cantidades antes de subir el comprobante de pago.

+ +

Tu carrito está vacío

Agrega productos del catálogo para iniciar un pedido.

Ir al catálogo
+ +
+ +
+ +
ProductoPrecioCantidadTotal

Stock
+
Total:
Continuar al pago
+
+ +
+
+ diff --git a/checkout.php b/checkout.php new file mode 100644 index 0000000..817bdca --- /dev/null +++ b/checkout.php @@ -0,0 +1,91 @@ + 'jpg', 'image/png' => 'png', 'application/pdf' => 'pdf']; + $mime = mime_content_type($_FILES['proof']['tmp_name']) ?: ''; + if ($_FILES['proof']['size'] > $max) { $errors[] = 'El comprobante no puede superar 8 MB.'; } + if (!isset($allowed[$mime])) { $errors[] = 'El comprobante debe ser JPG, PNG o PDF.'; } + if (!$errors) { + $dir = __DIR__ . '/assets/uploads'; + if (!is_dir($dir)) { mkdir($dir, 0775, true); } + $filename = 'proof-' . date('YmdHis') . '-' . bin2hex(random_bytes(4)) . '.' . $allowed[$mime]; + if (move_uploaded_file($_FILES['proof']['tmp_name'], $dir . '/' . $filename)) { + $proofPath = 'assets/uploads/' . $filename; + } else { $errors[] = 'No se pudo guardar el comprobante.'; } + } + } else { + $errors[] = 'Sube el comprobante para revisión manual.'; + } + + if (!$errors) { + $orderId = create_order([ + 'customer_name' => $name, + 'customer_email' => $email, + 'customer_phone' => $phone, + 'delivery_notes' => $notes, + 'payment_method' => $method, + 'proof_path' => $proofPath, + 'items' => $items, + 'total' => cart_total(), + ]); + $_SESSION['cart'] = []; + header('Location: checkout.php?success=' . $orderId); + exit; + } +} + +$successId = isset($_GET['success']) ? (int)$_GET['success'] : 0; +$order = $successId ? get_order($successId) : null; +layout_header('Checkout', 'Checkout con QR, tarjeta, transferencia y comprobante manual para LA BORGUITA.'); +?> +
+
+ +
Pedido recibido

Pago pendiente de aprobación

Tu pedido # fue registrado por . El admin revisará el comprobante y cambiará el estado a aprobado.

Seguir comprandoVer panel admin
+ +

No hay productos para pagar

Agrega productos al carrito para continuar.

Ir al catálogo
+ +
Pago manual

Confirma tu pedido

Elige QR, tarjeta Visa/Mastercard o transferencia. Por ahora la confirmación es manual con comprobante.

+
Revisa:
+
+
+
+
+
+
+
+
+
+
JPG, PNG o PDF hasta 8 MB. El admin aprobará manualmente.
+
+ +
+
+
+ +
+
+ +
+
+ diff --git a/healthz b/healthz new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/healthz @@ -0,0 +1 @@ +ok diff --git a/includes/store.php b/includes/store.php new file mode 100644 index 0000000..09abe24 --- /dev/null +++ b/includes/store.php @@ -0,0 +1,152 @@ + [ + 'id' => 'combo-24', + 'name' => 'Combo Mercado 24', + 'price' => 24.99, + 'stock' => 18, + 'category' => 'Supermarket', + 'description' => 'Selección esencial para compras rápidas: snacks, bebidas y básicos del día.', + ], + 'tech-charge' => [ + 'id' => 'tech-charge', + 'name' => 'Carga Tecnológica', + 'price' => 39.00, + 'stock' => 12, + 'category' => 'Tecnología', + 'description' => 'Kit tecnológico con cable premium, cargador rápido y soporte compacto.', + ], + 'fresh-box' => [ + 'id' => 'fresh-box', + 'name' => 'Fresh Box Familiar', + 'price' => 54.50, + 'stock' => 9, + 'category' => 'Despensa', + 'description' => 'Caja familiar con productos de alta rotación para abastecer la semana.', + ], + ]; +} + +function get_product(string $id): ?array { + $products = store_products(); + return $products[$id] ?? null; +} + +function cart_items(): array { + if (session_status() !== PHP_SESSION_ACTIVE) { + session_start(); + } + $cart = $_SESSION['cart'] ?? []; + $items = []; + foreach ($cart as $id => $qty) { + $product = get_product((string)$id); + $qty = max(1, (int)$qty); + if ($product) { + $product['qty'] = min($qty, (int)$product['stock']); + $product['line_total'] = $product['qty'] * (float)$product['price']; + $items[] = $product; + } + } + return $items; +} + +function cart_total(): float { + return array_reduce(cart_items(), fn($sum, $item) => $sum + (float)$item['line_total'], 0.0); +} + +function cart_count(): int { + return array_reduce(cart_items(), fn($sum, $item) => $sum + (int)$item['qty'], 0); +} + +function money(float $amount): string { + return '$' . number_format($amount, 2) . ' USD'; +} + +function ensure_orders_table(): void { + db()->exec("CREATE TABLE IF NOT EXISTS lb_orders ( + id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + customer_name VARCHAR(120) NOT NULL, + customer_email VARCHAR(180) NOT NULL, + customer_phone VARCHAR(40) NOT NULL, + delivery_notes TEXT NULL, + payment_method VARCHAR(40) NOT NULL, + proof_path VARCHAR(255) NULL, + items_json JSON NOT NULL, + total DECIMAL(10,2) NOT NULL DEFAULT 0, + status VARCHAR(30) NOT NULL DEFAULT 'pending_review', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); +} + +function create_order(array $data): int { + ensure_orders_table(); + $stmt = db()->prepare('INSERT INTO lb_orders (customer_name, customer_email, customer_phone, delivery_notes, payment_method, proof_path, items_json, total, status) VALUES (:name, :email, :phone, :notes, :method, :proof, :items, :total, :status)'); + $stmt->execute([ + ':name' => $data['customer_name'], + ':email' => $data['customer_email'], + ':phone' => $data['customer_phone'], + ':notes' => $data['delivery_notes'], + ':method' => $data['payment_method'], + ':proof' => $data['proof_path'], + ':items' => json_encode($data['items'], JSON_UNESCAPED_UNICODE), + ':total' => $data['total'], + ':status' => 'pending_review', + ]); + return (int)db()->lastInsertId(); +} + +function list_orders(): array { + ensure_orders_table(); + return db()->query('SELECT * FROM lb_orders ORDER BY created_at DESC, id DESC LIMIT 50')->fetchAll(); +} + +function get_order(int $id): ?array { + ensure_orders_table(); + $stmt = db()->prepare('SELECT * FROM lb_orders WHERE id = :id LIMIT 1'); + $stmt->execute([':id' => $id]); + $row = $stmt->fetch(); + return $row ?: null; +} + +function approve_order(int $id): void { + ensure_orders_table(); + $stmt = db()->prepare("UPDATE lb_orders SET status = 'approved', updated_at = CURRENT_TIMESTAMP WHERE id = :id"); + $stmt->execute([':id' => $id]); +} + +function layout_header(string $title, string $description = ''): void { + $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? $description; + $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; + $cartCount = cart_count(); + echo ''; + echo '' . h($title) . ' | LA BORGUITA'; + if ($projectDescription) { + echo ''; + echo ''; + echo ''; + } + if ($projectImageUrl) { + echo ''; + echo ''; + } + echo ''; + echo ''; + echo ''; + echo ''; + echo '
LB

Cargando tienda segura…

'; + echo '
'; +} + +function layout_footer(): void { + echo '
WA
© ' . date('Y') . ' LA BORGUITA. Precios en dólares.Pago manual con revisión admin · Visa/Mastercard listo para integración MX/US.
'; +} diff --git a/index.php b/index.php index 7205f3d..cd8c9ca 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,85 @@ - - - - - - New Style - - - - - - - - - - - - - - - - - - - - - -
-
-

Analyzing your requirements and generating your website…

-
- Loading… +
+
+ +
+
+ Super market 24 · USD · Pago manual +

LA BORGUITA vende rápido, confirma pagos y atiende por WhatsApp.

+

Un MVP de tienda virtual con productos activos, stock visible, carrito, QR de pago reservado y comprobantes para aprobación del admin.

+ +
+
+
+
LA BORGUITAPagos Visa · Mastercard · Transferencia
+
Espacio para QR de pagoSube aquí tu QR definitivo desde el editor cuando lo tengas listo.
+
Pedidos pendientesRevisión manual
+
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

-
-
- Page updated: (UTC) -
- - + + + + + +
+
+
+
QR reservadoBloque visual listo para colocar el código real.
+
Visa/MastercardMétodo visible para integrar pasarelas MX/US.
+
Admin apruebaLos comprobantes quedan pendientes hasta revisión.
+
+
+
+ diff --git a/product.php b/product.php new file mode 100644 index 0000000..83a5dac --- /dev/null +++ b/product.php @@ -0,0 +1,34 @@ +
Producto no encontrado.
Volver
'; layout_footer(); exit; } +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'); + exit; +} +layout_header($product['name'], $product['description']); +?> +
+
+ ← Volver al catálogo +
+
+
+ +

+

+
+

Disponible en almacén: unidades

+
+ + +
+
+
+
+
+