Ir al contenido

Workspace Layout

El área autenticada (dashboard) tiene su propio layout con sidebar, top bar y breadcrumbs. Desde el refactor a rutas dinámicas, cada workspace se representa con una URL propia: /[locale]/workspaces/[workspaceId]/....

apps/web/app/[locale]/workspaces/
├── page.tsx ← Listado de workspaces
└── [workspaceId]/
├── layout.tsx ← Layout del workspace (validación + UI)
├── home/page.tsx ← Dashboard principal
├── kanban/page.tsx ← Tablero Kanban (primer board, funcional con DnD)
├── kanban/[boardId]/page.tsx ← Tablero Kanban de un board concreto
├── backlog/page.tsx ← Backlog del workspace (tareas sin columna)
├── calendar/page.tsx ← Calendario: tabs Equipo / Mi tiempo (time tracking)
├── teams/page.tsx ← Equipos (miembros, roles y estadísticas)
├── chat/page.tsx ← Chat (placeholder)
├── settings/page.tsx ← Ajustes del workspace (nombre, descripción, URL)
└── profile/ ← Perfil dentro del contexto del workspace
├── page.tsx ← Perfil propio del usuario
├── edit/page.tsx ← Edición del perfil
└── [id]/page.tsx ← Perfil público de otro usuario

Layout dinámico (app/[locale]/workspaces/[workspaceId]/layout.tsx)

Sección titulada «Layout dinámico (app/[locale]/workspaces/[workspaceId]/layout.tsx)»

Server Component que:

  1. Lee params.workspaceId.
  2. Busca el usuario autenticado y sus membresías.
  3. Verifica que el usuario pertenezca al workspace solicitado.
  4. Redirige a /[locale]/workspaces si no es miembro.
  5. Renderiza Sidebar + TopBar + {children}.
export default async function WorkspaceLayout({
children,
params,
}: {
children: ReactNode;
params: Promise<{ workspaceId: string }>;
}) {
const { workspaceId } = await params;
// validación de membresía...
}

Listado de workspaces (app/[locale]/workspaces/page.tsx)

Sección titulada «Listado de workspaces (app/[locale]/workspaces/page.tsx)»

Página pública para usuarios autenticados. Muestra las tarjetas de cada workspace y permite navegar al workspace seleccionado.

/es/workspaces
/en/workspaces

Cuando el usuario no tiene workspaces, se muestra un estado vacío con un botón “Crear nuevo workspace”. También hay un botón al final del grid cuando ya existen workspaces.

Ambos botones abren un modal (components/workspace/CreateWorkspaceModal.tsx) con un formulario que pide:

  • Nombre (requerido)
  • Descripción (opcional)

Al enviar, la server action createWorkspaceAction en server/workspace/actions/workspace-actions.ts:

  1. Valida los datos con Zod
  2. Genera un slug único a partir del nombre
  3. Crea el workspace y al usuario como OWNER
  4. Redirige al dashboard del nuevo workspace

Componentes involucrados:

Archivo Propósito
components/workspace/CreateWorkspaceModal.tsx Modal con formulario, dos variantes: empty (botón inline) y grid (tarjeta dashed)
server/workspace/actions/workspace-actions.ts Server action createWorkspaceAction con validación Zod

Para desarrollo local, ejecutar el seeder de Prisma (desde la raíz del repositorio):

Ventana de terminal
cd syncro/apps/web
npx prisma migrate deploy
npx prisma db seed

Esto crea:

  • 5 usuarios (todos con contraseña demo1234): demo@syncro.app, maria@syncro.app, carlos@syncro.app, ana@syncro.app y pedro@syncro.app
  • Workspace “Proyecto Alpha”: con tablero (Por hacer → Completado), 9 tareas y 16 tareas de backlog
  • Workspace “Diseño UX”: con tablero (Descubrimiento → Entregado), 6 tareas y 12 tareas de backlog
  • Workspace “Marketing Digital”: con tablero (Pendiente → Publicado), 8 tareas y 12 tareas de backlog
  • 40 tareas de backlog en total, con las 4 prioridades, asignadas y sin asignar, y descripciones variadas

