Skip to content

Commit 641c2e2

Browse files
committed
feat: subscription edit & delete
1 parent 878df39 commit 641c2e2

File tree

22 files changed

+770
-179
lines changed

22 files changed

+770
-179
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { BtnUndoReturn } from '@/components/borrows/BtnUndoReturn'
88
import Link from 'next/link'
99
import { CornerUpLeft, Pen, PenOff } from 'lucide-react'
1010
import { BtnUndoLost } from '@/components/borrows/BtnUndoLost'
11-
import { ButtonGroup } from '@/components/ui/button-group'
11+
import { ButtonGroup, ButtonGroupSeparator } from '@/components/ui/button-group'
1212

1313
export default async function BorrowDetailsPage({
1414
params,
@@ -80,6 +80,7 @@ export default async function BorrowDetailsPage({
8080
Return
8181
</Link>
8282
</Button>
83+
<ButtonGroupSeparator />
8384
<Button asChild variant="secondary" className="text-destructive">
8485
<Link
8586
href={`/admin/borrows/${borrowRes.data.id}/lost`}

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { BtnReturnBook } from '@/components/borrows/BtnReturnBorrow'
3030
import { cookies } from 'next/headers'
3131
import { ModelFilter } from '@/components/common/ModelFilter'
3232
import { UserFilter, BookFilter, DateFilter } from '@/components/common/filters'
33+
import { BorrowCardErrorBoundary } from '@/components/borrows/BorrowCardErrorBoundary'
3334

3435
export const metadata: Metadata = {
3536
title: `Borrows · ${SITE_NAME}`,
@@ -179,11 +180,17 @@ export default async function Borrows({
179180

180181
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
181182
{res.data.map((borrow, idx) => (
182-
<ListCardBorrow key={borrow.id} borrow={borrow} idx={skip + idx + 1}>
183-
<BtnReturnBook variant="outline" className="w-full" borrow={borrow}>
184-
Return Book
185-
</BtnReturnBook>
186-
</ListCardBorrow>
183+
<BorrowCardErrorBoundary key={borrow.id} idx={skip + idx + 1}>
184+
<ListCardBorrow borrow={borrow} idx={skip + idx + 1}>
185+
<BtnReturnBook
186+
variant="outline"
187+
className="w-full"
188+
borrow={borrow}
189+
>
190+
Return Book
191+
</BtnReturnBook>
192+
</ListCardBorrow>
193+
</BorrowCardErrorBoundary>
187194
))}
188195
</div>
189196
<Pagination>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ModalEditSubscription } from '@/components/subscriptions/ModalEditSubscription'
2+
import { getSubscription } from '@/lib/api/subscription'
3+
import { Verify } from '@/lib/firebase/firebase'
4+
5+
// This is a server component use to pass data to the modal
6+
export default async function SubscriptionEditPage({
7+
params,
8+
}: {
9+
params: Promise<{ id: string }>
10+
}) {
11+
const { id } = await params
12+
13+
const headers = await Verify({ from: `/admin/subscriptions/${id}` })
14+
15+
const [subRes] = await Promise.all([getSubscription({ id }, { headers })])
16+
if ('error' in subRes) {
17+
return <div>{JSON.stringify(subRes.message)}</div>
18+
}
19+
return <ModalEditSubscription subscription={subRes.data} />
20+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Default() {
2+
return null
3+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Verify } from '@/lib/firebase/firebase'
2+
import { getSubscription } from '@/lib/api/subscription'
3+
import { FormEditSubscription } from '@/components/subscriptions/FormEditSubscription'
4+
5+
export default async function SubscriptionEditPage({
6+
params,
7+
}: {
8+
params: Promise<{ id: string }>
9+
}) {
10+
const { id } = await params
11+
12+
const headers = await Verify({ from: `/admin/subscriptions/${id}` })
13+
14+
const [subRes] = await Promise.all([getSubscription({ id }, { headers })])
15+
16+
if ('error' in subRes) {
17+
console.log({ libRes: subRes })
18+
return <div>{JSON.stringify(subRes.message)}</div>
19+
}
20+
21+
return (
22+
<div className="grid place-items-center">
23+
<FormEditSubscription sub={subRes.data} />
24+
</div>
25+
)
26+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default async function SubscriptionDetailsLayout({
2+
children,
3+
edit,
4+
}: Readonly<{
5+
children: React.ReactNode
6+
edit: React.ReactNode
7+
params: Promise<{ id: string }>
8+
}>) {
9+
return (
10+
<>
11+
{children}
12+
{edit}
13+
</>
14+
)
15+
}

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import { Badge } from '@/components/ui/badge'
1111
import { getSubscriptionStatus } from '@/lib/utils'
1212
import { getSubscription } from '@/lib/api/subscription'
1313
import { DetailSubscription } from '@/components/subscriptions/DetailSubscription'
14+
import { Button } from '@/components/ui/button'
15+
import Link from 'next/link'
16+
import { Pen } from 'lucide-react'
1417

1518
export default async function SubscriptionDetailsPage({
1619
params,
@@ -19,19 +22,15 @@ export default async function SubscriptionDetailsPage({
1922
}) {
2023
const { id } = await params
2124

22-
await Verify({ from: `/admin/subscriptions/${id}` })
25+
const headers = await Verify({ from: `/admin/subscriptions/${id}` })
2326

24-
const [subsRes] = await Promise.all([getSubscription({ id })])
27+
const [subsRes] = await Promise.all([getSubscription({ id }, { headers })])
2528

2629
if ('error' in subsRes) {
2730
console.log({ libRes: subsRes })
2831
return <div>{JSON.stringify(subsRes.message)}</div>
2932
}
3033

31-
// const cookieStore = await cookies()
32-
// const sessionName = process.env.SESSION_COOKIE_NAME as string
33-
// const session = cookieStore.get(sessionName)
34-
3534
return (
3635
<div className="space-y-4">
3736
<nav className="backdrop-blur-sm sticky top-0 z-10">
@@ -67,7 +66,17 @@ export default async function SubscriptionDetailsPage({
6766
</Badge>
6867
</div>
6968
</nav>
70-
<DetailSubscription subscription={subsRes.data} />
69+
<DetailSubscription subscription={subsRes.data}>
70+
<Button asChild>
71+
<Link
72+
href={`/admin/subscriptions/${subsRes.data.id}/edit`}
73+
className="w-full"
74+
>
75+
<Pen />
76+
Edit
77+
</Link>
78+
</Button>
79+
</DetailSubscription>
7180
</div>
7281
)
7382
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ export default async function SubscriptionDetailsPage({
1919
}) {
2020
const { id } = await params
2121

22-
await Verify({ from: `/subscriptions/${id}` })
22+
const headers = await Verify({ from: `/subscriptions/${id}` })
2323

24-
const [subsRes] = await Promise.all([getSubscription({ id })])
24+
const [subsRes] = await Promise.all([getSubscription({ id }, { headers })])
2525

2626
if ('error' in subsRes) {
2727
console.log({ libRes: subsRes })
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
'use client'
2+
3+
import { Component, ReactNode } from 'react'
4+
import {
5+
Card,
6+
CardContent,
7+
CardDescription,
8+
CardHeader,
9+
CardTitle,
10+
} from '@/components/ui/card'
11+
import { AlertCircle } from 'lucide-react'
12+
13+
type Props = {
14+
children: ReactNode
15+
idx: number
16+
}
17+
18+
type State = {
19+
hasError: boolean
20+
error?: Error
21+
}
22+
23+
export class BorrowCardErrorBoundary extends Component<Props, State> {
24+
constructor(props: Props) {
25+
super(props)
26+
this.state = { hasError: false }
27+
}
28+
29+
static getDerivedStateFromError(error: Error): State {
30+
return { hasError: true, error }
31+
}
32+
33+
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
34+
console.error('Error rendering borrow card:', error, errorInfo)
35+
}
36+
37+
render() {
38+
if (this.state.hasError) {
39+
return (
40+
<Card className="relative bg-destructive/5 border-destructive/20">
41+
<CardHeader>
42+
<div className="flex items-start gap-3">
43+
<AlertCircle className="size-5 text-destructive mt-1" />
44+
<div>
45+
<CardTitle className="text-lg text-destructive">
46+
Error loading borrow
47+
</CardTitle>
48+
<CardDescription className="text-muted-foreground/80 font-bold tracking-wider">
49+
#&nbsp;{this.props.idx.toString().padStart(4, '0')}
50+
</CardDescription>
51+
</div>
52+
</div>
53+
</CardHeader>
54+
<CardContent>
55+
<p className="text-sm text-muted-foreground">
56+
Encountered an error while loading this borrow.
57+
</p>
58+
{this.state.error && (
59+
<details className="mt-2">
60+
<summary className="text-xs text-muted-foreground cursor-pointer">
61+
Error details
62+
</summary>
63+
<pre className="text-xs mt-2 p-2 bg-muted rounded overflow-auto">
64+
{this.state.error.message}
65+
</pre>
66+
</details>
67+
)}
68+
</CardContent>
69+
</Card>
70+
)
71+
}
72+
73+
return this.props.children
74+
}
75+
}

components/borrows/BtnDeleteBorrow.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
import { Borrow } from '@/lib/types/borrow'
44
import { useTransition, useState } from 'react'
55
import { Button } from '../ui/button'
6-
import { Lock, Unlock, Loader, Trash } from 'lucide-react'
6+
import { Unlock, Loader, Trash } from 'lucide-react'
77
import { deleteBorrowAction } from '@/lib/actions/delete-borrow'
88
import { toast } from 'sonner'
99
import { redirect } from 'next/navigation'
1010

11-
export const BtnDeleteBook: React.FC<
11+
export const BtnDeleteBorrow: React.FC<
1212
React.ComponentProps<typeof Button> & {
1313
borrow: Borrow
1414
}

0 commit comments

Comments
 (0)