diff --git a/backend/src/server/errors.go b/backend/src/server/errors.go index 4e32d0ae..64162e11 100644 --- a/backend/src/server/errors.go +++ b/backend/src/server/errors.go @@ -3,9 +3,10 @@ package server import "errors" var ( - ErrInternalServerError = errors.New("internal server error") - ErrWrongStepType = errors.New("wrong step type") - ErrJsonParseError = errors.New("unable to parse json request body") + ErrInternalServerError = errors.New("internal server error") + ErrWrongStepType = errors.New("wrong step type") + ErrJsonParseError = errors.New("unable to parse json request body") + ErrPaginationParamsError = errors.New("invalid pagination parameters") ErrPipelineCreateFail = errors.New("failed to create pipeline") ErrInvalidPipelineId = errors.New("invalid pipeline id") diff --git a/backend/src/server/handlers.go b/backend/src/server/handlers.go index 91414161..15e2ce2b 100644 --- a/backend/src/server/handlers.go +++ b/backend/src/server/handlers.go @@ -597,11 +597,27 @@ func handleGetServiceRequestsByUserAndOrganization(logger logger.ServerLogger, c } queryFilters.Statuses = strings.Split(statusFilters, ",") } - - logger.Info(fmt.Sprintf("querying for service requests: user_id=%s org_id=%d, query_filters=%v", userId, orgId, queryFilters)) + logger.Info(fmt.Sprintf("query: %v", r.URL.Query())) + pageParam, err := extractQueryParam[int](r.URL.Query(), "page", false, 1, integerConverter) + if err != nil { + logger.Error(fmt.Sprintf("unable to extract page from query params: %s", err)) + encode(w, r, http.StatusBadRequest, newHandlerError(ErrPaginationParamsError, http.StatusBadRequest)) + return + } + pageSizeParam, err := extractQueryParam[int](r.URL.Query(), "page_size", false, 10, integerConverter) + if err != nil { + logger.Error(fmt.Sprintf("unable to extract page_size from query params: %s", err)) + encode(w, r, http.StatusBadRequest, newHandlerError(ErrPaginationParamsError, http.StatusBadRequest)) + return + } + if pageParam < 1 || pageSizeParam < 1 { + logger.Error(fmt.Sprintf("invalid page or page_size: page=%d, page_size=%d", pageParam, pageSizeParam)) + encode(w, r, http.StatusBadRequest, newHandlerError(ErrPaginationParamsError, http.StatusBadRequest)) + return + } + logger.Info(fmt.Sprintf("querying for service requests: org_id=%d, query_filters=%v, page=%d, page_size=%d", orgId, queryFilters, pageParam, pageSizeParam)) result, err := database.NewServiceRequest(client).GetAllServiceRequestByOrg(orgId, queryFilters, database.Pagination{ - Page: 1, // TODO: implement pagination from query params - PageSize: 10, + Page: pageParam, PageSize: pageSizeParam, }) if err != nil { logger.Error(fmt.Sprintf("error encountered while handling API request: %s", err)) @@ -648,10 +664,26 @@ func handleGetServiceRequestsForAdminByOrganization(logger logger.ServerLogger, queryFilters.Statuses = strings.Split(statusFilters, ",") } - logger.Info(fmt.Sprintf("querying for service requests: org_id=%d, query_filters=%v", orgId, queryFilters)) + pageParam, err := extractQueryParam[int](r.URL.Query(), "page", false, 1, integerConverter) + if err != nil { + logger.Error(fmt.Sprintf("unable to extract page from query params: %s", err)) + encode(w, r, http.StatusBadRequest, newHandlerError(ErrPaginationParamsError, http.StatusBadRequest)) + return + } + pageSizeParam, err := extractQueryParam[int](r.URL.Query(), "page_size", false, 10, integerConverter) + if err != nil { + logger.Error(fmt.Sprintf("unable to extract page_size from query params: %s", err)) + encode(w, r, http.StatusBadRequest, newHandlerError(ErrPaginationParamsError, http.StatusBadRequest)) + return + } + if pageParam < 1 || pageSizeParam < 1 { + logger.Error(fmt.Sprintf("invalid page or page_size: page=%d, page_size=%d", pageParam, pageSizeParam)) + encode(w, r, http.StatusBadRequest, newHandlerError(ErrPaginationParamsError, http.StatusBadRequest)) + return + } + logger.Info(fmt.Sprintf("querying for service requests: org_id=%d, query_filters=%v, page=%d, page_size=%d", orgId, queryFilters, pageParam, pageSizeParam)) result, err := database.NewServiceRequest(client).GetAllServiceRequestByOrg(orgId, queryFilters, database.Pagination{ - Page: 1, // TODO: implement pagination from query params - PageSize: 10, + Page: pageParam, PageSize: pageSizeParam, }) if err != nil { logger.Error(fmt.Sprintf("error encountered while handling API request: %s", err)) diff --git a/flowforge_api_bruno/service_request/all service requests.bru b/flowforge_api_bruno/service_request/all service requests.bru index 2e1d7d7b..22413729 100644 --- a/flowforge_api_bruno/service_request/all service requests.bru +++ b/flowforge_api_bruno/service_request/all service requests.bru @@ -5,11 +5,13 @@ meta { } get { - url: {{HOST}}/service_request?org_id=1 + url: {{HOST}}/service_request?org_id=1&page=1&page_size=10 body: none auth: inherit } query { org_id: 1 + page: 1 + page_size: 10 } diff --git a/frontend/src/app/(authenticated)/(main)/your-service-request-dashboard/_hooks/use-service-requests.ts b/frontend/src/app/(authenticated)/(main)/your-service-request-dashboard/_hooks/use-service-requests.ts index 9e41fe14..39025cfd 100644 --- a/frontend/src/app/(authenticated)/(main)/your-service-request-dashboard/_hooks/use-service-requests.ts +++ b/frontend/src/app/(authenticated)/(main)/your-service-request-dashboard/_hooks/use-service-requests.ts @@ -5,6 +5,7 @@ import { FormFieldType, JsonFormComponents } from "@/types/json-form-components" import { StepStatus } from "@/types/pipeline" import { ServiceRequest, ServiceRequestStatus } from "@/types/service-request" import { useQuery } from "@tanstack/react-query" +import { useMemo } from "react" const DUMMY_PIPELINE_FORM: JsonFormComponents = { fields: [ @@ -249,28 +250,43 @@ const DUMMY_SERVICE_REQUESTS: ServiceRequest[] = [ }, }, ] +interface UseServiceRequestProps { + page: number + pageSize: number +} -const useServiceRequests = () => { +const useServiceRequests = ({ page, pageSize }: UseServiceRequestProps) => { const { organizationId } = useOrganizationId() const { isLoading, data } = useQuery({ - queryKey: ["user_service_requests"], + queryKey: ["user_service_requests", page, pageSize], queryFn: () => { - return getAllServiceRequest(organizationId).catch((err) => { - console.error(err) - toast({ - title: "Fetching Service Requests Error", - description: - "Failed to fetch Service Requests for user. Please try again later.", - variant: "destructive", - }) - }) + return getAllServiceRequest(organizationId, page, pageSize).catch( + (err) => { + console.error(err) + toast({ + title: "Fetching Service Requests Error", + description: + "Failed to fetch Service Requests for user. Please try again later.", + variant: "destructive", + }) + } + ) }, refetchInterval: 2000, }) + const noOfPages = useMemo( + () => + data?.metadata.total_count + ? Math.ceil(data?.metadata.total_count / pageSize) + : undefined, + [data, pageSize] + ) + return { response: data, isLoading, + noOfPages, } } diff --git a/frontend/src/app/(authenticated)/(main)/your-service-request-dashboard/page.tsx b/frontend/src/app/(authenticated)/(main)/your-service-request-dashboard/page.tsx index a7457a81..275aa3d6 100644 --- a/frontend/src/app/(authenticated)/(main)/your-service-request-dashboard/page.tsx +++ b/frontend/src/app/(authenticated)/(main)/your-service-request-dashboard/page.tsx @@ -4,9 +4,14 @@ import { DataTable } from "@/components/data-table/data-table" import HeaderAccessory from "@/components/ui/header-accessory" import useServiceRequests from "./_hooks/use-service-requests" import { columns } from "./columns" +import { usePagination } from "@/hooks/use-pagination" export default function ServiceRequestDashboardPage() { - const { response } = useServiceRequests() + const { onPaginationChange, pagination } = usePagination() + const { response, noOfPages } = useServiceRequests({ + page: pagination.pageIndex + 1, // API is 1-based + pageSize: pagination.pageSize, + }) return (
Your Service Requests