1211 lines
50 KiB
PHP
1211 lines
50 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Livewire\Chat;
|
|
|
|
use App\Mail\ChatOtpMail;
|
|
use App\Models\Cuentas;
|
|
use App\Models\ChatContact;
|
|
use App\Models\ChatConversation;
|
|
use App\Models\ChatMessage;
|
|
use App\Models\Historiale;
|
|
use App\Models\Historial_cuenta;
|
|
use App\Models\Promociones;
|
|
use App\Models\recarga;
|
|
use App\Models\Saldo;
|
|
use App\Models\Servicio;
|
|
use App\Models\Tarifas;
|
|
use App\Models\User;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Illuminate\Support\Str;
|
|
use Livewire\Component;
|
|
use Livewire\WithFileUploads;
|
|
|
|
class PublicChat extends Component
|
|
{
|
|
use WithFileUploads;
|
|
|
|
// ── Paso actual ───────────────────────────────────────────
|
|
public string $paso = 'email'; // email | verificacion | registro | chat
|
|
public string $email = '';
|
|
public string $nombreRegistro = '';
|
|
public string $cedulaRegistro = '';
|
|
public string $celularRegistro = '';
|
|
public string $codigoIngresado = '';
|
|
public ?string $emailMascarado = null;
|
|
public ?int $contactIdPending = null; // contact.id mientras espera verificacion
|
|
public string $input = '';
|
|
public array $mensajes = [];
|
|
public ?int $convId = null;
|
|
public string $estadoConv = 'bot';
|
|
|
|
// ── Usuario identificado ──────────────────────────────────
|
|
public ?int $userId = null;
|
|
public ?string $nombreUsuario = null;
|
|
public ?float $saldoUsuario = null;
|
|
|
|
// ── Estado del wizard ─────────────────────────────────────
|
|
public string $flujo = '';
|
|
public array $flujoData = [];
|
|
|
|
// ── Upload comprobante ────────────────────────────────────
|
|
public $fotoComprobante = null;
|
|
public bool $procesandoImagen = false;
|
|
|
|
protected $rules = [
|
|
'email' => 'required|email|max:100',
|
|
'nombreRegistro' => 'required|max:80',
|
|
'cedulaRegistro' => 'nullable|max:20',
|
|
'celularRegistro' => 'nullable|max:20',
|
|
'codigoIngresado' => 'nullable|digits:6',
|
|
];
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Paso 1: buscar por correo
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
public function iniciar(): void
|
|
{
|
|
$this->validate(['email' => 'required|email|max:100']);
|
|
|
|
$user = User::where('email', $this->email)->first();
|
|
|
|
if (! $user) {
|
|
$this->paso = 'registro';
|
|
return;
|
|
}
|
|
|
|
$contact = ChatContact::firstOrCreate(
|
|
['canal' => 'web', 'canal_id' => $user->email],
|
|
['nombre' => $user->name, 'telefono' => $user->email, 'user_id' => $user->id]
|
|
);
|
|
|
|
if (! $contact->user_id) {
|
|
$contact->update(['user_id' => $user->id]);
|
|
}
|
|
|
|
$this->contactIdPending = $contact->id;
|
|
$this->emailMascarado = $this->enmascararEmail($user->email);
|
|
$this->enviarCodigoOtp($contact->id, $user);
|
|
$this->paso = 'verificacion';
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Paso 2a: crear cuenta nueva
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
public function crearCuenta(): void
|
|
{
|
|
$this->validate([
|
|
'email' => 'required|email|max:100',
|
|
'nombreRegistro' => 'required|max:80',
|
|
'cedulaRegistro' => 'nullable|max:20',
|
|
'celularRegistro' => 'nullable|max:20',
|
|
]);
|
|
|
|
$user = User::create([
|
|
'name' => $this->nombreRegistro,
|
|
'email' => $this->email,
|
|
'password' => Hash::make(Str::random(16)),
|
|
'cedula' => $this->cedulaRegistro ?: null,
|
|
'celular' => $this->celularRegistro ?: null,
|
|
'estado' => 'activo',
|
|
]);
|
|
|
|
$contact = ChatContact::create([
|
|
'canal' => 'web',
|
|
'canal_id' => $user->email,
|
|
'nombre' => $user->name,
|
|
'telefono' => $user->email,
|
|
'user_id' => $user->id,
|
|
]);
|
|
|
|
$this->contactIdPending = $contact->id;
|
|
$this->emailMascarado = $this->enmascararEmail($user->email);
|
|
$this->enviarCodigoOtp($contact->id, $user);
|
|
$this->paso = 'verificacion';
|
|
}
|
|
|
|
public function rechazarRegistro(): void
|
|
{
|
|
$this->email = '';
|
|
$this->nombreRegistro = '';
|
|
$this->cedulaRegistro = '';
|
|
$this->celularRegistro = '';
|
|
$this->paso = 'email';
|
|
}
|
|
|
|
public function cerrarSesion(): void
|
|
{
|
|
$this->email = '';
|
|
$this->nombreRegistro = '';
|
|
$this->cedulaRegistro = '';
|
|
$this->celularRegistro = '';
|
|
$this->codigoIngresado = '';
|
|
$this->emailMascarado = null;
|
|
$this->contactIdPending = null;
|
|
$this->userId = null;
|
|
$this->nombreUsuario = null;
|
|
$this->saldoUsuario = null;
|
|
$this->convId = null;
|
|
$this->estadoConv = 'bot';
|
|
$this->flujo = '';
|
|
$this->flujoData = [];
|
|
$this->mensajes = [];
|
|
$this->input = '';
|
|
$this->paso = 'email';
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Paso 2b: verificar código OTP
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function enviarCodigoOtp(int $contactId, User $user): void
|
|
{
|
|
$codigo = (string) random_int(100000, 999999);
|
|
Cache::put("chat_otp_{$contactId}", $codigo, now()->addMinutes(10));
|
|
|
|
try {
|
|
Mail::to($user->email)->send(new ChatOtpMail($codigo, $user->name));
|
|
} catch (\Throwable $e) {
|
|
\Illuminate\Support\Facades\Log::warning('[ChatOTP] Error enviando correo: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function verificarCodigo(): void
|
|
{
|
|
$this->validate(['codigoIngresado' => 'required|digits:6']);
|
|
|
|
if (! $this->contactIdPending) {
|
|
$this->addError('codigoIngresado', 'Sesion expirada. Recarga la pagina.');
|
|
return;
|
|
}
|
|
|
|
$codigoGuardado = Cache::get("chat_otp_{$this->contactIdPending}");
|
|
|
|
if (! $codigoGuardado) {
|
|
$this->addError('codigoIngresado', 'El codigo expiro. Solicita uno nuevo.');
|
|
return;
|
|
}
|
|
|
|
if ($this->codigoIngresado !== $codigoGuardado) {
|
|
$this->addError('codigoIngresado', 'Codigo incorrecto. Intentalo de nuevo.');
|
|
return;
|
|
}
|
|
|
|
Cache::forget("chat_otp_{$this->contactIdPending}");
|
|
|
|
$contact = ChatContact::find($this->contactIdPending);
|
|
if (! $contact) {
|
|
$this->addError('codigoIngresado', 'Sesion invalida. Recarga la pagina.');
|
|
return;
|
|
}
|
|
|
|
$this->contactIdPending = null;
|
|
$this->codigoIngresado = '';
|
|
$this->abrirChat($contact);
|
|
}
|
|
|
|
public function reenviarCodigo(): void
|
|
{
|
|
if (! $this->contactIdPending) {
|
|
return;
|
|
}
|
|
|
|
$contact = ChatContact::find($this->contactIdPending);
|
|
if (! $contact || ! $contact->user_id) {
|
|
return;
|
|
}
|
|
|
|
$user = User::find($contact->user_id);
|
|
if ($user) {
|
|
$this->enviarCodigoOtp($this->contactIdPending, $user);
|
|
session()->flash('otp_reenviado', 'Codigo reenviado a tu correo.');
|
|
}
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Abrir chat (después de identificación)
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function abrirChat(ChatContact $contact): void
|
|
{
|
|
if ($contact->user_id) {
|
|
$user = User::with('saldo')->find($contact->user_id);
|
|
$this->userId = $user->id;
|
|
$this->nombreUsuario = $user->name;
|
|
$this->saldoUsuario = $user->saldo?->valor ?? 0;
|
|
}
|
|
|
|
$conv = $contact->activeConversation();
|
|
|
|
if (! $conv) {
|
|
$conv = ChatConversation::create([
|
|
'contact_id' => $contact->id,
|
|
'canal' => 'web',
|
|
'estado' => 'bot',
|
|
'ultimo_mensaje_at' => now(),
|
|
]);
|
|
$saludo = $this->nombreUsuario
|
|
? "¡Hola, {$this->nombreUsuario}! Bienvenido."
|
|
: "¡Hola! Bienvenido.";
|
|
$this->guardarMensajeBot($conv->id, $saludo);
|
|
}
|
|
|
|
$this->convId = $conv->id;
|
|
$this->estadoConv = $conv->estado;
|
|
$this->paso = 'chat';
|
|
$this->cargarMensajes();
|
|
$this->mostrarMenuPrincipal($conv->id);
|
|
}
|
|
|
|
private function enmascararEmail(string $email): string
|
|
{
|
|
[$local, $dominio] = explode('@', $email, 2);
|
|
$visible = mb_substr($local, 0, min(3, mb_strlen($local)));
|
|
return $visible . str_repeat('*', max(0, mb_strlen($local) - 3)) . '@' . $dominio;
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Envío de texto libre
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
public function enviar(): void
|
|
{
|
|
if (! $this->convId || trim($this->input) === '') {
|
|
return;
|
|
}
|
|
|
|
$texto = trim($this->input);
|
|
$this->input = '';
|
|
|
|
$this->guardarMensajeUsuario($this->convId, $texto);
|
|
|
|
$conv = ChatConversation::find($this->convId);
|
|
if (! $conv || $conv->estado === 'agente') {
|
|
$this->cargarMensajes();
|
|
return;
|
|
}
|
|
|
|
$accionIA = $this->detectarIntencionIA($texto);
|
|
|
|
if ($accionIA) {
|
|
$this->clickBoton($accionIA['action'], $accionIA['data'] ?? []);
|
|
} else {
|
|
$this->guardarMensajeBot($this->convId, "No entendi tu mensaje. Usa los botones o escribe lo que deseas:");
|
|
$this->mostrarMenuPrincipal($this->convId);
|
|
}
|
|
|
|
$this->cargarMensajes();
|
|
$this->dispatchBrowserEvent('scroll-chat');
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Clic en botón
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
public function clickBoton(string $action, array $data = []): void
|
|
{
|
|
if (! $this->convId) {
|
|
return;
|
|
}
|
|
|
|
match (true) {
|
|
$action === 'menu.principal' => $this->mostrarMenuPrincipal($this->convId),
|
|
$action === 'servicios.listar' => $this->listarServicios(),
|
|
$action === 'servicios.ver' => $this->verServicio((int) ($data['id'] ?? 0)),
|
|
$action === 'compra.iniciar' => $this->iniciarCompra((int) ($data['tarifa_id'] ?? 0)),
|
|
$action === 'compra.pagar.saldo' => $this->pagarConSaldo(),
|
|
$action === 'compra.pagar.mp' => $this->pagarConMP(),
|
|
$action === 'promo.listar' => $this->listarPromociones(),
|
|
$action === 'promo.ver' => $this->verPromocion((int) ($data['id'] ?? 0)),
|
|
$action === 'promo.comprar.saldo' => $this->comprarPromoConSaldo((int) ($data['id'] ?? 0)),
|
|
$action === 'promo.comprar.mp' => $this->comprarPromoConMP((int) ($data['id'] ?? 0)),
|
|
$action === 'recarga.iniciar' => $this->mostrarFormRecarga(),
|
|
$action === 'recarga.elegir_metodo' => $this->elegirMetodoRecarga((int) ($data['monto'] ?? 0)),
|
|
$action === 'recarga.mp' => $this->generarLinkRecargaMP((int) ($data['monto'] ?? 0)),
|
|
$action === 'recarga.transferencia' => $this->mostrarTransferencia((int) ($data['monto'] ?? 0)),
|
|
$action === 'credenciales.listar' => $this->listarCredenciales(),
|
|
$action === 'historial.ver' => $this->verHistorial(),
|
|
$action === 'perfil.ver' => $this->verPerfil(),
|
|
$action === 'asesor.solicitar' => $this->solicitarAsesor(),
|
|
$action === 'pago.aplicar' => $this->aplicarRecargaValidada($data),
|
|
default => $this->mostrarMenuPrincipal($this->convId),
|
|
};
|
|
|
|
$this->cargarMensajes();
|
|
$this->dispatchBrowserEvent('scroll-chat');
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Upload comprobante de pago
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
public function updatedFotoComprobante(): void
|
|
{
|
|
if (! $this->fotoComprobante || ! $this->convId) {
|
|
return;
|
|
}
|
|
|
|
if (\App\Models\ChatConfig::get('validacion_foto_habilitada', '0') !== '1') {
|
|
$this->guardarMensajeBot($this->convId, "El analisis de comprobantes no esta habilitado. Contacta a un asesor.");
|
|
$this->fotoComprobante = null;
|
|
$this->cargarMensajes();
|
|
return;
|
|
}
|
|
|
|
$this->procesandoImagen = true;
|
|
|
|
try {
|
|
$path = $this->fotoComprobante->store('comprobantes', 'public');
|
|
$url = asset('storage/' . $path);
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'usuario',
|
|
'tipo_ui' => 'imagen',
|
|
'contenido' => '[Comprobante de pago]',
|
|
'payload' => ['url' => $url],
|
|
'leido' => false,
|
|
]);
|
|
|
|
$base64 = base64_encode(file_get_contents($this->fotoComprobante->getRealPath()));
|
|
$mimeType = $this->fotoComprobante->getMimeType();
|
|
|
|
$datosPago = app(\App\Services\GeminiVisionService::class)->extraerPago($base64, $mimeType);
|
|
|
|
if (! $datosPago) {
|
|
$this->guardarMensajeBot($this->convId, "No pude leer el comprobante. Intenta con una foto mas clara.");
|
|
$this->cargarMensajes();
|
|
return;
|
|
}
|
|
|
|
$resultado = app(\App\Services\PagoValidadorService::class)->validar($datosPago);
|
|
|
|
$botones = [];
|
|
if ($resultado['estado'] === 'confirmado') {
|
|
$botones[] = [
|
|
'label' => 'Aplicar recarga de $' . number_format($datosPago['valor'] ?? 0),
|
|
'action' => 'pago.aplicar',
|
|
'data' => ['monto' => $datosPago['valor'], 'referencia' => $datosPago['referencia'] ?? null],
|
|
];
|
|
}
|
|
$botones[] = ['label' => 'Hablar con asesor', 'action' => 'asesor.solicitar', 'data' => []];
|
|
$botones[] = ['label' => '<- Menu', 'action' => 'menu.principal', 'data' => []];
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'validacion',
|
|
'contenido' => 'Resultado del analisis:',
|
|
'payload' => [
|
|
'estado' => $resultado['estado'],
|
|
'ia_datos' => $datosPago,
|
|
'botones' => $botones,
|
|
],
|
|
'leido' => true,
|
|
]);
|
|
|
|
} catch (\Throwable $e) {
|
|
$this->guardarMensajeBot($this->convId, "Error analizando el comprobante. Por favor intenta de nuevo.");
|
|
} finally {
|
|
$this->procesandoImagen = false;
|
|
$this->fotoComprobante = null;
|
|
$this->cargarMensajes();
|
|
$this->dispatchBrowserEvent('scroll-chat');
|
|
}
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Menu principal
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function mostrarMenuPrincipal(int $convId): void
|
|
{
|
|
$this->flujo = '';
|
|
$this->flujoData = [];
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'buttons',
|
|
'contenido' => 'En que te puedo ayudar?',
|
|
'payload' => ['botones' => [
|
|
['label' => 'Ver Servicios', 'action' => 'servicios.listar', 'data' => []],
|
|
['label' => 'Promociones', 'action' => 'promo.listar', 'data' => []],
|
|
['label' => 'Recargar Saldo', 'action' => 'recarga.iniciar', 'data' => []],
|
|
['label' => 'Mis Credenciales', 'action' => 'credenciales.listar', 'data' => []],
|
|
['label' => 'Historial', 'action' => 'historial.ver', 'data' => []],
|
|
['label' => 'Mi Perfil', 'action' => 'perfil.ver', 'data' => []],
|
|
['label' => 'Hablar con asesor', 'action' => 'asesor.solicitar', 'data' => []],
|
|
]],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Servicios
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function listarServicios(): void
|
|
{
|
|
$servicios = Servicio::where('estado', 'activo')->orderBy('ubicacion')->get();
|
|
|
|
if ($servicios->isEmpty()) {
|
|
$this->guardarMensajeBot($this->convId, "No hay servicios disponibles en este momento.");
|
|
$this->volver('menu.principal');
|
|
return;
|
|
}
|
|
|
|
$this->guardarMensajeBot($this->convId, "Selecciona el servicio:");
|
|
|
|
foreach ($servicios as $s) {
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'card',
|
|
'contenido' => '',
|
|
'payload' => [
|
|
'imagen' => $s->img_inicio,
|
|
'titulo' => $s->nombre,
|
|
'detalle' => $s->por_tiempo ? 'Por tiempo' : 'Por pantallas',
|
|
'accion' => ['label' => 'Ver planes', 'action' => 'servicios.ver', 'data' => ['id' => $s->id]],
|
|
],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
private function verServicio(int $id): void
|
|
{
|
|
$servicio = Servicio::with('tarifas')->find($id);
|
|
if (! $servicio) {
|
|
$this->guardarMensajeBot($this->convId, "Servicio no encontrado.");
|
|
return;
|
|
}
|
|
|
|
$tarifas = $servicio->tarifas->where('estado', 'activo');
|
|
|
|
if ($tarifas->isEmpty()) {
|
|
$this->guardarMensajeBot($this->convId, "No hay planes para {$servicio->nombre} en este momento.");
|
|
$this->volver('servicios.listar');
|
|
return;
|
|
}
|
|
|
|
$botones = [];
|
|
foreach ($tarifas as $t) {
|
|
$label = $servicio->por_tiempo
|
|
? "{$t->dias} dias - $" . number_format($t->valor)
|
|
: "{$t->pantallas} pantalla(s) / {$t->dias} dias - $" . number_format($t->valor);
|
|
$botones[] = ['label' => $label, 'action' => 'compra.iniciar', 'data' => ['tarifa_id' => $t->id]];
|
|
}
|
|
$botones[] = ['label' => 'Volver', 'action' => 'servicios.listar', 'data' => []];
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'buttons',
|
|
'contenido' => "Planes de {$servicio->nombre}:",
|
|
'payload' => ['botones' => $botones],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Compra de plan
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function iniciarCompra(int $tarifaId): void
|
|
{
|
|
$tarifa = Tarifas::with('servicio')->find($tarifaId);
|
|
if (! $tarifa) {
|
|
$this->guardarMensajeBot($this->convId, "Plan no encontrado.");
|
|
return;
|
|
}
|
|
|
|
$disponibles = Cuentas::where('tarifa_id', $tarifaId)->where('estado', 'activo')->count();
|
|
if ($disponibles < 1) {
|
|
$this->guardarMensajeBot($this->convId, "Sin cuentas disponibles para este plan. Intenta con otro.");
|
|
$this->volver('servicios.listar');
|
|
return;
|
|
}
|
|
|
|
$this->flujo = 'compra';
|
|
$this->flujoData = [
|
|
'tarifa_id' => $tarifaId,
|
|
'valor' => $tarifa->valor,
|
|
'servicio' => $tarifa->servicio->nombre,
|
|
'dias' => $tarifa->dias,
|
|
'pantallas' => $tarifa->pantallas,
|
|
];
|
|
|
|
$detalle = $tarifa->servicio->por_tiempo
|
|
? "{$tarifa->dias} dias"
|
|
: "{$tarifa->pantallas} pantalla(s) / {$tarifa->dias} dias";
|
|
$saldoInsuficiente = ! $this->userId || ($this->saldoUsuario < $tarifa->valor);
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'buttons',
|
|
'contenido' => "{$tarifa->servicio->nombre} - {$detalle}\nPrecio: $" . number_format($tarifa->valor) . "\n\nElige como pagar:",
|
|
'payload' => ['botones' => [
|
|
['label' => 'Saldo ($' . number_format($tarifa->valor) . ')',
|
|
'action' => 'compra.pagar.saldo',
|
|
'data' => [],
|
|
'disabled' => $saldoInsuficiente],
|
|
['label' => 'MercadoPago', 'action' => 'compra.pagar.mp', 'data' => []],
|
|
['label' => 'Volver', 'action' => 'servicios.listar', 'data' => []],
|
|
]],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
private function pagarConSaldo(): void
|
|
{
|
|
if (! $this->userId || $this->flujo !== 'compra') {
|
|
$this->guardarMensajeBot($this->convId, "Debes estar identificado para pagar con saldo.");
|
|
return;
|
|
}
|
|
|
|
$tarifa = Tarifas::with('servicio')->find($this->flujoData['tarifa_id'] ?? 0);
|
|
if (! $tarifa) {
|
|
$this->guardarMensajeBot($this->convId, "Ocurrio un error. Intenta de nuevo.");
|
|
return;
|
|
}
|
|
|
|
$user = User::with('saldo')->find($this->userId);
|
|
$saldo = $user->saldo;
|
|
|
|
if (! $saldo || $saldo->valor < $tarifa->valor) {
|
|
$this->guardarMensajeBot(
|
|
$this->convId,
|
|
"Saldo insuficiente. Tienes $" . number_format($saldo?->valor ?? 0) .
|
|
" y el plan cuesta $" . number_format($tarifa->valor) . "."
|
|
);
|
|
$this->volver('menu.principal');
|
|
return;
|
|
}
|
|
|
|
$cuenta = Cuentas::where('tarifa_id', $tarifa->id)->where('estado', 'activo')->first();
|
|
if (! $cuenta) {
|
|
$this->guardarMensajeBot($this->convId, "No hay cuentas disponibles en este momento.");
|
|
return;
|
|
}
|
|
|
|
$historial = Historiale::create([
|
|
'fecha_inicio' => now(),
|
|
'fecha_final' => now()->addDays($tarifa->dias),
|
|
'valor' => $tarifa->valor,
|
|
'utilidad' => $tarifa->utilidad ?? 0,
|
|
'tipo_pago' => 'saldo',
|
|
'estado' => 'entregado',
|
|
'vendedor_id' => $this->userId,
|
|
'tarifa_id' => $tarifa->id,
|
|
'cliente_id' => $this->userId,
|
|
'nombre_cliente' => $user->name,
|
|
]);
|
|
|
|
Historial_cuenta::create(['historial_id' => $historial->id, 'cuenta_id' => $cuenta->id]);
|
|
$cuenta->update(['estado' => 'ocupado']);
|
|
$saldo->update(['valor' => $saldo->valor - $tarifa->valor]);
|
|
$this->saldoUsuario = $saldo->valor - $tarifa->valor;
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'credenciales',
|
|
'contenido' => 'Compra exitosa! Tus credenciales:',
|
|
'payload' => [
|
|
'servicio' => $tarifa->servicio->nombre,
|
|
'email' => $cuenta->correo,
|
|
'password' => $cuenta->password,
|
|
'perfil' => $tarifa->pantallas ?? null,
|
|
'vence' => now()->addDays($tarifa->dias)->format('d/m/Y'),
|
|
],
|
|
'leido' => true,
|
|
]);
|
|
|
|
$this->flujo = '';
|
|
$this->flujoData = [];
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
private function pagarConMP(): void
|
|
{
|
|
if ($this->flujo !== 'compra') {
|
|
return;
|
|
}
|
|
|
|
$valor = (int) ($this->flujoData['valor'] ?? 0);
|
|
$servicio = $this->flujoData['servicio'] ?? 'Plan streaming';
|
|
$ref = 'CHAT-' . strtoupper(Str::random(12));
|
|
$url = $this->crearPreferenciaMP($servicio, $valor, $ref);
|
|
|
|
if (! $url) {
|
|
$this->guardarMensajeBot($this->convId, "No se pudo generar el link de pago. Intenta de nuevo o contacta a un asesor.");
|
|
return;
|
|
}
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'link',
|
|
'contenido' => "Link de pago por $" . number_format($valor) . " listo. Despues de pagar, envia el comprobante aqui.",
|
|
'payload' => ['url' => $url, 'label' => 'Pagar $' . number_format($valor) . ' con MercadoPago', 'nota' => 'Ref: ' . $ref],
|
|
'leido' => true,
|
|
]);
|
|
|
|
$this->flujo = '';
|
|
$this->flujoData = [];
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Promociones
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function listarPromociones(): void
|
|
{
|
|
$promos = Promociones::where('visible', true)
|
|
->where(fn($q) => $q->whereNull('fecha_limite')->orWhere('fecha_limite', '>=', now()))
|
|
->get();
|
|
|
|
if ($promos->isEmpty()) {
|
|
$this->guardarMensajeBot($this->convId, "No hay promociones activas en este momento.");
|
|
$this->volver('menu.principal');
|
|
return;
|
|
}
|
|
|
|
$this->guardarMensajeBot($this->convId, "Promociones disponibles:");
|
|
|
|
foreach ($promos as $p) {
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'card',
|
|
'contenido' => '',
|
|
'payload' => [
|
|
'imagen' => $p->img_publicidad,
|
|
'titulo' => $p->nombre ?? 'Promocion especial',
|
|
'descripcion' => $p->descripcion ?? null,
|
|
'precio' => $p->precio,
|
|
'detalle' => $p->fecha_limite ? 'Hasta ' . Carbon::parse($p->fecha_limite)->format('d/m/Y') : null,
|
|
'accion' => ['label' => 'Comprar', 'action' => 'promo.ver', 'data' => ['id' => $p->id]],
|
|
],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
private function verPromocion(int $id): void
|
|
{
|
|
$promo = Promociones::find($id);
|
|
if (! $promo) {
|
|
$this->guardarMensajeBot($this->convId, "Promocion no encontrada.");
|
|
return;
|
|
}
|
|
|
|
$saldoInsuficiente = ! $this->userId || ($this->saldoUsuario < $promo->precio);
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'buttons',
|
|
'contenido' => ($promo->nombre ?? 'Promocion') . "\n$" . number_format($promo->precio) . "\n\nElige como pagar:",
|
|
'payload' => ['botones' => [
|
|
['label' => 'Saldo ($' . number_format($promo->precio) . ')',
|
|
'action' => 'promo.comprar.saldo',
|
|
'data' => ['id' => $id],
|
|
'disabled' => $saldoInsuficiente],
|
|
['label' => 'MercadoPago', 'action' => 'promo.comprar.mp', 'data' => ['id' => $id]],
|
|
['label' => 'Volver', 'action' => 'promo.listar', 'data' => []],
|
|
]],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
private function comprarPromoConSaldo(int $promoId): void
|
|
{
|
|
$promo = Promociones::find($promoId);
|
|
if (! $promo || ! $this->userId) {
|
|
$this->guardarMensajeBot($this->convId, "No se pudo procesar la compra.");
|
|
return;
|
|
}
|
|
|
|
$user = User::with('saldo')->find($this->userId);
|
|
$saldo = $user->saldo;
|
|
|
|
if (! $saldo || $saldo->valor < $promo->precio) {
|
|
$this->guardarMensajeBot($this->convId, "Saldo insuficiente ($" . number_format($saldo?->valor ?? 0) . "). La promo cuesta $" . number_format($promo->precio) . ".");
|
|
return;
|
|
}
|
|
|
|
$cuenta = Cuentas::where('promocion_id', $promoId)->where('estado', 'activo')->first();
|
|
if (! $cuenta) {
|
|
$this->guardarMensajeBot($this->convId, "No hay cuentas disponibles para esta promocion.");
|
|
return;
|
|
}
|
|
|
|
$historial = Historiale::create([
|
|
'fecha_inicio' => now(),
|
|
'fecha_final' => now()->addDays(30),
|
|
'valor' => $promo->precio,
|
|
'utilidad' => $promo->utilidad ?? 0,
|
|
'tipo_pago' => 'saldo',
|
|
'estado' => 'entregado',
|
|
'vendedor_id' => $this->userId,
|
|
'promocion_id' => $promoId,
|
|
'cliente_id' => $this->userId,
|
|
'nombre_cliente' => $user->name,
|
|
]);
|
|
|
|
Historial_cuenta::create(['historial_id' => $historial->id, 'cuenta_id' => $cuenta->id]);
|
|
$cuenta->update(['estado' => 'ocupado']);
|
|
$saldo->update(['valor' => $saldo->valor - $promo->precio]);
|
|
$this->saldoUsuario = $saldo->valor - $promo->precio;
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'credenciales',
|
|
'contenido' => 'Promo activada! Tus credenciales:',
|
|
'payload' => [
|
|
'servicio' => $promo->nombre ?? 'Promocion',
|
|
'email' => $cuenta->correo,
|
|
'password' => $cuenta->password,
|
|
'vence' => now()->addDays(30)->format('d/m/Y'),
|
|
],
|
|
'leido' => true,
|
|
]);
|
|
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
private function comprarPromoConMP(int $promoId): void
|
|
{
|
|
$promo = Promociones::find($promoId);
|
|
if (! $promo) {
|
|
return;
|
|
}
|
|
|
|
$ref = 'PROMO-' . strtoupper(Str::random(10));
|
|
$url = $this->crearPreferenciaMP($promo->nombre ?? 'Promocion streaming', (int) $promo->precio, $ref);
|
|
|
|
if (! $url) {
|
|
$this->guardarMensajeBot($this->convId, "No se pudo generar el link de pago. Intenta de nuevo o contacta a un asesor.");
|
|
return;
|
|
}
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'link',
|
|
'contenido' => "Link de pago por $" . number_format($promo->precio) . ". Envia el comprobante aqui al pagar.",
|
|
'payload' => ['url' => $url, 'label' => 'Pagar con MercadoPago', 'nota' => 'Ref: ' . $ref],
|
|
'leido' => true,
|
|
]);
|
|
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Recarga de saldo
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function mostrarFormRecarga(): void
|
|
{
|
|
$botones = [];
|
|
foreach ([20000, 50000, 100000, 200000, 500000] as $m) {
|
|
$botones[] = ['label' => '$' . number_format($m), 'action' => 'recarga.elegir_metodo', 'data' => ['monto' => $m]];
|
|
}
|
|
$botones[] = ['label' => 'Volver', 'action' => 'menu.principal', 'data' => []];
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'buttons',
|
|
'contenido' => "Selecciona el monto a recargar:",
|
|
'payload' => ['botones' => $botones],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
private function elegirMetodoRecarga(int $monto): void
|
|
{
|
|
if ($monto <= 0) {
|
|
return;
|
|
}
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'buttons',
|
|
'contenido' => "Recarga de $" . number_format($monto) . "\n¿Como quieres pagar?",
|
|
'payload' => ['botones' => [
|
|
['label' => 'MercadoPago', 'action' => 'recarga.mp', 'data' => ['monto' => $monto]],
|
|
['label' => 'Bre-B', 'action' => 'recarga.transferencia', 'data' => ['monto' => $monto]],
|
|
['label' => 'Volver', 'action' => 'recarga.iniciar', 'data' => []],
|
|
]],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
private function mostrarTransferencia(int $monto): void
|
|
{
|
|
if ($monto <= 0) {
|
|
return;
|
|
}
|
|
|
|
$banco = \App\Models\ChatConfig::get('recarga_banco_nombre', '');
|
|
$clave = \App\Models\ChatConfig::get('recarga_banco_llave', '');
|
|
$titular = \App\Models\ChatConfig::get('recarga_banco_titular', '');
|
|
|
|
if (! $clave) {
|
|
$this->guardarMensajeBot($this->convId, "El pago por Bre-B no esta disponible en este momento. Usa MercadoPago o contacta a un asesor.");
|
|
return;
|
|
}
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'banco',
|
|
'contenido' => 'Datos para transferencia:',
|
|
'payload' => [
|
|
'banco' => $banco,
|
|
'clave' => $clave,
|
|
'titular' => $titular,
|
|
'monto' => $monto,
|
|
],
|
|
'leido' => true,
|
|
]);
|
|
|
|
$this->guardarMensajeBot($this->convId, "Cuando hayas transferido, envia el comprobante usando el icono de camara (📷) y el sistema lo validara automaticamente.");
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
private function generarLinkRecargaMP(int $monto): void
|
|
{
|
|
if ($monto <= 0) {
|
|
$this->guardarMensajeBot($this->convId, "Monto invalido.");
|
|
return;
|
|
}
|
|
|
|
$ref = 'REC-' . strtoupper(Str::random(12));
|
|
$url = $this->crearPreferenciaMP('Recarga de saldo', $monto, $ref);
|
|
|
|
if (! $url) {
|
|
$this->guardarMensajeBot($this->convId, "No se pudo generar el link de recarga. Intenta de nuevo o contacta a un asesor.");
|
|
return;
|
|
}
|
|
|
|
if ($this->userId) {
|
|
$user = User::with('saldo')->find($this->userId);
|
|
$saldo = $user->saldo ?? Saldo::create(['usuario_id' => $this->userId, 'valor' => 0]);
|
|
recarga::create([
|
|
'monto' => $monto,
|
|
'reference' => $ref,
|
|
'status' => 'pendiente_mp',
|
|
'usuario_id' => $this->userId,
|
|
'saldo_id' => $saldo->id,
|
|
]);
|
|
}
|
|
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'link',
|
|
'contenido' => "Tu link de recarga por $" . number_format($monto) . " esta listo. Despues de pagar, envia el comprobante aqui.",
|
|
'payload' => ['url' => $url, 'label' => 'Recargar $' . number_format($monto) . ' con MercadoPago', 'nota' => 'Ref: ' . $ref],
|
|
'leido' => true,
|
|
]);
|
|
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
private function crearPreferenciaMP(string $titulo, int $valor, string $ref): ?string
|
|
{
|
|
$accessToken = config('services.mercadopago.token');
|
|
|
|
if (! $accessToken) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
$response = \Illuminate\Support\Facades\Http::withToken($accessToken)
|
|
->timeout(10)
|
|
->post('https://api.mercadopago.com/checkout/preferences', [
|
|
'items' => [[
|
|
'title' => $titulo,
|
|
'quantity' => 1,
|
|
'unit_price' => $valor,
|
|
'currency_id' => 'COP',
|
|
]],
|
|
'external_reference' => $ref,
|
|
'back_urls' => [
|
|
'success' => url('/chat'),
|
|
'failure' => url('/chat'),
|
|
'pending' => url('/chat'),
|
|
],
|
|
'auto_return' => 'approved',
|
|
'payment_methods' => [
|
|
'excluded_payment_types' => [['id' => 'ticket']],
|
|
],
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
return $response->json('init_point');
|
|
}
|
|
|
|
\Illuminate\Support\Facades\Log::warning('[ChatMP] Error creando preferencia: ' . $response->body());
|
|
return null;
|
|
|
|
} catch (\Throwable $e) {
|
|
\Illuminate\Support\Facades\Log::warning('[ChatMP] Excepcion: ' . $e->getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Credenciales
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function listarCredenciales(): void
|
|
{
|
|
if (! $this->userId) {
|
|
$this->guardarMensajeBot($this->convId, "No encontre tu cuenta. Contacta a un asesor para ver tus credenciales.");
|
|
$this->volver('menu.principal');
|
|
return;
|
|
}
|
|
|
|
$historiales = Historiale::where('cliente_id', $this->userId)
|
|
->where('estado', 'entregado')
|
|
->where('fecha_final', '>=', now())
|
|
->with('tarifa.servicio')
|
|
->orderBy('fecha_final', 'desc')
|
|
->limit(10)
|
|
->get();
|
|
|
|
if ($historiales->isEmpty()) {
|
|
$this->guardarMensajeBot($this->convId, "No tienes planes activos en este momento.");
|
|
$this->volver('menu.principal');
|
|
return;
|
|
}
|
|
|
|
$this->guardarMensajeBot($this->convId, "Tus planes activos:");
|
|
|
|
foreach ($historiales as $h) {
|
|
foreach ($h->cuentas as $c) {
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'credenciales',
|
|
'contenido' => '',
|
|
'payload' => [
|
|
'servicio' => $h->tarifa?->servicio?->nombre ?? 'Servicio',
|
|
'email' => $c->correo,
|
|
'password' => $c->password,
|
|
'perfil' => $h->tarifa?->pantallas ?? null,
|
|
'vence' => Carbon::parse($h->fecha_final)->format('d/m/Y'),
|
|
],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
}
|
|
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Historial
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function verHistorial(): void
|
|
{
|
|
if (! $this->userId) {
|
|
$this->guardarMensajeBot($this->convId, "Inicia sesion para ver tu historial.");
|
|
$this->volver('menu.principal');
|
|
return;
|
|
}
|
|
|
|
$historiales = Historiale::where('cliente_id', $this->userId)
|
|
->with('tarifa.servicio')
|
|
->orderBy('created_at', 'desc')
|
|
->limit(10)
|
|
->get();
|
|
|
|
if ($historiales->isEmpty()) {
|
|
$this->guardarMensajeBot($this->convId, "No tienes compras registradas.");
|
|
$this->volver('menu.principal');
|
|
return;
|
|
}
|
|
|
|
$lineas = ["Tus ultimas compras:\n"];
|
|
foreach ($historiales as $h) {
|
|
$activo = Carbon::parse($h->fecha_final)->gte(now()) ? '[activo]' : '[vencido]';
|
|
$nombre = $h->tarifa?->servicio?->nombre ?? ($h->promocion_id ? 'Promo' : 'Plan');
|
|
$fecha = Carbon::parse($h->created_at)->format('d/m/Y');
|
|
$lineas[] = "{$activo} {$nombre} - $" . number_format($h->valor) . " ({$fecha})";
|
|
}
|
|
|
|
$this->guardarMensajeBot($this->convId, implode("\n", $lineas));
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Perfil
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function verPerfil(): void
|
|
{
|
|
if (! $this->userId) {
|
|
$this->guardarMensajeBot($this->convId, "No encontre tu cuenta. Contacta a un asesor.");
|
|
$this->volver('menu.principal');
|
|
return;
|
|
}
|
|
|
|
$user = User::with('saldo')->find($this->userId);
|
|
|
|
$this->guardarMensajeBot(
|
|
$this->convId,
|
|
"Tu perfil\nNombre: {$user->name}\nEmail: {$user->email}\nSaldo: $" . number_format($user->saldo?->valor ?? 0)
|
|
);
|
|
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Asesor
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function solicitarAsesor(): void
|
|
{
|
|
$conv = ChatConversation::find($this->convId);
|
|
if ($conv) {
|
|
$conv->update(['estado' => 'agente']);
|
|
$this->estadoConv = 'agente';
|
|
}
|
|
$this->guardarMensajeBot($this->convId, "Un asesor se comunicara contigo en breve. Por favor espera.");
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Aplicar recarga validada por IA
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function aplicarRecargaValidada(array $data): void
|
|
{
|
|
if (! $this->userId) {
|
|
$this->guardarMensajeBot($this->convId, "No puedo aplicar la recarga: no estas identificado.");
|
|
return;
|
|
}
|
|
|
|
$monto = (int) ($data['monto'] ?? 0);
|
|
if ($monto <= 0) {
|
|
$this->guardarMensajeBot($this->convId, "Monto invalido.");
|
|
return;
|
|
}
|
|
|
|
$user = User::with('saldo')->find($this->userId);
|
|
$saldo = $user->saldo ?? Saldo::create(['usuario_id' => $this->userId, 'valor' => 0]);
|
|
$nuevoSaldo = $saldo->valor + $monto;
|
|
$saldo->update(['valor' => $nuevoSaldo]);
|
|
$this->saldoUsuario = $nuevoSaldo;
|
|
|
|
$this->guardarMensajeBot(
|
|
$this->convId,
|
|
"Recarga de $" . number_format($monto) . " aplicada. Tu nuevo saldo: $" . number_format($nuevoSaldo) . "."
|
|
);
|
|
|
|
$this->volver('menu.principal');
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// IA: detectar intencion
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function detectarIntencionIA(string $texto): ?array
|
|
{
|
|
try {
|
|
return app(\App\Services\GeminiIntentService::class)->detectar($texto);
|
|
} catch (\Throwable) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Cargar mensajes
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
public function cargarMensajes(): void
|
|
{
|
|
if (! $this->convId) {
|
|
return;
|
|
}
|
|
|
|
$this->mensajes = ChatMessage::where('conversation_id', $this->convId)
|
|
->orderBy('id')
|
|
->get()
|
|
->map(fn($m) => [
|
|
'tipo' => $m->tipo,
|
|
'tipo_ui' => $m->tipo_ui ?? 'text',
|
|
'contenido' => $m->contenido,
|
|
'payload' => $m->payload ?? [],
|
|
'created_at' => $m->created_at->format('H:i'),
|
|
])
|
|
->toArray();
|
|
|
|
$this->dispatchBrowserEvent('scroll-chat');
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
// Helpers
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
private function guardarMensajeBot(int $convId, string $contenido): void
|
|
{
|
|
ChatMessage::create([
|
|
'conversation_id' => $convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'text',
|
|
'contenido' => $contenido,
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
private function guardarMensajeUsuario(int $convId, string $contenido): void
|
|
{
|
|
ChatMessage::create([
|
|
'conversation_id' => $convId,
|
|
'tipo' => 'usuario',
|
|
'tipo_ui' => 'text',
|
|
'contenido' => $contenido,
|
|
'leido' => false,
|
|
]);
|
|
}
|
|
|
|
private function volver(string $action): void
|
|
{
|
|
ChatMessage::create([
|
|
'conversation_id' => $this->convId,
|
|
'tipo' => 'bot',
|
|
'tipo_ui' => 'buttons',
|
|
'contenido' => '',
|
|
'payload' => ['botones' => [
|
|
['label' => 'Menu principal', 'action' => $action, 'data' => []],
|
|
]],
|
|
'leido' => true,
|
|
]);
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.chat.public-chat');
|
|
}
|
|
}
|