Gatsby open modal window on button click - javascript

I'm working on a website about donation using Gatsby v2 (Reactjs) and I need an example like open modal window on button donation click using Gatsby or ReactJS. I search on internet and I got nothing.
Thanks in advance.

Here's a simple (Gatsby) page that makes use of react-modal as an example. In this example I've replaced the default IndexPage in the Gatsby v2's new starter site that you can generate via the CLI.
import React, { Component } from 'react'
import ReactModal from 'react-modal'
import { Link } from 'gatsby'
import Layout from '../components/layout'
ReactModal.setAppElement('#main')
class IndexPage extends Component {
constructor(props) {
super(props)
this.state = {
isModalOpen: false,
}
}
handleModalOpen = event => {
// console.log('handleModalOpen: ', event);
this.setState({ isModalOpen: true })
}
handleModalClose = event => {
// console.log('handleModalOpen: ', event);
this.setState({ isModalOpen: false })
}
render() {
return (
<Layout>
<div id="main">
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<Link to="#" onClick={this.handleModalOpen}>
Donate Now
</Link>
</div>
<ReactModal
isOpen={this.state.isModalOpen}
onRequestClose={this.handleModalClose}
contentLabel="Example Modal In Gatsby"
>
<h2>Donate</h2>
<button onClick={this.handleModalClose}>Close Modal</button>
</ReactModal>
</Layout>
)
}
}
export default IndexPage
That should get you going. Best to read up on how to expand on this example using react-modal here (or use an alternative).

First of all the above example will not work because #main doesn't exist, right now the id for Gatsby app is ___gatsby, so it shoul look like this
ReactModal.setAppElement('#___gatsby')
But it's not good to hope that this id is not going to change in the future. So it's better to implement your own React modal component, here is a good example https://www.digitalocean.com/community/tutorials/react-modal-component

Related

<Link> onClick react-notifications not showing, but it runs the function

I created a survey page, but when someone doesn't have credits I want to show a notification to the user using react-notifications, I've already tested the button and standalone it works, but when I added it to the tag using react-router-dom on an onClick event, the functions runs, but the notifications doesn't appear. Here's the code:
import React, { Component } from 'react';
import 'react-notifications/lib/notifications.css';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import {NotificationContainer, NotificationManager} from 'react-notifications';
class Button extends Component {
createNotification = () => {
return () => {
switch (this.props.auth.credits) {
case 0:
console.log(this.props.auth.credits);
NotificationManager.error('You have no credits', 'Click to close!', 5000, () => {
});
break;
}
};
};
render() {
return (
<div>
<div className="fixed-action-btn">
<Link to="/surveys/new" className="btn-floating btn-large red" onClick={this.createNotification()}>
<i className="material-icons">add</i>
</Link>
</div>
<NotificationContainer/>
</div>
);
}
}
function mapStateToProps({ auth }){
return { auth };
}
export default connect(mapStateToProps)(Button);
So, when I test this on:
import React from 'react';
import Surveys from './surveys/Surveys';
import Button from '../utilities/addButton';
const Board = () => {
return (
<div>
<Surveys />
<Button />
</div>
);
};
export default Board;
It shows the button, and when clicked without credits, it console.logs the 0 credits, but, it just redirects to the referenced page without showing the notification created.
On my side, it doesn't appear an error neither in the terminal nor in the console or network. But still, the notification is processed but not shown.
So my question is: Is it possible to make the notification appear when the tag redirects to the new page, the only way that I see a solutions if it's not possible is making a conditional to stop the tag to make the change, am I wrong?
Thanks in advance.
Sorry if my question is not properly presented or written, is my first question here.
onClick prop for Link accept function reference. so try replacing
<Link to="/surveys/new" className="btn-floating btn-large red" onClick={this.createNotification}>
<i className="material-icons">add</i>
</Link>
This may be a Very Late reply but for those who didnt answer its because Link doesnt accept onCLick... try for html or with react or reactbootstrap package

how to add tab component and load pages in tabs in react js app?

