Skip to main content

Chat de tickets (features/whaticket)

Pantalla principal del agente y destino por defecto tras el login (/ redirige a whaticket/chat). Reúne en una sola vista la lista de tickets, el hilo de mensajes del contacto seleccionado, el compositor, el panel de datos del contacto y todas las acciones sobre el ticket. Esta página es el índice y la visión general; el detalle está repartido en páginas hermanas:

PáginaContenido
Lista de ticketsPestañas de estado, alcance, filtros, búsqueda, tarjetas, panel de datos del contacto, ventanas flotantes y vista de solo lectura
Hilo de mensajesCabecera, carga paginada, tipos de mensaje, menú contextual, selección y reenvío, destacados, visor de medios
Compositor y adjuntosTexto, emoji, respuestas rápidas, firma, nota interna, responder, adjuntos, audio, envío programado
Acciones del ticketLas 54 acciones del slice TicketActions y los 15 identificadores del menú, con efecto, endpoint y permiso
Tiempo real y estadoCómo la feature consume los sockets, el slice NgRx tickets y la resincronización
Etiquetas y datos del contactoPanel de etiquetas y metadatos, asignación rápida, barra de etiquetas, motivo de contacto

Ruta y guards​

CapaArchivoDefinición
Raízshared/routes/content.routes.tswhaticket con canActivate: [AuthGuard], carga WhaticketModule
Sub-rutawhaticket/whaticket-routing.module.ts'' redirige a chat; chat con permissionGuard y TICKET_READ, carga ChatModule
Páginawhaticket/chat/chat-routing.module.tsRuta vacía a ChatPageComponent con permissionGuard y TICKET_READ

WhaticketModule solo contiene el routing. ChatModule (chat/chat.module.ts) declara 18 componentes e importa OverlayModule, PortalModule, NgbTooltipModule, NgbModalModule, NgSelectModule, SwitchModule, TranslateModule y SharedModule; además importa como standalone ScheduleSendButtonComponent y ScheduledMessageStripComponent. El estado de la URL es ?chatId=<ticketId> (y highlightMessageId para el salto a un mensaje destacado).

Permisos de la feature​

Todos se aplican con *appShowWithPermission salvo que se indique otra cosa; el detalle de cada uno está en la página donde actúa.

AcrónimoDóndeEfecto
TICKET_READRutasEntrar a la pantalla
TICKET_FILTER_STATUS_OPEN, _IN_PROGRESS, _PENDING, _POSTPONED, _RESOLVED, _CLOSED, _CANCELLEDListaMostrar cada pestaña de estado (solo visualización)
TICKET_FILTER_SCOPE_MINE, _ALL, _UNASSIGNEDListaMostrar cada opción del selector de alcance
TICKET_FILTER_BY_AGENTListaFiltro por operador; habilita GET /tickets/filter-agents
TICKET_VIEW_AGENT_AVATARTarjetaInsignia con el avatar del agente asignado
TICKET_UPDATEMenú de accionesResolver, devolver, bloquear, transferir, posponer, cambiar estado
TICKET_DELETEMenú de accionesEliminar ticket
MESSAGE_CREATECompositorBotón de envío programado (junto con el indicador del tenant)
MESSAGE_DELETEMenú del mensajeEliminar un mensaje propio
CONTACT_UPDATEPanel de datos, etiquetasEditar contacto, asignar etiquetas, editar metadatos
LABEL_UPDATE, LABEL_DELETEPanel de etiquetasEditar o eliminar etiquetas del catálogo desde el panel

TICKET_UNLOCK_ANY existe pero actúa en Tickets bloqueados, no aquí. Los acrónimos de pestañas y alcance son solo un interruptor de visualización: el código lo aclara y el backend no los comprueba.

Archivos​

features/whaticket/
├── whaticket.module.ts, whaticket-routing.module.ts
├── chat/ # chat.module.ts, chat-routing.module.ts
├── pages/chat-page/ # barra de conexión + app-chat-list
└── components/chat/
├── chat-list/ # lista, tarjeta (chat-list-item), panel de datos del contacto
├── chat-conversation/ # hilo + compositor
├── ticket-actions-menu/ # menú de acciones del ticket
├── transfer-panel/, postpone-dialog/ (+ service), forward-tickets-panel/
├── labels-panel/, labels-quick-assign/ (+ overlay service y types), chat-labels-bar/
├── chat-filter-panel/, chat-popout/, chat-view-modal/
├── message-context-menu/, media-viewer/
├── schedule-message-dialog/ (+ service), schedule-send-button/, scheduled-message-strip/
└── contact-reason-modal/, contact-metadata-modal/, ticket-history-bar/

