Skip to content

Commit 6fd90f9

Browse files
committed
feat: return & lost models
1 parent 9126e57 commit 6fd90f9

File tree

19 files changed

+654
-72
lines changed

19 files changed

+654
-72
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ModalLostBorrow } from '@/components/borrows/ModalLostBorrow'
2+
import { getBorrow } from '@/lib/api/borrow'
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 BorrowDetailsPage({
7+
params,
8+
}: {
9+
params: Promise<{ id: string }>
10+
}) {
11+
const { id } = await params
12+
13+
await Verify({ from: `/admin/borrows/${id}` })
14+
15+
const [borrowRes] = await Promise.all([getBorrow({ id })])
16+
if ('error' in borrowRes) {
17+
return <div>{JSON.stringify(borrowRes.message)}</div>
18+
}
19+
return <ModalLostBorrow borrow={borrowRes.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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ModalReturnBorrow } from '@/components/borrows/ModalReturnBorrow'
2+
import { getBorrow } from '@/lib/api/borrow'
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 BorrowDetailsPage({
7+
params,
8+
}: {
9+
params: Promise<{ id: string }>
10+
}) {
11+
const { id } = await params
12+
13+
await Verify({ from: `/admin/borrows/${id}` })
14+
15+
const [borrowRes] = await Promise.all([getBorrow({ id })])
16+
if ('error' in borrowRes) {
17+
return <div>{JSON.stringify(borrowRes.message)}</div>
18+
}
19+
return <ModalReturnBorrow borrow={borrowRes.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+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ import { getBorrowStatus } from '@/lib/utils'
1313
export default async function BorrowDetailsLayout({
1414
children,
1515
edit,
16+
lost,
17+
return: returnNode,
1618
params,
1719
}: Readonly<{
1820
children: React.ReactNode
1921
edit: React.ReactNode
22+
lost: React.ReactNode
23+
return: React.ReactNode
2024
params: Promise<{ id: string }>
2125
}>) {
2226
const { id } = await params
@@ -64,6 +68,8 @@ export default async function BorrowDetailsLayout({
6468
</nav>
6569
{edit}
6670
{children}
71+
{lost}
72+
{returnNode}
6773
</div>
6874
)
6975
}
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 { getBorrow } from '@/lib/api/borrow'
3+
import { FormLostBorrow } from '@/components/borrows/FormLostBorrow'
4+
5+
export default async function BorrowLostPage({
6+
params,
7+
}: {
8+
params: Promise<{ id: string }>
9+
}) {
10+
const { id } = await params
11+
12+
await Verify({ from: `/admin/borrows/${id}/lost` })
13+
14+
const [borrowRes] = await Promise.all([getBorrow({ id })])
15+
16+
if ('error' in borrowRes) {
17+
console.log({ libRes: borrowRes })
18+
return <div>{JSON.stringify(borrowRes.message)}</div>
19+
}
20+
21+
return (
22+
<div className="grid place-items-center">
23+
<FormLostBorrow borrow={borrowRes.data} />
24+
</div>
25+
)
26+
}

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

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ import { getBorrow, getListBorrows } from '@/lib/api/borrow'
33
import { Borrow } from '@/lib/types/borrow'
44
import { redirect, RedirectType } from 'next/navigation'
55
import { DetailBorrow } from '@/components/borrows/DetailBorrow'
6-
import { BtnReturnBook } from '@/components/borrows/BtnReturnBorrow'
76
import { Button } from '@/components/ui/button'
87
import { BtnUndoReturn } from '@/components/borrows/BtnUndoReturn'
98
import Link from 'next/link'
10-
import { Pen } from 'lucide-react'
11-
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
12-
import { FormLostBorrow } from '@/components/borrows/FormLostBorrow'
9+
import { CornerUpLeft, Pen, PenOff } from 'lucide-react'
10+
import { BtnUndoLost } from '@/components/borrows/BtnUndoLost'
11+
import { ButtonGroup } from '@/components/ui/button-group'
1312

1413
export default async function BorrowDetailsPage({
1514
params,
@@ -55,42 +54,53 @@ export default async function BorrowDetailsPage({
5554

5655
return (
5756
<DetailBorrow borrow={borrowRes.data} prevBorrows={prevBorrows}>
58-
<>
59-
{borrowRes.data.returning || borrowRes.data.lost ? null : (
60-
<Card className="bg-destructive/10 border-destructive/20">
61-
<CardHeader>
62-
<CardTitle>Mark as Lost</CardTitle>
63-
</CardHeader>
64-
<CardContent>
65-
<FormLostBorrow id={borrowRes.data.id} />
66-
</CardContent>
67-
</Card>
57+
<div className="bottom-0 sticky py-2 grid md:grid-cols-2 gap-2">
58+
{borrowRes.data.returning ? (
59+
<BtnUndoReturn
60+
variant="outline"
61+
className="w-full backdrop-blur-md"
62+
borrow={borrowRes.data}
63+
/>
64+
) : null}
65+
{borrowRes.data.lost ? (
66+
<BtnUndoLost
67+
variant="outline"
68+
className="w-full backdrop-blur-md"
69+
borrow={borrowRes.data}
70+
/>
71+
) : null}
72+
{borrowRes.data.lost || borrowRes.data.returning ? null : (
73+
<ButtonGroup className="w-full backdrop-blur-md">
74+
<Button variant="secondary" asChild>
75+
<Link
76+
href={`/admin/borrows/${borrowRes.data.id}/return`}
77+
className="w-1/2 bg-secondary"
78+
>
79+
<CornerUpLeft />
80+
Return
81+
</Link>
82+
</Button>
83+
<Button asChild variant="secondary" className="text-destructive">
84+
<Link
85+
href={`/admin/borrows/${borrowRes.data.id}/lost`}
86+
className="w-1/2"
87+
>
88+
<PenOff />
89+
Mark as Lost
90+
</Link>
91+
</Button>
92+
</ButtonGroup>
6893
)}
69-
<div className="bottom-0 sticky py-2 grid md:grid-cols-2 gap-2">
70-
{borrowRes.data.returning ? (
71-
<BtnUndoReturn
72-
variant="outline"
73-
className="w-full backdrop-blur-md"
74-
borrow={borrowRes.data}
75-
/>
76-
) : (
77-
<BtnReturnBook
78-
variant="outline"
79-
className="w-full"
80-
borrow={borrowRes.data}
81-
/>
82-
)}
83-
<Button asChild>
84-
<Link
85-
href={`/admin/borrows/${borrowRes.data.id}/edit`}
86-
className="w-full"
87-
>
88-
<Pen />
89-
Edit
90-
</Link>
91-
</Button>
92-
</div>
93-
</>
94+
<Button asChild>
95+
<Link
96+
href={`/admin/borrows/${borrowRes.data.id}/edit`}
97+
className="w-full"
98+
>
99+
<Pen />
100+
Edit
101+
</Link>
102+
</Button>
103+
</div>
94104
</DetailBorrow>
95105
)
96106
}
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 { getBorrow } from '@/lib/api/borrow'
3+
import { FormReturnBorrow } from '@/components/borrows/FormReturnBorrow'
4+
5+
export default async function BorrowReturnPage({
6+
params,
7+
}: {
8+
params: Promise<{ id: string }>
9+
}) {
10+
const { id } = await params
11+
12+
await Verify({ from: `/admin/borrows/${id}/return` })
13+
14+
const [borrowRes] = await Promise.all([getBorrow({ id })])
15+
16+
if ('error' in borrowRes) {
17+
console.log({ libRes: borrowRes })
18+
return <div>{JSON.stringify(borrowRes.message)}</div>
19+
}
20+
21+
return (
22+
<div className="grid place-items-center">
23+
<FormReturnBorrow borrow={borrowRes.data} />
24+
</div>
25+
)
26+
}

components/borrows/BtnReturnBorrow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const BtnReturnBook: React.FC<
2828
startTransition(async () => {
2929
clearTimeout(confirmTimeout)
3030
setConfirmTimeout(undefined)
31-
const res = await returnBorrowAction(borrow.id)
31+
const res = await returnBorrowAction({ id: borrow.id })
3232
if ('error' in res) {
3333
toast.error(res.error)
3434
return

components/borrows/BtnUndoLost.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
'use client'
2+
3+
import { Borrow } from '@/lib/types/borrow'
4+
import { useTransition, useState } from 'react'
5+
import { Button } from '../ui/button'
6+
import { Lock, Unlock, Loader } from 'lucide-react'
7+
import { toast } from 'sonner'
8+
import { undoLostAction } from '@/lib/actions/undo-lost'
9+
10+
export const BtnUndoLost: React.FC<
11+
React.ComponentProps<typeof Button> & {
12+
borrow: Borrow
13+
}
14+
> = ({ borrow, ...props }) => {
15+
const [confirmTimeout, setConfirmTimeout] = useState<NodeJS.Timeout>()
16+
const [isPending, startTransition] = useTransition()
17+
18+
const onUnlock = () => {
19+
const timerId = setTimeout(() => {
20+
setConfirmTimeout(undefined)
21+
}, 3_000)
22+
setConfirmTimeout(timerId)
23+
}
24+
25+
const onClick = () => {
26+
startTransition(async () => {
27+
clearTimeout(confirmTimeout)
28+
setConfirmTimeout(undefined)
29+
const res = await undoLostAction(borrow.id)
30+
if ('error' in res) {
31+
toast.error(res.error)
32+
return
33+
}
34+
toast.success(res.message)
35+
})
36+
}
37+
38+
if (!confirmTimeout) {
39+
return (
40+
<Button onClick={onUnlock} {...props}>
41+
<Lock />
42+
Undo Lost
43+
</Button>
44+
)
45+
}
46+
47+
return (
48+
<Button
49+
onClick={onClick}
50+
{...props}
51+
variant="destructive"
52+
disabled={isPending}
53+
>
54+
{isPending ? <Loader className="animate-spin" /> : <Unlock />}
55+
Click again to confirm
56+
</Button>
57+
)
58+
}

0 commit comments

Comments
 (0)