mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 13:35:25 +02:00
Add pagination to Pricing tab
Load data in batches of 100 products per page with navigation controls
This commit is contained in:
@@ -51,6 +51,8 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
const [filterMode, setFilterMode] = useState<FilterMode>('all_errors');
|
const [filterMode, setFilterMode] = useState<FilterMode>('all_errors');
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [searchMode, setSearchMode] = useState<'all' | 'selected'>('all');
|
const [searchMode, setSearchMode] = useState<'all' | 'selected'>('all');
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const pageSize = 100;
|
||||||
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({
|
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({
|
||||||
articleNo: 100,
|
articleNo: 100,
|
||||||
articleName: 220,
|
articleName: 220,
|
||||||
@@ -387,6 +389,14 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
return sorted;
|
return sorted;
|
||||||
}, [filteredRows, sortConfig]);
|
}, [filteredRows, sortConfig]);
|
||||||
|
|
||||||
|
// ── Pagination ─────────────────────────────────────────────────────────
|
||||||
|
const paginatedRows = useMemo(() => {
|
||||||
|
const start = (currentPage - 1) * pageSize;
|
||||||
|
return sortedRows.slice(start, start + pageSize);
|
||||||
|
}, [sortedRows, currentPage]);
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(sortedRows.length / pageSize);
|
||||||
|
|
||||||
const handleSort = (key: string | number) => {
|
const handleSort = (key: string | number) => {
|
||||||
setSortConfig(prev => {
|
setSortConfig(prev => {
|
||||||
if (prev.key === key) {
|
if (prev.key === key) {
|
||||||
@@ -713,7 +723,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
{FILTERS.map(f => (
|
{FILTERS.map(f => (
|
||||||
<button
|
<button
|
||||||
key={f.id}
|
key={f.id}
|
||||||
onClick={() => setFilterMode(f.id)}
|
onClick={() => { setFilterMode(f.id); setCurrentPage(1); }}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-colors',
|
'flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-colors',
|
||||||
filterMode === f.id
|
filterMode === f.id
|
||||||
@@ -1056,7 +1066,7 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{sortedRows.map(({ row, dataIndex, pricingErrors, unitErrors, isCritical }) => {
|
{paginatedRows.map(({ row, dataIndex, pricingErrors, unitErrors, isCritical }) => {
|
||||||
const saveStatus = rowStatuses[String(row[COLUMNS.ARTICLE_NO])];
|
const saveStatus = rowStatuses[String(row[COLUMNS.ARTICLE_NO])];
|
||||||
const isValidated = !!row[COLUMNS.VALIDATED_CHECK];
|
const isValidated = !!row[COLUMNS.VALIDATED_CHECK];
|
||||||
const note = String(row[COLUMNS.VALIDATED_NOTE] || '');
|
const note = String(row[COLUMNS.VALIDATED_NOTE] || '');
|
||||||
@@ -1274,13 +1284,50 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ── Footer count ── */}
|
{/* ── Footer count & Pagination ── */}
|
||||||
<p className="text-xs text-slate-500 pb-1">
|
<div className="flex items-center justify-between">
|
||||||
Showing {filteredRows.length} of {stats.total} products
|
<p className="text-xs text-slate-500 pb-1">
|
||||||
{pricingEditableCols.length > 0 && (
|
Showing {paginatedRows.length} of {sortedRows.length} products {totalPages > 1 && `(${currentPage}/${totalPages})`}
|
||||||
<> · Click any <span className="text-blue-400">price cell</span> to edit inline</>
|
{pricingEditableCols.length > 0 && (
|
||||||
|
<> · Click any <span className="text-blue-400">price cell</span> to edit inline</>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<button
|
||||||
|
onClick={() => setCurrentPage(1)}
|
||||||
|
disabled={currentPage === 1}
|
||||||
|
className="px-2 py-1 text-xs bg-slate-800 hover:bg-slate-700 rounded disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
>
|
||||||
|
««
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
|
||||||
|
disabled={currentPage === 1}
|
||||||
|
className="px-2 py-1 text-xs bg-slate-800 hover:bg-slate-700 rounded disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
>
|
||||||
|
«
|
||||||
|
</button>
|
||||||
|
<span className="text-xs text-slate-400 px-2">
|
||||||
|
{currentPage} / {totalPages}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
|
||||||
|
disabled={currentPage === totalPages}
|
||||||
|
className="px-2 py-1 text-xs bg-slate-800 hover:bg-slate-700 rounded disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
>
|
||||||
|
»
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setCurrentPage(totalPages)}
|
||||||
|
disabled={currentPage === totalPages}
|
||||||
|
className="px-2 py-1 text-xs bg-slate-800 hover:bg-slate-700 rounded disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
>
|
||||||
|
»»
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user