Skip to main content

Etiquetas, metadatos y motivo de contacto

Componentes de la pantalla de Chat de tickets que gestionan lo que se sabe del contacto: las etiquetas (catálogo en Etiquetas, backend Label), los metadatos libres y el motivo de contacto del ticket. Las etiquetas y los metadatos pertenecen al contacto (no al ticket); ver Contactos y Contact.

Archivos​

ArchivoRolEstado
components/chat/chat-labels-bar/chat-labels-bar.component.*Barra de chips bajo la cabecera de la conversaciónEn uso
components/chat/labels-quick-assign/labels-quick-assign.component.*, labels-quick-assign-overlay.service.ts, labels-quick-assign.types.tsSelector rápido anclado a la barraEn uso
components/chat/labels-panel/labels-panel.component.*Panel completo de etiquetas y metadatos (acción "Motivos de contacto")En uso
components/chat/contact-reason-modal/contact-reason-modal.component.*Modal para registrar el motivo de contacto del ticketDeclarado, sin llamador activo
components/chat/contact-metadata-modal/contact-metadata-modal.component.*Modal solo de metadatosNo declarado en ningún módulo ni usado
components/chat/ticket-history-bar/ticket-history-bar.component.*Barra horizontal de tickets previosDeclarado, nunca renderizado
core/helpers/ui/labels.constant.tsLABELS_PAGE_LIMIT = 10, DEFAULT_LABEL_COLOR = '#6366f1'

Servicios y endpoints​

LlamadaPeticiónUso
LabelService.findLabelsPaginated(page, limit, filter)GET /labels/get-all (isActive: true, name si hay búsqueda)Catálogo paginado en los tres componentes
LabelService.createLabelPOST /labels/createCrear desde el selector rápido
LabelService.updateLabelPATCH /labels/update/:idEditar nombre y color en el panel
LabelService.removeLabelDELETE /labels/remove/:idEliminar del catálogo desde el panel
ContactService.assignLabels(contactId, labelIds)PATCH /contacts/:id/assign-labels con { labelIds }Reemplaza el conjunto de etiquetas del contacto
ContactService.updateContact(contactId, { metadata })PATCH /contacts/update/:idGuarda los metadatos
TicketService.createContactReason(ticketId, data)POST /tickets/contact-reason/:id con { labels?, description? }Solo desde el modal de motivo de contacto

Barra de etiquetas (ChatLabelsBarComponent)​

Muestra las etiquetas del contacto como chips (punto de color, nombre y, si existe, descripción). Con CONTACT_UPDATE (LABELS_ASSIGN_PERMISSION) añade el botón de gestión: si no hay etiquetas, un botón "agregar la primera"; si las hay, un +. Sin el permiso muestra los chips en solo lectura (o nada si no hay). Emite quickAssign con el elemento ancla. ChatConversationComponent.onLabelsQuickAssign arma un LabelsQuickAssignRequest (anchor, contactId del contacto, currentLabels) y lo emite hasta la lista, que lo atiende con LabelsQuickAssignOverlayService.

Asignación rápida (LabelsQuickAssignComponent)​

Overlay anclado a la barra (se cierra con clic fuera o Escape) abierto por LabelsQuickAssignOverlayService.open(request), que devuelve un observable con el conjunto confirmado de etiquetas.

  • Lista paginada (10 por página, scroll infinito, búsqueda con debounce de 300 ms) con casilla por etiqueta activa; enfoca el buscador al abrir.
  • Alternar una etiqueta persiste el conjunto completo de inmediato (assignLabels) y revierte el cambio local si falla.
  • Crear y asignar: si el texto de búsqueda no coincide exactamente con ninguna etiqueta, aparece "crear" (requiere LABEL_CREATE); crea la etiqueta activa con el color por defecto y la asigna.
  • Tras cada guardado emite saved con las etiquetas del contacto; la lista las aplica de forma optimista en los tickets en memoria (applyLabelsOptimistically) y recarga.

Panel completo (LabelsPanelComponent)​

Se abre como overlay centrado desde la acción de menú "Motivos de contacto" (contactReasons), con las etiquetas y los metadatos actuales del contacto del ticket.

  • Etiquetas del contacto: bloque de seleccionadas (chips) y lista paginada solo con las no seleccionadas (10 por página, búsqueda con debounce de 300 ms); si una página entera ya está seleccionada, pide la siguiente automáticamente para no dejar el scroll vacío.
  • Gestión del catálogo en línea: editar nombre y color de una etiqueta (LABEL_UPDATE, PATCH /labels/update/:id) y eliminarla (LABEL_DELETE, confirmación y DELETE /labels/remove/:id; también la saca de la selección).
  • Metadatos: lista de pares nombre y descripción libres; agregar (CONTACT_UPDATE, requiere nombre) y quitar. Son los que la lista muestra en "Información adicional".
  • Guardar (visible con CONTACT_UPDATE o LABEL_UPDATE): ejecuta en paralelo assignLabels y updateContact({ metadata }) con forkJoin; en éxito emite updated (la lista recarga) y cierra.

Modal Ng estático (sin cierre por teclado ni clic fuera). Entradas: ticketId y requirement (none, optional o required, el campo contactReasonRequirement del departamento; ver Departamentos). Selector múltiple de etiquetas activas (20 por página, búsqueda con debounce) y descripción de hasta 500 caracteres. Con requirement === 'required' exige al menos una etiqueta y una descripción no vacía; en los otros casos siempre se puede guardar. Guarda con POST /tickets/contact-reason/:id y cierra devolviendo 'saved'.

El backend (TICKET_UPDATE) crea un registro con el departamento del ticket, las etiquetas y la descripción. El único llamador es ChatListComponent._handleResolveWithContactReason, que según el departamento del ticket abriría este modal antes de resolver (obligatorio, opcional o sin modal); ese método es privado y no se invoca desde ningún flujo de la rama, de modo que en la práctica el modal no se abre y el requisito del departamento no se aplica al resolver.

Metadatos y barra de historial sin uso​

  • ContactMetadataModalComponent (entradas contactId y currentMetadata; salidas close y saved) permite agregar y quitar pares y guardarlos con updateContact; su función la cubre hoy el panel de etiquetas y no está declarado en ChatModule.
  • TicketHistoryBarComponent (entradas tickets, activeTicketId, isLoadingMore, hasMore; salidas ticketSelect, loadMore) es una barra horizontal con paginación por scroll lateral y el estado, el agente y un extracto del último mensaje de cada ticket. Está declarado en ChatModule pero ninguna plantilla lo usa; el historial por contacto se ve hoy en la pestaña "history" del panel de datos.

Pruebas​

No hay specs para chat-labels-bar, labels-quick-assign, labels-panel, contact-reason-modal, contact-metadata-modal ni ticket-history-bar. La visibilidad por permiso de las pestañas y el flujo de edición de contacto de la lista están cubiertos en chat-list.component.spec.ts (ver Lista de tickets).

Gotchas​

  • La acción "Motivos de contacto" del menú abre el panel de etiquetas y metadatos, no el modal de motivo de contacto ni llama a POST /tickets/contact-reason/:id.
  • El panel de etiquetas edita y elimina etiquetas del catálogo del tenant, no solo las del contacto: la edición y el borrado afectan a la etiqueta compartida (ver Etiquetas).
  • Las etiquetas del panel y del selector rápido se asignan reemplazando el conjunto completo del contacto (assignLabels recibe todos los ids), no añadiendo una a una.