4. Login

LoginComponent

Crea el Guard: src/app/core/auth/auth.guard.ts
import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
import { AuthService } from './auth.service';

export const authGuard: CanActivateFn = () => {
  const auth = inject(AuthService);
  const router = inject(Router);

  // Si aún está cargando el estado, dejamos pasar y que el componente decida (simple)
  if (auth.loading()) return true;

  if (auth.isLoggedIn()) return true;

  router.navigateByUrl('/login');
  return false;
};

Crea LoginComponent  (ReactiveForms)

src/app/pages/login/

ng g c pages/login --standalone

src/app/pages/login/login.ts

import { Component,inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AuthService } from '../../core/auth/auth.service';


@Component({
  selector: 'app-login',
  imports: [ReactiveFormsModule],
  templateUrl: './login.html',
  styleUrl: './login.css',
})
export class LoginComponent {
  private fb = inject(FormBuilder);
  private auth = inject(AuthService);
  private router = inject(Router);

  error = '';

  form = this.fb.nonNullable.group({
    email: ['', [Validators.required, Validators.email]],
    password: ['', [Validators.required, Validators.minLength(6)]],
  });

  get email() { return this.form.controls.email; }
  get password() { return this.form.controls.password; }

  async onLogin() {
    this.error = '';
    if (this.form.invalid) {
      this.form.markAllAsTouched();
      return;
    }
    const { email, password } = this.form.getRawValue();
    try {
      await this.auth.login(email, password);
      this.router.navigateByUrl('/admin');
    } catch (e: any) {
      this.error = e?.message ?? 'Error en login';
    }
  }

  async onRegister() {
    this.error = '';
    if (this.form.invalid) {
      this.form.markAllAsTouched();
      return;
    }
    const { email, password } = this.form.getRawValue();
    try {
      await this.auth.register(email, password);
      this.router.navigateByUrl('/admin');
    } catch (e: any) {
      this.error = e?.message ?? 'Error en registro';
    }
  }

}

src/app/pages/login/login.component.html

<h2>Login</h2>

<form [formGroup]="form" (ngSubmit)="onLogin()" class="card">
  <label>
    Email
    <input type="email" formControlName="email" />
  </label>

  @if (email.touched && email.errors?.['required']) {
    <small class="err">Email obligatorio</small>
  }
  @if (email.touched && email.errors?.['email']) {
    <small class="err">Email no válido</small>
  }

  <label>
    Contraseña
    <input type="password" formControlName="password" />
  </label>

  @if (password.touched && password.errors?.['required']) {
    <small class="err">Contraseña obligatoria</small>
  }
  @if (password.touched && password.errors?.['minlength']) {
    <small class="err">Mínimo 6 caracteres</small>
  }

  <button type="submit" [disabled]="form.invalid">Entrar</button>
</form>

<div class="row">
  <button type="button" (click)="onRegister()" [disabled]="form.invalid">
    Crear cuenta
  </button>
</div>

@if (error) {
  <p class="err">{{ error }}</p>
}

src/app/pages/login/login.component.css

.card { display: grid; gap: 10px; max-width: 360px; padding: 16px; border: 1px solid #ddd; border-radius: 10px; }
label { display: grid; gap: 6px; }
input { padding: 10px; border: 1px solid #ccc; border-radius: 8px; }
button { padding: 10px; border-radius: 8px; border: 1px solid #ccc; cursor: pointer; }
button[disabled] { opacity: 0.6; cursor: not-allowed; }
.row { margin-top: 10px; display: flex; gap: 10px; }
.err { color: #b00020; margin-top: 10px; }