|
| 1 | +# CC Components Library |
| 2 | + |
| 3 | +## AI Agent Routing (Do Not Start Here) |
| 4 | + |
| 5 | +If you are an AI assistant or tool reading this file **as your first entry point**, do **not** start your reasoning or code generation workflow from here. |
| 6 | + |
| 7 | +- **Primary entrypoint:** Always begin with the **nearest parent** contact-center AI docs `AGENTS.md` (for example, the root `ai-docs/AGENTS.md` at the repository root). |
| 8 | +- **Process:** |
| 9 | + - Load and follow the instructions and templates in that parent `AGENTS.md`. |
| 10 | + - Only after a parent `AGENTS.md` explicitly routes you to this file should you treat this document as package-specific guidance. |
| 11 | +- **Never** skip the parent `AGENTS.md` even if the user prompt directly mentions this specific package or file. |
| 12 | + |
| 13 | +Once you have gone through the parent `AGENTS.md` and been routed here, you can use the rest of this file as the authoritative reference for the `@webex/cc-components` library. |
| 14 | + |
| 15 | +## Overview |
| 16 | + |
| 17 | +The CC Components library is a shared React component library that provides presentational components for building contact center widgets. It contains all the UI components used by widgets like StationLogin, UserState, TaskList, CallControl, and more. These components are built using Momentum UI and follow a consistent design system. |
| 18 | + |
| 19 | +**Package:** `@webex/cc-components` |
| 20 | + |
| 21 | +**Version:** See [package.json](../package.json) |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +## Why and What is This Library Used For? |
| 26 | + |
| 27 | +### Purpose |
| 28 | + |
| 29 | +The CC Components library serves as the presentation layer for contact center widgets. It: |
| 30 | +- **Provides reusable UI components** for all contact center widgets |
| 31 | +- **Maintains consistent design** using Momentum UI components |
| 32 | +- **Separates presentation from business logic** following best practices |
| 33 | +- **Integrates metrics tracking** via the ui-logging package |
| 34 | +- **Exports type definitions** for TypeScript support |
| 35 | + |
| 36 | +### Key Capabilities |
| 37 | + |
| 38 | +- **Component Library**: Pre-built, tested UI components for common contact center scenarios |
| 39 | +- **Momentum UI Integration**: Built on top of @momentum-ui/react-collaboration |
| 40 | +- **Type Safety**: Full TypeScript support with exported interfaces |
| 41 | +- **Metrics Ready**: Components can be wrapped with metrics HOC |
| 42 | +- **Store Integration**: Components consume data from @webex/cc-store |
| 43 | +- **Dual Exports**: Both React components and Web Component-ready builds |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +## Examples and Use Cases |
| 48 | + |
| 49 | +### Getting Started |
| 50 | + |
| 51 | +#### Basic Component Import (React) |
| 52 | + |
| 53 | +```typescript |
| 54 | +import { StationLoginComponent } from '@webex/cc-components'; |
| 55 | +import React from 'react'; |
| 56 | + |
| 57 | +function MyCustomLogin() { |
| 58 | + const props = { |
| 59 | + teams: ['Team A', 'Team B'], |
| 60 | + loginOptions: ['BROWSER', 'EXTENSION'], |
| 61 | + deviceType: 'BROWSER', |
| 62 | + login: () => console.log('Login called'), |
| 63 | + // ... other required props |
| 64 | + }; |
| 65 | + |
| 66 | + return <StationLoginComponent {...props} />; |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +#### Using UserStateComponent |
| 71 | + |
| 72 | +```typescript |
| 73 | +import { UserStateComponent } from '@webex/cc-components'; |
| 74 | +import { observer } from 'mobx-react-lite'; |
| 75 | +import store from '@webex/cc-store'; |
| 76 | + |
| 77 | +const UserStateWrapper = observer(() => { |
| 78 | + const props = { |
| 79 | + idleCodes: store.idleCodes, |
| 80 | + currentState: store.currentState, |
| 81 | + setAgentStatus: (code) => console.log('Status changed:', code), |
| 82 | + elapsedTime: 120, |
| 83 | + // ... other props |
| 84 | + }; |
| 85 | + |
| 86 | + return <UserStateComponent {...props} />; |
| 87 | +}); |
| 88 | +``` |
| 89 | + |
| 90 | +### Common Use Cases |
| 91 | + |
| 92 | +#### 1. Building Custom Widgets |
| 93 | + |
| 94 | +```typescript |
| 95 | +import { TaskListComponent } from '@webex/cc-components'; |
| 96 | +import store from '@webex/cc-store'; |
| 97 | +import { observer } from 'mobx-react-lite'; |
| 98 | + |
| 99 | +const CustomTaskList = observer(() => { |
| 100 | + const handleTaskSelect = (taskId: string) => { |
| 101 | + console.log('Task selected:', taskId); |
| 102 | + // Custom handling logic |
| 103 | + }; |
| 104 | + |
| 105 | + return ( |
| 106 | + <TaskListComponent |
| 107 | + tasks={store.tasks} |
| 108 | + selectedTaskId={store.selectedTaskId} |
| 109 | + onTaskSelected={handleTaskSelect} |
| 110 | + logger={store.logger} |
| 111 | + /> |
| 112 | + ); |
| 113 | +}); |
| 114 | +``` |
| 115 | + |
| 116 | +#### 2. Extending Components with Custom Logic |
| 117 | + |
| 118 | +```typescript |
| 119 | +import { CallControlComponent } from '@webex/cc-components'; |
| 120 | +import { useCallback } from 'react'; |
| 121 | + |
| 122 | +function EnhancedCallControl({ taskId }) { |
| 123 | + const handleHold = useCallback(() => { |
| 124 | + // Add analytics tracking |
| 125 | + trackEvent('call_hold_clicked', { taskId }); |
| 126 | + |
| 127 | + // Call original handler |
| 128 | + return store.holdCall(taskId); |
| 129 | + }, [taskId]); |
| 130 | + |
| 131 | + return ( |
| 132 | + <CallControlComponent |
| 133 | + task={store.getTask(taskId)} |
| 134 | + onHoldResume={handleHold} |
| 135 | + // ... other props |
| 136 | + /> |
| 137 | + ); |
| 138 | +} |
| 139 | +``` |
| 140 | + |
| 141 | +#### 3. Using Type Definitions |
| 142 | + |
| 143 | +```typescript |
| 144 | +import type { |
| 145 | + StationLoginComponentProps, |
| 146 | + IUserState, |
| 147 | + UserStateComponentsProps |
| 148 | +} from '@webex/cc-components'; |
| 149 | + |
| 150 | +// Type-safe prop interfaces |
| 151 | +const loginProps: StationLoginComponentProps = { |
| 152 | + teams: ['Team A'], |
| 153 | + loginOptions: ['BROWSER'], |
| 154 | + deviceType: 'BROWSER', |
| 155 | + login: () => {}, |
| 156 | + // TypeScript ensures all required props are present |
| 157 | +}; |
| 158 | +``` |
| 159 | + |
| 160 | +#### 4. Integration with Metrics HOC |
| 161 | + |
| 162 | +```typescript |
| 163 | +import { StationLoginComponent } from '@webex/cc-components'; |
| 164 | +import { withMetrics } from '@webex/cc-ui-logging'; |
| 165 | + |
| 166 | +// Wrap component with metrics tracking |
| 167 | +const StationLoginWithMetrics = withMetrics( |
| 168 | + StationLoginComponent, |
| 169 | + 'StationLoginComponent' |
| 170 | +); |
| 171 | + |
| 172 | +// Use the wrapped component |
| 173 | +function App() { |
| 174 | + return <StationLoginWithMetrics {...props} />; |
| 175 | +} |
| 176 | +``` |
| 177 | + |
| 178 | +### Integration Patterns |
| 179 | + |
| 180 | +#### With Custom Styling |
| 181 | + |
| 182 | +```typescript |
| 183 | +import { UserStateComponent } from '@webex/cc-components'; |
| 184 | +import './custom-user-state.scss'; // Your custom styles |
| 185 | + |
| 186 | +// Components use BEM naming, easy to override |
| 187 | +function StyledUserState(props) { |
| 188 | + return ( |
| 189 | + <div className="my-custom-wrapper"> |
| 190 | + <UserStateComponent {...props} /> |
| 191 | + </div> |
| 192 | + ); |
| 193 | +} |
| 194 | +``` |
| 195 | + |
| 196 | +#### With Error Boundaries |
| 197 | + |
| 198 | +```typescript |
| 199 | +import { IncomingTaskComponent } from '@webex/cc-components'; |
| 200 | +import { ErrorBoundary } from 'react-error-boundary'; |
| 201 | + |
| 202 | +function SafeIncomingTask(props) { |
| 203 | + return ( |
| 204 | + <ErrorBoundary fallback={<div>Error loading task</div>}> |
| 205 | + <IncomingTaskComponent {...props} /> |
| 206 | + </ErrorBoundary> |
| 207 | + ); |
| 208 | +} |
| 209 | +``` |
| 210 | + |
| 211 | +#### Creating Composite Components |
| 212 | + |
| 213 | +```typescript |
| 214 | +import { |
| 215 | + CallControlComponent, |
| 216 | + TaskListComponent |
| 217 | +} from '@webex/cc-components'; |
| 218 | +import { observer } from 'mobx-react-lite'; |
| 219 | +import store from '@webex/cc-store'; |
| 220 | + |
| 221 | +// Combine multiple components |
| 222 | +const TaskPanel = observer(() => { |
| 223 | + const selectedTask = store.selectedTask; |
| 224 | + |
| 225 | + return ( |
| 226 | + <div className="task-panel"> |
| 227 | + <TaskListComponent |
| 228 | + tasks={store.tasks} |
| 229 | + onTaskSelected={(id) => store.setSelectedTask(id)} |
| 230 | + /> |
| 231 | + {selectedTask && ( |
| 232 | + <CallControlComponent |
| 233 | + task={selectedTask} |
| 234 | + onEnd={() => store.endTask(selectedTask.id)} |
| 235 | + /> |
| 236 | + )} |
| 237 | + </div> |
| 238 | + ); |
| 239 | +}); |
| 240 | +``` |
| 241 | + |
| 242 | +--- |
| 243 | + |
| 244 | +## Dependencies |
| 245 | + |
| 246 | +**Note:** For exact versions, see [package.json](../package.json) |
| 247 | + |
| 248 | +### Runtime Dependencies |
| 249 | + |
| 250 | +| Package | Purpose | |
| 251 | +|---------|---------| |
| 252 | +| `@momentum-ui/illustrations` | Momentum UI illustration assets | |
| 253 | +| `@r2wc/react-to-web-component` | React to Web Component conversion (for wc.ts export) | |
| 254 | +| `@webex/cc-store` | MobX singleton store for state management | |
| 255 | +| `@webex/cc-ui-logging` | Metrics tracking utilities | |
| 256 | + |
| 257 | +### Peer Dependencies |
| 258 | + |
| 259 | +| Package | Purpose | |
| 260 | +|---------|---------| |
| 261 | +| `@momentum-ui/react-collaboration` | Momentum UI React components | |
| 262 | +| `react` | React framework | |
| 263 | +| `react-dom` | React DOM rendering | |
| 264 | + |
| 265 | +### Development Dependencies |
| 266 | + |
| 267 | +Key development tools (see [package.json](../package.json) for versions): |
| 268 | +- TypeScript |
| 269 | +- Jest (testing) |
| 270 | +- Webpack (bundling) |
| 271 | +- ESLint (linting) |
| 272 | +- React Testing Library |
| 273 | + |
| 274 | +--- |
| 275 | + |
| 276 | +## Exported Components |
| 277 | + |
| 278 | +### Main Components |
| 279 | + |
| 280 | +| Component | Purpose | Key Props | |
| 281 | +|-----------|---------|-----------| |
| 282 | +| `StationLoginComponent` | Agent station login UI | `teams`, `loginOptions`, `deviceType`, `login`, `logout` | |
| 283 | +| `UserStateComponent` | Agent state management UI | `idleCodes`, `currentState`, `setAgentStatus`, `elapsedTime` | |
| 284 | +| `CallControlComponent` | Call control buttons | `task`, `onHoldResume`, `onEnd`, `onWrapUp` | |
| 285 | +| `CallControlCADComponent` | CAD-enabled call control | `task`, `onHoldResume`, `onEnd`, `cadVariables` | |
| 286 | +| `IncomingTaskComponent` | Incoming task notifications | `incomingTask`, `onAccepted`, `onRejected` | |
| 287 | +| `TaskListComponent` | Active tasks list | `tasks`, `selectedTaskId`, `onTaskSelected` | |
| 288 | +| `OutdialCallComponent` | Outbound dialing UI | `entryPoints`, `addressBook`, `onDial` | |
| 289 | + |
| 290 | +### Type Exports |
| 291 | + |
| 292 | +```typescript |
| 293 | +export * from './components/StationLogin/constants'; |
| 294 | +export * from './components/StationLogin/station-login.types'; |
| 295 | +export * from './components/UserState/user-state.types'; |
| 296 | +export * from './components/task/task.types'; |
| 297 | +``` |
| 298 | + |
| 299 | +### Dual Export Paths |
| 300 | + |
| 301 | +```typescript |
| 302 | +// React components (default export) |
| 303 | +import { StationLoginComponent } from '@webex/cc-components'; |
| 304 | + |
| 305 | +// Web Component wrappers (for wc.ts export) |
| 306 | +import { StationLoginComponent } from '@webex/cc-components/wc'; |
| 307 | +``` |
| 308 | + |
| 309 | +--- |
| 310 | + |
| 311 | +## Installation |
| 312 | + |
| 313 | +```bash |
| 314 | +# Install as part of contact center widgets development |
| 315 | +yarn add @webex/cc-components |
| 316 | + |
| 317 | +# Peer dependencies (required) |
| 318 | +yarn add @momentum-ui/react-collaboration react react-dom |
| 319 | +``` |
| 320 | + |
| 321 | +--- |
| 322 | + |
| 323 | +## Usage in Widget Development |
| 324 | + |
| 325 | +### Creating a New Widget |
| 326 | + |
| 327 | +```typescript |
| 328 | +// 1. Create widget wrapper |
| 329 | +import { StationLoginComponent } from '@webex/cc-components'; |
| 330 | +import { observer } from 'mobx-react-lite'; |
| 331 | +import store from '@webex/cc-store'; |
| 332 | + |
| 333 | +const MyWidget = observer((props) => { |
| 334 | + // 2. Add business logic/hooks |
| 335 | + const handleLogin = () => { |
| 336 | + // Business logic |
| 337 | + }; |
| 338 | + |
| 339 | + // 3. Map store data to component props |
| 340 | + const componentProps = { |
| 341 | + teams: store.teams, |
| 342 | + loginOptions: store.loginOptions, |
| 343 | + deviceType: store.deviceType, |
| 344 | + login: handleLogin, |
| 345 | + ...props |
| 346 | + }; |
| 347 | + |
| 348 | + // 4. Render component |
| 349 | + return <StationLoginComponent {...componentProps} />; |
| 350 | +}); |
| 351 | +``` |
| 352 | + |
| 353 | +### Testing Components |
| 354 | + |
| 355 | +```typescript |
| 356 | +import { render } from '@testing-library/react'; |
| 357 | +import { StationLoginComponent } from '@webex/cc-components'; |
| 358 | + |
| 359 | +test('renders station login', () => { |
| 360 | + const props = { |
| 361 | + teams: ['Team A'], |
| 362 | + loginOptions: ['BROWSER'], |
| 363 | + deviceType: 'BROWSER', |
| 364 | + login: jest.fn(), |
| 365 | + // ... minimal required props |
| 366 | + }; |
| 367 | + |
| 368 | + const { getByText } = render(<StationLoginComponent {...props} />); |
| 369 | + expect(getByText('Login')).toBeInTheDocument(); |
| 370 | +}); |
| 371 | +``` |
| 372 | + |
| 373 | +--- |
| 374 | + |
| 375 | +## Additional Resources |
| 376 | + |
| 377 | +For detailed component architecture, integration patterns, and troubleshooting, see [architecture.md](./architecture.md). |
| 378 | + |
| 379 | +--- |
| 380 | + |
| 381 | +_Last Updated: 2025-11-26_ |
| 382 | + |
0 commit comments