feat: never-expire Telegram session + logout confirmation on both channels
- STATE_TTL: 7200s → 315360000s (10 years) so sessions survive indefinitely - Telegram: "salir"/"/salir" now shows inline confirmation keyboard instead of going straight to menu; "Cerrar sesión" button added to main menu; logout_ask/logout_confirm/confirmLogout() handler clears state and returns to email prompt - Web chat: "Cerrar sesión" button in main menu; clicking it shows a confirmation message with "Sí, cerrar sesión" / "No, quedarme" buttons; only the confirmed action calls cerrarSesion() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
80dd7ee9ca
commit
9a13bad235
Regular → Executable
+22
@@ -171,6 +171,25 @@ class PublicChat extends Component
|
|||||||
$this->paso = 'email';
|
$this->paso = 'email';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function confirmarCierreSesion(): void
|
||||||
|
{
|
||||||
|
if (! $this->convId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatMessage::create([
|
||||||
|
'conversation_id' => $this->convId,
|
||||||
|
'tipo' => 'bot',
|
||||||
|
'tipo_ui' => 'buttons',
|
||||||
|
'contenido' => '¿Seguro que deseas cerrar sesión? Tendrás que volver a ingresar tu correo y código la próxima vez.',
|
||||||
|
'payload' => ['botones' => [
|
||||||
|
['label' => '✅ Sí, cerrar sesión', 'action' => 'sesion.cerrar.confirmar', 'data' => []],
|
||||||
|
['label' => '❌ No, quedarme', 'action' => 'menu.principal', 'data' => []],
|
||||||
|
]],
|
||||||
|
'leido' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function cerrarSesion(): void
|
public function cerrarSesion(): void
|
||||||
{
|
{
|
||||||
session()->forget(['chat_user_id', 'chat_conv_id']);
|
session()->forget(['chat_user_id', 'chat_conv_id']);
|
||||||
@@ -407,6 +426,8 @@ class PublicChat extends Component
|
|||||||
$action === 'perfil.ver' => $this->verPerfil(),
|
$action === 'perfil.ver' => $this->verPerfil(),
|
||||||
$action === 'asesor.solicitar' => $this->solicitarAsesor(),
|
$action === 'asesor.solicitar' => $this->solicitarAsesor(),
|
||||||
$action === 'pago.aplicar' => $this->aplicarRecargaValidada($data),
|
$action === 'pago.aplicar' => $this->aplicarRecargaValidada($data),
|
||||||
|
$action === 'sesion.cerrar' => $this->confirmarCierreSesion(),
|
||||||
|
$action === 'sesion.cerrar.confirmar' => $this->cerrarSesion(),
|
||||||
default => $this->mostrarMenuPrincipal($this->convId),
|
default => $this->mostrarMenuPrincipal($this->convId),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -515,6 +536,7 @@ class PublicChat extends Component
|
|||||||
['label' => 'Historial', 'action' => 'historial.ver', 'data' => []],
|
['label' => 'Historial', 'action' => 'historial.ver', 'data' => []],
|
||||||
['label' => 'Mi Perfil', 'action' => 'perfil.ver', 'data' => []],
|
['label' => 'Mi Perfil', 'action' => 'perfil.ver', 'data' => []],
|
||||||
['label' => 'Hablar con asesor', 'action' => 'asesor.solicitar', 'data' => []],
|
['label' => 'Hablar con asesor', 'action' => 'asesor.solicitar', 'data' => []],
|
||||||
|
['label' => '🚪 Cerrar sesión', 'action' => 'sesion.cerrar', 'data' => []],
|
||||||
]],
|
]],
|
||||||
'leido' => true,
|
'leido' => true,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use Illuminate\Support\Str;
|
|||||||
|
|
||||||
class TelegramBotService
|
class TelegramBotService
|
||||||
{
|
{
|
||||||
private const STATE_TTL = 7200; // 2 hours
|
private const STATE_TTL = 315360000; // 10 years — session never expires automatically
|
||||||
|
|
||||||
private ?int $convId = null;
|
private ?int $convId = null;
|
||||||
|
|
||||||
@@ -63,10 +63,20 @@ class TelegramBotService
|
|||||||
|
|
||||||
$lower = strtolower(trim($text));
|
$lower = strtolower(trim($text));
|
||||||
|
|
||||||
|
// "salir" siempre pide confirmación de cierre de sesión
|
||||||
|
if (in_array($lower, ['salir', '/salir'])) {
|
||||||
|
if ($state['user_id'] ?? null) {
|
||||||
|
$this->showLogoutConfirmation($chatId);
|
||||||
|
} else {
|
||||||
|
$this->askEmail($chatId);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Palabras que siempre regresan al menú, desde cualquier punto del flujo
|
// Palabras que siempre regresan al menú, desde cualquier punto del flujo
|
||||||
$menuTriggers = [
|
$menuTriggers = [
|
||||||
'/start', '/menu', '/salir', '/inicio', '/cancelar',
|
'/start', '/menu', '/inicio', '/cancelar',
|
||||||
'menu', 'menú', 'inicio', 'hola', 'salir', 'volver',
|
'menu', 'menú', 'inicio', 'hola', 'volver',
|
||||||
'regresar', 'cancelar', 'empezar', 'comenzar', 'start',
|
'regresar', 'cancelar', 'empezar', 'comenzar', 'start',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -118,7 +128,9 @@ class TelegramBotService
|
|||||||
$action = $parts[0];
|
$action = $parts[0];
|
||||||
|
|
||||||
match ($action) {
|
match ($action) {
|
||||||
'menu' => $this->showMainMenu($chatId),
|
'menu' => $this->showMainMenu($chatId),
|
||||||
|
'logout_ask' => $this->showLogoutConfirmation($chatId),
|
||||||
|
'logout_confirm' => $this->confirmLogout($chatId),
|
||||||
'svc_list' => $this->listServices($chatId),
|
'svc_list' => $this->listServices($chatId),
|
||||||
'svc_view' => $this->viewService($chatId, (int) ($parts[1] ?? 0)),
|
'svc_view' => $this->viewService($chatId, (int) ($parts[1] ?? 0)),
|
||||||
'buy_start' => $this->startPurchase($chatId, (int) ($parts[1] ?? 0)),
|
'buy_start' => $this->startPurchase($chatId, (int) ($parts[1] ?? 0)),
|
||||||
@@ -497,6 +509,30 @@ class TelegramBotService
|
|||||||
|
|
||||||
// ─── Main menu ────────────────────────────────────────────
|
// ─── Main menu ────────────────────────────────────────────
|
||||||
|
|
||||||
|
private function showLogoutConfirmation(string $chatId): void
|
||||||
|
{
|
||||||
|
$this->sendWithKeyboard(
|
||||||
|
$chatId,
|
||||||
|
"⚠️ ¿Deseas cerrar sesión?\nDeberás volver a ingresar tu correo y código para continuar.",
|
||||||
|
[
|
||||||
|
[
|
||||||
|
['text' => '✅ Sí, cerrar sesión', 'callback_data' => 'logout_confirm'],
|
||||||
|
['text' => '❌ No, quedarme', 'callback_data' => 'menu'],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function confirmLogout(string $chatId): void
|
||||||
|
{
|
||||||
|
$state = $this->getState($chatId);
|
||||||
|
unset($state['user_id'], $state['conv_id'], $state['step'], $state['data']);
|
||||||
|
$state['step'] = 'await_email';
|
||||||
|
$this->setState($chatId, $state);
|
||||||
|
$this->send($chatId, "👋 Sesión cerrada. Hasta pronto.");
|
||||||
|
$this->askEmail($chatId);
|
||||||
|
}
|
||||||
|
|
||||||
private function showMainMenu(string $chatId): void
|
private function showMainMenu(string $chatId): void
|
||||||
{
|
{
|
||||||
$state = $this->getState($chatId);
|
$state = $this->getState($chatId);
|
||||||
@@ -520,6 +556,9 @@ class TelegramBotService
|
|||||||
[
|
[
|
||||||
['text' => '🧑 Hablar con asesor', 'callback_data' => 'agent'],
|
['text' => '🧑 Hablar con asesor', 'callback_data' => 'agent'],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
['text' => '🚪 Cerrar sesión', 'callback_data' => 'logout_ask'],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user