I have this React table in JHipster project:
<div className="table-responsive">
{activePairsList && activePairsList.length > 0 ? (
<Table responsive>
<thead>
<tr>
<th className="hand" onClick={sort('id')}>
ID <FontAwesomeIcon icon="sort" />
</th>
<th className="hand" onClick={sort('exchangeId')}>
Exchange Id <FontAwesomeIcon icon="sort" />
</th>
...........
<th />
</tr>
</thead>
<tbody>
{activePairsList.map((activePairs, i) => (
<tr key={`entity-${i}`} data-cy="entityTable">
<td>
<Button tag={Link} to={`${match.url}/${activePairs.id}`} color="link" size="sm">
{activePairs.id}
</Button>
</td>
<td>{activePairs.exchangeId}</td>
</tr>
))}
</tbody>
</Table>
) : (
!loading && <div className="alert alert-warning">No Active Pairs found</div>
)}
</div>
I would like to add search functionality for this table. I want to add Filter by exchange to be present and when any exchange is selected the table should be filtered to show only data for the selected exchange. Do you know how this can be implemented?
I've worked on your issue in stackblitz. I create a link to a simple sample of what you want you can check it here.
I've added an input to filter data is passing to the table on input changes. Hope you find it useful.
I prepared a ReactJS/Typescript solution and implemented it on the JHipster 7.
NOTE: if you have no active-pairs entity, apply the below steps.Else continue from step 4.
First of all, create a monolith web project with JHipster 7 & ReactJS.
Create an entity of ActivePairs with JDL Studio and download
the JDL file from the JDL Studio. (activepairs-jdl.jdl)
If you want to pagination add this expression in your jdl file : paginate all with pagination
Copy the activepairs-jdl.jdl file to the root folder of your
project.
Open a terminal on the root folder of your project and write below command:
jhipster jdl activepairs-jdl.jdl
Go this path in your project :
src>main>webapp>app>entities>active-pairs>active-pairs.tsx
Copy the below code and paste it in your active-pairs.tsx file.
import { connect } from 'react-redux';
import { Link, RouteComponentProps } from 'react-router-dom';
import { Button, Col, Row, Table } from 'reactstrap';
import { ICrudGetAllAction, ICrudSearchAction } from 'react-jhipster';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { IRootState } from 'app/shared/reducers';
import { getEntities } from './active-pairs.reducer';
import { IActivePairs } from 'app/shared/model/active-pairs.model';
import { APP_DATE_FORMAT, APP_LOCAL_DATE_FORMAT } from 'app/config/constants';
export interface IActivePairsProps extends StateProps, DispatchProps, RouteComponentProps<{ url: string }> { }
export const ActivePairs = (props: IActivePairsProps) => {
useEffect(() => {
props.getEntities();
}, []);
const { activePairsList, match, loading = true } = props;
const myDataSource = props.activePairsList;
const [myActivePairsList, setActivePairsList] = useState(props.activePairsList);
const [dropdownList, setDropdownList] = useState([])
const [focus, setFocus] = useState(false)
const [searchValue, setSearchValue] = useState('')
const [arrOfSelectedExId, setArrOfSelectedExId] = useState([])
useEffect(() => {
const unrepeated = activePairsList.reduce((acc, curr) => {
if (acc.find(item => item.exchangeId === curr.exchangeId)) {
return acc
}
return acc.concat(curr)
}, [])
const regexes = [`${searchValue}`];
const filtered = unrepeated.filter(item => regexes.some(regex => item.exchangeId.match(regex)));
setDropdownList(filtered);
setActivePairsList(activePairsList);
}, [searchValue, activePairsList])
useEffect(() => {
if (arrOfSelectedExId.length) {
setActivePairsList(myDataSource.filter(activePairs => {
return arrOfSelectedExId.includes(activePairs.exchangeId)
}))
} else {
setActivePairsList(myDataSource)
}
}, [arrOfSelectedExId])
return (
<div>
<input value={searchValue} onFocus={() => setFocus(true)} onBlur={(e) => setFocus(false)} onChange={e => setSearchValue(e.target.value)} />
{(dropdownList.length !== 0) && focus && (<div className="dropdown-parent">
{
dropdownList.map((item, i) => {
return <div key={'drp' + i} className={arrOfSelectedExId.includes(item.exchangeId) ? 'selected' : ''} onMouseDown={(e) => {
e.preventDefault()
setArrOfSelectedExId(prev => {
if (prev.includes(item.exchangeId)) {
return prev.filter(x => x !== item.exchangeId)
} else {
return prev.concat(item.exchangeId)
}
})
// setSearchValue(item.exchangeId)
}}>{item.exchangeId}</div>
})
}
</div>)}
<h2 id="active-pairs-heading">
Active Pairs
<Link to={`${match.url}/new`} className="btn btn-primary float-right jh-create-entity" id="jh-create-entity">
<FontAwesomeIcon icon="plus" />
Create new Active Pairs
</Link>
</h2>
<div className="table-responsive">
{myActivePairsList && myActivePairsList.length > 0 ? (
<Table responsive>
<thead>
<tr>
<th>ID</th>
<th>Exchange Id</th>
<th />
</tr>
</thead>
<tbody>
{myActivePairsList.map((activePairs, i) => (
<tr key={`entity-${i}`}>
<td>
<Button tag={Link} to={`${match.url}/${activePairs.id}`} color="link" size="sm">
{activePairs.id}
</Button>
</td>
<td>{activePairs.exchangeId}</td>
<td className="text-right">
<div className="btn-group flex-btn-group-container">
<Button tag={Link} to={`${match.url}/${activePairs.id}`} color="info" size="sm">
<FontAwesomeIcon icon="eye" /> <span className="d-none d-md-inline">View</span>
</Button>
<Button tag={Link} to={`${match.url}/${activePairs.id}/edit`} color="primary" size="sm">
<FontAwesomeIcon icon="pencil-alt" /> <span className="d-none d-md-inline">Edit</span>
</Button>
<Button tag={Link} to={`${match.url}/${activePairs.id}/delete`} color="danger" size="sm">
<FontAwesomeIcon icon="trash" /> <span className="d-none d-md-inline">Delete</span>
</Button>
</div>
</td>
</tr>
))}
</tbody>
</Table>
) : (
!loading && <div className="alert alert-warning">No Active Pairs found</div>
)}
</div>
</div>
);
};
const mapStateToProps = ({ activePairs }: IRootState) => ({
activePairsList: activePairs.entities,
loading: activePairs.loading,
});
const mapDispatchToProps = {
getEntities,
};
type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
export default connect(mapStateToProps, mapDispatchToProps)(ActivePairs);
copy below css codes in your app.scss file :
h1,
p {
font-family: sans-serif;
}
.selected {
background-color: rgb(190, 188, 188);
}
.dropdown-parent {
max-height: 80px;
width: 200px;
overflow-y: scroll;
border: 1px solid black;
background-color: white;
position: absolute;
}
Run this command ./mvnw
You should see a search box at the top of your table.
As you see I selected 98 and It listed just the rows which have the
values of ExchangeID is 98
Thanks.
Related
So, I have this appointments array coming in from its parent component. This component should map over the array, and then return a div for each item that occurs at a date later than today. Then, when the user clicks the "confirm" button it should re-render the list and remove that item that was just clicked from the list of rendered divs.
The problem is when it re-renders, I get the same "appointments.map() is not a function" error. If I click refresh the component renders as expected with the div that was clicked on removed from the list.
I can't seem to figure out why, as this component shouldn't even load unless the appointments array has a length (as it states in the parent component).
This is the parent component:
import React, { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { getAppointments } from '../../../actions/appointment'
import ConfirmAppointment from '../Appointments/ConfirmAppointment'
const Dashboard = ({user}) => {
const dispatch = useDispatch()
useEffect(() => {
//get appointment data
dispatch(getAppointments(user?.result._id))
}, [dispatch])
const appointments = useSelector((state)=>state?.usersReducer?.appointment)
return (
<>
<div>
<h3>Welcome {user?.result?.firstName}! :D</h3>
{/* <Link to='/bookappointment'>
<button className="ui button" style={{backgroundColor: '#adad85'}}>Book an appointment</button>
</Link> */}
<Link to="/healthhistory/update" >
<button className="ui button" style={{backgroundColor: '#adad85'}}>Update Health History</button>
</Link>
<Link to="/dashboard/receipts">
<button className="ui button" style={{backgroundColor: '#adad85'}}>View Appointment Receipts</button>
</Link>
{appointments?.length === 0 ? (
<div>Loading ...</div>
) : (
<ConfirmAppointment user={user} appointments={appointments} />
)
}
</div>
</>
)
}
export default Dashboard
And this is the component with the .map function:
import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { confirmAppointment } from '../../../actions/appointment'
const ConfirmAppointment = ({user, appointments}) => {
const dispatch = useDispatch()
const { _id } = user?.result
const today = new Date()
const [reasonForMassage, setReasonForMassage] = useState('')
const [treatmentConsent, setTreatmentConsent] = useState(false)
const [glutes, setGlutes] = useState(false)
const [chest, setChest] = useState(false)
const [abdomen, setAbdomen] = useState(false)
const [innerThighs, setInnerThighs] = useState(false)
const [areasToAvoid, setAreasToAvoid] = useState('')
const formData = {
reasonForMassage,
consents: {
treatmentConsent,
glutes,
chest,
abdomen,
innerThighs,
areasToAvoid
}
}
const handleSubmit = (e, appointmentId) => {
e.preventDefault()
setTreatmentConsent(true)
//update appointment with the appointment id
dispatch(confirmAppointment(_id, appointmentId, formData))
clear()
}
const clear = () => {
setReasonForMassage('')
setGlutes(false)
setChest(false)
setAbdomen(false)
setInnerThighs(false)
setAreasToAvoid(false)
}
return (
appointments?.length === 0 ? (
<div>
No upcoming appointments
</div>
) : (
<div style={{marginTop: '3em'}}>
<h4>Upcoming Appointments</h4>
{appointments && appointments?.map((appointment) => (
new Date(appointment?.date) >= today && appointment?.consents?.treatmentConsent !== true ? (
<div style={{marginBottom: '3em'}} key={appointment._id} >
<table className="ui table">
<thead>
<tr>
<th>Date</th>
<th>Time</th>
<th>Duration</th>
</tr>
</thead>
<tbody>
<tr>
<td>{appointment?.date}</td>
<td>{appointment?.time}</td>
<td>{appointment?.duration}</td>
</tr>
</tbody>
</table>
<form className="ui form" onSubmit={(e)=>handleSubmit(e, appointment?._id)} >
<div className="ui fields">
<div className="ui field">
<label>Reason for booking massage:</label>
<input type="text" value={reasonForMassage} onChange={(e)=>setReasonForMassage(e.target.value)}/>
</div>
<div className="ui field">
<h5>I give consent to massage the following areas:</h5>
<div>
<input type="checkbox" value={glutes} onChange={(e)=>setGlutes(e.target.checked)} />
<label>Glutes</label>
<input type="checkbox" value={abdomen} onChange={(e)=>setAbdomen(e.target.checked)} />
<label>Abdomen</label>
<input type="checkbox" value={chest} onChange={(e)=>setChest(e.target.checked)} />
<label>Chest</label>
<input type="checkbox" value={innerThighs} onChange={(e)=>setInnerThighs(e.target.checked)} />
<label>Inner thighs</label>
</div>
</div>
<div className="ui field">
<label>Are there any other areas you would not like to be massaged?</label>
<input type="text" value={areasToAvoid} onChange={(e)=>setAreasToAvoid(e.target.value)} />
</div>
</div>
<button type="submit" className="ui button">Confirm Appointment</button>
</form>
</div>
) : (
<div></div>
)
))}
</div>
)
)
}
export default ConfirmAppointment
Hope you guys are fine.
I have the next code for dynamically show the quantity of each selected product
import React, { useState, useEffect } from 'react';
import db from '../firebase';
//const Swal = window.Swal;
const NewSale = () => {
const [products, setProducts] = useState([]);
const [selectedProducts, setSelectedProducts] = useState([]);
useEffect(() => {
if(products.length === 0){
db.collection('products').get().then((querySnapshot) => {
const docs = [];
querySnapshot.forEach((doc) => {
docs.push({
id: doc.id,
...doc.data()
});
});
docs.sort((a, b)=> a.name.localeCompare(b.name));
setProducts(docs);
});
}
});
const handleSelectChange = (e) => {
const value = e.target.value;
if(value){
const selectedProduct = products.filter(item => item.id === value)[0];
setSelectedProducts(selectedProducts => [...selectedProducts, {
id: value,
name: selectedProduct.name,
quantity: 1
}]);
}
}
const handleRangeChange = (target, index) => {
const currentValue = parseInt(target.value);
let currentArrayValue = selectedProducts;
currentArrayValue[index].quantity = currentValue;
setSelectedProducts(currentArrayValue);
}
const handleCancelButton = () => {
setSelectedProducts([]);
}
return (
<React.Fragment>
<div className='container'>
<h1 className='display-3 text-center'>New Sale</h1>
<div className='row'>
<div className='col'>
<div className='mb-3'>
<label htmlFor='product' className='form-label fs-3'>Service</label>
<select id='product' onChange={handleSelectChange} className='form-select form-select-lg' multiple aria-label='multiple select service'>
{products.length !== 0?
products.map(item => <option key={item.id} value={item.id}>{item.name}</option>) : <option>No product registered</option>
}
</select>
</div>
</div>
</div>
<div className='row mt-4'>
<div className='col'>
<table className='table caption-top'>
<caption>Sell List</caption>
<thead>
<tr>
<th scope='col'>#</th>
<th scope='col'>Product</th>
<th scope='col'>Quantity</th>
</tr>
</thead>
<tbody>
{selectedProducts.length !== 0?
selectedProducts.map((item, index) => (
<tr key={index}>
<th scope='row'>{(index + 1)}</th>
<td>{item.name}</td>
<td>
<label htmlFor={`customRange-${index}`} className='form-label'>{item.quantity} Units</label>
<input
type='range'
className='form-range'
value={item.quantity}
onChange={({target}) => handleRangeChange(target, index)}
min='1'
max='100'
step='1'
id={`customRange-${index}`}/>
</td>
</tr>
)) :
<tr>
<th className='text-center' colSpan='3'>Nothing selected!</th>
</tr>
}
</tbody>
</table>
</div>
</div>
<div className='row mt-2'>
<div className='col'>
<button className='btn btn-success'>Save</button>
</div>
<div className='col'>
<button className='btn btn-warning' onClick={handleCancelButton}>Cancel</button>
</div>
</div>
</div>
</React.Fragment>
)
};
export default NewSale;
The code shows this... I do not know if I'm allowed to do this kind of operations because I'm adding events every time I select a product so, I'm not sure this is the best way to do it.
And the problem is that I'm getting this unexpected result,
What I want to do is show the current Quantity for each selected item,
Thanks!!
I want to render large lists of data inside a table. I am using the React-List library found online, but when the user scrolls about 200 items, the rest of them take too much time to load.
I achieved something like this:
After about 200 items, I get these warnings in the console, and the list starts to render slower and slower like in the image below:
I use React-List for rendering this table and a get request to get all the data once, code will be shown below.
import React from 'react';
import axios from 'axios';
import { toastr } from '../../../components/toastr/toastr.component';
import { Table } from 'react-bootstrap';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faTrashAlt } from '#fortawesome/free-solid-svg-icons';
import DaysJS from 'react-dayjs';
import Loading from '../../../components/loading/loading.component';
import Tooltip from '../../../components/tooltip/tooltip.component';
import ReactList from 'react-list';
import './error.styles.scss';
class ErrorPage extends React.Component {
constructor() {
super();
this.state = {
pending: true,
errors: []
}
};
componentDidMount() {
axios.get('/api/logError').then(resp => {
this.setState({ pending: false, errors: resp.data });
}).catch(() => toastr('error', 'Eroare la preluarea datelor!'));
};
renderItem = (index, key) => {
return (
<tr key={key}>
<td>
{this.state.errors[index].id}
</td>
</tr>
)
};
renderTable (items, ref) {
return (
<div style={{maxHeight: '400px', overflowY: 'scroll'}}>
<Table bordered striped hover size="sm">
<tbody ref={ref}>
{items}
</tbody>
</Table>
</div>
);
}
renderRow = (index, key) => {
const entry = this.state.errors[index]
return (
<tr key={key}>
<td width='40px' className='text-center'>{index}</td>
<td width='40px' className='text-center'>{entry.id_user}</td>
<td width='200px'>{entry.email}</td>
<td width='200px'>{entry.name}</td>
<td width='200px'>{entry.action}</td>
<td>{entry.error}</td>
<td width='120px' className='text-center'><DaysJS format='DD.MM.YYYY - HH:MM'>{entry.createdAt}</DaysJS></td>
<td width='30px' className='cursor-pointer text-center' data-tip data-for='tooltip'>
<Tooltip id='tooltip' message='Șterge eroare'/>
<FontAwesomeIcon className='text-danger' icon={faTrashAlt} />
</td>
</tr>
);
}
render() {
const { pending, errors } = this.state;
return (
<div className='error-page mt-3 row'>
<Loading pending={pending} />
<div className='col-sm-4 fw-bold'>Total erori: {errors.length}</div>
<div className='col-sm-4'>
<h4 className='text-center'>Erori</h4>
</div>
<div className='col-sm-4 text-end'>
<button className='btn btn-danger btn-sm'>
<FontAwesomeIcon icon={faTrashAlt} className='me-1' />
Șterge toate
</button>
</div>
<div className='col-sm-12'>
<Table bordered size="sm">
<thead>
<tr>
<th width='40px'>Id user</th>
<th width='200px'>Email</th>
<th width='200px'>Unitate</th>
<th width='200px'>Acțiune</th>
<th>Eroare</th>
<th width='120px'>Data</th>
<th width='38px'></th>
</tr>
</thead>
</Table>
<ReactList
itemsRenderer={(items, ref) => this.renderTable(items, ref)}
itemRenderer={this.renderRow}
length={errors.length}
/>
</div>
</div>
);
};
};
export default ErrorPage;
I used in AngularJS a library called ng-infinite-scroll that rendered the items with no problem with infinite scroll and I tried to find something similar for ReactJS.
I am new with programing and I want to use if ternario, but it doesn't work. I have two functions and I create a third function to show one of them or the other. It is an application in ReactJS. Below is the code:
import { Table } from "react-bootstrap";
import { Link } from "react-router-dom";
import { useCartContext } from "../../Context/CartContext";
const emptyCart = () => {
return(
<>
<div>
<h3>The Cart is empty</h3>
<p>
Return to home to see our products
</p>
<Link to='/' ><button className="btn btn-info"> Home </button></Link>
</div>
</>
);
};
const CartFunction = () => {
const { list, totalPrice } = useCartContext();
return (
<Table striped hover>
<thead>
<tr>
<th>Product</th>
<th>Title</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{list.map((varietal) => (
<tr key={varietal.id}>
<td>
<img
src={varietal.pictureUrl}
alt='img'
style={{ width: "82px" }}
/>
</td>
<td>{varietal.title}</td>
<td>{varietal.count}</td>
<td>${varietal.price}</td>
</tr>
))}
</tbody>
<thead>
<tr>
<td colSpan="3">Total</td>
<td>${totalPrice()}</td>
</tr>
</thead>
</Table>
);
};
const CartComponent = () => {
const { list } = useCartContext();
return (
<>
{list.length !== 0 ? <CartFunction /> : <emptyCart />}
</>
);
};
export default CartComponent;
Visual Code it says that emptyCard has a value but it is never used. If there is someone that could help me I would appreciate it. Cheers
I'm pretty new to reactjs and I came to a situation where I cannot solved !
My app has a json array in this following format:
[
{"email":"sample1#sample.com", "mobile":"000000", "iscompleted":"false"},
{"email":"sample2#sample.com", "mobile":"000000", "iscompleted":"false"},
{"email":"sample3#sample.com", "mobile":"000000", "iscompleted":"false"},
{"email":"sample4#sample.com", "mobile":"000000", "iscompleted":"false"}
]
In my app logic, once I send a POST request and get its return response I update the iscompleted to True.
Then, I have a click button that refresh the application to its original state... however, I want to only display the button if all items in the json object is as "iscompleted":"true".
The question here, is how is the best approach to do that ?
I'm using react hooks for all my code, although, i dont know if its relevant.
I was thinking in a arrow function that returns true then i can use the following:
{is_all_completed ? <StartAgainBtn /> : null}
Thank you
Update
I'm using the following code logic at the end of the file. Also, I'm using const and arrow functions. As you can tell, I'm pretty new to react !
return (
<div>
{props.recipients[0] && !props.report_sent ? <UserRecipientsTableView /> : null}
{props.report_sent ? <ReportsSubmittedTable /> : null}
{props.report_sent? <StartAgainBtn /> : null}
{user_confirmed && !props.report_sent ? <SendReports /> : null}
</div>
);
};
export default Confirmation;
Update2
Full code controller goes below:
import React, { useState } from "react";
import axios from "axios";
import { toast } from "react-toastify";
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
import InputAdornment from "#material-ui/core/InputAdornment";
const Confirmation = props => {
const [user_confirmed, setUserInputConfirmation] = useState('');
const [recipients, updateRecipients] = useState(props.recipients);
const handleSubmit = e => {
e.preventDefault();
props.setReportSent(true)
props.recipients.forEach(function (element, index) {
// Make it spin !
updateRecipients([...recipients, element['iscomplete'] = false, element['errors'] = false])
axios
.post("/api/delivery/", element,
{
headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${props.accessToken}`
},
})
.then(function(response) {
if (response.status === 202){
updateRecipients([...recipients, element['iscomplete'] = true, element['errors'] = false])
// for (const [key, value] of Object.entries(response.data)) {
// toast.success(` 🎉 ${key}: ${value} 🎉`);
// }
}
})
.catch(function(error) {
toast.error(` 😥 Oh no! {${error.response.data}`);
console.log(error.response.data);
updateRecipients([...recipients, element['iscomplete'] = true, element['errors'] = true])
// updateReportSentList([...report_sent_list, {element}])
for (const [key, value] of Object.entries(error.response.data)) {
toast.error(` 😥 Oh no! ${key}: ${value}`);
}
});
});
};
const UserConfirmationView = () => {
if (user_confirmed)
return (
<div>
<br/>
<span>
<h4>Please go ahead and click 'SEND IT'!</h4>
</span>
<br></br>
</div>
)
else {
return(
<div className='user-consent-input'>
<br></br>
<TextField
id="input-with-icon-grid"
label=""
placeholder='If you agree to the above, please type CONFIRMED in here ...'
// variant="outlined"
onChange={handleUserConfirmation}
style = {{width: 500}}
error={!user_confirmed ? true : false}
// helperText={name.error ? name.helptext : ""}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<i className="fas fa-check-double"></i>
</InputAdornment>
)
}}
/>
<br></br>
</div>
)
}
}
const UserRecipientsTableView = () => {
return (
<div className="card">
<div className="card-body">
<p className="you-are-about"> You are about to send <span className="userconfirm-view-filename-attr"> {props.filename}</span> to these contacts
below as <spam className="userconfirm-view-filename-attr"> {props.project_owner_name}</spam> being the project owner of the jobID: <spam className="userconfirm-view-filename-attr">{props.project_id}</spam>.</p>
<br>
</br>
<p className="card-text">
<div className="recipients-table">
<table className="table table-hover table-sm">
<thead className='thead-dark'>
<tr>
<th scope="col">Recipient's Name </th>
<th scope="col">Recipient's Email</th>
<th scope="col">Recipient's Mobile</th>
<th scope="col">Project Desc</th>
<th scope="col"></th>
</tr>
</thead>
{/* Table body */}
{props.allRecipients}
</table>
</div>
<p>
<div className="userconfirm-view">
<br></br>
<p className="you-are-about"> If you agree, please type <span className="userconfirm-view-filename-attr">CONFIRMED</span> into the box below.</p>
<div className="col final-buttom" >
<UserConfirmationView />
</div>
</div>
</p>
</p>
</div>
</div>
);
};
const handleUserConfirmation = e => {
if (e.target.value.trim().toUpperCase() === "CONFIRMED") {
setUserInputConfirmation("Confirmed");
} else
setUserInputConfirmation("");
// setName({ error: true, helptext: "Wrong!" });
};
const SendReports = () => {
if(user_confirmed){
return (
<Button variant="contained" color="secondary"
onClick={handleSubmit}
fullWidth={true}
size="medium"
style={{fontSize: "59px"}}
// style={{minWidth: '300px', minHeight: '130px', marginTop: '40px', fontWeight: '700', lineHeight: '22px', marginBottom: '25px'}}
// startIcon={<i className="fas fa-file-upload fa-6x"></i>}
>
<h4 className="send-it">Send it!</h4>
</Button>
);
}else{
return (
alert("Can't submit it! Please start again.")
)
}
};
const statusStyle = (item) => {
if (!item['iscomplete'] && (!item['errors'])) {
// spin loader ...
return(<span><i className="fas fa-spinner fa-spin fa-2x"></i> Loading ...</span>)
} else if (item['iscomplete'] && (!item['errors'])) {
// if completed and no errros how Success
return(<Button
variant="contained"
color="secondary"
className='success-btn'
startIcon={<i className="fas fa-check-circle fa-2x"></i>}
>
DELIVERED!
</Button>)
// return (<span><i className="fas fa-check-circle fa-2x"></i>Delivered!</span>);
} else {
// Damn boy ! something went wrong!
return(<Button
classes={{ label: 'failed-button' }}
variant="contained"
color="secondary"
startIcon={<i className="fas fa-exclamation-triangle fa-2x"></i>}
>
Failed
</Button>)
// return (<span><i className="fas fa-exclamation-triangle fa-2x"></i>Please, try again ...</span>);
}
}
const ReportsSubmittedTable = () => {
const tableAfterReportSent = props.recipients.map((item, index) =>
<tbody key={index}>
<tr>
<th scope="row">{item.client_name}</th>
<td>{item.client_email}</td>
<td>{item.client_mobile}</td>
<td>{statusStyle(item)}</td>
{/* <td>{statusStyle(item.iscomplete)}</td> */}
{/* <td><i className="recipients-x-remove" onClick={() => removeTodo(index)}><span role='img'> ❌ </span></i></td> */}
</tr>
</tbody>
);
return (
<div className="card" onChange={ReportsSubmittedTable}>
<div className="card-body">
{/* <h5 className="card-title">I'm doing what you told me to ... Please, hold on!</h5> */}
<br></br>
{/* <h6 className="card-subtitle mb-2 text-muted">You are about to send <span>{props.filename}</span> to the following people: </h6> */}
<p className="card-text">
<div className="recipients-table">
<table className="table table-hover table-sm">
<thead className='thead-dark'>
<tr>
<th scope="col">Recipient's Name </th>
<th scope="col">Recipient's Email</th>
<th scope="col">Recipient's Mobile</th>
<th scope="col">Status</th>
{/* <th scope="col">Errors</th> */}
</tr>
</thead>
{/* Table body */}
{tableAfterReportSent}
</table>
</div>
<p>
<hr></hr>
</p>
</p>
</div>
</div>
);
};
const StartAgainBtn = () => {
if (props.report_sent){
return (
<div className="card completed">
<div className="card-body">
<div className="row">
<div className="col">
<h4>Completed!</h4>
<br></br>
<h4>Want to send a new file ?</h4>
</div>
<div className="col">
<Button
variant="outlined"
color="primary"
size="large"
onClick={e => props.resetfile()}
style={{
minWidth: "100%",
minHeight: "100%",
// marginTop: "20px",
fontWeight: "600",
// lineHeight: "22px"
}}
>
<i className="fas fa-redo fa-4x"></i>
<h4 className="start-again">{ }Start Again!</h4>
</Button>
</div>
</div>
</div>
</div>
);
}
}
return (
<div>
{props.recipients[0] && !props.report_sent ? <UserRecipientsTableView /> : null}
{props.report_sent ? <ReportsSubmittedTable /> : null}
{props.report_sent? <StartAgainBtn /> : null}
{user_confirmed && !props.report_sent ? <SendReports /> : null}
</div>
);
};
export default Confirmation;
You could do something like this:
Create a function that takes the list and checks for isComplete property of each item on the array.
Then you can just call that function on your ternary operator {isAllCompleted(JSON.parse(responseDataASJSON))? <StartAgainBtn /> : null}
// param ="resultData" is the data received from Ajax Response. data must be a javascript object.
function isAllCompleted(data){
for(let i =0; i < data.length; i++){
if(data[i].isCompleted === "false"){
// If any false value was found, return false
//
return false;
}
}
// At this point, no value was found to be false,
// because it wouldn't returned false based on the loop block
return true;
}
You can use the JS function .every() for easy iteration through the JSON object.
is_all_completed = YourJSONObj.every(function (n) { return n.iscompleted === "true";})
I hope it helps.
That ternary will work fine. I typically like to simplify it even more with the following:
{ is_all_completed && <StartAgainBtn /> }
Just makes things a little more concise but either way works.