diff --git a/widgets-samples/cc/samples-cc-react-app/ai-docs/AGENTS.md b/widgets-samples/cc/samples-cc-react-app/ai-docs/AGENTS.md new file mode 100644 index 000000000..6816fc7b0 --- /dev/null +++ b/widgets-samples/cc/samples-cc-react-app/ai-docs/AGENTS.md @@ -0,0 +1,367 @@ +# React Sample App - Widget Integration Guide + +## Purpose + +Demonstrates how to integrate Contact Center widgets into a React application. Use this as a reference when adding new widgets. + +## Design System + +- **Framework:** React 18.3.1 + TypeScript +- **UI Library:** Momentum Design System (`@momentum-design/components`) +- **State:** MobX store (`@webex/cc-store`) +- **Theme:** Dark/Light mode toggle (persisted in localStorage) +- **Layout:** CSS Grid with `.box`, `.section-box`, `.fieldset` structure + +## Critical Integration Pattern + +**Follow this exact pattern for ALL new widgets:** + +### Step 1: Import the Widget + +```tsx +import {NewWidget} from '@webex/cc-widgets'; +``` + +### Step 2: Add to defaultWidgets + +```tsx +const defaultWidgets = { + stationLogin: true, + userState: true, + // ... existing widgets + newWidget: false, // ← Add here (false by default for user opt-in) +}; +``` + +### Step 3: Add Checkbox for Widget Selection + +```tsx + + New Widget + +``` + +### Step 4: Conditional Rendering with Standard Layout + +```tsx +{ + selectedWidgets.newWidget && ( +
+
+
+ New Widget + handleNewWidgetEvent(data)} onError={(error) => onError('NewWidget', error)} /> +
+
+
+ ); +} +``` + +### Step 5: Add callbacks (if needed) + +```tsx +const handleNewWidgetCallback = (data) => { + console.log('New widget callback:', data); + // Handle callback logic +}; +``` + +## Layout Structure Rules + +### Container Hierarchy (ALWAYS use this) + +```tsx +
+ {' '} + {/* Outer container with background */} +
+ {' '} + {/* Inner section with padding */} +
+ {' '} + {/* Fieldset for grouping */} + Title {/* Title/legend */} + {/* Actual widget */} +
+
+
+``` + +### Why this structure? + +- `box` - Consistent spacing and background +- `section-box` - Momentum Design padding +- `fieldset` - Semantic grouping +- `legend-box` - Styled title +- **Result:** Visual consistency across all widgets + +## Styling Rules + +### CSS Variables (MUST USE) + +```scss +// Colors +var(--mds-color-theme-text-primary-normal) +var(--mds-color-theme-background-solid-primary-normal) +var(--mds-color-theme-background-primary-normal) + +// Spacing +var(--mds-spacing-1) // 0.25rem (4px) +var(--mds-spacing-2) // 0.5rem (8px) +var(--mds-spacing-3) // 1rem (16px) +var(--mds-spacing-4) // 1.5rem (24px) + +// Typography +var(--mds-font-size-body-small) +var(--mds-font-size-body-medium) +``` + +### ❌ NEVER Do This + +```tsx +
// Hardcoded color +
// Hardcoded spacing +``` + +### ✅ ALWAYS Do This + +```tsx +
+``` + +## Event Handling Pattern + +### Standard onError Handler + +```tsx +const onError = (widgetName: string, error: Error) => { + console.error(`${widgetName} error:`, error); + // Optional: Show toast notification + setToast({type: 'error'}); +}; +``` + +**EVERY widget MUST have onError callback.** + +### Widget-Specific Events + +```tsx +// IncomingTask +const onIncomingTaskCB = ({task}) => { + console.log('Incoming task:', task); + setIncomingTasks((prev) => [...prev, task]); + playNotificationSound(); // Custom logic +}; + +// UserState +const onAgentStateChangedCB = (newState: AgentState, oldState: AgentState) => { + console.log('State changed from', oldState, 'to', newState); + setSelectedState(newState); +}; + +// CallControl +const onRecordingToggleCB = ({isRecording, task}) => { + console.log('Recording:', isRecording, 'for task:', task.data.interactionId); +}; +``` + +## Theme Integration + +Theme is controlled by `@momentum-ui`'s `ThemeProvider`: + +```tsx +import {ThemeProvider} from '@momentum-design/components/dist/react'; + + + {/* Your widgets */} +; +``` + +- **Theme provider**: `@momentum-ui` library manages the theme through `ThemeProvider` +- **Theme storage**: `store.currentTheme` stores the theme as a string ('LIGHT' or 'DARK') +- **Theme classes**: Theme class names (`mds-theme-stable-lightWebex` / `mds-theme-stable-darkWebex`) are passed to ThemeProvider +- **Automatic updates**: All widgets automatically respond to theme changes through the ThemeProvider context + +**User can toggle theme via UI checkbox** - widgets update automatically through the provider. + +## State Management + +### When to Use store Directly + +```tsx +// Access store for global state +import {store} from '@webex/cc-widgets'; + +// Examples: +store.currentTask; // Current active task +store.taskList; // All tasks +store.incomingTask; // Incoming task +store.agentState; // Current agent state +``` + +### When to Use Local State + +```tsx +// UI-only state (no widget dependency) +const [showPopup, setShowPopup] = useState(false); +const [selectedOption, setSelectedOption] = useState(''); +``` + +## Complete Example: Adding a New Widget + +```tsx +// 1. Import +import {NewAwesomeWidget} from '@webex/cc-widgets'; + +// 2. Add to defaultWidgets +const defaultWidgets = { + // ... existing + newAwesomeWidget: false, +}; + +// 3. Checkbox in widget selector + + New Awesome Widget +; + +// 4. Setup callback handler (if needed) +const handleCallback = (data) => { + console.log('Callback:', data); +}; + +// 5. Render with standard layout +{ + selectedWidgets.newAwesomeWidget && ( +
+
+
+ New Awesome Widget + onError('NewAwesomeWidget', error)} + customProp={someValue} + /> +
+
+
+ ); +} +``` + +## Common Mistakes to AVOID + +### ❌ Breaking CSS class structure + +```tsx +// WRONG +
+ +
+``` + +### ✅ Correct + +```tsx +
+
+
+ Widget Name + +
+
+
+``` + +### ❌ Forgetting defaultWidgets entry + +```tsx +// WRONG - Widget renders immediately, user can't disable +{ + selectedWidgets.newWidget && ; +} +// But newWidget not in defaultWidgets! +``` + +### ✅ Correct + +```tsx +// In defaultWidgets +const defaultWidgets = { + newWidget: false, // ← MUST ADD HERE +}; + +// Then render +{ + selectedWidgets.newWidget && ; +} +``` + +### ❌ Missing error handler + +```tsx +// WRONG + +``` + +### ✅ Correct + +```tsx + onError('NewWidget', error)} /> +``` + +### ❌ Hardcoding colors + +```tsx +// WRONG +
+``` + +### ✅ Correct + +```tsx +
+``` + +## Testing Checklist + +After adding a new widget: + +- [ ] Widget imports without errors +- [ ] Appears in widget selector checkbox list +- [ ] Can be enabled/disabled via checkbox +- [ ] Selection persists in localStorage +- [ ] Renders with correct layout (box > section-box > fieldset) +- [ ] Has legend/title +- [ ] Uses Momentum CSS variables (no hardcoded colors) +- [ ] Callbacks are handled correctly +- [ ] onError handler present and logs errors +- [ ] Works in both light and dark themes +- [ ] No console errors when enabled/disabled +- [ ] No visual/layout breaking when rendered alongside other widgets + +## File Locations + +- **Main App:** `src/App.tsx` +- **Styles:** `src/App.scss` + +## Additional Resources + +- [MobX Store Package](../../packages/contact-center/store/ai-docs/agent.md) +- [cc-widgets Package](../../packages/contact-center/cc-widgets/ai-docs/agent.md)