enh
This commit is contained in:
parent
dc644aef7e
commit
ffaade32d6
1 changed files with 158 additions and 31 deletions
|
|
@ -1,31 +1,61 @@
|
|||
import { useState } from 'react'
|
||||
import { useState, useCallback } from 'react'
|
||||
import { trpc } from '@/trpc/client'
|
||||
|
||||
export function UserConnectRoute() {
|
||||
const [search, setSearch] = useState('')
|
||||
const [searchInput, setSearchInput] = useState('')
|
||||
const [cursor, setCursor] = useState<number | undefined>(undefined)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [visitedCursors, setVisitedCursors] = useState<(number | undefined)[]>([undefined])
|
||||
const [itemsPerPage, setItemsPerPage] = useState(50)
|
||||
|
||||
const cursor = visitedCursors[currentPage - 1]
|
||||
|
||||
const { data, isLoading, error } = trpc.admin.user.getAllUsers.useQuery({
|
||||
limit: 50,
|
||||
limit: itemsPerPage,
|
||||
cursor,
|
||||
search,
|
||||
})
|
||||
|
||||
const handleSearch = () => {
|
||||
setSearch(searchInput)
|
||||
setCursor(undefined)
|
||||
setCurrentPage(1)
|
||||
setVisitedCursors([undefined])
|
||||
}
|
||||
|
||||
const handleNextPage = () => {
|
||||
if (data?.nextCursor) {
|
||||
setCursor(data.nextCursor)
|
||||
}
|
||||
const newCursors = [...visitedCursors]
|
||||
newCursors[currentPage] = data.nextCursor
|
||||
setVisitedCursors(newCursors)
|
||||
setCurrentPage(currentPage + 1)
|
||||
}
|
||||
}
|
||||
|
||||
const handlePrevPage = () => {
|
||||
setCursor(undefined)
|
||||
if (currentPage > 1) {
|
||||
setCurrentPage(currentPage - 1)
|
||||
}
|
||||
}
|
||||
|
||||
const handlePageSelect = (page: number) => {
|
||||
setCurrentPage(page)
|
||||
}
|
||||
|
||||
const handleClearSearch = () => {
|
||||
setSearch('')
|
||||
setSearchInput('')
|
||||
setCurrentPage(1)
|
||||
setVisitedCursors([undefined])
|
||||
}
|
||||
|
||||
const handleItemsPerPageChange = (newLimit: number) => {
|
||||
setItemsPerPage(newLimit)
|
||||
setCurrentPage(1)
|
||||
setVisitedCursors([undefined])
|
||||
}
|
||||
|
||||
const totalPages = Math.min(currentPage + (data?.hasMore ? 3 : 0), 20)
|
||||
const pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1)
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
|
|
@ -76,11 +106,7 @@ export function UserConnectRoute() {
|
|||
</button>
|
||||
{search && (
|
||||
<button
|
||||
onClick={() => {
|
||||
setSearch('')
|
||||
setSearchInput('')
|
||||
setCursor(undefined)
|
||||
}}
|
||||
onClick={handleClearSearch}
|
||||
className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors"
|
||||
>
|
||||
Clear
|
||||
|
|
@ -88,6 +114,75 @@ export function UserConnectRoute() {
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center mb-4 pb-4 border-b border-gray-200">
|
||||
<div className="flex items-center gap-4">
|
||||
<p className="text-sm text-gray-600">
|
||||
Page {currentPage} • Showing {data?.users.length || 0} users
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<label className="text-sm text-gray-600">Per page:</label>
|
||||
<select
|
||||
value={itemsPerPage}
|
||||
onChange={(e) => handleItemsPerPageChange(Number(e.target.value))}
|
||||
className="px-2 py-1 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value={10}>10</option>
|
||||
<option value={25}>25</option>
|
||||
<option value={50}>50</option>
|
||||
<option value={100}>100</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{pageNumbers.length > 1 && (
|
||||
<>
|
||||
<button
|
||||
onClick={handlePrevPage}
|
||||
disabled={currentPage === 1}
|
||||
className={`px-3 py-1.5 rounded-md transition-colors ${
|
||||
currentPage === 1
|
||||
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||
}`}
|
||||
>
|
||||
‹
|
||||
</button>
|
||||
|
||||
{pageNumbers.map((page) => (
|
||||
<button
|
||||
key={page}
|
||||
onClick={() => handlePageSelect(page)}
|
||||
className={`px-3 py-1.5 rounded-md transition-colors ${
|
||||
currentPage === page
|
||||
? 'bg-blue-600 text-white'
|
||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||
}`}
|
||||
>
|
||||
{page}
|
||||
</button>
|
||||
))}
|
||||
|
||||
{data?.hasMore && currentPage >= totalPages - 2 && (
|
||||
<span className="px-2 text-gray-400">...</span>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={handleNextPage}
|
||||
disabled={!data?.hasMore}
|
||||
className={`px-3 py-1.5 rounded-md transition-colors ${
|
||||
!data?.hasMore
|
||||
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||
}`}
|
||||
>
|
||||
›
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
|
|
@ -147,25 +242,57 @@ export function UserConnectRoute() {
|
|||
</div>
|
||||
|
||||
<div className="flex justify-between items-center mt-4 pt-4 border-t border-gray-200">
|
||||
<p className="text-sm text-gray-600">
|
||||
Showing {data?.users.length || 0} users
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
{cursor !== undefined && (
|
||||
<button
|
||||
onClick={handlePrevPage}
|
||||
className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
)}
|
||||
{data?.hasMore && (
|
||||
<button
|
||||
onClick={handleNextPage}
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
<div className="flex items-center gap-4">
|
||||
<p className="text-sm text-gray-600">
|
||||
Page {currentPage} • Showing {data?.users.length || 0} users
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{pageNumbers.length > 1 && (
|
||||
<>
|
||||
<button
|
||||
onClick={handlePrevPage}
|
||||
disabled={currentPage === 1}
|
||||
className={`px-3 py-1.5 rounded-md transition-colors ${
|
||||
currentPage === 1
|
||||
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||
}`}
|
||||
>
|
||||
‹
|
||||
</button>
|
||||
|
||||
{pageNumbers.map((page) => (
|
||||
<button
|
||||
key={page}
|
||||
onClick={() => handlePageSelect(page)}
|
||||
className={`px-3 py-1.5 rounded-md transition-colors ${
|
||||
currentPage === page
|
||||
? 'bg-blue-600 text-white'
|
||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||
}`}
|
||||
>
|
||||
{page}
|
||||
</button>
|
||||
))}
|
||||
|
||||
{data?.hasMore && currentPage >= totalPages - 2 && (
|
||||
<span className="px-2 text-gray-400">...</span>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={handleNextPage}
|
||||
disabled={!data?.hasMore}
|
||||
className={`px-3 py-1.5 rounded-md transition-colors ${
|
||||
!data?.hasMore
|
||||
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||
}`}
|
||||
>
|
||||
›
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue