Change Authorization for Users on React/Firebase - reactjs

Using React and Firebase I have a small page where users can vote on polls.
I am trying to achieve that all polls (saved on Firebase Database) can be seen by all users (registered via Firebase Authentication).
At the moment only users that are manually assigned to the poll in the database can see the poll on their Dashboard.
Below is the Dashboard.js file. Can anyone help me to figure out what I have to change to authorize all users to see all polls automatically?
import React from 'react';
import { Link } from 'react-router';
import { firebaseApp } from '../utils/firebase';
import Helmet from "react-helmet";
import FlatButton from 'material-ui/FlatButton';
import IconButton from 'material-ui/IconButton';
import Dialog from 'material-ui/Dialog';
import Paper from 'material-ui/Paper';
import Divider from 'material-ui/Divider';
import Loading from './Loading';
class Dashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
dialogOpen: false,
loading: true,
polls: [] //items like { id: 34324, title: 'sdf'}
};
this.poll2Delete = '';
this.poll2DeleteTitle = ''
this.handleClose = this.handleClose.bind(this);
this.handleDelete = this.handleDelete.bind(this);
}
componentWillMount() {
//const uid = getLocalUserId();
firebaseApp.auth().onAuthStateChanged(user => {
if (user) { //this can get called after componentWillUnmount, make sure its there to avoid errors
const uid = user.uid;
this.userPollsRef = firebaseApp.database().ref(`user-polls/${uid}`);
//check if user has no polls to quit loading indicator
this.userPollsRef.once('value').then(snapshot => {
if (!snapshot.hasChildren()) {
if (this.mounted) {
this.setState({ loading: false });
}
}
});
this.userPollsRef.on('child_added', ((newPollIdSnapshot) => {
const pollId = newPollIdSnapshot.key;
firebaseApp.database().ref(`polls/${pollId}/title`).once('value').then(snapshot => {
const title = snapshot.val();
const polls = this.state.polls;
polls.push({ title: title, id: pollId })
if (this.mounted) {
this.setState({
polls: polls,
loading: false
});
}
});
})).bind(this);
this.userPollsRef.on('child_removed', ((removedPollIdSnapshot) => {
const pollId = removedPollIdSnapshot.key;
const polls = this.state.polls.filter(poll => poll.id !== pollId);
if (this.mounted) {
this.setState({
polls: polls
});
}
})).bind(this);
}
});
this.mounted = true; //the callbacks above can be called after componentWillUnmount(), to avoid errors, check
}
componentWillUnmount() {
this.userPollsRef.off();
this.mounted = false;
}
handleOpen(pollId) {
this.setState({ dialogOpen: true });
this.poll2Delete = pollId;
this.poll2DeleteTitle = this.state.polls.find(poll => poll.id === this.poll2Delete).title;
}
handleClose() {
this.setState({ dialogOpen: false });
}
handleDelete() {
// updating to null deletes
const updates = {};
updates[`/polls/${this.poll2Delete}`] = null;
updates[`/user-polls/${firebaseApp.auth().currentUser.uid}/${this.poll2Delete}`] = null;
firebaseApp.database().ref().update(updates);
this.setState({ dialogOpen: false });
}
render() {
const actions = [
<FlatButton
label="Cancel"
primary={false}
onTouchTap={this.handleClose}
/>,
<FlatButton
label="Delete"
primary={true}
onTouchTap={this.handleDelete}
/>,
];
let pollsUIs = this.state.polls.map((poll) => {
return (
<div key={poll.id} >
<IconButton
iconClassName="fa fa-trash"
/>
<Link to={`/polls/poll/${poll.id}`}>
<FlatButton
label={poll.title}
style={{ textAlign: 'left', width: '50%' }}
/>
</Link>
<Divider />
</div>
);
});
return (
<div className="row">
<div className="col-sm-12 text-xs-center">
<Helmet title="Dashboard" />
<Paper>
<br />
<h2> Current Polls </h2>
<br />
<Dialog
actions={actions}
modal={false}
open={this.state.dialogOpen}
onRequestClose={this.handleClose}
>
Delete "{this.poll2DeleteTitle}"?
</Dialog>
<br /><br />
{pollsUIs}
<Loading loading={this.state.loading} />
<br /><br />
</Paper>
</div>
</div>
);
}
}
export default Dashboard;

