How to increase height of a table cell if the content overflows - reactjs

I'm coding a credit log system in react using firebase realtime database. I have something like this:
and I'd like to have it so that when the content is really long it doesn't result in a scroll bar but rather causes the height of the cell to increase. I've tried doing some messing around but I'm not so proficient in tailwind. I've attached the code below.
import React, {useState, useEffect} from "react";
import PropTypes from "prop-types";
import firebase from "Firebase"
import TableDropdown from "components/Dropdowns/TableDropdown.js";
// Todo: Make this more module through adding component/variable for each cell
export default function MyCreditLog({ color }) {
const [creditData, setCreditData] = useState([]);
useEffect(() => {
let ref = firebase.database().ref("/creditlogs/"+firebase.auth().currentUser.uid)
console.log(firebase.auth().currentUser.uid)
ref.on("value", snapshot => {
const state = snapshot.val()
setCreditData(Object.values(state))
console.log(state)
})
}, [])
return (
<>
<div
className={
"relative flex flex-col min-w-0 break-words w-full mb-6 shadow-lg rounded " +
(color === "light" ? "bg-white" : "bg-blue-900 text-white")
}
>
<div className="rounded-t mb-0 px-4 py-3 border-0">
<div className="flex flex-wrap items-center">
<div className="relative w-full px-4 max-w-full flex-grow flex-1">
<h3
className={
"font-semibold text-lg " +
(color === "light" ? "text-gray-800" : "text-white")
}
>
My Credit Log
</h3>
</div>
</div>
</div>
<div className="block w-full overflow-x-auto">
{/* Projects table */}
<table className="items-center w-full bg-transparent border-collapse">
<thead>
<tr className="overflow-x-hidden">
<th
className={
"px-6 align-middle border border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-no-wrap font-semibold text-left " +
(color === "light"
? "bg-gray-100 text-gray-600 border-gray-200"
: "bg-blue-800 text-blue-300 border-blue-700")
}
>
Date
</th>
<th
className={
"px-6 align-middle border border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-no-wrap font-semibold text-left " +
(color === "light"
? "bg-gray-100 text-gray-600 border-gray-200"
: "bg-blue-800 text-blue-300 border-blue-700")
}
>
Time In
</th>
<th
className={
"px-6 align-middle border border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-no-wrap font-semibold text-left " +
(color === "light"
? "bg-gray-100 text-gray-600 border-gray-200"
: "bg-blue-800 text-blue-300 border-blue-700")
}
>
Time Out
</th>
<th
className={
"px-6 align-middle border border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-no-wrap font-semibold text-left " +
(color === "light"
? "bg-gray-100 text-gray-600 border-gray-200"
: "bg-blue-800 text-blue-300 border-blue-700")
}
>
Type
</th>
<th
className={
"px-6 align-middle border border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-no-wrap font-semibold text-left " +
(color === "light"
? "bg-gray-100 text-gray-600 border-gray-200"
: "bg-blue-800 text-blue-300 border-blue-700")
}
>
Description
</th>
<th
className={
"px-6 align-middle border border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-no-wrap font-semibold text-left " +
(color === "light"
? "bg-gray-100 text-gray-600 border-gray-200"
: "bg-blue-800 text-blue-300 border-blue-700")
}></th>
</tr>
</thead>
<tbody>
{/* loop through fetched credit data and add rows */}
{creditData.map((credit, index) => {
return (<tr key={index}>
<th className="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-no-wrap p-4 text-left flex items-center">
{credit.date}
</th>
<td className="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-no-wrap p-4">
{credit.timeIn}
</td>
<td className="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-no-wrap p-4">
{credit.timeOut}
</td>
<td className="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-no-wrap p-4">
{credit.type}
</td>
<td className="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-no-wrap p-4">
{credit.description}
</td>
<td className="border-t-0 px-6 align-middle border-l-0 border-r-0 text-xs whitespace-no-wrap p-4 text-right">
<TableDropdown />
</td>
</tr>)
})}
</tbody>
</table>
</div>
</div>
</>
);
}
MyCreditLog.defaultProps = {
color: "light",
};
MyCreditLog.propTypes = {
color: PropTypes.oneOf(["light", "dark"]),
};

What a stupid question. I removed the "whitespace-no-wrap" class from each element and it worked perfectly.

Related

Why isn't col-span spanning the full table width

