Skip to main content

Respuestas rápidas (features/quick-responses)

CRUD de plantillas de mensaje con atajo (shortcut) asociadas a uno o varios departamentos: listado paginado en servidor con filtros, alta, edición, vista de solo lectura y activación o desactivación. Contraparte del backend: QuickResponse. El compositor del Chat consume estas plantillas; los departamentos se gestionan en Departamentos.

Ruta​

QuickResponsesModule se carga en shared/routes/content.routes.ts bajo quick-responses (PAGE_URLS.QUICK_RESPONSES) con canActivate: [AuthGuard, permissionGuard] y data: { permission: 'QUICK_RESPONSE_READ' }. QuickResponsesRoutingModule repite permissionGuard con el mismo permiso. Entrada de menú: quickResponses.titleSidebar, con permission: 'QUICK_RESPONSE_READ'.

Archivos​

ArchivoRol
quick-responses.module.ts / quick-responses-routing.module.tsDeclaran los cuatro componentes; importan ReactiveFormsModule, FormsModule, NgbModalModule, NgbTooltipModule, NgSelectModule, SharedModule
pages/quick-responses-page/quick-responses-page.component.*Compone shared-breadcrumb y quick-responses-table
components/quick-responses-table/quick-responses-table.component.*Tabla, paginación, filtros aplicados, modal y activar o desactivar; hospeda el filtro
components/quick-responses-filter/quick-responses-filter.component.*Filtro por atajo y estado
components/quick-response-modal-form/quick-response-modal-form.component.*Modal de alta, edición y vista
*.spec.tsSpecs de modal, filtro y tabla

Permisos​

AcrónimoEfecto
QUICK_RESPONSE_READRuta y menú
QUICK_RESPONSE_CREATEBotón "agregar"
QUICK_RESPONSE_UPDATEBotones "editar" y "activar / desactivar" por fila

El botón "ver" no tiene restricción adicional. El backend además define QUICK_RESPONSE_DELETE para DELETE remove/:id, que la UI no usa.

Servicios y endpoints​

QuickResponseService (core/services/api/quick-response.service.ts, providedIn: 'root') usa API_URLS.QUICK_RESPONSES (/quick-responses). Las mutaciones muestran toast de éxito con res.message (título quickResponses.title).

MétodoEndpointDetalle
findPaginated(page, limit, filter?)GET /quick-responses/get-allQuery page, limit más shortcut, isActive, y opcionalmente search y ticketId
create(data)POST /quick-responses/create
update(id, data)PATCH /quick-responses/update/:idid es el identifier, no el _id
toggleActive(id)PATCH /quick-responses/toggle-active/:idBody vacío; id es el identifier
remove(id)DELETE /quick-responses/remove/:idSin consumidores en la UI

Además, DepartmentService.getAll() alimenta el selector de departamentos del modal.

Fuera de esta feature, chat-conversation.component.ts llama findPaginated(1, 10, { search, ticketId }) para el selector de plantillas del compositor (escribiendo el atajo o desde el botón manual) y copia qr.message al mensaje; con ticketId el backend limita a plantillas activas del departamento del ticket (verificado en quick-response.service.spec.ts del backend).

:::note Modelo del backend QuickResponse describe un modelo con title y body y rutas REST simplificadas. El esquema real (quick-response/models) y el frontend usan identifier, shortcut, message, departmentIds e isActive, con rutas get-all, create, update/:id, toggle-active/:id y remove/:id. :::

Modelos​

core/interfaces/api/quick-response.interface.ts:

InterfazCampos
QuickResponse_id, identifier, shortcut, message, departmentIds: string[], isActive, createdAt?, updatedAt?
QuickResponseFormshortcut, message, departmentIds, isActive
QuickResponseFilterPartial<Omit<QuickResponseForm, 'departmentIds'>> más search?, ticketId?
QuickResponsePaginatedDataresults, meta { total, page, limit }

Constantes QUICK_RESPONSE_VALIDATIONS (core/helpers/global/quick-response.constant.ts): SHORTCUT 1 a 50 caracteres, MESSAGE 1 a 1000.

Listado y filtros​

Mismo patrón que Contactos: currentPage, currentLimit (10), currentFilter; ordenamiento local. Columnas: atajo (título móvil, ordenable), mensaje (subtítulo móvil; se muestra truncado a 25 con los pipes truncate y whatsappMarkup vía innerHTML), activo (insignia sí / no), creado y acciones. QuickResponsesFilterComponent guarda { shortcut, isActive } y emite el filtro con los mismos recortes y conversión a booleano que las demás features.

Formulario (QuickResponseModalFormComponent)​

CampoValidadores
shortcutrequired, minLength(1), maxLength(50)
messagerequired, minLength(1), maxLength(1000); editor app-rich-text-editor (5 filas) con maxLength 1000
departmentIdsrequired; ng-select múltiple con los departamentos (bindLabel name, bindValue _id)
isActivepor defecto true

En VIEW se deshabilita. En edición se llama update(quickResponse.identifier, payload).

Flujo​

  1. Abrir quick-responses: el guard comprueba QUICK_RESPONSE_READ y se pide la primera página.
  2. Filtrar: se vuelve a pedir la página 1.
  3. Alta o edición: modal → create / update → closed('saved') → recarga.
  4. Activar o desactivar: el botón de la fila llama toggleActive(identifier) y recarga la tabla (a diferencia de contactos o usuarios, que parchean la fila).

Estado, sockets y utilidades​

No usa NgRx ni sockets. Reutiliza DEFAULT_NGX_DATATABLE_CONFIG, BUTTON_ACTIONS, FORMAT_FOR_DATES, shared-tables-ngx-datatable, app-rich-text-editor y los pipes truncate y whatsappMarkup (ver Compartido).

Pruebas​

Tres specs de Karma/Jasmine: quick-response-modal-form.component.spec.ts (ADD, EDIT y VIEW: título, validación, llamadas a create / update), quick-responses-filter.component.spec.ts (armado del filtro y reinicio) y quick-responses-table.component.spec.ts (carga, filtros, paginación, onToggleActive, apertura del modal). No hay spec de QuickResponseService ni de la página.

Gotchas e inconsistencias​

  • Se usa identifier en update y toggleActive, mientras que contactos, etiquetas y usuarios usan _id; la fila lleva ambos.
  • El mensaje es texto plano con marcas de WhatsApp: app-rich-text-editor usa marcadores como * y _ y resalta con highlightWhatsappMarkup. La tabla lo renderiza con whatsappMarkup y el compositor del chat lo copia tal cual (qr.message).
  • El modal no controla isSubmitting; un doble clic puede duplicar la petición.
  • El botón de activar no pide confirmación.
  • QuickResponseService.remove y el permiso QUICK_RESPONSE_DELETE existen sin botón en la UI.
  • departmentIds es obligatorio en el formulario: una plantilla sin departamento no se puede guardar desde esta pantalla.