Getting a dialog on click of Edit Button on admin-on-rest - material-ui

I am working on an application using admin-on-rest framework. For editing an entry on a Resource we provide XXXEdit, XXXShow, XXXCreate props to it. My requirement is that when I click on an Edit button in List view on any entry I should get a Dialog box with the parameters in XXXEdit instead of going to a new page. I tried doing this by using a Dialog in XXXEdit component
<Edit title={<RoleTitle />} {...props}>
<SimpleForm>
<Dialog
title="Dialog With Actions"
actions={actions}
modal={false}
open={true}
>
<TextInput source="id" />
<TextInput source="name" validate={required} />
.
.//some more fields
</Dialog>
</SimpleForm>
</Edit>
I get errors like The TextInput component wasn't called within a redux-form
If I use a DisabledInput then I get an error cannot read value of undefined
How do I go on with this?

I do not think you can use Simpleform for this. You will need to create a custom Form using Redux-Form. Look at the bottom answer that documents the final answer.
This might help you
How to richly style AOR Edit page
Instead of creating a page. You are creating a component that connects to the Redux state and displays as a dialog box.

I tried to resolve this using HOC and react-router.
I created a button using AOR button and provided a containerElement
containerElement={
<Link
key={record.id}
to={{
...{
pathname: `${basePath}/${encodeURIComponent(record.id)}`
},
...{ state: { modal: true } }
}}
/>
}
I created a route like this where DialogRoleEdit is an AOR edit component wrapped with a dialog HOC below .
<Route
exact
path="/roles/:id"
render={routeProps => {
return !!(
routeProps.location.state && routeProps.location.state.modal
) ? (
<Restricted authClient={authClient} location={routeProps.location}>
<div>
<RoleList resource={"roles"} {...routeProps} />
<DialogRoleEdit resource={"roles"} {...routeProps} />
</div>
</Restricted>
) : (
<Restricted authClient={authClient} location={routeProps.location}>
<RoleEdit resource={"roles"} {...routeProps} />
</Restricted>
);
}}
/>
Finally an HOC
handleClose = () => {
this.props.history.goBack();
};
render() {
const actions = [
<FlatButton label="Cancel" primary={true} onClick={this.handleClose} />
];
return (
<Dialog>
<WrappedComponent/>
</Dialog>
)
}
We need to provide edit prop for this resource in App.js
edit={DialogUserEdit}

Related

Vite React VScode. Errors not underlined, no warnings etc

I've just started assembling my projects with Vite. And noticed that VSCode doesn't inform you about your mistakes anymore. Component just doesn't work properly and I don't see any underlines. So I did something like this:
const BasketItem = ({ removeFrromOrder, id, name, price, quantity }) => {
return (
<ListItem>
<Typography variant='body1'>
{name} {price}руб x{quantity}
</Typography>
<IconButton onClick={() => removeFrromOrder(id)}>
<Close />
</IconButton>
</ListItem>
);
};
<BasketItem key={item.name} removeFromOrder={removeFromOrder} {...item} />
Nothing is underlined. Usually the last string of code would be underlined since component expects removeFrromOrder with two 'r' (which is typo :)
Any ideas why it would be happening? Is it connected with Vite in any way?

#mui/lab/DateRangePicker - How to add custom toolbar with action buttons above and under calendar

I'm using DateRangePicker from #mui/lab and now, there is need to add custom toolbar with action buttons above or under calendar (for example, buttons apply or cancel). I struggled to find solution but couldn't find something useful. It should be on both desktop and mobile versions of datepicker.
For all those who suffer from the lack of simple and necessary solutions.
Hope this will help 🫡
Here the docs, but there is huge lack of information and examples
<LocalizationProvider dateAdapter={AdapterDateFns} localeText={{ start: 'from', end: 'to' }}>
<DateRangePicker
components={{ //edit component
PaperContent: data => { //exactly PaperContent
const childCopy = [...data.children]; //duplicate to avoid errors
const Component = () => <Box>BUILD YOUR COMPONENT</Box>;
childCopy.push(<Component />);
return childCopy; //return array of childrens
}
}}
value={value}
onChange={newValue => {
setValue(newValue);
}}
renderInput={(startProps, endProps) => (
<>
<MNVTTextField {...startProps} />
<Box>-</Box>
<MNVTTextField {...endProps} />
</>
)}
/>
</LocalizationProvider>;

How to pass data between pages without URL Parameters

I'm wondering how I can pass non-string data between two pages in Ionic 5 using ReactRouter.
All solutions I could find used Ionic and Angular or just passed one string as URL parameter.
These are my components so far:
App.tsx
const App: React.FC = () => {
return (
<IonApp>
<IonReactRouter>
<IonSplitPane contentId="main">
<Menu />
<IonRouterOutlet id="main">
<Route path="/page/Home" component={Home} exact />
<Route path="/page/DataEntry" component={DataEntry} exact />
<Route path="/page/Request" component={Request} exact />
<Route path="/page/ResultMap" component={ResultMap} exact />
<Redirect from="/" to="/page/Home" exact />
</IonRouterOutlet>
</IonSplitPane>
</IonReactRouter>
</IonApp>
);
};
Page 1 here collects user input data (strings, objects, arrays) and I want to call the route '/page/ResultMap' on Button click and pass the data, so the next page can handle it:
<IonGrid>
<IonRow>
<IonCol class="ion-text-center">
<IonButton text-center="ion-text-center" color="primary" size="default" routerLink='/page/ResultMap'>Erkunden!</IonButton>
</IonCol>
</IonRow>
</IonGrid>
Page 2, which should receive the Data:
const ResultMap: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Map</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
</IonContent>
</IonPage>
);
};
I understand the React principle about props and state, I just dont know how to combine it with Ionic in this case.
I appreciate your help!
Edit:
As suggested I changed the button onClick like this:
<IonButton text-center="ion-text-center" color="primary" size="default" onClick={e => {
e.preventDefault();
history.push({
pathname: '/page/ResultMap',
state: { time: transportTime }
})}}>
And try to receive the data on the ResultMap page like this:
let time = history.location.state.time;
But I get the error:
Object is of type 'unknown'. TS2571
7 | let history = useHistory();
8 |
> 9 | let time = history.location.state.time;
| ^
How do I access the passed object on the new page?
as for react-router I know you can use this:
history.push({
pathname: '/template',
state: { detail: response.data }
})
in this situation you can pass data without URL Params
can also use history.replace
if you redirect and want the back button work properly to the end user
and for the history do the following
let history = useHistory();
Check this link for a great understand how to implement the useHistory type

