0

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.

2
  • " 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.".In my experience, this is most likely due to a user state change not triggering a component re-render. Check for any useEffect hooks that might be missing dependencies. Commented Aug 1 at 4:48
  • Try passing employee state to function ``` useEffect(() => { updateEmployee(employee) }, [employee]) ``` Commented Aug 1 at 4:51

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.