package http import ( "net/http" "net/url" "strconv" "strings" "time" "primaya-api/cpone-middleware/internal/repository" ) type PaketValidationResponse struct { Success bool `json:"success"` Status string `json:"status"` Message string `json:"message"` Data any `json:"data"` } type PaketPaginationResponse struct { CurrentPage int `json:"current_page"` Data []repository.PaketSummary `json:"data"` FirstPageURL string `json:"first_page_url"` From *int `json:"from"` LastPage int `json:"last_page"` LastPageURL string `json:"last_page_url"` Links map[string]any `json:"links"` NextPageURL *string `json:"next_page_url"` Total int `json:"total"` PerPage int `json:"per_page"` } func (h Handler) ListPaket(w http.ResponseWriter, r *http.Request) { params, message := parsePaketListParams(r) if message != "" { writePaketValidationError(w, message) return } page, err := h.paketRepository(r.Context()).ListPaket(r.Context(), params) if err != nil { WriteJSON(w, http.StatusInternalServerError, Response{ Success: false, Message: "internal server error", Data: nil, }) return } lastPage := (page.Total + params.PerPage - 1) / params.PerPage if lastPage < 1 { lastPage = 1 } var from *int if len(page.Items) > 0 { value := (params.Page-1)*params.PerPage + 1 from = &value } var nextPageURL *string if params.Page < lastPage { value := currentRequestURL(r, params.Page+1) nextPageURL = &value } WriteJSON(w, http.StatusOK, PaketPaginationResponse{ CurrentPage: params.Page, Data: page.Items, FirstPageURL: "", From: from, LastPage: lastPage, LastPageURL: "", Links: map[string]any{}, NextPageURL: nextPageURL, Total: page.Total, PerPage: params.PerPage, }) } func (h Handler) GetPaket(w http.ResponseWriter, r *http.Request) { id := strings.TrimSpace(r.PathValue("id")) paket, err := h.paketRepository(r.Context()).GetPaket(r.Context(), id) if err != nil { WriteJSON(w, http.StatusInternalServerError, Response{ Success: false, Message: "internal server error", Data: nil, }) return } if paket == nil { WriteJSON(w, http.StatusNotFound, Response{ Success: false, Message: "Data tidak ditemukan", Data: nil, }) return } WriteJSON(w, http.StatusOK, Response{Success: true, Message: "ok", Data: paket}) } func parsePaketListParams(r *http.Request) (repository.PaketListParams, string) { query := r.URL.Query() params := repository.PaketListParams{ Search: query.Get("search"), Code: query.Get("code"), CareType: query.Get("care_type"), Active: query.Get("active"), StartDate: query.Get("start_date"), EndDate: query.Get("end_date"), Status: 2, Page: 1, PerPage: 15, } if params.CareType != "" && params.CareType != "RI" && params.CareType != "RJ" { return params, "The selected care type is invalid." } if raw, exists := firstQueryValue(r, "status"); exists && raw != "" { value, err := strconv.Atoi(raw) if err != nil { return params, "The status must be an integer." } if value < -1 || value > 2 { return params, "The selected status is invalid." } params.Status = value } if params.Active != "" && params.Active != "N" && params.Active != "Y" { return params, "The selected active is invalid." } if params.StartDate != "" { if _, err := time.Parse("2006-01-02", params.StartDate); err != nil { return params, "The start date does not match the format Y-m-d." } } if params.EndDate != "" { end, err := time.Parse("2006-01-02", params.EndDate) if err != nil { return params, "The end date does not match the format Y-m-d." } if params.StartDate != "" { start, _ := time.Parse("2006-01-02", params.StartDate) if end.Before(start) { return params, "The end date must be a date after or equal to start date." } } } if raw, exists := firstQueryValue(r, "page"); exists && raw != "" { value, err := strconv.Atoi(raw) if err != nil { return params, "The page must be an integer." } if value < 1 { return params, "The page must be at least 1." } params.Page = value } if raw, exists := firstQueryValue(r, "per_page"); exists && raw != "" { value, err := strconv.Atoi(raw) if err != nil { return params, "The per page must be an integer." } if value < 1 || value > 100 { return params, "The per page must be between 1 and 100." } params.PerPage = value } return params, "" } func currentRequestURL(r *http.Request, page int) string { scheme := "http" if r.TLS != nil { scheme = "https" } if forwarded := r.Header.Get("X-Forwarded-Proto"); forwarded != "" { scheme = strings.TrimSpace(strings.Split(forwarded, ",")[0]) } host := r.Host if host == "" { host = "localhost" } query := url.Values{} if code := r.URL.Query().Get("kode_rs"); code != "" { query.Set("kode_rs", code) } query.Set("page", strconv.Itoa(page)) return (&url.URL{Scheme: scheme, Host: host, Path: r.URL.Path, RawQuery: query.Encode()}).String() } func writePaketValidationError(w http.ResponseWriter, message string) { WriteJSON(w, http.StatusUnprocessableEntity, PaketValidationResponse{ Success: false, Status: "validation_error", Message: message, Data: nil, }) }