I have a react js app, that i'm working on. I created a myfirstcomponent, which call a rest api and displays some json data. Now I want to expand my app and add more components, say mySecondComponent. but i want to make it such that i create tabs for this. so I researched and based on the tutorials, i created a tabs and a tab component as well. Now, i want to modify my render method in my app.js file , such that i can render my components within the tab component. so i tried the following, added the Tabs and Tab component inside the app div, now i need to show/hide the components based on the selected tab. . I'm new to react so, i want to make sure i am headed in right direction. is this the right way of doing this in reactjs?
render() {
return (
<div className="app">
<Tabs tabs={['first', 'second']} selected={ this.state.selected }
setSelected={ this.setSelected }>
<Tab isSelected={ this.state.selected === 'first' }></Tab>
<Tab isSelected={ this.state.selected === 'second' }></Tab>
</Tabs>
<myfirstcomponent className="compnent"/>
<mySecondcomponent className="compnent"/>
</div>
);
}
app.js file
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<myfirstcomponent className="App-com"/>
</div>
);
}
}
export default App;
Tabs
import React from 'react';
class Tabs extends React.Component {
render() {
return (
<div style={{ width: '30%' }}>
<ul className="nav nav-tabs">
{
this.props.tabs.map(tab => {
const active = (tab === this.props.selected ? 'active ' : '' );
return (
<li className="nav-item" key={ tab }>
<a className={"nav-link " + active + styles.tab} onClick={ () =>
this.props.setSelected(tab) }>
{ tab }
</a>
</li>
);
})
}
</ul>
{ this.props.children }
</div>
);
}
}
export default Tabs;
Tab.js
import React from 'react';
class Tab extends React.Component {
render() {
if (this.props.isSelected) {
return (
<div>
{ this.props.children }
</div>
);
}
return null;
}
}
export default Tab;
I don't think that approach is right. You should be using routing inside the tab component and links to the routes. Pluralsight site has a pretty good example on how to implement what you want to do.
https://app.pluralsight.com/guides/how-to-create-nested-tab-routes-with-react-router
NOTE: This might not be exact answer for your question.
I think you can use material-ui for creating the tabs component.
Here is a good example with the code. https://material-ui.com/components/tabs/
And also if you are new to react. I would encourage to learn/write functional components rather than class based components. Because in class based components the state management and props with the "this" keyword is very confusing.

How to redirect to a gatsby-react page with an onclick event of a component?

I'm trying to redirect to a page using an onClick event of a component. As I have react gatsby installation is it possible to use Link from gatsby-link to redirect.
import React from 'react';
import { OverflowMenu, OverflowMenuItem } from '../Overflow';
import Link from 'gatsby-theme-carbon/src/components/Link';
class OverflowComponent extends React.Component {
editPage(index) {
console.log();
// window.location.href='/edit';
return(
<Link to="/edit"></Link> // I'm trying to redirect to Edit page
)
}
deletePage() {
console.log("Delete clicked");
}
render(){
return (
<div>
<OverflowMenu flipped={true}>
<OverflowMenuItem itemText="Edit" primaryFocus onClick={() => this.editPage()} />
<OverflowMenuItem itemText="Delete" onClick={() => this.deletePaget()} />
</OverflowMenu>
</div>
);
}
}
export default OverflowComponent;
from the above code the Overflow component is a contributed component and it can have a onClick function. And I'm trying to redirect using gatsby-link.
Instead of using Link or window.location as mentioned in the question we can use navigate from gatsby. As shown below
import React from 'react';
import { OverflowMenu, OverflowMenuItem } from '../Overflow';
import {navigate} from 'gatsby'; //import navigate from gatsby
class OverflowComponent extends React.Component {
editPage(index) {
navigate('/edit'); //navigate to edit page
}
deletePage() {
console.log("Delete clicked");
}
render(){
return (
<div>
<OverflowMenu flipped={true}>
<OverflowMenuItem itemText="Edit" primaryFocus onClick={() => this.editPage()} />
<OverflowMenuItem itemText="Delete" onClick={() => this.deletePaget()} />
</OverflowMenu>
</div>
);
}
}
export default OverflowComponent;
<Link> renders an anchor element (<a href='...'>). You would probably want to use navigate here instead: https://www.gatsbyjs.org/docs/gatsby-link/#how-to-use-the-navigate-helper-function.
You might also need to use the onClick prop on the <OverflowMenuItem> component depending on how you have that setup.

