Paginate registration lists
This commit is contained in:
@@ -11,11 +11,13 @@ import {
|
|||||||
saveCatalogProduct,
|
saveCatalogProduct,
|
||||||
saveConsumptionReference
|
saveConsumptionReference
|
||||||
} from '../dataService';
|
} from '../dataService';
|
||||||
|
import PaginationControls from '../components/PaginationControls';
|
||||||
import type { CatalogCategory, CatalogProduct, CatalogProductType, CatalogSummary, ConsumptionReference } from '../types';
|
import type { CatalogCategory, CatalogProduct, CatalogProductType, CatalogSummary, ConsumptionReference } from '../types';
|
||||||
import { formatColorLabel } from '../displayFormatters';
|
import { formatColorLabel } from '../displayFormatters';
|
||||||
|
|
||||||
type RegistrationTab = 'products' | 'categories' | 'references';
|
type RegistrationTab = 'products' | 'categories' | 'references';
|
||||||
type SaveStatus = 'idle' | 'saving' | 'saved' | 'error';
|
type SaveStatus = 'idle' | 'saving' | 'saved' | 'error';
|
||||||
|
type RegistrationPagination = Record<RegistrationTab, { page: number; pageSize: number }>;
|
||||||
|
|
||||||
const emptyCatalog: CatalogSummary = {
|
const emptyCatalog: CatalogSummary = {
|
||||||
categories: [],
|
categories: [],
|
||||||
@@ -111,6 +113,11 @@ const Registrations = () => {
|
|||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [activeTab, setActiveTab] = useState<RegistrationTab>('products');
|
const [activeTab, setActiveTab] = useState<RegistrationTab>('products');
|
||||||
const [productFilter, setProductFilter] = useState<'all' | CatalogProductType>('all');
|
const [productFilter, setProductFilter] = useState<'all' | CatalogProductType>('all');
|
||||||
|
const [pagination, setPagination] = useState<RegistrationPagination>({
|
||||||
|
products: { page: 1, pageSize: 20 },
|
||||||
|
categories: { page: 1, pageSize: 20 },
|
||||||
|
references: { page: 1, pageSize: 20 },
|
||||||
|
});
|
||||||
const [status, setStatus] = useState<SaveStatus>('idle');
|
const [status, setStatus] = useState<SaveStatus>('idle');
|
||||||
const [feedback, setFeedback] = useState('');
|
const [feedback, setFeedback] = useState('');
|
||||||
const appliedSkuPrefillRef = useRef('');
|
const appliedSkuPrefillRef = useRef('');
|
||||||
@@ -247,6 +254,28 @@ const Registrations = () => {
|
|||||||
return catalog.products.filter(product => product.type === productFilter);
|
return catalog.products.filter(product => product.type === productFilter);
|
||||||
}, [catalog.products, productFilter]);
|
}, [catalog.products, productFilter]);
|
||||||
|
|
||||||
|
const updatePagination = (tab: RegistrationTab, patch: Partial<RegistrationPagination[RegistrationTab]>) => {
|
||||||
|
setPagination(current => ({
|
||||||
|
...current,
|
||||||
|
[tab]: { ...current[tab], ...patch }
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const productTotalPages = Math.ceil(filteredProducts.length / pagination.products.pageSize);
|
||||||
|
const safeProductPage = Math.min(pagination.products.page, productTotalPages || 1);
|
||||||
|
const productStartIndex = (safeProductPage - 1) * pagination.products.pageSize;
|
||||||
|
const paginatedProducts = filteredProducts.slice(productStartIndex, productStartIndex + pagination.products.pageSize);
|
||||||
|
|
||||||
|
const categoryTotalPages = Math.ceil(catalog.categories.length / pagination.categories.pageSize);
|
||||||
|
const safeCategoryPage = Math.min(pagination.categories.page, categoryTotalPages || 1);
|
||||||
|
const categoryStartIndex = (safeCategoryPage - 1) * pagination.categories.pageSize;
|
||||||
|
const paginatedCategories = catalog.categories.slice(categoryStartIndex, categoryStartIndex + pagination.categories.pageSize);
|
||||||
|
|
||||||
|
const referenceTotalPages = Math.ceil(catalog.consumptionReferences.length / pagination.references.pageSize);
|
||||||
|
const safeReferencePage = Math.min(pagination.references.page, referenceTotalPages || 1);
|
||||||
|
const referenceStartIndex = (safeReferencePage - 1) * pagination.references.pageSize;
|
||||||
|
const paginatedReferences = catalog.consumptionReferences.slice(referenceStartIndex, referenceStartIndex + pagination.references.pageSize);
|
||||||
|
|
||||||
const runAction = async (action: () => Promise<void>, successMessage: string) => {
|
const runAction = async (action: () => Promise<void>, successMessage: string) => {
|
||||||
setStatus('saving');
|
setStatus('saving');
|
||||||
setFeedback('');
|
setFeedback('');
|
||||||
@@ -473,7 +502,10 @@ const Registrations = () => {
|
|||||||
</div>
|
</div>
|
||||||
<select
|
<select
|
||||||
value={productFilter}
|
value={productFilter}
|
||||||
onChange={(event) => setProductFilter(event.target.value as 'all' | CatalogProductType)}
|
onChange={(event) => {
|
||||||
|
setProductFilter(event.target.value as 'all' | CatalogProductType);
|
||||||
|
updatePagination('products', { page: 1 });
|
||||||
|
}}
|
||||||
className="h-10 rounded-xl border border-dark-border bg-dark-input px-3 text-sm font-bold text-dark-text outline-none focus:border-brand-primary cursor-pointer"
|
className="h-10 rounded-xl border border-dark-border bg-dark-input px-3 text-sm font-bold text-dark-text outline-none focus:border-brand-primary cursor-pointer"
|
||||||
>
|
>
|
||||||
<option value="all">Todos</option>
|
<option value="all">Todos</option>
|
||||||
@@ -482,7 +514,7 @@ const Registrations = () => {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y divide-dark-border">
|
<div className="divide-y divide-dark-border">
|
||||||
{filteredProducts.map(product => (
|
{paginatedProducts.map(product => (
|
||||||
<div key={product.id} className="flex flex-col gap-3 p-4 md:flex-row md:items-center md:justify-between">
|
<div key={product.id} className="flex flex-col gap-3 p-4 md:flex-row md:items-center md:justify-between">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
@@ -512,6 +544,19 @@ const Registrations = () => {
|
|||||||
<div className={emptyStateClassName}>Nenhum produto cadastrado.</div>
|
<div className={emptyStateClassName}>Nenhum produto cadastrado.</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<PaginationControls
|
||||||
|
totalItems={filteredProducts.length}
|
||||||
|
currentPage={safeProductPage}
|
||||||
|
totalPages={productTotalPages}
|
||||||
|
pageSize={pagination.products.pageSize}
|
||||||
|
pageSizeOptions={[10, 20, 50, 100]}
|
||||||
|
itemLabel="produtos"
|
||||||
|
pageSizeLabel="por página"
|
||||||
|
startIndex={productStartIndex}
|
||||||
|
endIndex={Math.min(productStartIndex + pagination.products.pageSize, filteredProducts.length)}
|
||||||
|
onPageChange={(page) => updatePagination('products', { page })}
|
||||||
|
onPageSizeChange={(pageSize) => updatePagination('products', { page: 1, pageSize })}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={formPanelClassName}>
|
<div className={formPanelClassName}>
|
||||||
@@ -662,7 +707,7 @@ const Registrations = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y divide-dark-border">
|
<div className="divide-y divide-dark-border">
|
||||||
{catalog.categories.map(category => (
|
{paginatedCategories.map(category => (
|
||||||
<div key={category.id} className="flex items-center justify-between gap-3 p-4">
|
<div key={category.id} className="flex items-center justify-between gap-3 p-4">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-bold text-dark-text">{category.name}</h3>
|
<h3 className="text-sm font-bold text-dark-text">{category.name}</h3>
|
||||||
@@ -675,6 +720,19 @@ const Registrations = () => {
|
|||||||
))}
|
))}
|
||||||
{!catalog.categories.length && <div className={emptyStateClassName}>Nenhuma categoria cadastrada.</div>}
|
{!catalog.categories.length && <div className={emptyStateClassName}>Nenhuma categoria cadastrada.</div>}
|
||||||
</div>
|
</div>
|
||||||
|
<PaginationControls
|
||||||
|
totalItems={catalog.categories.length}
|
||||||
|
currentPage={safeCategoryPage}
|
||||||
|
totalPages={categoryTotalPages}
|
||||||
|
pageSize={pagination.categories.pageSize}
|
||||||
|
pageSizeOptions={[10, 20, 50, 100]}
|
||||||
|
itemLabel="categorias"
|
||||||
|
pageSizeLabel="por página"
|
||||||
|
startIndex={categoryStartIndex}
|
||||||
|
endIndex={Math.min(categoryStartIndex + pagination.categories.pageSize, catalog.categories.length)}
|
||||||
|
onPageChange={(page) => updatePagination('categories', { page })}
|
||||||
|
onPageSizeChange={(pageSize) => updatePagination('categories', { page: 1, pageSize })}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={formPanelClassName}>
|
<div className={formPanelClassName}>
|
||||||
@@ -710,7 +768,7 @@ const Registrations = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y divide-dark-border">
|
<div className="divide-y divide-dark-border">
|
||||||
{catalog.consumptionReferences.map(reference => (
|
{paginatedReferences.map(reference => (
|
||||||
<div key={reference.id} className="flex flex-col gap-3 p-4 md:flex-row md:items-start md:justify-between">
|
<div key={reference.id} className="flex flex-col gap-3 p-4 md:flex-row md:items-start md:justify-between">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
@@ -768,6 +826,19 @@ const Registrations = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<PaginationControls
|
||||||
|
totalItems={catalog.consumptionReferences.length}
|
||||||
|
currentPage={safeReferencePage}
|
||||||
|
totalPages={referenceTotalPages}
|
||||||
|
pageSize={pagination.references.pageSize}
|
||||||
|
pageSizeOptions={[10, 20, 50, 100]}
|
||||||
|
itemLabel="referências"
|
||||||
|
pageSizeLabel="por página"
|
||||||
|
startIndex={referenceStartIndex}
|
||||||
|
endIndex={Math.min(referenceStartIndex + pagination.references.pageSize, catalog.consumptionReferences.length)}
|
||||||
|
onPageChange={(page) => updatePagination('references', { page })}
|
||||||
|
onPageSizeChange={(pageSize) => updatePagination('references', { page: 1, pageSize })}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={formPanelClassName}>
|
<div className={formPanelClassName}>
|
||||||
|
|||||||
Reference in New Issue
Block a user