feat(improvement): add pagination to endpoints and pages + sync navbar when data changes
This commit is contained in:
@@ -10,12 +10,18 @@ import DeleteClientModal from "../components/DeleteClientModal"
|
||||
import FilterBar from "../components/FilterBar"
|
||||
import { Button } from "../components/ui/button"
|
||||
import { Card } from "../components/ui/card"
|
||||
import { Pagination } from "../components/Pagination"
|
||||
|
||||
export default function Clients() {
|
||||
const { activeWorkspace } = useWorkspace()
|
||||
const [clients, setClients] = useState<Client[]>([])
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
// Pagination States
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [totalItems, setTotalItems] = useState(0)
|
||||
const [limit, setLimit] = useState(10)
|
||||
|
||||
// Filter States
|
||||
const [searchQuery, setSearchQuery] = useState("")
|
||||
const [debouncedSearch, setDebouncedSearch] = useState("")
|
||||
@@ -37,6 +43,11 @@ export default function Clients() {
|
||||
{ value: "-updated_at", label: isFa ? "اخیراً بروزرسانی شده" : "Recently Updated" },
|
||||
]
|
||||
|
||||
// بازگشت به صفحه اول در صورت تغییر فیلتر یا جستجو
|
||||
useEffect(() => {
|
||||
setCurrentPage(1)
|
||||
}, [debouncedSearch, ordering])
|
||||
|
||||
// Debounce search input to avoid spamming the API
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
@@ -53,8 +64,14 @@ export default function Clients() {
|
||||
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const data: any = await getClients(activeWorkspace.id, debouncedSearch, ordering)
|
||||
setClients(data?.results || (Array.isArray(data) ? data : []))
|
||||
const offset = (currentPage - 1) * limit
|
||||
const data: any = await getClients(activeWorkspace.id, debouncedSearch, ordering, limit, offset)
|
||||
|
||||
const items = data?.results || (Array.isArray(data) ? data : [])
|
||||
const count = data?.count !== undefined ? data.count : items.length
|
||||
|
||||
setClients(items)
|
||||
setTotalItems(count)
|
||||
} catch (error) {
|
||||
console.error(t.clients.errors.fetchFailed, error)
|
||||
setClients([])
|
||||
@@ -76,10 +93,9 @@ export default function Clients() {
|
||||
}
|
||||
}
|
||||
|
||||
// Refetch when workspace, debounced search, or ordering changes
|
||||
useEffect(() => {
|
||||
fetchClientsList()
|
||||
}, [activeWorkspace?.id, debouncedSearch, ordering])
|
||||
}, [activeWorkspace?.id, debouncedSearch, ordering, currentPage, limit])
|
||||
|
||||
if (!activeWorkspace) {
|
||||
return (
|
||||
@@ -90,7 +106,7 @@ export default function Clients() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-6xl mx-auto min-h-[calc(100vh-73px)]">
|
||||
<div className="flex flex-col p-6 max-w-6xl mx-auto min-h-[calc(100vh-73px)]">
|
||||
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-8">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">{t.clients.title}</h1>
|
||||
@@ -114,7 +130,7 @@ export default function Clients() {
|
||||
searchPlaceholder={t.clients.searchPlaceholder}
|
||||
/>
|
||||
|
||||
<Card className="overflow-hidden dark:bg-slate-900 dark:border-slate-800">
|
||||
<Card className="overflow-hidden dark:bg-slate-900 dark:border-slate-800 mb-6">
|
||||
<div className="p-0">
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center items-center p-12 text-slate-500">
|
||||
@@ -169,6 +185,16 @@ export default function Clients() {
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{!isLoading && clients.length > 0 && (
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalCount={totalItems}
|
||||
limit={limit}
|
||||
onPageChange={setCurrentPage}
|
||||
onLimitChange={setLimit}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CreateClientModal
|
||||
isOpen={isCreateModalOpen}
|
||||
onClose={() => setIsCreateModalOpen(false)}
|
||||
|
||||
Reference in New Issue
Block a user