Add loader on button click in react/redux application

I'm trying to add a Loader as Higher-Order-Component on button click in react/redux application.
Already have working Loader component and styling, just need to set logic when button is clicked show loader and hide existing button.
Button component:
import React from 'react'
import '../../../styles/components/_statement-print.scss';
import Loader from './Loader';
const StatementPrint = (props) => {
return (
<div>
<button
className="print-statement-button"
onClick={props.handleStatementPrint}>PRINT
</button>
</div>
);
};
export default Loader(StatementPrint);
Loader:
import React, { Component} from 'react';
import '../../../styles/components/_loader.scss';
const Loader = (WrappedComponent) => {
return class Loader extends Component {
render() {
return this.props.handleStatementPrint // Where must be logic when to show loader or existing button component
? <button className="loader-button">
<div className="loader">
<span className="loader-text">LOADING...</span>
</div>
</button>
: <WrappedComponent {...this.props} />
}
}
}
export default Loader;
In Loader component i added comment where need to write logic when to set loader or button.
I followed this example: ReactCasts - Higher Order Components
I searched a lot of examples but most of them shows how to set loader then is data is fetching, but in my case i just need to show then onClick method is triggered.
So how to set logic when onClick method is fired? Is this is a good aproach? Also it will be better to try acomplish this doing with redux state, but don't know how to do this.
Any help will be appreciated.
You will have to make small modifications to achieve what you want.
The wrapper component Loader can have a isLoading state, on the basis of which you can decide whether to show the loader span or the wrapped component.
This state isLoading can be updated by the wrapped component by passing showLoader function as a prop.
Button component
import React from 'react'
import '../../../styles/components/_statement-print.scss';
import Loader from './Loader';
const StatementPrint = ({handleStatementPrint, showLoader}) => {
return (
<div>
<button
className="print-statement-button"
onClick={() => {
showLoader();
handleStatementPrint();
}}>
PRINT
</button>
</div>
);
};
export default Loader(StatementPrint);
Loader
import React, { Component} from 'react';
import '../../../styles/components/_loader.scss';
const Loader = (WrappedComponent) => {
return class Loader extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: false
}
this.showLoader = this.showLoader.bind(this);
}
showLoader() {
this.setState({isLoading: true});
}
render() {
return this.state.isLoading
? <button className="loader-button">
<div className="loader">
<span className="loader-text">LOADING...</span>
</div>
</button>
: <WrappedComponent
{...this.props}
showLoader={this.showLoader}
/>
}
}
}
export default Loader;
EDIT
Since handleStatementPrint was required to be called, I have updated the click handler to include that function.
Also using de-structuring to avoid typing props repeatedly. See here for more info.
Just some external state is needed.
If you can't have external state (eg isLoading) than you could pass a function into a loader hoc which will derive isLoading from current props
Example: https://codesandbox.io/s/8n08qoo3j2

used wrapper but modal not opening

import React, { PropTypes } from 'react';
import Dialog from 'material-ui/Dialog';
export default class simpleModal extends React.Component {
constructor(props){
super(props)
}
handlePrimaryButton = () => {
this.props.router.push('/some/path');
}
render(){
return(
<Dialog
actions={<RaisedButton
label="OK"
primary={true}
onTouchTap={this.handlePrimaryButton}
/>}
modal={false}
open={this.props.open}
>
{this.props.msg}
</Dialog>
)
}
}
I created a wrapper using material-ui Dialog component but I can't open it. In another component I have this in my render method:
<simpleModal open={this.state.openSimpleModal} />
I then change the state of openSimpleModal using this.setState({openSimpleModal: true})
I don't see the modal being open. Is there anything missing in my above code? I manage to use Dialog component of material-ui directly but not with a wrapper.
Note: No error in chrome console at all.
Old thread but I had the same issue while using a wrapper. Had to use a callback to the parent, not pretty.
The Dialog component in material-ui-next doesn't have this issue any more.

Categories

Resources