Skip to content

Commit 7c07323

Browse files
committed
feat: subscription to borrow links
1 parent d4e90bc commit 7c07323

File tree

19 files changed

+473
-209
lines changed

19 files changed

+473
-209
lines changed

app/(protected)/admin/books/[id]/page.tsx

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { Calendar, Hash, Library, Star } from 'lucide-react'
1+
import {
2+
ArrowRight,
3+
Calendar,
4+
Hash,
5+
Library,
6+
MessageSquare,
7+
Star,
8+
} from 'lucide-react'
29
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
310
import { Badge } from '@/components/ui/badge'
411
import { formatDate, getBookStatus } from '@/lib/utils'
@@ -120,60 +127,70 @@ export default async function BookDetailsPage({
120127
</div>
121128
</CardHeader>
122129
<CardContent>
123-
<div className="space-y-6">
124-
{reviewsRes.data.map((review) => (
125-
<div
126-
key={review.id}
127-
className="border-b last:border-b-0 pb-6 last:pb-0"
128-
>
129-
<div className="flex items-start justify-between mb-2">
130-
<div className="flex items-center gap-2">
131-
<Avatar className="h-8 w-8">
132-
<AvatarFallback className="text-xs bg-primary/10">
133-
{review.user?.name?.slice(0, 2)}
134-
</AvatarFallback>
135-
</Avatar>
136-
<div>
137-
{review.user?.name}
138-
<div className="flex items-center gap-1 text-xs text-muted-foreground">
139-
<Calendar className="h-3 w-3" />
140-
{formatDate(review.created_at)}
130+
{reviewsRes.meta.total === 0 ? (
131+
<div className="text-center py-8 text-muted-foreground">
132+
<MessageSquare className="h-12 w-12 mx-auto mb-3 opacity-50" />
133+
<p>No reviews yet</p>
134+
</div>
135+
) : (
136+
<>
137+
<div className="space-y-6">
138+
{reviewsRes.data.map((review) => (
139+
<div
140+
key={review.id}
141+
className="border-b last:border-b-0 pb-6 last:pb-0"
142+
>
143+
<div className="flex items-start justify-between mb-2">
144+
<div className="flex items-center gap-2">
145+
<Avatar className="h-8 w-8">
146+
<AvatarFallback className="text-xs bg-primary/10">
147+
{review.user?.name?.slice(0, 2)}
148+
</AvatarFallback>
149+
</Avatar>
150+
<div>
151+
{review.user?.name}
152+
<div className="flex items-center gap-1 text-xs text-muted-foreground">
153+
<Calendar className="h-3 w-3" />
154+
{formatDate(review.created_at)}
155+
</div>
156+
</div>
157+
</div>
158+
<div className="flex items-center gap-1">
159+
{[1, 2, 3, 4, 5].map((star) => (
160+
<Star
161+
key={star}
162+
className={`h-4 w-4 ${
163+
star <= review.rating
164+
? 'fill-(--color-vibrant,var(--color-yellow-400)) text-(--color-vibrant,var(--color-yellow-400))'
165+
: 'text-gray-300'
166+
}`}
167+
/>
168+
))}
141169
</div>
142170
</div>
171+
<p className="text-sm leading-relaxed text-foreground">
172+
{review.comment}
173+
</p>
143174
</div>
144-
<div className="flex items-center gap-1">
145-
{[1, 2, 3, 4, 5].map((star) => (
146-
<Star
147-
key={star}
148-
className={`h-4 w-4 ${
149-
star <= review.rating
150-
? 'fill-(--color-vibrant,var(--color-yellow-400)) text-(--color-vibrant,var(--color-yellow-400))'
151-
: 'text-gray-300'
152-
}`}
153-
/>
154-
))}
155-
</div>
156-
</div>
157-
<p className="text-sm leading-relaxed text-foreground">
158-
{review.comment}
159-
</p>
175+
))}
160176
</div>
161-
))}
162-
</div>
163-
<div className="mt-6 pt-6 border-t">
164-
<Link
165-
href={`/admin/reviews?book_id=${id}`}
166-
aria-disabled={reviewsRes.meta.total === 0}
167-
>
168-
<Button
169-
variant="outline"
170-
className="w-full bg-transparent"
171-
disabled={reviewsRes.meta.total === 0}
172-
>
173-
View All Reviews ({reviewsRes.meta.total})
174-
</Button>
175-
</Link>
176-
</div>
177+
<div className="mt-6 pt-6 border-t">
178+
<Link
179+
href={`/admin/reviews?book_id=${id}`}
180+
aria-disabled={reviewsRes.meta.total === 0}
181+
>
182+
<Button
183+
variant="ghost"
184+
className="w-full bg-transparent"
185+
disabled={reviewsRes.meta.total === 0}
186+
>
187+
View All Reviews ({reviewsRes.meta.total})
188+
<ArrowRight />
189+
</Button>
190+
</Link>
191+
</div>
192+
</>
193+
)}
177194
</CardContent>
178195
</Card>
179196
</div>

app/(protected)/admin/borrows/page.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { ModelFilter } from '@/components/common/ModelFilter'
3232
import { UserFilter, BookFilter, DateFilter } from '@/components/common/filters'
3333
import { BorrowCardErrorBoundary } from '@/components/borrows/BorrowCardErrorBoundary'
3434
import { ModalExportBorrow } from '@/components/borrows/ModalExportBorrow'
35+
import { SubscriptionFilter } from '@/components/common/filters/SubscriptionFilter'
3536

3637
export const metadata: Metadata = {
3738
title: `Borrows · ${SITE_NAME}`,
@@ -50,6 +51,7 @@ export default async function Borrows({
5051
due_at?: string
5152
returned_at?: string
5253
lost_at?: string
54+
subscription_id?: string
5355
}>
5456
}) {
5557
const sp = await searchParams
@@ -62,6 +64,7 @@ export default async function Borrows({
6264
const due_at = sp?.due_at
6365
const returned_at = sp?.returned_at
6466
const lost_at = sp?.lost_at
67+
const subscription_id = sp?.subscription_id
6568

6669
const headers = await Verify({
6770
from: '/admin/borrows',
@@ -85,6 +88,7 @@ export default async function Borrows({
8588
due_at,
8689
returned_at,
8790
lost_at,
91+
subscription_id,
8892
},
8993
{
9094
headers,
@@ -169,10 +173,12 @@ export default async function Borrows({
169173
'due_at',
170174
'returned_at',
171175
'lost_at',
176+
'subscription_id',
172177
]}
173178
>
174179
<UserFilter />
175180
<BookFilter />
181+
<SubscriptionFilter />
176182
<DateFilter filterKey="borrowed_at" placeholder="Borrow Date" />
177183
<DateFilter filterKey="due_at" placeholder="Due Date" />
178184
<DateFilter filterKey="returned_at" placeholder="Returned Date" />
@@ -197,6 +203,7 @@ export default async function Borrows({
197203
returned_at,
198204
status,
199205
user_id,
206+
subscription_id,
200207
}}
201208
>
202209
<BtnReturnBook

app/(protected)/admin/dashboard/page.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ import type { Metadata, Route } from 'next'
1212
import { DateRangeSelector } from '@/components/dashboard/DateRangeSelector'
1313
import { IsLoggedIn } from '@/lib/firebase/firebase'
1414
import { redirect, RedirectType } from 'next/navigation'
15-
import { format, subMonths, parse, startOfDay, endOfDay } from 'date-fns'
15+
import {
16+
format,
17+
subMonths,
18+
parse,
19+
startOfDay,
20+
endOfDay,
21+
addDays,
22+
} from 'date-fns'
1623
import { getListLibraries } from '@/lib/api/library'
1724
import { DateRange } from 'react-day-picker'
1825
import { cookies } from 'next/headers'
@@ -62,7 +69,7 @@ export default async function DashboardPage({
6269

6370
if (!to || !from) {
6471
const now = new Date()
65-
const to = format(now, 'dd-MM-yyyy')
72+
const to = format(addDays(now, 1), 'dd-MM-yyyy')
6673
const from = format(subMonths(now, 1), 'dd-MM-yyyy')
6774
const sp = new URLSearchParams()
6875
sp.set('from', from)

app/(protected)/admin/page.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,18 @@ import { IsLoggedIn } from '@/lib/firebase/firebase'
1818
import { logoutAction } from '@/lib/actions/logout'
1919
import { ModeToggle } from '@/components/button-toggle-theme'
2020
import { redirect, RedirectType } from 'next/navigation'
21+
import { addDays, format, subMonths } from 'date-fns'
22+
23+
const now = new Date()
24+
const to = format(addDays(now, 1), 'dd-MM-yyyy')
25+
const from = format(subMonths(now, 1), 'dd-MM-yyyy')
2126

2227
const menuItems = [
23-
{ title: 'Dashboard', icon: ChartSpline, href: '/admin/dashboard' },
28+
{
29+
title: 'Dashboard',
30+
icon: ChartSpline,
31+
href: `/admin/dashboard?from=${from}&to=${to}`,
32+
},
2433
{ title: 'Libraries', icon: Library, href: '/admin/libraries' },
2534
{ title: 'Notifications', icon: BellIcon, href: '/notifications' },
2635
{ title: 'Books', icon: Book, href: '/admin/books' },

app/(protected)/admin/reviews/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default async function ReviewsLayout({
3333
<div className="flex justify-between">
3434
<SearchInput
3535
className="max-w-md"
36-
placeholder="Search by review comment..."
36+
placeholder="Search by comment"
3737
name="comment"
3838
/>
3939
<div className="self-end inline-flex gap-2">

app/(protected)/admin/subscriptions/[id]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export default async function SubscriptionDetailsPage({
6666
</Badge>
6767
</div>
6868
</nav>
69-
<DetailSubscription subscription={subsRes.data}>
69+
<DetailSubscription subscription={subsRes.data} isAdmin>
7070
<Button asChild>
7171
<Link
7272
href={`/admin/subscriptions/${subsRes.data.id}/edit`}

app/(protected)/books/[id]/page.tsx

Lines changed: 71 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { Calendar, Hash, Library, Star } from 'lucide-react'
1+
import {
2+
ArrowRight,
3+
Calendar,
4+
Hash,
5+
Library,
6+
MessageSquare,
7+
Star,
8+
} from 'lucide-react'
29
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
310
import { Badge } from '@/components/ui/badge'
411
import { formatDate, getBookStatus } from '@/lib/utils'
@@ -130,62 +137,72 @@ export default async function BookDetailsPage({
130137
</div>
131138
</CardHeader>
132139
<CardContent>
133-
<div className="space-y-6">
134-
{reviewsRes.data.map((review) => (
135-
<div
136-
key={review.id}
137-
className="border-b last:border-b-0 pb-6 last:pb-0"
138-
>
139-
<div className="flex items-start justify-between mb-2">
140-
<div className="flex items-center gap-2">
141-
<Avatar className="h-8 w-8">
142-
<AvatarFallback className="text-xs bg-primary/10">
143-
{review.user.name.slice(0, 2)}
144-
</AvatarFallback>
145-
</Avatar>
146-
<div className="flex flex-col">
147-
<h4 className="font-medium">{review.user.name}</h4>
148-
<DateTime
149-
dateTime={review.created_at}
150-
className="text-xs text-muted-foreground"
151-
>
152-
{formatDate(review.created_at)}
153-
</DateTime>
140+
{reviewsRes.meta.total === 0 ? (
141+
<div className="text-center py-8 text-muted-foreground">
142+
<MessageSquare className="h-12 w-12 mx-auto mb-3 opacity-50" />
143+
<p>No reviews yet</p>
144+
</div>
145+
) : (
146+
<>
147+
<div className="space-y-6">
148+
{reviewsRes.data.map((review) => (
149+
<div
150+
key={review.id}
151+
className="border-b last:border-b-0 pb-6 last:pb-0"
152+
>
153+
<div className="flex items-start justify-between mb-2">
154+
<div className="flex items-center gap-2">
155+
<Avatar className="h-8 w-8">
156+
<AvatarFallback className="text-xs bg-primary/10">
157+
{review.user.name.slice(0, 2)}
158+
</AvatarFallback>
159+
</Avatar>
160+
<div className="flex flex-col">
161+
<h4 className="font-medium">{review.user.name}</h4>
162+
<DateTime
163+
dateTime={review.created_at}
164+
className="text-xs text-muted-foreground"
165+
>
166+
{formatDate(review.created_at)}
167+
</DateTime>
168+
</div>
169+
</div>
170+
<div className="flex items-center gap-1">
171+
{[1, 2, 3, 4, 5].map((star) => (
172+
<Star
173+
key={star}
174+
className={`h-4 w-4 ${
175+
star <= review.rating
176+
? 'fill-(--color-vibrant,var(--color-yellow-400)) text-(--color-vibrant,var(--color-yellow-400))'
177+
: 'text-gray-300'
178+
}`}
179+
/>
180+
))}
181+
</div>
154182
</div>
183+
<p className="text-sm leading-relaxed text-foreground">
184+
{review.comment}
185+
</p>
155186
</div>
156-
<div className="flex items-center gap-1">
157-
{[1, 2, 3, 4, 5].map((star) => (
158-
<Star
159-
key={star}
160-
className={`h-4 w-4 ${
161-
star <= review.rating
162-
? 'fill-(--color-vibrant,var(--color-yellow-400)) text-(--color-vibrant,var(--color-yellow-400))'
163-
: 'text-gray-300'
164-
}`}
165-
/>
166-
))}
167-
</div>
168-
</div>
169-
<p className="text-sm leading-relaxed text-foreground">
170-
{review.comment}
171-
</p>
187+
))}
172188
</div>
173-
))}
174-
</div>
175-
<div className="mt-6 pt-6 border-t">
176-
<Link
177-
href={`/books/${id}/reviews`}
178-
aria-disabled={reviewsRes.meta.total === 0}
179-
>
180-
<Button
181-
variant="outline"
182-
className="w-full bg-transparent"
183-
disabled={reviewsRes.meta.total === 0}
184-
>
185-
View All Reviews ({reviewsRes.meta.total})
186-
</Button>
187-
</Link>
188-
</div>
189+
<div className="mt-6 pt-6 border-t">
190+
<Link
191+
href={`/books/${id}/reviews`}
192+
aria-disabled={reviewsRes.meta.total === 0}
193+
>
194+
<Button
195+
variant="ghost"
196+
className="w-full bg-transparent"
197+
disabled={reviewsRes.meta.total === 0}
198+
>
199+
View All Reviews ({reviewsRes.meta.total})
200+
<ArrowRight />
201+
</Button>
202+
</Link>
203+
</div>{' '}
204+
</>
205+
)}
189206
</CardContent>
190207
</Card>
191208
</div>

0 commit comments

Comments
 (0)