Los usuarios y workspaces no se duplican al re-ejecutar (upsert por email/slug). Para resetear datos: npx prisma migrate reset.

Ver documentación completa del seeder en Seeder.

Sección titulada «Sidebar (apps/web/components/layout/Sidebar.tsx)»

Barra lateral de navegación con las siguientes características:

  • Colapsable — Botón para colapsar/expandir (icono ChevronLeft/ChevronRight)
  • Iconos + texto — Cada item muestra un icono de lucide-react y su label
  • Indicador activo — El item de la ruta actual se resalta con color primary
  • Responsive — En mobile se oculta y se muestra como overlay con hamburger button
  • Links dinámicos — Cada link incluye el workspaceId: /workspaces/[workspaceId]/home
  • Animación — Transición suave de 300ms al colapsar
Ruta Icono Descripción
/home LayoutDashboard Inicio del dashboard
/kanban Columns3 Tablero Kanban
/calendar Calendar Calendario y horas
/teams Users Gestión de equipos
/chat MessageSquareText Chat
/settings Settings Ajustes

Bajo el nav principal, la sidebar lista los boards del workspace con CRUD inline:

  • Crear (+) → createBoardAction, redirige al nuevo board
  • Renombrar (lápiz) → input inline → renameBoardAction
  • Eliminar (papelera) → deleteBoardAction con confirmación
  • Cada board enlaza a /kanban/[boardId] y se resalta el activo

Requiere listBoardsAction para cargar el listado inicial.

TopBar (apps/web/components/layout/TopBar.tsx)

Sección titulada «TopBar (apps/web/components/layout/TopBar.tsx)»

Barra superior con:

  • Breadcrumb del workspace activo: Workspaces / Nombre del workspace
  • Toggle de idioma
  • Toggle de tema
  • Botón “Invitar” con dropdown: copiar enlace del workspace + placeholder para invitar miembros
  • Menú de usuario

Nota: El componente WorkspaceSelector fue eliminado. Ahora el selector de workspaces está integrado en la TopBar como un dropdown inline en el breadcrumb (workspaces / {nombre} ▾).

Sección titulada «Breadcrumbs (apps/web/components/layout/Breadcrumbs.tsx)»

Navegación jerárquica que ignora el prefijo workspaces/[workspaceId] y muestra solo los segmentos de página (home, kanban, settings, etc.).

WelcomeBanner (apps/web/components/dashboard/WelcomeBanner.tsx)

Sección titulada «WelcomeBanner (apps/web/components/dashboard/WelcomeBanner.tsx)»

Hero del dashboard con:

  • Saludo personalizado: “Bienvenido, {nombre}!”
  • Badge de estado de la aplicación
  • Subtítulo informativo

RoadmapSection (apps/web/components/dashboard/RoadmapSection.tsx)

Sección titulada «RoadmapSection (apps/web/components/dashboard/RoadmapSection.tsx)»

Grid de funcionalidades planificadas con:

  • RoadmapCard — Tarjeta con icono, título, descripción y badge de estado
  • Badge — Indicador visual del estado (planned/building/ready)

Solo chat sigue siendo un placeholder (WorkspacePlaceholder). El resto son funcionales:

Kanban (kanban/page.tsx y kanban/[boardId]/page.tsx)

Sección titulada «Kanban (kanban/page.tsx y kanban/[boardId]/page.tsx)»

Tablero Kanban completo con:

  • Drag & drop de tareas entre columnas con @dnd-kit y optimistic updates
  • CRUD de columnas: crear, renombrar inline, selector de colores, eliminar (mín. 3, máx. 7)
  • CRUD de boards desde la sidebar
  • Toolbar: búsqueda, filtros de prioridad/asignado, ancho, densidad, tamaño de letra
  • Prioridades, asignaciones con avatares, descripciones markdown y actividad

Ver documentación completa en Kanban Board y Backend del Kanban.

  • Lista las tareas del workspace sin columna (columnId: null)
  • CRUD de tareas de backlog con TaskFormDialog, ordenación por prioridad/asignado y búsqueda
  • Mover tareas al tablero desde AddBacklogTaskDialog
  • Dos tabs: Equipo (grid mensual con tareas programadas y horas por día) y Mi tiempo (imputación semanal)
  • Time tracking: TimeEntry, estimatedHours y métricas de desviación

