Tul xxx Tul
User / IP
:
216.73.216.146
Host / Server
:
45.84.207.204 / aircan.me
System
:
Linux lt-bnk-web1726.main-hosting.eu 5.14.0-611.36.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Mar 3 11:23:52 EST 2026 x86_64
Command
|
Upload
|
Create
Mass Deface
|
Jumping
|
Symlink
|
Reverse Shell
Ping
|
Port Scan
|
DNS Lookup
|
Whois
|
Header
|
cURL
:
/
home
/
u931257429
/
domains
/
aircan.me
/
public_html
/
comidarapidafran2
/
admin
/
Viewing: settings.php
<?php include '../components/connect.php'; require_once '../components/admin_roles.php'; session_start(); $admin_id = $_SESSION['admin_id'] ?? null; if (!$admin_id) { header('location:admin_login.php'); exit(); } ensureAdminRolesSchema($conn); $currentCurrencyCode = strtoupper(trim((string)getSystemSetting($conn, 'currency_code', ''))); $businessName = getBusinessName($conn); $businessLogo = getBusinessLogo($conn); $businessLogoVersion = getBusinessLogoVersion($conn); $businessPhone = getBusinessPhone($conn); $businessHours = trim((string)getSystemSetting($conn, 'business_hours', '')); $businessAddress = trim((string)getSystemSetting($conn, 'business_address', '')); $googleMapsUrl = trim((string)getSystemSetting($conn, 'google_maps_url', '')); $businessLocationHint = trim((string)getSystemSetting($conn, 'business_location_hint', '')); $socialFacebookUrl = trim((string)getSystemSetting($conn, 'social_facebook_url', '')); $socialInstagramUrl = trim((string)getSystemSetting($conn, 'social_instagram_url', '')); $socialGmailUrl = trim((string)getSystemSetting($conn, 'social_gmail_url', '')); $paymentBanksJson = (string)getSystemSetting($conn, 'payment_banks', ''); $paymentBanks = json_decode($paymentBanksJson, true); if (!is_array($paymentBanks)) { $paymentBanks = []; } if (empty($paymentBanks)) { $paymentBanks = [ [ 'id' => 'nequi', 'name' => 'Nequi', 'logo' => 'images/nequi.png', 'logos' => ['images/nequi.png'], 'account_number' => '', 'account_type' => 'Nequi', 'account_holder' => '', 'document' => '', 'active' => 1, ], [ 'id' => 'daviplata', 'name' => 'Daviplata', 'logo' => 'images/daviplata.png', 'logos' => ['images/daviplata.png'], 'account_number' => '', 'account_type' => 'Daviplata', 'account_holder' => '', 'document' => '', 'active' => 1, ], ]; } function sanitizePaymentBanks(array $banks): array { $out = []; foreach ($banks as $b) { if (!is_array($b)) { continue; } $id = trim((string)($b['id'] ?? '')); $id = preg_replace('/[^a-zA-Z0-9_-]/', '', $id); $name = trim((string)($b['name'] ?? '')); if ($id === '') { continue; } $logosRaw = $b['logos'] ?? ($b['images'] ?? null); $logos = []; if (is_array($logosRaw)) { foreach ($logosRaw as $p) { $p = trim((string)$p); if ($p !== '') { $logos[] = $p; } if (count($logos) >= 3) { break; } } } $legacyLogo = trim((string)($b['logo'] ?? '')); if ($legacyLogo !== '' && empty($logos)) { $logos[] = $legacyLogo; } $logos = array_slice(array_values(array_filter($logos)), 0, 3); $logo = $logos[0] ?? ''; $out[] = [ 'id' => $id, 'name' => $name, 'logo' => $logo, 'logos' => $logos, 'account_number' => trim((string)($b['account_number'] ?? '')), 'account_type' => trim((string)($b['account_type'] ?? '')), 'account_holder' => trim((string)($b['account_holder'] ?? '')), 'document' => trim((string)($b['document'] ?? '')), 'active' => (int)($b['active'] ?? 0) ? 1 : 0, ]; } return $out; } if ($businessHours === '') { $businessHours = 'Todos los días: 4:30 PM - 11:30 PM'; } if ($businessAddress === '') { $businessAddress = 'Av. 6 , #17-77, Barrio La Cabrera, Cúcuta, Norte de Santander, Colombia.'; } if ($googleMapsUrl === '') { $googleMapsUrl = 'https://maps.app.goo.gl/FiWLRGpXxnTb3gzL6'; } if ($businessLocationHint === '') { $businessLocationHint = 'Centro La Cabrera'; } function formatCurrencyOptionLabel(array $row): string { $name = (string)($row['name'] ?? ''); if ($name !== '' && function_exists('mb_convert_case')) { $name = mb_convert_case($name, MB_CASE_TITLE, 'UTF-8'); } elseif ($name !== '') { $name = ucfirst($name); } $code = (string)($row['code'] ?? ''); $symbol = (string)($row['symbol'] ?? ''); return trim($code . ' · ' . $name . ' (' . $symbol . ')'); } $errors = []; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = (string)($_POST['action'] ?? 'currency'); if ($action === 'branding') { $submittedName = trim((string)($_POST['business_name'] ?? '')); if ($submittedName === '') { $errors[] = 'El nombre del negocio es obligatorio.'; } $submittedPhoneRaw = trim((string)($_POST['business_phone'] ?? '')); $submittedPhone = preg_replace('/\s+/', ' ', $submittedPhoneRaw); if ($submittedPhone === '') { $errors[] = 'El teléfono del negocio es obligatorio.'; } elseif (!preg_match('/^[0-9+\s()\-]{7,25}$/', $submittedPhone)) { $errors[] = 'El teléfono del negocio no tiene un formato válido.'; } $newLogoPath = ''; if (!empty($_FILES['business_logo']) && isset($_FILES['business_logo']['error']) && (int)$_FILES['business_logo']['error'] === UPLOAD_ERR_OK) { $tmpName = (string)($_FILES['business_logo']['tmp_name'] ?? ''); $origName = (string)($_FILES['business_logo']['name'] ?? ''); $size = (int)($_FILES['business_logo']['size'] ?? 0); if ($size <= 0 || $size > 3500000) { $errors[] = 'El logo supera el tamaño permitido.'; } elseif (!is_file($tmpName)) { $errors[] = 'No se pudo leer el archivo del logo.'; } else { $ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION)); $allowed = ['png', 'jpg', 'jpeg', 'webp']; if (!in_array($ext, $allowed, true)) { $errors[] = 'Formato de logo no permitido.'; } elseif (@getimagesize($tmpName) === false) { $errors[] = 'El archivo del logo no parece una imagen válida.'; } else { $targetName = 'business_logo.' . $ext; $targetDiskPath = __DIR__ . '/../uploaded_img/' . $targetName; $targetRelPath = 'uploaded_img/' . $targetName; if (!@move_uploaded_file($tmpName, $targetDiskPath)) { $errors[] = 'No se pudo guardar el logo.'; } else { $newLogoPath = $targetRelPath; } } } } if (empty($errors)) { setSystemSetting($conn, 'business_name', $submittedName); setSystemSetting($conn, 'business_phone', $submittedPhone); if ($newLogoPath !== '') { setSystemSetting($conn, 'business_logo', $newLogoPath); setSystemSetting($conn, 'business_logo_version', (string)time()); } addAdminFlashMessage('Identidad del negocio actualizada correctamente.'); header('location:settings.php'); exit(); } } elseif ($action === 'contact') { $submittedHours = trim((string)($_POST['business_hours'] ?? '')); $submittedAddress = trim((string)($_POST['business_address'] ?? '')); $submittedLocationHint = trim((string)($_POST['business_location_hint'] ?? '')); $submittedMapsUrl = trim((string)($_POST['google_maps_url'] ?? '')); if ($submittedHours === '') { $errors[] = 'El horario de atención es obligatorio.'; } if ($submittedAddress === '') { $errors[] = 'La dirección es obligatoria.'; } if ($submittedMapsUrl !== '' && !filter_var($submittedMapsUrl, FILTER_VALIDATE_URL)) { $errors[] = 'El enlace de Google Maps no tiene un formato válido.'; } if (empty($errors)) { setSystemSetting($conn, 'business_hours', $submittedHours); setSystemSetting($conn, 'business_address', $submittedAddress); setSystemSetting($conn, 'business_location_hint', $submittedLocationHint); setSystemSetting($conn, 'google_maps_url', $submittedMapsUrl); addAdminFlashMessage('Información de contacto actualizada correctamente.'); header('location:settings.php'); exit(); } } elseif ($action === 'social') { $submittedFacebookUrl = trim((string)($_POST['social_facebook_url'] ?? '')); $submittedInstagramUrl = trim((string)($_POST['social_instagram_url'] ?? '')); $submittedGmailUrl = trim((string)($_POST['social_gmail_url'] ?? '')); if ($submittedFacebookUrl !== '' && !filter_var($submittedFacebookUrl, FILTER_VALIDATE_URL)) { $errors[] = 'El enlace de Facebook no tiene un formato válido.'; } if ($submittedInstagramUrl !== '' && !filter_var($submittedInstagramUrl, FILTER_VALIDATE_URL)) { $errors[] = 'El enlace de Instagram no tiene un formato válido.'; } if ($submittedGmailUrl !== '') { if (stripos($submittedGmailUrl, 'mailto:') === 0) { // ok } elseif (filter_var($submittedGmailUrl, FILTER_VALIDATE_EMAIL)) { $submittedGmailUrl = 'mailto:' . $submittedGmailUrl; } elseif (!filter_var($submittedGmailUrl, FILTER_VALIDATE_URL)) { $errors[] = 'El enlace de Gmail no tiene un formato válido.'; } } if (empty($errors)) { setSystemSetting($conn, 'social_facebook_url', $submittedFacebookUrl); setSystemSetting($conn, 'social_instagram_url', $submittedInstagramUrl); setSystemSetting($conn, 'social_gmail_url', $submittedGmailUrl); addAdminFlashMessage('Redes sociales actualizadas correctamente.'); header('location:settings.php'); exit(); } } elseif ($action === 'bank_add' || $action === 'bank_update' || $action === 'bank_delete' || $action === 'bank_logo_delete') { $paymentBanks = sanitizePaymentBanks($paymentBanks); $bankId = trim((string)($_POST['bank_id'] ?? '')); $bankId = preg_replace('/[^a-zA-Z0-9_-]/', '', $bankId); if ($action === 'bank_delete') { if ($bankId === '') { $errors[] = 'Banco inválido.'; } else { $filtered = []; foreach ($paymentBanks as $b) { if ((string)$b['id'] !== $bankId) { $filtered[] = $b; } } $paymentBanks = $filtered; } } elseif ($action === 'bank_logo_delete') { $logoIndex = (int)($_POST['logo_index'] ?? 0); if ($bankId === '' || $logoIndex < 1 || $logoIndex > 3) { $errors[] = 'Imagen inválida.'; } else { $updated = false; foreach ($paymentBanks as $idx => $b) { if ((string)($b['id'] ?? '') !== $bankId) { continue; } $logos = []; if (!empty($b['logos']) && is_array($b['logos'])) { foreach ($b['logos'] as $p) { $p = trim((string)$p); if ($p !== '') { $logos[] = $p; } if (count($logos) >= 3) { break; } } } $legacyLogo = trim((string)($b['logo'] ?? '')); if ($legacyLogo !== '' && empty($logos)) { $logos[] = $legacyLogo; } $logos = array_slice(array_values(array_filter($logos)), 0, 3); $toDelete = $logos[$logoIndex - 1] ?? ''; if ($toDelete !== '' && stripos($toDelete, 'uploaded_img/banks/') === 0) { $baseDir = realpath(__DIR__ . '/../uploaded_img/banks'); $diskPath = realpath(__DIR__ . '/../' . ltrim($toDelete, '/')); if ($baseDir && $diskPath && strpos($diskPath, $baseDir) === 0 && is_file($diskPath)) { @unlink($diskPath); } } if (isset($logos[$logoIndex - 1])) { unset($logos[$logoIndex - 1]); } $logos = array_slice(array_values(array_filter($logos)), 0, 3); $logo = $logos[0] ?? ''; $paymentBanks[$idx] = array_merge($b, [ 'logo' => $logo, 'logos' => $logos, ]); $updated = true; break; } if (!$updated) { $errors[] = 'Banco inválido.'; } } } else { $name = trim((string)($_POST['bank_name'] ?? '')); $accountNumber = trim((string)($_POST['bank_account_number'] ?? '')); $accountType = trim((string)($_POST['bank_account_type'] ?? '')); $accountHolder = trim((string)($_POST['bank_account_holder'] ?? '')); $document = trim((string)($_POST['bank_document'] ?? '')); $active = !empty($_POST['bank_active']) ? 1 : 0; if ($bankId === '') { $bankId = 'bank' . substr(str_replace('.', '', uniqid('', true)), -10); $bankId = preg_replace('/[^a-zA-Z0-9_-]/', '', $bankId); } $existingLogos = []; foreach ($paymentBanks as $b) { if ((string)($b['id'] ?? '') !== $bankId) { continue; } if (!empty($b['logos']) && is_array($b['logos'])) { foreach ($b['logos'] as $p) { $p = trim((string)$p); if ($p !== '') { $existingLogos[] = $p; } if (count($existingLogos) >= 3) { break; } } } $legacyLogo = trim((string)($b['logo'] ?? '')); if ($legacyLogo !== '' && empty($existingLogos)) { $existingLogos[] = $legacyLogo; } break; } $uploadBankLogo = function(string $field, string $bankId, int $slot) use (&$errors): string { if (empty($_FILES[$field]) || !isset($_FILES[$field]['error']) || (int)$_FILES[$field]['error'] !== UPLOAD_ERR_OK) { return ''; } $tmpName = (string)($_FILES[$field]['tmp_name'] ?? ''); $origName = (string)($_FILES[$field]['name'] ?? ''); $size = (int)($_FILES[$field]['size'] ?? 0); if ($size <= 0 || $size > 3500000) { $errors[] = 'La imagen del banco supera el tamaño permitido.'; return ''; } if (!is_file($tmpName)) { $errors[] = 'No se pudo leer la imagen del banco.'; return ''; } $ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION)); $allowed = ['png', 'jpg', 'jpeg', 'webp']; if (!in_array($ext, $allowed, true)) { $errors[] = 'Formato de imagen no permitido.'; return ''; } if (@getimagesize($tmpName) === false) { $errors[] = 'La imagen del banco no parece válida.'; return ''; } $dir = __DIR__ . '/../uploaded_img/banks'; if (!is_dir($dir)) { @mkdir($dir, 0775, true); } $targetName = $bankId . '_' . $slot . '.' . $ext; $targetDiskPath = $dir . '/' . $targetName; $targetRelPath = 'uploaded_img/banks/' . $targetName; if (!@move_uploaded_file($tmpName, $targetDiskPath)) { $errors[] = 'No se pudo guardar la imagen del banco.'; return ''; } return $targetRelPath; }; if (empty($errors)) { $logos = array_slice(array_values(array_filter($existingLogos)), 0, 3); for ($i = 1; $i <= 3; $i++) { $field = 'bank_logo_' . $i; $newPath = $uploadBankLogo($field, $bankId, $i); if ($newPath !== '') { $logos[$i - 1] = $newPath; } } $logos = array_slice(array_values(array_filter($logos)), 0, 3); $logo = $logos[0] ?? ''; $updated = false; foreach ($paymentBanks as $idx => $b) { if ((string)$b['id'] === $bankId) { $paymentBanks[$idx] = [ 'id' => $bankId, 'name' => $name, 'logo' => $logo, 'logos' => $logos, 'account_number' => $accountNumber, 'account_type' => $accountType, 'account_holder' => $accountHolder, 'document' => $document, 'active' => $active, ]; $updated = true; break; } } if (!$updated) { $paymentBanks[] = [ 'id' => $bankId, 'name' => $name, 'logo' => $logo, 'logos' => $logos, 'account_number' => $accountNumber, 'account_type' => $accountType, 'account_holder' => $accountHolder, 'document' => $document, 'active' => $active, ]; } } } if (empty($errors)) { $paymentBanks = sanitizePaymentBanks($paymentBanks); setSystemSetting( $conn, 'payment_banks', json_encode($paymentBanks, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ); addAdminFlashMessage('Bancos/métodos de transferencia actualizados correctamente.'); header('location:settings.php'); exit(); } } else { $submittedCurrency = strtoupper(trim((string)($_POST['currency_code'] ?? ''))); if ($submittedCurrency === '' || !preg_match('/^[A-Z]{3}$/', $submittedCurrency)) { $errors[] = 'Selecciona una moneda válida.'; } else { $stmt = $conn->prepare('SELECT code FROM currencies WHERE code = ? LIMIT 1'); $stmt->execute([$submittedCurrency]); $exists = $stmt->fetchColumn(); if (!$exists) { $errors[] = 'La moneda seleccionada no existe en el catálogo.'; } } if (empty($errors)) { setSystemSetting($conn, 'currency_code', $submittedCurrency); addAdminFlashMessage('Moneda actualizada correctamente.'); header('location:settings.php'); exit(); } } } if (!empty($errors)) { $businessHours = trim((string)($_POST['business_hours'] ?? $businessHours)); $businessAddress = trim((string)($_POST['business_address'] ?? $businessAddress)); $googleMapsUrl = trim((string)($_POST['google_maps_url'] ?? $googleMapsUrl)); $businessLocationHint = trim((string)($_POST['business_location_hint'] ?? $businessLocationHint)); $socialFacebookUrl = trim((string)($_POST['social_facebook_url'] ?? $socialFacebookUrl)); $socialInstagramUrl = trim((string)($_POST['social_instagram_url'] ?? $socialInstagramUrl)); $socialGmailUrl = trim((string)($_POST['social_gmail_url'] ?? $socialGmailUrl)); } $currenciesStmt = $conn->query('SELECT code, name, symbol, fraction_size, template FROM currencies WHERE is_active = 1 ORDER BY name ASC'); $currencies = $currenciesStmt ? $currenciesStmt->fetchAll(PDO::FETCH_ASSOC) : []; $currentCurrency = getSystemCurrency($conn); ?> <!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Configuración | <?= htmlspecialchars($businessName); ?></title> <?php $logoHref = '../' . ltrim($businessLogo, '/'); if ($businessLogoVersion !== '') { $logoHref .= (strpos($logoHref, '?') === false ? '?' : '&') . 'v=' . rawurlencode($businessLogoVersion); } ?> <link rel="icon" href="../icon.php?size=64<?= $businessLogoVersion !== '' ? '&v=' . rawurlencode($businessLogoVersion) : ''; ?>" type="image/png"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <link rel="stylesheet" href="../css/admin_style.css"> <style> body.settings-page { background: radial-gradient(circle at top, rgba(14, 165, 233, 0.12), transparent 55%), linear-gradient(135deg, #f8fafc 0%, #fff7f3 100%); min-height: 100vh; } .settings-page .page-wrap { max-width: 1100px; margin: 0 auto; padding: 1.9rem 1.25rem 3.5rem; } .settings-page .page-title { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.4rem; } .settings-page .page-title h1 { margin: 0; font-weight: 900; font-size: 2.1rem; color: #0f172a; } .settings-page .page-title p { margin: 0; color: rgba(15, 23, 42, 0.65); font-weight: 600; } .settings-page .kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; margin: 18px 0 20px; } .settings-page .kpi-card { position: relative; overflow: hidden; border-radius: 18px; padding: 16px 16px 14px; background: rgba(255, 255, 255, 0.82); border: 1px solid rgba(226, 232, 240, 0.95); box-shadow: 0 18px 44px rgba(15, 21, 45, 0.11); backdrop-filter: blur(12px); transition: transform 0.25s ease, box-shadow 0.25s ease; } .settings-page .kpi-card:hover { transform: translateY(-3px); box-shadow: 0 22px 54px rgba(15, 21, 45, 0.14); } .settings-page .kpi-card::before { content: ''; position: absolute; inset: -70% -55% auto auto; height: 240px; width: 240px; background: radial-gradient(140px at top right, rgba(14, 165, 233, 0.16), transparent 70%); transform: rotate(12deg); pointer-events: none; } .settings-page .kpi-card__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; } .settings-page .kpi-card__label { font-weight: 800; font-size: 0.95rem; color: rgba(24, 24, 24, 0.72); } .settings-page .kpi-card__value { font-weight: 900; font-size: 1.2rem; color: #0f172a; margin-top: 8px; word-break: break-word; } .settings-page .kpi-card__icon { height: 44px; width: 44px; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; color: #fff; background: linear-gradient(135deg, #0ea5e9, #2563eb); box-shadow: 0 12px 26px rgba(37, 99, 235, 0.22); } .settings-page .kpi-card__icon--blue { background: linear-gradient(135deg, #0ea5e9, #2563eb); box-shadow: 0 12px 26px rgba(37, 99, 235, 0.22); } .settings-page .kpi-card__icon--green { background: linear-gradient(135deg, #2ecc71, #1abc9c); box-shadow: 0 12px 26px rgba(46, 204, 113, 0.22); } .settings-page .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 1.25rem; } .settings-page .card { background: rgba(255, 255, 255, 0.82); border: 1px solid rgba(226, 232, 240, 0.95); border-radius: 18px; box-shadow: 0 18px 46px rgba(15, 23, 42, 0.10); padding: 1.4rem 1.45rem; position: relative; overflow: hidden; backdrop-filter: blur(12px); transition: transform 0.25s ease, box-shadow 0.25s ease; } .settings-page .card::before { content: ''; position: absolute; inset: -70% -55% auto auto; height: 240px; width: 240px; background: radial-gradient(140px at top right, rgba(14, 165, 233, 0.14), transparent 70%); transform: rotate(10deg); pointer-events: none; } .settings-page .card:hover { transform: translateY(-4px); box-shadow: 0 22px 56px rgba(15, 23, 42, 0.14); } .settings-page .card h3 { margin: 0 0 1rem 0; display: flex; align-items: center; gap: .75rem; font-size: 1.25rem; font-weight: 900; color: #111827; position: relative; z-index: 1; } .settings-page .badge { display: inline-flex; align-items: center; gap: .55rem; padding: .35rem .85rem; border-radius: 999px; background: rgba(37, 99, 235, 0.12); color: rgba(29, 78, 216, 0.92); font-weight: 800; font-size: .92rem; border: 1px solid rgba(37, 99, 235, 0.18); } .settings-page label { display: block; font-weight: 800; color: rgba(15, 23, 42, 0.8); margin-bottom: .45rem; } .settings-page .field { position: relative; z-index: 1; } .settings-page .field-icon { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 16px; background: rgba(255, 255, 255, 0.82); border: 1px solid rgba(15, 23, 42, 0.12); box-shadow: 0 14px 30px rgba(15, 21, 45, 0.08); backdrop-filter: blur(10px); } .settings-page .field-icon i { color: rgba(48, 49, 73, 0.7); } .settings-page .field-icon .social-icon { width: 20px; height: 20px; object-fit: contain; flex: 0 0 auto; opacity: 0.92; } .settings-page .bank-row { border: 1px solid rgba(148, 163, 184, 0.38); background: rgba(255,255,255,0.76); border-radius: 14px; padding: 1rem; margin-top: 0.85rem; } .settings-page .bank-row__head { display: flex; gap: .9rem; align-items: center; justify-content: space-between; flex-wrap: wrap; } .settings-page .bank-row__title { display: flex; gap: .75rem; align-items: center; min-width: 240px; } .settings-page .bank-row__title img { width: 44px; height: 44px; border-radius: 12px; object-fit: contain; background: #fff; border: 1px solid rgba(15, 23, 42, 0.08); box-shadow: 0 8px 20px rgba(15, 21, 45, 0.08); } .settings-page .bank-row__actions { display: flex; gap: .55rem; align-items: center; } .settings-page .bank-logos-preview { display: flex; gap: .65rem; flex-wrap: wrap; margin-top: .85rem; } .settings-page .bank-logos-preview .bank-logo-item { display: flex; flex-direction: column; align-items: center; gap: .45rem; position: relative; } .settings-page .bank-logos-preview .bank-logo-item form { position: absolute; top: -8px; right: -8px; margin: 0; } .settings-page .bank-logos-preview .bank-logo-item .logo-remove-btn { width: 30px; height: 30px; border-radius: 999px; padding: 0; display: inline-flex; align-items: center; justify-content: center; box-shadow: 0 14px 28px rgba(239, 68, 68, 0.25); border: 1px solid rgba(239, 68, 68, 0.35); } .settings-page .bank-logos-preview img { width: 58px; height: 58px; border-radius: 16px; object-fit: contain; background: #fff; border: 1px solid rgba(15, 23, 42, 0.1); box-shadow: 0 10px 24px rgba(15, 21, 45, 0.08); } .settings-page .btn-ghost { display: inline-flex; align-items: center; gap: .5rem; padding: .7rem 1rem; border-radius: 999px; background: rgba(15, 23, 42, 0.04); border: 1px solid rgba(148, 163, 184, 0.42); color: rgba(15, 23, 42, 0.84); font-weight: 800; cursor: pointer; transition: .16s ease; } .settings-page .btn-ghost:hover { background: rgba(14, 165, 233, 0.12); border-color: rgba(14, 165, 233, 0.35); } .settings-page .btn-danger { background: rgba(239, 68, 68, 0.08); border-color: rgba(239, 68, 68, 0.25); color: rgba(185, 28, 28, 0.95); } .settings-page .btn-danger:hover { background: rgba(239, 68, 68, 0.14); border-color: rgba(239, 68, 68, 0.32); } .settings-page .field-icon input, .settings-page .field-icon select, .settings-page .field-icon textarea { border: none; outline: none; background: transparent; width: 100%; padding: 0; font-size: 1rem; font-weight: 700; color: #0f172a; } .settings-page .field-icon textarea { resize: vertical; min-height: 78px; line-height: 1.45; font-family: inherit; } .settings-page select, .settings-page input { width: 100%; padding: .85rem 1rem; border-radius: 14px; border: 1px solid rgba(148, 163, 184, 0.45); background: rgba(255,255,255,0.92); font-size: 1rem; font-weight: 700; color: #0f172a; transition: box-shadow .2s ease, border-color .2s ease; } .settings-page select:focus, .settings-page input:focus { outline: none; border-color: rgba(37, 99, 235, 0.55); box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.16); } .settings-page .help { margin-top: .75rem; color: rgba(15, 23, 42, 0.65); font-weight: 600; line-height: 1.45; } .settings-page .preview { margin-top: 1.05rem; display: flex; align-items: center; justify-content: space-between; gap: .85rem; padding: .95rem 1.05rem; border-radius: 14px; background: rgba(15, 23, 42, 0.04); border: 1px dashed rgba(15, 23, 42, 0.14); font-weight: 800; color: rgba(15, 23, 42, 0.75); } .settings-page .preview strong { font-size: 1.1rem; color: #0f172a; } .settings-page .brand-preview { display: flex; align-items: center; gap: 1rem; padding: .95rem 1.05rem; border-radius: 14px; background: rgba(15, 23, 42, 0.04); border: 1px dashed rgba(15, 23, 42, 0.14); position: relative; z-index: 1; } .settings-page .brand-preview img { width: 64px; height: 64px; border-radius: 16px; object-fit: contain; background: #fff; border: 1px solid rgba(148, 163, 184, 0.35); } .settings-page .brand-preview strong { display: block; font-size: 1.15rem; font-weight: 900; color: #0f172a; } .settings-page .brand-preview span { display: block; margin-top: .2rem; color: rgba(15, 23, 42, 0.65); font-weight: 700; } .settings-page .actions { margin-top: 1.25rem; display: flex; justify-content: flex-end; gap: .85rem; flex-wrap: wrap; position: relative; z-index: 1; } .settings-page .actions .btn, .settings-page .actions .option-btn { min-width: 160px; text-align: center; } .settings-page .actions .btn { display: inline-flex; align-items: center; justify-content: center; gap: 10px; border-radius: 14px; border: none; background: linear-gradient(135deg, #0ea5e9, #2563eb); box-shadow: 0 14px 28px rgba(37, 99, 235, 0.22); transition: transform .2s ease, box-shadow .2s ease; } .settings-page .actions .btn:hover { transform: translateY(-2px); box-shadow: 0 16px 34px rgba(37, 99, 235, 0.28); } .settings-page .actions .option-btn { display: inline-flex; align-items: center; justify-content: center; gap: 10px; border-radius: 14px; background: rgba(255, 255, 255, 0.86); border: 1px solid rgba(20, 20, 33, 0.12); color: rgba(20, 20, 33, 0.86); box-shadow: 0 12px 26px rgba(15, 21, 45, 0.08); transition: transform .2s ease, box-shadow .2s ease; } .settings-page .actions .option-btn:hover { transform: translateY(-2px); box-shadow: 0 14px 32px rgba(15, 21, 45, 0.12); } .settings-page .error-box { background: #fef2f2; border: 1px solid #fca5a5; color: #b91c1c; padding: 1rem 1.15rem; border-radius: 14px; margin-bottom: 1.25rem; font-weight: 700; } .settings-page .future { display: flex; flex-direction: column; gap: .85rem; position: relative; z-index: 1; } .settings-page .future-item { display: flex; align-items: center; justify-content: space-between; gap: .85rem; padding: .85rem 1rem; border-radius: 14px; background: rgba(255,255,255,0.72); border: 1px solid rgba(148, 163, 184, 0.25); } .settings-page .future-item span { font-weight: 800; color: rgba(15, 23, 42, 0.78); } .settings-page .future-item small { font-weight: 700; color: rgba(15, 23, 42, 0.55); } </style> </head> <body class="settings-page admin-panel"> <?php include '../components/admin_header.php'; ?> <section class="page-wrap"> <div class="page-title"> <div> <h1><i class="fa-solid fa-gear"></i> Configuración</h1> <p>Ajustes globales del sistema y de la página web.</p> </div> <span class="badge"><i class="fa-solid fa-coins"></i> Moneda actual: <?= htmlspecialchars((string)($currentCurrency['code'] ?? '')); ?></span> </div> <div class="kpi-row"> <div class="kpi-card"> <div class="kpi-card__row"> <div> <div class="kpi-card__label">Nombre del negocio</div> <div class="kpi-card__value"><?= htmlspecialchars($businessName); ?></div> </div> <div class="kpi-card__icon"><i class="fa-solid fa-store"></i></div> </div> </div> <div class="kpi-card"> <div class="kpi-card__row"> <div> <div class="kpi-card__label">Teléfono</div> <div class="kpi-card__value"><?= htmlspecialchars($businessPhone); ?></div> </div> <div class="kpi-card__icon kpi-card__icon--green"><i class="fa-solid fa-phone"></i></div> </div> </div> <div class="kpi-card"> <div class="kpi-card__row"> <div> <div class="kpi-card__label">Moneda</div> <div class="kpi-card__value"><?= htmlspecialchars((string)($currentCurrency['code'] ?? '')); ?></div> </div> <div class="kpi-card__icon kpi-card__icon--blue"><i class="fa-solid fa-coins"></i></div> </div> </div> </div> <?php if (!empty($errors)): ?> <div class="error-box"> <?php foreach ($errors as $err): ?> <div><?= htmlspecialchars($err); ?></div> <?php endforeach; ?> </div> <?php endif; ?> <div class="grid"> <div class="card"> <h3><i class="fa-solid fa-coins"></i> Moneda del sistema</h3> <form method="post" action=""> <input type="hidden" name="action" value="currency"> <div class="field"> <label for="currencySearch">Buscar</label> <div class="field-icon"> <i class="fa-solid fa-magnifying-glass"></i> <input id="currencySearch" type="text" placeholder="Escribe: dólar, euro, peso, USD..." autocomplete="off"> </div> </div> <div class="field" style="margin-top:1rem;"> <label for="currency_code">Selecciona la moneda</label> <div class="field-icon"> <i class="fa-solid fa-money-bill"></i> <select name="currency_code" id="currency_code" required data-current="<?= htmlspecialchars($currentCurrencyCode); ?>"> <?php foreach ($currencies as $c): ?> <?php $code = (string)($c['code'] ?? ''); ?> <option value="<?= htmlspecialchars($code); ?>" <?= $code === $currentCurrencyCode ? 'selected' : ''; ?> data-code="<?= htmlspecialchars($code); ?>" data-symbol="<?= htmlspecialchars((string)($c['symbol'] ?? '')); ?>" data-fraction="<?= (int)($c['fraction_size'] ?? 0); ?>" data-template="<?= htmlspecialchars((string)($c['template'] ?? '')); ?>"> <?= htmlspecialchars(formatCurrencyOptionLabel($c)); ?> </option> <?php endforeach; ?> </select> </div> </div> <div class="preview"> <span>Vista previa</span> <strong id="currencyPreview"><?= htmlspecialchars(formatMoney(1234567.89, $conn)); ?></strong> </div> <div class="help"> Este ajuste aplica a: <div style="margin-top:.45rem; display:flex; flex-wrap:wrap; gap:.45rem;"> <span class="badge" style="background:rgba(15,23,42,0.06); border-color:rgba(15,23,42,0.12); color:rgba(15,23,42,0.78);"><i class="fa-solid fa-globe"></i> Web</span> <span class="badge" style="background:rgba(15,23,42,0.06); border-color:rgba(15,23,42,0.12); color:rgba(15,23,42,0.78);"><i class="fa-solid fa-user-shield"></i> Panel admin</span> </div> </div> <div class="actions"> <button type="submit" class="btn"><i class="fa-solid fa-floppy-disk"></i> Guardar</button> </div> </form> </div> <div class="card"> <h3><i class="fa-solid fa-store"></i> Identidad del negocio</h3> <form method="post" action="" enctype="multipart/form-data"> <input type="hidden" name="action" value="branding"> <div class="brand-preview" style="margin-bottom:1rem;"> <img id="brandLogoPreview" src="<?= htmlspecialchars($logoHref); ?>" alt="<?= htmlspecialchars($businessName); ?>"> <div> <strong id="brandNamePreview"><?= htmlspecialchars($businessName); ?></strong> <span id="brandFileMeta">Vista previa del nombre y logo</span> </div> </div> <div class="field"> <label for="business_name">Nombre del negocio</label> <div class="field-icon"> <i class="fa-solid fa-signature"></i> <input id="business_name" name="business_name" type="text" required value="<?= htmlspecialchars($businessName); ?>"> </div> </div> <div class="field" style="margin-top:1rem;"> <label for="business_phone">Teléfono del negocio</label> <div class="field-icon"> <i class="fa-solid fa-phone"></i> <input id="business_phone" name="business_phone" type="text" required value="<?= htmlspecialchars($businessPhone); ?>" placeholder="+57 322 3512346"> </div> </div> <div class="field" style="margin-top:1rem;"> <label for="business_logo">Logo (PNG/JPG/WEBP)</label> <input id="business_logo" name="business_logo" type="file" accept="image/png,image/jpeg,image/webp"> </div> <div class="help"> Cambia el nombre y el logo del sistema. Se aplicará en el panel admin y en la web. </div> <div class="actions"> <button type="submit" class="btn"><i class="fa-solid fa-floppy-disk"></i> Guardar</button> </div> </form> </div> <div class="card"> <h3><i class="fa-solid fa-location-dot"></i> Horario, ubicación y Google Maps</h3> <form method="post" action=""> <input type="hidden" name="action" value="contact"> <div class="field"> <label for="business_hours">Horario de atención</label> <div class="field-icon"> <i class="fa-solid fa-clock"></i> <textarea id="business_hours" name="business_hours" required placeholder="Ej: Todos los días: 4:30 PM - 11:30 PM"><?= htmlspecialchars($businessHours); ?></textarea> </div> </div> <div class="field" style="margin-top:1rem;"> <label for="business_address">Dirección / ubicación</label> <div class="field-icon"> <i class="fa-solid fa-map-pin"></i> <textarea id="business_address" name="business_address" required placeholder="Ej: Av. 6 #17-77, Barrio La Cabrera, Cúcuta"><?= htmlspecialchars($businessAddress); ?></textarea> </div> </div> <div class="field" style="margin-top:1rem;"> <label for="business_location_hint">Detalle corto (opcional)</label> <div class="field-icon"> <i class="fa-solid fa-tag"></i> <input id="business_location_hint" name="business_location_hint" type="text" value="<?= htmlspecialchars($businessLocationHint); ?>" placeholder="Ej: Centro La Cabrera"> </div> </div> <div class="field" style="margin-top:1rem;"> <label for="google_maps_url">Enlace de Google Maps</label> <div class="field-icon"> <i class="fa-brands fa-google"></i> <input id="google_maps_url" name="google_maps_url" type="url" value="<?= htmlspecialchars($googleMapsUrl); ?>" placeholder="https://maps.app.goo.gl/..."> </div> </div> <div class="help"> Esta información se mostrará en la web (sección de contacto y botón “¿Cómo llegar?”). </div> <div class="actions"> <button type="submit" class="btn"><i class="fa-solid fa-floppy-disk"></i> Guardar</button> </div> </form> </div> <div class="card"> <h3><i class="fa-solid fa-share-nodes"></i> Redes sociales</h3> <form method="post" action=""> <input type="hidden" name="action" value="social"> <div class="field"> <label for="social_facebook_url">Facebook</label> <div class="field-icon"> <img class="social-icon" src="../assets/img/facebook.png" alt="Facebook"> <input id="social_facebook_url" name="social_facebook_url" type="url" value="<?= htmlspecialchars($socialFacebookUrl); ?>" placeholder="https://facebook.com/..."> </div> </div> <div class="field" style="margin-top:1rem;"> <label for="social_instagram_url">Instagram</label> <div class="field-icon"> <img class="social-icon" src="../assets/img/instagram.png" alt="Instagram"> <input id="social_instagram_url" name="social_instagram_url" type="url" value="<?= htmlspecialchars($socialInstagramUrl); ?>" placeholder="https://instagram.com/..."> </div> </div> <div class="field" style="margin-top:1rem;"> <label for="social_gmail_url">Gmail</label> <div class="field-icon"> <img class="social-icon" src="../assets/img/gmail.png" alt="Gmail"> <input id="social_gmail_url" name="social_gmail_url" type="text" value="<?= htmlspecialchars($socialGmailUrl); ?>" placeholder="correo@gmail.com o mailto:correo@gmail.com"> </div> </div> <div class="help"> Los íconos se mostrarán automáticamente en la web solo si estos campos tienen contenido. </div> <div class="actions"> <button type="submit" class="btn"><i class="fa-solid fa-floppy-disk"></i> Guardar</button> </div> </form> </div> <?php $paymentBanks = sanitizePaymentBanks($paymentBanks); ?> <?php foreach ($paymentBanks as $b): ?> <?php $bid = (string)($b['id'] ?? ''); $isActive = !empty($b['active']); $bankDisplayName = trim((string)($b['name'] ?? '')); if ($bankDisplayName === '') { $bankDisplayName = 'Banco'; } $logos = []; if (!empty($b['logos']) && is_array($b['logos'])) { foreach ($b['logos'] as $p) { $p = trim((string)$p); if ($p !== '') { $logos[] = $p; } if (count($logos) >= 3) { break; } } } $legacyLogo = trim((string)($b['logo'] ?? '')); if ($legacyLogo !== '' && empty($logos)) { $logos[] = $legacyLogo; } $logos = array_slice(array_values(array_filter($logos)), 0, 3); ?> <div class="card"> <h3><i class="fa-solid fa-building-columns"></i> <?= htmlspecialchars($bankDisplayName); ?></h3> <div class="help"> <?= $isActive ? 'Activo' : 'Inactivo'; ?> </div> <?php if (!empty($logos)): ?> <div class="bank-logos-preview"> <?php foreach ($logos as $i => $p): ?> <div class="bank-logo-item"> <img src="<?= htmlspecialchars('../' . ltrim((string)$p, '/')); ?>" alt="<?= htmlspecialchars((string)($b['name'] ?? '')); ?>"> <form method="post" action="" onsubmit="return confirm('¿Eliminar esta imagen?');"> <input type="hidden" name="action" value="bank_logo_delete"> <input type="hidden" name="bank_id" value="<?= htmlspecialchars($bid); ?>"> <input type="hidden" name="logo_index" value="<?= (int)$i + 1; ?>"> <button type="submit" class="btn-ghost btn-danger logo-remove-btn" title="Eliminar imagen" aria-label="Eliminar imagen"><i class="fa-solid fa-trash"></i></button> </form> </div> <?php endforeach; ?> </div> <?php endif; ?> <form method="post" action="" enctype="multipart/form-data" style="margin-top:1rem;"> <input type="hidden" name="action" value="bank_update"> <input type="hidden" name="bank_id" value="<?= htmlspecialchars($bid); ?>"> <div class="field"> <label>Nombre del banco</label> <div class="field-icon"> <i class="fa-solid fa-landmark"></i> <input name="bank_name" type="text" value="<?= htmlspecialchars((string)($b['name'] ?? '')); ?>"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Número / cuenta / teléfono</label> <div class="field-icon"> <i class="fa-solid fa-hashtag"></i> <input name="bank_account_number" type="text" value="<?= htmlspecialchars((string)($b['account_number'] ?? '')); ?>" placeholder="Ej: 3223512346 o 123456789"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Tipo</label> <div class="field-icon"> <i class="fa-solid fa-credit-card"></i> <input name="bank_account_type" type="text" value="<?= htmlspecialchars((string)($b['account_type'] ?? '')); ?>" placeholder="Ej: Ahorros / Corriente / Nequi"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Titular</label> <div class="field-icon"> <i class="fa-solid fa-user"></i> <input name="bank_account_holder" type="text" value="<?= htmlspecialchars((string)($b['account_holder'] ?? '')); ?>" placeholder="Ej: Nombre del titular"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Documento (opcional)</label> <div class="field-icon"> <i class="fa-solid fa-id-card"></i> <input name="bank_document" type="text" value="<?= htmlspecialchars((string)($b['document'] ?? '')); ?>" placeholder="CC/NIT"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Imágenes / logos (hasta 3)</label> <div style="display:grid; gap:.65rem;"> <input name="bank_logo_1" type="file" accept="image/png,image/jpeg,image/webp"> <input name="bank_logo_2" type="file" accept="image/png,image/jpeg,image/webp"> <input name="bank_logo_3" type="file" accept="image/png,image/jpeg,image/webp"> </div> </div> <div class="field" style="margin-top:1rem;"> <label style="display:flex; gap:.65rem; align-items:center;"> <input type="checkbox" name="bank_active" value="1" <?= $isActive ? 'checked' : ''; ?> style="width:auto;"> Activo </label> </div> <div class="actions"> <button type="submit" class="btn"><i class="fa-solid fa-floppy-disk"></i> Guardar</button> </div> </form> <form method="post" action="" style="margin-top:.65rem; display:flex; justify-content:flex-end;" onsubmit="return confirm('¿Eliminar este banco?');"> <input type="hidden" name="action" value="bank_delete"> <input type="hidden" name="bank_id" value="<?= htmlspecialchars($bid); ?>"> <button type="submit" class="btn-ghost btn-danger"><i class="fa-solid fa-trash"></i> Eliminar</button> </form> </div> <?php endforeach; ?> <div class="card"> <h3><i class="fa-solid fa-plus"></i> Agregar banco</h3> <div class="help">Crea un nuevo método para transferencia. En la web se mostrarán solo los que estén activos.</div> <form method="post" action="" enctype="multipart/form-data" style="margin-top:1rem;"> <input type="hidden" name="action" value="bank_add"> <input type="hidden" name="bank_id" value=""> <div class="field"> <label>Nombre del banco</label> <div class="field-icon"> <i class="fa-solid fa-landmark"></i> <input name="bank_name" type="text" placeholder="Ej: Bancolombia"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Número / cuenta / teléfono</label> <div class="field-icon"> <i class="fa-solid fa-hashtag"></i> <input name="bank_account_number" type="text" placeholder="Ej: 3223512346 o 123456789"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Tipo</label> <div class="field-icon"> <i class="fa-solid fa-credit-card"></i> <input name="bank_account_type" type="text" placeholder="Ej: Ahorros / Corriente / Nequi"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Titular</label> <div class="field-icon"> <i class="fa-solid fa-user"></i> <input name="bank_account_holder" type="text" placeholder="Ej: Nombre del titular"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Documento (opcional)</label> <div class="field-icon"> <i class="fa-solid fa-id-card"></i> <input name="bank_document" type="text" placeholder="CC/NIT"> </div> </div> <div class="field" style="margin-top:1rem;"> <label>Imágenes / logos (hasta 3)</label> <div style="display:grid; gap:.65rem;"> <input name="bank_logo_1" type="file" accept="image/png,image/jpeg,image/webp"> <input name="bank_logo_2" type="file" accept="image/png,image/jpeg,image/webp"> <input name="bank_logo_3" type="file" accept="image/png,image/jpeg,image/webp"> </div> </div> <div class="field" style="margin-top:1rem;"> <label style="display:flex; gap:.65rem; align-items:center;"> <input type="checkbox" name="bank_active" value="1" checked style="width:auto;"> Activo </label> </div> <div class="actions"> <button type="submit" class="btn"><i class="fa-solid fa-plus"></i> Agregar</button> </div> </form> </div> </div> </section> <script> (function(){ const select = document.getElementById('currency_code'); const search = document.getElementById('currencySearch'); const preview = document.getElementById('currencyPreview'); function formatPreview(value, option){ const code = option?.dataset?.code || ''; const symbol = option?.dataset?.symbol || '$'; const fractionRaw = option?.dataset?.fraction || '0'; const template = option?.dataset?.template || '$1'; const fraction = Math.max(0, Math.min(6, parseInt(fractionRaw, 10) || 0)); const number = Number(value || 0); const formatted = number.toLocaleString('es-CO', { minimumFractionDigits: fraction, maximumFractionDigits: fraction }); const symbolPos = String(template).indexOf('$'); const numberPos = String(template).indexOf('1'); if (symbolPos === -1 || numberPos === -1) { return symbol + formatted; } if (symbolPos < numberPos) { const between = String(template).slice(symbolPos + 1, numberPos); const glue = /\s/.test(between) ? ' ' : ''; return symbol + glue + formatted; } const between = String(template).slice(numberPos + 1, symbolPos); const glue = /\s/.test(between) ? ' ' : ''; return formatted + glue + symbol; } function refreshPreview(){ if (!select || !preview) return; const option = select.options[select.selectedIndex]; preview.textContent = formatPreview(1234567.89, option); } function filterOptions(){ if (!select || !search) return; const term = (search.value || '').trim().toLowerCase(); const options = Array.from(select.options); let firstVisibleIndex = -1; options.forEach((opt, idx) => { const text = (opt.textContent || '').toLowerCase(); const visible = term === '' || text.includes(term); opt.hidden = !visible; if (visible && firstVisibleIndex === -1) firstVisibleIndex = idx; }); if (term !== '' && firstVisibleIndex !== -1) { select.selectedIndex = firstVisibleIndex; refreshPreview(); } } select?.addEventListener('change', refreshPreview); search?.addEventListener('input', filterOptions); refreshPreview(); })(); </script> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <script> document.addEventListener('DOMContentLoaded', () => { const errors = <?= json_encode(array_values($errors), JSON_UNESCAPED_UNICODE); ?>; const nodes = Array.from(document.querySelectorAll('.message')); if(nodes.length && window.Swal){ const texts = nodes.map(n => (n.querySelector('span')?.textContent || '').trim()).filter(Boolean); nodes.forEach(n => n.remove()); if(texts.length){ const Toast = Swal.mixin({ toast: true, position: 'top-end', showConfirmButton: false, timer: 3200, timerProgressBar: true, }); texts.forEach((t) => Toast.fire({ icon: 'success', title: t })); } } if(errors.length && window.Swal){ Swal.fire({ title: 'Revisa la configuración', html: `<div style="text-align:left;">${errors.map(e => `- ${e}`).join('<br>')}</div>`, icon: 'error', confirmButtonText: 'Entendido', }); } const logoInput = document.getElementById('business_logo'); const logoPreview = document.getElementById('brandLogoPreview'); const fileMeta = document.getElementById('brandFileMeta'); const nameInput = document.getElementById('business_name'); const namePreview = document.getElementById('brandNamePreview'); nameInput?.addEventListener('input', () => { if(namePreview){ namePreview.textContent = nameInput.value || ''; } }); logoInput?.addEventListener('change', () => { const file = logoInput.files && logoInput.files[0] ? logoInput.files[0] : null; if(!file) return; if(fileMeta){ const sizeMb = (file.size / (1024 * 1024)).toFixed(2); fileMeta.textContent = `${file.name} · ${sizeMb} MB`; } if(logoPreview){ const url = URL.createObjectURL(file); logoPreview.src = url; logoPreview.onload = () => URL.revokeObjectURL(url); } }); }); </script> </body> </html>
Coded With 💗 by
0x6ick