Skip to content

Commit 67b8d72

Browse files
committed
feat: borrow list by v0
1 parent e69231d commit 67b8d72

File tree

1 file changed

+91
-39
lines changed

1 file changed

+91
-39
lines changed

app/(protected)/borrows/page.tsx

Lines changed: 91 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,44 @@ import {
88
BreadcrumbSeparator,
99
} from '@/components/ui/breadcrumb'
1010
import { Button } from '@/components/ui/button'
11+
import {
12+
Card,
13+
CardContent,
14+
CardDescription,
15+
CardFooter,
16+
CardHeader,
17+
CardTitle,
18+
} from '@/components/ui/card'
1119
import {
1220
Pagination,
1321
PaginationContent,
1422
PaginationItem,
1523
PaginationNext,
1624
PaginationPrevious,
1725
} from '@/components/ui/pagination'
18-
import {
19-
Table,
20-
TableBody,
21-
TableCell,
22-
TableHead,
23-
TableHeader,
24-
TableRow,
25-
} from '@/components/ui/table'
26+
2627
import { getListBorrows } from '@/lib/api/borrow'
28+
import { Borrow } from '@/lib/types/borrow'
29+
import { Book, Calendar, LibraryIcon, User } from 'lucide-react'
2730
import { cookies } from 'next/headers'
2831
import Link from 'next/link'
2932

33+
const formatDate = (date: string): string => {
34+
const formatter = new Intl.DateTimeFormat('en-US', {
35+
month: 'short',
36+
day: 'numeric',
37+
year: 'numeric',
38+
})
39+
return formatter.format(new Date(date))
40+
}
41+
42+
const getBorrowStatus = (borrow: Borrow) => {
43+
const now = new Date()
44+
const due = new Date(borrow.due_at)
45+
if (borrow.returned_at) return 'returned'
46+
return now > due ? 'overdue' : 'active'
47+
}
48+
3049
export default async function Borrows({
3150
searchParams,
3251
}: {
@@ -87,39 +106,72 @@ export default async function Borrows({
87106
</BreadcrumbList>
88107
</Breadcrumb>
89108
<Button asChild>
90-
<Link href="/borrows/new">New Borrow</Link>
109+
<Link href="/borrows/new">
110+
<Book className="mr-2 h-4 w-4" />
111+
New Borrow
112+
</Link>
91113
</Button>
92114
</div>
93-
94-
<Table>
95-
{/* <TableCaption>List of books available in the library.</TableCaption> */}
96-
<TableHeader>
97-
<TableRow>
98-
<TableHead>Book</TableHead>
99-
<TableHead>Date</TableHead>
100-
<TableHead>User</TableHead>
101-
<TableHead>Due</TableHead>
102-
<TableHead>Title</TableHead>
103-
<TableHead>Library</TableHead>
104-
<TableHead>Returned Date</TableHead>
105-
</TableRow>
106-
</TableHeader>
107-
<TableBody>
108-
{res.data.map((b) => (
109-
<TableRow key={b.id}>
110-
<TableCell>{b.book.code}</TableCell>
111-
<TableCell>{b.borrowed_at}</TableCell>
112-
<TableCell>{b.subscription.user.name}</TableCell>
113-
<TableCell>{b.due_at}</TableCell>
114-
<TableCell>{b.book.title}</TableCell>
115-
<TableCell>{b.subscription.membership.library.name}</TableCell>
116-
<TableCell>
117-
{b.returned_at ?? <Badge variant="outline">Active</Badge>}
118-
</TableCell>
119-
</TableRow>
120-
))}
121-
</TableBody>
122-
</Table>
115+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
116+
{res.data.map((borrow) => (
117+
<Card key={borrow.id} className="relative">
118+
<CardHeader>
119+
<div className="flex justify-between items-start">
120+
<div>
121+
<CardTitle className="text-lg">{borrow.book.title}</CardTitle>
122+
<CardDescription>{borrow.book.code}</CardDescription>
123+
</div>
124+
<Badge
125+
variant={
126+
getBorrowStatus(borrow) === 'overdue'
127+
? 'destructive'
128+
: getBorrowStatus(borrow) === 'returned'
129+
? 'secondary'
130+
: 'default'
131+
}
132+
className="capitalize"
133+
>
134+
{getBorrowStatus(borrow)}
135+
</Badge>
136+
</div>
137+
</CardHeader>
138+
<CardContent className="space-y-3">
139+
<div className="flex items-center gap-2 text-sm">
140+
<User className="h-4 w-4 text-muted-foreground" />
141+
<span>{borrow.subscription.user.name}</span>
142+
</div>
143+
<div className="flex items-center gap-2 text-sm">
144+
<LibraryIcon className="h-4 w-4 text-muted-foreground" />
145+
<span>{borrow.subscription.membership.library.name}</span>
146+
</div>
147+
<div className="flex items-center gap-2 text-sm">
148+
<Calendar className="h-4 w-4 text-muted-foreground" />
149+
<div className="flex flex-col">
150+
<span>Borrowed: {formatDate(borrow.borrowed_at)}</span>
151+
<span
152+
className={`${
153+
getBorrowStatus(borrow) === 'overdue'
154+
? 'text-destructive'
155+
: ''
156+
}`}
157+
>
158+
Due: {formatDate(borrow.due_at)}
159+
</span>
160+
</div>
161+
</div>
162+
</CardContent>
163+
<CardFooter>
164+
<Button
165+
variant="outline"
166+
className="w-full"
167+
// onClick={() => alert(`Return book: ${borrow.book_id}`)}
168+
>
169+
Return Book
170+
</Button>
171+
</CardFooter>
172+
</Card>
173+
))}
174+
</div>
123175

124176
<Pagination>
125177
<PaginationContent>

0 commit comments

Comments
 (0)