Material UI Tabs no selected tab

I'm trying to use Material UI Tabs for navigation. However, there are routes in my application that match none of the tabs. When I pass a value to the Tabs component that does not match any of the child tab values, I get a warning about an invalid value.
I created a hidden tab will a value of null as a work-around.
Is it possible to disable this warning about an invalid tab value?
Can tabs in Material UI have no selection?
Thanks
The value of the currently selected Tab. If you don't want any selected Tab, you can set this property to false.
From: https://material-ui.com/api/tabs/
What I ended up doing is creating a switch statement with valid tab values, and if windows.location.pathname doesn't match any of them have the default return false.
Example Routes:
class Routes extends Component {
render() {
return (
<Switch>
<Route path={'/test2'} component={Test2} />
<Route path={'/test3'} component={Test3} />
<Route exact path={'/'} component={Test} />
</Switch>
);
}
}
Example NavBar:
checkPathnameValue() {
const { pathname } = window.location;
switch (pathname) {
case '/test2':
case '/test3':
break;
default:
return false;
}
return pathname;
}
render() {
const { classes } = this.props;
const tabValue = this.checkPathnameValue();
return (
<div className={classes.root}>
<AppBar position={'static'}>
<Toolbar>
<Tabs value={tabValue}>
<Tab
label={'Test 2'}
value={'/test2'}
to={'/test2'}
component={Link}
/>
<Tab
label={'Test 3'}
value={'/test3'}
to={'/test3'}
component={Link}
/>
</Tabs>
</Toolbar>
</AppBar>
</div>
);
}
Seems like setting the value property of Tabs to false will not show any warning and will deselect all the tabs correctly.
Philip's solution works perfectly, here I am just removing the need for the switch case.
In my case, I only had one tab (Login) where I wanted no tab to be selected since it is a button rather than a tab.
Here's what I did to solve this:
<Tabs value={this.state.content !== "login" ? this.state.content : false} onChange={(event, newValue) => { this.setState({content: newValue}) }}>
<Tab value="home" label="Home" wrapped />
<Tab value="tab1" label="Tab 1" />
<Tab value="tab2" label="Tab 2" />
</Tabs>
on another part of my AppBar I had a Login button:
<Button onClick={(event, newValue) => { this.setState({content: "login"}) }}>Login</Button >
Similarly to Philips's answer, the key is in {this.state.content !== "login" ? this.state.content : false} which prevents Tabs from being rendered with "login" value. Instead, it is given the value "false" which is allowed and does not invoke the warning.
I also experienced this issue a while back and follow the same pattern.
E.g.,
return <Tabbar value={value ?? false} onChange={(event: React.ChangeEvent<{}>, value: any) => onChange(value)}>{tabs}</Tabbar>
Toggle Effect
To get a toggle effect the listener will need to be placed on the individual <Tab onClick/> events as <Tabs onChange> will not trigger when clicking the same button multiple times.
const Container = ()=>{
const [currentTab,setCurrentTab] = React.useState<string|false>('a')
const handleChange = (val: string) =>
setCurrentTab(val === currentTab ? false : val)
return <Tabs value={currentTab}>
<Tab value='a' label='a' onClick={()=>handleChange('a')}/>
<Tab value='b' label='b' onClick={()=>handleChange('b')}/>
</Tabs>
}

Purescript-Pux: How to add a react component as property to another react component (Material-UI)

Some libraries like material-ui require to add components as properties to another react component.
JSX Example (See live/complete):
render() {
const actions = [
<FlatButton
label="Cancel"
primary={true}
onTouchTap={this.handleClose}
/>,
<FlatButton
label="Submit"
primary={true}
keyboardFocused={true}
onTouchTap={this.handleClose}
/>,
];
return (
<div>
<RaisedButton label="Dialog" onTouchTap={this.handleOpen} />
<Dialog
title="Dialog With Actions"
actions={actions}
modal={false}
open={this.state.open}
onRequestClose={this.handleClose}
>
The actions in this window were passed in as an array of React objects.
</Dialog>
</div>
);
}
I wonder if this is possible in purescript-pux. The following approach does not work. Is there a way which works?
foreign import raisedButtonClass :: ? props. ReactClass props
raisedButton = reactClassWithProps raisedButtonClass "RaisedButton"
foreign import dialogClass :: ? props. ReactClass props
dialog = reactClassWithProps dialogClass "Dialog"
...
dialog {
-- the next line does not work
actions: [(raisedButton {label: "Close"} #! onClick (const ToggleDialog) $ mempty)],
open: state.isDialogOpen,
title: "Dialog Title"
}
#! (on "onRequestClose" (const ToggleDialog))
$ text "Dialog Text"
You can find a complete example here: https://github.com/shybyte/pux-starter-app-material-ui/blob/master/src/Main.purs