Skip to content

Commit bbc6548

Browse files
committed
Pagination
1 parent 007d8bb commit bbc6548

File tree

5 files changed

+92
-16
lines changed

5 files changed

+92
-16
lines changed

app/Http/Controllers/PuppyController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ public function index(Request $request)
2222
->orWhere('trait', 'like', "%{$search}%");
2323
})
2424
->with(['user', 'likedBy'])
25-
->get()
25+
->paginate(9)
26+
->withQueryString()
2627
),
2728
'filters' => [
2829
'search' => $search,

resources/js/components/PuppiesList.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
import { type Puppy } from '../types';
1+
import { PaginatedResponse, type Puppy } from '../types';
22
import { LikeToggle } from './LikeToggle';
3+
import { Pagination } from './pagination';
34

4-
export function PuppiesList({ puppies }: { puppies: Puppy[] }) {
5+
export function PuppiesList({ puppies }: { puppies: PaginatedResponse<Puppy> }) {
56
return (
6-
<ul className="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
7-
{puppies.map((puppy) => (
8-
<PuppyCard key={puppy.id} puppy={puppy} />
9-
))}
10-
</ul>
7+
<>
8+
<ul className="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
9+
{puppies.data.map((puppy) => (
10+
<PuppyCard key={puppy.id} puppy={puppy} />
11+
))}
12+
</ul>
13+
<Pagination className="mt-6" meta={puppies.meta} links={puppies.links} />
14+
</>
1115
);
1216
}
1317

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { cn } from '@/lib/utils';
2+
import { PaginationLinks, PaginationMeta } from '@/types';
3+
import { Link } from '@inertiajs/react';
4+
import { ChevronLeft, ChevronRight } from 'lucide-react';
5+
import { Button } from './ui/button';
6+
7+
type PaginationProps = {
8+
meta: PaginationMeta;
9+
links: PaginationLinks;
10+
className?: string;
11+
};
12+
13+
export function Pagination({ meta, links, className }: PaginationProps) {
14+
return (
15+
<div className={cn('flex items-center justify-between', className)}>
16+
<div>
17+
{links.prev && (
18+
<Button variant="ghost" asChild>
19+
<Link preserveScroll href={links.prev}>
20+
<ChevronLeft className="size-4" />
21+
<span>Previous</span>
22+
</Link>
23+
</Button>
24+
)}
25+
</div>
26+
<p className="text-sm font-medium">
27+
page {meta.current_page} of {meta.last_page}
28+
</p>
29+
<div>
30+
{links.next && (
31+
<Button variant="ghost" asChild>
32+
<Link preserveScroll href={links.next}>
33+
<span>Next</span>
34+
<ChevronRight className="size-4" />
35+
</Link>
36+
</Button>
37+
)}
38+
</div>
39+
</div>
40+
);
41+
}

resources/js/pages/puppies/index.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,33 @@ import { PuppiesList } from '@/components/PuppiesList';
66
import { Search } from '@/components/Search';
77
import { Shortlist } from '@/components/Shortlist';
88

9-
import { Filters, Puppy, SharedData } from '@/types';
9+
import { Filters, PaginatedResponse, Puppy, SharedData } from '@/types';
1010
import { usePage } from '@inertiajs/react';
1111
import { useState } from 'react';
1212

13-
export default function App({ puppies, filters }: { puppies: Puppy[]; filters: Filters }) {
13+
export default function App({ puppies, filters }: { puppies: PaginatedResponse<Puppy>; filters: Filters }) {
1414
return (
1515
<PageWrapper>
1616
<Container>
1717
<Header />
18-
<Main inertiaPuppies={puppies} filters={filters} />
18+
<Main paginatedPuppies={puppies} filters={filters} />
1919
</Container>
2020
</PageWrapper>
2121
);
2222
}
2323

24-
function Main({ inertiaPuppies, filters }: { inertiaPuppies: Puppy[]; filters: Filters }) {
25-
const [puppies, setPuppies] = useState<Puppy[]>(inertiaPuppies);
24+
function Main({ paginatedPuppies, filters }: { paginatedPuppies: PaginatedResponse<Puppy>; filters: Filters }) {
25+
const [puppies, setPuppies] = useState<Puppy[]>(paginatedPuppies.data);
2626
const { auth } = usePage<SharedData>().props;
2727

2828
return (
2929
<main>
3030
<div className="mt-24 grid gap-8 sm:grid-cols-2">
3131
<Search filters={filters} />
32-
{auth.user && <Shortlist puppies={inertiaPuppies} />}
32+
{auth.user && <Shortlist puppies={paginatedPuppies.data} />}
3333
</div>
34-
<PuppiesList puppies={inertiaPuppies} />
35-
<NewPuppyForm puppies={inertiaPuppies} setPuppies={setPuppies} />
34+
<PuppiesList puppies={paginatedPuppies} />
35+
<NewPuppyForm puppies={paginatedPuppies.data} setPuppies={setPuppies} />
3636
</main>
3737
);
3838
}

resources/js/types/index.d.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,33 @@ export interface Filters {
5555
search?: string;
5656
[key: string]: unknown;
5757
}
58+
59+
export interface PaginationLink {
60+
url: string | null;
61+
label: string;
62+
active: boolean;
63+
}
64+
65+
export interface PaginationMeta {
66+
current_page: number;
67+
from: number | null;
68+
last_page: number;
69+
links: PaginationLink[];
70+
path: string;
71+
per_page: number;
72+
to: number | null;
73+
total: number;
74+
}
75+
76+
export interface PaginationLinks {
77+
first: string | null;
78+
last: string | null;
79+
prev: string | null;
80+
next: string | null;
81+
}
82+
83+
export interface PaginatedResponse<T> {
84+
data: T[];
85+
meta: PaginationMeta;
86+
links: PaginationLinks;
87+
}

0 commit comments

Comments
 (0)