Proyectos de Subversion LeadersLinked - SPA

Rev

Rev 3533 | Rev 3603 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |

import { useEffect, useState, useCallback, useMemo } from 'react';

import { useFetch } from './useFetch';

export function usePagination(
  url,
  {
    initialPage = 1,
    initialLimit = 10,
    initialParams = {},
    enableInfiniteScroll = false,
    resetOnUrlChange = true
  } = {}
) {
  const [items, setItems] = useState([]);
  const [page, setPage] = useState(initialPage);
  const [totalPages, setTotalPages] = useState(0);
  const [totalItems, setTotalItems] = useState(0);
  const [limit, setLimit] = useState(initialLimit);
  const [params, setParams] = useState({ page, limit, ...initialParams });

  const { data, loading, error, refetch } = useFetch(url, {
    params
  });

  // Memoized pagination state
  const paginationState = useMemo(
    () => ({
      page,
      limit,
      totalPages,
      totalItems,
      hasMore: page < totalPages,
      hasPrevious: page > 1,
      isFirstPage: page === 1,
      isLastPage: page === totalPages
    }),
    [page, limit, totalPages, totalItems]
  );

  // Optimized page navigation functions
  const nextPage = useCallback(() => {
    if (paginationState.hasMore) {
      setPage((prevPage) => prevPage + 1);
    }
  }, [paginationState.hasMore]);

  const prevPage = useCallback(() => {
    if (paginationState.hasPrevious) {
      setPage((prevPage) => prevPage - 1);
    }
  }, [paginationState.hasPrevious]);

  const goToPage = useCallback(
    (newPage) => {
      if (newPage >= 1 && newPage <= totalPages) {
        setPage(newPage);
      }
    },
    [totalPages]
  );

  const setPageLimit = useCallback((newLimit) => {
    if (newLimit > 0) {
      setLimit(newLimit);
      setPage(1);
    }
  }, []);

  const resetPagination = useCallback(() => {
    setPage(initialPage);
    setItems([]);
    setTotalPages(0);
    setTotalItems(0);
  }, [initialPage]);

  const updateParams = useCallback((newParams) => {
    setParams((prevParams) => ({ ...prevParams, ...newParams }));
  }, []);

  // Handle data updates with flexible structure support
  useEffect(() => {
    if (data) {
      let newItems = [];
      let pages = 0;
      let items = 0;

      // Handle different response structures
      if (data?.current?.items) {
        // Structure: { current: { items: [] }, total: { pages: number, items: number } }
        newItems = data.current.items;
        pages = data.total?.pages || 0;
        items = data.total?.items || 0;
      } else if (data?.data && Array.isArray(data.data)) {
        // Structure: { data: [], pagination: { ... } }
        newItems = data.data;
        pages = data.pagination?.pageCount || data.pagination?.last || 0;
        items = data.pagination?.totalItemCount || 0;
      } else if (Array.isArray(data)) {
        // Structure: direct array
        newItems = data;
        pages = 1;
        items = data.length;
      } else if (data?.items && Array.isArray(data.items)) {
        // Structure: { items: [], pagination: { ... } }
        newItems = data.items;
        pages = data.pagination?.pageCount || data.pagination?.last || 0;
        items = data.pagination?.totalItemCount || 0;
      }

      setItems((prevItems) => {
        if (enableInfiniteScroll && page > 1) {
          // For infinite scroll, append new items
          return [...prevItems, ...newItems];
        } else {
          // For regular pagination, replace items
          return newItems;
        }
      });

      setTotalPages(pages);
      setTotalItems(items);
    }
  }, [data, page, enableInfiniteScroll]);

  // Update params when page or limit changes
  useEffect(() => {
    setParams((prevParams) => ({
      ...prevParams,
      page,
      limit
    }));
  }, [page, limit]);

  // Reset pagination when URL changes (if enabled)
  useEffect(() => {
    if (resetOnUrlChange) {
      resetPagination();
    }
  }, [url, resetOnUrlChange, resetPagination]);

  return {
    // Data
    items,
    ...paginationState,

    // Loading and error states
    loading,
    error,

    // Actions
    nextPage,
    prevPage,
    goToPage,
    setPageLimit,
    resetPagination,
    updateParams,
    refetch
  };
}