Skip to content

Commit 2804b2c

Browse files
author
manasa
committed
Added support for cards in DataReference
1 parent 5756597 commit 2804b2c

File tree

5 files changed

+516
-2
lines changed

5 files changed

+516
-2
lines changed

packages/react-sdk-components/src/components/field/Checkbox/Checkbox.tsx

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import handleEvent from '../../helpers/event-utils';
77
import { getComponentFromMap } from '../../../bridge/helpers/sdk_component_map';
88
import { insertInstruction, deleteInstruction, updateNewInstuctions } from '../../helpers/instructions-utils';
99
import { PConnFieldProps } from '../../../types/PConnProps';
10+
import SelectableCard from '../SelectableCard/SelectableCard';
1011

1112
interface CheckboxProps extends Omit<PConnFieldProps, 'value'> {
1213
// If any, enter additional props that only exist on Checkbox here
@@ -21,6 +22,14 @@ interface CheckboxProps extends Omit<PConnFieldProps, 'value'> {
2122
primaryField: string;
2223
readonlyContextList: any;
2324
referenceList: string;
25+
variant?: string;
26+
hideFieldLabels: boolean;
27+
additionalProps: any;
28+
imagePosition: string;
29+
imageSize: string;
30+
showImageDescription: string;
31+
renderMode: string;
32+
image: string;
2433
}
2534

2635
const useStyles = makeStyles(() => ({
@@ -56,8 +65,17 @@ export default function CheckboxComponent(props: CheckboxProps) {
5665
selectionList,
5766
primaryField,
5867
referenceList,
59-
readonlyContextList: selectedvalues
68+
readonlyContextList: selectedvalues,
69+
variant,
70+
hideFieldLabels,
71+
additionalProps,
72+
imagePosition,
73+
imageSize,
74+
showImageDescription,
75+
renderMode,
76+
image
6077
} = props;
78+
const [theSelectedButton, setSelectedButton] = useState(value);
6179
const classes = useStyles();
6280
const helperTextToDisplay = validatemessage || helperText;
6381
const thePConn = getPConnect();
@@ -77,6 +95,11 @@ export default function CheckboxComponent(props: CheckboxProps) {
7795
}
7896
}, [thePConn]);
7997

98+
useEffect(() => {
99+
// This update theSelectedButton which will update the UI to show the selected button correctly
100+
setSelectedButton(value);
101+
}, [value]);
102+
80103
if (displayMode === 'DISPLAY_ONLY') {
81104
return <FieldValueList name={hideLabel ? '' : caption} value={value ? trueLabel : falseLabel} />;
82105
}
@@ -93,6 +116,66 @@ export default function CheckboxComponent(props: CheckboxProps) {
93116
thePConn.getValidationApi().validate(event.target.checked);
94117
};
95118

119+
const handleCheckboxChange = (event, item) => {
120+
if (event.target.checked) {
121+
insertInstruction(thePConn, selectionList, selectionKey, primaryField, item);
122+
} else {
123+
deleteInstruction(thePConn, selectionList, selectionKey, item);
124+
}
125+
thePConn.clearErrorMessages({ property: selectionList });
126+
};
127+
128+
const actions = thePConn.getActionsApi();
129+
130+
const commonProps = {
131+
...additionalProps,
132+
className: 'standard',
133+
disabled,
134+
readOnly,
135+
onClick: (actions as any).onClick
136+
};
137+
138+
if (variant === 'card') {
139+
return (
140+
<div>
141+
<h4 style={{ marginTop: 0, marginBottom: 0 }}>{label}</h4>
142+
<SelectableCard
143+
{...commonProps}
144+
testId={testId}
145+
displayMode={displayMode}
146+
dataSource={datasource}
147+
getPConnect={getPConnect}
148+
readOnly={renderMode === 'ReadOnly' || displayMode === 'DISPLAY_ONLY' || readOnly}
149+
onChange={e => {
150+
e.stopPropagation();
151+
const recordKey = selectionKey?.split('.').pop();
152+
const selectedItem = datasource?.source?.find(item => item[recordKey as any] === e.target.id) ?? {};
153+
handleCheckboxChange(e, {
154+
id: selectedItem[recordKey as any],
155+
primary: selectedItem[recordKey as any]
156+
});
157+
}}
158+
onBlur={() => {
159+
thePConn.getValidationApi().validate(selectedvalues, selectionList);
160+
}}
161+
hideFieldLabels={hideFieldLabels}
162+
recordKey={selectionKey?.split('.').pop()}
163+
cardLabel={primaryField.split('.').pop()}
164+
image={{
165+
imagePosition,
166+
imageSize,
167+
showImageDescription,
168+
imageField: image?.split('.').pop(),
169+
imageDescription: (thePConn?.getRawMetadata()?.config as any).imageDescription?.split('.').pop()
170+
}}
171+
readOnlyList={selectedvalues}
172+
type='checkbox'
173+
showNoValue={(renderMode === 'ReadOnly' || readOnly || displayMode === 'DISPLAY_ONLY') && selectedvalues.length === 0}
174+
/>
175+
</div>
176+
);
177+
}
178+
96179
const handleChangeMultiMode = (event, element) => {
97180
if (event.target.checked) {
98181
insertInstruction(thePConn, selectionList, selectionKey, primaryField, {

packages/react-sdk-components/src/components/field/RadioButtons/RadioButtons.tsx

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@ import Utils from '../../helpers/utils';
55
import handleEvent from '../../helpers/event-utils';
66
import { getComponentFromMap } from '../../../bridge/helpers/sdk_component_map';
77
import { PConnFieldProps } from '../../../types/PConnProps';
8+
import SelectableCard from '../SelectableCard/SelectableCard';
89

910
// Can't use RadioButtonProps until getLocaleRuleNameFromKeys is NOT private
1011
interface RadioButtonsProps extends PConnFieldProps {
1112
// If any, enter additional props that only exist on RadioButtons here
1213
inline: boolean;
1314
fieldMetadata?: any;
15+
variant?: string;
16+
hideFieldLabels?: boolean;
17+
additionalProps?: any;
18+
imagePosition?: string;
19+
imageSize?: string;
20+
showImageDescription?: boolean;
21+
datasource?: any;
1422
}
1523

1624
export default function RadioButtons(props: RadioButtonsProps) {
@@ -29,7 +37,14 @@ export default function RadioButtons(props: RadioButtonsProps) {
2937
inline,
3038
displayMode,
3139
hideLabel,
32-
fieldMetadata
40+
fieldMetadata,
41+
variant,
42+
hideFieldLabels,
43+
additionalProps,
44+
datasource,
45+
imagePosition,
46+
imageSize,
47+
showImageDescription
3348
} = props;
3449
const [theSelectedButton, setSelectedButton] = useState(value);
3550

@@ -65,6 +80,7 @@ export default function RadioButtons(props: RadioButtonsProps) {
6580
return (
6681
<FieldValueList
6782
name={hideLabel ? '' : label}
83+
// @ts-ignore - Property 'getLocaleRuleNameFromKeys' is private and only accessible within class 'C11nEnv'
6884
value={thePConn.getLocalizedValue(value, localePath, thePConn.getLocaleRuleNameFromKeys(localeClass, localeContext, localeName))}
6985
/>
7086
);
@@ -74,6 +90,7 @@ export default function RadioButtons(props: RadioButtonsProps) {
7490
return (
7591
<FieldValueList
7692
name={hideLabel ? '' : label}
93+
// @ts-ignore - Property 'getLocaleRuleNameFromKeys' is private and only accessible within class 'C11nEnv'
7794
value={thePConn.getLocalizedValue(value, localePath, thePConn.getLocaleRuleNameFromKeys(localeClass, localeContext, localeName))}
7895
variant='stacked'
7996
/>
@@ -88,6 +105,36 @@ export default function RadioButtons(props: RadioButtonsProps) {
88105
thePConn.getValidationApi().validate(event.target.value, ''); // 2nd arg empty string until typedef marked correctly as optional
89106
};
90107

108+
if (variant === 'card') {
109+
const stateProps = thePConn.getStateProps();
110+
return (
111+
<div>
112+
<h4 style={{ marginTop: 0, marginBottom: 0 }}>{label}</h4>
113+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 40ch), 1fr))', gridAutoRows: '1fr', gap: '0.5rem' }}>
114+
<SelectableCard
115+
hideFieldLabels={hideFieldLabels}
116+
additionalProps={additionalProps}
117+
getPConnect={getPConnect}
118+
dataSource={datasource}
119+
image={{
120+
imagePosition,
121+
imageSize,
122+
showImageDescription,
123+
imageField: stateProps.image?.split('.').pop(),
124+
imageDescription: stateProps.imageDescription?.split('.').pop()
125+
}}
126+
onChange={handleChange}
127+
recordKey={stateProps.value?.split('.').pop()}
128+
cardLabel={stateProps.primaryField?.split('.').pop()}
129+
radioBtnValue={value}
130+
type='radio'
131+
setIsRadioCardSelected={displayMode !== 'DISPLAY_ONLY' ? setSelectedButton : undefined}
132+
/>
133+
</div>
134+
</div>
135+
);
136+
}
137+
91138
return (
92139
<FormControl variant='standard' error={status === 'error'} required={required}>
93140
<FormLabel component='legend'>{label}</FormLabel>
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { Radio, Checkbox, FormControlLabel, Card, CardContent, Typography } from '@mui/material';
2+
import { resolveReferenceFields } from './utils';
3+
4+
5+
export default function SelectableCard(props) {
6+
const {
7+
getPConnect,
8+
type,
9+
image: { imagePosition, imageSize, showImageDescription, imageField = '', imageDescription = '' },
10+
dataSource,
11+
recordKey = '',
12+
className,
13+
cardLabel,
14+
hideFieldLabels = false,
15+
readOnly,
16+
disabled,
17+
readOnlyList = [],
18+
displayMode,
19+
radioBtnValue,
20+
onChange,
21+
onBlur,
22+
onClick,
23+
onKeyDown,
24+
additionalProps,
25+
testId,
26+
setIsRadioCardSelected,
27+
showNoValue = false
28+
} = props;
29+
30+
const pConn = getPConnect();
31+
32+
if (showNoValue) return <Typography>No Value</Typography>;
33+
34+
const cardDataSource = readOnly || displayMode === 'DISPLAY_ONLY' ? readOnlyList || [] : dataSource?.source;
35+
const imageDescriptionKey = showImageDescription ? imageDescription : undefined;
36+
37+
let radioItemSelected = false;
38+
39+
return (
40+
<>
41+
{(cardDataSource || []).map(item => {
42+
const resolvedFields = resolveReferenceFields(item, hideFieldLabels, recordKey, pConn);
43+
44+
const commonProps = {
45+
id: item[recordKey],
46+
key: item[recordKey],
47+
fields: resolvedFields,
48+
label: item[cardLabel]
49+
};
50+
51+
const image = item[imageField]
52+
? {
53+
src: item[imageField],
54+
alt: showImageDescription && imageDescriptionKey ? item[imageDescriptionKey] : '',
55+
style: { width: imageSize, objectPosition: imagePosition }
56+
}
57+
: undefined;
58+
59+
const cardContent = (
60+
<Card className={className} style={{ display: 'flex' }} data-testid={testId}>
61+
{image && <img src={image.src} alt={image.alt} style={{ width: '100px' }} />}
62+
<CardContent>
63+
<Typography variant='body1'>{item[cardLabel]}</Typography>
64+
{commonProps.fields.map((field, index) => (
65+
// eslint-disable-next-line react/no-array-index-key
66+
<Typography key={index} variant='body2'>
67+
{field.value}
68+
</Typography>
69+
))}
70+
</CardContent>
71+
</Card>
72+
);
73+
74+
if (displayMode === 'DISPLAY_ONLY') {
75+
return cardContent;
76+
}
77+
78+
const component = (
79+
<div style={{ paddingTop: '15px' }}>
80+
<Card className={className} style={{ display: 'flex', height: '500px' }} data-testid={testId}>
81+
<CardContent style={{
82+
...(imagePosition === 'inline-start' && { display: 'flex' })
83+
}}>
84+
<div>
85+
{image && <img src={image.src} alt={image.alt} style={{ width: '100%', backgroundColor: 'rgb(233, 238, 243)', aspectRatio: '16 / 9', maxHeight: '100%', height: '100%', objectFit: 'contain', maxWidth: '100%' }} />}
86+
</div>
87+
<div>
88+
{type === 'radio' ? (
89+
<FormControlLabel
90+
control={
91+
<Radio
92+
value={item[recordKey]}
93+
checked={radioBtnValue === item[recordKey]}
94+
onChange={onChange}
95+
onBlur={onBlur}
96+
onClick={onClick}
97+
onKeyDown={onKeyDown}
98+
disabled={disabled}
99+
{...additionalProps}
100+
/>
101+
}
102+
label={<Typography variant='body1'>{item[cardLabel]}</Typography>}
103+
/>) : (<FormControlLabel
104+
control={
105+
<Checkbox
106+
id={item[recordKey]}
107+
getPConnect={getPConnect}
108+
checked={readOnlyList.some(data => data[recordKey] === item[recordKey])}
109+
onChange={onChange}
110+
onBlur={onBlur}
111+
onClick={onClick}
112+
onKeyDown={onKeyDown}
113+
disabled={disabled}
114+
{...additionalProps}
115+
/>
116+
}
117+
label={<Typography variant='body1'>{item[cardLabel]}</Typography>}
118+
/>)}
119+
120+
{commonProps.fields.map((field, index) => (
121+
// eslint-disable-next-line react/no-array-index-key
122+
<div key={index}
123+
style={{
124+
fontSize: '0.875rem',
125+
...(field.type !== 'TextArea' && { display: 'grid', gridTemplateColumns: '1fr 1fr' }),
126+
margin: '5px'
127+
}}
128+
>
129+
<div style={{ color: 'rgba(0, 0, 0, 0.6)' }}>{field.name}</div>
130+
<div>{field?.value?.props.value}</div>
131+
</div>
132+
))}
133+
</div>
134+
</CardContent>
135+
</Card>
136+
</div>
137+
);
138+
139+
if (type === 'radio' && radioBtnValue === item[recordKey]) {
140+
radioItemSelected = true;
141+
}
142+
143+
return component;
144+
})}
145+
146+
{type === 'radio' && setIsRadioCardSelected && setIsRadioCardSelected(radioItemSelected)}
147+
</>
148+
);
149+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './SelectableCard';

0 commit comments

Comments
 (0)