Ver Calendario y horas y Backend del Kanban.

Gestión de miembros del workspace:

  • Lista con avatar, nombre, email y estadísticas (tasksCreated, tasksAssigned)
  • Roles editables por el OWNER (RoleBadgeSelect): OWNER / ADMIN / MEMBER
  • Añadir miembro por email (addMemberAction) con selector de rol, solo OWNER/ADMIN
  • Eliminar miembro con confirmación, solo OWNER/ADMIN
  • Leyenda de roles (crown/shield/user)
  • Formulario para editar nombre y descripción del workspace
  • URL del workspace (slug) visible pero no editable
  • Botón “Copiar enlace” que copia /{locale}/workspaces/{workspaceId}/home al portapapeles con feedback visual
  • Sección de configuración de equipo (rol por defecto y toggle de invitaciones)
  • Eliminar workspace: solo para rol OWNER, tipo “ELIMINAR” para confirmar (componente DeleteWorkspaceDialog)
  • Sección de “Zona de peligro” con acciones irreversibles

Disponible en dos lugares:

  • Settings: botón inline junto a la URL del workspace
  • TopBar: menú desplegable al hacer clic en “Invitar” → opción “Copiar enlace” con feedback de 2 segundos

Las páginas de perfil viven bajo el layout del workspace para mantener la UI consistente (sidebar, topbar, breadcrumbs), pero los datos del perfil pertenecen al usuario, no al workspace.

  • profile/page.tsx — Muestra la información del usuario logueado.
  • profile/edit/page.tsx — Formulario para editar el perfil. La server action editProfileAction actualiza el usuario globalmente y luego revalida la ruta del perfil.
  • profile/[id]/page.tsx — Vista pública del perfil de otro usuario.

Antes del refactor, el workspace activo se guardaba en una cookie (currentWorkspace) y el layout lo leía para saber en qué workspace estaba el usuario. Esto causaba problemas al abrir varias pestañas.

Después del refactor, el workspaceId forma parte de la URL. Esto permite:

  • Compartir URLs directas a un workspace.
  • Trabajar en varios workspaces simultáneamente sin conflictos.
  • Simplificar el layout: ya no necesita leer cookies.
Archivo Propósito
app/[locale]/workspaces/page.tsx Listado de workspaces
app/[locale]/workspaces/[workspaceId]/layout.tsx Layout dinámico con validación
components/layout/Sidebar.tsx Barra lateral colapsable y responsive
components/layout/TopBar.tsx Barra superior con breadcrumbs
components/layout/Breadcrumbs.tsx Migas de pan
components/workspace/CreateWorkspaceModal.tsx Modal de creación de workspace
components/workspace/DeleteWorkspaceDialog.tsx Diálogo de eliminación con type-to-confirm
components/kanban/KanbanBoard.tsx Tablero Kanban con DnD
components/kanban/KanbanToolbar.tsx Barra de filtros y controles de vista
components/kanban/KanbanColumn.tsx Columna dropeable del Kanban
components/kanban/TaskCard.tsx Card de tarea sortable
components/tasks/TaskFormDialog.tsx Modal de crear/editar tareas
components/kanban/ConfirmDialog.tsx Modal de confirmación reutilizable
components/kanban/TaskActivityDialog.tsx Historial de actividad de una tarea
components/workspace/MemberList.tsx Lista de miembros con roles y stats
components/calendar/CalendarGrid.tsx Grid mensual del equipo
components/calendar/MyTimeView.tsx Vista personal de imputación de horas
components/layout/WorkspacePlaceholder.tsx Placeholder para páginas en construcción
components/dashboard/WelcomeBanner.tsx Hero del dashboard
components/dashboard/RoadmapSection.tsx Grid de features planificadas
components/dashboard/RoadmapCard.tsx Tarjeta individual del roadmap
components/ui/Badge.tsx Etiqueta de estado