How do you use popconfirm in an antd react table? - reactjs

I have a reactjs component which displays an antd table of which one of the columns is to execute an action to archive the item in the row. If someone clicks on Archive I want it to show a popconfirm with yes/no confirmation before it moves forward and archives the item.
Everything works fine until I add the Popconfirm block. Then I get the below error. I think that there is something wrong with my usage of onconfirm and oncancel in the popconfirm but i'm just not getting something probably obvious here. Appreciate any feedback!
import React, { Component } from 'react';
import { connect } from 'react-redux';
import selectProperties from '../selectors/properties';
import { Table, Tag, Divider, Popconfirm, message } from 'antd';
export class PropertyList extends React.Component {
constructor(){
super();
this.columns = [
{
title: 'Address',
dataIndex: 'street',
key: 'street',
render: text => <a>{text}</a>,
},
{
title: 'City',
dataIndex: 'city',
key: 'city',
},
{
title: 'State',
dataIndex: 'state',
key: 'state',
},
{
title: 'Workflow',
key: 'workflow',
dataIndex: 'workflow',
sorter: (a, b) => a.workflow.length - b.workflow.length,
sortDirections: ['descend'],
render: workflow => {
let color = 'geekblue';
if (workflow === 'Inspection' || workflow === 'Maintenance' || workflow === 'Cleaning') {
color = 'volcano';
}
else if (workflow === 'Rented') {
color = 'green';
}
return (
<span>
<Tag color={color} key={workflow}>
{workflow.toUpperCase()}
</Tag>
</span>
);
},
},
{
title: 'Action',
key: 'action',
render: (text, record) => (
<span>
<a>Edit</a>
<Divider type="vertical" />
<Popconfirm
title="Are you sure?"
onConfirm={this.confirm(record)}
onCancel={this.cancel}
okText="Yes"
cancelText="No"
>
Archive
</Popconfirm>
</span>
),
},
];
}
confirm = (record) => {
message.success('Archived');
console.log("confirm function.. record");
console.log(record);
}
cancel = () => {
message.error('Cancelled');
}
render() {
console.log("PropertyList render");
console.log(this.props);
console.log(this.props.properties);
console.log(this.columns);
return (
<div className="content-container">
<div className="list-body">
{
this.props.properties.length === 0 ? (
<div className="list-item list-item--message">
<span>No properties. Add some!</span>
</div>
) : (
<Table
rowKey="id"
dataSource={this.props.properties}
columns={this.columns}
pagination = { false }
footer={() => ''}
/>
)
}
</div>
</div>
)
}
};
const mapStateToProps = (state) => {
console.log("PropertyList mapStateToProps..");
console.log(state);
return {
properties: selectProperties(state.properties, state.filters)
};
};
const mapDispatchToProps = (dispatch) => ({
updateProperty: (id, property) => dispatch(editProperty(id, property))
});
export default connect(mapStateToProps, mapDispatchToProps)(PropertyList);

you are invoking the method confirm (in onConfirm) immediately when it renders the Table rows.
Change:
onConfirm={this.confirm(record)}
To:
onConfirm={() => this.confirm(record)}

Related

How can I have a button in a const object?

I'm learning React.js and this is a table showing which user has which items.
I would like to have a button for each item and delete the corresponding item.
How do you have or {FaTrash} icon in a const object?
This is my full code below
const columns = [
{
name: "Username",
selector: "username",
sortable: true
},
{
name: "Email",
selector: "email",
sortable: true
},
{
name: "Item",
selector: "items",
sortable: true,
right: true
},
{
name: "Action",
value: <button>Edit</button>
}
]
const Admin = () => {
const [data, setData] = useState(allUsers);
const handleRowClicked = row => {
const updatedData = data.map(item => {
if (row.id !== item.id) {
return item;
}
return {
...item,
toggleSelected: !item.toggleSelected
};
});
setData(updatedData);
}
return ( <>
<div className='users p-5'>
<DataTable
title="Users"
columns={columns}
data={data}
defaultSortField="title"
pagination
onRowClicked={handleRowClicked}
/>
</div>
</> );
}
export default Admin;
I used to pass a function that returns a piece of layout with handler
{
name: "Action",
actionRenderer: ({ index, item }) => {
return (
<button onClick={() => onhandle(item)}>
ActionName <!--or icon component-->
</button>
)
}
},
Than you need to create <DataTableRow> component wich will render each object in your columns array. Somewhere in the <DataTableRow> you will be able to access to actionRenderer and your data item:
<div>{actionColumn.actionRenderer({ index, item })}</div>

