163 lines
8.0 KiB
PHP
163 lines
8.0 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../db/config.php';
|
|
|
|
function h(string $value): string {
|
|
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
function store_logo_path(): string {
|
|
return 'assets/pasted-20260630-162052-2e0489d8.png';
|
|
}
|
|
|
|
function store_products(): array {
|
|
return [
|
|
'combo-24' => [
|
|
'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 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,
|
|
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();
|
|
$logoPath = store_logo_path();
|
|
echo '<!doctype html><html lang="es"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">';
|
|
echo '<title>' . h($title) . ' | LA BORGUITA</title>';
|
|
if ($projectDescription) {
|
|
echo '<meta name="description" content="' . h($projectDescription) . '">';
|
|
echo '<meta property="og:description" content="' . h($projectDescription) . '">';
|
|
echo '<meta property="twitter:description" content="' . h($projectDescription) . '">';
|
|
}
|
|
if ($projectImageUrl) {
|
|
echo '<meta property="og:image" content="' . h($projectImageUrl) . '">';
|
|
echo '<meta property="twitter:image" content="' . h($projectImageUrl) . '">';
|
|
}
|
|
echo '<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>';
|
|
echo '<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">';
|
|
echo '<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">';
|
|
echo '<link rel="stylesheet" href="assets/css/custom.css?v=' . time() . '">';
|
|
echo '</head><body><div id="loader" class="tech-loader"><div class="loader-card"><div class="loader-mark"><img src="' . h($logoPath) . '" alt="Logo LA BORGUITA" width="46" height="46"></div><div class="loader-line"></div><p>Cargando tienda segura…</p></div></div>';
|
|
echo '<header class="site-header sticky-top"><nav class="navbar navbar-expand-lg"><div class="container"><a class="navbar-brand brand" href="index.php"><span class="brand-logo"><img src="' . h($logoPath) . '" alt="" width="34" height="34"></span><span>LA BORGUITA</span></a><button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#nav" aria-controls="nav" aria-expanded="false" aria-label="Abrir navegación"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="nav"><ul class="navbar-nav ms-auto align-items-lg-center gap-lg-2"><li class="nav-item"><a class="nav-link" href="index.php#catalogo">Catálogo</a></li><li class="nav-item"><a class="nav-link" href="cart.php">Carrito <span class="badge text-bg-dark">' . $cartCount . '</span></a></li><li class="nav-item"><a class="nav-link" href="admin.php">Admin</a></li><li class="nav-item"><a class="btn btn-sm btn-dark" href="https://wa.me/5351746028" target="_blank" rel="noopener">WhatsApp</a></li></ul></div></div></nav></header><main>';
|
|
}
|
|
|
|
function layout_footer(): void {
|
|
echo '</main><a class="whatsapp-float" href="https://wa.me/5351746028" target="_blank" rel="noopener" aria-label="Contactar por WhatsApp">WA</a><footer class="footer"><div class="container d-flex flex-column flex-md-row justify-content-between gap-2"><span>© ' . date('Y') . ' LA BORGUITA. Precios en dólares.</span><span>Pago manual con revisión admin · Visa/Mastercard listo para integración MX/US.</span></div></footer><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script><script src="assets/js/main.js?v=' . time() . '"></script></body></html>';
|
|
}
|