# ServiceManagement `ServiceManagement` is the backoffice module for Humand's **Service Management** product (a.k.a. "Help Desk" / service catalog). It lets admins configure a catalog of internal services, define the form an end-user fills to request each service, route those requests to agents, and monitor everything via metrics and CSAT. This README is a high-level map of the module: what it does, how the folders are organized, and where to look when you need to touch each feature. Project-wide conventions (component structure, hook naming, query keys, etc.) are assumed and are not repeated here — see the `HuLibraries` README for a deeper take on those conventions. --- ## Module map at a glance ``` ServiceManagement/ ├── ServiceItems/ → /service-management/catalog ├── NewServiceItem/ → /service-management/catalog/new | /catalog/:id/edit ├── AgentManagement/ → /service-management/agent-management (+ agents, help-desks, agent-groups) ├── Metrics/ → /service-management/metrics (rendered from the dashboard's metrics route) ├── components/ ← shared presentational components ├── hooks/ ← shared module-level hooks (config, permissions, snackbar, hydration) ├── services/ ← split by domain (agents, categories, metrics, module, reports, …) ├── types/ ← split by domain (agents, categories, metrics, pdf, questions, …) ├── utils/ ← split by domain (dates, dynamic forms, questions, validation, …) ├── constants.ts ← icons, banner colors, table columns, length limits ├── queries.ts ← React Query key factory: `serviceManagementKeys` └── routes.ts ← URL builders: `serviceManagementRoutes` ``` URL builders live in [`routes.ts`](routes.ts) and **must** be used instead of hardcoded strings: ```ts serviceManagementRoutes.base() // /service-management serviceManagementRoutes.serviceItems() // /service-management/catalog serviceManagementRoutes.newServiceItem() // /service-management/catalog/new serviceManagementRoutes.edit(id) // /service-management/catalog/:id/edit serviceManagementRoutes.agents() // /service-management/agent-management/agents serviceManagementRoutes.helpDesks() // /service-management/agent-management/help-desks serviceManagementRoutes.agentGroupCreate(hdId) // .../help-desks/:helpDeskId/agent-groups/new ``` --- ## Features ### 1. Service Items (catalog) — [`ServiceItems/`](ServiceItems/) The catalog of services available to end users. Each `ServiceItem` has: - **Identity & presentation** — name, optional description (plain + rich), automatic message, category, optional cover picture, banner color, tags. - **Status** — `DRAFT` / `ACTIVE` / `INACTIVE` (`ServiceItemStatus`) plus a `hidden` flag. - **Dynamic form** — addressed by `formTag`; either a regular sectioned form or a PDF-based form (see [Dynamic forms](#dynamic-forms)). - **Audience (`visibilityGroup`)** — who can **see and request** this service. Encoded as a [`SegmentationGroup`](types/collaborators.ts): either `all: true` (every user), or a combination of segmentation criteria + explicit user IDs. Driven by the wizard's `COLLABORATORS` step (`CollaboratorType.ALL_USERS` vs `CollaboratorType.SEGMENTATION_GROUP`) plus a `visible` flag for soft-hiding the item. - **Resolvers (`candidateResolverGroup`)** — who is eligible to **handle** the resulting tasks. Same `SegmentationGroup` shape, but populated from the wizard's `ASSIGNMENT` step. When the assignment points to an agent group, `candidateResolverGroup.agentGroupId` is set; otherwise the group enumerates the candidate agents (via segmentation and/or user IDs). `automaticAssignation` controls whether tasks are auto-assigned within that pool. - **SLAs** — optional `slaDefinitions` / `slaDefinitionIds` (only meaningful when `slaEnabled` is on at module level). What you'll find here: - `ServiceItems.tsx` — the catalog page: filters, search, table, pagination, configuration drawer. - `components/` — table, filters drawer, columns config drawer, categories sidebar, reorder drawer, new category drawer, color/icon pickers, skeletons. - `hooks/useCategories.ts` — fetching/reordering/CRUD over categories. - `form/schemas.ts` — zod schema for the filters form. Common entry points: - Create a service item → `serviceManagementRoutes.newServiceItem()` (opens the wizard). - Edit a service item → `serviceManagementRoutes.edit(id)`. - Filter the catalog → `ServiceFilters` form (status, tags, creators, date range). - Activate/deactivate/delete/duplicate → row actions in `ServicesTable`. - Reorder/create/edit categories → `CategoriesSidebar` + drawers. ### 2. New / Edit Service Item wizard — [`NewServiceItem/`](NewServiceItem/) A multi-step wizard for creating or editing a service item. Same screen for both flows; edit mode is signaled by a route param (`/catalog/:id/edit`). Detailed in [Wizard architecture](#wizard-architecture-newserviceitem) below. ### 3. Agent Management — [`AgentManagement/`](AgentManagement/) Hub page that splits into two sub-features: - **Agents** ([`Agents.tsx`](AgentManagement/Agents.tsx) + [`AgentProfile.tsx`](AgentManagement/AgentProfile.tsx)) — list and detail of users acting as agents. The profile shows the help desks and agent groups a given agent belongs to. - **Help Desks & Agent Groups** ([`HelpDesks.tsx`](AgentManagement/HelpDesks.tsx) + [`CreateOrEditAgentGroup.tsx`](AgentManagement/CreateOrEditAgentGroup.tsx)) — a help desk is a top-level container with coordinators; under it live agent groups, each with a name, description, status, an assignment strategy and a roster of agents. Key types ([`types/agents.ts`](types/agents.ts)): - `HelpDesk`, `HelpDeskCreateRequest`, `AgentGroup`, `AgentGroupCreateRequest`, `AgentGroupForm`, `AgentProfile`, `HydratedUser`. - `AgentGroupAssignmentType`: `MANUAL` | `ROUND_ROBIN` | `WORKLOAD` — defines how new tasks are distributed across the group's agents. - `AgentGroupChangeType`: `CREATED` | `EDITED` | `ACTIVATED` | `DEACTIVATED` — used in the audit/event log. The hub page redirects to an "activate module" card if `stateMachineEnabled` is `false` in the module configuration. See [Module configuration](#module-configuration). ### 4. Metrics — [`Metrics/`](Metrics/) Dashboard for service-level metrics and CSAT. Sits behind the `VIEW_METRICS` permission (see [Permissions](#permissions)). What's there: - `Metrics.tsx` — the page: filter pills, filters drawer, KPI cards, charts, CSAT table. - `components/` - `ServiceItemsStateChart` (+ skeleton) — distribution of tasks by state. - `CsatChart`, `CsatTable` (+ skeletons) — CSAT score breakdown and individual responses. - `MetricFiltersControls`, `MetricFiltersDrawer`, `FilterPills` — filter UI. - `DownloadCsatReportDrawer`, `InfoCard`, `FormSwitchCardItem`. - `form/yupSchemas.ts` — yup schemas for filters and CSAT report download forms. - `hooks/useMetrics.tsx` — orchestrates the metrics + CSAT queries, increments a `filtersVersion` to bust the React Query cache when filters change. - `hooks/useInfiniteServiceItems.ts` — paginated autocomplete for the "service items" filter. Filters ([`types/metrics.ts`](types/metrics.ts) — `MetricFiltersForm`): - Date range (last 7 / 14 / 30 days, or custom range). - Service items (multi-select, paginated). Reports — `DownloadCsatReportDrawer` lets a user with `DOWNLOAD_CSAT_REPORT` request a CSAT report by email. Service-level reports are also available behind `DOWNLOAD_SERVICES_REPORT`. ### 5. Categories Categories are not a top-level page; they live inside the catalog (`ServiceItems/`) and are managed through: - The categories sidebar in `ServiceItems.tsx`. - Drawers: `NewCategoryDrawer`, `ReorderCategoriesDrawer`. - A dedicated route segment: `/service-management/catalog/categories/:id` (filters the catalog by that category). A category has a name (1–30 chars), an icon (`CategoryIcon`, mapped to a Tabler icon in [`constants.ts`](constants.ts)) and a position. The instance-level "category order" is either alphabetical or custom (`CategoriesOrder` in [`types/module.ts`](types/module.ts)). --- ## Wizard architecture (`NewServiceItem/`) The wizard drives both creation and edition through five steps, declared in `Step` ([`types/wizard.ts`](types/wizard.ts)): | Step | Field key in the form | What it captures | |---|---|---| | `BASIC_INFORMATION` | `basic_information` | Name, description, rich description, category, automatic message, cover picture. | | `FORM` | `form` | The dynamic form attached to this service item. Either `Section[]` (regular) or a `PdfSection` (PDF-based). | | `ASSIGNMENT` | `assignment` | Agents and/or agent group assigned to handle requests for this service. | | `COLLABORATORS` | `collaborators` | Audience: who can request this service (`ALL_USERS` or `SEGMENTATION_GROUP` with criteria) and visibility flag. | | `REVISION` | `final_revision` | Read-only summary before saving. | The whole wizard is one big `react-hook-form` form. Field paths are built through the typed factory in [`forms.ts`](NewServiceItem/forms.ts) (`newServiceItemFields`) — never hardcode field paths. ``` NewServiceItem.tsx ├── FormProvider (single form instance for all steps) ├── SidebarNavigation → step list + completion status ├── → renders the active step │ ├── BasicInformation/ │ ├── FormCreation/ → router into Regular vs Pdf sub-flows │ │ ├── Regular/CreateForm.tsx ← + FormCreationProvider │ │ └── pdf/PdfCreation.tsx ← + PdfCreationProvider │ ├── Assignment/ │ ├── Collaborators/ │ └── Revision/ └── StepFooter → next/back/save buttons ``` ### Form creation contexts Because the form-building UX is large and stateful, the `FORM` step has its own React contexts under [`contexts/`](NewServiceItem/contexts/): - **[`FormCreation`](NewServiceItem/contexts/FormCreation.tsx)** (regular forms): keeps track of `selected` (current section/question), expanded sections, side-menu state, and exposes mutators that operate on the underlying `react-hook-form` field array (`createSection`, `duplicateSection`, `deleteSection`, `createQuestion`, `deleteQuestion`, `duplicateQuestion`, `createQuestionChoice`, `deleteQuestionChoice`, …). - **[`PdfFormCreation`](NewServiceItem/contexts/PdfFormCreation.tsx)** (PDF-based forms): manages placed fields on top of a PDF — adding/removing/duplicating fields, drag state, page scale, current page, scroll/zoom, choice management on selection-style fields, font-size constraints, etc. These contexts only exist while the user is in the `FORM` step. ### Validation `utils/serviceItemValidation.ts` exposes step-by-step predicates used both to gate the "Next" button and to compute the `SidebarNavigation` completion state: - `isValidBasicInformation` - `isValidForm` / `isValidPdfForm` - `isValidAgentAssignment` - `isValidCollaborators` - `isValidServiceItemName`, `isValidName`, `isValidPdfField` - `isEmptyForm`, `dynamicFormHasChanges`, `getServiceItemDirtyCheckSnapshot` (used to decide if a "discard changes" modal is needed when leaving the wizard). --- ## Dynamic forms Each service item has a **dynamic form** attached. There are two flavors, captured by `DynamicFormType` (from `src/types/dynamicForms`) and selected in the `FORM` step: ### Regular forms — `Section[]` of `Question[]` A regular form is a list of sections, each with a list of questions. Question types ([`types/questions.ts`](types/questions.ts)) are grouped into four families: | Group | Types | |---|---| | **General** | `TEXT`, `DATE`, `TIME`, `PHONE`, `INTEGER`, `FLOAT` | | **Information** | `AUTOCOMPLETE` (binds to a profile field), `INFO` (read-only block) | | **Interaction** | `SIGNATURE`, `FILE`, `STAR_RATING` | | **Choice** | `MULTIPLE_CHOICE` (1 selection), `CHECKBOX` (n selections), `DROPDOWN` | Choice questions support **branching**: a choice can declare `sectionIfChosen`, in which case answering that choice jumps the user to a specific section (or the special `NEXT_SECTION_ID` sentinel). The same applies at section level via `goToOnFinish`. UI for picking and editing question types lives under [`NewServiceItem/components/QuestionMenu/`](NewServiceItem/components/QuestionMenu) (the side panel) and [`NewServiceItem/components/Questions/`](NewServiceItem/components/Questions) (the per-type editors: `Selection/`, `Autocomplete/`, `Attachments/`, plus generic ones). ### PDF-based forms — `PdfSection` with placed fields For services that need a PDF document filled out (signed waivers, forms, etc.), the user uploads a PDF and places fields on top of it. Field types ([`types/pdf.ts`](types/pdf.ts)): - `TEXT`, `NUMBER` (frontend-only — maps to `INTEGER` or `FLOAT` based on the "whole/float" config), `DATE`, `SIGNATURE`, `DROPDOWN`, `AUTOCOMPLETE`, `MULTIPLE_CHOICE`, `CHECKBOX`. Each `PdfPlacedField` carries normalized coordinates (`x`, `y`, `width`, `height` in `[0..1]`), the page index (0-based), required/validation flags, and type-specific config (font, dateFormat, choices, min/max, profileFieldId, …). The PDF editor is fully owned by `PdfFormCreation` context and the components under [`NewServiceItem/components/FormCreation/pdf/`](NewServiceItem/components/FormCreation/pdf): `PdfFieldEditor`, `PlacedFields/`, `Configuration/` (per-type config cards), `utils/geometry.ts`, `utils/pdfInspection.ts`. ### Server side Dynamic forms are loaded/saved through [`useDynamicForm`](NewServiceItem/hooks/useDynamicForm.tsx). They are addressed by a `formTag` string (one per service item) and the conversion between the wizard's form state and the server's `DynamicForm` shape is handled in `utils/dynamicForm.ts` and `utils/questions.ts`. --- ## Module configuration A **single** instance-level configuration object drives several module-wide toggles ([`types/module.ts`](types/module.ts) — `ModuleConfiguration`): | Field | Meaning | |---|---| | `instanceId` | The instance this config belongs to. | | `coverColor` | Banner color used across the module (`BannerColor`). | | `stateMachineEnabled` | Whether the module is "activated" (default states have been seeded). When `false`, all sub-pages render an `ActivateModuleCard` instead of their content. | | `slaEnabled` | Whether SLAs are enforced for this instance. | | `csatEnabled` | Whether CSAT surveys are enabled. | | `categoryOrderBy` | `ALPHABETICAL` (`'NAME'`) or `CUSTOM` (`'CUSTOM_POSITION'`). | It's loaded and mutated through [`hooks/useModuleConfiguration.tsx`](hooks/useModuleConfiguration.tsx): - `moduleConfiguration` — current value. - `moduleActivated` — alias of `stateMachineEnabled ?? false`. - `updateConfigurationMutation` — partial update (used by `ConfigurationDrawer` and similar). - `createDefaultStatesMutation` — seeds default states; this is what the `ActivateModuleCard` button triggers. There is also a **per-user** configuration ([`ServiceManagementUserConfiguration`](types/serviceItem.ts)) that stores UI preferences such as which catalog table columns the user has hidden — see `serviceTableDisabledColumns` in `serviceManagementKeys`. --- ## Permissions The module exposes four roles via `ServiceManagementRole` (`ADMIN`, `INITIATOR`, `AGENT`, `COORDINATOR`). For UI-level checks, use [`hooks/useServiceMgmtPermissions.tsx`](hooks/useServiceMgmtPermissions.tsx). It returns boolean flags backed by the project-wide `UserPermissions`: | Flag | Backed by | |---|---| | `canViewMetrics` | `VIEW_METRICS` | | `canDownloadCsatReport` | `DOWNLOAD_CSAT_REPORT` | | `canDownloadServiceItemsReport` | `DOWNLOAD_SERVICES_REPORT` | | `canManageCategories` | `MANAGE_CATEGORIES` | | `canCreateServiceItems` / `canEditServiceItems` / `canDeleteServiceItems` | `CREATE_SERVICES` / `EDIT_SERVICES` / `DELETE_SERVICES` | | `canCreateAgents` | `SERVICE_MANAGER_CREATE_AGENTS` | | `canCreateAgentGroupsAndDesks` / `canEditAgentGroupsAndDesks` / `canDeleteAgentGroupsAndDesks` | `CREATE_AGENTS_GROUPS_DESKS` / `EDIT_GROUPS_DESKS` / `DELETE_GROUPS_DESKS` | | `canCreateWorkflows` / `canEditWorkflows` / `canDeleteWorkflows` | `CREATE_WORKFLOWS` / `EDIT_WORKFLOWS` / `DELETE_WORKFLOWS` | Always go through this hook instead of calling `hasAllPermissions` directly inside components — it keeps the permission ↔ UI mapping in one place. --- ## Shared building blocks ### Shared components — [`components/`](components/) - `ContainerLayout` — page-level shell used by most sub-pages. - `NavTitleCard` — large clickable card used in the `AgentManagement` hub. - `ActivateModuleCard` — empty-state card shown when `moduleActivated` is `false`. - `TableCellOverflowTooltip` — tooltip helper for ellipsised table cells. ### Shared hooks — [`hooks/`](hooks/) - `useModuleConfiguration` — see [Module configuration](#module-configuration). - `useServiceMgmtPermissions` — see [Permissions](#permissions). - `useUserHydration` / `useAgentGroupHydration` — turn lists of IDs into fully-hydrated `User` / `AgentGroup` objects (used in the Assignment step and in agent forms). - `useElementRect` — generic ResizeObserver hook for measuring DOM nodes. ### Types — [`types/`](types/) Split by domain and re-exported from `types/index.ts`: - `agents.ts` — Agents, Help Desks, Agent Groups, group events, hydrated users. - `categories.ts` — categories and category icons. - `collaborators.ts` — audience model: `CollaboratorType`, `Segmentation`, `SegmentationGroup`. - `common.ts` — small shared primitives. - `metrics.ts` — metric filters, CSAT model, date-range options, autocomplete items. - `module.ts` — `ServiceManagementRole`, `BannerColor`, `ViewportType`, `CategoriesOrder`, `ModuleConfiguration`. - `pdf.ts` — `PdfFieldType`, `PdfPlacedField`, `PdfSection`, `PdfFieldConfig`, page dimensions. - `questions.ts` — `QuestionType`, `Question` variants, `Section`. - `reports.ts` — CSAT report download payloads. - `serviceItem.ts` — `ServiceItemStatus`, `TaskType`, `RequestStatus`, `ServiceItemDraft`, `ServiceParams`, SLA definitions, user table-config. - `tags.ts` — service tags. - `wizard.ts` — `Step`, `SectionCreationSteps`, wizard payloads. ### Utils — [`utils/`](utils/) Split by domain and re-exported from `utils/index.ts`: - `agents.ts`, `category.ts`, `collaborators.ts` — domain helpers. - `date.ts` — date formatting / range helpers used across catalog and metrics. - `dynamicForm.ts` — convert between wizard form state and `DynamicForm` API shape. - `metrics.ts` — derived numbers for the metrics page (averages, totals, distribution). - `questions.ts` — duplicate/reorder helpers, `isChoiceQuestion`, etc. - `reports.ts` — CSAT/service report payload builders. - `serviceItemDraft.ts` — `ServiceItemDraftFormData` ↔ API translation. - `serviceItemStatus.ts` — status transitions. - `serviceItemValidation.ts` — wizard-step validity predicates (see [Validation](#validation)). - `staticQuery.ts` — small helpers for filter parameter parsing. ### Query keys & API API calls live in [`services/`](services/), split by domain and re-exported from `services/index.ts`: - `agents.ts` — agents, help desks and agent groups CRUD (mirrors `types/agents.ts`). - `categories.ts` — categories CRUD and custom ordering. - `metrics.ts` — task and CSAT metrics, CSAT responses. - `module.ts` — module configuration and default states bootstrap. - `reports.ts` — service item, certificate, and CSAT report downloads. - `serviceItem.ts` — service items CRUD, states, and service-table user config. - `tags.ts` — tag CRUD and resource linking. Query keys are centralized in [`queries.ts`](queries.ts) under `serviceManagementKeys`: ``` service-management ├── configuration │ └── service-table-disabled-columns ├── service-items / detail / list / listByName / tags ├── categories / list ├── dynamic-forms / detail ├── agents / list / infiniteList / profile ├── help-desks / list ├── metrics / service-items / csat / csat-responses ├── agent-groups / list / detail / events ├── states └── audience / count / users / selectedUsers / collaborators / selectedCollaborators ``` Always invalidate from the highest sensible level: `serviceManagementKeys.all()` invalidates everything, `serviceManagementKeys.serviceItems.all()` invalidates the catalog, etc. --- ## Where do I touch X? | I want to… | Start here | |---|---| | Add a new step to the wizard | `types/wizard.ts` (`Step`), `NewServiceItem/forms.ts`, `NewServiceItem/components/SidebarNavigation.tsx`, `NewServiceItem.tsx` (step rendering), `utils/serviceItemValidation.ts`. | | Add a new question type | `types/questions.ts` (`QuestionType`), `NewServiceItem/components/QuestionMenu/SideMenu/`, `NewServiceItem/components/Questions/`, `utils/questions.ts`, `utils/dynamicForm.ts`. | | Add a new PDF field type | `types/pdf.ts` (`PdfFieldType`), `NewServiceItem/components/FormCreation/pdf/Configuration/`, `NewServiceItem/components/FormCreation/pdf/PlacedFields/`, `NewServiceItem/contexts/PdfFormCreation.tsx`. | | Add a column to the catalog table | `constants.ts` (`SERVICE_TABLE_COLUMNS`, `SERVICE_TABLE_COLUMN_TRANSLATION_KEYS`, `FIXED_COLUMNS`), `ServiceItems/components/ServicesTable.tsx`, `ServiceItems/components/ColumnConfigDrawer.tsx`. | | Add a metric / CSAT chart | `types/metrics.ts`, `Metrics/hooks/useMetrics.tsx`, `Metrics/components/`, `queries.ts` (`metrics.*`). | | Add a permission flag | `useServiceMgmtPermissions` (after registering it in `src/utils/permissions`). | | Add a module-level setting (toggle, color, …) | `types/module.ts` (`ModuleConfiguration`), `useModuleConfiguration`, `ServiceItems/components/ConfigurationDrawer.tsx`. | | Add a new agent assignment strategy | `types/agents.ts` (`AgentGroupAssignmentType`), `AgentManagement/CreateOrEditAgentGroup.tsx`. |