Not used to firebase, but and I think you have to remove uid from the paramater in order to get all the results from firebase.
this.userPollsRef = firebaseApp.database().ref(`user-polls/${uid}`)
to like this
this.userPollsRef = firebaseApp.database().ref(`user-polls`)

Related

React/Redux - mapDispatchToProps. Props undefined

I'm looking for information in a database, in an app with react. In the actions.js file I can see the response.data data, when I put a console.table.
But even exporting, when I try to display the information, the variable's value comes as undefined.
I've already looked at the original file I'm using to learn, and I couldn't see where the error is.
action.js
import { CLEAR_SEARCH, SEARCH_CUSTOMERS } from "./actionTypes";
import Axios from "axios";
import { SEARCH_CUSTOMERS_URL } from "../../configs";
export const searchCustomers = (lat, lng, query) => dispatch => {
Axios.post(SEARCH_CUSTOMERS_URL, {
q: query,
})
.then(response => {
const customers = response.data;
console.log( "services/searchCustomers/actions.js, line 30" );
console.log( customers ); //ok, showing data
return dispatch({ type: SEARCH_CUSTOMERS, payload: customers });
})
.catch(function(error) {
console.log(error);
});
};
export const clearSearch = () => dispatch => {
const customers = [];
return dispatch({ type: CLEAR_SEARCH, payload: customers });
};
reducer.js
import { CLEAR_SEARCH, SEARCH_CUSTOMERS } from "./actionTypes";
const initialState = {
customers: []
};
export default function(state = initialState, action) {
switch (action.type) {
case SEARCH_CUSTOMERS:
return { ...state, customers: action.payload };
case CLEAR_SEARCH:
return { ...state, customers: action.payload };
default:
return state;
}
}
actionTypes.js
export const SEARCH_CUSTOMERS = "SEARCH_CUSTOMERS";
export const CLEAR_SEARCH = "CLEAR_SEARCH";
index.js
import React, { Component } from "react";
import { clearSearch, searchCustomers } from "../../../../services/searchCustomers/actions";
import Dialog from "#material-ui/core/Dialog";
import DelayLink from "../../../helpers/delayLink";
import Ink from "react-ink";
import LazyLoad from "react-lazyload";
import { Redirect } from "react-router";
import CustomerSearch from "../../CustomerSearch";
import CustomerSearchList from "../CustomerSearchList";
import { connect } from "react-redux";
import { debounce } from "../../../helpers/debounce";
import ContentLoader from "react-content-loader";
class SelectCustomer extends Component {
state = {
open: false,
queryLengthError: false,
loading: false,
showBgImage: true,
nothingFound: false,
};
handleCustomerSearch = debounce((query) => {
// call to searchCustomers search API
if (query.length >= 3) {
this.props.searchCustomers(
JSON.parse(localStorage.getItem("userSetAddress")).lat,
JSON.parse(localStorage.getItem("userSetAddress")).lng,
query
);
console.table( this.props ); //customers is undefined
this.setState({
queryLengthError: false,
loading: true,
nothingFound: false,
});
} else {
this.setState({ queryLengthError: true });
}
}, 400);
componentDidMount() {
//others
}
componentWillUnmount() {
//others
}
componentWillReceiveProps(nextProps) {
//this.props.customers is undefined
if (this.props.customers !== nextProps.customers) {
this.setState({ loading: false });
}
// console.log(nextProps.customers.length);
if (nextProps.customers) {
if (nextProps.customers.length === 0 ) {
this.setState({ showBgImage: true, nothingFound: true });
} else {
this.setState({ showBgImage: false, nothingFound: false });
}
}
//Overlay/Dialog.
if (nextProps.confirmSelectCustomerOpen === false) {
this.setState({ open: false });
}
if (nextProps.confirmSelectCustomerOpen === true) {
this.setState({ open: true });
}
}
//Overlay/Dialog
handleClose = () => {
this.setState({ open: false });
};
render() {
return (
<React.Fragment>
<Dialog
fullWidth={true}
fullScreen={false}
open={this.state.open}
onClose={this.handleClose}
style={{ width: "100%", margin: "auto" }}
PaperProps={{ style: { backgroundColor: "#fff", borderRadius: "10px" } }}
>
{this.state.queryLengthError && (
<div className="auth-error" style={{ marginBottom: "4rem" }}>
<div className="">{localStorage.getItem("searchAtleastThreeCharsMsg")}</div>
</div>
)}
<CustomerSearch searchFunction={this.handleCustomerSearch} />
{this.state.loading && (
{/*loading*/}
)}
{/* Here Should list customers */}
{this.props.customers && this.props.customers.length > 0 && (
<CustomerSearchList customers={this.props.customers} />
)}
{this.state.showBgImage && (
<div className="d-flex justify-content-center mt-100">
<img
className="img-fluid explore-bg"
src="/assets/img/various/explore-bg.png"
alt={localStorage.getItem("restaurantSearchPlaceholder")}
/>
</div>
)}
{this.state.nothingFound && (
<div className="auth-error" style={{ marginBottom: "4rem" }}>
<div className="error-shake">{localStorage.getItem("exploreNoResults")}</div>
</div>
)}
</Dialog>
</React.Fragment>
);
}
}
const mapStateToProps = (state) => ({
customers: state.customers
});
export default connect(
mapStateToProps,
{ searchCustomers, clearSearch }
)(SelectCustomer);
CustomerSearch/index.js
import React, { Component } from "react";
import Ink from "react-ink";
class CustomerSearch extends Component {
state = {
customer: ""
};
componentDidMount() {
this.searchInput.focus();
}
static contextTypes = {
router: () => null
};
handleInputChange = e => {
this.setState({ customer: e.target.value });
this.props.searchFunction(e.target.value);
};
render() {
return (
<React.Fragment>
<div className="col-12 p-0">
<div className="block m-0">
<div className="block-content p-0">
<div className="input-group search-box">
<div className="input-group-prepend">
<button
type="button"
className="btn search-navs-btns"
style={{ position: "relative" }}
onClick={this.context.router.history.goBack}
>
<i className="si si-arrow-left" />
<Ink duration="500" />
</button>
</div>
{/*
placeholder do input
{localStorage.getItem("restaurantSearchPlaceholder")}
*/}
<input
type="text"
className="form-control search-input"
placeholder="Pesquisar Cliente"
value={this.state.customer}
onChange={this.handleInputChange}
ref={input => {
this.searchInput = input;
}}
/>
<div className="input-group-append">
<button type="submit" className="btn search-navs-btns" style={{ position: "relative" }}>
<i className="si si-magnifier" />
<Ink duration="500" />
</button>
</div>
</div>
</div>
</div>
</div>
</React.Fragment>
);
}
}
export default CustomerSearch;
CustomerSearchList/index.js
import React, { Component } from "react";
import DelayLink from "../../../helpers/delayLink";
import Ink from "react-ink";
import LazyLoad from "react-lazyload";
class CustomerSearchList extends Component {
render() {
const { customers } = this.props;
return (
<React.Fragment>
{customers.map((customer) => (
<div key={customer.id} className="col-xs-12">
<DelayLink
to={"../stores/" + customer.id}
delay={200}
className="block block-link-shadow text-center light-bottom-border"
>
<Ink duration="500" />
</DelayLink>
</div>
))}
</React.Fragment>
);
}
}
export default CustomerSearchList;
reducers.js
import { combineReducers } from "redux";
....
....
import customerSearchReducer from "./searchCustomers/reducer";
import addressesReducer from "./addresses/reducer";
....
....
export default combineReducers({
...
customers: customerSearchReducer,
addresses: addressesReducer,
...
});
SEARCH_CUSTOMERS_URL - URL to php, get data:
$response = ['customers' => $customers];
Output customers: Array(3)
0: {id: 2, name: "Customer 1", email: "customer1#gmail.com"}
1: {id: 3, name: "Customer 2", email: "customer2#gmail.com"}
2: {id: 4, name: "Customer 3", email: "customer3#gmail.com"}
It's 3 days racking my brain. I did some research but I couldn't solve the problem. I'm new to react/reduce and was trying to figure it out based on this script.
As per comments... add searchCustomer reducer to rootReducer.

