Skip to content

Commit ddc6b79

Browse files
committed
feat: borrows status filter
1 parent b139dd1 commit ddc6b79

File tree

4 files changed

+63
-6
lines changed

4 files changed

+63
-6
lines changed

app/(protected)/borrows/page.tsx

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import type { Metadata } from 'next'
2424
import { SITE_NAME } from '@/lib/consts'
2525
import { DropdownMenuBorrow } from '@/components/borrows/DropdownMenuBorrow'
2626
import { BtnScanReturnBorrow } from '@/components/borrows/ModalReturnBorrow'
27+
import { TabLink } from '@/components/borrows/TabLink'
2728

2829
export const metadata: Metadata = {
2930
title: `Borrows · ${SITE_NAME}`,
@@ -33,15 +34,17 @@ export default async function Borrows({
3334
searchParams,
3435
}: {
3536
searchParams: Promise<{
36-
skip?: number
37-
limit?: number
37+
skip?: string
38+
limit?: string
3839
library_id?: string
40+
status?: string
3941
}>
4042
}) {
4143
const sp = await searchParams
4244
const skip = Number(sp?.skip ?? 0)
4345
const limit = Number(sp?.limit ?? 20)
4446
const library_id = sp?.library_id
47+
const status = sp?.status as 'active' | 'overdue' | 'returned'
4548

4649
const headers = await Verify({
4750
from: '/borrows',
@@ -53,6 +56,7 @@ export default async function Borrows({
5356
sort_in: 'desc',
5457
limit: limit,
5558
skip: skip,
59+
status,
5660
...(library_id ? { library_id } : {}),
5761
},
5862
{
@@ -66,8 +70,16 @@ export default async function Borrows({
6670

6771
const prevSkip = skip - limit > 0 ? skip - limit : 0
6872

69-
const nextURL = `/borrows?skip=${skip + limit}&limit=${limit}`
70-
const prevURL = `/borrows?skip=${prevSkip}&limit=${limit}`
73+
// Build next and previous URLs, preserving existing search params except skip/limit
74+
const nextParams = new URLSearchParams(sp)
75+
nextParams.set('skip', String(skip + limit))
76+
nextParams.set('limit', String(limit))
77+
const nextURL = `/borrows?${nextParams.toString()}`
78+
79+
const prevParams = new URLSearchParams(sp)
80+
prevParams.set('skip', String(prevSkip))
81+
prevParams.set('limit', String(limit))
82+
const prevURL = `/borrows?${prevParams.toString()}`
7183

7284
return (
7385
<div className="space-y-4">
@@ -107,6 +119,17 @@ export default async function Borrows({
107119
</div>
108120
</div>
109121
</nav>
122+
<div className="">
123+
<TabLink
124+
tabs={[
125+
{ name: 'All', href: '/borrows' },
126+
{ name: 'Active', href: '/borrows?status=active' },
127+
{ name: 'Overdue', href: '/borrows?status=overdue' },
128+
{ name: 'Returned', href: '/borrows?status=returned' },
129+
]}
130+
activeHref={`/borrows${status ? `?status=${status}` : ''}`}
131+
/>
132+
</div>
110133
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
111134
{res.data.map((borrow) => (
112135
<ListCardBorrow key={borrow.id} borrow={borrow} />

components/borrows/TabLink.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { cn } from '@/lib/utils'
2+
import { ClassValue } from 'clsx'
3+
import Link from 'next/link'
4+
5+
export const TabLink: React.FC<{
6+
className?: ClassValue
7+
tabs: { name: string; href: string }[]
8+
activeHref: string
9+
}> = ({ tabs, className, activeHref }) => {
10+
return (
11+
<div
12+
className={cn(
13+
'inline-flex gap-2 w-fit items-center justify-center rounded-lg bg-muted text-muted-foreground p-[3px]',
14+
className
15+
)}
16+
>
17+
{tabs.map(({ name, href }) => (
18+
<Link
19+
replace
20+
key={href}
21+
href={href}
22+
className={cn(
23+
'px-2 py-1 text-center text-sm font-medium text-foreground flex items-center justify-center min-w-[80px]', // min-w ensures same width
24+
activeHref === href && 'bg-background rounded-md shadow-sm'
25+
)}
26+
>
27+
{name}
28+
</Link>
29+
))}
30+
</div>
31+
)
32+
}

components/ui/pagination.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77

88
import { cn } from '@/lib/utils'
99
import { Button, buttonVariants } from '@/components/ui/button'
10+
import Link from 'next/link'
1011

1112
function Pagination({ className, ...props }: React.ComponentProps<'nav'>) {
1213
return (
@@ -40,7 +41,7 @@ function PaginationItem({ ...props }: React.ComponentProps<'li'>) {
4041
type PaginationLinkProps = {
4142
isActive?: boolean
4243
} & Pick<React.ComponentProps<typeof Button>, 'size'> &
43-
React.ComponentProps<'a'>
44+
React.ComponentProps<typeof Link>
4445

4546
function PaginationLink({
4647
className,
@@ -49,7 +50,7 @@ function PaginationLink({
4950
...props
5051
}: PaginationLinkProps) {
5152
return (
52-
<a
53+
<Link
5354
aria-current={isActive ? 'page' : undefined}
5455
data-slot="pagination-link"
5556
data-active={isActive}

lib/api/borrow.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type GetListBorrowsQuery = QueryParams<
99
is_active?: boolean
1010
is_expired?: boolean
1111
library_id?: string
12+
status?: 'active' | 'overdue' | 'returned'
1213
}
1314
>
1415
type GetListBorrowsResponse = Promise<ResList<Borrow>>

0 commit comments

Comments
 (0)