Skip to content

Commit 4c287ef

Browse files
committed
feat: borrow list item style enhc
1 parent 1b7fde3 commit 4c287ef

File tree

5 files changed

+111
-77
lines changed

5 files changed

+111
-77
lines changed

app/(protected)/borrows/page.tsx

Lines changed: 3 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { BtnReturnBook } from '@/components/borrows/BtnReturnBorrow'
2-
import { Badge } from '@/components/ui/badge'
1+
import { CardBorrow } from '@/components/borrows/CardBorrow'
32
import {
43
Breadcrumb,
54
BreadcrumbItem,
@@ -9,14 +8,6 @@ import {
98
BreadcrumbSeparator,
109
} from '@/components/ui/breadcrumb'
1110
import { Button } from '@/components/ui/button'
12-
import {
13-
Card,
14-
CardContent,
15-
CardDescription,
16-
CardFooter,
17-
CardHeader,
18-
CardTitle,
19-
} from '@/components/ui/card'
2011
import {
2112
Pagination,
2213
PaginationContent,
@@ -27,18 +18,9 @@ import {
2718

2819
import { getListBorrows } from '@/lib/api/borrow'
2920
import { Verify } from '@/lib/firebase/firebase'
30-
import { Borrow } from '@/lib/types/borrow'
31-
import { formatDate } from '@/lib/utils'
32-
import { Book, Calendar, LibraryIcon, User } from 'lucide-react'
21+
import { Book } from 'lucide-react'
3322
import Link from 'next/link'
3423

35-
const getBorrowStatus = (borrow: Borrow) => {
36-
const now = new Date()
37-
const due = new Date(borrow.due_at)
38-
if (borrow.returned_at) return 'returned'
39-
return now > due ? 'overdue' : 'active'
40-
}
41-
4224
export default async function Borrows({
4325
searchParams,
4426
}: {
@@ -106,62 +88,7 @@ export default async function Borrows({
10688
</div>
10789
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
10890
{res.data.map((borrow) => (
109-
<Card key={borrow.id} className="relative">
110-
<CardHeader>
111-
<div className="flex justify-between items-start">
112-
<div>
113-
<CardTitle className="text-lg">{borrow.book.title}</CardTitle>
114-
<CardDescription>{borrow.book.code}</CardDescription>
115-
</div>
116-
<Badge
117-
variant={
118-
getBorrowStatus(borrow) === 'overdue'
119-
? 'destructive'
120-
: getBorrowStatus(borrow) === 'returned'
121-
? 'secondary'
122-
: 'default'
123-
}
124-
className="capitalize"
125-
>
126-
{getBorrowStatus(borrow)}
127-
</Badge>
128-
</div>
129-
</CardHeader>
130-
<CardContent className="space-y-3">
131-
<div className="flex items-center gap-2 text-sm">
132-
<User className="h-4 w-4 text-muted-foreground" />
133-
<span>{borrow.subscription.user.name}</span>
134-
</div>
135-
<div className="flex items-center gap-2 text-sm">
136-
<LibraryIcon className="h-4 w-4 text-muted-foreground" />
137-
<span>{borrow.subscription.membership.library.name}</span>
138-
</div>
139-
<div className="flex items-center gap-2 text-sm">
140-
<Calendar className="h-4 w-4 text-muted-foreground" />
141-
<div className="flex flex-col">
142-
<span>Borrowed: {formatDate(borrow.borrowed_at)}</span>
143-
<span
144-
className={`${
145-
getBorrowStatus(borrow) === 'overdue'
146-
? 'text-destructive'
147-
: ''
148-
}`}
149-
>
150-
Due: {formatDate(borrow.due_at)}
151-
</span>
152-
</div>
153-
</div>
154-
</CardContent>
155-
<CardFooter>
156-
<BtnReturnBook
157-
variant="outline"
158-
className="w-full"
159-
borrow={borrow}
160-
>
161-
Return Book
162-
</BtnReturnBook>
163-
</CardFooter>
164-
</Card>
91+
<CardBorrow key={borrow.id} borrow={borrow} />
16592
))}
16693
</div>
16794

components/borrows/CardBorrow.tsx

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { BtnReturnBook } from '@/components/borrows/BtnReturnBorrow'
2+
import { Badge } from '@/components/ui/badge'
3+
import { Borrow } from '@/lib/types/borrow'
4+
import { formatDate } from '@/lib/utils'
5+
import {
6+
Calendar,
7+
CalendarClock,
8+
CalendarX,
9+
LibraryIcon,
10+
User,
11+
} from 'lucide-react'
12+
13+
import {
14+
Card,
15+
CardContent,
16+
CardDescription,
17+
CardFooter,
18+
CardHeader,
19+
CardTitle,
20+
} from '@/components/ui/card'
21+
import { useMemo } from 'react'
22+
import clsx from 'clsx'
23+
24+
const checkIsDue = (borrow: Borrow) => {
25+
const now = new Date()
26+
const due = new Date(borrow.due_at)
27+
return now > due
28+
}
29+
30+
const getBorrowStatus = (borrow: Borrow) => {
31+
if (borrow.returned_at) return 'returned'
32+
33+
return checkIsDue(borrow) ? 'overdue' : 'active'
34+
}
35+
36+
export const CardBorrow: React.FC<{ borrow: Borrow }> = ({ borrow }) => {
37+
const isDue = useMemo(() => checkIsDue(borrow), [borrow])
38+
39+
return (
40+
<Card
41+
key={borrow.id}
42+
className={clsx('relative', {
43+
'bg-destructive/5': isDue && !borrow.returned_at,
44+
})}
45+
>
46+
<CardHeader>
47+
<div className="flex justify-between items-start min-h-20">
48+
<div>
49+
<CardTitle className="text-lg line-clamp-2">
50+
<abbr title={borrow.book.title} className="no-underline">
51+
{borrow.book.title}
52+
</abbr>
53+
</CardTitle>
54+
<CardDescription>{borrow.book.code}</CardDescription>
55+
</div>
56+
<Badge
57+
variant={
58+
getBorrowStatus(borrow) === 'overdue'
59+
? 'destructive'
60+
: getBorrowStatus(borrow) === 'returned'
61+
? 'secondary'
62+
: 'default'
63+
}
64+
className="capitalize"
65+
>
66+
{getBorrowStatus(borrow)}
67+
</Badge>
68+
</div>
69+
</CardHeader>
70+
<CardContent className="space-y-3">
71+
<div className="flex items-center gap-2 text-sm">
72+
<User className="h-4 w-4 text-muted-foreground" />
73+
<span>{borrow.subscription.user.name}</span>
74+
</div>
75+
<div className="flex items-center gap-2 text-sm">
76+
<LibraryIcon className="h-4 w-4 text-muted-foreground" />
77+
<span>{borrow.subscription.membership.library.name}</span>
78+
</div>
79+
<div className="flex items-center gap-2 text-sm">
80+
<Calendar className="h-4 w-4 text-muted-foreground" />
81+
<span>Borrowed: {formatDate(borrow.borrowed_at)}</span>
82+
</div>
83+
<div className="flex items-center gap-2 text-sm">
84+
{isDue ? (
85+
<CalendarX className="h-4 w-4 text-destructive" />
86+
) : (
87+
<CalendarClock className="h-4 w-4 text-muted-foreground" />
88+
)}
89+
<span className={`${isDue ? 'text-destructive' : ''}`}>
90+
Due: {formatDate(borrow.due_at)}
91+
</span>
92+
</div>
93+
</CardContent>
94+
<CardFooter>
95+
<BtnReturnBook variant="outline" className="w-full" borrow={borrow}>
96+
Return Book
97+
</BtnReturnBook>
98+
</CardFooter>
99+
</Card>
100+
)
101+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@radix-ui/react-slot": "^1.1.1",
2121
"@radix-ui/react-toast": "^1.2.3",
2222
"@radix-ui/react-tooltip": "^1.1.5",
23+
"@tailwindcss/line-clamp": "^0.4.4",
2324
"class-variance-authority": "^0.7.1",
2425
"clsx": "^2.1.1",
2526
"cmdk": "1.0.0",

tailwind.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,5 @@ export default {
5858
},
5959
},
6060
},
61-
plugins: [require('tailwindcss-animate')],
61+
plugins: [require('tailwindcss-animate'), require('@tailwindcss/line-clamp')],
6262
} satisfies Config

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,11 @@
14061406
dependencies:
14071407
tslib "^2.8.0"
14081408

1409+
"@tailwindcss/line-clamp@^0.4.4":
1410+
version "0.4.4"
1411+
resolved "https://registry.yarnpkg.com/@tailwindcss/line-clamp/-/line-clamp-0.4.4.tgz#767cf8e5d528a5d90c9740ca66eb079f5e87d423"
1412+
integrity sha512-5U6SY5z8N42VtrCrKlsTAA35gy2VSyYtHWCsg1H87NU1SXnEfekTVlrga9fzUDrrHcGi2Lb5KenUWb4lRQT5/g==
1413+
14091414
"@tootallnate/once@2":
14101415
version "2.0.0"
14111416
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"

0 commit comments

Comments
 (0)