my users details is not is not rendering users list when i type in search

there is one more error TypeError: Cannot destructure property 'handleShow' of 'object null' as it is null.
output when i consoled log is
pr
SearchModal.js:35 {username: "pr"}
SearchModal.js:38 [{…}]0: {id: "602df77cea2b563d7ceda4ac", username: "pratik", email: "pratik#gmail.com"}length: 1__proto_: Array(0)
also it is not searching when i type p its giving searc:'' and when i add prat then search : 'pra' only
Also it is not rendering username just check userdetails.map it is console logging the details but not rendering on page
import React, { Component } from 'react';
import { SearchUser } from '../services/SearchService';
import {Modal} from 'react-bootstrap';
class SearchModal extends Component {
constructor(props){
super(props);
this.state = {
show: false,
search: '',
userdetails:[]
}
this.handleShow = this.handleShow.bind(this);
this.handleClose = this.handleClose.bind(this);
this.onTextboxChangeSearch = this.onTextboxChangeSearch.bind(this);
}
handleShow() {
this.setState({ show: true })
}
handleClose(){
this.setState({ show: false })
}
async onTextboxChangeSearch(event) {
this.setState({
search: event.target.value
});
let {search,userdetails} = this.state;
console.log(search)
const data = {username:search};
console.log(data)
let SearchStatus = await SearchUser(data);
userdetails=SearchStatus.user
console.log(userdetails);
}
render() {
let {search,userdetails}= this.state;
return (
<div>
<Modal show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>
<input
type="text"
placeholder="Search.."
value={search}
onChange={this.onTextboxChangeSearch}
></input>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<h3>Users</h3>
<div>
<ul>
{userdetails.map(element => {
<li>{element.username}</li>
})}
</ul>
</div>
</Modal.Body>
</Modal>
</div>
)
}
}
export default SearchModal;
Dashboard
import React, { Component } from 'react';
import { Link,Redirect } from 'react-router-dom';
import UserService from "../services/userservice";
import SearchModal from './SearchModal'
export default class Dashboard extends Component{
constructor(props) {
super(props);
this.state = {
currentUser: UserService.getCurrentUser(),
isLoading:false,
};
this.logOut = this.logOut.bind(this);
this.onClick = this.onClick.bind(this);
}
logOut() {
UserService.logout()
}
SearchModalRef = ({handleShow}) => {
this.showModal = handleShow;
}
onClick = () => {
this.showModal();
}
render(){
const { currentUser ,isLoading } = this.state;
console.log(currentUser)
if (isLoading) {
return (<div><p>Loading...</p></div>);
}
if(!currentUser){
return(
<div>
<Redirect to='/login' />
</div>
)
}
else{
return(
<div>
<header>
<h1>Dashboard</h1>
{' '}
<div>
<Link to={`/dashboard/profile/:${currentUser.user._id}`}>Profile</Link>
</div>
{' '}
<div>
<Link to="/login" onClick={this.logOut}>LogOut</Link>
</div>
{' '}
<SearchModal ref={this.SearchModalRef} ></SearchModal>
<button type="button" onClick={this.onClick}>
Search
</button>
</header>
<div>
</div>
</div>
);
}
}
}
Issue
it is not searching when i type p its giving searc:'' and when i add
prat then search : 'pra' only
React state updates are asynchronous and batch processed between render cycles. This means when you enqueue a state update it won't be available until the next render cycle. Any further references to state in the same function will be the state value from the current render cycle.
async onTextboxChangeSearch(event) {
this.setState({
search: event.target.value // <-- next state
});
let {search,userdetails} = this.state; // <-- still current state!
console.log(search)
const data = {username:search};
console.log(data)
let SearchStatus = await SearchUser(data);
userdetails=SearchStatus.user
console.log(userdetails);
}
Solution
I suggest factoring out the search logic into its own function to be called by the componentDidUpdate lifecycle methods when state updates.
onTextboxChangeSearch(event) {
const { value } = event.target;
this.setState({
search: value // <-- (1) update state
});
}
searchForUser = async () => { // <-- (3) refactored search function
const { search, userdetails } = this.state;
const data = { username: search };
const { user } = await SearchUser(data);
this.setState(prevState => ({
userdetails: [...prevState.userdetails, user], // append user
}));
}
componentDidUpdate(prevProps, prevState) {
if (prevState.search !== this.state.search) {
this.searchForUser(); // <-- (2) search state updated, do search for user
}
}

