Skip to content

Commit 7701c21

Browse files
committed
feat: return borrow
1 parent ad3b3a0 commit 7701c21

File tree

10 files changed

+145
-50
lines changed

10 files changed

+145
-50
lines changed

.github/workflows/prod-deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,4 @@ jobs:
8686
eval "$(ssh-agent -s)"
8787
ssh-add ~/.ssh/action
8888
cd /home/ubuntu/deploy
89-
bash deploy.sh
89+
bash deploy.sh

app/(protected)/borrows/page.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { BtnReturnBook } from '@/components/borrows/BtnReturnBook'
12
import { Badge } from '@/components/ui/badge'
23
import {
34
Breadcrumb,
@@ -160,13 +161,13 @@ export default async function Borrows({
160161
</div>
161162
</CardContent>
162163
<CardFooter>
163-
<Button
164+
<BtnReturnBook
164165
variant="outline"
165166
className="w-full"
166-
// onClick={() => alert(`Return book: ${borrow.book_id}`)}
167+
borrow={borrow}
167168
>
168169
Return Book
169-
</Button>
170+
</BtnReturnBook>
170171
</CardFooter>
171172
</Card>
172173
))}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use client'
2+
3+
import { Borrow } from '@/lib/types/borrow'
4+
import { useState } from 'react'
5+
import { Button, ButtonProps } from '../ui/button'
6+
import { Lock, Unlock } from 'lucide-react'
7+
import { Return } from '@/lib/actions/return-borrow'
8+
9+
export const BtnReturnBook: React.FC<
10+
ButtonProps & {
11+
borrow: Borrow
12+
}
13+
> = ({ borrow, ...props }) => {
14+
const [confirm, setConfirm] = useState<NodeJS.Timeout>()
15+
16+
const onUnlock = () => {
17+
console.log('unlock')
18+
const timerId = setTimeout(() => {
19+
setConfirm(undefined)
20+
}, 3_000)
21+
setConfirm(timerId)
22+
}
23+
24+
const onClick = () => {
25+
console.log('return book', borrow.id)
26+
Return(borrow.id)
27+
if (confirm) clearTimeout(confirm)
28+
}
29+
30+
if (borrow.returned_at)
31+
return (
32+
<Button {...props} variant="secondary" disabled>
33+
{borrow.returned_at}
34+
</Button>
35+
)
36+
37+
if (!confirm) {
38+
return (
39+
<Button onClick={onUnlock} {...props}>
40+
<Lock />
41+
Return
42+
</Button>
43+
)
44+
}
45+
return (
46+
<Button onClick={onClick} {...props} variant="default">
47+
<Unlock />
48+
Confirm
49+
</Button>
50+
)
51+
}

components/ui/button.tsx

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
1-
import * as React from "react"
2-
import { Slot } from "@radix-ui/react-slot"
3-
import { cva, type VariantProps } from "class-variance-authority"
1+
import * as React from 'react'
2+
import { Slot } from '@radix-ui/react-slot'
3+
import { cva, type VariantProps } from 'class-variance-authority'
44

5-
import { cn } from "@/lib/utils"
5+
import { cn } from '@/lib/utils'
66

77
const buttonVariants = cva(
8-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
8+
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
99
{
1010
variants: {
1111
variant: {
12-
default: "bg-primary text-primary-foreground hover:bg-primary/90",
12+
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
1313
destructive:
14-
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
14+
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
1515
outline:
16-
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
16+
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
1717
secondary:
18-
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
19-
ghost: "hover:bg-accent hover:text-accent-foreground",
20-
link: "text-primary underline-offset-4 hover:underline",
18+
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
19+
ghost: 'hover:bg-accent hover:text-accent-foreground',
20+
link: 'text-primary underline-offset-4 hover:underline',
2121
},
2222
size: {
23-
default: "h-10 px-4 py-2",
24-
sm: "h-9 rounded-md px-3",
25-
lg: "h-11 rounded-md px-8",
26-
icon: "h-10 w-10",
23+
default: 'h-10 px-4 py-2',
24+
sm: 'h-9 rounded-md px-3',
25+
lg: 'h-11 rounded-md px-8',
26+
icon: 'h-10 w-10',
2727
},
2828
},
2929
defaultVariants: {
30-
variant: "default",
31-
size: "default",
30+
variant: 'default',
31+
size: 'default',
3232
},
3333
}
3434
)
@@ -41,7 +41,7 @@ export interface ButtonProps
4141

4242
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
4343
({ className, variant, size, asChild = false, ...props }, ref) => {
44-
const Comp = asChild ? Slot : "button"
44+
const Comp = asChild ? Slot : 'button'
4545
return (
4646
<Comp
4747
className={cn(buttonVariants({ variant, size, className }))}
@@ -51,6 +51,6 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
5151
)
5252
}
5353
)
54-
Button.displayName = "Button"
54+
Button.displayName = 'Button'
5555

5656
export { Button, buttonVariants }

components/ui/card.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import * as React from "react"
1+
import * as React from 'react'
22

3-
import { cn } from "@/lib/utils"
3+
import { cn } from '@/lib/utils'
44

55
const Card = React.forwardRef<
66
HTMLDivElement,
@@ -9,25 +9,25 @@ const Card = React.forwardRef<
99
<div
1010
ref={ref}
1111
className={cn(
12-
"rounded-lg border bg-card text-card-foreground shadow-sm",
12+
'rounded-lg border bg-card text-card-foreground shadow-sm',
1313
className
1414
)}
1515
{...props}
1616
/>
1717
))
18-
Card.displayName = "Card"
18+
Card.displayName = 'Card'
1919