Fuera de la feature, la lógica de datos vive en: core/services/api/ticket.service.ts, message.service.ts, starred-message.service.ts, scheduled-message.service.ts, file-api.service.ts; core/services/ui/chat-socket.service.ts y los ayudantes chat-*.service.ts; core/states/ticket/* y core/states/scheduled-message/*; core/interfaces/api/ticket.interface.ts; AudioPlayerComponent (declarado en ChatModule pero ubicado en shared/components/audio-player).

Composición​

ChatPageComponent renderiza app-connection-status-bar (estado del socket con botón de reintento, que llama a ChatSocketService.connect con el _id del perfil) y app-chat-list. ChatListComponent hospeda la lista, la conversación activa (app-chat-conversation), el panel de datos del contacto y las ventanas flotantes. Los demás componentes se abren como overlays CDK o modales NgbModal desde la lista o la conversación.

Servicios y endpoints de la feature​

Rutas verificadas contra ticket.controller.ts y message.controller.ts; páginas de backend: Ticket, Message, Starred message, Contact, Label, Quick response, Departments y File. La tabla de endpoints de la página de Ticket del backend puede no listar todas las rutas de abajo.

ServicioPeticiónUso
TicketService.getTicketsGET /tickets/get-all (filtros en query)Lista, historial por contacto, panel de reenvío
TicketService.getTicketByIdGET /tickets/get-one/:idAbrir un ticket que no está en la lista
TicketService.getFilterableAgentsGET /tickets/filter-agentsFiltro por operador
TicketService.findAgentsForSelect, getAgentsGET /users/get-allPanel de transferencia
TicketService (acciones)Ver Acciones del ticket12 PATCH, un DELETE y un POST
MessageService.getContactMessagesGET /messages/:contactId (page, limit 20)Hilo: mensajes de todos los tickets del contacto
MessageService.getContactNotesGET /messages/:contactId con messageType=note (limit 10)Pestaña de notas
MessageService.deleteMessageDELETE /messages/remove/:idEliminar mensaje (MESSAGE_DELETE)
StarredMessageServicePOST /starred-messages/toggle/:messageId, GET /starred-messages/ids, GET /starred-messages/by-contact/:contactId, GET /messages/:id/windowDestacados y salto a mensaje
ScheduledMessageServicePOST /scheduled-messages/create, GET .../mine, GET .../by-ticket/:ticketId, PATCH .../update/:id, PATCH .../cancel/:idVer Mensajes programados
FileApiService.uploadPOST /files/upload (multipart, campo file)Adjuntos y audio
QuickResponseService.findPaginatedGET /quick-responses/get-all (search, ticketId)Autocompletado con /
LabelService, ContactService.assignLabels, updateContactGET /labels/get-all, PATCH /contacts/:id/assign-labels, PATCH /contacts/update/:idEtiquetas y metadatos

Los mensajes de texto, archivos y notas del agente no usan REST: se emiten por socket (send-message, send-file, send-note); ver Compositor.

Modelos principales​

core/interfaces/api/ticket.interface.ts:

TipoCampos o valores
TicketStatusopen, closed, inProgress, pending, postponed, resolved, cancelled
Ticket_id, identifier, status, tenantId, department?, contact?, assignedUser?, lastMessage?, unreadCount?, agentUnread?, postponedUntil?, reactivated? (solo UI), lockedBy?, lockedByUser?, connection? (channelType, name, phone?; nunca el token), createdAt, updatedAt
TicketContactdatos del contacto, labels, metadata, isBlocked, isActive, isOnline, lastSeen, lastDisconnectReason
TicketsFilterpage, limit, status, assignedUserId, assignedUserIds, unassigned, includeUnassigned, contactId, createdFrom, createdTo, hasUnread, lastMessage*, labelId, contactIsBlocked, contactIsActive, groupByContact, lockedOnly
TicketMenuActionIdresolve, resolveNoFarewell, return, transfer, postpone, cancelPostpone, markUnread, contactReasons, delete, statusOpen, statusInProgress, statusClosed, statusCancelled, lock, unlock
ChatConversationProyección de un ticket para la UI (userId es el _id del ticket; otherParticipantId es el contacto)

Canal en la UI​

La lista y el encabezado de la conversación dibujan el icono del canal del ticket (conversation.channelType) tomándolo de CONNECTION_CHANNELS (ver Iconos de canal y Conexiones). Si el ticket no tiene conexión no se dibuja icono: el código evita asumir web. El tooltip muestra connectionName o, en su defecto, el tipo de canal.

Estado de acuse de los mensajes propios​

Un mensaje propio muestra, según message.ack: un check simple (sent o sin valor), doble check (delivered), doble check azul (read) o un icono de exclamación rojo (failed) con tooltip del motivo (messages.failure.<motivo>). Ver Estado failed.

Enlaces clicables​

El texto de los mensajes y las leyendas de medios se renderizan con renderMessageMarkup, que activa linkify en renderWhatsappMarkup (ver Compartido).

Pruebas​

SpecCubre
whaticket-routing.module.spec.ts, chat/chat-routing.module.spec.tsAmbas rutas con permissionGuard y TICKET_READ
chat-list.component.spec.ts, chat-list-item.component.spec.ts, chat-filter-panel.component.spec.tsVer Lista de tickets
chat-conversation.component.spec.ts, message-context-menu, media-viewerVer Hilo
ticket-actions-menu, transfer-panel, postpone-dialog, ticket.*.spec.tsVer Acciones del ticket
schedule-*, scheduled-message-stripVer Compositor

No hay specs para labels-panel, labels-quick-assign, chat-labels-bar, forward-tickets-panel, contact-reason-modal, contact-metadata-modal, ticket-history-bar, chat-view-modal ni chat-page.

Gotchas​

  • Hay tres componentes sin uso en las plantillas de la rama: TicketHistoryBarComponent (declarado en ChatModule, nunca renderizado), ContactMetadataModalComponent (no está declarado en ningún módulo; su función la cubre el panel de etiquetas) y ContactReasonModalComponent (solo lo abre _handleResolveWithContactReason de ChatListComponent, un método privado que nadie invoca).
  • El hilo carga los mensajes por contacto (/messages/:contactId), no por ticket: se ven los mensajes de todos los tickets del contacto en un solo hilo.
  • El ítem "Motivos de contacto" del menú no abre el modal de motivo de contacto sino el panel de etiquetas y metadatos; ver Etiquetas.