refactor(quota): modularize QuotaPage into separate section components
This commit is contained in:
87
src/components/quota/hooks/useQuotaSection.ts
Normal file
87
src/components/quota/hooks/useQuotaSection.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Shared hook for quota section pagination and loading state management.
|
||||
*/
|
||||
|
||||
import { useState, useMemo, useCallback } from 'react';
|
||||
|
||||
interface UseQuotaSectionOptions<T> {
|
||||
items: T[];
|
||||
defaultPageSize?: number;
|
||||
}
|
||||
|
||||
interface UseQuotaSectionReturn<T> {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
currentPage: number;
|
||||
pageItems: T[];
|
||||
setPage: (page: number) => void;
|
||||
setPageSize: (size: number) => void;
|
||||
goToPrev: () => void;
|
||||
goToNext: () => void;
|
||||
loading: boolean;
|
||||
loadingScope: 'page' | 'all' | null;
|
||||
setLoading: (loading: boolean, scope?: 'page' | 'all' | null) => void;
|
||||
}
|
||||
|
||||
export function useQuotaSection<T>(
|
||||
options: UseQuotaSectionOptions<T>
|
||||
): UseQuotaSectionReturn<T> {
|
||||
const { items, defaultPageSize = 6 } = options;
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSizeState] = useState(defaultPageSize);
|
||||
const [loading, setLoadingState] = useState(false);
|
||||
const [loadingScope, setLoadingScope] = useState<'page' | 'all' | null>(null);
|
||||
|
||||
const totalPages = useMemo(
|
||||
() => Math.max(1, Math.ceil(items.length / pageSize)),
|
||||
[items.length, pageSize]
|
||||
);
|
||||
|
||||
const currentPage = useMemo(
|
||||
() => Math.min(page, totalPages),
|
||||
[page, totalPages]
|
||||
);
|
||||
|
||||
const pageItems = useMemo(() => {
|
||||
const start = (currentPage - 1) * pageSize;
|
||||
return items.slice(start, start + pageSize);
|
||||
}, [items, currentPage, pageSize]);
|
||||
|
||||
const handleSetPageSize = useCallback((size: number) => {
|
||||
setPageSizeState(size);
|
||||
setPage(1);
|
||||
}, []);
|
||||
|
||||
const goToPrev = useCallback(() => {
|
||||
setPage((p) => Math.max(1, p - 1));
|
||||
}, []);
|
||||
|
||||
const goToNext = useCallback(() => {
|
||||
setPage((p) => Math.min(totalPages, p + 1));
|
||||
}, [totalPages]);
|
||||
|
||||
const setLoading = useCallback(
|
||||
(isLoading: boolean, scope?: 'page' | 'all' | null) => {
|
||||
setLoadingState(isLoading);
|
||||
setLoadingScope(isLoading ? (scope ?? null) : null);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return {
|
||||
page,
|
||||
pageSize,
|
||||
totalPages,
|
||||
currentPage,
|
||||
pageItems,
|
||||
setPage,
|
||||
setPageSize: handleSetPageSize,
|
||||
goToPrev,
|
||||
goToNext,
|
||||
loading,
|
||||
loadingScope,
|
||||
setLoading
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user