# 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
├── <step component>                 → 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`. |
