Move Pagination Outside Scrollable Area | Add smooth transition dropdown rows per page select | adjust sync button

This commit is contained in:
fadingNA
2024-11-23 18:06:54 -05:00
parent 25b1173db7
commit f01f76dba7
3 changed files with 112 additions and 70 deletions

View File

@@ -19,7 +19,10 @@ const Pagination: React.FC<PaginationProps> = ({
onPageChange,
onRowsPerPageChange,
}) => {
const [rowsPerPageOptions] = useState([5, 10, 15, 20]);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const rowsPerPageOptions = [5, 10, 20, 50];
const toggleDropdown = () => setIsDropdownOpen((prev) => !prev);
const handlePreviousPage = () => {
if (currentPage > 1) {
@@ -41,31 +44,51 @@ const Pagination: React.FC<PaginationProps> = ({
onPageChange(totalPages);
};
const handleSelectRowsPerPage = (rows: number) => {
setIsDropdownOpen(false);
onRowsPerPageChange(rows);
};
return (
<div className="flex items-center text-xs justify-end gap-4 mt-2 p-2 border-gray-200">
<div className="flex items-center gap-2 ">
<div className="flex items-center text-xs justify-end gap-4 mt-2 p-2 border-gray-200">
{/* Rows per page dropdown */}
<div className="flex items-center gap-2 relative">
<span className="text-gray-900 dark:text-gray-50">Rows per page:</span>
<select
value={rowsPerPage}
onChange={(e) => onRowsPerPageChange(Number(e.target.value))}
className="border border-gray-300 rounded px-2 py-1 dark:bg-dark-charcoal dark:text-gray-50"
>
{rowsPerPageOptions.map((option) => (
<option
className="bg-white dark:bg-dark-charcoal dark:text-gray-50"
key={option}
value={option}
>
{option}
</option>
))}
</select>
<div className="relative">
<button
onClick={toggleDropdown}
className="px-3 py-1 border rounded dark:bg-dark-charcoal dark:text-light-gray hover:bg-gray-200 dark:hover:bg-neutral-700"
>
{rowsPerPage}
</button>
<div
className={`absolute z-50 right-0 mt-1 w-28 transform bg-white shadow-lg ring-1 ring-black ring-opacity-5 transition-all duration-200 ease-in-out ${
isDropdownOpen
? 'scale-100 opacity-100 visible'
: 'scale-95 opacity-0 invisible'
}`}
>
{rowsPerPageOptions.map((option) => (
<div
key={option}
onClick={() => handleSelectRowsPerPage(option)}
className={`cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 dark:hover:bg-neutral-700 ${
rowsPerPage === option
? 'bg-gray-100 dark:bg-neutral-700 dark:text-light-gray'
: 'bg-white dark:bg-dark-charcoal dark:text-light-gray'
}`}
>
{option}
</div>
))}
</div>
</div>
</div>
{/* Pagination controls */}
<div className="text-gray-900 dark:text-gray-50">
Page {currentPage} of {totalPages}
</div>
<div className="flex items-center gap-2 text-gray-900 dark:text-gray-50">
<button
onClick={handleFirstPage}
@@ -74,7 +97,7 @@ const Pagination: React.FC<PaginationProps> = ({
>
<img
src={DoubleArrowLeft}
alt="arrow"
alt="First page"
className="dark:invert dark:sepia dark:brightness-200"
/>
</button>
@@ -85,7 +108,7 @@ const Pagination: React.FC<PaginationProps> = ({
>
<img
src={SingleArrowLeft}
alt="arrow"
alt="Previous page"
className="dark:invert dark:sepia dark:brightness-200"
/>
</button>
@@ -96,7 +119,7 @@ const Pagination: React.FC<PaginationProps> = ({
>
<img
src={SingleArrowRight}
alt="arrow"
alt="Next page"
className="dark:invert dark:sepia dark:brightness-200"
/>
</button>
@@ -107,7 +130,7 @@ const Pagination: React.FC<PaginationProps> = ({
>
<img
src={DoubleArrowRight}
alt="arrow"
alt="Last page"
className="dark:invert dark:sepia dark:brightness-200"
/>
</button>

View File

@@ -48,7 +48,7 @@ export default function DropdownMenu({
<div className="static inline-block text-left" ref={dropdownRef}>
<button
onClick={handleToggle}
className="flex w-20 cursor-pointer flex-row items-center gap-px rounded-3xl border-purple-30/25 bg-purple-30 p-2 text-xs text-white hover:bg-[#6F3FD1] focus:outline-none"
className="flex w-20 cursor-pointer flex-row gap-1 rounded-3xl border-purple-30/25 bg-purple-30 p-2 text-xs text-white hover:bg-[#6F3FD1] focus:outline-none"
>
{icon && <img src={icon} alt="OptionIcon" className="h-4 w-4" />}
{selectedOption.value !== 'never' ? selectedOption.label : name}

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useCallback } from 'react';
import PropTypes from 'prop-types';
import userService from '../api/services/userService';
import SyncIcon from '../assets/sync.svg';
@@ -59,34 +59,50 @@ const Documents: React.FC<DocumentsProps> = ({
{ label: 'Monthly', value: 'monthly' },
];
const refreshDocs = (
field: 'date' | 'tokens' | undefined,
pageNumber?: number,
rows?: number,
) => {
const page = pageNumber ?? currentPage;
const rowsPerPg = rows ?? rowsPerPage;
const refreshDocs = useCallback(
(
field: 'date' | 'tokens' | undefined,
pageNumber?: number,
rows?: number,
) => {
const page = pageNumber ?? currentPage;
const rowsPerPg = rows ?? rowsPerPage;
if (field !== undefined) {
if (field === sortField) {
// Toggle sort order
setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc');
} else {
// Change sort field and reset order to 'desc'
setSortField(field);
setSortOrder('desc');
// If field is undefined, (Pagination or Search) use the current sortField
const newSortField = field ?? sortField;
// If field is undefined, (Pagination or Search) use the current sortOrder
const newSortOrder =
field === sortField
? sortOrder === 'asc'
? 'desc'
: 'asc'
: sortOrder;
// If field is defined, update the sortField and sortOrder
if (field) {
setSortField(newSortField);
setSortOrder(newSortOrder);
}
}
getDocsWithPagination(sortField, sortOrder, page, rowsPerPg, searchTerm)
.then((data) => {
dispatch(setPaginatedDocuments(data ? data.docs : []));
setTotalPages(data ? data.totalPages : 0);
})
.catch((error) => console.error(error))
.finally(() => {
setLoading(false);
});
};
getDocsWithPagination(
newSortField,
newSortOrder,
page,
rowsPerPg,
searchTerm,
)
.then((data) => {
dispatch(setPaginatedDocuments(data ? data.docs : []));
setTotalPages(data ? data.totalPages : 0);
})
.catch((error) => console.error(error))
.finally(() => {
setLoading(false);
});
},
[currentPage, rowsPerPage, sortField, sortOrder, searchTerm],
);
const handleManageSync = (doc: Doc, sync_frequency: string) => {
setLoading(true);
@@ -118,13 +134,15 @@ const Documents: React.FC<DocumentsProps> = ({
};
useEffect(() => {
console.log('modalState', modalState);
if (modalState === 'INACTIVE') {
refreshDocs(sortField, currentPage, rowsPerPage);
}
}, [modalState, sortField, currentPage, rowsPerPage]);
}, [modalState]);
useEffect(() => {
refreshDocs(sortField, 1, rowsPerPage);
// undefine to prevent reset the sort order
refreshDocs(undefined, 1, rowsPerPage);
}, [searchTerm]);
return (
@@ -151,6 +169,7 @@ const Documents: React.FC<DocumentsProps> = ({
</div>
<button
className="rounded-full w-40 bg-purple-30 px-4 py-3 text-white hover:bg-[#6F3FD1]"
title="Add New Document"
onClick={() => {
setIsOnboarding(false); // Set onboarding flag if needed
setModalState('ACTIVE'); // Open the upload modal
@@ -165,7 +184,7 @@ const Documents: React.FC<DocumentsProps> = ({
<div className="flex flex-col">
<div className="flex-grow">
<div className="dark:border-silver/40 border-silver rounded-xl border overflow-auto">
<table className="min-w-full divide-y divide-gray-200 ">
<table className="min-w-full divide-y divide-silver dark:divide-silver/40 ">
<thead>
<tr>
<th className="px-5 py-3 text-start text-sm font-medium text-gray-700 dark:text-gray-50 uppercase">
@@ -269,26 +288,26 @@ const Documents: React.FC<DocumentsProps> = ({
</tbody>
</table>
</div>
<div className="mt-4">
<Pagination
currentPage={currentPage}
totalPages={totalPages}
rowsPerPage={rowsPerPage}
onPageChange={(page) => {
setCurrentPage(page);
refreshDocs(sortField, page, rowsPerPage);
}}
onRowsPerPageChange={(rows) => {
setRowsPerPage(rows);
setCurrentPage(1);
refreshDocs(sortField, 1, rows);
}}
/>
</div>
</div>
</div>
)}
</div>
{/* outside scrollable area */}
<Pagination
currentPage={currentPage}
totalPages={totalPages}
rowsPerPage={rowsPerPage}
onPageChange={(page) => {
setCurrentPage(page);
refreshDocs(undefined, page, rowsPerPage);
}}
onRowsPerPageChange={(rows) => {
setRowsPerPage(rows);
setCurrentPage(1);
refreshDocs(undefined, 1, rows);
}}
/>
{/* Conditionally render the Upload modal based on modalState */}
{modalState === 'ACTIVE' && (
<div className="fixed top-0 left-0 w-screen h-screen z-50 flex items-center justify-center bg-transparent">