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'
|
import { trpc } from '@/trpc/client'
|
||||||
|
|
||||||
export function UserConnectRoute() {
|
export function UserConnectRoute() {
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
const [searchInput, setSearchInput] = 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({
|
const { data, isLoading, error } = trpc.admin.user.getAllUsers.useQuery({
|
||||||
limit: 50,
|
limit: itemsPerPage,
|
||||||
cursor,
|
cursor,
|
||||||
search,
|
search,
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
setSearch(searchInput)
|
setSearch(searchInput)
|
||||||
setCursor(undefined)
|
setCurrentPage(1)
|
||||||
|
setVisitedCursors([undefined])
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleNextPage = () => {
|
const handleNextPage = () => {
|
||||||
if (data?.nextCursor) {
|
if (data?.nextCursor) {
|
||||||
setCursor(data.nextCursor)
|
const newCursors = [...visitedCursors]
|
||||||
}
|
newCursors[currentPage] = data.nextCursor
|
||||||
|
setVisitedCursors(newCursors)
|
||||||
|
setCurrentPage(currentPage + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePrevPage = () => {
|
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) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -76,11 +106,7 @@ export function UserConnectRoute() {
|
||||||
</button>
|
</button>
|
||||||
{search && (
|
{search && (
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={handleClearSearch}
|
||||||
setSearch('')
|
|
||||||
setSearchInput('')
|
|
||||||
setCursor(undefined)
|
|
||||||
}}
|
|
||||||
className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors"
|
className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors"
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
|
|
@ -88,6 +114,75 @@ export function UserConnectRoute() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</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">
|
<div className="overflow-x-auto">
|
||||||
<table className="w-full">
|
<table className="w-full">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -147,25 +242,57 @@ export function UserConnectRoute() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-between items-center mt-4 pt-4 border-t border-gray-200">
|
<div className="flex justify-between items-center mt-4 pt-4 border-t border-gray-200">
|
||||||
<p className="text-sm text-gray-600">
|
<div className="flex items-center gap-4">
|
||||||
Showing {data?.users.length || 0} users
|
<p className="text-sm text-gray-600">
|
||||||
</p>
|
Page {currentPage} • Showing {data?.users.length || 0} users
|
||||||
<div className="flex gap-2">
|
</p>
|
||||||
{cursor !== undefined && (
|
</div>
|
||||||
<button
|
|
||||||
onClick={handlePrevPage}
|
<div className="flex items-center gap-2">
|
||||||
className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors"
|
{pageNumbers.length > 1 && (
|
||||||
>
|
<>
|
||||||
Previous
|
<button
|
||||||
</button>
|
onClick={handlePrevPage}
|
||||||
)}
|
disabled={currentPage === 1}
|
||||||
{data?.hasMore && (
|
className={`px-3 py-1.5 rounded-md transition-colors ${
|
||||||
<button
|
currentPage === 1
|
||||||
onClick={handleNextPage}
|
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||||
>
|
}`}
|
||||||
Next
|
>
|
||||||
</button>
|
‹
|
||||||
|
</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>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue