Skip to content

Commit 6d32fe2

Browse files
4manasamanasa
andauthored
Added support for cards in DataReference (#469)
* Added support for cards in DataReference --------- Co-authored-by: manasa <[email protected]>
1 parent 5b300e9 commit 6d32fe2

File tree

6 files changed

+537
-2
lines changed

6 files changed

+537
-2
lines changed

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

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ interface CheckboxProps extends Omit<PConnFieldProps, 'value'> {
2121
primaryField: string;
2222
readonlyContextList: any;
2323
referenceList: string;
24+
variant?: string;
25+
hideFieldLabels: boolean;
26+
additionalProps: any;
27+
imagePosition: string;
28+
imageSize: string;
29+
showImageDescription: string;
30+
renderMode: string;
31+
image: string;
2432
}
2533

2634
const useStyles = makeStyles(() => ({
@@ -33,6 +41,7 @@ const useStyles = makeStyles(() => ({
3341
export default function CheckboxComponent(props: CheckboxProps) {
3442
// Get emitted components from map (so we can get any override that may exist)
3543
const FieldValueList = getComponentFromMap('FieldValueList');
44+
const SelectableCard = getComponentFromMap('SelectableCard');
3645

3746
const {
3847
getPConnect,
@@ -56,8 +65,18 @@ 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+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
79+
const [theSelectedButton, setSelectedButton] = useState(value);
6180
const classes = useStyles();
6281
const helperTextToDisplay = validatemessage || helperText;
6382
const thePConn = getPConnect();
@@ -77,6 +96,11 @@ export default function CheckboxComponent(props: CheckboxProps) {
7796
}
7897
}, [thePConn]);
7998

99+
useEffect(() => {
100+
// This update theSelectedButton which will update the UI to show the selected button correctly
101+
setSelectedButton(value);
102+
}, [value]);
103+
80104
if (displayMode === 'DISPLAY_ONLY') {
81105
return <FieldValueList name={hideLabel ? '' : caption} value={value ? trueLabel : falseLabel} />;
82106
}
@@ -93,6 +117,66 @@ export default function CheckboxComponent(props: CheckboxProps) {
93117
thePConn.getValidationApi().validate(event.target.checked);
94118
};
95119

120+
const handleCheckboxChange = (event, item) => {
121+
if (event.target.checked) {
122+
insertInstruction(thePConn, selectionList, selectionKey, primaryField, item);
123+
} else {
124+
deleteInstruction(thePConn, selectionList, selectionKey, item);
125+
}
126+
thePConn.clearErrorMessages({ property: selectionList });
127+
};
128+
129+
const actions = thePConn.getActionsApi();
130+
131+
const commonProps = {
132+
...additionalProps,
133+
className: 'standard',
134+
disabled,
135+
readOnly,
136+
onClick: (actions as any).onClick
137+
};
138+
139+
if (variant === 'card') {
140+
return (
141+
<div>
142+
<h4 style={{ marginTop: 0, marginBottom: 0 }}>{label}</h4>
143+
<SelectableCard
144+
{...commonProps}
145+
testId={testId}
146+
displayMode={displayMode}
147+
dataSource={datasource}
148+
getPConnect={getPConnect}
149+
readOnly={renderMode === 'ReadOnly' || displayMode === 'DISPLAY_ONLY' || readOnly}
150+
onChange={e => {
151+
e.stopPropagation();
152+
const recordKey = selectionKey?.split('.').pop();
153+
const selectedItem = datasource?.source?.find(item => item[recordKey as any] === e.target.id) ?? {};
154+
handleCheckboxChange(e, {
155+
id: selectedItem[recordKey as any],
156+
primary: selectedItem[recordKey as any]
157+
});
158+
}}
159+
onBlur={() => {
160+
thePConn.getValidationApi().validate(selectedvalues, selectionList);
161+
}}
162+
hideFieldLabels={hideFieldLabels}
163+
recordKey={selectionKey?.split('.').pop()}
164+
cardLabel={primaryField.split('.').pop()}
165+
image={{
166+
imagePosition,
167+
imageSize,
168+
showImageDescription,
169+
imageField: image?.split('.').pop(),
170+
imageDescription: (thePConn?.getRawMetadata()?.config as any).imageDescription?.split('.').pop()
171+
}}
172+
readOnlyList={selectedvalues}
173+
type='checkbox'
174+
showNoValue={(renderMode === 'ReadOnly' || readOnly || displayMode === 'DISPLAY_ONLY') && selectedvalues.length === 0}
175+
/>
176+
</div>
177+
);
178+
}
179+
96180
const handleChangeMultiMode = (event, element) => {
97181
if (event.target.checked) {
98182
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
@@ -11,11 +11,19 @@ interface RadioButtonsProps extends PConnFieldProps {
1111
// If any, enter additional props that only exist on RadioButtons here
1212
inline: boolean;
1313
fieldMetadata?: any;
14+
variant?: string;
15+
hideFieldLabels?: boolean;
16+
additionalProps?: any;
17+
imagePosition?: string;
18+
imageSize?: string;
19+
showImageDescription?: boolean;
20+
datasource?: any;
1421
}
1522

1623
export default function RadioButtons(props: RadioButtonsProps) {
1724
// Get emitted components from map (so we can get any override that may exist)
1825
const FieldValueList = getComponentFromMap('FieldValueList');
26+
const SelectableCard = getComponentFromMap('SelectableCard');
1927

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