modal not shown in storybook - javascript

I have a working modal component which i need to show in storybook as well. It depends on the props
to show and close. For example, if i need to show modal i would have to do the following
const Demo = () => {
const [open, setOpen] = useState(false)
return (
<>
<button onClick={() => setOpen(true)}>Open Modal</button>
<Modal open={open} onClose={() => setOpen(false)}>
<Modal.Header>Modal Header goes here</Modal.Header>
<Modal.Content>Modal Content goes here</Modal.Content>
<Modal.Footer>Modal Footer goes here</Modal.Footer>
</Modal>
</>
)
}
I am using ReactDOM.createPortal to render modal so for this i have created a div element with an id
modal and inside it another div element is created where the modal appears. For such i have created a
story of modal as follow
storiesOf('Modals', module)
.addDecorator(storyFn => (
<>
<div id="modal">
<div>{storyFn()}</div>
</div>
</>
))
.addDecorator(withKnobs)
.add('Modals - Basic', () => (
<>
<button type="button">Show Modal</button>
<Modal open={boolean('open', false)}>
<Modal.Header>Modal Header goes here</Modal.Header>
<Modal.Content>Modal Content goes here</Modal.Content>
<Modal.Footer>Modal Footer goes here</Modal.Footer>
</Modal>
</>
))
My modal is created in the following way
const el = document.createElement('div')
const modal = document.getElementById('modal')
return ReactDOM.createPortal(
<>
<Backdrop onClick={e => closeModal(e)}>
<ModalBox>
<Wrapper position={position} {...props}>
{children}
<CloseIcon icon={faTimesCircle} />
</Wrapper>
</ModalBox>
</Backdrop>
</>,
el,
)

Related

Transform button into text after condition is true

I'm using the AppBar component of material-ui library, I added a button, I'd say it's hardcoded in the AppBar, I'm trying to transform this button to just a text in the AppBar, but I got nothing.
How can I transform the button in the AppBar to just text?
App.js:
const connectWalletChecker = () => {
return(
<div>
<SearchAppBar id='walletButton' apptitle={apptitle} color='primary' variant='contained' text='Connect Wallet' handle={connectWalletPressed}/>
</div>
)
}
const AlreadyConnected = () => {
return(
<div>
<SearchAppBar id='walletButton' apptitle={apptitle} color='primary' variant='contained' text={walletAddress} handle={null}/>
</div>
)
}
return(
<div>
{walletAddress ? AlreadyConnected() : connectWalletChecker()}
</div>
)
};
AppBar:
<Button id={props.id} color={props.color} variant={props.variant}
href="#contained-buttons" onClick={props.handle}>{props.text}</Button>
Full code on Github.
use variant="text" instead of variant="contained" for transforming button into text.
your code will be :
const connectWalletChecker = () => {
return(
<div>
<SearchAppBar id='walletButton' apptitle={apptitle} color='primary' variant='text' text='Connect Wallet' handle={connectWalletPressed}/>
</div>
)
}
const AlreadyConnected = () => {
return(
<div>
<SearchAppBar id='walletButton' apptitle={apptitle} color='primary' variant='text' text={walletAddress} handle={null}/>
</div>
)
}
return(
<div>
{walletAddress ? AlreadyConnected() : connectWalletChecker()}
</div>
)
};

How to hide box on body click except of button in using ReactJS Hooks?

