Estado global con NgRx
core/states/app.state.ts registra ocho slices en StoreModule.forRoot(ROOT_REDUCERS) y sus efectos en EffectsModule.forRoot(ROOT_EFFECTS). Cada slice vive en core/states/<slice>/ con *.actions.ts, *.reducers.ts, *.effects.ts y *.selectors.ts.
Clave de AppState | Carpeta | Contenido |
|---|---|---|
theme | states/theme | Tema light-only / dark-only; persiste en localStorage (clave Theme); por defecto light-only |
language | states/language | Idioma activo (es / en) |
auth | states/auth | user, message, loading; sesión y login |
tickets | states/ticket | Lista de tickets, paginación, filtro activo |
departments | states/departments | Departamentos (CRUD) |
internalChat | states/internal-chat | Conversaciones, agentes, miembros y mensajes del chat interno |
scheduledMessages | states/scheduled-message | Mensajes programados (mis envíos, por ticket) |
settings | states/settings | Ajustes del tenant (TenantSettings) |
auth
UserActions (auth.actions.ts) cubre: loadUserSession, userAuthenticationRequest/Success/Failure, frameAuthenticateRequest, preAuthenticateUser, preAuthenticationSuccess, userLogout y completeUserLogout. Los efectos (auth.effects.ts):
loadUserSession$: leeUSER_SESSIONdel storage cifrado; si hay token llama agetMeUser()(GET /users/get-me) y emiteuserAuthenticationSuccess; si falla, limpia la sesión.loginUser$:POST /auth/login, guarda{ token }, consultaget-me, guarda el usuario completo y navega a/whaticket/chat.frameLogin$:POST /auth/frame-loginpara el modo iframe (ver Frame); en error navega a/auth/reconnect.logoutUser$:AuthService.logout()(borra la sesión y navega a login).
Selectores relevantes: selectUser, selectUserId, selectLoading, selectErrorMessage y selectScheduledMessagesEnabled, que lee user.featureFlags.scheduledMessagesEnabled del perfil (get-me) y es false hasta que carga el usuario; no depende del slice settings, que requiere permiso SETTINGS_READ.
language
Al terminar la autenticación (userAuthenticationSuccess), LanguageEffects.tenantAuthenticatedLanguage$ aplica user.tenantPreferences.language si es es o en; en otro caso es. Ver i18n y tema.
tickets
Es el slice más grande: 54 acciones en ticket.actions.ts. Estado (TicketState):
{ tickets, totalCount, currentPage, hasMore, isLoading,
isInitialLoad, isLoadingMore, error, activeFilter }
Familias de acciones:
| Familia | Acciones |
|---|---|
| Carga | loadTickets, loadMoreTickets, resetTickets (y Success/Failure) |
| Acciones de agente | resolveTicket, resolveNoFarewellTicket, returnTicket, unassignTicket, transferTicket, postponeTicket, cancelPostponeTicket, deleteTicket, changeTicketStatus, markUnread |
| Bloqueo ("Mantener conmigo") | lockTicket, unlockTicket, ticketLockChangedFromSocket, ticketLockConflict |
| Desde socket | ticketUpdatedFromSocket, ticketAssignedFromSocket, ticketStatusChangedFromSocket, ticketReactivatedFromSocket, ticketDeletedFromSocket, contactPresenceChangedFromSocket |
| No leídos / acuse | ticketIncrementUnread, ticketClearUnread, ticketLastMessageAckChanged |
Los efectos (ticket.effects.ts) llaman a TicketService (/tickets/...) para cada acción y despachan las acciones Success / Failure correspondientes. Los eventos de socket se vuelcan al store directamente desde ChatSocketService (ver Sockets).
Cambios de la rama feat/meta_connections en este slice
ticketUpdatedFromSocketincorporamessageId?yack?; el reducer los copia enlastMessage(_idyack) cuando vienen.- Nueva acción
ticketLastMessageAckChanged({ ticketId, messageIds, ack }): el reducer actualizalastMessage.acksolo si el_iddel último mensaje está enmessageIds. Se despacha desdeChatListComponenten cadamessage_ack_changed, lo que permite que la lista pinte el estado failed del último mensaje (ver Estado failed).
internalChat, scheduledMessages, settings, departments
internalChat:loadConversations,loadAgents,loadMembers,loadMessages,loadMoreMessages,resetMessages,leaveConversation, altas/bajas de miembros. Se carga al entrar al layout autenticado.scheduledMessages:loadMine,loadByTicket,create,cancel,reset.settings:loadSettings/loadSettingsSuccess/loadSettingsFailure; el comentario desettings.actions.tsindica que se creó porque no existía un slice de ajustes del tenant (la página de settings los pedía por HTTP).departments: CRUD conLoad,Create,Update,Deletey susSuccess/Failure.
Qué no está en NgRx
Conexiones, contactos, usuarios, etiquetas, respuestas rápidas, roles/permisos y dashboard se consultan por HTTP desde sus tablas o servicios, sin slice. El estado de la sesión de WhatsApp de una conexión se mantiene en el componente ConnectionsTableComponent a partir del socket (ver Conexiones Meta).