package recruiting import ( "net/http" "github.com/go-chi/chi/v5" "github.com/google/uuid" "github.com/shopspring/decimal" ) func (h *Handler) listGoals(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() out, err := h.svc.ListGoals(r.Context(), q.Get("team_id"), q.Get("owner")) if err != nil { h.fail(w, err) return } writeJSON(w, http.StatusOK, map[string]any{"goals": out, "count": len(out)}) } func (h *Handler) setGoal(w http.ResponseWriter, r *http.Request) { var in struct { Scope string `json:"scope"` SubjectID string `json:"subject_id"` Metric string `json:"metric"` PeriodStart string `json:"period_start"` PeriodDays int `json:"period_days"` Target decimal.Decimal `json:"target"` Note string `json:"note"` } if err := decode(w, r, &in); err != nil { writeErr(w, http.StatusBadRequest, "invalid body", "") return } if in.PeriodDays == 0 { // The manager view's own default window, so a goal set without thinking about length lines up with // the figure it will be judged against rather than silently spanning a different period. in.PeriodDays = 30 } out, err := h.svc.SetGoal(r.Context(), in.Scope, in.SubjectID, in.Metric, in.PeriodStart, in.PeriodDays, in.Target, in.Note) if err != nil { h.fail(w, err) return } writeJSON(w, http.StatusOK, out) } func (h *Handler) deleteGoal(w http.ResponseWriter, r *http.Request) { id, err := uuid.Parse(chi.URLParam(r, "goalID")) if err != nil { writeErr(w, http.StatusBadRequest, "invalid goal id", "") return } if err := h.svc.DeleteGoal(r.Context(), id); err != nil { h.fail(w, err) return } w.WriteHeader(http.StatusNoContent) } // forecast returns the weighted pipeline for a scope. func (h *Handler) forecast(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() out, err := h.svc.Pipeline(r.Context(), q.Get("team_id"), q.Get("owner")) if err != nil { h.fail(w, err) return } writeJSON(w, http.StatusOK, out) }