2020
const CardHeader = React.forwardRef<
2121
HTMLDivElement,
2222
React.HTMLAttributes<HTMLDivElement>
2323
>(({ className, ...props }, ref) => (
2424
<div
2525
ref={ref}
26-
className={cn("flex flex-col space-y-1.5 p-6", className)}
26+
className={cn('flex flex-col space-y-1.5 p-6', className)}
2727
{...props}
2828
/>
2929
))
30-
CardHeader.displayName = "CardHeader"
30+
CardHeader.displayName = 'CardHeader'
3131

3232
const CardTitle = React.forwardRef<
3333
HTMLDivElement,
@@ -36,44 +36,44 @@ const CardTitle = React.forwardRef<
3636
<div
3737
ref={ref}
3838
className={cn(
39-
"text-2xl font-semibold leading-none tracking-tight",
39+
'text-2xl font-semibold leading-none tracking-tight',
4040
className
4141
)}
4242
{...props}
4343
/>
4444
))
45-
CardTitle.displayName = "CardTitle"
45+
CardTitle.displayName = 'CardTitle'
4646

4747
const CardDescription = React.forwardRef<
4848
HTMLDivElement,
4949
React.HTMLAttributes<HTMLDivElement>
5050
>(({ className, ...props }, ref) => (
5151
<div
5252
ref={ref}
53-
className={cn("text-sm text-muted-foreground", className)}
53+
className={cn('text-sm text-muted-foreground', className)}
5454
{...props}
5555
/>
5656
))
57-
CardDescription.displayName = "CardDescription"
57+
CardDescription.displayName = 'CardDescription'
5858

5959
const CardContent = React.forwardRef<
6060
HTMLDivElement,
6161
React.HTMLAttributes<HTMLDivElement>
6262
>(({ className, ...props }, ref) => (
63-
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
63+
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
6464
))
65-
CardContent.displayName = "CardContent"
65+
CardContent.displayName = 'CardContent'
6666

6767
const CardFooter = React.forwardRef<
6868
HTMLDivElement,
6969
React.HTMLAttributes<HTMLDivElement>
7070
>(({ className, ...props }, ref) => (
7171
<div
7272
ref={ref}
73-
className={cn("flex items-center p-6 pt-0", className)}
73+
className={cn('flex items-center p-6 pt-0', className)}
7474
{...props}
7575
/>
7676
))
77-
CardFooter.displayName = "CardFooter"
77+
CardFooter.displayName = 'CardFooter'
7878

7979
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }

components/ui/input.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import * as React from "react"
1+
import * as React from 'react'
22

3-
import { cn } from "@/lib/utils"
3+
import { cn } from '@/lib/utils'
44

5-
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
5+
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(
66
({ className, type, ...props }, ref) => {
77
return (
88
<input
99
type={type}
1010
className={cn(
11-
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
11+
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
1212
className
1313
)}
1414
ref={ref}
@@ -17,6 +17,6 @@ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
1717
)
1818
}
1919
)
20-
Input.displayName = "Input"
20+
Input.displayName = 'Input'
2121

2222
export { Input }

components/ui/label.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
"use client"
1+
'use client'
22

3-
import * as React from "react"
4-
import * as LabelPrimitive from "@radix-ui/react-label"
5-
import { cva, type VariantProps } from "class-variance-authority"
3+
import * as React from 'react'
4+
import * as LabelPrimitive from '@radix-ui/react-label'
5+
import { cva, type VariantProps } from 'class-variance-authority'
66

7-
import { cn } from "@/lib/utils"
7+
import { cn } from '@/lib/utils'
88

99
const labelVariants = cva(
10-
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
10+
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
1111
)
1212

1313
const Label = React.forwardRef<

lib/actions/return-borrow.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use server'
2+
import { revalidatePath } from 'next/cache'
3+
import { returnBorrow } from '../api/borrow'
4+
import { Verify } from '../firebase/firebase'
5+
6+
export async function Return(id: string, init?: RequestInit) {
7+
const headers = await Verify({
8+
from: '/borrows',
9+
})
10+
11+
returnBorrow(
12+
{
13+
id,
14+
returned_at: new Date().toISOString(),
15+
// FIXME: accept staff_id in api
16+
staff_id: '',
17+
},
18+
{
19+
headers,
20+
...init,
21+
}
22+
)
23+
24+
revalidatePath('/borrows')
25+
}

lib/api/borrow.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ export const getListBorrows = async (
2626

2727
const response = await fetch(url.toString(), init)
2828
if (!response.ok) {
29-
// FIXME: handle token expired error
3029
const e = await response.json()
3130
throw e
3231
}
@@ -60,3 +59,23 @@ export const createBorrow = async (
6059

6160
return response.json()
6261
}
62+
63+
export const returnBorrow = async (
64+
data: Pick<Borrow, 'id' | 'staff_id' | 'returned_at'>,
65+
init?: RequestInit
66+
): GetBookResponse => {
67+
const response = await fetch(`${BORROW_URL}/${data.id}`, {
68+
...init,
69+
method: 'PUT',
70+
body: JSON.stringify(data),
71+
headers: {
72+
'Content-Type': 'application/json',
73+
},
74+
})
75+
if (!response.ok) {
76+
const e = await response.json()
77+
throw e
78+
}
79+
80+
return response.json()
81+
}

lib/firebase/admin.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,5 @@ const adminApp = !admin.apps.length
1010
'admin'
1111
)
1212
: admin.app('admin')
13-
// }
1413

1514
export { adminApp }

0 commit comments

Comments
 (0)