(prevProps: T, nextProps: T): boolean => {
+ const prevKeys = Object.keys(prevProps);
+ const nextKeys = Object.keys(nextProps);
+
+ if (prevKeys.length !== nextKeys.length) {
+ return true;
+ }
+
+ for (const key of prevKeys) {
+ if (prevProps[key as keyof T] !== nextProps[key as keyof T]) {
+ return true;
+ }
+ }
+
+ return false;
+};
+
+export const sendWidgetEvent = (
+ widgetName: string,
+ event: 'WIDGET_INITIALIZED' | 'WIDGET_UNMOUNTED' | 'WIDGET_PROP_UPDATED' | 'WIDGET_DETECTED',
+ props?: any
+): void => {
+ const timestamp = Date.now();
+ const metricEvent: MetricEvent = {
+ widgetName,
+ event,
+ props,
+ timestamp,
+ };
+ metricsCollector.logMetrics(metricEvent);
+};
diff --git a/packages/contact-center/WidgetsProvider/src/withMetrics.tsx b/packages/contact-center/WidgetsProvider/src/withMetrics.tsx
new file mode 100644
index 000000000..320c624d2
--- /dev/null
+++ b/packages/contact-center/WidgetsProvider/src/withMetrics.tsx
@@ -0,0 +1,47 @@
+import React, {useEffect, useRef} from 'react';
+import {havePropsChanged, logMetrics} from './metricsLogger';
+
+export default function withMetrics(Component: any, widgetName: string) {
+ return React.memo(
+ (props: P) => {
+ const previousProps = useRef
();
+
+ // Handle mount and unmount events
+ useEffect(() => {
+ logMetrics({
+ widgetName,
+ event: 'WIDGET_INITIALIZED',
+ props,
+ timestamp: Date.now(),
+ });
+
+ return () => {
+ logMetrics({
+ widgetName,
+ event: 'WIDGET_UNMOUNTED',
+ timestamp: Date.now(),
+ });
+ };
+ }, []);
+
+ // Handle prop updates
+ useEffect(() => {
+ if (previousProps.current && havePropsChanged(previousProps.current, props)) {
+ logMetrics({
+ widgetName,
+ event: 'WIDGET_PROP_UPDATED',
+ props,
+ timestamp: Date.now(),
+ });
+ }
+ previousProps.current = props;
+ });
+
+ return ;
+ },
+ (prevProps, nextProps) => {
+ const hasChanged = havePropsChanged(prevProps, nextProps);
+ return !hasChanged;
+ }
+ );
+}
diff --git a/packages/contact-center/WidgetsProvider/tsconfig.json b/packages/contact-center/WidgetsProvider/tsconfig.json
new file mode 100644
index 000000000..50b68ce6a
--- /dev/null
+++ b/packages/contact-center/WidgetsProvider/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../../../tsconfig.json",
+ "include": [
+ "./src"
+ ],
+ "compilerOptions": {
+ "outDir": "./dist",
+ "declaration": true,
+ "declarationDir": "./dist/types"
+ },
+}
\ No newline at end of file
diff --git a/packages/contact-center/WidgetsProvider/webpack.config.js b/packages/contact-center/WidgetsProvider/webpack.config.js
new file mode 100644
index 000000000..2e36143d3
--- /dev/null
+++ b/packages/contact-center/WidgetsProvider/webpack.config.js
@@ -0,0 +1,62 @@
+const {merge} = require('webpack-merge');
+const path = require('path');
+
+const baseConfig = require('../../../webpack.config');
+
+// Helper function to resolve paths relative to the monorepo root
+const resolveMonorepoRoot = (...segments) => path.resolve(__dirname, '../../../', ...segments);
+
+module.exports = merge(baseConfig, {
+ output: {
+ path: path.resolve(__dirname, 'dist'),
+ filename: 'index.js', // Set the output filename to index.js
+ libraryTarget: 'commonjs2',
+ },
+ externals: {
+ react: 'react',
+ 'react-dom': 'react-dom',
+ '@webex/cc-store': '@webex/cc-store',
+ '@momentum-ui/react-collaboration': '@momentum-ui/react-collaboration',
+ },
+ module: {
+ rules: [
+ {
+ test: /\.css$/,
+ use: ['style-loader', 'css-loader'],
+ include: [
+ resolveMonorepoRoot('node_modules/@momentum-ui/react-collaboration'), // Include specific node module
+ path.resolve(__dirname, 'packages'), // Include all CSS from the local package
+ ],
+ },
+ {
+ test: /\.scss$/,
+ use: [
+ 'style-loader', // Injects styles into DOM
+ 'css-loader', // Turns CSS into CommonJS
+ 'sass-loader', // Compiles Sass to CSS
+ ],
+ include: [
+ resolveMonorepoRoot('node_modules/@momentum-ui/react-collaboration'), // Include specific node module
+ path.resolve(__dirname, 'packages'), // Include all CSS from the local package
+ ],
+ },
+ {
+ test: /\.(woff|woff2|eot|ttf|otf)$/,
+ include: [resolveMonorepoRoot('node_modules/@momentum-ui/react-collaboration')],
+ type: 'asset/resource',
+ generator: {
+ filename: 'fonts/[name][ext][query]',
+ },
+ },
+ {
+ test: /\.(png|jpg|gif|svg)$/,
+ include: [resolveMonorepoRoot('node_modules/@momentum-ui/react-collaboration')],
+
+ type: 'asset/resource',
+ generator: {
+ filename: 'images/[name][ext][query]',
+ },
+ },
+ ],
+ },
+});
diff --git a/packages/contact-center/station-login/src/station-login/index.tsx b/packages/contact-center/station-login/src/station-login/index.tsx
index 98293bef4..65fd13173 100644
--- a/packages/contact-center/station-login/src/station-login/index.tsx
+++ b/packages/contact-center/station-login/src/station-login/index.tsx
@@ -54,7 +54,11 @@ const StationLogin: React.FunctionComponent = observer(
logger,
profileMode,
};
- return ;
+ return (
+
+
+
+ );
}
);
diff --git a/packages/contact-center/task/src/CallControl/index.tsx b/packages/contact-center/task/src/CallControl/index.tsx
index 82929a599..16964fbe6 100644
--- a/packages/contact-center/task/src/CallControl/index.tsx
+++ b/packages/contact-center/task/src/CallControl/index.tsx
@@ -45,7 +45,11 @@ const CallControl: React.FunctionComponent = observer(
allowConsultToQueue,
logger,
};
- return ;
+ return (
+
+
+
+ );
}
);
diff --git a/packages/contact-center/task/src/CallControlCAD/index.tsx b/packages/contact-center/task/src/CallControlCAD/index.tsx
index 29d395a1f..c0f22a2ea 100644
--- a/packages/contact-center/task/src/CallControlCAD/index.tsx
+++ b/packages/contact-center/task/src/CallControlCAD/index.tsx
@@ -47,7 +47,11 @@ const CallControlCAD: React.FunctionComponent = observer(
logger,
};
- return ;
+ return (
+
+
+
+ );
}
);
diff --git a/packages/contact-center/task/src/IncomingTask/index.tsx b/packages/contact-center/task/src/IncomingTask/index.tsx
index 6dfe5d4db..b612631bb 100644
--- a/packages/contact-center/task/src/IncomingTask/index.tsx
+++ b/packages/contact-center/task/src/IncomingTask/index.tsx
@@ -15,7 +15,11 @@ const IncomingTask: React.FunctionComponent = observer(({inco
logger,
};
- return ;
+ return (
+
+
+
+ );
});
export {IncomingTask};
diff --git a/packages/contact-center/task/src/OutdialCall/index.tsx b/packages/contact-center/task/src/OutdialCall/index.tsx
index aa6eff781..63735c56b 100644
--- a/packages/contact-center/task/src/OutdialCall/index.tsx
+++ b/packages/contact-center/task/src/OutdialCall/index.tsx
@@ -12,7 +12,11 @@ const OutdialCall: React.FunctionComponent = observer(() => {
...result,
};
- return ;
+ return (
+
+
+
+ );
});
export {OutdialCall};
diff --git a/packages/contact-center/task/src/TaskList/index.tsx b/packages/contact-center/task/src/TaskList/index.tsx
index 6d3ed878d..d54f89227 100644
--- a/packages/contact-center/task/src/TaskList/index.tsx
+++ b/packages/contact-center/task/src/TaskList/index.tsx
@@ -17,7 +17,11 @@ const TaskList: React.FunctionComponent = observer(
logger,
};
- return ;
+ return (
+
+
+
+ );
}
);
diff --git a/packages/contact-center/user-state/src/user-state/index.tsx b/packages/contact-center/user-state/src/user-state/index.tsx
index 6e03ad675..48000d5cd 100644
--- a/packages/contact-center/user-state/src/user-state/index.tsx
+++ b/packages/contact-center/user-state/src/user-state/index.tsx
@@ -35,7 +35,11 @@ const UserState: React.FunctionComponent = observer(({onStateCh
logger,
};
- return ;
+ return (
+
+
+
+ );
});
export {UserState};
diff --git a/widgets-samples/cc/samples-cc-react-app/package.json b/widgets-samples/cc/samples-cc-react-app/package.json
index 0d9d49b55..ea1d60904 100644
--- a/widgets-samples/cc/samples-cc-react-app/package.json
+++ b/widgets-samples/cc/samples-cc-react-app/package.json
@@ -18,6 +18,7 @@
"@babel/preset-typescript": "^7.25.9",
"@momentum-ui/react-collaboration": "26.197.0",
"@webex/cc-widgets": "workspace:*",
+ "@webex/cc-widgets-provider": "workspace:*",
"babel-loader": "^9.2.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.6.3",
diff --git a/widgets-samples/cc/samples-cc-react-app/src/App.tsx b/widgets-samples/cc/samples-cc-react-app/src/App.tsx
index 73e19e036..a43730d6f 100644
--- a/widgets-samples/cc/samples-cc-react-app/src/App.tsx
+++ b/widgets-samples/cc/samples-cc-react-app/src/App.tsx
@@ -11,7 +11,8 @@ import {
} from '@webex/cc-widgets';
import {StationLogoutSuccess} from '@webex/plugin-cc';
import Webex from 'webex';
-import {ThemeProvider, IconProvider, Icon, Button, Checkbox, Text, Select, Option} from '@momentum-design/components/dist/react';
+import {Icon, Button, Checkbox, Text, Select, Option} from '@momentum-design/components/dist/react';
+import {WidgetsProvider} from '@webex/cc-widgets-provider';
import {PopoverNext} from '@momentum-ui/react-collaboration';
import './App.scss';
import {observer} from 'mobx-react-lite';
@@ -66,18 +67,18 @@ function App() {
});
const handleSaveStart = () => {
- setShowLoader(true);
- setToast(null);
-};
+ setShowLoader(true);
+ setToast(null);
+ };
-const handleSaveEnd = (isComplete: boolean) => {
- setShowLoader(false);
- if (isComplete) {
- setToast({type: 'success'});
- } else {
- setToast({type: 'error'});
- }
-};
+ const handleSaveEnd = (isComplete: boolean) => {
+ setShowLoader(false);
+ if (isComplete) {
+ setToast({type: 'success'});
+ } else {
+ setToast({type: 'error'});
+ }
+ };
const onIncomingTaskCB = ({task}) => {
console.log('Incoming task:', task);
@@ -88,28 +89,22 @@ const handleSaveEnd = (isComplete: boolean) => {
useEffect(() => {
if (window.location.hash) {
const urlParams = new URLSearchParams(window.location.hash.replace('#', '?'));
-
+
const accessToken = urlParams.get('access_token');
-
+
if (accessToken) {
window.localStorage.setItem('accessToken', accessToken);
setAccessToken(accessToken);
// Clear the hash from the URL to remove the token from browser history
- window.history.replaceState(
- {},
- document.title,
- window.location.pathname + window.location.search
- );
+ window.history.replaceState({}, document.title, window.location.pathname + window.location.search);
}
- }
- else {
+ } else {
const storedAccessToken = window.localStorage.getItem('accessToken');
if (storedAccessToken) {
setAccessToken(storedAccessToken);
}
}
- }
- , []);
+ }, []);
const webexConfig = {
fedramp: false,
@@ -157,7 +152,7 @@ const handleSaveEnd = (isComplete: boolean) => {
console.log('onTaskAccepted invoked for task:', task);
};
-const onTaskDeclined = (task,reason) => {
+ const onTaskDeclined = (task, reason) => {
console.log('onTaskDeclined invoked for task:', task);
setRejectedReason(reason);
setShowRejectedPopup(true);
@@ -265,30 +260,17 @@ const onTaskDeclined = (task,reason) => {
}
// Reference: https://developer.webex-cx.com/documentation/integrations
- const ccMandatoryScopes = [
- "cjp:config_read",
- "cjp:config_write",
- "cjp:config",
- "cjp:user",
- ];
+ const ccMandatoryScopes = ['cjp:config_read', 'cjp:config_write', 'cjp:config', 'cjp:user'];
- const webRTCCallingScopes = [
- "spark:webrtc_calling",
- "spark:calls_read",
- "spark:calls_write",
- "spark:xsi"
- ];
+ const webRTCCallingScopes = ['spark:webrtc_calling', 'spark:calls_read', 'spark:calls_write', 'spark:xsi'];
const additionalScopes = [
- "spark:kms", // to avoid token downscope to only spark:kms error on SDK init
+ 'spark:kms', // to avoid token downscope to only spark:kms error on SDK init
];
const requestedScopes = Array.from(
- new Set(
- ccMandatoryScopes
- .concat(webRTCCallingScopes)
- .concat(additionalScopes))
- ).join(' ');
+ new Set(ccMandatoryScopes.concat(webRTCCallingScopes).concat(additionalScopes))
+ ).join(' ');
const webexConfig = {
config: {
@@ -318,7 +300,7 @@ const onTaskDeclined = (task,reason) => {
// Store accessToken changes in local storage
useEffect(() => {
- if(accessToken.trim() !== '') {
+ if (accessToken.trim() !== '') {
window.localStorage.setItem('accessToken', accessToken);
}
}, [accessToken]);
@@ -347,19 +329,20 @@ const onTaskDeclined = (task,reason) => {
};
}, []);
- const onStateChange = (status) => {
- console.log('onStateChange invoked', status);
- //adding a log to be used for automation
- console.log('onStateChange invoked with state name:', status?.name);
- if (!status || !status.name) return;
- if (status.name !== 'RONA') {
- setShowRejectedPopup(false);
- setRejectedReason('');
- }
-};
+ const onStateChange = (status) => {
+ console.log('onStateChange invoked', status);
+ //adding a log to be used for automation
+ console.log('onStateChange invoked with state name:', status?.name);
+ if (!status || !status.name) return;
+ if (status.name !== 'RONA') {
+ setShowRejectedPopup(false);
+ setRejectedReason('');
+ }
+ };
- const stationLogout = () => {
- store.cc.stationLogout({logoutReason: 'User requested logout'})
+ const stationLogout = () => {
+ store.cc
+ .stationLogout({logoutReason: 'User requested logout'})
.then((res: StationLogoutSuccess) => {
console.log('Agent logged out successfully', res.data.type);
})
@@ -379,374 +362,386 @@ const onTaskDeclined = (task,reason) => {
return (
-
-
-
-
Contact Center Widgets in a React app
- {showLoader && (
-
- )}
+
+
Contact Center Widgets in a React app
+ {showLoader && (
+
+ )}
- {toast && toast.type === 'success' && (
-
-
-
-
-
-
- Interaction preferences changes
-
+ {toast && toast.type === 'success' && (
+
+
+
+
+
+
Interaction preferences changes
+
Your interaction preference is updated
+
+
setToast(null)}
+ className="toast-close"
+ />
+
+ )}
+
+
+
+
+ Authentication
+ {
+ const selectedType = e.detail.value;
+ if (selectedType !== 'token' && selectedType !== 'oauth') return;
+ setLoginType(selectedType);
+ }}
+ >
+
+ Access Token
+
+
+ Login with Webex
+
+
+
+
+ {loginType === 'token' && (
- Your interaction preference is updated
+ Your access token:
+ setAccessToken(e.target.value)} />
-
- setToast(null)}
- className="toast-close"
- />
+ )}
+ {loginType === 'oauth' && (
+
+ Login with Webex
+
+ )}
- )}
-
-
+
+
+
+
+
+
- Authentication
- {
- const selectedType = e.detail.value;
- if(selectedType !== 'token' && selectedType !== 'oauth') return;
- setLoginType(selectedType);
- }}
- >
- Access Token
- Login with Webex
-
-
-
- {loginType === 'token' && (
-
- Your access token:
- setAccessToken(e.target.value)}
- />
-
- )}
- {loginType === 'oauth' && (
-
- Login with Webex
-
- )}
+
Select Widgets to Show
+
+ {Object.keys(defaultWidgets).map((widget) => (
+ <>
+
+
+
+ {formatWidgetName(widget)}
+ {widget === 'outdialCall' && (
+
+ }
+ placement="auto-end"
+ closeButtonPlacement="top-left"
+ closeButtonProps={{'aria-label': 'Close'}}
+ >
+
+
+ Note: When a number is dialed, the agent gets an incoming task to
+ accept via an Extension, Dial Number, or Browser. It's recommended to have the
+ incoming task/task list widget and call controls widget according to your needs.
+
+
+
+
+ )}
+
+ >
+ ))}
-
-
-
-
-
- Select Widgets to Show
-
- {Object.keys(defaultWidgets).map((widget) => (
- <>
-
-
-
- {formatWidgetName(widget)}
- {widget === 'outdialCall' && (
-
- }
- placement="auto-end"
- closeButtonPlacement="top-left"
- closeButtonProps={{'aria-label': 'Close'}}
- >
-
-
- Note: When a number is dialed, the agent gets an incoming task to
- accept via an Extension, Dial Number, or Browser. It's recommended to have the
- incoming task/task list widget and call controls widget according to your needs.
-
-
-
-
- )}
-
- >
- ))}
-
-
-
-
-
-
-
-
- Sample App Toggles and Operations
- {
- setCurrentTheme(currentTheme === 'DARK' ? 'LIGHT' : 'DARK');
- store.setCurrentTheme(currentTheme === 'DARK' ? 'LIGHT' : 'DARK');
- }}
- />
- {
- setShowAgentProfile(!showAgentProfile);
- }}
- />
- {
- setDoStationLogout(!doStationLogout);
- }}
- />
- {
- setintegrationEnv(!integrationEnv);
- }}
- />
- {store.isAgentLoggedIn && (
-
- Station Logout
-
- )}
-
-
-
-
-
-
-
-
- {
- setShowLoader(true);
- store.init({webexConfig, access_token: accessToken}).then(() => {
- setIsSdkReady(true);
- setShowLoader(false);
- });
- }}
- data-testid="samples:init-widgets-button"
- >
- Init Widgets
-
-
- {isSdkReady && (
- <>
- {showAgentProfile && store.agentProfile && (
- <>
-
-
- Agent Profile
-
-
-
-
-
-
- Agent Name:
-
-
- {store.agentProfile.agentName}
-
-
-
-
- Profile Type:
-
-
- {store.agentProfile.profileType}
-
-
-
-
- Org ID:
-
-
- {store.agentProfile.orgId}
-
-
-
-
- Handle call using:
-
-
- {store.agentProfile.deviceType}
-
-
-
-
- Roles:
-
-
- {store.agentProfile.roles}
-
-
-
-
- MM Profile:
-
-
-
-
-
- {store.agentProfile.mmProfile &&
- Object.entries(store.agentProfile.mmProfile).map(([channel, count]) => (
-
-
- {channel.charAt(0).toUpperCase() + channel.slice(1)}
-
- {count}
-
- ))}
-
-
-
-
-
-
-
-
- >
- )}
- {selectedWidgets.stationLogin && (
-
-
-
- Station Login
-
-
-
-
-
-
- )}
- {selectedWidgets.stationLoginProfile && store.isAgentLoggedIn && (
-
-
-
- Station Login (Profile Mode)
-
-
+
+
+
+
+ Sample App Toggles and Operations
+ {
+ setCurrentTheme(currentTheme === 'DARK' ? 'LIGHT' : 'DARK');
+ store.setCurrentTheme(currentTheme === 'DARK' ? 'LIGHT' : 'DARK');
+ }}
+ />
+ {
+ setShowAgentProfile(!showAgentProfile);
+ }}
+ />
+ {
+ setDoStationLogout(!doStationLogout);
+ }}
+ />
+ {
+ setintegrationEnv(!integrationEnv);
+ }}
+ />
+ {store.isAgentLoggedIn && (
+
+ Station Logout
+
+ )}
+
+
+
+
-
- )}
- {(store.isAgentLoggedIn || isLoggedIn) && (
- <>
- {selectedWidgets.userState && (
-
-
+
+
+
+
+
+
+
+
+
+ {
+ setShowLoader(true);
+ store.init({webexConfig, access_token: accessToken}).then(() => {
+ setIsSdkReady(true);
+ setShowLoader(false);
+ });
+ }}
+ data-testid="samples:init-widgets-button"
+ >
+ Init Widgets
+
+
+ {isSdkReady && (
+ <>
+ {showAgentProfile && store.agentProfile && (
+ <>
+
+
+ Agent Profile
+
+
+
+
+
+
+ Agent Name:
+
+
+ {store.agentProfile.agentName}
+
+
+
+
+ Profile Type:
+
+
+ {store.agentProfile.profileType}
+
+
+
+
+ Org ID:
+
+
+ {store.agentProfile.orgId}
+
+
+
+
+ Handle call using:
+
+
+ {store.agentProfile.deviceType}
+
+
+
+
+ Roles:
+
+
+ {store.agentProfile.roles}
+
+
+
+
+ MM Profile:
+
+
+
+
+
+ {store.agentProfile.mmProfile &&
+ Object.entries(store.agentProfile.mmProfile).map(([channel, count]) => (
+
+
+ {channel.charAt(0).toUpperCase() + channel.slice(1)}
+
+ {count}
+
+ ))}
+
+
+
+
+
+
+
+
+ >
+ )}
+ {selectedWidgets.stationLogin && (
+
+
+
+ Station Login
+
+
- )}
- {selectedWidgets.callControl && store.currentTask && (
-
-
+
+
+
+ )}
+ {selectedWidgets.stationLoginProfile && store.isAgentLoggedIn && (
+
+
+
+ Station Login (Profile Mode)
+
+
- )}
- {selectedWidgets.callControlCAD && store.currentTask && (
-
-
-
- Call Control with Call Associated Data (CAD)
+
+
+
+ )}
+ {(store.isAgentLoggedIn || isLoggedIn) && (
+ <>
+ {selectedWidgets.userState && (
+
+ )}
+ {selectedWidgets.callControl && store.currentTask && (
+
+
+
+ Call Control
+
+
+
+
+
+
+ )}
+ {selectedWidgets.callControlCAD && store.currentTask && (
+
+
+
+ Call Control with Call Associated Data (CAD)
+
{
callControlClassName={'call-control-outer'}
callControlConsultClassName={'call-control-consult-outer'}
/>
-
-
-
- )}
-
- {selectedWidgets.incomingTask && (
- <>
-
-
- {incomingTasks.map((task) => (
- {
- if (collapsedTasks.includes(task.data.interactionId)) {
- setCollapsedTasks((prev) => prev.filter((id) => id !== task.data.interactionId));
- }
- }}
- >
- <>
- {
- e.stopPropagation();
- setIncomingTasks((prevTasks) =>
- prevTasks.filter((t) => t.data.interactionId !== task.data.interactionId)
- );
- }}
- >
- ×
-
-
- >
-
- ))}
-
-
- >
- )}
+
+
+
+
+ )}
- {selectedWidgets.taskList && (
-
+ {selectedWidgets.incomingTask && (
+ <>
+
-
- Task List
-
-
+ {incomingTasks.map((task) => (
+ {
+ if (collapsedTasks.includes(task.data.interactionId)) {
+ setCollapsedTasks((prev) => prev.filter((id) => id !== task.data.interactionId));
+ }
+ }}
+ >
+ <>
+ {
+ e.stopPropagation();
+ setIncomingTasks((prevTasks) =>
+ prevTasks.filter((t) => t.data.interactionId !== task.data.interactionId)
+ );
+ }}
+ >
+ ×
+
+
+ >
+
+ ))}
- )}
- {selectedWidgets.outdialCall &&
}
- >
- )}
- >
- )}
- {showRejectedPopup && (
-
-
- ×
-
-
- Task Rejected
-
-
-
- Reason: {rejectedReason}
-
-
-
{
- setSelectedState(e.detail.value);
- }}
- >
-
- Available
-
-
- Idle
-
-
-
- Confirm State Change
-
-
- )}
+ >
+ )}
+
+ {selectedWidgets.taskList && (
+
+ )}
+ {selectedWidgets.outdialCall && (
+
+
+
+ )}
+ >
+ )}
+ >
+ )}
+ {showRejectedPopup && (
+
+
+ ×
+
+
+ Task Rejected
+
+
+
+ Reason: {rejectedReason}
+
+
+
{
+ setSelectedState(e.detail.value);
+ }}
+ >
+
+ Available
+
+
+ Idle
+
+
+
+ Confirm State Change
+
+
+ )}
- {isSdkReady && (store.isAgentLoggedIn || isLoggedIn) && (
+ {isSdkReady && (store.isAgentLoggedIn || isLoggedIn) && (
+
- )}
-
-
-
+
+ )}
+
+
);
}
diff --git a/widgets-samples/cc/samples-cc-react-app/webpack.config.js b/widgets-samples/cc/samples-cc-react-app/webpack.config.js
index cfd17aaf2..54fb6dd75 100644
--- a/widgets-samples/cc/samples-cc-react-app/webpack.config.js
+++ b/widgets-samples/cc/samples-cc-react-app/webpack.config.js
@@ -17,6 +17,7 @@ module.exports = merge(baseConfig, {
'@webex/cc-user-state': path.resolve(__dirname, '../../../packages/contact-center/user-state/src'),
'@webex/cc-task': path.resolve(__dirname, '../../../packages/contact-center/task/src'),
'@webex/cc-components': path.resolve(__dirname, '../../../packages/contact-center/cc-components/src'),
+ '@webex/cc-widgets-provider': path.resolve(__dirname, '../../../packages/contact-center/WidgetsProvider/src'),
},
},
module: {
diff --git a/yarn.lock b/yarn.lock
index f84429f86..bf84ae33f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9604,6 +9604,52 @@ __metadata:
languageName: unknown
linkType: soft
+"@webex/cc-widgets-provider@workspace:*, @webex/cc-widgets-provider@workspace:packages/contact-center/WidgetsProvider":
+ version: 0.0.0-use.local
+ resolution: "@webex/cc-widgets-provider@workspace:packages/contact-center/WidgetsProvider"
+ dependencies:
+ "@babel/core": "npm:7.25.2"
+ "@babel/preset-env": "npm:7.25.4"
+ "@babel/preset-react": "npm:7.24.7"
+ "@babel/preset-typescript": "npm:7.25.9"
+ "@eslint/js": "npm:^9.20.0"
+ "@momentum-design/components": "npm:latest"
+ "@testing-library/dom": "npm:10.4.0"
+ "@testing-library/jest-dom": "npm:6.6.2"
+ "@testing-library/react": "npm:16.0.1"
+ "@types/jest": "npm:29.5.14"
+ "@types/node": "npm:^22.13.13"
+ "@types/react-test-renderer": "npm:18"
+ babel-jest: "npm:29.7.0"
+ babel-loader: "npm:9.2.1"
+ eslint: "npm:^9.20.1"
+ eslint-config-prettier: "npm:^10.0.1"
+ eslint-config-standard: "npm:^17.1.0"
+ eslint-plugin-import: "npm:^2.25.2"
+ eslint-plugin-n: "npm:^15.0.0 || ^16.0.0 "
+ eslint-plugin-prettier: "npm:^5.2.3"
+ eslint-plugin-promise: "npm:^6.0.0"
+ eslint-plugin-react: "npm:^7.37.4"
+ file-loader: "npm:6.2.0"
+ globals: "npm:^16.0.0"
+ jest: "npm:29.7.0"
+ jest-environment-jsdom: "npm:29.7.0"
+ prettier: "npm:^3.5.1"
+ react: "npm:18.3.1"
+ react-dom: "npm:18.3.1"
+ ts-loader: "npm:9.5.1"
+ typescript: "npm:5.6.3"
+ typescript-eslint: "npm:^8.24.1"
+ webpack: "npm:5.94.0"
+ webpack-cli: "npm:5.1.4"
+ webpack-merge: "npm:6.0.1"
+ peerDependencies:
+ "@momentum-design/components": ">=1.0.0"
+ react: ">=18.3.1"
+ react-dom: ">=18.3.1"
+ languageName: unknown
+ linkType: soft
+
"@webex/cc-widgets@workspace:*, @webex/cc-widgets@workspace:packages/contact-center/cc-widgets":
version: 0.0.0-use.local
resolution: "@webex/cc-widgets@workspace:packages/contact-center/cc-widgets"
@@ -31032,6 +31078,7 @@ __metadata:
"@eslint/js": "npm:^9.20.0"
"@momentum-ui/react-collaboration": "npm:26.197.0"
"@webex/cc-widgets": "workspace:*"
+ "@webex/cc-widgets-provider": "workspace:*"
babel-loader: "npm:^9.2.1"
eslint: "npm:^9.20.1"
eslint-config-prettier: "npm:^10.0.1"