How to "dynamically add/ edit/cancel/ the textarea" in reactjs

As, I am new to react I don't know how to perform dynamic add and edit and cancel operations on the textarea. I have dynamic array , i want to perform edit and cancel operations for every textarea individually . If I click on a edit button the mouse cursor should point to the specific textbox, and it should turn into editable mode . If, I click on cancel button the specific textarea should turn into non-editable mode. codesandboxdemo please Run the code in codesandox and give me the solution
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
App.js
import React, { Component } from "react";
class App extends Component {
constructor() {
super();
this.state = {
count: [],
disabled: false
};
this.newText = {};
this.handleEdit = this.selectText.bind(this);
}
handleCancel(e,index) {
this.setState({disabled:true})
}
handleRemove(index)
{
this.state.count.splice(index,1)
this.setState({count: this.state.count})
}
selectText(e, index) {
newText = this.state.count[index];
console.log(newText);
this.newText.select();
}
add(e) {
this.setState({ count: [...this.state.count, ""] ,disabled:false});
}
handleChange(e, index) {
this.state.count[index] = e.target.value;
this.setState({ count: this.state.count });
}
render() {
return (
<div>
<label>Enter the text</label>
{this.state.count.map((counts, index) => {
return (
<div key={index}>
<input
ref={(newText) => (this.newText = newText)}
onChange={(e) => this.handleChange(e, index)}
value={counts}
disabled = {(this.state.disabled)? "disabled" : ""}
/>
<button onClick={(e) => this.handleEdit(e,index)}>Edit</button>
<button onClick={() => this.handleRemove(index)}>Remove</button>
<button onClick = {(e) =>this.handleCancel(e,index)}> cancel </button>
</div>
);
})}
<button onClick={(e) => this.add(e)}> Add</button>
</div>
);
}
}
export default App;
.App {
font-family: sans-serif;
text-align: center;
}
`]2
I just tried doing it this way for you. This is not a complete answer (just to make sure I don't spoon-feed you, but this is a possible approach). Tell me if this works?
import React, { useState } from "react";
import "./styles.css";
const App = () => {
const [Value, setValue] = useState("");
const [EditMode, setEditMode] = useState(false);
const toggleEditMode = () => setEditMode(!EditMode);
return EditMode ? (
<input
type="text"
value={Value}
onChange={(e) => setValue(e.target.value)}
onBlur={toggleEditMode}
/>
) : (
<span onClick={toggleEditMode}>{Value}</span>
);
};
export default App;
Click and it will make it editable. Come out and it shows updated value.
CodeSandbox: https://c4fog.csb.app/
Here is full working code of App.js
import React, { Component } from "react";
class App extends Component {
constructor() {
super();
this.state = {
count: [],
disabled: [],
};
this.references = []
}
handleRef(r, index) {
this.references[index] = r
}
handleCancel(e,index) {
const { disabled } = this.state;
disabled[index] = true
this.setState({ disabled })
}
handleRemove(index)
{
this.state.count.splice(index,1)
this.setState({count: this.state.count})
}
handleEdit(e, index) {
const { disabled } = this.state;
disabled[index] = false
this.setState({ disabled }, () => {
this.references[index].focus()
})
}
add(e) {
this.setState({ count: [...this.state.count, ""] });
}
handleChange(e, index) {
const { count } = this.state;
count[index] = e.target.value;
this.setState({ count });
}
render() {
const { disabled, count } = this.state
return (
<div>
<label>Enter the text</label>
{count.map((counts, index) => {
return (
<div key={index}>
<input
ref={(newText) => this.handleRef(newText, index)}
onChange={(e) => this.handleChange(e, index)}
value={counts}
disabled ={disabled[index]}
/>
<button onClick={(e) => this.handleEdit(e,index)}>Edit</button>
<button onClick={() => this.handleRemove(index)}>Remove</button>
<button onClick={(e) =>this.handleCancel(e,index)}>Cancel</button>
</div>
);
})}
<button onClick={(e) => this.add(e)}> Add</button>
</div>
);
}
}
export default App;

React Router/Context API Search Component

I used to make this code work out for my search component but after the on submit is called, I receive this error which never happened before, does anyone have any clue???
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
import React, { Component } from "react";
import axios from "axios";
import { Redirect } from "react-router-dom";
import { Consumer } from "../context";
class Search extends Component {
constructor() {
super();
this.state = {
productTitle: "",
apiUrl: "*******************************",
redirect: false
};
}
findProduct = (dispatch, e) => {
e.preventDefault();
axios
.post(
`${this.state.apiUrl}`,
JSON.stringify({ query: this.state.productTitle })
)
.then(res => {
dispatch({
type: "SEARCH_TRACKS",
payload: res.data.output.items
});
this.setState({ items: res.data.output.items, redirect: true });
})
.catch(err => console.log(err));
};
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
render() {
const { redirect } = this.state;
if (redirect) {
return <Redirect to="/searchresult" />;
}
return (
<Consumer>
{value => {
const { dispatch } = value;
return (
<div>
<form onSubmit={this.findProduct.bind(this, dispatch)}>
<div className="form-group" id="form_div">
<input
type="text"
className="form-control form-control-md"
placeholder="...محصولات دسته یا برند مورد نظرتان را انتخاب کنید"
name="productTitle"
value={this.state.productTitle}
onChange={this.onChange}
/>
<button className="btn" type="submit">
<i className="fas fa-search" />
</button>
</div>
</form>
</div>
);
}}
</Consumer>
);
}
}
import React, { Component } from 'react'
import axios from 'axios'
const Context = React.createContext();
export const axiosDashboard = () => {
const URL = (`*****************`);
return axios(URL, {
method: 'POST',
data: JSON.stringify({refresh:"true"}),
})
.then(response => response.data)
.catch(error => {
throw error;
});
};
const reducer = (state, action) => {
switch(action.type){
case 'SEARCH_TRACKS':
return {
...state,
items: action.payload,
heading: 'Search Results'
};
default:
return state;
}
}
export class Provider extends Component {
state = {
dispatch:action => this.setState(state => reducer(state, action))
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
export const Consumer = Context.Consumer
import React, { Component } from 'react'
import { Consumer } from '../context'
import SearchResult from './SearchResult'
import './Search.css'
class Tracks extends Component {
render() {
return (
<Consumer>
{value => {
const { items } = value
if(items === undefined || items.length === 0){
return 'hello'}
else{
return(
<React.Fragment>
<div id='products_search'>
<div className='container'>
<div className="row justify-content-end">
{items.map(item => (
<SearchResult
key={item.id}
id={item.id}
title={item.name}
current_price={item.current_price}
lowest_price={item.lowest_price}
store_name={item.store_name}
thumb={item.thumb_url}/>
))}
</div>
</div>
</div>
</React.Fragment>
)
}
}}
</Consumer>
)
}
}
export default Tracks
import React from 'react'
import {Link} from 'react-router-dom'
import './Search.css'
const SearchResult = (props) => {
const {title,current_price,lowest_price,thumb,id,store_name} = props
return (
<div className="col-md-3" id="searchresult">
<img src={thumb} alt=""/>
<div className="sexy_line"></div>
<p className="muted">{store_name}</p>
<h6>{title}</h6>
<p>{lowest_price}</p>
<Link to={`products/item/${id}`}>
<button type="button" className="btn btn-light rounded-pill">{
new Intl
.NumberFormat({style: 'currency', currency: 'IRR'})
.format(current_price)
}</button>
</Link>
</div>
)
}
export default SearchResult
Maximum update depth exceeded.
This means that you are in a infinit loop of re rendering a component.
The only place where I can see this is possible to happen is in this part
if (redirect) {
return <Redirect to="/searchresult" />;
}
Maybe you are redirecing to the a route that will get the same component that have the redirect.
Please check if you aren't redirecting to the same route as this component and provide your routes and what is inside Consumer.

Modal is not working with react js, on click of edit button

I am new here in react js, I want to open modal on click of edit button, but it gives me error 'App' is not defined react/jsx-no-undef, Can anyone please help why i am getting that error ? On click of edit button it is call editTask function, and from that function it call toggleModal()function here i have added my full code here, anyhelp will be really appreciated
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import './modal.js';
class PalladiumHub extends React.Component {
render() {
return (<tr>
<td>{this.props.keyuser}</td>
<td>{this.props.name.name}</td>
<td><button type="button" onClick={(e) => { this.props.editTask(this.props.index) }} >Edit</button><button onClick={(e) => { this.props.deleteTask(this.props.index) }}>Delete</button></td>
</tr>
)
}
} //{} {}
class CallCRUD extends React.Component {
constructor(props) {
super(props);
this.deleteTask = this.deleteTask.bind(this);
this.editTask = this.editTask.bind(this);
this.state = {
error: null,
isLoaded: false,
items: [],
isOpen: false
};
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
toggleModal() {
return <App openModal = {this.openModal} />;
}
deleteTask(index) {
alert(index);
console.log(index);
//return false;
let tasks = this.state.items;
tasks.splice(index, 1);
this.setState({
items: tasks
})
}
editTask(index) {
this.toggleModal();
console.log(index);
}
render() {
console.log(this.state.items);
return (<table border="1"> <tr><th>ID</th><th>Name</th><th>Action</th></tr> {
this.state.items.map((data, index) => {
//return console.log(data.id);
return <PalladiumHub name={data} keyuser={data.id} index={index} key={index} deleteTask={this.deleteTask} editTask={this.editTask} />
})
}
</table>
);
}
}
ReactDOM.render(
<CallCRUD />, document.getElementById('root')
);
modal.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Modal from 'react-modal';
const customStyles = {
content : {
top : '50%',
left : '50%',
right : 'auto',
bottom : 'auto',
marginRight : '-50%',
transform : 'translate(-50%, -50%)'
}
};
// Make sure to bind modal to your appElement (http://reactcommunity.org/react-modal/accessibility/)
//Modal.setAppElement('#root')
class App extends React.Component {
constructor() {
super();
this.state = {
modalIsOpen: false
};
this.openModal = this.openModal.bind(this);
this.afterOpenModal = this.afterOpenModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
openModal() {
this.setState({modalIsOpen: true});
}
afterOpenModal() {
// references are now sync'd and can be accessed.
this.subtitle.style.color = '#f00';
}
closeModal() {
this.setState({modalIsOpen: false});
}
render() {
return (
<div>
<Modal
isOpen={this.state.modalIsOpen}
onAfterOpen={this.afterOpenModal}
onRequestClose={this.closeModal}
style={customStyles}
contentLabel="Example Modal"
>
<h2 ref={subtitle => this.subtitle = subtitle}>Hello</h2>
<button onClick={this.closeModal}>close</button>
<div>I am a modal</div>
<form>
<input />
<button>tab navigation</button>
<button>stays</button>
<button>inside</button>
<button>the modal</button>
</form>
</Modal>
</div>
);
}
}
It looks like you dont have App imported into your PalladiumHub and CallCRUD file. It's just saying that Reacy doesnt know where App is coming from.

Resources