feat(chat): identificación por correo con registro automático
- Reemplaza campo teléfono por correo electrónico en el inicio del chat - Si el correo existe: envía OTP y abre el chat - Si no existe: ofrece crear cuenta automáticamente (pide nombre) - Si rechaza registro: vuelve al formulario inicial - Cuenta nueva se crea con contraseña aleatoria Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
536377363c
commit
a693ce2527
@@ -17,6 +17,7 @@ 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;
|
||||
@@ -27,9 +28,9 @@ class PublicChat extends Component
|
||||
use WithFileUploads;
|
||||
|
||||
// ── Paso actual ───────────────────────────────────────────
|
||||
public string $paso = 'telefono'; // telefono | verificacion | chat
|
||||
public string $telefono = '';
|
||||
public string $nombre = '';
|
||||
public string $paso = 'email'; // email | verificacion | registro | chat
|
||||
public string $email = '';
|
||||
public string $nombreRegistro = '';
|
||||
public string $codigoIngresado = '';
|
||||
public ?string $emailMascarado = null;
|
||||
public ?int $contactIdPending = null; // contact.id mientras espera verificacion
|
||||
@@ -52,54 +53,83 @@ class PublicChat extends Component
|
||||
public bool $procesandoImagen = false;
|
||||
|
||||
protected $rules = [
|
||||
'telefono' => 'required|min:7|max:20',
|
||||
'nombre' => 'nullable|max:80',
|
||||
'email' => 'required|email|max:100',
|
||||
'nombreRegistro' => 'required|max:80',
|
||||
'codigoIngresado' => 'nullable|digits:6',
|
||||
];
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// Paso 1: identificar usuario
|
||||
// Paso 1: buscar por correo
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
public function iniciar(): void
|
||||
{
|
||||
$this->validate(['telefono' => 'required|min:7|max:20', 'nombre' => 'nullable|max:80']);
|
||||
$this->validate(['email' => 'required|email|max:100']);
|
||||
|
||||
$contact = ChatContact::firstOrCreate(
|
||||
['canal' => 'web', 'canal_id' => $this->telefono],
|
||||
['nombre' => $this->nombre ?: $this->telefono, 'telefono' => $this->telefono]
|
||||
);
|
||||
$user = User::where('email', $this->email)->first();
|
||||
|
||||
if ($this->nombre && $contact->nombre !== $this->nombre) {
|
||||
$contact->update(['nombre' => $this->nombre]);
|
||||
}
|
||||
|
||||
// Buscar usuario en el sistema por cédula o email
|
||||
$user = null;
|
||||
if (! $contact->user_id) {
|
||||
$user = User::where('cedula', $this->telefono)
|
||||
->orWhere('email', $this->telefono)
|
||||
->first();
|
||||
if ($user) {
|
||||
$contact->update(['user_id' => $user->id]);
|
||||
}
|
||||
} else {
|
||||
$user = User::find($contact->user_id);
|
||||
}
|
||||
|
||||
// Si se encontró el usuario: enviar OTP al correo registrado
|
||||
if ($user && $user->email) {
|
||||
$this->contactIdPending = $contact->id;
|
||||
$this->emailMascarado = $this->enmascararEmail($user->email);
|
||||
$this->enviarCodigoOtp($contact->id, $user);
|
||||
$this->paso = 'verificacion';
|
||||
if (! $user) {
|
||||
$this->paso = 'registro';
|
||||
return;
|
||||
}
|
||||
|
||||
// Sin cuenta registrada: acceso como invitado (sin saldo ni compras)
|
||||
$this->abrirChat($contact);
|
||||
$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',
|
||||
]);
|
||||
|
||||
$user = User::create([
|
||||
'name' => $this->nombreRegistro,
|
||||
'email' => $this->email,
|
||||
'password' => \Illuminate\Support\Facades\Hash::make(\Illuminate\Support\Str::random(16)),
|
||||
]);
|
||||
|
||||
$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->paso = 'email';
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// Paso 2b: verificar código OTP
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
private function enviarCodigoOtp(int $contactId, User $user): void
|
||||
{
|
||||
$codigo = (string) random_int(100000, 999999);
|
||||
@@ -112,10 +142,6 @@ class PublicChat extends Component
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// Paso 2: verificar código OTP
|
||||
// ─────────────────────────────────────────────────────────
|
||||
|
||||
public function verificarCodigo(): void
|
||||
{
|
||||
$this->validate(['codigoIngresado' => 'required|digits:6']);
|
||||
|
||||
Reference in New Issue
Block a user