I have an add method in my application. When a widget is clicked you are given the ability to add another widget. Currently the default component being added is but I want the user to be able to select from a list of components. I am new to react any help would be great.
addEvent=(index)=>{
this.setState({isModalOpen: true})
const copyWidgets=Object.assign([],this.state.widgets);
let widget=this.state.widgets[index];
widget.content=<DataTable/>; //I would like to allow the user to choose from a list of components instead of just adding <DataTable/>
copyWidgets[index]=widget;
this.setState({
widgets:copyWidgets
})
}
This is my app.js which contains the widgets and add event:
import React, { Component } from 'react';
import Swappable from './components/SwappableComponent'
import './App.css';
import DataTable from './components/tableWidget';
import CheckboxList from './components/CheckboxList';
import AddWidgetDialog from './components/AddWidgetDialog';
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import Paper from "#material-ui/core/Paper";
import Grid from "#material-ui/core/Grid";
import { Table } from '#material-ui/core';
const styles = theme => ({
root: {
flexGrow: 1
},
paper: {
padding: theme.spacing.unit * 2,
textAlign: "center",
color: theme.palette.text.secondary
}
});
class App extends Component {
constructor(props) {
super(props);
this.state={
widgetOptions:[{name:"Data Table", comp:<DataTable/>},{name:"List", comp:<CheckboxList/>}],
widgets:[ //array for layout
{id:1, content: <DataTable/>},
{id:2, content: <CheckboxList/>},
{id:3, content: ""},
{id:4, content: ""}
],
isModalOpen: false
}
}
deleteEvent=(index)=>{
const copyWidgets=Object.assign([],this.state.widgets);
let widget=this.state.widgets[index];
widget.content="";
copyWidgets[index]=widget;
this.setState({
widgets:copyWidgets
})
}
addEvent=(index)=>{
this.setState({isModalOpen: true})
const copyWidgets=Object.assign([],this.state.widgets);
let widget=this.state.widgets[index];
widget.content=<DataTable/>;
copyWidgets[index]=widget;
this.setState({
widgets:copyWidgets
})
}
onRequestClose = () => {
this.setState({
isModalOpen: false,
});
}
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AddWidgetDialog widgets={this.state.widgetOptions} isModalOpen={this.state.isModalOpen} onRequestClose={this.onRequestClose} />
<Grid container spacing={24}>
{
this.state.widgets.map((widget,index)=>{
return(
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}><Swappable id={widget.id} content={widget.content} delete={this.deleteEvent.bind(this,index)} add={this.addEvent.bind(this,index)}/></Paper>
</Grid>
)
})
}
</Grid>
</div>
);
}
}
App.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(App);
This is my modal:
import React, { PropTypes } from 'react';
import Modal from 'react-modal';
const AddWidgetDialog = ({ widgets, isModalOpen, onRequestClose}) => {
const widgetItems = Object.keys(widgets).map((widget, key) => {
return (
<div key={key} className="list-group">
<a href="#" className="list-group-item">
<h6 className="list-group-item-heading">{widgets[widget].name}</h6>
</a>
</div>
);
});
return (
<Modal
className="Modal__Bootstrap modal-dialog"
isOpen={isModalOpen}>
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" onClick={onRequestClose}>
<span aria-hidden="true">×</span>
<span className="sr-only">Close</span>
</button>
<h4 className="modal-title">Add a widget</h4>
</div>
<div className="modal-body">
<h5>Pick a widget to add</h5>
{widgetItems}
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" onClick={onRequestClose}>Close</button>
</div>
</div>
</Modal>
);
};
export default AddWidgetDialog;
I am not sure did I understand well, but in general I would do something like this:
function compGallery(picked) {
switch(picked) {
case "ListWidget": return <ListWidget />
case "Table": return <Table />
...
default: return <DataTable />
}
}
Then I would create a list component where the user can pick , which handler would call this.setState({ pickedComponent })
and use it inside your method:
addEvent=(index)=>{
this.setState({isModalOpen: true})
const copyWidgets=Object.assign([],this.state.widgets);
let widget=this.state.widgets[index];
widget.content=compGalery(this.state.pickedComponent);
copyWidgets[index]=widget;
this.setState({
widgets:copyWidgets
})
}
I hope it helps.
After update of the question here are my suggestions:
we pass the handler as a prop handleWidgetSelection
const AddWidgetDialog = ({ handleWidgetSelection, widgets, isModalOpen, onRequestClose}) => {
const widgetItems = Object.keys(widgets).map((widget, key) => {
return (
<div key={key} className="list-group">
<a href="#" onClick={() => handleWidgetSelection(widget.name)} className="list-group-item">
<h6 className="list-group-item-heading">{widgets[widget].name}</h6>
</a>
</div>
);
});
return (
<Modal
className="Modal__Bootstrap modal-dialog"
isOpen={isModalOpen}>
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" onClick={onRequestClose}>
<span aria-hidden="true">×</span>
<span className="sr-only">Close</span>
</button>
<h4 className="modal-title">Add a widget</h4>
</div>
<div className="modal-body">
<h5>Pick a widget to add</h5>
{widgetItems}
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" onClick={onRequestClose}>Close</button>
</div>
</div>
</Modal>
);
};
Here we can define the handler which updates selectedWidgetId which is basically the item you selected in the modal, once we have that we just pass find which component want to show
import React, { Component } from 'react';
import Swappable from './components/SwappableComponent'
import './App.css';
import DataTable from './components/tableWidget';
import CheckboxList from './components/CheckboxList';
import AddWidgetDialog from './components/AddWidgetDialog';
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import Paper from "#material-ui/core/Paper";
import Grid from "#material-ui/core/Grid";
import { Table } from '#material-ui/core';
const styles = theme => ({
root: {
flexGrow: 1
},
paper: {
padding: theme.spacing.unit * 2,
textAlign: "center",
color: theme.palette.text.secondary
}
});
class App extends Component {
constructor(props) {
super(props);
this.state={
selectedWidgetId: "Data Table",
widgetOptions:[{name:"Data Table", comp:<DataTable/>},{name:"List", comp:<CheckboxList/>}],
widgets:[ //array for layout
{id:1, content: <DataTable/>},
{id:2, content: <CheckboxList/>},
{id:3, content: ""},
{id:4, content: ""}
],
isModalOpen: false
}
}
handleWidgetSelection=(id) => {
this.setState({selectedWidgetId: id})
}
deleteEvent=(index)=>{
const copyWidgets=Object.assign([],this.state.widgets);
let widget=this.state.widgets[index];
widget.content="";
copyWidgets[index]=widget;
this.setState({
widgets:copyWidgets
})
}
addEvent=(index)=>{
this.setState({isModalOpen: true})
const copyWidgets=Object.assign([],this.state.widgets);
let widget=this.state.widgets[index];
widget.content=this.state.widgetOptions.find(w => w.name === this.state.selectedWidgetId).comp;
copyWidgets[index]=widget;
this.setState({
widgets:copyWidgets
})
}
onRequestClose = () => {
this.setState({
isModalOpen: false,
});
}
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AddWidgetDialog handleWidgetSelection={this.handleWidgetSelection} widgets={this.state.widgetOptions} isModalOpen={this.state.isModalOpen} onRequestClose={this.onRequestClose} />
<Grid container spacing={24}>
{
this.state.widgets.map((widget,index)=>{
return(
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}><Swappable id={widget.id} content={widget.content} delete={this.deleteEvent.bind(this,index)} add={this.addEvent.bind(this,index)}/></Paper>
</Grid>
)
})
}
</Grid>
</div>
);
}
}
App.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(App);
Related
Hi everyone I am new to react but have the task to implement this modal. Unfortunately If I click on the button nothing happens. I could not find a solution and to my total confusion it seems like there are many different ways to implement this kind of modals.
Does anyone have a suggestion please?
The modal itself:
import React, { useState } from 'react'
import './BookingUpdate.css';
function Modal({ setOpenModal, children } : {setOpenModal:any, children:any}) {
if(!setOpenModal) return null;
return (
<div className="modalBackground">
<div className="modalContainer">
<div className="titleCloseBtn">
<button
onClick={() => {
setOpenModal(false);
}}
>
X
</button>
</div>
<div className="title">
<h1>Are You Sure You Want to Continue?</h1>
</div>
<div className="body">
<p>The next page looks amazing. Hope you want to go there!</p>
</div>
<div className="footer">
<button
onClick={() => {
setOpenModal(false);
}}
id="cancelBtn"
>
Cancel
</button>
<button>Continue</button>
</div>
</div>
</div>
);
}
export default Modal;
The file from which it is called:
import React, { useState } from 'react';
import FullLayout from '../components/FullLayout';
import Loading from '../components/Loading';
import { Booking, Formatting } from 'flexspace-commons';
import { Table, Form, Col, Row, Button } from 'react-bootstrap';
import { Search as IconSearch, Download as IconDownload, X as IconX , Settings as IconSettings } from 'react-feather';
import ExcellentExport from 'excellentexport';
import { withTranslation } from 'react-i18next';
import { TFunction } from 'i18next';
import type * as CSS from 'csstype';
import Modal from "../components/BookingUpdate";
interface State {
loading: boolean
start: string
end: string
modalIsOpen: boolean
}
interface Props {
t: TFunction
}
class Bookings extends React.Component<Props, State> {
data: Booking[];
constructor(props: any) {
super(props);
this.data = [];
let end = new Date();
let start = new Date();
start.setDate(end.getDate() - 7);
this.state = {
loading: true,
start: Formatting.getISO8601(start),
end: Formatting.getISO8601(end),
modalIsOpen: false
};
this.toggleBookingModal = this.toggleBookingModal.bind( this );
}
.
.
.
toggleBookingModal = (booking: Booking) => {
this.setState( { modalIsOpen: ! this.state.modalIsOpen } );
<Modal setOpenModal={this.state.modalIsOpen} >
</Modal>
}
renderItem = (booking: Booking) => {
const btnStyle: CSS.Properties = {
['padding' as any]: '0.1rem 0.3rem',
['font-size' as any]: '0.875rem',
['border-radius' as any]: '0.2rem',
};
return (
<tr key={booking.id}>
<td>{booking.user.email}</td>
<td>{booking.space.location.name}</td>
<td>{booking.space.name}</td>
<td>{Formatting.getFormatterShort().format(booking.enter)}</td>
<td>{Formatting.getFormatterShort().format(booking.leave)}</td>
<td><Button variant="info" style={btnStyle} onClick={() => this.toggleBookingModal(booking)}><IconSettings className="feather" /></Button></td>
<td><Button variant="danger" style={btnStyle} onClick={() => this.cancelBooking(booking)}><IconX className="feather" /></Button></td>
</tr>
);
}
.
.
.
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.
js
I have two buttons in parent component e.g button1 ,button2 ,and
I have two radio button in my child component e.g radio1,radio2 ,and both have class to active yellow
the task i need to do is onclick button1 in the parent component, the radio1 become active class and same on click on button2, radio2 in child become active class
import React ,{Component} from 'react';
import { withStyles } from '#material-ui/core/styles';
import { Radio } from '#material-ui/core';
import "react-datepicker/dist/react-datepicker.css";
import { connect } from 'react-redux';
import "./strip.css";
import * as actions from '../../actions/instruction';
import PaypalPayment from "./PaypalPayment"
import BankPayment from "./BankPayment"
class WidthdrawPayment extends Component {
state={
open: false,
cardId: 0,
}
setButton = (id) => {
this.setState({ cardId: id });
}
handlesChange = ({ id }) => {
//const { cardId } = this.props;
this.setState({ cardId: id });
};
render() {
const { open,cardId } = this.state;
return (
<>
<div className="main">
<div className="container-fluid no-padding">
<div style={{display: 'flex'}} >
<div
className=" lawyer-payment-big-box row">
<div className="col-md-12">
<div
className={cardId === 1 ? "active-div widthdraw-payment-choose-box col-sm-4 col-md-4 col-lg-4" :"widthdraw-payment-choose-box col-sm-4 col-lg-4 col-md-4"}>
<span>
<Radio
style={{color:'#fff'}}
color="primary"
checked={cardId === 1}
onClick={() => this.setButton(1)}
onChange={() => this.handlesChange({ id: 1 })}
name="radio-button-demo"
/>
</span>
<span className="widthdraw-payment-type-font" >Transfer</span>
</div>
<div
className={cardId === 2 ? "active-div widthdraw-payment-choose-box col-sm-4 col-md-4 col-lg-4" :"widthdraw-payment-choose-box col-sm-4 col-md-4 col-lg-4"}>
<span>
<Radio
style={{color:'#fff'}}
className=""
color="primary"
checked={cardId === 2}
onClick={() => this.setButton(2)}
onChange={()=> this.handlesChange({ id: 2 })}
name="radio-button-demo"
/>
</span>
<span className="widthdraw-payment-type-font">Bank Transfer</span>
</div>
<div className="col-md-4"></div>
</div>
{cardId === 0 ?
<div className="row">
<div style={{padding:'30px'}} className="col-md-12">
<p>Please select your payment method first to proceed</p>
</div>
</div>
:
<>
{
cardId ===1 ?
<>
{cardId ===1 &&
<PaypalPayment
{...this.props}
{...this.state}
/>
}
</>
:
<>
{/* <BankPayment
{...this.props}
{...this.state}
/> */}
{cardId ===2 ?
<>
{cardId===2 &&<BankPayment
{...this.props}
{...this.state}
/>
}
</>
:
<>
<div className="row">
<div style={{padding:'30px'}} className="col-md-12">
<p>Please select your payment method first to proceed</p>
</div>
</div>
</>
}
</>
}
</>
}
</div>
</div>
</div>
</div>
</div>
</>
)
}
}
export default WidthdrawPayment
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
import { KeyboardDatePicker, MuiPickersUtilsProvider } from "#material-ui/pickers";
import DateFnsUtils from '#date-io/date-fns';
import {Link,Redirect} from 'react-router-dom';
import { Button, TYPES } from "../../components/atoms/YellowButton";
import { connect } from 'react-redux';
import moment from 'moment';
import * as actions from '../../actions/instruction';
import { EmptyList } from '../../components/molecules/NotFound/EmptyView';
import WidthdrawPayment from '../WidthdrawPayment'
const drawerWidth = 550;
class FirmPaymentStats extends React.Component {
constructor(props) {
super(props);
this.state={
open: false,
buttonId: 1,
cardId: 0,
}
this.superheroElement = React.createRef();
}
handlePaypalPayment = () => {
const {history} = this.props;
this.defaultactivepaypal()
history.push(`/main/dashboardmaster/widthdrawpayment`)
}
handleBankPayment = () => {
const {history} = this.props;
this.defaultActivebank()
history.push(`/main/dashboardmaster/widthdrawpayment`)
}
defaultactivepaypal = () => {
const {cardId} = this.props;
this.setState({ cardId: 1 });
}
defaultActivebank = () => {
const {cardId} = this.props;
this.setState({ cardId: 2 });
}
render() {
const { history,cardId } = this.props;
const { open,cardId } = this.state;
return (
<div className='main'>
<div className='container-fluid no-padding'>
<div className={classes.root}>
<div className="firm-payment-history-box row">
<div className='admin-options-section cases-section row'>
{/* balance bar */}
<div style={{ padding: '0px 30px' }} className="row">
<div class="lawyer-payment-subheading">
<div >
<p className="system-ui-bold-text firm-payment-main-heading" >Your Balance</p>
</div>
<div style={{paddingTop:'25px'}} className="lawyer-payment-subheading-btn-end">
<div className="system-ui-bold-text" style={{fontSize: "18px",padding: '8px 5px 0px 5px' }}>Widthdraw Balance:</div>
<button
className="yellow-button "
// checked={cardId === 1}
style={{display:'inline',marginRight: '10px'}}
onClick={this.handlePaypalPayment}
>
Paypal Account
</button>
<button
// checked={cardId === 2}
onClick={this.handleBankPayment}
className="yellow-button " style={{display:'inline'}}>
<img style={{marginRight:'10px'}}
src={require("../../assets/img/bank.png")} />
Bank Account
</button>
</div>
</div>
<div className='user-con-filter page-extras'>
{/* search bar and calender*/}
{/* table */}
</div>
<div className='pagination-dim'>
</div>
</div>
</div>
</div>
<div
style={{display: 'none'}}
>
<WidthdrawPayment
{...this.state}
{...this.props}
handlePaypalPayment={this.handlePaypalPayment}
handleBankPayment={this.handleBankPayment}
handleChange={ this.handlepaymenttypeChange}
/>
</div>
</div>
);
}
}
const wrappedFirmPaymentStats = withStyles(styles, { withTheme: true })(FirmPaymentStats);
const mapStateToProps = ({ instruction }) => ({
...instruction
});
export default connect(mapStateToProps, actions)(wrappedFirmPaymentStats)
I have a list of comments on soccer champions, and am trying to display comments of each soccer champion separately. I'm trying to order by id in firebase, but don't know how I can pass id from the champion component to the component where I display all the comments. It's just giving me undefined for some reason. Any help is greatly appreciated!
champ.js
import React, { Component } from "react";
import { ChampsRef, timeRef } from "./reference";
import { getsinglechamp } from "../actions/champs";
import { connect } from "react-redux"; // this is not being used. oh isee so like this?
import { Redirect, Link } from "react-router-dom";
import { Container, Row, Col } from "reactstrap";
import { Upvote } from "react-upvote";
import Form from "./Form";
import { Icon } from "react-icons-kit";
import Specials from "./specials";
import app from "../config/dev";
import { chevronDown } from "react-icons-kit/fa/chevronDown";
import { chevronUp } from "react-icons-kit/fa/chevronUp";
class OneChamp extends Component {
state = {
name: "",
weak: [],
img: "",
authenticated: false,
currentUser: null,
email: ""
};
componentDidMount() {
app.auth().onAuthStateChanged(user => {
if (user) {
this.setState({
currentUser: user,
email: user.email,
authenticated: true
});
} else {
this.setState({
currentUser: null,
authenticated: false
});
}
});
}
componentWillMount() {
const { dispatch, match } = this.props;
dispatch(getsinglechamp(match.params.id));
console.log(this.props);
}
render() {
console.log(this.props.champ);
const { dispatch, loading } = this.props;
const authenticated = this.state.authenticated;
console.log("change", this.props);
console.log("c", this.props.champ.img);
console.log("", this.props.champ.stats);
const champ = this.props.champ.stats;
let content = null;
if (loading) {
content = <p>Loading...</p>;
} else {
content = (
<div id="f">
<div className="ChampionHeader_row_ArTlM">
<div
style={{
paddingRight: "0.75rem",
paddingLeft: "0.75rem",
flexGrow: 1
}}
>
<div style={{ display: "flex", marginBottom: "1.5rem" }}>
<div style={{ flexShrink: 0, marginRight: "1rem" }}>
<div className="IconChampion_component_2qg6y IconChampion_lg_2QLBf">
<img
className="v-lazy-image v-lazy-image-loaded IconChampion_img_3U2qE"
src={this.props.champ.img}
height="80px"
/>
</div>
</div>
</div>
</div>
</div>
<div className="timeline-panel">
<div className="timeline-heading">
{" "}
<h4>{this.props.champ.name}</h4>
</div>
<ul>
{Object.keys(champ).map((item, i) => (
<div className="card">
<li className="travelcompany-input" key={i}>
<div> {champ[item]}</div>
</li>
</div>
))}
</ul>
<br />
<div className="w3-container">
// place i want to pass id <Comments id={this.props.champ.id} />
<h2>Weak To</h2> <br />
<ul className="w3-ul w3-card-4">
<li className="w3-bar">
<img
src={this.props.champ.img2}
className="w3-bar-item w3-circle w3-hide-small"
style={{ width: 145 }}
/>
<div className="w3-bar-item">
<span className="w3-large">{this.props.champ.weak}</span>
<br />
<span id="item"> Mid </span>
<div className="col-sm-5">
<span className="label label-primary">
{this.props.champ.win}
</span>
</div>
</div>
</li>
<li className="w3-bar">
<img
src={this.props.champ.img3}
className="w3-bar-item w3-circle w3-hide-small"
style={{ width: 145 }}
/>
<div className="w3-bar-item">
<Link to={`/Matchup/${this.props.champ.id}`}>
{" "}
<span className="w3-large">{this.props.champ.weak3}</span>
<br />{" "}
</Link>
<span id="item"> Mid </span>
<span className="label label-primary">
{this.props.champ.win}
</span>
</div>
</li>
</ul>
</div>
</div>
<div />
{authenticated ? (
<div className="nav-item">
<Form id={this.props.champ.id} />
</div>
) : (
<div className="nav-item">
<Link to="/login" className="nav-link2">
{" "}
Login to post
</Link>
</div>
)}
</div>
);
}
return <div>{content}</div>;
}
}
const mapStateToProps = state => {
console.log("champs", state.champs);
console.log(state.loading);
return {
champ: state.champs.champ,
loading: state.loading
};
};
export default connect(
mapStateToProps,
null
)(OneChamp);
comments.js
import React, { Component } from "react";
import axios from "axios";
import app from "../config/dev";
import { Link } from "react-router-dom";
import { ChampsRef, CommentsRef, timeRef } from "./reference";
import { connect } from "react-redux";
import { getsinglechamp } from "../actions/champs";
class Comments extends Component {
state = {
comments: [],
champ_id: "",
loading: true,
email: ""
};
componentWillMount() {
const champ_id = this.props.champ.id;
console.log("id", this.props.champ);
CommentsRef.orderByChild("champ_id")
.equalTo(`${champ_id}`)
.on("value", snap => {
const tasks = [];
let comments = [];
snap.forEach(child => {
comments.push({ ...child.val(), key: child.key });
});
this.setState({ comments: comments, Loading: false });
});
}
render() {
const { dispatch, loading } = this.props;
const { comments, ChampsLoading } = this.state;
const orderedchamps = comments;
let commentList;
if (ChampsLoading) {
commentList = <div className="TaskList-empty">Loading...</div>;
} else if (comments.length) {
commentList = (
<ul className="TaskList">
{comments.map(comment => (
<div>{comment.text}</div>
))}
</ul>
);
}
return (
<div>
<h1> Popular Cham</h1>
<p> {commentList} </p>
</div>
);
}
}
const mapStateToProps = state => {
console.log("champs", state.champs);
console.log(state.loading);
return {
champ: state.champs.champ,
loading: state.loading
};
};
export default connect(
mapStateToProps,
null
)(Comments);
I need to build a drop down menu in a modal popup window with using Material UI
I have drop down menu in my modal window, and as a value I see the last item is "Third" and when I want to select for instance "First" it doesn't work, the menu doesn't select it and still having the last one item as a value in menu
I have 2 files App.js and list.js
App.js code:
import React, { Component } from 'react';
import './App.css';
import {AppButtons} from './components/button'
import {AppList} from './components/list'
import Dialog from 'material-ui/Dialog'
import FlatButton from 'material-ui/FlatButton'
export default class App extends Component {
constructor (props) {
super (props)
this.state = {
isModalOpen: false,
itemsList: [
{name: 'First'},
{name: 'Second'},
{name: 'Third'}
],
}
this.handleChange = this.handleChange.bind(this)
}
handleChange = () => this.setState({this.state.itemsList});
render() {
const actions = [
<FlatButton
label="Save"
primary={true}
onClick={() => this.setState({isModalOpen: false})}
/>,
<FlatButton
label="Cancel"
primary={true}
onClick={() => this.setState({isModalOpen: false})}
/>,
];
return (
<div className="container">
<AppButtons
openModal = {() => this.setState ({isModalOpen: true})}
/>
<Dialog
title="Numbers structure"
actions={actions}
open={this.state.isModalOpen}
onRequestClose={() => this.setState({isModalOpen: true})}
>
<AppList
items = {this.state.itemsList}
/>
</Dialog>
</div>
);
}
}
And list.js code:
import React from 'react'
import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';
const styles = {
customWidth: {
width: 200,
},
};
export const AppList = (props) => {
return (
<div>
<DropDownMenu
style={styles.customWidth}
onChange={this.handleChange}
>
{props.items.map((item, key) => {
return (
<MenuItem
primaryText = {item.name}
openImmediately={true}
autoWidth={false}/>
)
})
}
</DropDownMenu>
<br />
</div>
)
}
Here is the shot
It's because you aren't passing down your handleChange function as a prop to <AppList/>:
<AppList
items = {this.state.itemsList}
/>
Change it to:
<AppList
items = {this.state.itemsList}
handleChange={this.handleChange}
/>
And then in your AppList component, the Dropdown component needs to use this.props.handleChange instead of this.handleChange:
<DropDownMenu
style={styles.customWidth}
onChange={this.props.handleChange}
>
...
</DropDownMenu>