diff --git a/packages/react-sdk-components/src/samples/Embedded/MainScreen/index.tsx b/packages/react-sdk-components/src/samples/Embedded/MainScreen/index.tsx
index de8b91f6..3ed8c5f6 100644
--- a/packages/react-sdk-components/src/samples/Embedded/MainScreen/index.tsx
+++ b/packages/react-sdk-components/src/samples/Embedded/MainScreen/index.tsx
@@ -1,9 +1,9 @@
-import { useEffect, useMemo, useState } from 'react';
+import { useEffect, useState } from 'react';
import { getSdkConfig } from '@pega/auth/lib/sdk-auth-manager';
import { makeStyles } from '@mui/styles';
-import StoreContext from '../../../bridge/Context/StoreContext';
-import createPConnectComponent from '../../../bridge/react_pconnect';
+import { usePegaAuth } from '../context/PegaAuthProvider';
+import { usePega } from '../context/PegaReadyContext';
import ShoppingOptionCard from '../ShoppingOptionCard';
import ResolutionScreen from '../ResolutionScreen';
@@ -105,45 +105,35 @@ const useStyles = makeStyles(theme => ({
pegaForm: {}
}));
-function RootComponent(props) {
- const PegaConnectObj = createPConnectComponent();
- const thePConnObj = ;
+export default function MainScreen() {
+ const { isAuthenticated } = usePegaAuth();
+ const { isPegaReady, PegaContainer, createCase } = usePega();
- /**
- * NOTE: For Embedded mode, we add in displayOnlyFA to our React context
- * so it is available to any component that may need it.
- * VRS: Attempted to remove displayOnlyFA but it presently handles various components which
- * SDK does not yet support, so all those need to be fixed up before it can be removed.
- * To be done in a future sprint.
- */
- const contextValue = useMemo(() => {
- return { store: PCore.getStore(), displayOnlyFA: true };
- }, [PCore.getStore()]);
-
- return {thePConnObj};
-}
-
-export default function MainScreen(props) {
const classes = useStyles();
+
const [showPega, setShowPega] = useState(false);
const [showLandingPage, setShowLandingPage] = useState(true);
const [showResolution, setShowResolution] = useState(false);
useEffect(() => {
- // Subscribe to the EVENT_CANCEL event to handle the assignment cancellation
- PCore.getPubSubUtils().subscribe(PCore.getConstants().PUB_SUB_EVENTS.EVENT_CANCEL, () => cancelAssignment(), 'cancelAssignment');
- // Subscribe to the END_OF_ASSIGNMENT_PROCESSING event to handle assignment completion
- PCore.getPubSubUtils().subscribe(
- PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.END_OF_ASSIGNMENT_PROCESSING,
- () => assignmentFinished(),
- 'endOfAssignmentProcessing'
- );
+ if (isPegaReady) {
+ // Subscribe to the EVENT_CANCEL event to handle the assignment cancellation
+ PCore.getPubSubUtils().subscribe(PCore.getConstants().PUB_SUB_EVENTS.EVENT_CANCEL, () => cancelAssignment(), 'cancelAssignment');
+
+ // Subscribe to the END_OF_ASSIGNMENT_PROCESSING event to handle assignment completion
+ PCore.getPubSubUtils().subscribe(
+ PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.END_OF_ASSIGNMENT_PROCESSING,
+ () => assignmentFinished(),
+ 'endOfAssignmentProcessing'
+ );
+ }
+
return () => {
// unsubscribe to the events
PCore.getPubSubUtils().unsubscribe(PCore.getConstants().PUB_SUB_EVENTS.EVENT_CANCEL, 'cancelAssignment');
PCore.getPubSubUtils().unsubscribe(PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.END_OF_ASSIGNMENT_PROCESSING, 'endOfAssignmentProcessing');
};
- }, []);
+ }, [isPegaReady]);
const cancelAssignment = () => {
setShowLandingPage(true);
@@ -159,14 +149,8 @@ export default function MainScreen(props) {
setShowLandingPage(false);
setShowPega(true);
const sdkConfig = await getSdkConfig();
- let mashupCaseType = sdkConfig.serverConfig.appMashupCaseType;
- // If mashupCaseType is null or undefined, get the first case type from the environment info
- if (!mashupCaseType) {
- const caseTypes = PCore.getEnvironmentInfo()?.environmentInfoObject?.pyCaseTypeList;
- if (caseTypes && caseTypes.length > 0) {
- mashupCaseType = mashupCaseType = caseTypes[0].pyWorkTypeImplementationClassName;
- }
- }
+ const mashupCaseType = sdkConfig.serverConfig.appMashupCaseType;
+
let selectedPhoneGUID = '';
const phoneName = optionClicked ? optionClicked.trim() : '';
switch (phoneName) {
@@ -198,12 +182,10 @@ export default function MainScreen(props) {
console.warn(`Unexpected case type: ${mashupCaseType}. PhoneModelss field not set.`);
}
- // Create a new case using the mashup API
- PCore.getMashupApi()
- .createCase(mashupCaseType, PCore.getConstants().APP.APP, options)
- .then(() => {
- console.log('createCase rendering is complete');
- });
+ // Call the createCase function from context to create a new case using the mashup API
+ createCase(mashupCaseType, options).then(() => {
+ console.log('createCase rendering is complete');
+ });
};
function renderLandingPage() {
@@ -244,13 +226,15 @@ export default function MainScreen(props) {
return (
);
}
+ if (!isAuthenticated) return Loading...
;
+
return (
{showLandingPage && renderLandingPage()}
diff --git a/packages/react-sdk-components/src/samples/Embedded/context/PegaAuthProvider.tsx b/packages/react-sdk-components/src/samples/Embedded/context/PegaAuthProvider.tsx
new file mode 100644
index 00000000..6ebecae6
--- /dev/null
+++ b/packages/react-sdk-components/src/samples/Embedded/context/PegaAuthProvider.tsx
@@ -0,0 +1,74 @@
+import { createContext, useContext, useEffect, useState } from 'react';
+import { getSdkConfig, loginIfNecessary, sdkSetAuthHeader, sdkSetCustomTokenParamsCB } from '@pega/auth/lib/sdk-auth-manager';
+
+interface AuthContextType {
+ isAuthenticated: boolean;
+}
+
+const UserAuthContext = createContext
(undefined);
+
+const PegaAuthProvider: React.FC = ({ children }) => {
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
+
+ const initialize = async () => {
+ try {
+ // Add event listener for when logged in and constellation bootstrap is loaded
+ document.addEventListener('SdkConstellationReady', () => {
+ setIsAuthenticated(true);
+ });
+
+ // Initialize authentication settings
+ await initializeAuthentication();
+
+ // this function will handle login process, and SdkConstellationReady event will be fired once PCore is ready
+ loginIfNecessary({ appName: 'embedded', mainRedirect: false });
+ } catch (error) {
+ console.error('Something went wrong while login', error);
+ }
+ };
+
+ useEffect(() => {
+ initialize();
+ }, []);
+
+ return {children};
+};
+
+export default PegaAuthProvider;
+
+export const usePegaAuth = (): AuthContextType => {
+ const context = useContext(UserAuthContext);
+ if (context === undefined) {
+ throw new Error('useAuth must be used within an AuthProvider');
+ }
+ return context;
+};
+
+async function initializeAuthentication() {
+ const { authConfig } = await getSdkConfig();
+
+ if ((authConfig.mashupGrantType === 'none' || !authConfig.mashupClientId) && authConfig.customAuthType === 'Basic') {
+ // Service package to use custom auth with Basic
+ const sB64 = window.btoa(`${authConfig.mashupUserIdentifier}:${window.atob(authConfig.mashupPassword)}`);
+ sdkSetAuthHeader(`Basic ${sB64}`);
+ }
+
+ if ((authConfig.mashupGrantType === 'none' || !authConfig.mashupClientId) && authConfig.customAuthType === 'BasicTO') {
+ const now = new Date();
+ const expTime = new Date(now.getTime() + 5 * 60 * 1000);
+ let sISOTime = `${expTime.toISOString().split('.')[0]}Z`;
+ const regex = /[-:]/g;
+ sISOTime = sISOTime.replace(regex, '');
+ // Service package to use custom auth with Basic
+ const sB64 = window.btoa(`${authConfig.mashupUserIdentifier}:${window.atob(authConfig.mashupPassword)}:${sISOTime}`);
+ sdkSetAuthHeader(`Basic ${sB64}`);
+ }
+
+ if (authConfig.mashupGrantType === 'customBearer' && authConfig.customAuthType === 'CustomIdentifier') {
+ // Use custom bearer with specific custom parameter to set the desired operator via
+ // a userIdentifier property. (Caution: highly insecure...being used for simple demonstration)
+ sdkSetCustomTokenParamsCB(() => {
+ return { userIdentifier: authConfig.mashupUserIdentifier };
+ });
+ }
+}
diff --git a/packages/react-sdk-components/src/samples/Embedded/context/PegaReadyContext.tsx b/packages/react-sdk-components/src/samples/Embedded/context/PegaReadyContext.tsx
new file mode 100644
index 00000000..0cba0fa5
--- /dev/null
+++ b/packages/react-sdk-components/src/samples/Embedded/context/PegaReadyContext.tsx
@@ -0,0 +1,151 @@
+import { createContext, useContext, useEffect, useMemo, useState } from 'react';
+import { CssBaseline, StyledEngineProvider, ThemeProvider } from '@mui/material';
+import type { CaseOptions } from '@pega/pcore-pconnect-typedefs/mashup/types';
+
+import StoreContext from '../../../bridge/Context/StoreContext';
+import createPConnectComponent from '../../../bridge/react_pconnect';
+import { getSdkComponentMap } from '../../../bridge/helpers/sdk_component_map';
+
+import localSdkComponentMap from '../../../../sdk-local-component-map';
+
+import { usePegaAuth } from './PegaAuthProvider';
+
+function RootComponent(props) {
+ const PegaConnectObj = createPConnectComponent();
+ const thePConnObj = ;
+
+ /**
+ * NOTE: For Embedded mode, we add in displayOnlyFA to our React context
+ * so it is available to any component that may need it.
+ * VRS: Attempted to remove displayOnlyFA but it presently handles various components which
+ * SDK does not yet support, so all those need to be fixed up before it can be removed.
+ * To be done in a future sprint.
+ */
+ const contextValue = useMemo(() => {
+ return { store: PCore.getStore(), displayOnlyFA: true };
+ }, [PCore.getStore()]);
+
+ return {thePConnObj};
+}
+
+interface PegaContextProps {
+ isPegaReady: boolean;
+ rootPConnect?: typeof PConnect; // Function to get Pega Connect object, if available
+ createCase: (mashupCaseType: string, options: CaseOptions) => Promise;
+ PegaContainer: React.FC;
+}
+
+declare const myLoadMashup: any;
+
+const PegaContext = createContext(undefined);
+
+interface PegaReadyProviderProps {
+ theme: any;
+}
+
+export const PegaReadyProvider: React.FC> = ({ children, theme }) => {
+ const { isAuthenticated } = usePegaAuth();
+ const [isPegaReady, setIsPegaReady] = useState(false);
+ const [rootProps, setRootProps] = useState<{
+ getPConnect?: () => typeof PConnect;
+ [key: string]: any;
+ }>({});
+
+ const [loading, setLoading] = useState(false);
+
+ const startMashup = async () => {
+ try {
+ PCore.onPCoreReady(async renderObj => {
+ console.log(`PCore ready!`);
+
+ const theComponentMap = await getSdkComponentMap(localSdkComponentMap);
+ console.log(`SdkComponentMap initialized`, theComponentMap);
+
+ const { props } = renderObj;
+ setRootProps(props);
+ setIsPegaReady(true);
+ });
+
+ // load the Mashup and handle the onPCoreEntry response that establishes the
+ // top level Pega root element (likely a RootContainer)
+ myLoadMashup('pega-root', false); // this is defined in bootstrap shell that's been loaded already
+ } catch (error) {
+ console.error('Error loading pega:', error);
+ }
+ };
+
+ /**
+ * Start the mashup once authenticated
+ * This ensures that the Pega environment is ready for use
+ */
+ useEffect(() => {
+ if (isAuthenticated) {
+ startMashup();
+ }
+ }, [isAuthenticated]);
+
+ // Memoize the root PConnect function to avoid unnecessary re-renders
+ const rootPConnect = useMemo(() => {
+ if (rootProps && rootProps?.getPConnect) {
+ return rootProps.getPConnect();
+ }
+
+ return undefined;
+ }, [rootProps]);
+
+ const createCase = (mashupCaseType: string, options: CaseOptions) => {
+ if (!isPegaReady) {
+ console.error('Pega is not ready. Cannot create case.');
+ return Promise.reject('Pega is not ready');
+ }
+
+ setLoading(true);
+ return new Promise((resolve, reject) => {
+ // If mashupCaseType is null or undefined, get the first case type from the environment info
+ if (!mashupCaseType) {
+ const caseTypes = PCore.getEnvironmentInfo()?.environmentInfoObject?.pyCaseTypeList;
+ if (caseTypes && caseTypes.length > 0) {
+ mashupCaseType = caseTypes[0].pyWorkTypeImplementationClassName;
+ }
+ }
+
+ PCore.getMashupApi()
+ .createCase(mashupCaseType, PCore.getConstants().APP.APP, options)
+ .then(() => {
+ resolve();
+ })
+ .catch(error => {
+ console.error('Error creating case:', error);
+ reject(error);
+ })
+ .finally(() => {
+ setLoading(false);
+ });
+ });
+ };
+
+ const PegaContainer = () => {
+ if (loading) return Loading...
;
+
+ return isPegaReady ? : null;
+ };
+
+ return (
+
+
+
+
+ {children}
+
+
+
+ );
+};
+
+export const usePega = () => {
+ const context = useContext(PegaContext);
+ if (!context) {
+ throw new Error('usePega must be used within a PegaProvider');
+ }
+ return context;
+};
diff --git a/packages/react-sdk-components/src/samples/Embedded/index.tsx b/packages/react-sdk-components/src/samples/Embedded/index.tsx
index e7c891a8..7a88c9d3 100644
--- a/packages/react-sdk-components/src/samples/Embedded/index.tsx
+++ b/packages/react-sdk-components/src/samples/Embedded/index.tsx
@@ -1,83 +1,20 @@
-import { useEffect, useState } from 'react';
-import { CssBaseline, StyledEngineProvider, ThemeProvider } from '@mui/material';
-import { getSdkConfig, loginIfNecessary } from '@pega/auth/lib/sdk-auth-manager';
-
-import { getSdkComponentMap } from '../../bridge/helpers/sdk_component_map';
-import { compareSdkPCoreVersions } from '../../components/helpers/versionHelpers';
+import PegaAuthProvider from './context/PegaAuthProvider';
+import { PegaReadyProvider } from './context/PegaReadyContext';
import Header from './Header';
import MainScreen from './MainScreen';
-import localSdkComponentMap from '../../../sdk-local-component-map';
-import { initializeAuthentication } from './utils';
import { theme } from '../../theme';
import './styles.css';
-declare const myLoadMashup: any;
-
export default function Embedded() {
- const [isLoggedIn, setIsLoggedIn] = useState(false);
- const [rootProps, setRootProps] = useState({});
-
- useEffect(() => {
- initialize();
- }, []);
-
- const initialize = async () => {
- try {
- // Add event listener for when logged in and constellation bootstrap is loaded
- document.addEventListener('SdkConstellationReady', () => handleSdkConstellationReady());
-
- const { authConfig } = await getSdkConfig();
- initializeAuthentication(authConfig);
-
- // this function will handle login process, and SdkConstellationReady event will be fired once PCore is ready
- loginIfNecessary({ appName: 'embedded', mainRedirect: false });
- } catch (error) {
- console.error('Something went wrong while login', error);
- }
- };
-
- const initializeRootContainerProps = renderObj => {
- const { props } = renderObj;
-
- setRootProps(props);
- };
-
- const startMashup = () => {
- PCore.onPCoreReady(async renderObj => {
- // Check that we're seeing the PCore version we expect
- compareSdkPCoreVersions();
-
- await getSdkComponentMap(localSdkComponentMap);
-
- console.log(`SdkComponentMap initialized`);
-
- // Don't call initializeRootContainerProps until SdkComponentMap is fully initialized
- initializeRootContainerProps(renderObj);
- });
-
- myLoadMashup('pega-root', false); // this is defined in bootstrap shell that's been loaded already
- };
-
- const handleSdkConstellationReady = () => {
- setIsLoggedIn(true);
-
- startMashup();
- };
-
return (
-
-
-
- {isLoggedIn ? (
- <>
-
-
- >
- ) : (
- Loading...
- )}
-
-
+
+
+ <>
+
+
+ >
+
+
);
}