Say I have a material ui dialog component that renders children:
export interface DialogProps {
open: boolean;
title: string;
children: React.ReactNode;
onCancelClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
saveButtonLabel?: string;
onSaveClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
permissionKey?: string
}
const Dialog = (props: DialogProps) => {
const { children } = props;
// takes a key and access level, returns true/false:
const { checkPermissions } = useCurrentUser();
<Dialog>
<div>
{children}
</div>
<DialogActions>
<Button variant="outlined" onClick={props.handleCancelClick}>
Cancel
</Button>
<Button
variant="contained"
onClick={props.handleSaveClick}
>
{props.saveButtonLabel ?? Save}
</Button>
</DialogActions>
</Dialog>
}
I'm looking for a way to iterate over all the children passed to the dialog and check permissions and set a prop on certain children based on the result of the check. For example, if they have read-only I want to attach disabled to the children's prop so the field cannot be edited, rather than having the user of the dialog need to check permissions and set disabled manually. To have the user just pass a key to the dialog component and the dialog would check that key against a context provider function called checkPermissions and an access level (eg, Update).
Something like:
React.useEffect(() => {
if (props.permissionKey !== undefined) {
if (!checkPermission(props.permissionKey, AccessLevel.Update)) {
const childs = React.Children.toArray(children);
React.Children.map(childs, (child, index) => {
// here set disabled on either all the children or even based on
// type. ie, if text field then disable. if another, then set some
// other prop appropriate to that type.
if (typeof child is X) {
child.disabled = true;
}
});
}
}
},[])
Usage currently:
function MyComponent() {
const [readOnly] = React.useState(!checkPermissions("somekey", AccessLevel.Update);
<MyDialog
open={true}
title="My Dialog"
permissionKey="someKey"
...
>
<TextField disabled={readOnly}>
{data.someValue}
</TextField>
...
</MyDialog>
}
I've never seen this done. Is it possible to dynamically do this?