React.js: CheckOut Time is not showing (Array not updating) - reactjs

Actually, I am making Employee attendance portal. I have 2 buttons on the Dashboard named as CheckIn & CheckOut. When I click the CheckIn button I get the current date, attendance as 'PRESENT' & CheckIn time from the Backend & when I click the checkOut button I get CheckOut time from the Backend. I just wanted to display all of these data in a table on React. I am getting all the data from the backend but I am unable to show the checkOut time in a table. What I am doing is I have made an array UseState with the name checkIn and I am putting all the data in that array. But in my scenario, only CheckIn data is pushed in the CheckIn array, and CheckOut data is not pushed in CheckIn array. On the table, I have mapped on Checkin array data. Getting the chechIn data & checkOut column remains empty.
import React, { useState, useEffect } from "react";
import moment from "moment";
import EmployeeNavbar from "./EmployeeNavbar";
import { useDispatch, useSelector } from "react-redux";
import {
employeeCheckIn,
employeeCheckOut,
getEmployeeCheckIn,
getEmployeeCheckOut
} from "../../actions/employeeActions.js";
const EmployeePanel = () => {
const employee = useSelector(state => state.employee);
const dispatch = useDispatch();
const [checkIn, setCheckIn] = useState([]);
const handleCheckIn = id => {
dispatch(employeeCheckIn(id));
};
const handleCheckOut = id => {
dispatch(employeeCheckOut(id));
};
console.log(employee);
useEffect(() => {
dispatch(getEmployeeCheckIn());
dispatch(getEmployeeCheckOut());
{
employee.checkOut
? setCheckIn(employee.checkIn, employee.checkOut)
: setCheckIn(employee.checkIn);
}
console.log(checkIn);
});
return (
<div>
<EmployeeNavbar />
<div className="container">
<h4>
<b>Employee Attendance Portal</b>
</h4>
<div>
<button
className="btn-small waves-effect waves-light hoverable green"
onClick={() => handleCheckIn(employee.employee.employeeData._id)}
>
Check In
</button>
<button
className="btn-small waves-effect waves-light hoverable red accent-4"
onClick={() => handleCheckOut(employee.employee.employeeData._id)}
>
Check Out
</button>
</div>
<table className="striped centered">
<thead>
<tr>
<th>Date</th>
<th>Attendance</th>
<th>Check In</th>
<th>Check Out</th>
</tr>
</thead>
<tbody>
{checkIn
? checkIn.map((list, i) => {
return (
<tr key={i}>
<td>{moment(list.date).format("MMM Do YYYY")}</td>
<td>{list.attendance}</td>
<td>{list.checkIn}</td>
<td>{list.checkOut}</td>
</tr>
);
})
: ""}
</tbody>
</table>
</div>
</div>
);
};
export default EmployeePanel;

Hi in this line you are only showing checkin data
{checkIn
? checkIn.map((list, i) => {
return (
<tr key={i}>
<td>{moment(list.date).format("MMM Do YYYY")}</td>
<td>{list.attendance}</td>
<td>{list.checkIn}</td>
<td>{list.checkOut}</td>
</tr>
);
})
: ""}
you should merge both checkedIn and checkedOut data into single arry.then it will work

Related

How to pass partial data to a parent component in react

