Angular 21 de Cero a Experto / Proyecto final
Proyecto: tablero colaborativo de gastos en tiempo real
Es hora de construir el proyecto que corona el curso: un tablero colaborativo donde varios usuarios organizan gastos por columnas (pendiente → aprobado → pagado) y ven los cambios de los demás al instante. Integra TODO lo que aprendiste —señales, store, computed, socket, presencia, optimismo, guard de auth—. La estructura Angular la verás en código exacto; el MOTOR completo —el store, el socket y la colaboración— corre en vivo aquí mismo.
La estructura Angular
El componente del tablero consume el store y renderiza las columnas con el control flow moderno:
import { Component, inject, computed } from '@angular/core';
import { TableroStore } from './tablero.store';
@Component({
selector: 'app-tablero',
template: `
<header>
<h1>Tablero de gastos</h1>
<app-presencia [usuarios]="store.conectados()" />
</header>
<div class="columnas">
@for (col of columnas(); track col.estado) {
<section class="columna">
<h2>{{ col.titulo }} · {{ col.total() }} COP</h2>
@for (g of col.gastos(); track g.id) {
<app-tarjeta-gasto [gasto]="g"
(mover)="store.mover(g.id, $event)"
(borrar)="store.borrar(g.id)" />
} @empty {
<p class="vacia">Sin gastos aquí</p>
}
</section>
}
</div>
`,
})
export class TableroComponent {
protected store = inject(TableroStore);
// las columnas se DERIVAN del estado compartido con computed
protected columnas = computed(() => {
const gastos = this.store.gastos();
return (['pendiente', 'aprobado', 'pagado'] as const).map((estado) => ({
estado,
titulo: { pendiente: 'Pendiente', aprobado: 'Aprobado', pagado: 'Pagado' }[estado],
gastos: computed(() => gastos.filter((g) => g.estado === estado)),
total: computed(() => gastos.filter((g) => g.estado === estado).reduce((s, g) => s + g.valor, 0)),
}));
});
}El TableroStore alimenta sus señales desde el socket, y las operaciones (mover, borrar,
crear) emiten al socket con actualización optimista. Aquí está su lógica completa, corriendo:
El motor completo, en vivo
Qué acabas de construir
Mini-reto (amplía el proyecto)
Añade al motor: 1) un computed granTotal (suma de todo el tablero); 2) una operación
crear que ponga el gasto directamente en una columna dada (no siempre "pendiente"); 3) un
segundo bot que mueva gastos por su cuenta cada cierto tiempo, para ver más colaboración.
Verifica que todos los derivados reaccionan solos.
Qué sigue
Tienes un tablero colaborativo funcionando de punta a punta. Pero un proyecto real necesita más para ser un PRODUCTO: que sobreviva a una recarga, que avise de cambios no vistos, que sea accesible. El siguiente reto lleva tu tablero de demo a producto —el salto que separa un ejercicio de una app que la gente usaría—.