Rows per page standarized
This commit is contained in:
@@ -19,7 +19,7 @@ export default function AuditoriaPage() {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const limit = 50;
|
||||
const [limit, setLimit] = useState(10);
|
||||
|
||||
const actions: AuditAction[] = [
|
||||
"CREATE",
|
||||
@@ -36,7 +36,8 @@ export default function AuditoriaPage() {
|
||||
|
||||
useEffect(() => {
|
||||
fetchAuditLogs();
|
||||
}, [currentPage, selectedAction, selectedTable]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentPage, selectedAction, selectedTable, limit]);
|
||||
|
||||
const fetchAuditLogs = async () => {
|
||||
try {
|
||||
@@ -78,6 +79,11 @@ export default function AuditoriaPage() {
|
||||
setShowDetails(true);
|
||||
};
|
||||
|
||||
const handleLimitChange = (newLimit: number) => {
|
||||
setLimit(newLimit);
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
const getActionColor = (action: AuditAction) => {
|
||||
const colors: Record<AuditAction, string> = {
|
||||
CREATE: "bg-green-100 text-green-800",
|
||||
@@ -296,28 +302,64 @@ export default function AuditoriaPage() {
|
||||
)}
|
||||
|
||||
{/* Pagination */}
|
||||
{!loading && logs.length > 0 && (
|
||||
<div className="mt-4 flex flex-wrap items-center justify-between gap-4 px-4">
|
||||
{/* Page Info */}
|
||||
<div className="text-sm text-gray-600">
|
||||
Mostrando{" "}
|
||||
<span className="font-semibold text-gray-800">
|
||||
{(currentPage - 1) * limit + 1}
|
||||
</span>{" "}
|
||||
a{" "}
|
||||
<span className="font-semibold text-gray-800">
|
||||
{Math.min(currentPage * limit, total)}
|
||||
</span>{" "}
|
||||
de{" "}
|
||||
<span className="font-semibold text-gray-800">{total}</span>{" "}
|
||||
registros
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Page Size Selector */}
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-gray-600">Filas por página:</span>
|
||||
<select
|
||||
value={limit}
|
||||
onChange={(e) => handleLimitChange(Number(e.target.value))}
|
||||
className="px-3 py-1.5 text-sm bg-white border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
>
|
||||
<option value={10}>10</option>
|
||||
<option value={20}>20</option>
|
||||
<option value={50}>50</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Page Navigation */}
|
||||
{totalPages > 1 && (
|
||||
<div className="mt-4 flex justify-center gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
||||
disabled={currentPage === 1}
|
||||
className="px-4 py-2 border border-gray-300 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
Anterior
|
||||
</button>
|
||||
<span className="px-4 py-2">
|
||||
<span className="px-4 py-2 text-sm text-gray-700">
|
||||
Página {currentPage} de {totalPages}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
|
||||
disabled={currentPage === totalPages}
|
||||
className="px-4 py-2 border border-gray-300 rounded-md disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
className="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
Siguiente
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Details Modal */}
|
||||
|
||||
@@ -58,7 +58,6 @@ export default function UsersPage() {
|
||||
try {
|
||||
setLoadingUsers(true);
|
||||
const usersResponse = await getAllUsers();
|
||||
console.log('Users API response:', usersResponse);
|
||||
|
||||
const mappedUsers: User[] = usersResponse.data.map((apiUser: ApiUser) => ({
|
||||
id: apiUser.id,
|
||||
@@ -312,7 +311,15 @@ export default function UsersPage() {
|
||||
]}
|
||||
data={filtered}
|
||||
onRowClick={(_, rowData) => setActiveUser(rowData as User)}
|
||||
options={{ actionsColumnIndex: -1, search: false, paging: true, sorting: true, rowStyle: rowData => ({ backgroundColor: activeUser?.id === (rowData as User).id ? "#EEF2FF" : "#FFFFFF" }) }}
|
||||
options={{
|
||||
actionsColumnIndex: -1,
|
||||
search: false,
|
||||
paging: true,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: [10, 20, 50],
|
||||
sorting: true,
|
||||
rowStyle: rowData => ({ backgroundColor: activeUser?.id === (rowData as User).id ? "#EEF2FF" : "#FFFFFF" })
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -94,6 +94,8 @@ export default function ConcentratorsTable({
|
||||
actionsColumnIndex: -1,
|
||||
search: false,
|
||||
paging: true,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: [10, 20, 50],
|
||||
sorting: true,
|
||||
rowStyle: (rowData) => ({
|
||||
backgroundColor:
|
||||
|
||||
@@ -35,7 +35,7 @@ export default function ConsumptionPage() {
|
||||
const [projects, setProjects] = useState<Project[]>([]);
|
||||
const [pagination, setPagination] = useState<Pagination>({
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
totalPages: 0,
|
||||
});
|
||||
@@ -73,10 +73,12 @@ export default function ConsumptionPage() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const loadData = async (page = 1) => {
|
||||
const loadData = async (page = 1, pageSize?: number) => {
|
||||
setLoadingReadings(true);
|
||||
setLoadingSummary(true);
|
||||
|
||||
const currentPageSize = pageSize || pagination.pageSize;
|
||||
|
||||
try {
|
||||
const [readingsResult, summaryResult] = await Promise.all([
|
||||
fetchReadings({
|
||||
@@ -84,7 +86,7 @@ export default function ConsumptionPage() {
|
||||
startDate: startDate || undefined,
|
||||
endDate: endDate || undefined,
|
||||
page,
|
||||
pageSize: 100,
|
||||
pageSize: currentPageSize,
|
||||
}),
|
||||
fetchConsumptionSummary(selectedProject || undefined),
|
||||
]);
|
||||
@@ -167,6 +169,15 @@ export default function ConsumptionPage() {
|
||||
});
|
||||
};
|
||||
|
||||
const handlePageChange = (newPage: number) => {
|
||||
loadData(newPage);
|
||||
};
|
||||
|
||||
const handlePageSizeChange = (newPageSize: number) => {
|
||||
setPagination({ ...pagination, pageSize: newPageSize, page: 1 });
|
||||
loadData(1, newPageSize);
|
||||
};
|
||||
|
||||
const exportToCSV = () => {
|
||||
const headers = ["Fecha", "Medidor", "Serial", "Ubicación", "Valor", "Tipo", "Batería", "Señal"];
|
||||
const rows = filteredReadings.map((r) => [
|
||||
@@ -502,6 +513,88 @@ export default function ConsumptionPage() {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{!loadingReadings && filteredReadings.length > 0 && (
|
||||
<div className="px-5 py-4 border-t border-slate-100 flex flex-wrap items-center justify-between gap-4">
|
||||
<div className="text-sm text-slate-600">
|
||||
Mostrando{" "}
|
||||
<span className="font-semibold text-slate-800">
|
||||
{(pagination.page - 1) * pagination.pageSize + 1}
|
||||
</span>{" "}
|
||||
a{" "}
|
||||
<span className="font-semibold text-slate-800">
|
||||
{Math.min(pagination.page * pagination.pageSize, pagination.total)}
|
||||
</span>{" "}
|
||||
de{" "}
|
||||
<span className="font-semibold text-slate-800">{pagination.total}</span>{" "}
|
||||
resultados
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-slate-600">Filas por página:</span>
|
||||
<select
|
||||
value={pagination.pageSize}
|
||||
onChange={(e) => handlePageSizeChange(Number(e.target.value))}
|
||||
className="px-3 py-1.5 text-sm bg-white border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500"
|
||||
>
|
||||
<option value={10}>10</option>
|
||||
<option value={20}>20</option>
|
||||
<option value={50}>50</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<button
|
||||
onClick={() => handlePageChange(pagination.page - 1)}
|
||||
disabled={pagination.page === 1}
|
||||
className="p-2 rounded-lg hover:bg-slate-100 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
<ChevronLeft size={18} className="text-slate-600" />
|
||||
</button>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
{Array.from({ length: pagination.totalPages }, (_, i) => i + 1)
|
||||
.filter((pageNum) => {
|
||||
if (pageNum === 1 || pageNum === pagination.totalPages) return true;
|
||||
if (Math.abs(pageNum - pagination.page) <= 1) return true;
|
||||
return false;
|
||||
})
|
||||
.map((pageNum, idx, arr) => {
|
||||
const prevNum = arr[idx - 1];
|
||||
const showEllipsis = prevNum && pageNum - prevNum > 1;
|
||||
|
||||
return (
|
||||
<div key={pageNum} className="flex items-center">
|
||||
{showEllipsis && (
|
||||
<span className="px-2 text-slate-400">...</span>
|
||||
)}
|
||||
<button
|
||||
onClick={() => handlePageChange(pageNum)}
|
||||
className={`min-w-[36px] px-3 py-1.5 text-sm rounded-lg transition-colors ${
|
||||
pageNum === pagination.page
|
||||
? "bg-blue-600 text-white font-semibold"
|
||||
: "text-slate-600 hover:bg-slate-100"
|
||||
}`}
|
||||
>
|
||||
{pageNum}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => handlePageChange(pagination.page + 1)}
|
||||
disabled={pagination.page === pagination.totalPages}
|
||||
className="p-2 rounded-lg hover:bg-slate-100 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
<ChevronRight size={18} className="text-slate-600" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -263,6 +263,8 @@ export default function ProjectsPage() {
|
||||
options={{
|
||||
search: false,
|
||||
paging: true,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: [10, 20, 50],
|
||||
sorting: true,
|
||||
rowStyle: (rowData) => ({
|
||||
backgroundColor:
|
||||
|
||||
Reference in New Issue
Block a user