cambios importantes

This commit is contained in:
Lizandro Guarnizo
2026-06-12 22:02:03 -05:00
parent bc422e0a1c
commit 4bd353c128
3 changed files with 571 additions and 0 deletions
+460
View File
@@ -1604,6 +1604,7 @@ HTML;
<a href="/admin/pending" class="nav-link">⏳ Pendientes</a>
<a href="/admin/chat" class="nav-link active">💬 Chat</a>
<a href="/admin/companies" class="nav-link">🏢 Empresas</a>
<a href="/admin/bot-config" class="nav-link">🤖 Bot Config</a>
<a href="/admin/settings" class="nav-link">⚙️ Configuración</a>
<a href="/admin/sync-companies" class="nav-link" onclick="return confirm('¿Sincronizar empresas desde el ERP?')">🔄 Sincronizar</a>
<a href="/admin/process-queue" class="nav-link" onclick="return confirm('¿Procesar cola de mensajes?')">📨 Procesar Cola</a>
@@ -1914,4 +1915,463 @@ HTML;
jsonResponse(200, ['status' => 'sent']);
}
// ─── GET /admin/bot-config ──────────────────────────────────────────────
public static function botConfig(): void
{
SessionAuth::require();
$user = SessionAuth::user();
$userName = self::h($user['name'] ?? 'Admin');
$companyId = (int)($_GET['id'] ?? 0);
$companies = CompanyRepository::findAll();
$company = null;
$config = ['commands' => [], 'menus' => [], 'flows' => [], 'ai_prompt' => '', 'fallback' => '', 'greeting' => ''];
$msg = $_GET['msg'] ?? '';
$toastHtml = $msg === 'saved' ? '<div class="toast toast-success">Configuración guardada exitosamente.</div>' : '';
if ($companyId > 0) {
$company = CompanyRepository::findById($companyId);
if ($company) {
$cj = $company['config_json'] ?? '';
if ($cj) {
$parsed = json_decode($cj, true);
if (is_array($parsed)) $config = $parsed;
}
}
}
$configJson = self::h(json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
http_response_code(200);
header('Content-Type: text/html; charset=utf-8');
echo <<<HTML
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Configurar Bot &mdash; Palmas360</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;background:#f5f7fb;color:#1a1d23;font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased}
.topbar{background:linear-gradient(135deg,#0a2e6e,#0b3d91,#1565c0);color:#fff;padding:12px 28px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:100;box-shadow:0 2px 12px rgba(0,0,0,.12)}
.topbar h1{font-size:15px;font-weight:700;letter-spacing:.02em;display:flex;align-items:center;gap:8px}
.topbar-r{display:flex;align-items:center;gap:10px}
.ubadge{background:rgba(255,255,255,.15);border-radius:20px;padding:4px 14px;font-size:12px;font-weight:500;backdrop-filter:blur(4px)}
.btn-out{background:rgba(255,255,255,.15);color:#fff;border:1px solid rgba(255,255,255,.2);border-radius:8px;padding:6px 16px;font-size:13px;font-weight:500;cursor:pointer;text-decoration:none;transition:all .15s;backdrop-filter:blur(4px)}
.btn-out:hover{background:rgba(255,255,255,.25);border-color:rgba(255,255,255,.35)}
.nav-bar{background:#fff;padding:10px 28px;display:flex;gap:2px;flex-wrap:wrap;border-bottom:1px solid #eef1f5;box-shadow:0 1px 3px rgba(0,0,0,.04);position:sticky;top:52px;z-index:99}
.nav-link{padding:8px 18px;border-radius:10px;font-size:13px;font-weight:500;color:#5f6b7a;text-decoration:none;transition:all .2s ease;display:inline-flex;align-items:center;gap:6px;letter-spacing:.01em}
.nav-link:hover{background:#f0f4ff;color:#0b3d91;transform:translateY(-1px)}
.nav-link.active{background:#0b3d91;color:#fff;box-shadow:0 2px 8px rgba(11,61,145,.25)}
.wrap{padding:24px;max-width:1100px;margin:0 auto}
.toast{padding:12px 18px;border-radius:10px;font-size:13px;font-weight:600;margin-bottom:16px;text-align:center}
.toast-success{background:#dcfce7;color:#166534;border:1px solid #a3e4bc}
.tabs{display:flex;gap:2px;margin-bottom:0;flex-wrap:wrap;position:sticky;top:104px;z-index:90;background:#f5f7fb;padding:10px 0 0}
.tab-btn{padding:10px 18px;border:none;border-radius:10px 10px 0 0;font-size:13px;font-weight:600;cursor:pointer;background:#e8ecf2;color:#5f6b7a;transition:all .15s}
.tab-btn:hover{background:#dce1e8}
.tab-btn.active{background:#fff;color:#0b3d91;box-shadow:0 -2px 4px rgba(0,0,0,.04)}
.tab-content{display:none;background:#fff;border-radius:0 12px 12px 12px;box-shadow:0 1px 4px rgba(0,0,0,.04),0 4px 16px rgba(0,0,0,.03);padding:24px;border:1px solid #eef1f5;margin-bottom:24px}
.tab-content.active{display:block}
.card-h{font-size:16px;font-weight:700;color:#0b3d91;margin-bottom:16px;padding-bottom:10px;border-bottom:2px solid #eef1f5}
.form-group{margin-bottom:14px}
.form-group label{display:block;font-size:12px;font-weight:600;color:#3d4552;margin-bottom:4px}
.form-group input,.form-group select,.form-group textarea{width:100%;padding:9px 12px;border:1px solid #e2e5ea;border-radius:8px;font-size:13px;outline:none;font-family:inherit;background:#fafbfc;transition:all .15s;color:#1a1d23}
.form-group input:focus,.form-group select:focus,.form-group textarea:focus{border-color:#1565c0;background:#fff;box-shadow:0 0 0 3px rgba(21,101,192,.08)}
.form-group textarea{min-height:60px;resize:vertical;font-family:'SF Mono',Monaco,monospace;font-size:12px;line-height:1.6}
.form-row{display:flex;gap:12px;flex-wrap:wrap}
.form-row .form-group{flex:1;min-width:150px}
.btn-primary{background:#0b3d91;color:#fff;border:none;border-radius:8px;padding:10px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all .15s}
.btn-primary:hover{background:#1565c0;box-shadow:0 2px 8px rgba(11,61,145,.2)}
.btn-secondary{background:#f0f4ff;color:#0b3d91;border:1px solid #d6e4ff;border-radius:8px;padding:8px 16px;font-size:13px;font-weight:600;cursor:pointer;transition:all .15s}
.btn-secondary:hover{background:#dbeafe}
.btn-danger-sm{background:#fef2f2;color:#991b1b;border:1px solid #fecaca;border-radius:6px;padding:4px 10px;font-size:11px;font-weight:600;cursor:pointer;transition:all .15s}
.btn-danger-sm:hover{background:#fee2e2}
.item-card{background:#f8f9fd;border:1px solid #eef1f5;border-radius:10px;padding:16px;margin-bottom:12px}
.item-card .item-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;font-weight:600;font-size:13px;color:#0b3d91}
.item-card .item-head .del{cursor:pointer;color:#991b1b;font-size:12px;background:none;border:none;font-weight:600}
.add-btn{background:none;border:2px dashed #d6e4ff;border-radius:8px;padding:10px;text-align:center;color:#0b3d91;font-size:13px;font-weight:600;cursor:pointer;width:100%;transition:all .15s}
.add-btn:hover{background:#f0f4ff;border-color:#0b3d91}
.inline-group{display:flex;gap:8px;align-items:center;margin-bottom:8px;flex-wrap:wrap}
.inline-group input,.inline-group select{flex:1;min-width:100px}
.inline-group .del{margin-left:auto}
table.simple{width:100%;border-collapse:collapse;margin-bottom:12px}
table.simple th{text-align:left;padding:8px 10px;font-size:11px;font-weight:700;color:#0b3d91;text-transform:uppercase;letter-spacing:.3px;border-bottom:2px solid #e8eaf6;background:#f8f9fd}
table.simple td{padding:8px 10px;border-bottom:1px solid #f0f2f5;font-size:13px;vertical-align:middle}
.company-select{display:flex;gap:12px;align-items:center;margin-bottom:20px;flex-wrap:wrap}
.company-select select{padding:9px 14px;border:1px solid #e2e5ea;border-radius:8px;font-size:13px;outline:none;background:#fff;min-width:250px}
.company-select select:focus{border-color:#1565c0}
@media(max-width:768px){.wrap{padding:12px}.tabs{top:auto}.tab-content{padding:16px}}
</style>
</head>
<body>
<div class="topbar">
<div><h1><img src="https://app.palmas360.com/Test/imgLogin/logo.png" alt="Palmas360" style="height:32px;vertical-align:middle;margin-right:8px;filter:brightness(0) invert(1)"> Configurar Bot</h1></div>
<div class="topbar-r"><span class="ubadge">&#128100; {$userName}</span><a href="/logout" class="btn-out">Salir</a></div>
</div>
<nav class="nav-bar">
<a href="/admin/dashboard" class="nav-link">📊 Dashboard</a>
<a href="/admin/live" class="nav-link">🔴 Live Feed</a>
<a href="/admin/pending" class="nav-link">⏳ Pendientes</a>
<a href="/admin/chat" class="nav-link">💬 Chat</a>
<a href="/admin/companies" class="nav-link">🏢 Empresas</a>
<a href="/admin/bot-config" class="nav-link active">🤖 Bot Config</a>
<a href="/admin/settings" class="nav-link">⚙️ Configuración</a>
<a href="/admin/sync-companies" class="nav-link" onclick="return confirm('¿Sincronizar empresas desde el ERP?')">🔄 Sincronizar</a>
<a href="/admin/process-queue" class="nav-link" onclick="return confirm('¿Procesar cola de mensajes?')">📨 Procesar Cola</a>
</nav>
<div class="wrap">
{$toastHtml}
<div class="company-select">
<label style="font-weight:600;font-size:13px">Seleccionar empresa:</label>
<select onchange="if(this.value) window.location='?id='+this.value">
<option value="">— Selecciona —</option>
HTML;
foreach ($companies as $c) {
$sel = $companyId === (int)$c['id'] ? 'selected' : '';
echo "<option value=\"{$c['id']}\" {$sel}>" . self::h($c['name'] . ' — ' . ($c['display_name'] ?? '')) . "</option>";
}
echo '</select></div>';
if (!$company) {
echo '<div class="tab-content active" style="border-radius:12px;text-align:center;padding:40px;color:#a0a8b8;font-size:15px">Selecciona una empresa para configurar su bot.</div>';
echo '</div></body></html>';
exit;
}
$c = $company;
$cId = (int)$c['id'];
$cName = self::h($c['name'] ?? '');
// Pre-fill form values from config
$greetingVal = self::h($config['greeting'] ?? '');
$fallbackVal = self::h($config['fallback'] ?? '');
$aiPromptVal = self::h($config['ai_prompt'] ?? '');
$aiModelVal = self::h($config['ai_model'] ?? 'gpt-4o-mini');
$aiTempVal = self::h((string)($config['ai_temperature'] ?? 0.7));
$aiProviderVal = self::h($config['ai_provider'] ?? '');
$approvalWebhookVal = self::h($config['approval_webhook'] ?? '');
$ignoreVal = self::h(implode("\n", $config['ignore_prefixes'] ?? []));
$commands = $config['commands'] ?? [];
$menus = $config['menus'] ?? [];
$flows = $config['flows'] ?? [];
$aiProviderOpenai = $aiProviderVal === 'openai' ? ' selected' : '';
$aiProviderMock = $aiProviderVal === 'mock' ? ' selected' : '';
$aiModelMini = $aiModelVal === 'gpt-4o-mini' ? ' selected' : '';
$aiModel4o = $aiModelVal === 'gpt-4o' ? ' selected' : '';
$aiModel35 = $aiModelVal === 'gpt-3.5-turbo' ? ' selected' : '';
echo <<<HTML
<form method="POST" action="/admin/bot-config/save">
<input type="hidden" name="company_id" value="{$cId}">
<div class="tabs">
<button type="button" class="tab-btn active" onclick="switchTab('commands',this)">📋 Comandos</button>
<button type="button" class="tab-btn" onclick="switchTab('menus',this)">📑 Menús</button>
<button type="button" class="tab-btn" onclick="switchTab('flows',this)">🔀 Flujos</button>
<button type="button" class="tab-btn" onclick="switchTab('ai',this)">🤖 IA</button>
<button type="button" class="tab-btn" onclick="switchTab('general',this)">⚙️ General</button>
</div>
<!-- ─── COMMANDS ─────────────────────────────────────────────────────── -->
<div class="tab-content active" id="tab-commands">
<div class="card-h">📋 Comandos</div>
<p style="font-size:12px;color:#7a8291;margin-bottom:14px">Palabras clave que el usuario escribe para ejecutar acciones. Ej: "menu", "info", "contacto"</p>
<table class="simple" id="cmdTable">
<thead><tr><th>Palabra clave</th><th>Acción (menú o flujo)</th><th></th></tr></thead>
<tbody id="cmdBody">
HTML;
$cmdIdx = 0;
foreach ($commands as $keyword => $action) {
echo "<tr id=\"cmd-row-{$cmdIdx}\">
<td><input type=\"text\" name=\"cmd_keyword[]\" value=\"" . self::h($keyword) . "\" style=\"width:100%;padding:6px 10px;border:1px solid #e2e5ea;border-radius:6px;font-size:13px\"></td>
<td><input type=\"text\" name=\"cmd_action[]\" value=\"" . self::h($action) . "\" style=\"width:100%;padding:6px 10px;border:1px solid #e2e5ea;border-radius:6px;font-size:13px\" placeholder=\"ej: show_main, servicios...\"></td>
<td><button type=\"button\" class=\"btn-danger-sm\" onclick=\"this.closest('tr').remove()\">✕</button></td>
</tr>";
$cmdIdx++;
}
echo <<<HTML
</tbody>
</table>
<button type="button" class="add-btn" onclick="addCmd()">+ Agregar comando</button>
</div>
<!-- ─── MENUS ────────────────────────────────────────────────────────── -->
<div class="tab-content" id="tab-menus">
<div class="card-h">📑 Menús Interactivos</div>
<p style="font-size:12px;color:#7a8291;margin-bottom:14px">Menús tipo lista o botones que se envían al usuario. Cada menú tiene un ID (ej: show_main) y puede tener secciones con filas.</p>
<div id="menuContainer">
HTML;
$menuIdx = 0;
foreach ($menus as $mk => $menu) {
$mt = $menu['type'] ?? 'list';
$mh = self::h($menu['header'] ?? '');
$mb = self::h($menu['body'] ?? '');
$mf = self::h($menu['footer'] ?? '');
$mbtn = self::h($menu['button'] ?? '');
echo "<div class=\"item-card\" id=\"menu-card-{$menuIdx}\">
<div class=\"item-head\">
<span>Menú: <input type=\"text\" name=\"menu_key[]\" value=\"" . self::h($mk) . "\" style=\"border:none;background:transparent;font-weight:700;color:#0b3d91;width:200px;font-size:13px\" placeholder=\"ID del menú (ej: show_main)\"></span>
<button type=\"button\" class=\"del\" onclick=\"this.closest('.item-card').remove()\">✕ Eliminar menú</button>
</div>
<div class=\"form-row\">
<div class=\"form-group\"><label>Tipo</label><select name=\"menu_type[]\"><option value=\"list\"" . ($mt==='list'?' selected':'') . ">Lista</option><option value=\"button\"" . ($mt==='button'?' selected':'') . ">Botones</option></select></div>
<div class=\"form-group\"><label>Header</label><input type=\"text\" name=\"menu_header[]\" value=\"{$mh}\" placeholder=\"Título del menú\"></div>
<div class=\"form-group\"><label>Body</label><input type=\"text\" name=\"menu_body[]\" value=\"{$mb}\" placeholder=\"Cuerpo del mensaje\"></div>
<div class=\"form-group\"><label>Footer</label><input type=\"text\" name=\"menu_footer[]\" value=\"{$mf}\" placeholder=\"Footer (opcional)\"></div>
<div class=\"form-group\"><label>Botón</label><input type=\"text\" name=\"menu_button[]\" value=\"{$mbtn}\" placeholder=\"Texto del botón\"></div>
</div>
<div style=\"margin-top:8px\">
<div style=\"font-size:12px;font-weight:600;color:#3d4552;margin-bottom:6px\">Secciones:</div>
<div class=\"sections-container\" id=\"menu-sections-{$menuIdx}\">";
$si = 0;
foreach ($menu['sections'] ?? [] as $section) {
$st = self::h($section['title'] ?? '');
echo "<div class=\"section-card\" style=\"background:#fff;border:1px solid #eef1f5;border-radius:8px;padding:12px;margin-bottom:8px\">
<div style=\"display:flex;align-items:center;gap:8px;margin-bottom:8px\">
<input type=\"text\" name=\"menu_sections[{$menuIdx}][{$si}][title]\" value=\"{$st}\" placeholder=\"Título de sección\" style=\"flex:1;padding:6px 10px;border:1px solid #e2e5ea;border-radius:6px;font-size:13px\">
<button type=\"button\" class=\"btn-danger-sm\" onclick=\"this.closest('.section-card').remove()\">✕</button>
</div>
<div style=\"font-size:11px;font-weight:600;color:#7a8291;margin-bottom:4px\">Filas (cada fila es una opción):</div>";
$ri = 0;
foreach ($section['rows'] ?? [] as $row) {
$rid = self::h($row['id'] ?? '');
$rt = self::h($row['title'] ?? '');
$rd = self::h($row['description'] ?? '');
echo "<div class=\"inline-group\" style=\"margin-bottom:4px\">
<input type=\"text\" name=\"menu_sections[{$menuIdx}][{$si}][rows][{$ri}][id]\" value=\"{$rid}\" placeholder=\"ID (ej: servicios)\" style=\"flex:1\">
<input type=\"text\" name=\"menu_sections[{$menuIdx}][{$si}][rows][{$ri}][title]\" value=\"{$rt}\" placeholder=\"Título\" style=\"flex:1\">
<input type=\"text\" name=\"menu_sections[{$menuIdx}][{$si}][rows][{$ri}][description]\" value=\"{$rd}\" placeholder=\"Descripción\" style=\"flex:1.5\">
<button type=\"button\" class=\"btn-danger-sm\" onclick=\"this.closest('.inline-group').remove()\">✕</button>
</div>";
$ri++;
}
echo "<button type=\"button\" class=\"btn-secondary\" style=\"font-size:11px;padding:4px 10px;margin-top:4px\" onclick=\"addRow(this,{$menuIdx},{$si})\">+ Fila</button>
</div>";
$si++;
}
echo "</div>
<button type=\"button\" class=\"btn-secondary\" style=\"font-size:11px;padding:4px 10px;margin-top:6px\" onclick=\"addSection({$menuIdx})\">+ Sección</button>
</div>
</div>";
$menuIdx++;
}
echo <<<HTML
</div>
<button type="button" class="add-btn" onclick="addMenu()">+ Agregar menú</button>
</div>
<!-- ─── FLOWS ────────────────────────────────────────────────────────── -->
<div class="tab-content" id="tab-flows">
<div class="card-h">🔀 Flujos</div>
<p style="font-size:12px;color:#7a8291;margin-bottom:14px">Acciones que se ejecutan cuando un comando o fila de menú es seleccionada.</p>
<div id="flowContainer">
HTML;
$flowIdx = 0;
foreach ($flows as $fk => $flow) {
$ft = $flow['type'] ?? 'text';
$fMsg = self::h($flow['message'] ?? '');
$fFn = self::h($flow['function'] ?? 'forward_to_ai');
$fMenu = self::h($flow['menu'] ?? '');
echo "<div class=\"item-card\" id=\"flow-card-{$flowIdx}\">
<div class=\"item-head\">
<span>ID: <input type=\"text\" name=\"flow_key[]\" value=\"" . self::h($fk) . "\" style=\"border:none;background:transparent;font-weight:700;color:#0b3d91;width:200px;font-size:13px\" placeholder=\"ID del flujo (ej: servicios)\"></span>
<button type=\"button\" class=\"del\" onclick=\"this.closest('.item-card').remove()\">✕</button>
</div>
<div class=\"form-row\">
<div class=\"form-group\" style=\"min-width:120px\">
<label>Tipo</label>
<select name=\"flow_type[]\" onchange=\"flowTypeChange(this)\">
<option value=\"text\"" . ($ft==='text'?' selected':'') . ">Texto (respuesta fija)</option>
<option value=\"function\"" . ($ft==='function'?' selected':'') . ">Función (acción especial)</option>
<option value=\"menu\"" . ($ft==='menu'?' selected':'') . ">Menú (submenú)</option>
</select>
</div>
<div class=\"form-group flow-text\" style=\"" . ($ft==='text'?'':'display:none') . "\">
<label>Mensaje de respuesta</label>
<textarea name=\"flow_message[]\" rows=\"2\" placeholder=\"Texto que se enviará al usuario\">{$fMsg}</textarea>
</div>
<div class=\"form-group flow-function\" style=\"" . ($ft==='function'?'':'display:none') . "\">
<label>Función</label>
<select name=\"flow_function[]\">
<option value=\"forward_to_ai\"" . ($fFn==='forward_to_ai'?' selected':'') . ">Escalar a IA</option>
<option value=\"forward_to_agent\"" . ($fFn==='forward_to_agent'?' selected':'') . ">Escalar a agente humano</option>
<option value=\"webhook\"" . ($fFn==='webhook'?' selected':'') . ">Llamar webhook externo</option>
</select>
</div>
<div class=\"form-group flow-menu\" style=\"" . ($ft==='menu'?'':'display:none') . "\">
<label>Menú a mostrar</label>
<input type=\"text\" name=\"flow_menu[]\" value=\"{$fMenu}\" placeholder=\"ID del menú (ej: show_main)\">
</div>
</div>
</div>";
$flowIdx++;
}
echo <<<HTML
</div>
<button type="button" class="add-btn" onclick="addFlow()">+ Agregar flujo</button>
</div>
<!-- ─── AI ───────────────────────────────────────────────────────────── -->
<div class="tab-content" id="tab-ai">
<div class="card-h">🤖 Inteligencia Artificial</div>
<div class="form-group">
<label>Proveedor (sobrescribe el global)</label>
<select name="ai_provider">
<option value="">Usar configuración global</option>
<option value="openai"{$aiProviderOpenai}>OpenAI</option>
<option value="mock"{$aiProviderMock}>Mock (simulado)</option>
</select>
<div style="font-size:11px;color:#7a8291;margin-top:3px">Si no se selecciona, usa el proveedor de Configuración General</div>
</div>
<div class="form-row">
<div class="form-group">
<label>Modelo</label>
<select name="ai_model">
<option value="gpt-4o-mini"{$aiModelMini}>GPT-4o Mini</option>
<option value="gpt-4o"{$aiModel4o}>GPT-4o</option>
<option value="gpt-3.5-turbo"{$aiModel35}>GPT-3.5 Turbo</option>
</select>
</div>
<div class="form-group">
<label>Temperatura ({$aiTempVal})</label>
<input type="range" name="ai_temperature" min="0" max="1" step="0.1" value="{$aiTempVal}" oninput="this.previousElementSibling.textContent='Temperatura ('+this.value+')'">
</div>
</div>
<div class="form-group">
<label>System Prompt</label>
<textarea name="ai_prompt" rows="4" placeholder="Eres un asistente virtual de {$cName}...">{$aiPromptVal}</textarea>
<div style="font-size:11px;color:#7a8291;margin-top:3px">Instrucciones que define el comportamiento de la IA</div>
</div>
</div>
<!-- ─── GENERAL ──────────────────────────────────────────────────────── -->
<div class="tab-content" id="tab-general">
<div class="card-h">⚙️ General</div>
<div class="form-row">
<div class="form-group">
<label>Mensaje de bienvenida (greeting)</label>
<textarea name="greeting" rows="2" placeholder="¡Bienvenido! Escribe 'menu' para ver opciones...">{$greetingVal}</textarea>
<div style="font-size:11px;color:#7a8291;margin-top:3px">Primer mensaje que recibe un usuario nuevo</div>
</div>
<div class="form-group">
<label>Mensaje por defecto (fallback)</label>
<textarea name="fallback" rows="2" placeholder="No entendí. Escribe menu para ver opciones.">{$fallbackVal}</textarea>
<div style="font-size:11px;color:#7a8291;margin-top:3px">Cuando el bot no entiende el mensaje</div>
</div>
</div>
<div class="form-group">
<label>Webhook de aprobación (approval_webhook)</label>
<input type="text" name="approval_webhook" value="{$approvalWebhookVal}" placeholder="https://api.ejemplo.com/webhook-aprobacion">
<div style="font-size:11px;color:#7a8291;margin-top:3px">URL a la que se notificará cuando se requiera aprobación</div>
</div>
<div class="form-group">
<label>Prefijos a ignorar (uno por línea)</label>
<textarea name="ignore_prefixes" rows="3" placeholder="Ej:&#10;555&#10;111">{$ignoreVal}</textarea>
<div style="font-size:11px;color:#7a8291;margin-top:3px">Números que comiencen con estos prefijos no recibirán respuestas del bot</div>
</div>
</div>
<div style="display:flex;gap:12px;margin-top:16px">
<button type="submit" class="btn-primary">💾 Guardar configuración</button>
<a href="/admin/companies" class="btn-secondary" style="text-decoration:none;display:inline-flex;align-items:center">↩ Volver a empresas</a>
</div>
</form>
</div>
<script>
function switchTab(tab, btn) {
document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-btn').forEach(t => t.classList.remove('active'));
document.getElementById('tab-' + tab).classList.add('active');
btn.classList.add('active');
}
// Commands
function addCmd() {
const tbody = document.getElementById('cmdBody');
const idx = tbody.children.length;
const tr = document.createElement('tr');
tr.id = 'cmd-row-' + idx;
tr.innerHTML = '<td><input type="text" name="cmd_keyword[]" style="width:100%;padding:6px 10px;border:1px solid #e2e5ea;border-radius:6px;font-size:13px" placeholder="ej: menu"></td>' +
'<td><input type="text" name="cmd_action[]" style="width:100%;padding:6px 10px;border:1px solid #e2e5ea;border-radius:6px;font-size:13px" placeholder="ej: show_main"></td>' +
'<td><button type="button" class="btn-danger-sm" onclick="this.closest(\'tr\').remove()">✕</button></td>';
tbody.appendChild(tr);
}
// Menus
function addMenu() {
const container = document.getElementById('menuContainer');
const idx = container.children.length;
const div = document.createElement('div');
div.className = 'item-card';
div.id = 'menu-card-' + idx;
div.innerHTML = '<div class="item-head"><span>Menú: <input type="text" name="menu_key[]" style="border:none;background:transparent;font-weight:700;color:#0b3d91;width:200px;font-size:13px" placeholder="ID del menú (ej: show_main)"></span><button type="button" class="del" onclick="this.closest(\'.item-card\').remove()">✕ Eliminar menú</button></div>' +
'<div class="form-row">' +
'<div class="form-group"><label>Tipo</label><select name="menu_type[]"><option value="list">Lista</option><option value="button">Botones</option></select></div>' +
'<div class="form-group"><label>Header</label><input type="text" name="menu_header[]" placeholder="Título del menú"></div>' +
'<div class="form-group"><label>Body</label><input type="text" name="menu_body[]" placeholder="Cuerpo del mensaje"></div>' +
'<div class="form-group"><label>Footer</label><input type="text" name="menu_footer[]" placeholder="Footer (opcional)"></div>' +
'<div class="form-group"><label>Botón</label><input type="text" name="menu_button[]" placeholder="Texto del botón"></div>' +
'</div>' +
'<div style="margin-top:8px"><div style="font-size:12px;font-weight:600;color:#3d4552;margin-bottom:6px">Secciones:</div><div class="sections-container" id="menu-sections-' + idx + '"></div><button type="button" class="btn-secondary" style="font-size:11px;padding:4px 10px;margin-top:6px" onclick="addSection(' + idx + ')">+ Sección</button></div>';
container.appendChild(div);
}
function addSection(mi) {
const container = document.getElementById('menu-sections-' + mi);
const si = container.children.length;
const div = document.createElement('div');
div.className = 'section-card';
div.style.cssText = 'background:#fff;border:1px solid #eef1f5;border-radius:8px;padding:12px;margin-bottom:8px';
div.innerHTML = '<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px"><input type="text" name="menu_sections[' + mi + '][' + si + '][title]" placeholder="Título de sección" style="flex:1;padding:6px 10px;border:1px solid #e2e5ea;border-radius:6px;font-size:13px"><button type="button" class="btn-danger-sm" onclick="this.closest(\'.section-card\').remove()">✕</button></div>' +
'<div style="font-size:11px;font-weight:600;color:#7a8291;margin-bottom:4px">Filas:</div>' +
'<div class="rows-container" id="menu-rows-' + mi + '-' + si + '"></div>' +
'<button type="button" class="btn-secondary" style="font-size:11px;padding:4px 10px;margin-top:4px" onclick="addRow(this,' + mi + ',' + si + ')">+ Fila</button>';
container.appendChild(div);
}
function addRow(btn, mi, si) {
const container = btn.closest('.section-card').querySelector('.rows-container');
const ri = container.children.length;
const div = document.createElement('div');
div.className = 'inline-group';
div.style.cssText = 'display:flex;gap:8px;align-items:center;margin-bottom:4px';
div.innerHTML = '<input type="text" name="menu_sections[' + mi + '][' + si + '][rows][' + ri + '][id]" placeholder="ID" style="flex:1;padding:6px 10px;border:1px solid #e2e5ea;border-radius:6px;font-size:12px">' +
'<input type="text" name="menu_sections[' + mi + '][' + si + '][rows][' + ri + '][title]" placeholder="Título" style="flex:1;padding:6px 10px;border:1px solid #e2e5ea;border-radius:6px;font-size:12px">' +
'<input type="text" name="menu_sections[' + mi + '][' + si + '][rows][' + ri + '][description]" placeholder="Descripción" style="flex:1.5;padding:6px 10px;border:1px solid #e2e5ea;border-radius:6px;font-size:12px">' +
'<button type="button" class="btn-danger-sm" onclick="this.closest(\'.inline-group\').remove()">✕</button>';
container.appendChild(div);
}
// Flows
function addFlow() {
const container = document.getElementById('flowContainer');
const idx = container.children.length;
const div = document.createElement('div');
div.className = 'item-card';
div.id = 'flow-card-' + idx;
div.innerHTML = '<div class="item-head"><span>ID: <input type="text" name="flow_key[]" style="border:none;background:transparent;font-weight:700;color:#0b3d91;width:200px;font-size:13px" placeholder="ID del flujo (ej: servicios)"></span><button type="button" class="del" onclick="this.closest(\'.item-card\').remove()">✕</button></div>' +
'<div class="form-row">' +
'<div class="form-group" style="min-width:120px"><label>Tipo</label><select name="flow_type[]" onchange="flowTypeChange(this)"><option value="text">Texto (respuesta fija)</option><option value="function">Función (acción especial)</option><option value="menu">Menú (submenú)</option></select></div>' +
'<div class="form-group flow-text"><label>Mensaje de respuesta</label><textarea name="flow_message[]" rows="2" placeholder="Texto que se enviará al usuario"></textarea></div>' +
'<div class="form-group flow-function" style="display:none"><label>Función</label><select name="flow_function[]"><option value="forward_to_ai">Escalar a IA</option><option value="forward_to_agent">Escalar a agente humano</option><option value="webhook">Llamar webhook externo</option></select></div>' +
'<div class="form-group flow-menu" style="display:none"><label>Menú a mostrar</label><input type="text" name="flow_menu[]" placeholder="ID del menú (ej: show_main)"></div>' +
'</div>';
container.appendChild(div);
}
function flowTypeChange(sel) {
const card = sel.closest('.item-card');
card.querySelector('.flow-text').style.display = sel.value === 'text' ? '' : 'none';
card.querySelector('.flow-function').style.display = sel.value === 'function' ? '' : 'none';
card.querySelector('.flow-menu').style.display = sel.value === 'menu' ? '' : 'none';
}
</script>
</body>
</html>
HTML;
exit;
}
}