feat(chat): recarga con transferencia bancaria, fix OTP y mejoras UI
- Fix: autocomplete="off" en campo OTP (evita que el correo aparezca ahí) - Recarga: nuevo paso elegir método (MercadoPago o Transferencia bancaria) - Transferencia: muestra card con banco/clave/titular/monto y aviso de comprobante - Validación automática al enviar foto del comprobante (flujo existente) - Config admin: nuevos campos banco/clave/titular para transferencia - UI: card de banco con estilo diferenciado (azul), aviso destacado en ámbar Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
9d0940873d
commit
9b76f63aa0
@@ -324,7 +324,9 @@ class PublicChat extends Component
|
||||
$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(),
|
||||
@@ -821,7 +823,7 @@ class PublicChat extends Component
|
||||
{
|
||||
$botones = [];
|
||||
foreach ([20000, 50000, 100000, 200000, 500000] as $m) {
|
||||
$botones[] = ['label' => '$' . number_format($m), 'action' => 'recarga.mp', 'data' => ['monto' => $m]];
|
||||
$botones[] = ['label' => '$' . number_format($m), 'action' => 'recarga.elegir_metodo', 'data' => ['monto' => $m]];
|
||||
}
|
||||
$botones[] = ['label' => 'Volver', 'action' => 'menu.principal', 'data' => []];
|
||||
|
||||
@@ -835,6 +837,59 @@ class PublicChat extends Component
|
||||
]);
|
||||
}
|
||||
|
||||
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' => 'Transferencia bancaria', '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_clave', '');
|
||||
$titular = \App\Models\ChatConfig::get('recarga_banco_titular', '');
|
||||
|
||||
if (! $clave) {
|
||||
$this->guardarMensajeBot($this->convId, "La transferencia bancaria 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) {
|
||||
|
||||
@@ -22,22 +22,28 @@ class ShowConfiguracionChat extends Component
|
||||
public string $gemini_prompt_extra = '';
|
||||
|
||||
// ── Validación de pago por foto + correo ──────────────────
|
||||
public string $validacion_foto_habilitada = '0';
|
||||
public string $validacion_accion_auto = 'solo_notificar'; // recargar_saldo | solo_notificar
|
||||
public string $validacion_foto_habilitada = '0';
|
||||
public string $validacion_accion_auto = 'solo_notificar';
|
||||
public string $validacion_monto_tolerancia = '0';
|
||||
|
||||
// ── Transferencia bancaria ─────────────────────────────────
|
||||
public string $recarga_banco_nombre = '';
|
||||
public string $recarga_banco_clave = '';
|
||||
public string $recarga_banco_titular = '';
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$keys = [
|
||||
'telegram_token', 'mensaje_bienvenida', 'mensaje_transferencia',
|
||||
'gemini_api_key', 'gemini_habilitado', 'gemini_prompt_extra',
|
||||
'validacion_foto_habilitada', 'validacion_accion_auto', 'validacion_monto_tolerancia',
|
||||
'recarga_banco_nombre', 'recarga_banco_clave', 'recarga_banco_titular',
|
||||
];
|
||||
|
||||
$defaults = [
|
||||
'mensaje_bienvenida' => 'Hola! Bienvenido. Escribe tu consulta.',
|
||||
'mensaje_transferencia' => 'Un agente se comunicara contigo en breve. Por favor espera.',
|
||||
'validacion_accion_auto' => 'solo_notificar',
|
||||
'mensaje_bienvenida' => 'Hola! Bienvenido. Escribe tu consulta.',
|
||||
'mensaje_transferencia' => 'Un agente se comunicara contigo en breve. Por favor espera.',
|
||||
'validacion_accion_auto' => 'solo_notificar',
|
||||
'validacion_monto_tolerancia' => '0',
|
||||
];
|
||||
|
||||
@@ -52,12 +58,16 @@ class ShowConfiguracionChat extends Component
|
||||
'mensaje_bienvenida' => 'required|string|max:500',
|
||||
'mensaje_transferencia' => 'required|string|max:500',
|
||||
'validacion_monto_tolerancia' => 'nullable|integer|min:0',
|
||||
'recarga_banco_nombre' => 'nullable|max:60',
|
||||
'recarga_banco_clave' => 'nullable|max:60',
|
||||
'recarga_banco_titular' => 'nullable|max:100',
|
||||
]);
|
||||
|
||||
$keys = [
|
||||
'telegram_token', 'mensaje_bienvenida', 'mensaje_transferencia',
|
||||
'gemini_api_key', 'gemini_habilitado', 'gemini_prompt_extra',
|
||||
'validacion_foto_habilitada', 'validacion_accion_auto', 'validacion_monto_tolerancia',
|
||||
'recarga_banco_nombre', 'recarga_banco_clave', 'recarga_banco_titular',
|
||||
];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
<div>
|
||||
<label class="block text-[#8696a0] text-xs font-medium mb-1.5 uppercase tracking-wider">Código de verificación</label>
|
||||
<input wire:model.defer="codigoIngresado" type="text" inputmode="numeric"
|
||||
pattern="[0-9]*" maxlength="6" autocomplete="one-time-code"
|
||||
pattern="[0-9]*" maxlength="6" autocomplete="off"
|
||||
placeholder="000000"
|
||||
class="w-full bg-[#2a3942] text-white rounded-xl px-4 py-3.5 outline-none border border-transparent focus:border-[#00a884] transition placeholder-[#8696a0] text-center text-2xl font-bold tracking-[0.5em]"
|
||||
style="color-scheme: dark;">
|
||||
@@ -390,6 +390,51 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- BANCO: datos de transferencia bancaria --}}
|
||||
@elseif ($tipoUi === 'banco')
|
||||
<div class="max-w-[85%] bg-[#202c33] rounded-xl rounded-tl-sm shadow overflow-hidden">
|
||||
<div class="px-4 py-2.5 bg-blue-900/40 flex items-center gap-2">
|
||||
<svg class="w-4 h-4 text-blue-400 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21v-8.25M15.75 21v-8.25M8.25 21v-8.25M3 9l9-6 9 6m-1.5 12V10.332A48.36 48.36 0 0 0 12 9.75c-2.551 0-5.056.2-7.5.582V21M3 21h18M12 6.75h.008v.008H12V6.75Z" />
|
||||
</svg>
|
||||
<p class="text-blue-300 text-xs font-semibold uppercase tracking-wider">Transferencia bancaria</p>
|
||||
</div>
|
||||
<div class="px-4 py-3 space-y-3">
|
||||
@if (!empty($payload['banco']))
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[#8696a0] text-xs">Banco / Billetera</span>
|
||||
<span class="text-white text-sm font-semibold">{{ $payload['banco'] }}</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="bg-[#0b141a] rounded-xl px-4 py-3 text-center">
|
||||
<p class="text-[#8696a0] text-[11px] mb-1">Número / Clave</p>
|
||||
<p class="text-[#00a884] text-xl font-bold font-mono tracking-widest">{{ $payload['clave'] ?? '' }}</p>
|
||||
</div>
|
||||
@if (!empty($payload['titular']))
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[#8696a0] text-xs">Titular</span>
|
||||
<span class="text-white text-sm">{{ $payload['titular'] }}</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex justify-between items-center border-t border-white/10 pt-2">
|
||||
<span class="text-[#8696a0] text-xs">Monto exacto</span>
|
||||
<span class="text-white text-base font-bold">${{ number_format($payload['monto'] ?? 0) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-4 pb-3">
|
||||
<div class="bg-amber-900/20 border border-amber-700/30 rounded-lg px-3 py-2 flex items-start gap-2">
|
||||
<svg class="w-4 h-4 text-amber-400 flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6.827 6.175A2.31 2.31 0 0 1 5.186 7.23c-.38.054-.757.112-1.134.175C2.999 7.58 2.25 8.507 2.25 9.574V18a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9.574c0-1.067-.75-1.994-1.802-2.169a47.865 47.865 0 0 0-1.134-.175 2.31 2.31 0 0 1-1.64-1.055l-.822-1.316a2.192 2.192 0 0 0-1.736-1.039 48.774 48.774 0 0 0-5.232 0 2.192 2.192 0 0 0-1.736 1.039l-.821 1.316Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 12.75a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0ZM18.75 10.5h.008v.008h-.008V10.5Z" />
|
||||
</svg>
|
||||
<p class="text-amber-300 text-xs">Envía el comprobante con el ícono 📷 de abajo y el sistema lo validará automáticamente</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-4 pb-2 text-right">
|
||||
<span class="text-[#8696a0] text-[11px]">{{ $msg['created_at'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- fallback --}}
|
||||
@else
|
||||
<div class="max-w-[80%] bg-[#202c33] text-white rounded-xl rounded-tl-sm px-4 py-2 shadow">
|
||||
|
||||
@@ -114,6 +114,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="border-gray-100">
|
||||
|
||||
{{-- Transferencia bancaria --}}
|
||||
<div>
|
||||
<h3 class="text-sm font-bold text-gray-700 mb-1">Transferencia bancaria</h3>
|
||||
<p class="text-xs text-gray-400 mb-4">Datos que se muestran al cliente cuando elige pagar por transferencia. Deja vacío para deshabilitar esta opción.</p>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-1">Banco / Billetera</label>
|
||||
<input wire:model.defer="recarga_banco_nombre" type="text" placeholder="Ej: Nequi, Bancolombia, Daviplata"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none">
|
||||
@error('recarga_banco_nombre') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-1">Número / Clave</label>
|
||||
<input wire:model.defer="recarga_banco_clave" type="text" placeholder="Ej: 3001234567"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none font-mono">
|
||||
@error('recarga_banco_clave') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-1">Titular de la cuenta</label>
|
||||
<input wire:model.defer="recarga_banco_titular" type="text" placeholder="Nombre del titular"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-500 outline-none">
|
||||
@error('recarga_banco_titular') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Guardar --}}
|
||||
<div class="flex justify-end pt-2">
|
||||
<button wire:click="guardar"
|
||||
|
||||
Reference in New Issue
Block a user