Newer
Older
job-tracker / frontend / src / components / JobForm.js
import React, { useEffect, useState } from "react";
import { useParams, useNavigate } from "react-router-dom";
import { apiGet, apiPost, apiPut } from "../api";

const STATUSES = ["INTERESTED", "APPLIED", "PHONE_SCREEN", "TECH_INTERVIEW", "OFFER", "REJECTED", "WITHDRAWN"];

export default function JobForm() {
  const { id } = useParams();
  const navigate = useNavigate();
  const isEdit = Boolean(id);
  const today = new Date().toISOString().split("T")[0];

  const [companies, setCompanies] = useState([]);
  const [form, setForm] = useState({
    companyId: "",
    role: "",
    appliedDate: today,
    jobUrl: "",
    status: "INTERESTED",
    location: "",
    source: "",
    salaryExpectation: "",
    notes: ""
  });
  const [error, setError] = useState(null);

  const handleChange = (field) => (e) => setForm({ ...form, [field]: e.target.value });

  useEffect(() => {
    // Fetch companies for the dropdown
    apiGet('/api/companies')
      .then(setCompanies)
      .catch(error => setError(error.message));

    if (isEdit) {
      apiGet(`/api/jobs/${id}`)
        .then(data => {
          setForm({
            companyId: data.company?.id || "",
            role: data.role || "",
            appliedDate: data.appliedDate || "",
            jobUrl: data.jobUrl || "",
            status: data.status || "APPLIED",
            location: data.location || "",
            source: data.source || "",
            salaryExpectation: data.salaryExpectation || "",
            notes: data.notes || ""
          });
        })
        .catch(err => setError(err.message));
    }
  }, [id, isEdit]);

  async function onSubmit(e) {
    e.preventDefault();
    setError(null);

    // Backend expects payload to include company object (id) or companyId depending on implementation.
    // Here we send company as { id: companyId } because our sample backend used that previously.
    const payload = {
      role: form.role,
      appliedDate: form.appliedDate || null,
      jobUrl: form.jobUrl || null,
      status: form.status,
      location: form.location || null,
      source: form.source || null,
      salaryExpectation: form.salaryExpectation || null,
      notes: form.notes || null,
      company: { id: form.companyId }
    };

    try {
      if (isEdit) {
        await apiPut(`/api/jobs/${id}`, payload);
      } else {
        await apiPost("/api/jobs", payload);
      }
      navigate("/");
    } catch (err) {
      setError(err.message);
    }
  }

  return (
    <div className="container mt-4">
      <h2>{isEdit ? "Edit job" : "New job"}</h2>
      {error && <div className="alert alert-danger">{error}</div>}
      <form onSubmit={onSubmit} className="mt-3">
        <div className="row">
          {/* Left column */}
          <div className="col-md-6">
            <div className="mb-3">
              <label className="form-label">Company</label>
              <select
                required
                value={form.companyId}
                onChange={handleChange('companyId')}
                className="form-select"
              >
                <option value="">Select company</option>
                {companies.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
              </select>
            </div>

            <div className="mb-3">
              <label className="form-label">Role</label>
              <input
                required
                value={form.role}
                onChange={handleChange('role')}
                className="form-control"
              />
            </div>

            <div className="mb-3">
              <label className="form-label">Applied date</label>
              <input
                type="date"
                value={form.appliedDate}
                onChange={handleChange('appliedDate')}
                className="form-control"
              />
            </div>

            <div className="mb-3">
              <label className="form-label">Job URL</label>
              <input
                value={form.jobUrl}
                onChange={handleChange('jobUrl')}
                className="form-control"
              />
            </div>

            <div className="mb-3">
              <label className="form-label">Status</label>
              <select
                value={form.status}
                onChange={handleChange('status')}
                className="form-select"
              >
                {STATUSES.map(s => <option key={s} value={s}>{s}</option>)}
              </select>
            </div>
          </div>

          {/* Right column */}
          <div className="col-md-6">
            <div className="mb-3">
              <label className="form-label">Location</label>
              <input
                value={form.location}
                onChange={handleChange('location')}
                className="form-control"
              />
            </div>

            <div className="mb-3">
              <label className="form-label">Source</label>
              <input
                value={form.source}
                onChange={handleChange('source')}
                className="form-control"
              />
            </div>

            <div className="mb-3">
              <label className="form-label">Salary expectation (per annum, €)</label>
              <input
                type="number"
                value={form.salaryExpectation}
                onChange={handleChange('salaryExpectation')}
                className="form-control"
              />
            </div>

            <div className="mb-3">
              <label className="form-label">Notes</label>
              <textarea
                value={form.notes}
                onChange={handleChange('notes')}
                className="form-control"
                rows={5}
              />
            </div>
          </div>
        </div>

        <div className="d-flex gap-2">
          <button type="submit" className="btn btn-success">Save</button>
          <button type="button" onClick={() => navigate(-1)} className="btn btn-secondary">Cancel</button>
        </div>
      </form>
    </div>
  );
}