T have a button with a box & box will hide/show (toggle) on button click. This is working fine now I want to when we click on body except of button then box should be hide.
My Code:-
function App() {
const [show, setShow] = useState(false);
return (
<div>
<button className="btn" onClick={() => setShow(!show)}></button>
{show ? <div className="box"></div>
: null}
</div>
);
}
export default App;
ThankYou for your efforts!
There's many tricks to solve this. But one of them I prefer, do it like modals. So:
Add background div beside of the box that shows back of the box
Set onClick on this new div to hide the box
function App() {
const [show, setShow] = useState(false);
return (
<div>
<button className="btn" onClick={() => setShow(!show)}></button>
{show && (
<>
<div style={{bottom:0 , top:0, right:0, left:0,position:"absolute"}} onClick={()=> setShow(false)}></div>
<div className="box"></div>
</>)
}
</div>
);
export default App;
If I got your point rightly. You can solve it like this.
It will close the box/modal when one clicks outside of the modal or body
function App() {
const [show, setShow] = useState(false);
return (
<div>
<button className="btn" onClick={() => setShow(!show)}></button>
{show ?
<div onClick={() => setShow(false)}
style={{width: '100vw',
height: '100vh',
position: 'absolute',
top: 0,
left: 0
}}>
<div className="box" onClick={(e) => e.stopPropagation()}></div>
</div>
);
}
export default App;

How to pass data from a table row and pass it to another component when it renders?

I have a component that shows a table and one of its columns have a field Actions which has buttons (view, edit, delete etc.). On button click, I need to render another component (component is a popup) and pass the data from the table so that it displays the data in some form which I need to further add.
I have managed to get the current data from its row by passing in onClick. I tried to use state for another component to render but it didn't work out. I'm using Semantic-UI React components to display the button with animations.
Here is the code that has the table,
const MainContent = () => {
const [actions, setActions] = useState(false);
const handleView = (rowData) => {
console.log(rowData);
setActions(true);
if (actions == true) return <ParentView />;
};
....
....
const contents = (item, index) => {
return item.routeChildEntry ? (
<>
<tr key={index}>
<td>{item.appName}</td>
<td></td>
<td>{item.createdTs}</td>
<td>{item.pattern}</td>
<td></td>
<td></td>
<td></td>
<td>
<Button animated onClick={() => handleView(item)}>
<Button.Content visible>View</Button.Content>
<Button.Content hidden>
<Icon name="eye" />
</Button.Content>
</Button>
</td>
</tr>
{item.routeChildEntry.map(routeContents)}
</>
) : (
....
....
....
);
};
return (
<div>
....
{loading ? (
<div className="table-responsive">
<table className="table">
<thead>
<tr>
<th>AppName</th>
<th>Parent_App</th>
<th>Created_Date</th>
<th>Req_Path</th>
<th>Resp_Code</th>
<th>Resp_Content_Type</th>
<th>Resp_Delay</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{data.map((routes, index) => {
return routes.map(contents, index);
})}
</tbody>
</table>
</div>
) : (
....
....
)}
</form>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default MainContent;
Below is the component to render on button click,
import React from "react";
import Popup from "reactjs-popup";
import { Icon } from "semantic-ui-react";
const Parent = (props) => {
return (
<Popup trigger={<Icon link name="eye" />} modal closeOnDocumentClick>
<h4>in parent</h4>
</Popup>
);
};
export default Parent;
How can I render the other component and pass data to it on button click?
Data can be passed to other components as props.
For example, if your component is <ParentView />, and the data you are passing is contained in the variable rowData, you can pass it as:
<ParentView dataPassedByAkhil = {rowData}/>
Then in your ParentView component,
export default function ParentView({dataPassedByAkhil}) {
console.log(dataPassedByAkhil);
Alternatively, you can accept the data as props as below
export default function ParentView(props) {
console.log(props.dataPassedByAkhil);
If you want to open and close another popup, you can pass a state just like above.
<PopupComponent open={stateSetForPopupByParent}/>
Example of popup using state.
Updated link above with how to pass data to the dialog from rows of buttons
Here is the full code:
export default function FormDialog() {
const [open, setOpen] = React.useState(false);
const [valueofRow, setValueOfRow] = React.useState();
const handleClickOpen = (value) => {
setValueOfRow(value);
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Button
variant="outlined"
color="primary"
onClick={() => {
handleClickOpen("John");
}}
>
Row 1 - value is John
</Button>
<br />
<br />
<Button
variant="outlined"
color="primary"
onClick={() => {
handleClickOpen("Sally");
}}
>
Row 2 Value is Sally
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="edit-apartment"
>
<DialogTitle id="edit-apartment">Edit</DialogTitle>
<DialogContent>
<DialogContentText>Dialog fired using state</DialogContentText>
<h1>{valueofRow} was clicked and passed from the row</h1>
<TextField
autoFocus
margin="dense"
id="field"
label="some field"
type="text"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="secondary">
Cancel
</Button>
<Button onClick={handleClose} color="primary">
Submit
</Button>
</DialogActions>
</Dialog>
</div>
);
}

How to use multiple material ui dialog with React?

I want to use two dialog in sign up page and login page.
the implement that I want to do are signup screen showing up when click to sign up button on the Top page, and login screen showing up when click to login Button on signup page.
I wrote open state on App.js.
but the trouble is when it's written in App.js, two of modal open..
Does anyone know how to settle it?
App.js
const App = () => {
const [open, setOpen] = useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Top handleClickOpen={handleClickOpen}/>
<SignupModal open={open} handleClose={handleClose} />
<LoginModal open={open} handleClose={handleClose} />
</div>
)
Top.js
const Top = (props) => {
const classes = useStyles();
return (
<React.Fragment>
<div style={style}>
<Button variant="outlined" className={classes.loginButton} onClick={props.handleClickOpen}>
Login
</Button>
</div>
<h1>Toppage</h1>
</React.Fragment>
);
}
SignupModal.js
const SignupModal = (props) => {
return (
<div>
<Dialog
open={props.open}
onClose={props.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title" className={classes.title}>Sign up</DialogTitle>
<DialogContent className={classes.content}>
<div className={classes.text}>
<TextField id="standard-basic" label=“name” fullWidth/>
<TextField id="standard-basic" label=“email” fullWidth/>
<TextField id="standard-basic" label=“password” fullWidth/>
<TextField id="standard-basic" label=“pass”word fullWidth/>
</div>
</DialogContent>
<p className={classes.toLogin}>to Login</p>
<DialogActions>
<Button onClick={props.handleClose} className={classes.signUpButton}>
Send
</Button>
</DialogActions>
</Dialog>
</div>
);
}
LoginModal.ls
const LoginModal = (props) => {
return (
<div>
<Dialog
open={props.open}
onClose={props.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title" className={classes.title}>Login</DialogTitle>
<DialogContent className={classes.content}>
<div className={classes.text}>
<TextField id="standard-basic" label=“name” fullWidth/>
<TextField id="standard-basic" label=“pass”word fullWidth}/>
</div>
</DialogContent>
<DialogActions>
<Button onClick={props.handleClose} className={classes.signUpButton}>
Login
</Button>
</DialogActions>
</Dialog>
</div>
);
}
export default LoginModal
You are sharing the state on both of your modals that's why.
The solution is simple, have 2 states; one that will determine if SignupModal is opened or not and another one for LoginModal.
const App = () => {
const [openLogin, setOpenLogin] = useState(false);
const [openSignup, setOpenSignup] = useState(false);
return (
<div>
<Top
onClickLogin={() => setOpenLogin(true)}
onClickSignup={() => setOpenSignup(true)}
/>
<SignupModal open={openLogin} handleClose={() => setOpenLogin(false)} />
<LoginModal open={openSignup} handleClose={() => setOpenSignup(false)} />
</div>
);
};
const Top = (props) => {
return (
<React.Fragment>
<div>
<Button
variant="outlined"
className={classes.loginButton}
onClick={props.onClickLogin}
>
Login
</Button>
<Button
variant="outlined"
className={classes.loginButton}
onClick={props.onClickSignup}
>
Signup
</Button>
</div>
<h1>Toppage</h1>
</React.Fragment>
);
};

Modal not selecting current object

I have this class in React:
render() {
let addedItems = this.props.items.length ? (
this.props.items.map(item => {
return (
<li className="collection-item avatar" key={item.id}>
<div className="item-desc">
<Modal trigger={<Button onClick={this.handleOpen}>Editar</Button>}>
<Header icon="archive" content="Archive Old Messages" />
<Modal.Content>
{/* CHEESE */}
<Button.Group>
<Link to="/cart">
<Button
icon="plus"
onClick={() => {
console.log("BUT +");
this.handleCheese(item, "+");
}}
/>
</Link>
<Button content="Cheese" labelPosition="left" />
<Link to="/cart">
<Button
icon="minus"
onClick={() => {
this.handleCheese(item, "-");
}}
/>
</Link>
<h2>{item.queijo}</h2>
</Button.Group>
</Modal.Content>
</Modal>
</div>
</li>
);
})
)
}
In resume a modal should open according to the object I'm selecting.
But in my code the item.id is selecting the last object I inserted in the addedItems.
I need the modal to have the info about the obj I selected.
In case you want to see all code is in: https://github.com/fernanda-avelar/burguer_cart ->
This page is the /src/components/Cart.js
I guess you can have only one modal in your window, that's why it's taking the last one (by having overriden all others).
So instead you should put your modal out of the .map.
Also, keep track of the selected item via a controlled state selectedItem.
Then use it the the Modal.Content :
render() {
return (
<>
<Modal.Content>
/* content depending of this.state.selectedItem */
</Model.Content>
/* your other stuff */
</>
)
}

Categories