This is my table code, using React and Tailwind CSS. There is one peculiarity: when col-span turns 8, it works as expected. But when it turns 12, it breaks.
I want the table to expand to 12 cols, but it only expands to 10. If I use 11 or 12 it goes to 1, no matter what I used for colspan.
<div className={`flex flex-col lg:col-span-${order.smopen ? 8 : 12}`}>
<div className="overflow-x-auto">
<div className="align-middle inline-block min-w-full">
<div className="shadow overflow-hidden border-b border-gray-200">
<table
className={`min-w-full divide-y divide-gray-200 lg:col-span-${
order.smopen ? 8 : 12
}`}
>
<thead
className={`min-w-full divide-y divide-gray-200 lg:col-span-${
order.smopen ? 8 : 12
}`}
>
<tr>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Тема
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Дедлайн
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Статус
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Сумма
</th>
</tr>
</thead>
<tbody
className={`min-w-full divide-y divide-gray-200 lg:col-span-${
order.smopen ? 8 : 12
}`}
>
{orders.map((order, orderIdx) => (
<tr
onClick={() =>
orderDispatch({
type: "selected",
payload: {
smopen: true,
title: order.title,
dateDeadline: new Date(order.dateDeadline).toLocaleString(
"ru-RU",
{
year: "numeric",
month: "long",
day: "numeric",
}
),
status: order.status,
sum: order.sum,
},
})
}
key={order.id}
className={
orderIdx % 2 === 0
? "bg-white hover:bg-gray-100 cursor-pointer transition-all ease-in-out"
: "transition-all ease-in-out cursor-pointer bg-gray-50 hover:bg-gray-100"
}
>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{order.title}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{new Date(order.dateDeadline).toLocaleString("ru-RU", {
year: "numeric",
month: "long",
day: "numeric",
})}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{orderTypeSwitch(order.status)}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{order.sum} ₽
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>;
How can I fix this to have my table span the whole 12 columns?

Passing function to modal in ReactJs

In an application in ReactJs, I am trying to use a modal to confirm the deletion of a user. Normally I have a delete function created in the users table that deletes a user from my database. Now I would like to pass this functionality to the modal. I am wondering how I can easily pass the delete function to the modal. That when I confirm the delete action in modal a user is deleted. I would be grateful for any guidance.
MyModal.js
import React from "react";
export default function MyModal() {
const [showModal, setShowModal] = React.useState(false);
return (
<>
<button
className="bg-red-600 text-white active:bg-pink-600 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
type="button"
onClick={() => setShowModal(true)}
>
Delete
</button>
{showModal ? (
<>
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
<div className="relative w-auto my-6 mx-auto max-w-3xl">
{/*content*/}
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
{/*header*/}
<div className="flex items-start justify-between p-5 border-b border-solid border-slate-200 rounded-t">
<h3 className="text-3xl font-semibold">Modal Title</h3>
<button
className="p-1 ml-auto bg-transparent border-0 text-black opacity-5 float-right text-3xl leading-none font-semibold outline-none focus:outline-none"
onClick={() => setShowModal(false)}
>
<span className="bg-transparent text-black opacity-5 h-6 w-6 text-2xl block outline-none focus:outline-none">
×
</span>
</button>
</div>
{/*body*/}
<div className="relative p-6 flex-auto">
<p className="my-4 text-slate-500 text-lg leading-relaxed">
Are you sure you want to delete this user?
</p>
</div>
{/*footer*/}
<div className="flex items-center justify-end p-6 border-t border-solid border-slate-200 rounded-b">
<button
className="text-blue-600 background-transparent font-bold uppercase px-6 py-2 text-sm outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
type="button"
onClick={() => setShowModal(false)}
>
Close
</button>
<button
className="bg-red-600 text-white active:bg-emerald-600 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150"
type="button"
onClick={() => setShowModal(false)}
>
Delete
</button>
</div>
</div>
</div>
</div>
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</>
);
}
ManageUser.js
import { useEffect, useState } from "react";
import { useAuthContext } from "../hooks/useAuthContext";
import MyModal from "../components/MyModal"
import LoadingSpinner from "../components/LoadingSpinner";
function ManageUser() {
const [users, setUser] = useState([]);
const [loading, setLoading] = useState(false)
useEffect(() => {
getData();
}, []);
async function deleteOperation(_id) {
let result = await fetch(`/api/user/${_id}`, {
method: "DELETE",
});
result = await result.json();
console.warn(result);
getData();
}
async function getData() {
setLoading(true)
let result = await fetch("/api/user/users");
result = await result.json();
setUser(result);
setLoading(false)
}
return (
<div>
<h1 className="flex justify-center py-4 text-xl font-bold">Zarządzaj użytkownikami:</h1>
<div className="flex justify-center py-2">
<div className="flex justify-between items-center h-30 max-w-[1240px] mx-auto px-4">
{ loading ? (<div className="flex justify-center items-center "><LoadingSpinner/></div>) :
<div className=" overflow-x-auto relative shadow-md sm:rounded-lg">
<table className="w-full text-sm text-center text-white">
<thead className="text-xs text-white uppercase bg-rgba(6, 18, 36, 0.945)">
<tr>
<th scope="col" className="py-3 px-6">
Nazwa
</th>
<th scope="col" className="py-3 px-6 hidden sm:table-cell">
Email
</th>
<th scope="col" className="py-3 px-6">
Admin
</th>
<th scope="col" className="py-3 px-6">
</th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user._id} user={user} className="bg-rgba(6, 18, 36, 0.945) border-b border-[#00df9a] ">
<th scope="row" className="py-4 px-6 font-medium text-white whitespace-nowrap">
{user.name}
</th>
<td className="py-4 px-6 hidden sm:table-cell">
{user.email}
</td>
<td className="py-4 px-6">
{user.isAdmin ? "Tak" : "Nie"}
</td>
<td className="py-4 px-6 text-right">
<MyModal/><button className="bg-red-500 hover:bg-[#00df9a] text-white font-semibold py-2 px-4 border border-zinc-900 rounded shadow" onClick={() => deleteOperation(user._id)}>Delete</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
}
</div>
</div>
</div>
);
}
export default ManageUser;
Is there any quick way to pass the function that I use for deleting a user to this modal?
You could just pass a property to your model component, lets call it onSubmit
export default function MyModal( { onSubmit } ) {
Within your modal you can handle the submitting with a submitHandler like
const submitHandler = () => {
setShowModal(false);
onSubmit();
}
Your delete button in the MyModal can call this submitHandler like
<button onClick={submitHandler}>
Delete
</button>
and within your ManageUser component you could pass the deleteOperation as the onSubmit function like
<MyModal onSubmit={() => deleteOperation(user.id)}/>

How to solve the error Parsing error: Missing semicolon?

I am developing a search bar that performs the search by calling an api, I encounter an error: Parsing error: Missing semicolon. The error comes from this part of the code:
const form = event.target as HTMLFormElement;
specifically between the event.target and the as. Could someone explain me the reason of this error and how to solve it?
import React, { FormEvent, useState, useEffect } from "react";
import Select, { SingleValue } from "react-select";
import { getCollegiate } from "../../api/drupalAPI";
import { Collegiate } from "#icofcv/common";
import Loader from "../spinner/Loader";
interface Props {
showModal: boolean;
closeModal: () => void;
}
export const ModalFilterCollegiate: React.FC<Props> = ({
children,
showModal,
closeModal,
}) => {
const [collegiateList, setCollegiateList] = useState<Collegiate[]>([]);
const [collegiateSearch, setCollegiateSearch] = useState("");
const searchForCollegiates = async (query: String): Promise<Collegiate[]> => {
const result = await fetch(`/collegiate?filter=${query}`);
return (await result.json()).results;
};
useEffect(() => {
(async () => {
const query = encodeURIComponent(collegiateSearch);
const response = await searchForCollegiates(query);
setCollegiateList(response);
})();
}, [collegiateSearch]);
const search = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
const form = event.target as HTMLFormElement;
const input = form.querySelector("#searchText") as HTMLInputElement;
setCollegiateSearch(input.value);
input.value = "";
};
return (
<>
<div>
{showModal ? (
<>
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none">
<div className="relative p-2 w-full max-w-2xl h-full md:h-auto">
{/*content*/}
<div className="relative bg-white rounded-lg shadow">
{/*header*/}
<div className="flex justify-between items-start px-4 py-3 rounded-t border-b">
<h3 className="text-lg font-medium">Buscar Colegiado</h3>
<button
className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center"
onClick={closeModal}
>
<svg
aria-hidden="true"
className="w-5 h-5"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clip-rule="evenodd"
></path>
</svg>
</button>
</div>
{/*body*/}
<div className="relative px-3 py-3 flex-auto overflow-auto modal-body">
<form
className="searchForm"
onSubmit={(event) => search(event)}
>
<div className="grid md:grid-cols-2 md:gap-4">
<div className="relative z-0 w-full group my-2">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Número colegiado
</label>
<input
name=""
type="text"
id=""
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
/>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
</div>
<div className="grid md:grid-cols-2 md:gap-4">
<div className="relative z-0 w-full group my-2">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Nombre
</label>
<input
name=""
type="text"
id="searchText"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
/>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
<div className="relative z-0 w-full group my-2">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Apellidos
</label>
<input
name=""
type="text"
id=""
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
/>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
</div>
<div className="grid md:grid-cols-2 md:gap-4">
<div className="relative z-0 w-full group">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Provincia
</label>
<select className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
<option>Cualquier Provincia</option>
</select>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
<div className="relative z-0 w-full group">
<label
htmlFor=""
className="block mb-2 text-xs font-medium text-stone-600"
>
Tipo
</label>
<select className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
<option>Seleccionar tipo</option>
<option>Ejercientes</option>
<option>No ejercientes</option>
<option>Honorarios</option>
<option>Colegiados de honor</option>
</select>
<p className="mt-2 text-xs text-red-600 hidden">
Completa este espacio
</p>
</div>
</div>
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-slate-200 rounded-b gap-2">
<button
className="btn text-black text-sm background-transparent px-8 outline-none focus:outline-none focus:ring-teal-600 focus:border-teal-600"
type="button"
onClick={closeModal}
>
Cancelar
</button>
<button
className="btn bg-teal-600 hover:bg-teal-700 text-white text-sm active:bg-teal-700 px-8 outline-none focus:outline-none"
type="button"
>
Buscar
</button>
</div>
</form>
</div>
{/*footer*/}
{collegiateList.map((collegiate) => (
<tr key={collegiate.id} className="bg-white border-b">
<td className="py-2 px-6">{collegiate.color}</td>
<td className="py-2 px-6">{collegiate.collegiate}</td>
<td className="py-2 px-6">{collegiate.firstname}</td>
<td className="py-2 px-6">{collegiate.lastname}</td>
<td className="py-2 px-6">{collegiate.provincia}</td>
</tr>
))}
</div>
</div>
</div>
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</div>
</>
);
};

validateDOMNesting(...): <td> cannot appear as a child of <tbody>. even the Structure is ok

The structure is ok but I do get this error
But I dont have any <td> inside <tbody> only <td>s inside <tr>
my code is
<table className="min-w-full divide-y divide-gray-200 ">
<thead className="bg-gray-100">
<tr>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<input
onChange={(e) => {
setAllChecked(!allChecked);
setData(data.map(item => {
return {...item, isChecked: !allChecked}
}))
if (allChecked) {
setSelectedRows([])
} else if (!allChecked) {
setSelectedRows(data);
}
}}
checked={allChecked}
id="remember-me"
name="remember-me"
type="checkbox"
className="h-4 w-4 text-red-600 focus:ring-red-500 border-gray-300 rounded"
/>
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Product Name / Product id
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Product Category
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Brand
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Price
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Stock
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Status
</th>
<th scope="col" className="relative px-6 py-3">
<span className="sr-only">Action</span>
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{data.length > 0 ? <>
{data.map((product) => (
<tr
className={`${data.indexOf(product) % 2 === 0 ? 'bg-gray-50' : 'bg-white'}`}
key={product.id}>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<input
onChange={() => {
setData(data.map((item) => {
if (item.id === product.id) {
item.isChecked = !item.isChecked;
}
return item;
}));
setSelectedRows(data.filter((item) => item.isChecked));
}}
checked={product.isChecked}
id="remember-me"
name="remember-me"
type="checkbox"
className="h-4 w-4 text-red-600 focus:ring-red-500 border-gray-300 rounded"
/>
</td>
<td className="px-6 pl-2 py-4 whitespace-nowrap">
<div className="flex items-center">
<div className="ml-4">
<div
className="text-sm font-medium text-gray-900">{product.name.length > 20 ? product.name.slice(0, 20) + '...' : product.name}</div>
<div className="text-sm text-gray-500">{product.id}</div>
</div>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap">
<div className="flex items-center">
<div className="ml-4">
<div
className="text-sm font-medium text-gray-900">{product.category}</div>
<div
className="text-sm text-gray-500">{product.mainProductCategory}</div>
</div>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap">
<div className="text-sm text-gray-900">{product.brand}</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$ {product.price}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{product.stock}</td>
<td className="px-6 py-4 whitespace-nowrap">
{product.isPublished ? <>
<span
className="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Published</span></>
: <>
<span
className="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">Not Published</span>
</>}
</td>
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<span className="relative z-0 inline-flex shadow-sm rounded-md">
<button
onClick={(x) => {
changePublishedStatus(product.id, !product.isPublished)
}}
type="button"
className={`relative inline-flex items-center py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-red-500 focus:border-red-500 ${product.isPublished ? 'px-4' : 'px-6'}`}
>
{product.isPublished ? 'Unpublish' : 'Publish'}
</button>
<button
type="button"
className="-ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-red-500 focus:border-red-500"
>
Edit
</button>
<button
onClick={() => {
deleteProduct(product.id)
}}
type="button"
className="-ml-px relative inline-flex items-center px-4 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-red-500 focus:border-red-500 "
>
Delete
</button>
</span>
</td>
</tr>
))}
</> : <>
<tr>
<td></td>
<td></td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<span
className="inline-flex items-center px-2.5 py-0.5 rounded-md text-sm font-medium bg-red-100 text-red-800">
No results found. Please refine your search or add Products.
</span>
</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</>}
</tbody>
</table>
how to fix this

Using pagination in NextJS from ExpressJS

I have an API in ExpressJS with an endpoint that pages users. A parameter is passed to the query in the api with the page number, and it takes care of the rest. Everything works normal on the API side.
I have been using actions in NextJS to make API requests. It has worked fine so far. This actions makes the request to the aforementioned endpoint:
export const getInactiveUsers = async (page) => {
try {
console.log(page)
const res = await _fetch(`${API}/user/inactives?page=${page}`, {
method: "GET",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
Authorization: `Bearer ${getCookie('token')}`,
}
})
const data = await res.json();
console.log('Data on action', data)
if (data.error) {
return data.error
}
return data
} catch (error) {
return console.error(error);
}
}
Make the request correctly. The problem is when it receives the page parameter for the first time. It always goes undefined.
An example of use is this table, which has access to the router, and receives the page number through the queries. Accessing from http://host.com/dashboard/waiting/number-of-page-passed-by-query
export default function WaitingHiringTable () {
const router = useRouter()
const { page } = router.query
const [people, setPeople] = useState([])
useEffect(() => {
loadUser()
}, [])
const loadUser = async () => {
const users = await getInactiveUsers(page)
if (users.error) {
console.log(users.error)
} else {
setPeople(users.data)
}
}
return (
<div className="flex flex-col mt-10">
<div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Name
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Email
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Phone
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
Role
</th>
<th scope="col" className="relative px-6 py-3">
<span className="sr-only">Edit</span>
</th>
</tr>
</thead>
<tbody>
{
people
.map((person, personIdx) => (
<tr key={person.email} className={personIdx % 2 === 0 ? 'bg-white' : 'bg-gray-50'}>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{person.firstName} {person.lastName}</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500"><a href={`mailto:${person.email}`}>{person.email}</a></td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500"><a href={`tel:${person.phone}`}>{person.phone}</a></td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{person.role}</td>
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button type="button" className="inline-flex items-center px-2.5 py-1.5 border border-gray-300 shadow-sm text-xs font-medium rounded text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Approve</button>
</td>
</tr>
))
}
</tbody>
</table>
{
people.length && (
<nav className="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6" aria-label="Pagination">
<div className="hidden sm:block">
<p className="text-sm text-gray-700">
Showing <span className="font-medium">1</span> to <span className="font-medium">{people.length}</span> of{' '}
<span className="font-medium">{people.length}</span> results
</p>
</div>
<div className="flex-1 flex justify-between sm:justify-end">
<button onClick={() => setNewPage(page - 1)}
className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
Previous
</button>
<button onClick={() => setNewPage(page + 1)}
className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
Next
</button>
</div>
</nav>
)
}
</div>
</div>
</div>
</div>
)
}

Resources