Reputation: 47
I am trying to get a list of data called packages and put it in a table. Added filter and sorting to it.
Skipping code which is not necessary
const PackageScreen = ({ match }) => {
const [ order, setOrder ] = useState('ASC')
const packageList = useSelector(state => state.packageList)
const { loading, error, packages } = packageList
const packageCreate = useSelector(state => state.packageCreate)
const { loading:loadingCreate , error:errorCreate , success: successCreate, package: createdPackage } = packageCreate
const packageDelete = useSelector(state => state.packageDelete)
const { loading:loadingDelete , error:errorDelete , success: successDelete } = packageDelete
const [ data, setData ] = useState([])
useEffect(() => {
dispatch({type: PACKAGE_CREATE_RESET})
if(!userInfo || !userInfo.isAdmin){
navigate('/')
}
setName('')
setMaxDays(0)
setMaxUsers(0)
dispatch(listPackages())
setData(packages)
}, [dispatch, userInfo, successCreate, successDelete, navigate] )
const sorting = (col) => {
if(order === 'ASC'){
const sorted = [...data].sort((a,b) =>
a[col].toString().toLowerCase() > b[col].toString().toLowerCase() ? 1 : -1
)
setData(sorted)
setOrder('DSC')
}
if(order === 'DSC'){
const sorted = [...data].sort((a,b) =>
a[col].toString().toLowerCase() < b[col].toString().toLowerCase() ? 1 : -1
)
setData(sorted)
setOrder('ASC')
}
}
function search(data) {
return data.filter((pack) =>
pack.packageName.toLowerCase().indexOf(q.toLowerCase()) > -1
)
}
const filteredPackages = search(data)
const submitHandler = (e) =>{
e.preventDefault()
dispatch(createPackage({
packageName: name,
maxDaysAllowed : maxDays * 30,
maxUserAllowed : maxUsers
}))
}
const deleteHandler = (id) =>{
if(window.confirm('Are you sure you want to delete?')){
dispatch(deletePackage(id))
}
}
return(
<>
<Link to='/' className='btn btn-dark my-3'>Go Back</Link>
<h1>Add Package</h1>
<Form onSubmit={submitHandler}>
<Row className='my-3' >
<Col>
<Form.Group className="mb-3" controlId='name'>
<FloatingLabel controlId="floatingInput" label="Package Name" className="mb-3">
<Form.Control type="text" placeholder="Package name"
value={name}
onChange = {(e)=> setName(e.target.value)}
/>
</FloatingLabel>
</Form.Group>
</Col>
<Col>
<Form.Group controlId='maxUsers'>
<FloatingLabel controlId="floatingSelect" label="Max. allowed users">
<Form.Control as='select' value={maxUsers}
onChange={(e) => setMaxUsers(e.target.value)}>
{/*<Form.Select aria-label="Floating label select example">*/}
<option>Select number of users</option>
<option value="3">3</option>
<option value="5">5</option>
<option value="10">10</option>
{/*</Form.Select>*/}
</Form.Control>
</FloatingLabel>
</Form.Group>
</Col>
<Col>
<Form.Group controlId='maxDays'>
<FloatingLabel controlId="floatingSelect" label="Package Limit">
<Form.Control as='select' value={maxDays}
onChange={(e) => setMaxDays(e.target.value)}>
{/*<Form.Select aria-label="Floating label select example">*/}
<option>Select Period</option>
<option value="1">1 Month</option>
<option value="3">3 Months</option>
<option value="6">6 Months</option>
<option value="12">1 year</option>
{/*</Form.Select>*/}
</Form.Control>
</FloatingLabel>
</Form.Group>
</Col>
</Row>
<Button type='submit' variant='primary'>
Save
</Button>
</Form>
<h2 className='mt-4'>Package List</h2>
<div className='d-flex'>
<div className='p-2'>
<div className='searchTable'>
<InputGroup className="me-2 my-2">
<InputGroup.Text>Search</InputGroup.Text>
<FormControl aria-label="Search"
value={q} onChange={(e) => setQ(e.target.value)}
/>
</InputGroup>
</div>
</div>
</div>
{ loading ? <Loader />
: error ? <Message variant='danger'>{error}</Message>
: (
<div>
<Table striped bordered hover responsive='md' className='table-sm bg-light' id="table-to-xls">
<thead>
<tr>
<th onClick={() => sorting('packageName')} ><span className='btn'>Package Name</span></th>
<th onClick={() => sorting('maxUserAllowed')} ><span className='btn'>Maximum Users</span></th>
<th onClick={() => sorting('maxDaysAllowed')} ><span className='btn'>Maximum Days</span></th>
<th><span className='btn'>Action</span></th>
</tr>
</thead>
<tbody>
{filteredPackages.map(pack => (
<tr key={pack._id} >
<td>{pack.packageName}</td>
<td>{pack.maxUserAllowed}</td>
<td>{pack.maxDaysAllowed}</td>
<td>
{/*<LinkContainer to={`/admin/product/${product._id}/edit`}>*/}
<Button variant='info' className='btn-sm mx-1' disabled>
<i className='fas fa-edit'></i>
</Button>
{/*</LinkContainer>*/}
<Button variant='danger' className='btn-sm'
onClick={()=> deleteHandler(pack._id)}
>
<i className='fas fa-trash'></i>
</Button>
</td>
</tr>
)) }
</tbody>
</Table>
</div>
)
}
</>
)
}
export default PackageScreen
data and filteredPackage both are empty at initial renders. I tried the below in useEffect but no luck
useEffect(() => {
dispatch({type: PACKAGE_CREATE_RESET})
if(!userInfo || !userInfo.isAdmin){
navigate('/')
}
setName('')
setMaxDays(0)
setMaxUsers(0)
dispatch(listPackages())
**const fetchData = async()=>{
await setData(packages)
}
fetchData()**
}, [dispatch, userInfo, successCreate, successDelete, navigate] )
Please let me know if you need further details.
Upvotes: 1
Views: 530
Reputation: 905
Make a const for packages and assign this to your data state
const packages = useSelector(state => state.packageList.packages)
...
const [ data, setData ] = useState(packages)
and write a useEffect that updates your data state when ever your package store value renders
useEffect(()=>{
setData([...packages])
},[packages])
Upvotes: 1