How do i fix items not being shown on screen from mongo db?

I'm trying to display my orders from mongo db using a List orders component but it shows the error in the image. Could this be a database problem?
this is the code that lists the orders.The image above with the loader looping is where the orders should populate. But it puts that error. Where should i check?
import React, { Fragment, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { MDBDataTable } from 'mdbreact'
import Loader from '../layouts/Loader'
import MetaData from '../layouts/MetaData'
import { useAlert } from 'react-alert'
import { useDispatch, useSelector } from 'react-redux'
import { myOrders, clearErrors } from '../../actions/orderActions'
const ListOrders = () => {
const alert = useAlert()
const dispatch = useDispatch()
const { loading, error, orders } = useSelector((state) => state.myOrders)
useEffect(() => {
dispatch(myOrders())
if (error) {
alert.error(error)
dispatch(clearErrors())
}
}, [dispatch, alert, error])
const setOrders = () => {
const data = {
columns: [
{
label: 'Order ID',
field: 'id',
sort: 'asc',
},
{
label: 'Num of Items',
field: 'numOfItems',
sort: 'asc',
},
{
label: 'Amount',
field: 'amount',
sort: 'asc',
},
{
label: 'Status',
field: 'status',
sort: 'asc',
},
{
label: 'Actions',
field: 'actions',
sort: 'asc',
},
],
rows: [],
}
orders.forEach((order) => {
data.rows.push({
id: order._id,
numOfItems: order.orderItems.length,
amount: `$${order.totalPrice}`,
status:
order.orderStatus &&
String(order.orderStatus).includes('Delivered') ? (
<p style={{ color: 'green' }}>{order.orderStatus}</p>
) : (
<p style={{ color: 'red' }}>{order.orderStatus}</p>
),
actions: (
<Link to={`/order/${order._id}`} className='btn btn-primary'>
<i className='fa fa-eye'></i>
</Link>
),
})
})
return data
}
return (
<Fragment>
<MetaData title={'My Orders'} />
<h1 className='mt-5'>My Orders</h1>
{loading ? (
<Loader />
) : (
<MDBDataTable
data={setOrders()}
className='px-3'
bordered
striped
hover
/>
)}
</Fragment>
)
}
export default ListOrders
[enter image description here][1]
[1]: https://i.stack.imgur.com/ANOZg.png
By the time you check orders.forEach((order) => {} orders must be default state value, must be empty array. This might be the only issue in your code
orders && orders.forEach((order) => {}

Why am I getting the TypeError: _this.props.data is not a function

I am using material-table to build a table of users from a call to my API. The data returns just fine in the console, but when I got to render it, I get an error. Here is an image of my error.
And my code:
import React, { useState, useEffect, useRef, Fragment } from 'react';
import axios from 'axios';
import { API } from '../../config';
import Layout from '../../components/Layout';
import MaterialTable from 'material-table';
const PendingUser = () => {
const [pendingUser, setPendingUser] = useState({
firstName: '',
lastName: '',
email: '',
agency: ''
});
const isMountedVal = useRef(1);
useEffect(() => {
isMountedVal.current = 1;
return () => {
isMountedVal.current = 0;
};
getPendingUsers();
setPendingUser(pendingUser);
}, []);
const getPendingUsers = async () => {
const { data } = await axios.get(`${API}/admin/pendinguser`);
await data.filter(user => {
user.accountApproved ? setPendingUser(user) : setPendingUser();
setPendingUser(user);
});
};
const handleClick = (name, rowData, index, email) => e => {
e.preventDefault();
try {
if (name === 'deny') {
axios.delete(`${API}/admin/pendinguser/${name}/${rowData._id}`);
} else {
name === 'approve';
axios.put(`${API}/admin/pendinguser/${name}/${rowData._id}`);
}
} catch (error) {
console.log(error);
}
};
const columns = [
{
title: 'First Name',
field: 'firstName'
},
{
title: 'Last Name',
field: 'lastName'
},
{
title: 'Email',
field: 'email'
},
{
title: 'Law Enforcement Agency',
field: 'leAgency'
},
{
title: 'Approve',
field: 'approve',
render: rowData => (
<i
className='far fa-check-circle fa-2x'
style={{ color: 'green' }}
onClick={handleClick('approve', rowData)}
></i>
)
},
{
title: 'Deny',
field: 'deny',
render: rowData => (
<i
className='far fa-times-circle fa-2x'
style={{ color: 'red' }}
onClick={handleClick('deny', rowData)}
></i>
)
},
{
title: 'Denial Reason',
field: 'denialReason',
render: rowData => (
<select>
<option value='Not Law Enforcement'>Not Law Enforcement</option>
<option value='Non US Law Enforcement'>Non US Law Enfrocement</option>
</select>
)
}
];
console.log(pendingUser);
return (
<Layout>
<MaterialTable
title='Pending Users'
columns={columns}
data={pendingUser}
isLoading={!pendingUser.length}
options={{
headerStyle: {
backgroundColor: '#249DCD',
color: 'white',
fontWeight: 'bold'
}
}}
/>
</Layout>
);
};
export default PendingUser;
If I remove the data from the columns render just fine, but what is the point if I cant get the data to render.
Material Table requires data to be either an array or a function. You are instead setting it as an object. So material-table first checks if its an array, its not, so it assumes its a function and tries to invoke it, resulting in the above error.

react nav link redirect on condition

I have two values at data index: isOnline (true and false). Right now <NavLink /> renders on both true and false, but I want to render only when value is false and not when it's true. Is there any possibility to do that?
I want to hide hyperlink if value is true. Hyperlink should only be rendered with false value. At the moment it gives me hyperlink on both true and false. But I want true value not to be linked with any other stuff but false value should be clickable.
import React, { useEffect, useState } from 'react';
import {
Tabs, Icon, Divider, Table, Button, Input, Row, Col,
} from 'antd';
import moment from 'moment';
import { NavLink, Redirect } from 'react-router-dom';
import { getAllLeads } from '../../shared/services/apiService';
import { isSuccess } from '../../shared/utils/jsHelper';
import routePaths from '../../shared/routePaths';
// rowSelection object indicates the need for row selection
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
},
getCheckboxProps: (record) => ({
disabled: record.name === 'Disabled User', // Column configuration not to be checked
name: record.name,
}),
};
const dateFormat = 'YYYY-MM-DD';
const Leads = () => {
const [leadList, setLeadList] = useState([]);
const columns = [
{
title: 'Sl no.',
dataIndex: 'name',
render: (name, record) =><span>{leadList.indexOf(record) + 1}</span>
},
{
title: 'Date',
dataIndex: 'createdAt',
},
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Phone number',
dataIndex: 'phone_number',
},
{
title: 'Email id',
dataIndex: 'email',
},
{
title: 'Type',
dataIndex: 'type',
},
{
title: 'Comment',
dataIndex: 'comment',
},
{
title: 'Property name',
dataIndex: 'propertyId.name',
//render: (name, row) => {row.propertyId ? (<NavLink to={`${routePaths.PROPERTY}/${row.propertyId._id}`}>{name}</NavLink>) : null},
},
{
title:'On-Line / Off-Line',
dataIndex: 'isOnline',
// render: (isOnline, row) => {
// if(!isOnline){
// <NavLink to={`${routePaths.LEADSFORM}/${row._id}`}>
// {isOnline}
// </NavLink>
// }else{null}
// }
render: (isOnline, row) => <NavLink to={`${routePaths.LEADSFORM}/${row._id}`}>{isOnline}</NavLink>,
}
];
const [loading, setLoading] = useState(false);
var tokenSession = localStorage.getItem('token');
if(tokenSession!='undefined' && tokenSession == null){
var setTokenSession = true;
}else{
var setTokenSession = false;
}
const [loggedDashOut, setDashLoggedOut] = useState(setTokenSession? true:false);
if (loggedDashOut) {
return <Redirect to={routePaths.LOGIN} />;
}
const getLeadsList = () => {
setLoading(true);
getAllLeads().then((resp) => {
if (isSuccess(resp)) {
setLeadList(resp.data.data);
}
}).finally(() => setLoading(false));
};
useEffect(() => {
getLeadsList();
return () => {};
}, []);
return (
<Row className="row-pad">
<Col xs={24} sm={24} md={8} lg={8} xl={8}><h3>Leads</h3></Col>
<Col xs={24} sm={24} md={8} lg={8} xl={8}></Col>
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
<NavLink to={routePaths.LEADSFORM}>
<Button type="primary" className="btn-add">Add Leads</Button>
</NavLink>
</Col>
<Divider />
<Table pagination={{ pageSize: 10 }} columns={columns} dataSource={leadList} />
</Row>
);
};
export default Leads;
I'm not sure where is your isOnline variable, but basically if you want to render something conditionally you can try:
return (
...
{isOnline ? null : <NavLink />}
...
)
This will render the <NavLink /> component only when isOnline is false.
This is not the only way to implement conditional rendering in React, just a very common one, and I think it suits your use case.
For more details you can refer to the official docs regarding conditional rendering.
Good luck!

