Habilita la Autenticación con Google en la consola de Firebase.
Crea las Credenciales del Cliente.
Agrega los Origenes autorizados (url clientes que van a acceder a la app)
Agrega los Orígenes autorizados (url clientes que van a acceder a la app)
Agregamos las urls de firebase, la del dominio o subdominio y las de el servidor de desarrollo.
Agrega las URL de redirección (esto abre la pantalla /__/auth/handler)
NOTA: como vemos son las mismas url pero agrenadoles al final /__/auth/handler
Por ultimo le damos CREAR ( en el botón azul )
SI LA APP ES PRIVADA SERÁ MAS RÁPIDP EL PROCESO, PODRAN ACCEDER HASTA 100 CORREOS GMAIL. SIRVE DE PRUEBAS Y APPS CERRADAS DE EMPRESAS.
IMPORTANTE COMPLETAR ESTE PASO EN LA CONSOLA.
Creamos el servicio en la carpeta firebase/auth con el siguiente comando:
ng g s firebase/auth
Se creará un servicio en la carpeta firebase llamado auth, el servicio requiere que las configuraciones de de firebase ya estén listas en el proyecto, paso que hicimos previamente al iniciar el proyecto.
código del servicio:
// src/app/services/auth.service.ts
import { Injectable, inject, signal, Signal } from '@angular/core';
import { Router } from '@angular/router';
import { GoogleAuthProvider, User, browserLocalPersistence, onAuthStateChanged, setPersistence, signInWithPopup, signOut} from 'firebase/auth';
import { collection, doc, getDoc, getDocs, query, setDoc, where, runTransaction, orderBy, Firestore // Asegúrate de que el tipo Firestore esté disponible si lo usas
} from 'firebase/firestore';
// Importa las instancias de Firebase que inicializaste globalmente en app.config.ts
import { auth, firestore, firebaseAppId } from '../../app.config';
// --- Interfaces Moviadas aquí ---
// Interfaz para el perfil público del usuario
export interface PublicUserProfile {
uid: string;
username: string;
email: string;
displayName?: string;
photoURL?: string;
bio?: string;
lastActive?: string;
createdAt: string;
userType?: 'business' | 'consumer' | 'admin'; // <--- ¡DEFINE EL TIPO DE USUARIO!
}
// Interfaz para un post básico (si planeas mostrar posts en el feed)
export interface Post {
id: string;
userId: string;
username: string;
imageUrl: string;
caption: string;
timestamp: any; // Firebase Timestamp (puede ser Date si lo conviertes)
likesCount?: number;
commentsCount?: number;
}
// ---------------------------------
@Injectable({
providedIn: 'root'
})
export class AuthService {
// Signals para el estado de autenticación y perfil público
private _user = signal<User | null | undefined>(undefined);
public user: Signal<User | null | undefined> = this._user.asReadonly();
private _publicUserProfile = signal<PublicUserProfile | null>(null);
public publicUserProfile: Signal<PublicUserProfile | null> = this._publicUserProfile.asReadonly();
private router = inject(Router);
constructor() {
console.log('AuthService (Consolidado): Usando instancias de Firebase inicializadas globalmente.');
console.log('AuthService (Consolidado): Firebase Project ID:', firebaseAppId);
this.initAuthListener();
}
/**
* Inicializa el listener de estado de autenticación de Firebase.
* Configura la persistencia y actualiza las Signals de usuario y perfil.
*/
private async initAuthListener(): Promise<void> {
try {
await setPersistence(auth, browserLocalPersistence);
console.log('AuthService (Consolidado): Persistencia de autenticación configurada a browserLocalPersistence.');
onAuthStateChanged(auth, async (user) => {
this._user.set(user);
if (user) {
console.log('AuthService (Consolidado): Usuario autenticado detectado:', user.uid);
// Cargar el perfil público del usuario o crearlo si no existe
try {
let publicProfile = await this.getProfileByUid(user.uid); // Intentar obtener el perfil
if (publicProfile) {
this._publicUserProfile.set(publicProfile);
console.log('AuthService (Consolidado): Perfil público cargado:', publicProfile.username);
} else {
// <--- ¡INICIA EL BLOQUE DE CÓDIGO A AÑADIR/MODIFICAR AQUÍ!
// Si el perfil NO existe en Firestore, crearlo como CONSUMER por defecto
console.log('AuthService (Consolidado): Perfil no encontrado para el usuario. Creando perfil CONSUMER por defecto.');
// Generar un username por defecto (ej. desde el email o un id truncado si el email no está disponible)
const defaultUsername = user.email ? user.email.split('@')[0] : `user_${user.uid.substring(0, 8)}`;
// Llama a createUserProfile con el tipo 'consumer' por defecto
publicProfile = await this.createUserProfile(user, defaultUsername, 'consumer');
this._publicUserProfile.set(publicProfile);
console.log('AuthService (Consolidado): Nuevo perfil CONSUMER creado y cargado.');
// <--- ¡TERMINA EL BLOQUE DE CÓDIGO A AÑADIR/MODIFICAR AQUÍ!
}
} catch (error) {
console.error('AuthService (Consolidado): Error al cargar o crear perfil público en initAuthListener:', error);
this._publicUserProfile.set(null);
}
} else {
this._publicUserProfile.set(null);
console.log('AuthService (Consolidado): Usuario desautenticado.');
}
});
} catch (error) {
console.error('AuthService (Consolidado): Error durante la inicialización de autenticación o persistencia:', error);
this._user.set(null);
this._publicUserProfile.set(null);
}
}
/**
* Inicia el proceso de autenticación con Google mediante un pop-up.
* @returns {Promise<User>} Una promesa que se resuelve con el objeto User autenticado en caso de éxito.
* @throws {Error} Lanza un error si la autenticación falla por alguna razón.
*/
async loginWithGoogle(): Promise<User> {
const provider = new GoogleAuthProvider();
provider.addScope('profile');
provider.addScope('email');
try {
const result = await signInWithPopup(auth, provider);
const user = result.user;
if (!user.email) {
throw new Error('No se pudo obtener el email del usuario de Google.');
}
console.log('AuthService (Consolidado): Login con Google exitoso:', user.uid);
return user;
} catch (error: any) {
console.error('AuthService (Consolidado): Error en loginWithGoogle:', error);
let errorMessage: string;
switch (error.code) {
case 'auth/popup-closed-by-user':
errorMessage = 'Inicio de sesión cancelado. La ventana emergente fue cerrada.';
break;
case 'auth/popup-blocked':
errorMessage = 'El navegador bloqueó la ventana emergente. Por favor, permita ventanas emergentes e intente nuevamente.';
break;
case 'auth/cancelled-popup-request':
errorMessage = 'La solicitud de autenticación fue cancelada.';
break;
case 'auth/account-exists-with-different-credential':
errorMessage = 'Ya existe una cuenta con el mismo email pero con diferente proveedor de autenticación.';
break;
case 'auth/unauthorized-domain':
errorMessage = 'El dominio de la aplicación no está autorizado para operaciones OAuth.';
break;
default:
errorMessage = `Error al iniciar sesión: ${error.message || 'Ha ocurrido un error desconocido'}`;
}
throw new Error(errorMessage);
}
}
/**
* Cierra la sesión del usuario actual en Firebase.
* @returns {Promise<void>} Una promesa que se resuelve cuando la sesión ha sido cerrada.
*/
async logout(): Promise<void> {
try {
await signOut(auth);
console.log('AuthService (Consolidado): Sesión cerrada.');
this.router.navigate(['/login']);
} catch (error) {
console.error('AuthService (Consolidado): Error al cerrar sesión:', error);
throw new Error('Error al cerrar sesión. Intente nuevamente.');
}
}
/**
* Obtiene el UID (User ID) del usuario actual de Firebase.
* @returns {string | null} El UID del usuario autenticado o `null` si no hay usuario.
*/
getCurrentUserId(): string | null {
return auth.currentUser ? auth.currentUser.uid : null;
}
// --- Métodos de Gestión de Perfil de Usuario (Movidos de UserProfileService) ---
/*** Obtiene el perfil público de un usuario por su UID.
* @param uid El UID del usuario.
* @returns {Promise<PublicUserProfile | null>} El perfil público o null si no existe. */
async getProfileByUid(uid: string): Promise<PublicUserProfile | null> {
try {
const profileDocRef = doc(firestore, `userProfiles`, uid);
const profileSnap = await getDoc(profileDocRef);
if (profileSnap.exists()) {
console.log(`AuthService (Consolidado): Perfil encontrado para UID ${uid}`);
return profileSnap.data() as PublicUserProfile;
}
console.log(`AuthService (Consolidado): No se encontró perfil para UID ${uid}`);
return null;
} catch (error) {
console.error(`AuthService (Consolidado): Error al obtener perfil por UID ${uid}:`, error);
throw new Error('Error al obtener el perfil de usuario.');
}
}
/**
* Obtiene el perfil público de un usuario por su username.
* @param username El nombre de usuario.
* @returns {Promise<PublicUserProfile | null>} El perfil público o null si no existe.
*/
async getProfileByUsername(username: string): Promise<PublicUserProfile | null> {
try {
const q = query(
collection(firestore, `userProfiles`),
where('username', '==', username)
);
const querySnapshot = await getDocs(q);
if (!querySnapshot.empty) {
console.log(`AuthService (Consolidado): Perfil encontrado para username ${username}`);
return querySnapshot.docs[0].data() as PublicUserProfile;
}
console.log(`AuthService (Consolidado): No se encontró perfil para username ${username}`);
return null;
} catch (error) {
console.error(`AuthService (Consolidado): Error al obtener perfil por username ${username}:`, error);
throw new Error('Error al obtener el perfil de usuario.');
}
}
/**
* Verifica si un username ya existe en la base de datos.
* @param username El nombre de usuario a verificar.
* @returns {Promise<boolean>} True si el username ya existe, false en caso contrario.
*/
async isUsernameTaken(username: string): Promise<boolean> {
try {
const normalizedUsername = username.toLowerCase().trim().replace(/[^a-z0-9_]/g, '');
const q = query(
collection(firestore, `userProfiles`),
where('username', '==', normalizedUsername)
);
const querySnapshot = await getDocs(q);
const isTaken = !querySnapshot.empty;
console.log(`AuthService (Consolidado): Username "${username}" (normalized: "${normalizedUsername}") taken: ${isTaken}`);
return isTaken;
} catch (error) {
console.error(`AuthService (Consolidado): Error al verificar la unicidad del username "${username}":`, error);
throw new Error('Error al verificar la unicidad del nombre de usuario.');
}
}
/**
* Crea o actualiza un perfil público de usuario con un username y un tipo de usuario.
* Utiliza una transacción para asegurar la unicidad del username si es un perfil nuevo.
* @param user El objeto User de Firebase (proveniente de la autenticación).
* @param username El username deseado por el usuario.
* @param type El tipo de usuario ('consumer', 'business', 'admin'). Por defecto 'consumer'. // <-- ¡NUEVA DESCRIPCIÓN Y PARÁMETRO!
* @returns {Promise<PublicUserProfile>} El perfil público creado o actualizado.
*/
async createUserProfile(
user: User,
username: string,
type: 'consumer' | 'business' | 'admin' = 'consumer' // <-- ¡MODIFICA ESTA LÍNEA! (Añade 'type' y su valor por defecto)
): Promise<PublicUserProfile> {
const uid = user.uid;
const normalizedUsername = username.toLowerCase().trim().replace(/[^a-z0-9_]/g, '');
if (!normalizedUsername) {
throw new Error('El nombre de usuario no puede estar vacío o contener solo caracteres especiales.');
}
try {
const newProfile: PublicUserProfile = {
uid: uid,
username: normalizedUsername,
email: user.email || '',
displayName: user.displayName || '',
photoURL: user.photoURL || '',
bio: '',
lastActive: new Date().toISOString(),
createdAt: new Date().toISOString(),
userType: type // <--- ¡AÑADE O MODIFICA ESTA LÍNEA PARA ASIGNAR EL TIPO!
};
await runTransaction(firestore, async (transaction) => {
const userProfileRef = doc(firestore, `userProfiles`, uid);
const userProfileSnap = await transaction.get(userProfileRef);
if (userProfileSnap.exists()) {
// Si el perfil ya existe, actualizamos username y lastActive si es necesario
const existingProfile = userProfileSnap.data() as PublicUserProfile;
if (!existingProfile.username || existingProfile.username !== normalizedUsername) {
transaction.update(userProfileRef, { username: normalizedUsername, lastActive: newProfile.lastActive });
console.log(`AuthService (Consolidado): Perfil existente para ${uid} actualizado con nuevo username: ${normalizedUsername}`);
} else {
transaction.update(userProfileRef, { lastActive: newProfile.lastActive });
console.log(`AuthService (Consolidado): Perfil existente para ${uid} actualizado solo lastActive.`);
}
// NOTA IMPORTANTE: El userType NO se actualiza aquí si el perfil ya existe.
// El userType se establece en la creación inicial. Si un usuario cambia de rol
// (ej. de consumidor a negocio), se manejaría con una función de "actualización de rol" separada.
} else {
// Si el perfil NO existe, lo creamos asegurando la unicidad del username
const qCheck = query(
collection(firestore, `userProfiles`),
where('username', '==', normalizedUsername)
);
const existingUsernameSnap = await getDocs(qCheck);
if (!existingUsernameSnap.empty) {
throw new Error('El nombre de usuario ya está en uso. Por favor, elige otro.');
}
transaction.set(userProfileRef, newProfile); // <-- Aquí se guarda el 'newProfile' con el 'userType'
console.log(`AuthService (Consolidado): Nuevo perfil público creado para ${uid} con username: ${normalizedUsername}, tipo: ${type}`);
}
});
return newProfile;
} catch (error: any) {
console.error(`AuthService (Consolidado): Error al crear o actualizar perfil para UID ${uid}:`, error);
throw new Error(error.message || 'Error al guardar el perfil de usuario.');
}
}
/*** Actualiza la fecha de última actividad de un perfil de usuario.
* @param uid El UID del usuario. */
async updateLastActive(uid: string): Promise<void> {
try {
const profileDocRef = doc(firestore, `userProfiles`, uid);
await setDoc(profileDocRef, { lastActive: new Date().toISOString() }, { merge: true });
console.log(`AuthService (Consolidado): lastActive actualizado para UID ${uid}`);
} catch (error) {
console.error(`AuthService (Consolidado): Error al actualizar lastActive para UID ${uid}:`, error);
}
}
/*** Obtiene los posts de un usuario específico por su UID.
* @param userId El UID del usuario.
* @returns {Promise<Post[]>} Una lista de posts del usuario. */
async getUserPosts(userId: string): Promise<Post[]> {
try {
const postsCollectionRef = collection(firestore, `posts`);
const q = query(postsCollectionRef, where('userId', '==', userId), orderBy('timestamp', 'desc'));
const querySnapshot = await getDocs(q);
const posts: Post[] = querySnapshot.docs.map(doc => ({
id: doc.id,
...doc.data() as Omit<Post, 'id'>
}));
console.log(`AuthService (Consolidado): Posts encontrados para UID ${userId}:`, posts.length);
return posts;
} catch (error) {
console.error(`AuthService (Consolidado): Error al obtener posts para UID ${userId}:`, error);
throw new Error('Error al cargar las publicaciones del usuario.');
}
}
}
// Final del codigo !
Creamos el componente login en vista/login, con el siguiente comando:
ng g c vistas/login
Se creara un componente nuevo y agregaremos el siguiente codigo:
.css:
.center {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.logo {
border-radius: 50%;
width: 100px;
height: 100px;
}
button {
width: 100%;
height: 48px;
display: flex;
align-items: center;
justify-content: center; margin-top: 16px;
}
.mat-typography {
padding: 16px;
margin: auto;
max-width: 400px;
text-align: center;
}
.html:
<!-- src/app/login/login.component.html -->
<!-- Contenedor principal del componente de login. -->
<div class="center">
<!-- Contenedor para aplicar estilos de tipografía de Material Design y centrar el contenido. -->
<div class="mat-typography">
<!-- Sección de carga inicial de autenticación.
Este bloque se muestra mientras la aplicación verifica el estado de la sesión. -->
@if (isAuthLoading()) {
<div style="padding: 32px 0;">
<mat-spinner diameter="50"></mat-spinner>
<p>Cargando autenticación...</p>
</div>
}
<!-- Contenido principal del formulario de login/creación de username.
Se muestra solo una vez que la autenticación inicial ha terminado. -->
@if (!isAuthLoading()) {
<mat-card>
<mat-card-content style="padding: 24px;">
<img class="logo" src="{{ logo }}" alt="">
<!-- SECCIÓN DE INICIO DE SESIÓN CON GOOGLE -->
<!-- Este bloque se muestra cuando el usuario necesita iniciar sesión (no tiene sesión activa o username). -->
@if (!showUsernameForm) {
<h3> {{ mensaje }} </h3>
<button mat-raised-button color="primary"
(click)="loginWithGoogle()" [disabled]="loading">
@if (!loading) {
<!-- Icono SVG de Google -->
<svg style="width: 20px; height: 20px; margin-right: 8px;" viewBox="0 0 24 24" fill="currentColor">
<path d="M22.675 11.238c0-.783-.069-1.543-.19-2.285H12v4.51h6.07c-.266 1.348-.99 2.483-2.078 3.327v2.925h3.766c2.203-2.028 3.48-5.006 3.48-8.477z" fill="#4285F4"/>
<path d="M12 23c3.053 0 5.617-1 7.487-2.735l-3.766-2.925c-1.088.751-2.49 1.205-3.721 1.205-2.868 0-5.29-1.93-6.167-4.502H2.884v2.99C4.814 21.36 8.236 23 12 23z" fill="#34A853"/>
<path d="M5.833 14.398c-.27-.791-.424-1.63-.424-2.48s.154-1.689.424-2.48V6.91H2.884C1.942 8.761 1.488 10.793 1.488 12.55s.454 3.789 1.396 5.639L5.833 14.398z" fill="#FBBC05"/>
<path d="M12 4.47c1.657 0 3.15.577 4.334 1.706L19.24 3.05c-1.87-1.735-4.434-2.735-7.24-2.735-3.764 0-7.186 1.64-9.116 4.398l2.949 2.308c.877-2.572 3.3-4.502 6.167-4.502z" fill="#EA4335"/>
</svg>
Iniciar Sesión con Google
} @else {
<mat-spinner [diameter]="24"></mat-spinner>
}
</button>
}
<!-- SECCIÓN DE CREACIÓN DE USERNAME -->
<!-- Este bloque se muestra solo si `showUsernameForm` es true (para usuarios nuevos que necesitan definir un username). -->
@if (showUsernameForm) {
<h3>Elige tu Nombre de Usuario</h3>
<p style="margin-bottom: 16px; color: var(--mdc-ref-palette-neutral70);">Este será tu identificador único en la aplicación.</p>
<mat-form-field appearance="outline" style="width: 100%; margin-bottom: 16px;">
<mat-label>Nombre de Usuario</mat-label>
<input matInput
placeholder="ej. mi_negocio_online"
[(ngModel)]="usernameInput"
(ngModelChange)="checkUsernameAvailability()"
[disabled]="usernameCheckLoading || loading"
required
minlength="3"
pattern="^[a-zA-Z0-9_]+$"
#usernameField="ngModel">
</mat-form-field>
<button
mat-raised-button
color="primary"
(click)="createUsernameAndProfile()"
[disabled]="usernameCheckLoading || loading || !usernameAvailable || usernameField.invalid">
@if (!loading) {
<span>Crear Nombre de Usuario y Entrar</span>
} @else {
<mat-spinner [diameter]="24"></mat-spinner>
}
</button>
}
</mat-card-content>
</mat-card>
}
</div>
</div>
.ts
// Angular Core
import { Component, inject, computed, effect } from '@angular/core';
import { Router } from '@angular/router';
import { CommonModule } from '@angular/common';
// Angular Material
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { FormsModule } from '@angular/forms';
// Firebase (solo el tipo `User` se importa)
import { User } from 'firebase/auth';
import { AuthService } from '../../firebase/auth/auth.service';
import { MatCardModule } from '@angular/material/card';
// ¡Solo un servicio!
// NO SE USA RxJS en este componente, por lo tanto, no se importan ni `Subscription` ni operadores.
@Component({
selector: 'app-login',
imports: [
CommonModule,
FormsModule,
MatCardModule,
MatButtonModule,
MatIconModule,
MatProgressSpinnerModule,
MatInputModule,
MatFormFieldModule
],
standalone: true,
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent {
public logo = 'assets/brand/copaguia-intro.gif';
public mensaje = 'Bienvenido a Copa Guia';
private router = inject(Router);
public authService = inject(AuthService); // ¡Ahora este es el único servicio inyectado
// --- Estados reactivos con Signals para el flujo de Login y Asignación de Username ---
errorMessage: string = '';
loading: boolean = false;
// `currentUser`: Signal que representa el usuario de Firebase logueado.
currentUser = this.authService.user;
// `isAuthLoading`: Signal computada que indica si el `AuthService` aún está verificando el estado inicial.
isAuthLoading = computed(() => this.currentUser() === undefined);
// --- Estados para el formulario de Username ---
showUsernameForm: boolean = false;
usernameInput: string = '';
usernameCheckLoading: boolean = false;
usernameAvailable: boolean | null = null;
usernameErrorMessage: string = '';
usernameSuccessMessage: string = '';
constructor() {
effect(async () => {
const user = this.currentUser();
if (user !== undefined) {
if (user) {
console.log('LoginComponent: Efecto detecta usuario autenticado:', user.uid);
try {
// Usar el método directamente del AuthService consolidado
const publicProfile = await this.authService.getProfileByUid(user.uid);
if (publicProfile && publicProfile.username) {
console.log('LoginComponent: Usuario existente con username. Redirigiendo a:', publicProfile.username);
this.router.navigate(['/profile', publicProfile.username]);
} else {
console.log('LoginComponent: Usuario autenticado sin username. Mostrando formulario de creación.');
this.showUsernameForm = true;
// --- INICIO DEL BLOQUE A COMENTAR (OPCIONAL PARA FUTURO PRE-RELLENO) ---
// if (user.email) {
// this.usernameInput = user.email.split('@')[0].replace(/[^a-zA-Z0-9_]/g, '').toLowerCase();
// this.checkUsernameAvailability(true);
// }
// --- FIN DEL BLOQUE A COMENTAR ---
}
} catch (error) {
console.error('LoginComponent: Error al verificar el perfil público del usuario:', error);
this.errorMessage = 'Error al cargar los datos del usuario. Por favor, intente nuevamente.';
this.showUsernameForm = true;
}
} else {
this.showUsernameForm = false;
console.log('LoginComponent: Efecto detecta usuario desautenticado (null).');
}
}
});
}
async loginWithGoogle(): Promise<void> {
this.loading = true;
this.errorMessage = '';
try {
await this.authService.loginWithGoogle(); // Usar el método del AuthService consolidado
console.log(
'LoginComponent: Login con Google completado.
El flujo posterior lo gestiona el efecto de Signal.')
;
} catch (error: any) {
this.errorMessage = error.message;
this.showUsernameForm = false;
console.error('LoginComponent: Error en loginWithGoogle:', error);
} finally {
this.loading = false;
}
}
async checkUsernameAvailability(initialCheck: boolean = false): Promise<void> {
this.usernameErrorMessage = '';
this.usernameSuccessMessage = '';
this.usernameAvailable = null;
if (this.usernameInput.length < 3) {
if (!initialCheck) {
this.usernameErrorMessage = 'El nombre de usuario debe tener al menos 3 caracteres.';
}
return;
}
if (!/^[a-zA-Z0-9_]+$/.test(this.usernameInput)) {
this.usernameErrorMessage = 'Solo letras, números y guiones bajos (ej. mi_usuario).';
return;
}
this.usernameCheckLoading = true;
try {
// Usar el método del AuthService consolidado
const taken = await this.authService.isUsernameTaken(this.usernameInput);
this.usernameAvailable = !taken;
if (taken) {
this.usernameErrorMessage = 'Este nombre de usuario ya está en uso. Por favor, elige otro.';
} else {
this.usernameSuccessMessage = '¡Nombre de usuario disponible!';
}
} catch (error: any) {
this.usernameErrorMessage = error.message || 'Error al verificar disponibilidad.';
this.usernameAvailable = null;
console.error('LoginComponent: Error al verificar username:', error);
} finally {
this.usernameCheckLoading = false;
}
}
async createUsernameAndProfile(): Promise<void> {
if (!this.currentUser()) {
this.errorMessage = 'No hay usuario autenticado para crear el perfil.';
return;
}
if (this.usernameAvailable === null || !this.usernameAvailable) {
this.usernameErrorMessage = 'Por favor, verifica la disponibilidad del nombre de usuario y elige uno disponible.';
return;
}
if (this.usernameInput.length < 3 || !/^[a-zA-Z0-9_]+$/.test(this.usernameInput)) {
this.usernameErrorMessage = 'El nombre de usuario no es válido.';
return;
}
this.loading = true;
this.usernameErrorMessage = '';
this.errorMessage = '';
try {
// Usar el método del AuthService consolidado
const profile = await this.authService.createUserProfile(this.currentUser() as User, this.usernameInput);
console.log('LoginComponent: Perfil de usuario creado/actualizado:', profile.username);
this.router.navigate(['/profile', profile.username]);
} catch (error: any) {
this.errorMessage = error.message || 'Error al crear/actualizar el perfil de usuario.';
console.error('LoginComponent: Error al crear username y perfil:', error);
} finally {
this.loading = false;
}
}
}
CON ESTOS PASO TU AUTENTICACIÓN CON GOOGLE ESTARÁ LISTA PARA FUNCIONAR EN TU APLICACIÓN Y PODRAS REUSAR EL SERVICIO PARA ACCIONES DE VERIFICACIÓN CONDICIONAL PARA ACCIONES EN ALGUNOS COMPONENTES, COMO DAR PODER HACER ALGUNA ACCIÓN SI EL USUARIO ESTA LOGUEADO.
ADEMÁS DE USARLO PARA PROTEGER RUTAS CON GUARDS.