|
| 1 | +# User State Widget |
| 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 root `AGENTS.md` and been routed here, you can use the rest of this file as the authoritative reference for `@webex/cc-components`. |
| 14 | + |
| 15 | +## Overview |
| 16 | + |
| 17 | +The User State widget provides a user interface for contact center agents to manage their availability status. It handles agent state transitions (Available, Idle with various reasons), displays state duration timers, and manages idle code selection. The widget integrates with the Webex Contact Center SDK and follows the standard three-layer architecture pattern (Widget → Hook → Component → Store). |
| 18 | + |
| 19 | +**Package:** `@webex/cc-user-state` |
| 20 | + |
| 21 | +**Version:** See [package.json](../package.json) |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +## Why and What is This Widget Used For? |
| 26 | + |
| 27 | +### Purpose |
| 28 | + |
| 29 | +The User State widget enables contact center agents to: |
| 30 | +- **Change their availability state** (Available, Idle, etc.) |
| 31 | +- **Select idle codes** for different idle reasons (Break, Lunch, Meeting, etc.) |
| 32 | +- **View state duration** with real-time timer display |
| 33 | +- **Track idle code duration** separately from overall state duration |
| 34 | +- **Receive state change notifications** via callbacks |
| 35 | + |
| 36 | +### Key Capabilities |
| 37 | + |
| 38 | +- **State Management**: Toggle between Available and various Idle states |
| 39 | +- **Idle Code Support**: Dropdown selection for different idle reasons |
| 40 | +- **Real-Time Timers**: Displays elapsed time in current state using Web Worker |
| 41 | +- **Dual Timer Support**: Tracks both state duration and idle code duration |
| 42 | +- **State Change Callbacks**: Extensible callback for state change events |
| 43 | +- **Automatic State Sync**: Syncs state changes with backend via SDK |
| 44 | +- **Error Handling**: Comprehensive error boundary with callback support |
| 45 | + |
| 46 | +--- |
| 47 | + |
| 48 | +## Examples and Use Cases |
| 49 | + |
| 50 | +### Getting Started |
| 51 | + |
| 52 | +#### Basic Usage (React) |
| 53 | + |
| 54 | +```typescript |
| 55 | +import { UserState } from '@webex/cc-user-state'; |
| 56 | +import React from 'react'; |
| 57 | + |
| 58 | +function MyApp() { |
| 59 | + const handleStateChange = (newState) => { |
| 60 | + console.log('Agent state changed to:', newState); |
| 61 | + // Update your application state |
| 62 | + }; |
| 63 | + |
| 64 | + return ( |
| 65 | + <UserState |
| 66 | + onStateChange={handleStateChange} |
| 67 | + /> |
| 68 | + ); |
| 69 | +} |
| 70 | +``` |
| 71 | + |
| 72 | +#### Web Component Usage |
| 73 | + |
| 74 | +```html |
| 75 | +<!-- Include the widget bundle --> |
| 76 | +<script src="path/to/cc-widgets.js"></script> |
| 77 | + |
| 78 | +<!-- Use the web component --> |
| 79 | +<cc-user-state></cc-user-state> |
| 80 | + |
| 81 | +<script> |
| 82 | + const widget = document.querySelector('cc-user-state'); |
| 83 | + |
| 84 | + widget.addEventListener('statechange', (event) => { |
| 85 | + console.log('Agent state changed:', event.detail); |
| 86 | + }); |
| 87 | +</script> |
| 88 | +``` |
| 89 | + |
| 90 | +#### With State Change Tracking |
| 91 | + |
| 92 | +```typescript |
| 93 | +import { UserState } from '@webex/cc-user-state'; |
| 94 | +import React, { useState } from 'react'; |
| 95 | + |
| 96 | +function AgentDashboard() { |
| 97 | + const [currentState, setCurrentState] = useState(null); |
| 98 | + const [stateHistory, setStateHistory] = useState([]); |
| 99 | + |
| 100 | + const handleStateChange = (newState) => { |
| 101 | + setCurrentState(newState); |
| 102 | + setStateHistory(prev => [...prev, { |
| 103 | + state: newState, |
| 104 | + timestamp: new Date() |
| 105 | + }]); |
| 106 | + console.log('State changed to:', newState.name); |
| 107 | + }; |
| 108 | + |
| 109 | + return ( |
| 110 | + <div> |
| 111 | + <h2>Current State: {currentState?.name || 'Unknown'}</h2> |
| 112 | + <UserState onStateChange={handleStateChange} /> |
| 113 | + |
| 114 | + <div> |
| 115 | + <h3>State History</h3> |
| 116 | + {stateHistory.map((entry, idx) => ( |
| 117 | + <div key={idx}> |
| 118 | + {entry.state.name} - {entry.timestamp.toLocaleString()} |
| 119 | + </div> |
| 120 | + ))} |
| 121 | + </div> |
| 122 | + </div> |
| 123 | + ); |
| 124 | +} |
| 125 | +``` |
| 126 | + |
| 127 | +### Common Use Cases |
| 128 | + |
| 129 | +#### 1. Agent Status Display |
| 130 | + |
| 131 | +```typescript |
| 132 | +// Display agent's current status with timer |
| 133 | +import { UserState } from '@webex/cc-user-state'; |
| 134 | +import { observer } from 'mobx-react-lite'; |
| 135 | +import store from '@webex/cc-store'; |
| 136 | + |
| 137 | +const AgentStatusPanel = observer(() => { |
| 138 | + const { currentState, idleCodes } = store; |
| 139 | + |
| 140 | + const handleStateChange = (newState) => { |
| 141 | + console.log(`Agent changed to: ${newState.name}`); |
| 142 | + // Store automatically updates |
| 143 | + }; |
| 144 | + |
| 145 | + return ( |
| 146 | + <div className="agent-panel"> |
| 147 | + <h3>Your Status</h3> |
| 148 | + <UserState onStateChange={handleStateChange} /> |
| 149 | + <p>Current: {currentState}</p> |
| 150 | + </div> |
| 151 | + ); |
| 152 | +}); |
| 153 | +``` |
| 154 | + |
| 155 | +#### 2. State Change Validation |
| 156 | + |
| 157 | +```typescript |
| 158 | +// Validate state changes before allowing |
| 159 | +import { UserState } from '@webex/cc-user-state'; |
| 160 | +import store from '@webex/cc-store'; |
| 161 | + |
| 162 | +function ValidatedUserState() { |
| 163 | + const handleStateChange = (newState) => { |
| 164 | + // Check if agent has pending tasks |
| 165 | + if (newState.name === 'Idle' && store.hasActiveTasks) { |
| 166 | + showWarning('Please complete active tasks before going idle'); |
| 167 | + // State change will be rejected by store |
| 168 | + return; |
| 169 | + } |
| 170 | + |
| 171 | + // Log state change |
| 172 | + auditLog('State change', { |
| 173 | + agent: store.agentId, |
| 174 | + from: store.currentState, |
| 175 | + to: newState.name, |
| 176 | + timestamp: Date.now() |
| 177 | + }); |
| 178 | + |
| 179 | + console.log('State change approved:', newState); |
| 180 | + }; |
| 181 | + |
| 182 | + return <UserState onStateChange={handleStateChange} />; |
| 183 | +} |
| 184 | +``` |
| 185 | + |
| 186 | +#### 3. Custom Error Handling |
| 187 | + |
| 188 | +```typescript |
| 189 | +import store from '@webex/cc-store'; |
| 190 | + |
| 191 | +// Set error callback before rendering widget |
| 192 | +store.onErrorCallback = (componentName, error) => { |
| 193 | + console.error(`Error in ${componentName}:`, error); |
| 194 | + |
| 195 | + // Notify user |
| 196 | + showErrorNotification('Failed to update state. Please try again.'); |
| 197 | + |
| 198 | + // Send to error tracking |
| 199 | + trackError(componentName, error); |
| 200 | +}; |
| 201 | + |
| 202 | +// Widget will call this callback on errors |
| 203 | +<UserState onStateChange={handleStateChange} /> |
| 204 | +``` |
| 205 | + |
| 206 | +### Integration Patterns |
| 207 | + |
| 208 | +#### With Agent Desktop |
| 209 | + |
| 210 | +```typescript |
| 211 | +import { UserState } from '@webex/cc-user-state'; |
| 212 | +import { observer } from 'mobx-react-lite'; |
| 213 | +import store from '@webex/cc-store'; |
| 214 | + |
| 215 | +const AgentDesktop = observer(() => { |
| 216 | + const { isAgentLoggedIn, currentState } = store; |
| 217 | + |
| 218 | + const handleStateChange = (newState) => { |
| 219 | + // Update local UI |
| 220 | + updateHeaderStatus(newState.name); |
| 221 | + |
| 222 | + // Log to analytics |
| 223 | + logStateChange(newState); |
| 224 | + }; |
| 225 | + |
| 226 | + if (!isAgentLoggedIn) { |
| 227 | + return <LoginScreen />; |
| 228 | + } |
| 229 | + |
| 230 | + return ( |
| 231 | + <div className="desktop"> |
| 232 | + <header> |
| 233 | + <UserState onStateChange={handleStateChange} /> |
| 234 | + </header> |
| 235 | + <main> |
| 236 | + <TaskPanel /> |
| 237 | + <CustomerInfo /> |
| 238 | + </main> |
| 239 | + </div> |
| 240 | + ); |
| 241 | +}); |
| 242 | +``` |
| 243 | + |
| 244 | +#### With Idle Code Management |
| 245 | + |
| 246 | +```typescript |
| 247 | +import { UserState } from '@webex/cc-user-state'; |
| 248 | +import { observer } from 'mobx-react-lite'; |
| 249 | +import store from '@webex/cc-store'; |
| 250 | + |
| 251 | +const StateManager = observer(() => { |
| 252 | + const { idleCodes, currentState } = store; |
| 253 | + |
| 254 | + const handleStateChange = (state) => { |
| 255 | + console.log('State changed:', state); |
| 256 | + |
| 257 | + // Log idle code if applicable |
| 258 | + if (state.name !== 'Available' && 'id' in state) { |
| 259 | + console.log('Idle code selected:', state.id); |
| 260 | + logIdleCode(state.id, state.name); |
| 261 | + } |
| 262 | + }; |
| 263 | + |
| 264 | + return ( |
| 265 | + <div> |
| 266 | + <UserState onStateChange={handleStateChange} /> |
| 267 | + |
| 268 | + <div className="info"> |
| 269 | + <p>Available idle codes: {idleCodes.length}</p> |
| 270 | + <p>Current state: {currentState}</p> |
| 271 | + </div> |
| 272 | + </div> |
| 273 | + ); |
| 274 | +}); |
| 275 | +``` |
| 276 | + |
| 277 | +--- |
| 278 | + |
| 279 | +## Dependencies |
| 280 | + |
| 281 | +**Note:** For exact versions, see [package.json](../package.json) |
| 282 | + |
| 283 | +### Runtime Dependencies |
| 284 | + |
| 285 | +| Package | Purpose | |
| 286 | +|---------|---------| |
| 287 | +| `@webex/cc-components` | React UI components | |
| 288 | +| `@webex/cc-store` | MobX singleton store for state management | |
| 289 | +| `mobx-react-lite` | React bindings for MobX | |
| 290 | +| `react-error-boundary` | Error boundary implementation | |
| 291 | +| `typescript` | TypeScript support | |
| 292 | + |
| 293 | +### Peer Dependencies |
| 294 | + |
| 295 | +| Package | Purpose | |
| 296 | +|---------|---------| |
| 297 | +| `react` | React framework | |
| 298 | +| `react-dom` | React DOM rendering | |
| 299 | + |
| 300 | +### Development Dependencies |
| 301 | + |
| 302 | +Key development tools (see [package.json](../package.json) for versions): |
| 303 | +- TypeScript |
| 304 | +- Jest (testing) |
| 305 | +- Webpack (bundling) |
| 306 | +- ESLint (linting) |
| 307 | + |
| 308 | +### External SDK Dependency |
| 309 | + |
| 310 | +The widget requires the **Webex Contact Center SDK** (`@webex/contact-center`) to be initialized and available through the store. The SDK provides: |
| 311 | +- `setAgentState()` - Updates agent state (Available/Idle) |
| 312 | +- Agent state events - Notifies on state changes |
| 313 | +- Idle code management - Provides available idle codes |
| 314 | + |
| 315 | +### Web Worker |
| 316 | + |
| 317 | +The widget uses a **Web Worker** for accurate timer management: |
| 318 | +- Runs timer in background thread |
| 319 | +- Prevents main thread blocking |
| 320 | +- Ensures accurate elapsed time tracking |
| 321 | +- Automatically cleaned up on unmount |
| 322 | + |
| 323 | +--- |
| 324 | + |
| 325 | +## Props API |
| 326 | + |
| 327 | +| Prop | Type | Required | Default | Description | |
| 328 | +|------|------|----------|---------|-------------| |
| 329 | +| `onStateChange` | `(state: IdleCode \| CustomState) => void` | No | - | Callback when agent state changes | |
| 330 | + |
| 331 | +**State Object:** |
| 332 | + |
| 333 | +```typescript |
| 334 | +// IdleCode (from idle codes list) |
| 335 | +interface IdleCode { |
| 336 | + id: string; // Idle code ID |
| 337 | + name: string; // Display name (e.g., "Break", "Lunch") |
| 338 | + // ... other properties |
| 339 | +} |
| 340 | + |
| 341 | +// CustomState (for custom states) |
| 342 | +interface CustomState { |
| 343 | + developerName: string; |
| 344 | + // ... custom properties |
| 345 | +} |
| 346 | +``` |
| 347 | + |
| 348 | +--- |
| 349 | + |
| 350 | +## Installation |
| 351 | + |
| 352 | +```bash |
| 353 | +# Install as part of contact center widgets |
| 354 | +yarn add @webex/cc-user-state |
| 355 | + |
| 356 | +# Or install the entire widgets bundle |
| 357 | +yarn add @webex/cc-widgets |
| 358 | +``` |
| 359 | + |
| 360 | +--- |
| 361 | + |
| 362 | +## Additional Resources |
| 363 | + |
| 364 | +For detailed component architecture, data flows, and sequence diagrams, see [architecture.md](./architecture.md). |
| 365 | + |
| 366 | +--- |
| 367 | + |
| 368 | +_Last Updated: 2025-11-26_ |
| 369 | + |
0 commit comments