Skip to content

Commit 1e6fe57

Browse files
4manasamanasa
andauthored
Added SelfServiceCaseView template to react SDK (#498)
* Added SelfServiceCaseView template to react SDK --------- Co-authored-by: manasa <[email protected]>
1 parent f60b361 commit 1e6fe57

File tree

4 files changed

+218
-88
lines changed

4 files changed

+218
-88
lines changed

packages/react-sdk-components/src/components/template/CaseSummary/CaseSummary.tsx

Lines changed: 5 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,22 @@
1-
import type { PropsWithChildren, ReactElement } from 'react';
1+
import type { PropsWithChildren } from 'react';
22
import { getComponentFromMap } from '../../../bridge/helpers/sdk_component_map';
33
import type { PConnProps } from '../../../types/PConnProps';
44

55
interface CaseSummaryProps extends PConnProps {
66
// If any, enter additional props that only exist on this component
7+
arPrimaryFields: any[];
8+
arSecondaryFields: any[];
79
}
810

911
export default function CaseSummary(props: PropsWithChildren<CaseSummaryProps>) {
1012
// Get emitted components from map (so we can get any override that may exist)
1113
const CaseSummaryFields = getComponentFromMap('CaseSummaryFields');
1214

13-
const { getPConnect, children } = props;
14-
15-
const thePConn = getPConnect();
16-
const theConfigProps: any = thePConn.getConfigProps();
17-
// const { status, showStatus } = theConfigProps;
18-
const status = theConfigProps.status;
19-
const showStatus = theConfigProps.showStatus;
20-
const localizedVal = PCore.getLocaleUtils().getLocaleValue;
21-
const localeCategory = 'ModalContainer';
22-
// from Constellation DX Components
23-
// get the primary and secondary fields with the raw data (which has the non-resolved property values)
24-
// const regionsRaw = getPConnect().getRawMetadata().children;
25-
// const primaryFieldsRaw = regionsRaw[0].children;
26-
// const secondaryFieldsRaw = regionsRaw[1].children;
27-
28-
// From other SDKs
29-
// may want to move these into useEffect/useState combo
30-
let arPrimaryFields: any[] = [];
31-
let arSecondaryFields: any[] = [];
32-
33-
function prepareComponentInCaseSummary(pConnectMeta, getPConnect) {
34-
const { config, children } = pConnectMeta;
35-
const pConnect = getPConnect();
36-
37-
const caseSummaryComponentObject: any = {};
38-
39-
const { type } = pConnectMeta;
40-
const createdComponent = pConnect.createComponent({
41-
type,
42-
children: children ? [...children] : [],
43-
config: {
44-
...config
45-
}
46-
});
47-
48-
caseSummaryComponentObject.value = createdComponent;
49-
return caseSummaryComponentObject;
50-
}
51-
52-
function prepareCaseSummaryData(summaryFieldChildren) {
53-
const convertChildrenToSummaryData = kid => {
54-
return kid?.map((childItem, index) => {
55-
const childMeta = childItem.getPConnect().meta;
56-
const caseSummaryComponentObject = prepareComponentInCaseSummary(childMeta, childItem.getPConnect);
57-
caseSummaryComponentObject.id = index + 1;
58-
return caseSummaryComponentObject;
59-
});
60-
};
61-
return summaryFieldChildren ? convertChildrenToSummaryData(summaryFieldChildren?.getChildren()) : undefined;
62-
}
63-
64-
for (const child of children as ReactElement[]) {
65-
const childPConn = (child as ReactElement).props.getPConnect();
66-
const childPConnData = childPConn.resolveConfigProps(childPConn.getRawMetadata());
67-
if (childPConnData.name.toLowerCase() === 'primary fields') {
68-
arPrimaryFields = childPConnData.children;
69-
arPrimaryFields.forEach(field => {
70-
if (field.config?.value && typeof field.config?.value === 'string') {
71-
field.config.value = localizedVal(field.config.value, localeCategory);
72-
}
73-
});
74-
} else if (childPConnData.name.toLowerCase() === 'secondary fields') {
75-
const secondarySummaryFields = prepareCaseSummaryData(childPConn);
76-
arSecondaryFields = childPConnData.children;
77-
arSecondaryFields.forEach((field, index) => {
78-
field.config.displayLabel = secondarySummaryFields[index]?.value?.props?.label;
79-
});
80-
}
81-
}
82-
83-
// At this point, should hand off to another component for layout and rendering
84-
// of primary and secondary fields in the Case Summary
85-
86-
// debugging/investigation help
87-
// console.log(`CaseSummary: arPrimaryFields: ${JSON.stringify(arPrimaryFields)}`);
88-
// console.log(`CaseSummary: arSecondaryFields: ${JSON.stringify(arSecondaryFields)}`);
15+
const { arPrimaryFields, arSecondaryFields } = props;
8916

9017
return (
9118
<div id='CaseSummary'>
92-
<CaseSummaryFields status={status} showStatus={showStatus} theFields={arPrimaryFields} />
19+
<CaseSummaryFields theFields={arPrimaryFields} />
9320
<CaseSummaryFields theFields={arSecondaryFields} />
9421
</div>
9522
);

packages/react-sdk-components/src/components/template/CaseView/CaseView.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Utils } from '../../helpers/utils';
99
import StoreContext from '../../../bridge/Context/StoreContext';
1010
import { getComponentFromMap } from '../../../bridge/helpers/sdk_component_map';
1111
import type { PConnProps } from '../../../types/PConnProps';
12+
import { prepareCaseSummaryData } from '../utils';
1213

1314
interface CaseViewProps extends PConnProps {
1415
// If any, enter additional props that only exist on this component
@@ -52,19 +53,17 @@ export default function CaseView(props: PropsWithChildren<CaseViewProps>) {
5253
const CaseViewActionsMenu = getComponentFromMap('CaseViewActionsMenu');
5354
const VerticalTabs = getComponentFromMap('VerticalTabs');
5455
const DeferLoad = getComponentFromMap('DeferLoad');
56+
const CaseSummary = getComponentFromMap('CaseSummary');
5557

5658
const {
5759
getPConnect,
5860
icon = '',
5961
header,
6062
subheader,
6163
children = [],
62-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
63-
showIconInHeader = true,
6464
caseInfo: { availableActions = [], availableProcesses = [], hasNewAttachments, caseTypeID = '', caseTypeName = '' }
6565
} = props;
6666
const { lastUpdateCaseTime = getPConnect().getValue('caseInfo.lastUpdateTime') } = props;
67-
6867
const currentCaseID = props.caseInfo.ID;
6968
let isComponentMounted = true;
7069
const { displayOnlyFA } = useContext<any>(StoreContext);
@@ -84,9 +83,8 @@ export default function CaseView(props: PropsWithChildren<CaseViewProps>) {
8483
*/
8584
function getChildRegionByName(inName: string): any {
8685
for (const child of children as ReactElement[]) {
87-
const theMetadataType: string = (child as ReactElement).props.getPConnect().getRawMetadata().type.toLowerCase();
88-
const theMetadataName: string = (child as ReactElement).props.getPConnect().getRawMetadata().name.toLowerCase();
89-
86+
const theMetadataType: string = (child as ReactElement).props.getPConnect().getRawMetadata().type?.toLowerCase();
87+
const theMetadataName: string = (child as ReactElement).props.getPConnect().getRawMetadata().name?.toLowerCase();
9088
if (theMetadataType === 'region' && theMetadataName === inName) {
9189
return child;
9290
}
@@ -95,7 +93,12 @@ export default function CaseView(props: PropsWithChildren<CaseViewProps>) {
9593
return null;
9694
}
9795

98-
const theSummaryRegion = getChildRegionByName('summary');
96+
const theSummaryRegion = children && children[0];
97+
98+
const data = prepareCaseSummaryData(theSummaryRegion);
99+
const primarySummaryFields = data.primarySummaryFields;
100+
const secondarySummaryFields = data.secondarySummaryFields;
101+
99102
const theStagesRegion = getChildRegionByName('stages');
100103
const theTodoRegion = getChildRegionByName('todo');
101104
const theUtilitiesRegion = getChildRegionByName('utilities');
@@ -109,7 +112,7 @@ export default function CaseView(props: PropsWithChildren<CaseViewProps>) {
109112
// const tmpLoadData2 = { config: { label: "Case History", name: "CaseHistory" }, type: "DeferLoad" };
110113

111114
// Extract the tabs we need to display from theTabsRegion (one tab per entry in theTabsRegionChildren)
112-
const theTabsRegionChildren = theTabsRegion.props.getPConnect().getChildren();
115+
const theTabsRegionChildren = theTabsRegion?.props.getPConnect().getChildren();
113116

114117
// vertTabInfo is sent to VerticalTabs component
115118
const vertTabInfo: object[] = [];
@@ -232,7 +235,7 @@ export default function CaseView(props: PropsWithChildren<CaseViewProps>) {
232235
/>
233236
{getActionButtonsHtml()}
234237
<Divider />
235-
{theSummaryRegion}
238+
<CaseSummary arPrimaryFields={primarySummaryFields} arSecondaryFields={secondarySummaryFields}></CaseSummary>
236239
<Divider />
237240
{vertTabInfo.length > 1 && <VerticalTabs tabconfig={vertTabInfo} />}
238241
</Card>
Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,145 @@
1+
import { Avatar, Card, CardHeader, Divider, Typography } from '@mui/material';
2+
import makeStyles from '@mui/styles/makeStyles';
3+
import Grid2 from '@mui/material/Grid2';
4+
import { getComponentFromMap } from '../../../bridge/helpers/sdk_component_map';
5+
import { prepareCaseSummaryData, filterUtilities } from '../utils';
6+
import { Utils } from '../../helpers/utils';
7+
8+
const useStyles = makeStyles(theme => ({
9+
root: {
10+
paddingRight: theme.spacing(1),
11+
paddingLeft: theme.spacing(1),
12+
paddingTop: theme.spacing(1),
13+
paddingBottom: theme.spacing(1),
14+
marginRight: theme.spacing(1),
15+
marginLeft: theme.spacing(1),
16+
marginTop: theme.spacing(1),
17+
marginBottom: theme.spacing(1)
18+
},
19+
caseViewHeader: {
20+
backgroundColor: theme.palette.info.light,
21+
color: theme.palette.getContrastText(theme.palette.info.light),
22+
borderRadius: 'inherit'
23+
},
24+
caseViewIconBox: {
25+
backgroundColor: theme.palette.info.dark,
26+
width: theme.spacing(8),
27+
height: theme.spacing(8),
28+
padding: theme.spacing(1)
29+
},
30+
caseViewIconImage: {
31+
filter: 'var(--svg-color)'
32+
}
33+
}));
34+
135
export default function SelfServiceCaseView(props) {
2-
console.log('SelfServiceCaseView props:', props);
36+
const classes = useStyles();
37+
const CaseViewActionsMenu = getComponentFromMap('CaseViewActionsMenu');
38+
const CaseSummary = getComponentFromMap('CaseSummary');
39+
const {
40+
icon = '',
41+
getPConnect,
42+
header,
43+
subheader,
44+
showCaseLifecycle = true,
45+
showSummaryRegion = true,
46+
showUtilitiesRegion = true,
47+
showCaseActions = true,
48+
children,
49+
caseClass,
50+
caseInfo: { availableActions = [], availableProcesses = [], caseTypeID = '', caseTypeName = '' }
51+
} = props;
52+
const pConnect = getPConnect();
53+
const [bShowCaseLifecycle, bShowSummaryRegion, bShowUtilitiesRegion, bShowCaseActions] = [
54+
showCaseLifecycle,
55+
showSummaryRegion,
56+
showUtilitiesRegion,
57+
showCaseActions
58+
].map((prop: boolean | string) => prop === true || prop === 'true');
59+
const isObjectType: boolean = (PCore.getCaseUtils() as any).isObjectCaseType(caseClass);
60+
const localeKey = pConnect?.getCaseLocaleReference();
61+
const svgCase = Utils.getImageSrc(icon, Utils.getSDKStaticConentUrl());
62+
const renderedRegions: any = isObjectType
63+
? {
64+
caseSummary: children[0],
65+
utilities: filterUtilities(children[2])
66+
}
67+
: {
68+
caseSummary: children[0],
69+
stages: children[1],
70+
todo: children[2],
71+
utilities: filterUtilities(children[4])
72+
};
73+
const { primarySummaryFields, secondarySummaryFields } = prepareCaseSummaryData(
74+
renderedRegions.caseSummary,
75+
(config: any) => config?.availableInChannel?.selfService === true
76+
);
77+
78+
const isUtilitiesRegionNotEmpty: () => boolean = () => {
79+
const utilitiesElement = renderedRegions.utilities;
80+
if (utilitiesElement?.props?.getPConnect()?.getChildren()?.length > 0) {
81+
return utilitiesElement.props
82+
.getPConnect()
83+
.getChildren()
84+
.some((prop: { getPConnect: () => any }) => prop.getPConnect().getConfigProps().visibility !== false);
85+
}
86+
return false;
87+
};
88+
89+
return (
90+
<div>
91+
{bShowCaseActions && (
92+
<div style={{ display: 'flex', justifyContent: 'space-around', alignItems: 'center', margin: '10px' }}>
93+
<div>{PCore.getLocaleUtils().getLocaleValue(header, '', localeKey)}</div>
94+
<CaseViewActionsMenu
95+
getPConnect={getPConnect}
96+
availableActions={availableActions}
97+
availableProcesses={availableProcesses}
98+
caseTypeName={caseTypeName}
99+
caseTypeID={caseTypeID}
100+
/>
101+
</div>
102+
)}
103+
<div>
104+
<Grid2 container>
105+
<Grid2 size={{ xs: 3 }}>
106+
{bShowSummaryRegion && (primarySummaryFields.length > 0 || secondarySummaryFields.length > 0) && (
107+
<div>
108+
<Card className={classes.root}>
109+
<CardHeader
110+
className={classes.caseViewHeader}
111+
title={
112+
<Typography variant='h6' component='div' id='case-name'>
113+
{PCore.getLocaleUtils().getLocaleValue(header, '', localeKey)}
114+
</Typography>
115+
}
116+
subheader={
117+
<Typography variant='body1' component='div' id='caseId'>
118+
{subheader}
119+
</Typography>
120+
}
121+
avatar={
122+
<Avatar className={classes.caseViewIconBox} variant='square'>
123+
<img src={svgCase} className={classes.caseViewIconImage} />
124+
</Avatar>
125+
}
126+
/>
127+
<Divider />
128+
<CaseSummary arPrimaryFields={primarySummaryFields} arSecondaryFields={secondarySummaryFields}></CaseSummary>
129+
<Divider />
130+
</Card>
131+
</div>
132+
)}
133+
</Grid2>
134+
135+
<Grid2 size={{ xs: 6 }}>
136+
{bShowCaseLifecycle && renderedRegions.stages}
137+
{renderedRegions.todo}
138+
</Grid2>
139+
140+
{bShowUtilitiesRegion && isUtilitiesRegionNotEmpty() && <Grid2 size={{ xs: 3 }}>{renderedRegions.utilities}</Grid2>}
141+
</Grid2>
142+
</div>
143+
</div>
144+
);
3145
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { ReactNode } from 'react';
2+
import { isValidElement } from 'react';
3+
4+
export function prepareCaseSummaryData(caseSummaryRegion, portalSpecificVisibilityChecker?) {
5+
const filterVisibleChildren = children => {
6+
return children
7+
?.getPConnect()
8+
?.getChildren()
9+
?.filter(child => {
10+
const configProps = child.getPConnect().getConfigProps();
11+
const defaultVisibilityCn = !('visibility' in configProps) || configProps.visibility === true;
12+
return defaultVisibilityCn && (portalSpecificVisibilityChecker?.(configProps) ?? true);
13+
});
14+
};
15+
const convertChildrenToSummaryData = children => {
16+
return children?.map(childItem => {
17+
const childPConnData = childItem.getPConnect().resolveConfigProps(childItem.getPConnect().getRawMetadata());
18+
return childPConnData;
19+
});
20+
};
21+
22+
const summaryFieldChildren = caseSummaryRegion.props
23+
.getPConnect()
24+
.getChildren()[0]
25+
?.getPConnect()
26+
?.getReferencedViewPConnect()
27+
?.getPConnect()
28+
?.getChildren();
29+
30+
const primarySummaryFields =
31+
summaryFieldChildren && summaryFieldChildren.length > 0
32+
? convertChildrenToSummaryData(filterVisibleChildren(summaryFieldChildren[0]))
33+
: undefined;
34+
const secondarySummaryFields =
35+
summaryFieldChildren && summaryFieldChildren.length > 1
36+
? convertChildrenToSummaryData(filterVisibleChildren(summaryFieldChildren[1]))
37+
: undefined;
38+
39+
return {
40+
primarySummaryFields,
41+
secondarySummaryFields
42+
};
43+
}
44+
45+
export const filterUtilities = (utils: ReactNode) => {
46+
let utilsMeta;
47+
if (isValidElement(utils)) {
48+
const pConnect = utils.props.getPConnect();
49+
utilsMeta = pConnect.getRawMetadata?.();
50+
if (!utilsMeta?.children?.length) return;
51+
utilsMeta = {
52+
...utilsMeta,
53+
children: utilsMeta.children.filter((child: any) => child.config?.availableInChannel?.selfService === true)
54+
};
55+
return utilsMeta.children?.length ? pConnect.createComponent(utilsMeta) : undefined;
56+
}
57+
return utilsMeta;
58+
};

0 commit comments

Comments
 (0)