Basically code is for an electron app with a react frontend and an express server connected to a local postgresql db.
I have a page with a list of employees on one side and an add icon. If you click on the add icon, on the other side the create employee form is shown. If you click on one of the employees, the employee details are shown in the same form and the employee can be updated or deleted. Until here it works fine, but the issue comes up when I delete/update an employee and then click to add an employee. All of sudden I can't type in any of the input forms. Strangely enough (for me at least), minimising and reopening the window solves the issue, even clicking inside the devtools solves the issue. I tried autofocus and still doesn't work.
This is the Employee Page:
const EmployeePage = () => {
const [employees, setEmployees] = useState([])
const [selectedEmployee, setSelectedEmployee] = useState(null)
const [createEmployee, setCreateEmployee] = useState(false)
const getEmployees = () => {
window.electron.getEmployees().then((data) => {
setEmployees(data)
})
}
const handleClose = () => {
setSelectedEmployee(null)
setCreateEmployee(false)
}
useEffect(() => {
getEmployees()
}, [])
const handleEmployee = (id) => {
setCreateEmployee(false)
setSelectedEmployee(employees.filter((employee) => employee.id == id)[0])
}
const handleCreateEmployee = () => {
setSelectedEmployee(null)
setCreateEmployee(true)
}
return (
<div className="p-8 max-w-3xl mx-auto">
<div className="flex">
<EmployeeList employees={employees} handleEmployee={handleEmployee} />
{selectedEmployee && (
<EmployeeDetails
employee={selectedEmployee}
action={handleClose}
getEmployees={getEmployees}
/>
)}
{createEmployee && (
<CreateEmployee getEmployees={getEmployees} action={handleClose} />
)}
</div>
<button
onClick={handleCreateEmployee}
className="flex items-center mb-6 bg-green-500 text-white rounded-full px-4 py-3 shadow group overflow-hidden transition-all duration-300 hover:scale-110 mt-10 mx-auto"
>
<Plus className="w-5 h-5 flex-shrink-0" />
</button>
</div>
)
}
This is the Employee List component:
const EmployeeList = ({ employees, handleEmployee }) => {
const [filter, setFilter] = useState("active")
const filteredEmployees = employees.filter((employee) => {
if (filter === "active") return employee.active
if (filter === "inactive") return !employee.active
if (filter === "all") return true
return true
})
return (
<div>
<h2 className="text-3xl font-semibold mb-6">Employee List</h2>
<div className="mb-4">
<label className="mr-2 font-medium">Filter:</label>
<select
value={filter}
onChange={(e) => setFilter(e.target.value)}
className="border rounded p-2"
>
<option value="all">All</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</div>
{filteredEmployees.length > 0 ? (
<div className="space-y-4">
{filteredEmployees.map((employee) => (
<div
key={employee.id}
className="p-4 rounded-lg shadow hover:bg-gray-50 cursor-pointer transition"
onClick={() => handleEmployee(employee.id)}
>
<h3 className="text-xl font-medium">
{employee.employee_id}. {employee.name}
</h3>
</div>
))}
</div>
) : (
<h1>No Employees</h1>
)}
</div>
)
}
This is the Employee Details Component:
const EmployeeDetails = ({ employee, action, getEmployees }) => {
const [detailsForm, setDetailsForm] = useState({
id: "",
employeeId: "",
name: "",
active: "",
})
const [message, setMessage] = useState("")
const updateEmployee = () => {
setDetailsForm({
id: employee.id,
employeeId: employee.employee_id,
name: employee.name,
active: employee.active,
})
}
const handleChange = (e) => {
const { name, value } = e.target
if (name == "active") {
setDetailsForm((prev) => ({ ...prev, [name]: e.target.checked }))
} else {
setDetailsForm((prev) => ({ ...prev, [name]: value }))
}
}
const handleSubmit = async (e) => {
e.preventDefault()
setMessage("")
if (!detailsForm.name || !detailsForm.employeeId) {
setMessage("? Employee Name and ID are required.")
return
}
try {
const response = await window.electron.updateEmployee(form)
if (response.code == 401) {
console.log(response)
setMessage(`? Failed to update. ${response.message}`)
toast.error("Error updating employee")
}
if (response.code == 200) {
toast.success("Employee updated successfully")
setMessage("? Update successful")
getEmployees()
}
} catch (err) {
setMessage("? Failed to update.")
console.error(err)
}
}
const handleDelete = async (e) => {
e.preventDefault()
setMessage("")
const confirmed = window.confirm(
"Are you sure you want to delete this employee?"
)
if (confirmed) {
try {
const response = await window.electron.deleteEmployee(detailsForm.id)
if (response.code == 401) {
setMessage(`? Failed to delete. ${response.message}`)
toast.error("Error deleting employee")
}
if (response.code == 200) {
toast.success("Employee deleted successfully")
getEmployees()
action()
}
} catch (err) {
setMessage("? Failed to delete.")
}
}
}
useEffect(() => {
updateEmployee()
}, [employee])
return (
<EmployeeForm
handleChange={handleChange}
handleSubmit={handleSubmit}
handleDelete={handleDelete}
form={detailsForm}
submitText="Update"
backAction={action}
message={message}
/>
)
}
This is the CreateEmployee component
const CreateEmployee = ({ getEmployees, action }) => {
const [createForm, setCreateForm] = useState({
employeeId: "",
name: "",
active: true,
})
const [message, setMessage] = useState("")
const handleChange = (e) => {
const { name, value } = e.target
if (name == "active") {
setCreateForm((prev) => ({ ...prev, [name]: e.target.checked }))
} else {
setCreateForm((prev) => ({ ...prev, [name]: value }))
}
}
const handleSubmit = async (e) => {
e.preventDefault()
setMessage("")
if (!createForm.name || !createForm.employeeId) {
setMessage("? Employee Name and ID are required.")
return
}
try {
const response = await window.electron.createEmployee(createForm)
if (response.code == 401) {
setMessage(`? Failed to submit. ${response.message}`)
toast.error("Error adding employee")
}
if (response.code == 201) {
toast.success("Employee added successfully")
setCreateForm({
employeeId: "",
name: "",
active: true,
})
getEmployees()
}
} catch (err) {
setMessage("? Failed to submit.")
console.error(err)
}
}
return (
<EmployeeForm
handleChange={handleChange}
handleSubmit={handleSubmit}
form={createForm}
submitText="Submit"
backAction={action}
message={message}
/>
)
}
And finally this is the Form component:
const EmployeeForm = ({
handleChange,
handleSubmit,
handleDelete,
form,
submitText,
backAction,
message,
}) => {
return (
<div className="relative max-w-md mx-auto">
<div
className="absolute top-2 right-2 cursor-pointer"
onClick={backAction}
>
<X />
</div>
<form className="mt-8">
<div className="relative z-0 w-full mb-5 group">
<input
type="text"
name="name"
placeholder=""
required
onChange={handleChange}
value={form.name}
/>
<label htmlFor="name">
Employee Name
</label>
</div>
<div className="grid md:grid-cols-2 md:gap-6">
<div className="relative z-0 w-full mb-5 group">
<input
type="number"
min="0"
name="employeeId"
placeholder=""
required
onChange={handleChange}
value={form.employeeId}
/>
<label htmlFor="employee">
Employee Id
</label>
</div>
<div className="flex items-center space-x-2">
<input
type="checkbox"
name="active"
onChange={handleChange}
checked={form.active}
/>
<label className="text-sm text-gray-700">Employee Active</label>
</div>
</div>
<SubmitButton msg={submitText} action={handleSubmit} />
{handleDelete && <DeleteButton action={handleDelete} />}
{message && <p>{message}</p>}
</form>
</div>
)
}
Apologies for the very long post, but thought providing the actual code should be helpful. Solutions are greatly appreciated, been stuck on this for too long.