I have the following Component TBorrowed
import React, { Fragment, useState} from "react";
import {Link} from 'react-router-dom';
const EditItem = ({ item }) => {
const [name, setName] = useState(item.name)
const saveData = async (e) => {
e.preventDefault();
const body = { name}
await fetch(`http://127.0.0.1:5000/item/edit/${item.id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
})
}
return (
<Fragment>
<Link className="link" data-toggle="modal" data-target={`#id${item.id}`} >{item.name}</Link>
<div className="modal" id={`id${item.id}`}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title">Edit Item</h4>
</div>
<div className="modal-body">
<label>Name</label>
<input value={name} onChange={e => { setName(e.target.value) }} type="text" />
</div>
<div className="modal-footer">
<button onClick={e => { saveData(e) }} type="button" className="btn btn-outline-success ml-auto" data-dismiss="modal">Save</button>
</div>
</div>
</div>
</div>
</Fragment>
)
}
export default EditItem;
The above is called in another component, Main as shown below
import React, { useState} from 'react';
import TBorrowed from './TBorrowed';
const Main = () => {
const [items, setItems] = useState([]);
...MANY ITEMS SKIPPED...
return (
<table className="layout">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Code</th>
</tr>
</thead>
<tbody>
{
items.map((item, index) => (
<tr key={item.id}>
<td>{index + 1}</td>
<td>{item.name}</td>
<td>{<TBorrowed item={item} />}</td>
</tr>
))
}
</tbody>
</table>
)
}
export default Main;
The above works well where I am able to see the item code in the Main component's <td></td> when rendered, which when I click, I am able to edit the particular item in a modal.
My issue is I no longer want to edit an item in a modal but I want it rendered on it's own page for editing.
When I try it without a data-toggle = "modal" in the TBorrowed component, I get all the contents of the TBorrowed component displaying in the Main component where the modal is called i.e <td>{<TBorrowed item={item} />}</td>. All the data in TBorrowed is shown in that <td></td> instead of just the item.code as it was showing while using the modal
My code has some parts missing so it can fit here.
Please assist, and if there's more information required I'll provide it.

Page crashes(reading properties of undefined) in React.js

In my project I'm using redux toolkit and react router v6. I have invoices list with 'View' button and when it's clicked it should open page with description about invoice. Also i have add invoice feature. When invoice added and I click on 'View' button page crashes and the error in console say:
Uncaught TypeError: Cannot read properties of undefined (reading 'invoice_num')
And the same happens if i click on existing item and reload the page. It says the error occured in InvoiceItem.js page.
Now the code. InvoiceItem.js
import React from "react";
import { useParams } from "react-router-dom";
import InvoiceItemDescription from "../Invoice/InvoiceItemDescription";
import { INVOICES_LIST } from "./InvoicesList";
const InvoiceItem = () => {
const params = useParams();
const invoice = INVOICES_LIST.find(
(invoice) => invoice.id === params.invoiceId
);
return (
<InvoiceItemDescription
invoiceNumber={invoice.invoice_num}
status={invoice.status}
order_date={invoice.order_date}
bill_from={invoice.bill_from}
bill_from_address={invoice.bill_from_address}
bill_from_email={invoice.bill_from_email}
bill_from_fax={invoice.bill_from_fax}
bill_from_phone={invoice.bill_from_phone}
bill_to={invoice.bill_to}
bill_to_address={invoice.bill_to_address}
bill_to_email={invoice.bill_to_email}
bill_to_fax={invoice.bill_to_fax}
bill_to_phone={invoice.bill_to_phone}
item_name={invoice.ITEMS.item_name}
unit_costs={invoice.ITEMS.unit_costs}
unit={invoice.ITEMS.unit}
price={invoice.ITEMS.price}
/>
);
};
export default InvoiceItem;
InvoiceItemDescription.js file
import React from "react";
import Wrapper from "../../UI/Wrapper";
import Footer from "../../UI/Footer";
import classes from "./InvoiceItemDescription.module.css";
import { Link } from "react-router-dom";
const InvoiceItemDescription = (props) => {
let counter = 1;
return (
<Wrapper isShrinked={props.isShrinked}>
<div className={classes.wrapper}>
<div className={classes["content-wrapper"]}>
<div className={classes["main-wrapper"]}>
<div className={classes["upper-buttons"]}>
<div className={classes["upper-buttons-wrapper"]}>
<Link to="/invoices">
<button type="button" className={classes["go-to-invoices"]}>
Go To Invoices
</button>
</Link>
<Link to="/invoices/edit-invoice">
<button type="button" className={classes["edit-invoice"]}>
Edit Invoice
</button>
</Link>
</div>
</div>
<div className={classes.content}>
<div className={classes["invoice-info"]}>
<div className={classes.info}>
<h3>Invoice Info</h3>
<span>{props.invoiceNumber}</span>
</div>
<div className={classes.order}>
<p>
<span className={classes["order-status"]}>
Order Status:
</span>
<span className={classes.status}>{props.status}</span>
</p>
<p>
<span className={classes["order-date"]}>Order Date:</span>
<span className={classes.date}>{props.order_date}</span>
</p>
</div>
</div>
<div className={classes.bills}>
<div className={classes["bill-from"]}>
<h3>Bill From</h3>
<div>
<p className={classes["bill-from-info"]}>
<span className={classes.name}>{props.bill_from}</span>
<span className={classes.email}>
{props.bill_from_email}
<br></br>
<br></br> {props.bill_from_address}
<br></br>
<br></br>
<br></br> {props.bill_from_phone}
</span>
</p>
</div>
</div>
<div className={classes["bill-to"]}>
<h3>Bill To</h3>
<p className={classes["bill-to-info"]}>
<span className={classes.name}>{props.bill_to}</span>
<span className={classes.email}>
{props.bill_to_email} <br></br>
<br></br> {props.bill_to_address} <br></br>
<br></br>
<br></br>
{props.bill_to_fax} <br></br> {props.bill_to_phone}
</span>
</p>
</div>
</div>
<div className={classes.table}>
<table>
<colgroup>
<col className={classes.col1}></col>
<col className={classes.col2}></col>
<col className={classes.col3}></col>
<col className={classes.col4}></col>
<col className={classes.col5}></col>
</colgroup>
<thead>
<tr>
<td>#</td>
<td>Item Name</td>
<td>Unit Costs</td>
<td>Unit</td>
<td>Price</td>
</tr>
</thead>
<tbody>
<tr>
<td>{counter++}</td>
<td>{props.item_name}</td>
<td>{props.unit_costs}</td>
<td>{props.unit}</td>
<td>{props.price}</td>
</tr>
</tbody>
</table>
</div>
<div className={classes.total}>
<p>
Sub-total:
<span>$13300</span>
</p>
<p>
Vat:
<span>$13300</span>
</p>
<h3>
Grand Total:
<span>$14630</span>
</h3>
</div>
</div>
<div className={classes["lower-btn"]}>
<button type="button">Send Invoice</button>
</div>
</div>
</div>
</div>
<Footer />
</Wrapper>
);
};
export default InvoiceItemDescription;
And Invoice.js file
import React from "react";
import classes from "./Invoice.module.css";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
import { invoiceActions } from "../../store/invoice-slice";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faTrash } from "#fortawesome/free-solid-svg-icons";
const Invoice = (props) => {
const { id, invoice_num, bill_from, bill_to, status } = props.invoiceItem;
const dispatch = useDispatch();
const removeInvoiceItem = () => {
dispatch(invoiceActions.removeInvoice(id));
};
return (
<tr className={classes.height}>
<td>
<span className={classes.checkbox}>
<input type="checkbox"></input>
</span>
</td>
<td>
<span>{invoice_num}</span>
</td>
<td>
<span>{bill_from}</span>
</td>
<td>
<span>{bill_to}</span>
</td>
<td>
<span>14300</span>
{/* This should be a dynamic value later */}
</td>
<td>
<span
className={`${
status === "Pending" ? classes["status-pending"] : ""
} ${status === "Delivered" ? classes["status-delivered"] : ""} ${
status === "Shipped" ? classes["status-shipped"] : ""
}`}
>
{status}
</span>
</td>
<td>
<div className={classes.buttons}>
<Link to={`/invoices/invoice-description/${id}`}>
<button className={classes["view-btn"]}>View</button>
</Link>
<button className={classes["delete-btn"]} onClick={removeInvoiceItem}>
<FontAwesomeIcon icon={faTrash} />
</button>
</div>
</td>
</tr>
);
};
export default Invoice;
I have no idea what can cause the crash of the page. Can someone help me with this, please?
P.S. here is my github repo(it's my PET project) - https://github.com/stepan-slyvka/test-project
The issue is that in the INVOICES_LIST test invoice data exported from src/components/Pages/Invoice/InvoicesList.js you are creating randomly generated id properties. When the page reloads, the entire app reloads, INVOICES_LIST is exported with all new id properties. The id that is read from the URL path is no longer valid and InvoiceItem can't render an invoice object that is undefined.
export const INVOICES_LIST = [
{
id: Math.random().toString(), // <-- random each time app loads
...
},
{
id: Math.random().toString(), // <-- random each time app loads
...
},
{
id: Math.random().toString(), // <-- random each time app loads
...
},
];
You really want GUIDs to be stable, and more determinant and guaranteed for uniqueness, so don't use Math.random to create them, use something more like uuid if you need to generate unique ids.
To resolve your specific issue the fix is to just hardcode a unique id value. Even just complete gibberish, so long as it uniquely identifies an object, is sufficient (for testing).
Example:
export const INVOICES_LIST = [
{
id: '09u34otiuhnrfgp9ioj45',
...
},
{
id: '234098ujh43gikoljaerpgiojaerg',
...
},
{
id: '0934tpinr-9ujw3ensdsf',
...
},
];
In the InvoiceItem component that is searching the INVOICES_LIST array keep in mind that Array.prototype.find potentially returns undefined when no match is found. The UI should handle this. Conditionally render the InvoiceItemDescription only if there is a found invoice.
Example:
const InvoiceItem = () => {
const { invoiceId } = useParams();
const invoice = INVOICES_LIST.find((invoice) => invoice.id === invoiceId);
return invoice ? (
<InvoiceItemDescription
invoice_num={invoice.invoice_num}
status={invoice.status}
order_date={invoice.order_date}
bill_from={invoice.bill_from}
bill_from_address={invoice.bill_from_address}
bill_from_email={invoice.bill_from_email}
bill_from_fax={invoice.bill_from_fax}
bill_from_phone={invoice.bill_from_phone}
bill_to={invoice.bill_to}
bill_to_address={invoice.bill_to_address}
bill_to_email={invoice.bill_to_email}
bill_to_fax={invoice.bill_to_fax}
bill_to_phone={invoice.bill_to_phone}
item_name={invoice.ITEMS.item_name}
unit_costs={invoice.ITEMS.unit_costs}
unit={invoice.ITEMS.unit}
price={invoice.ITEMS.price}
/>
) : (
<div>No Invoices Found.</div>
);
};
So, issue is fixed and to conclude, maybe someone is facing the same problem, I'll write a few words.
Firstly, when you have static data like I had(3 invoices which renders each time page loads) - hardcode your id's.
Secondly, for newly created items use stable id's(example - uuid) and store it somewhere(for example in local storage).
Thirdly, if page crashes or something renders wrong - check your state! In my case issue was in InvoiceItem.js file where i was trying to render INVOICES_LIST instead of selecting my state with const invoices = useSelector((state) => state.invoice.invoices)
Hope, this helps someone like me - novice in redux :)
P.S. final code is here

