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 [companies, setCompanies]=useState([]);
   const [form, setForm]=useState({
    companyId:"", 
    role:"", appliedDate:"",
    jobUrl:"",
    status:"INTERESTED",
    location:"",
    source:"",
    salaryExpectation:"",
    notes:""
   });
   const [error, setError]=useState(null);

   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="mb-3">
          <label className="form-label">Company<br />
            <select required value={form.companyId} 
            onChange={e => setForm({...form, companyId: e.target.value})}
            className="form-select">
              <option value="">Select company</option>
              {companies.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
            </select>
          </label>
        </div>

        <div className="mb-3">
          <label className="form-label">Role<br />
            <input required value={form.role} 
            onChange={e => setForm({...form, role: e.target.value})}
            className="form-control" />
          </label>
        </div>

        <div className="mb-3">
          <label className="form-label">Applied date<br />
            <input type="date" value={form.appliedDate} 
            onChange={e => setForm({...form, appliedDate: e.target.value})} 
            className="form-control"/>
          </label>
        </div>

        <div className="mb-3">
          <label className="form-label">Job URL<br />
            <input value={form.jobUrl} 
            onChange={e => setForm({...form, jobUrl: e.target.value})}
            className="form-control" />
          </label>
        </div>

        <div className="mb-3">
          <label className="form-label">Status<br />
            <select value={form.status} onChange={e => setForm({...form, status: e.target.value})} className="form-select">
              {STATUSES.map(s => <option key={s} value={s}>{s}</option>)}
            </select>
          </label>
        </div>

        <div className="mb-3">
          <label className="form-label">Location<br />
            <input value={form.location} onChange={e => setForm({...form, location: e.target.value})} 
            className="form-control"/>
          </label>
        </div>

        <div className="mb-3">
          <label className="form-label">Source<br />
            <input value={form.source} 
            onChange={e => setForm({...form, source: e.target.value})}
            className="form-control" />
          </label>
        </div>

        <div className="mb-3">
          <label className="form-label">Salary expectation<br />
            <input value={form.salaryExpectation} 
            onChange={e => setForm({...form, salaryExpectation: e.target.value})} 
            className="form-control"/>
          </label>
        </div>

        <div className="mb-3">
          <label className="form-label">Notes<br />
            <textarea value={form.notes} 
            onChange={e => setForm({...form, notes: e.target.value})} 
            className="form-control"
            rows={4}/>
          </label>
        </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>
  );
}