package handler import ( "errors" "net/http" "github.com/go-chi/chi/v5" "github.com/wotra/wotra/internal/service" ) // WeekHandler serves /api/weeks routes. type WeekHandler struct { svc *service.WeekService } func NewWeekHandler(svc *service.WeekService) *WeekHandler { return &WeekHandler{svc: svc} } func (h *WeekHandler) Routes(r chi.Router) { r.Get("/weeks", h.List) r.Post("/weeks/{week_key}/close", h.Close) r.Delete("/weeks/{week_key}/close", h.Reopen) } // List GET /api/weeks?from=YYYY-Www&to=YYYY-Www func (h *WeekHandler) List(w http.ResponseWriter, r *http.Request) { from := r.URL.Query().Get("from") to := r.URL.Query().Get("to") if from == "" { from = "0000-W01" } if to == "" { to = "9999-W53" } weeks, err := h.svc.ListWeeks(r.Context(), from, to) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } if weeks == nil { writeJSON(w, http.StatusOK, []struct{}{}) return } writeJSON(w, http.StatusOK, weeks) } // Close POST /api/weeks/{week_key}/close func (h *WeekHandler) Close(w http.ResponseWriter, r *http.Request) { weekKey := chi.URLParam(r, "week_key") cw, err := h.svc.CloseWeek(r.Context(), weekKey) if err != nil { switch { case errors.Is(err, service.ErrWeekAlreadyClosed): writeError(w, http.StatusConflict, err.Error()) case errors.Is(err, service.ErrWeekHasUnclosedDays): writeError(w, http.StatusUnprocessableEntity, err.Error()) case errors.Is(err, service.ErrNoSettings): writeError(w, http.StatusUnprocessableEntity, err.Error()) default: writeError(w, http.StatusInternalServerError, err.Error()) } return } writeJSON(w, http.StatusOK, cw) } // Reopen DELETE /api/weeks/{week_key}/close func (h *WeekHandler) Reopen(w http.ResponseWriter, r *http.Request) { weekKey := chi.URLParam(r, "week_key") if err := h.svc.ReopenWeek(r.Context(), weekKey); err != nil { switch { case errors.Is(err, service.ErrWeekNotClosed): writeError(w, http.StatusNotFound, err.Error()) default: writeError(w, http.StatusInternalServerError, err.Error()) } return } w.WriteHeader(http.StatusNoContent) }