I’m trying to implement pagination using React
and tanstack
. The table works correctly, and the buttons for the pagination are visible. But they are not clickable. What are I’m doing wrong?
This is my code:
Customer.js:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import {
createColumnHelper,
flexRender,
getCoreRowModel,
useReactTable,
getSortedRowModel,
getPaginationRowModel,
} from '@tanstack/react-table';
import { Button, Modal } from 'react-bootstrap';
import './Customers.css'; // Aggiunta per importare il file CSS
import ModalCustomer from './components/CustomerModal';
const Customers = () => {
const [customers, setCustomers] = useState([]);
const [showAddModal, setShowAddModal] = useState(false);
const [showEditModal, setShowEditModal] = useState(false);
const [selectedCustomer, setSelectedCustomer] = useState(null);
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [location, setLocation] = useState('');
const [hobbies, setHobbies] = useState('');
const [sorting, setSorting] = useState([]);
useEffect(() => {
fetchCustomers();
}, []);
const fetchCustomers = async () => {
try {
const response = await axios.get('http://127.0.0.1:5000/customers');
setCustomers(response.data);
} catch (error) {
console.error('Error fetching customers:', error);
}
};
const addCustomer = async () => {
try {
if (!name) {
alert('Name field is required!');
return;
}
if (!email) {
alert('Email field is required!');
return;
}
await axios.post('http://127.0.0.1:5000/customer', { name, email, phone, location, hobbies });
fetchCustomers();
setShowAddModal(false);
setName('');
setEmail('');
setPhone('');
setLocation('');
setHobbies('');
} catch (error) {
console.error('Error adding customer:', error);
}
};
const deleteCustomer = async id => {
try {
await axios.delete(`http://127.0.0.1:5000/customer/${id}`);
fetchCustomers();
} catch (error) {
console.error('Error deleting customer:', error);
}
};
const updateCustomer = async () => {
try {
await axios.put(`http://127.0.0.1:5000/customer/${selectedCustomer.id}`, { name, email, phone, location, hobbies });
fetchCustomers();
setShowEditModal(false);
setSelectedCustomer(null);
setName('');
setEmail('');
setLocation('');
setHobbies('');
setPhone('');
} catch (error) {
console.error('Error updating customer:', error);
}
};
const columnHelper = createColumnHelper();
const columns = [
columnHelper.accessor('name', {
header: 'Name',
cell: info => info.getValue(),
sortingFn: (a, b) => a.original.name.toLowerCase().localeCompare(b.original.name.toLowerCase()),
}),
columnHelper.accessor('email', {
header: 'Email',
cell: info => info.getValue(),
sortingFn: (a, b) => a.original.email.toLowerCase().localeCompare(b.original.email.toLowerCase()),
}),
columnHelper.accessor('phone', {
header: 'Phone',
cell: info => info.getValue(),
sortingFn: (a, b) => a.original.phone.localeCompare(b.original.phone),
}),
columnHelper.accessor('location', {
header: 'Location',
cell: info => info.getValue(),
sortingFn: (a, b) => a.original.location.toLowerCase().localeCompare(b.original.location.toLowerCase()),
}),
columnHelper.accessor('hobbies', {
header: 'Hobbies',
cell: info => info.getValue(),
sortingFn: (a, b) => a.original.hobbies.toLowerCase().localeCompare(b.original.hobbies.toLowerCase()),
}),
{
header: 'Actions',
accessorKey: 'id',
cell: ({ row }) => (
<div>
<Button className="edit-button" variant="info" onClick={() => {
setSelectedCustomer(row.original);
setName(row.original.name);
setEmail(row.original.email);
setPhone(row.original.phone);
setLocation(row.original.location);
setHobbies(row.original.hobbies);
setShowEditModal(true);
}}>Edit</Button>{' '}
<Button className="delete-button" variant="danger" onClick={() => deleteCustomer(row.original.id)}>Del</Button>
</div>
),
},
];
const table = useReactTable({
data: customers,
columns,
state: {
sorting,
},
getCoreRowModel: getCoreRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(), //load client-side pagination code
});
return (
<div className="flex flex-col items-center h-screen bg-gray-100">
<div className="title-container">
<h1 className="text-3xl font-bold my-4 text-center">Customers</h1>
</div>
<div className="table-container mx-auto">
<div className="overflow-x-auto w-full max-w-4xl">
<table className="min-w-full bg-white shadow-md rounded">
<thead className="bg-gray-200 text-gray-600 uppercase text-sm leading-normal">
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th
key={header.id}
className="py-3 px-6 text-left cursor-pointer hover:bg-gray-300" // Aggiungi hover per migliorare l'interazione
onClick={header.column.getToggleSortingHandler()} // Gestore del click per il sorting
>
{header.isPlaceholder
? null
: (
<>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
{{
asc: ' ????',
desc: ' ????'
}[header.column.getIsSorted()] ?? ' ????????'} {/* Indica la direzione del sorting o mostra le frecce */}
</>
)}
</th>
))}
</tr>
))}
</thead>
<tbody className="text-gray-600 text-sm font-light">
{table.getRowModel().rows.map(row => (
<tr key={row.id} className="border-b border-gray-200 hover:bg-gray-100">
{row.getVisibleCells().map(cell => (
<td key={cell.id} className="py-3 px-6 text-left whitespace-nowrap">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="button-container">
<Button className="mt-4 text-center add-customer-button" onClick={() => setShowAddModal(true)}>Add Customer</Button>
</div>
<Modal show={showAddModal} onHide={() => setShowAddModal(false)}>
<ModalCustomer
name={name}
email={email}
phone={phone}
location={location}
hobbies={hobbies}
setName={setName}
setEmail={setEmail}
setPhone={setPhone}
setLocation={setLocation}
setHobbies={setHobbies}
handleSubmit={addCustomer}
handleClose={() => {
setShowAddModal(false);
setName('');
setEmail('');
setPhone('');
setLocation('');
setHobbies('');
}}
title="Add Customer"
/>
</Modal>
<Modal show={showEditModal} onHide={() => setShowEditModal(false)}>
<ModalCustomer
name={name}
email={email}
phone={phone}
location={location}
hobbies={hobbies}
setName={setName}
setEmail={setEmail}
setPhone={setPhone}
setLocation={setLocation}
setHobbies={setHobbies}
handleSubmit={updateCustomer}
handleClose={() => {
setShowEditModal(false);
setName('');
setEmail('');
setPhone('');
setLocation('');
setHobbies('');
}}
title="Edit Customer"
/>
</Modal>
<Button
onClick={() => table.firstPage()}
disabled={!table.getCanPreviousPage()}
>
{'<<'}
</Button>
<Button
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
{'<'}
</Button>
<Button
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
{'>'}
</Button>
<Button
onClick={() => table.lastPage()}
disabled={!table.getCanNextPage()}
>
{'>>'}
</Button>
<select
value={table.getState().pagination.pageSize}
onChange={e => {
table.setPageSize(Number(e.target.value))
}}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
{pageSize}
</option>
))}
</select>
</div>
);
};
export default Customers;
Customer.css
.table-container {
margin: 0 auto;
width: 80%;
}
.table-container table {
border-spacing: 0;
width: 100%;
}
.table-container th,
.table-container td {
padding: 0.75rem;
text-align: center;
}
.table-container th:not(:last-child),
.table-container td:not(:last-child) {
border-right: 1px solid #dee2e6;
}
.table-container th:first-child,
.table-container td:first-child {
padding-left: 1rem;
}
.table-container th:last-child,
.table-container td:last-child {
padding-right: 1rem;
}
.table-container thead th {
border-bottom: 2px solid #dee2e6;
}
.edit-button {
background-color: #007bff;
color: white;
border: none;
}
.edit-button:hover {
background-color: #0056b3;
}
.delete-button:hover {
background-color: #b30000;
}
.delete-button {
background-color: red;
color: white;
border: none;
}
.edit-button,
.delete-button {
padding: 4px 12px;
font-size: 1rem;
border-radius: 8px;
}
.add-button {
position: absolute;
margin-top: 1em;
background-color: green;
color: white;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 5px;
}
.add-button:hover {
background-color: darkgreen;
}
.modal-container {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
backdrop-filter: blur(10px);
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
background-color: #fff;
padding: 20px;
border-radius: 16px;
width: 100%;
max-width: 500px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.modal-header, .modal-footer, .modal-footer-2 {
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-header {
position: relative;
}
.modal-header h1 {
flex: 1;
text-align: center;
}
.modal-header .close-button {
position: absolute;
right: 0;
top: 0;
background: none;
border: none;
cursor: pointer;
color: #000;
font-size: 18px;
}
.modal-body {
margin-top: 20px;
}
.modal-footer, .modal-footer-2 {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
}
.custom-form-group {
display: flex;
align-items: center;
margin-bottom: 1.5rem;
}
.custom-form-group .form-label {
display: flex;
align-items: center;
font-weight: bold;
margin-right: 1rem;
min-width: 100px;
}
.custom-form-group .form-label svg {
margin-right: 0.5rem;
}
.custom-form-control {
flex: 1;
border: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.6);
border-radius: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none;
max-width: 22rem;
font-size: 1.2rem;
}
.custom-form-control:focus {
border-bottom: 1px solid rgba(0, 123, 255, 0.6);
box-shadow: none;
}
.custom-form-control::placeholder {
color: #ccc;
font-size: 0.9rem;
}
.modal-footer button {
background-color: green;
color: white;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
}
.modal-footer button:hover {
background-color: darkgreen;
}
.modal-footer-2 button {
background-color: #C8C8C8;
color: white;
border: none;
padding: 10px 20px;
font-size: 18px;
border-radius: 5px;
cursor: pointer;
}
.modal-footer-2 button:hover {
background-color: darkgray;
}
.title-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 20vh;
}
.button-container {
display: flex;
justify-content: center;
}
.add-customer-button {
margin-top: 8rem;
margin-bottom: 8rem;
background-color: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
font-size: 1rem;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.add-customer-button:hover {
background-color: #45a049;
}