How to retrieve only one record from a list in props? (Reactjs)

My problem is the following:
I have a list with map that searches the DB and shows in a table.
The user has the option to click to check the details of the record.
A modal opens and shows these details.
But, in the modal, it search brings the list of all records instead of being only the one chosen by the user.
I already tried to use stopPropagation inside my button function but, even so it continues.
useState modal
const [isModalTraineeDetailsVisible, setModalTraineeDetailsVisible] = useState(false);
Function to select the person's id in the table
const traineeSelectById = (e, listTrainee) => {
e.stopPropagation();
setModalTraineeDetailsVisible(true);
Table showing the map and button with their functions
// Creating a map with date from listTraineeData, commes to the API BDD
listTraineeData.map((listTrainee) => (
<StyledTableRow key={listTrainee.id}>
<StyledTableCell>{listTrainee.first_name}</StyledTableCell>
<StyledTableCell>{listTrainee.last_name}</StyledTableCell>
<StyledTableCell>{listTrainee.num_soci}</StyledTableCell>
<StyledTableCell>{listTrainee.addresse1}</StyledTableCell>
<StyledTableCell>{listTrainee.active}</StyledTableCell>
<StyledTableCell>
<Button
variant="contained"
size="small"
onClick={(e) =>
traineeSelectById(listTrainee)
}
>
{" "}
Details modal
</Button>
{isModalTraineeDetailsVisible ? (
<ModalTraineeDetails
data={listTrainee}
onClose={() => setModalTraineeDetailsVisible(false)}
>
<h2>Modal Details Trainee</h2>
</ModalTraineeDetails>
) : null}
Because you map all items on isModalTraineeDetailsVisible, so if it false, will hide all items, and if it is true it will show all items, You should use an array instead and map with the index.
Also, You don't need to use e.stopPropagation
I investigate your problem.
Definitely, the example is not the best.
Try something like this
import { render } from 'react-dom'
import { useState } from 'react'
function App() {
const [selectedTrainee, setSelectedTrainee] = useState()
const trainees = [
{
id: '1',
first_name: 'Chris',
last_name: 'Ch'
},
{
id: '2',
first_name: 'Paul',
last_name: 'Pa'
}
]
return (
<div>
<table>
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th>Details</th>
</tr>
</thead>
<tbody>
{trainees.map(trainee => {
return (
<tr key={trainee.id}>
<td>{trainee.first_name}</td>
<td>{trainee.last_name}</td>
<td>
<button onClick={() => setSelectedTrainee(trainee)}>+</button>
</td>
</tr>
)
})}
</tbody>
</table>
{selectedTrainee && (
<Modal
trainee={selectedTrainee}
onClose={() => setSelectedTrainee(undefined)}
>
<h2>Modal Details Trainee</h2>
</Modal>
)}
</div>
)
}
function Modal(props) {
return (
<div>
{props.children}
<pre>{JSON.stringify(props.trainee)}</pre>
<button
onClick={props.onClose}
>
Close
</button>
</div>
)
}
render(<App />, document.getElementById('root'))
PS. You should be more careful about naming.
What I did here?
Firstly, I restructured your state.
You only need information about selectedTrainee.
Once you save the single trainee you can open the modal pretty easly.

Cannot update a component (`App`) while rendering a different component (`UserTable`)

I'm trying to learn React Hooks in functional components, and am following along with React Hooks tutorial but am getting the error: Cannot update a component (App) while rendering a different component (UserTable), and the error stack indicates this is related to the onClick={props.deleteUser(user.id)} property in the delete button in UserTable.js. I saw several posts indicating that one should try useEffect() to get around this issue, so I tried having deleteUser update a state variable, and then have useEffects change the users array. While the code compiled fine, the page simply hung and eventually timed out with an "out of memory" error (I assume caused by an endless cycle of trying to render and re-render?). Any ideas how to fix this situation?
App.js
import React, { useState } from 'react';
import UserTable from './tables/UserTable';
import AddUserForm from './forms/AddUserForm';
const App= () => {
const usersData = [
{id: 1, name: "Tania", username: "floppydiskette"},
{id: 2, name: "Craig", username: "siliconeidolon" },
{id: 3, name: "Ben", username: "benisphere"}
]
const [users, setUsers] = useState(usersData);
const addUser = (user) => {
user.id = users.length+1;
setUsers([...users,user])
}
const deleteUser = (id) => {
setUsers(users.filter((user)=>user.id !== id))
}
return (
<div className="container">
<h1> SIMPLE CRUD APP WITH HOOKS</h1>
<div className="flex-row">
<div className = "flex-large">
<h2> Add User </h2>
<AddUserForm addUser={addUser}/>
</div>
<div className = "flex-large">
<h2>View Users</h2>
<UserTable users={users} deleteUser={deleteUser}/>
</div>
</div>
</div>
);
}
export default App;
UserTable.js
import React from 'react';
const UserTable = (props) => {
return(
<table>
<thead>
<tr>
<th>Name</th>
<th>UserName</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{props.users.length > 0 ? (
props.users.map((user) => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.username}</td>
<td>
<button className="button muted-button">Edit</button>
>>> This triggers the `cannot update a component . . .` error:
<button className="button muted-button" onClick={props.deleteUser(user.id)}>Delete</button>
</td>
</tr>
))
) : (
<tr colspan={3}>No Users</tr>
)}
</tbody>
</table>
);
}
export default UserTable
You just have to change
onClick={props.deleteUser(user.id)}>Delete</button>
to
onClick={()=> props.deleteUser(user.id)}>Delete</button>
Otherwise your delete function will get automaticaly fired on render itself

Index Item of array not getting deleted

I've just noticed a problem with my UI where clicking the delete button at a particular index doesn't delete that particular record and instead ends up deleting data situated at a different index. I'm quite clueless as to why this is happening. The list seems to render properly in order but then it all goes south when I try deleting it. My first deduction of this issue for a split second was that this had something to do with the API that I'm fetching the data from but then I realized that the data was getting rendered as it should and as it was defined. I would like to know what I can do to ensure that I'm deleting the data that I've clicked and not anything else. Here is my code:
import { useEffect, useState } from "react";
const Task = () => {
const [todos, setTodos] = useState([]);
useEffect(() => {
fetch('http://jsonplaceholder.typicode.com/todos')
.then(res => res.json())
.then(data => {
setTodos(data)
})
}, []);
const deleteTodo = (index) => {
const temp = [...todos];
temp.splice(index, 1);
setTodos(temp);
console.log(index);
// console.log(`newData : ${arr} || newLength : ${arr.length}`);
console.log(`newLength : ${todos.length}`);
}
return (
<div className='container'>
<table className='table'>
<tbody>
{todos.map((key, value) => (
<tr key={key.id}>
<td>{todos[value].id}</td>
<td>{todos[value].title}</td>
<td>{`${todos[value].completed}`}</td>
<td>
<button className='btn btn-danger ' onClick={() => deleteTodo(key.id)}> Delete </button>
</td>
</tr>
))}
</tbody>
</table>
<button className='btn btn-primary'>Add Task</button>
</div>
);
}
export default Task;
You are passing key.id to deleteTodo and then delete the item in the todo with index of key.id and it may not as the same as the index of the item, you should pass the index of item to the deleteTodo
like this :
{todos.map((todoItem, todoIndex) => (
<tr key={todoItem.id}>
<td>{todoItem.id}</td>
<td>{todoItem.title}</td>
<td>{`${todoItem.completed}`}</td>
<td>
<button className='btn btn-danger ' onClick={() => deleteTodo(todoIndex)}> Delete </button>
</td>
</tr>
))}
Mehtod .splice() needs index of element as start index, but you are sending an id. So, if id is 1 you will remove element on position 1, what is other element.
You can do .findIndex of element by id inside your delete function.
There is working example Example

Resources