How to render Array data in Row of react-table

I'm new in React. Using react-table component to render data from firebase and that is working well.
constructor(props) {
super(props);
this.state = {
vehicles: []
};
}
getvehicles() {
let vehicles = [];
firebase
.database()
.ref(`vehicles`)
.once('value', snapshot => {
snapshot.forEach(level1 => {
level1.forEach(level2 => {
const vehicle = level2.val();
vehicle.pictures && vehicles.push(vehicle);
});
});
this.setState({
vehicles
});
});
}
From here Data comming in react-table
return (
<div style={style}>
<div>
<ReactTable
style={{ marginLeft: '-80%', marginRight: '-80%' }}
data={this.state.vehicles}
filterable
defaultFilterMethod={(filter, row) =>
String(row[filter.id]) === filter.value
}
columns={vehiclesColumns}
SubComponent={row => {
return ;
}}
/>
</div>
</div>
);
Problem is, that I'm getting "pictures" from database, and want to put them in "subcomponent" and I do not know how? Anyone to help?
SubComponent={row => {
return (
<div>
some code here
</div>
);
Image 1 Example of data loaded from firebase
Image 2 Example of table "click on arrow and show pics from database"
=====================
New question
Ok on the end I manage to make all together but still getting error 'imageUrls' is not defined.
For me this is nightmare to find where is problem, so is there anyone who can re-check this code totally and just make comment how to fix and where is problem?!
import React, { Component } from 'react';
import ReactTable from 'react-table';
import 'react-table/react-table.css';
import firebase from 'firebase';
import Moment from 'moment';
import { storage } from 'firebase';
import _ from 'underscore';
export const getFileByPath = async query =>
await storage
.ref()
.child(query)
.getDownloadURL();
class App extends Component {
constructor(props) {
super(props);
this.state = {
vehicles: []
};
this.state = {
imageUrls: []
};
}
prepareImages = () => {
Promise.all(
_.map(this.props.images, image => {
return storage.getFileByPath(image.remoteUri);
})
).then(results =>
_.each(results, result => {
const imageUrls = this.state.imageUrls;
imageUrls.push(result);
this.setState({ imageUrls: imageUrls, loading: false });
})
);
};
componentWillMount() {
this.getvehicles();
}
getvehicles() {
let vehicles = [];
firebase
.database()
.ref(`vehicles`)
.once('value', snapshot => {
snapshot.forEach(level1 => {
level1.forEach(level2 => {
const vehicle = level2.val();
vehicle.pictures && vehicles.push(vehicle);
});
});
this.setState({
vehicles
});
});
}
render() {
const vehiclesColumns = [
{
columns: [
{
Header: 'Vehicle ID',
id: 'vehicleID',
accessor: d => d.vehicleID,
filterMethod: (filter, row) =>
row[filter.id].startsWith(filter.value)
},
{
Header: 'Terminal',
id: 'terminal',
accessor: d => d.terminal,
filterMethod: (filter, row) =>
row[filter.id].startsWith(filter.value)
},
{
Header: 'Time',
id: 'timestamp',
accessor: d => {
return Moment(d.timestamp)
.local()
.format('DD-MMMM-YYYY', 'at', true);
},
filterMethod: (filter, row) =>
row[filter.id].startsWith(filter.value)
},
{
Header: 'User',
id: 'user',
accessor: d => d.user,
filterMethod: (filter, row) =>
row[filter.id].startsWith(filter.value)
}
]
}
];
return (
<div style={style}>
<div>
<ReactTable
style={{ marginLeft: '-80%', marginRight: '-80%' }}
data={this.state.vehicles}
filterable
defaultFilterMethod={(filter, row) =>
String(row[filter.id]) === filter.value
}
columns={vehiclesColumns}
SubComponent={row => {
return (
<div>
{_.map(imageUrls, image => (
<img src={image} key={image} />
))}
</div>
);
}}
/>
</div>
</div>
);
}
}
const style = {
display: 'flex',
justifyContent: 'center'
};
export default App;
I think what you are trying to do is something like:
// Somewhere else, maybe a different doc
const SubComponent = () => {
<div>Content here</div>
}
// [...previous Code]
return (
<ReactTable
style={{ marginLeft: "-80%", marginRight: "-80%" }}
data={this.state.vehicles}
filterable
defaultFilterMethod={(filter, row) =>
String(row[filter.id]) === filter.value
}
columns={vehiclesColumns}
>
<SubComponent props={somePropsHere} />
</ReactTable>
)
Am I right? The children of a Component should not be given as a property.
Regards

Resources