diff --git a/application/src/components/servers/ServerTable.tsx b/application/src/components/servers/ServerTable.tsx index d906b44..c73172f 100644 --- a/application/src/components/servers/ServerTable.tsx +++ b/application/src/components/servers/ServerTable.tsx @@ -47,21 +47,21 @@ export const ServerTable = ({ servers, isLoading, onRefresh }: ServerTableProps) newSet.delete(serverId); return newSet; }); - console.log('Resume server monitoring:', serverId); + // console.log('Resume server monitoring:', serverId); } else { setPausedServers(prev => new Set(prev).add(serverId)); - console.log('Pause server monitoring:', serverId); + // console.log('Pause server monitoring:', serverId); } }; const handleEdit = (serverId: string) => { // TODO: Implement edit functionality - console.log('Edit server:', serverId); + // console.log('Edit server:', serverId); }; const handleDelete = (serverId: string) => { // TODO: Implement delete functionality - console.log('Delete server:', serverId); + // console.log('Delete server:', serverId); }; if (isLoading) { diff --git a/application/src/components/services/ServicesPagination.tsx b/application/src/components/services/ServicesPagination.tsx new file mode 100644 index 0000000..a9fab1a --- /dev/null +++ b/application/src/components/services/ServicesPagination.tsx @@ -0,0 +1,131 @@ + +import { + Pagination, + PaginationContent, + PaginationItem, + PaginationLink, + PaginationNext, + PaginationPrevious +} from "@/components/ui/pagination"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from "@/components/ui/select"; +import { PageSize } from "@/hooks/useServicesPagination"; +import { useLanguage } from "@/contexts/LanguageContext"; + +interface ServicesPaginationProps { + currentPage: number; + totalPages: number; + pageSize: PageSize; + totalItems: number; + onPageChange: (page: number) => void; + onPageSizeChange: (size: PageSize) => void; +} + +export function ServicesPagination({ + currentPage, + totalPages, + pageSize, + totalItems, + onPageChange, + onPageSizeChange, +}: ServicesPaginationProps) { + const { t } = useLanguage(); + + // Generate page numbers to display + const getPageNumbers = () => { + const pages = []; + const maxVisiblePages = 5; + const halfVisible = Math.floor(maxVisiblePages / 2); + + let startPage = Math.max(1, currentPage - halfVisible); + let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1); + + // Adjust start page if we don't have enough pages at the end + if (endPage - startPage + 1 < maxVisiblePages) { + startPage = Math.max(1, endPage - maxVisiblePages + 1); + } + + for (let i = startPage; i <= endPage; i++) { + pages.push(i); + } + + return pages; + }; + + const startItem = Math.min((currentPage - 1) * pageSize + 1, totalItems); + const endItem = Math.min(currentPage * pageSize, totalItems); + + return ( +
+
+ + {t("rowsPerPage") ?? "Rows per page"}: + + + + {totalItems > 0 + ? `${startItem}-${endItem} of ${totalItems} ${t("services") || "services"}` + : `0 ${t("services") || "services"}` + } + +
+ + {totalPages > 1 && ( + + + + onPageChange(Math.max(1, currentPage - 1))} + className={ + currentPage === 1 + ? "pointer-events-none opacity-50" + : "cursor-pointer" + } + /> + + + {getPageNumbers().map((page) => ( + + onPageChange(page)} + className="cursor-pointer" + > + {page} + + + ))} + + + onPageChange(Math.min(totalPages, currentPage + 1))} + className={ + currentPage === totalPages + ? "pointer-events-none opacity-50" + : "cursor-pointer" + } + /> + + + + )} +
+ ); +} \ No newline at end of file diff --git a/application/src/components/services/ServicesTableContainer.tsx b/application/src/components/services/ServicesTableContainer.tsx index d8e65db..589f4ee 100644 --- a/application/src/components/services/ServicesTableContainer.tsx +++ b/application/src/components/services/ServicesTableContainer.tsx @@ -2,10 +2,12 @@ import { useEffect } from "react"; import { Service } from "@/types/service.types"; import { ServicesTableView } from "./ServicesTableView"; +import { ServicesPagination } from "./ServicesPagination"; import { ServiceDeleteDialog } from "./ServiceDeleteDialog"; import { ServiceHistoryDialog } from "./ServiceHistoryDialog"; import { ServiceEditDialog } from "./ServiceEditDialog"; import { useServiceActions, useDialogState } from "./hooks"; +import { useServicesPagination } from "@/hooks/useServicesPagination"; interface ServicesTableContainerProps { services: Service[]; @@ -36,6 +38,16 @@ export const ServicesTableContainer = ({ services }: ServicesTableContainerProps handleDeleteDialogChange } = useDialogState(); + const { + paginatedServices, + currentPage, + totalPages, + pageSize, + totalItems, + handlePageChange, + handlePageSizeChange, + } = useServicesPagination({ services: localServices }); + // Update local services state when props change useEffect(() => { updateServices(services); @@ -62,7 +74,7 @@ export const ServicesTableContainer = ({ services }: ServicesTableContainerProps return (
+ +
); -} +} \ No newline at end of file diff --git a/application/src/components/services/ServicesTableView.tsx b/application/src/components/services/ServicesTableView.tsx index 5cdb36c..cc545ca 100644 --- a/application/src/components/services/ServicesTableView.tsx +++ b/application/src/components/services/ServicesTableView.tsx @@ -26,8 +26,8 @@ export const ServicesTableView = ({ const { t } = useLanguage(); return ( -
-
+
+
@@ -65,4 +65,4 @@ export const ServicesTableView = ({ ); -}; +}; \ No newline at end of file diff --git a/application/src/hooks/useServicesPagination.ts b/application/src/hooks/useServicesPagination.ts new file mode 100644 index 0000000..960aca5 --- /dev/null +++ b/application/src/hooks/useServicesPagination.ts @@ -0,0 +1,52 @@ + +import { useState, useMemo } from 'react'; +import { Service } from '@/types/service.types'; + +export type PageSize = 10 | 30 | 50; + +interface UseServicesPaginationProps { + services: Service[]; + initialPageSize?: PageSize; +} + +export const useServicesPagination = ({ + services, + initialPageSize = 10 +}: UseServicesPaginationProps) => { + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(initialPageSize); + + const { paginatedServices, totalPages } = useMemo(() => { + const totalItems = services.length; + const pages = Math.ceil(totalItems / pageSize); + const startIndex = (currentPage - 1) * pageSize; + const endIndex = startIndex + pageSize; + + return { + paginatedServices: services.slice(startIndex, endIndex), + totalPages: Math.max(1, pages) + }; + }, [services, currentPage, pageSize]); + + // Reset to first page when page size changes or services change + const handlePageSizeChange = (newPageSize: PageSize) => { + setPageSize(newPageSize); + setCurrentPage(1); + }; + + // Reset to first page if current page exceeds total pages + const handlePageChange = (page: number) => { + const validPage = Math.min(Math.max(1, page), totalPages); + setCurrentPage(validPage); + }; + + return { + paginatedServices, + currentPage, + totalPages, + pageSize, + totalItems: services.length, + handlePageChange, + handlePageSizeChange, + }; +}; \ No newline at end of file