Skip to content

Commit ef2cd0c

Browse files
committed
feat: add useUploadImage hook
1 parent b7c97b9 commit ef2cd0c

File tree

4 files changed

+74
-95
lines changed

4 files changed

+74
-95
lines changed

apps/web/@/actions/upload/index.ts

Lines changed: 0 additions & 70 deletions
This file was deleted.

apps/web/@/hooks/useUploadImage.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { useState } from "react"
2+
3+
import { toast } from "react-toastify"
4+
import { useSWRConfig } from "swr"
5+
import useSWRMutation from "swr/mutation"
6+
import useSWRImmutable from "swr/mutation"
7+
8+
// upload image to server API
9+
const uploadImage = async (file: File) => {
10+
try {
11+
const formData = new FormData()
12+
13+
formData.append("file", file)
14+
15+
// Todo: replace with hook
16+
const response = await fetch("/api/protected/images", {
17+
method: "POST",
18+
body: formData,
19+
headers: {
20+
Authorization: `Bearer ${localStorage.getItem("token")}`,
21+
},
22+
})
23+
24+
toast.success("Image uploaded successfully")
25+
26+
return response.json()
27+
} catch (error) {
28+
toast.error("Error uploading image")
29+
// throw error
30+
}
31+
}
32+
33+
// upload image hook
34+
export const useUploadImage = () => {
35+
const { mutate } = useSWRConfig()
36+
37+
const { trigger, isMutating, error, data } = useSWRMutation(
38+
"/api/protected/images",
39+
async (url, { arg }: { arg: File }) => {
40+
const result = await uploadImage(arg)
41+
mutate(["/api/protected/images"])
42+
return result
43+
}
44+
)
45+
46+
return { uploadImage: trigger, isMutating, error, data }
47+
}

apps/web/@/molecules/upload/UploadImageButton.tsx

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,18 @@ import { useTranslations } from "next-intl"
77
import { toast } from "react-toastify"
88
import { LoadingButton } from "ui"
99

10+
import { useUploadImage } from "@/hooks/useUploadImage"
11+
1012
const UploadImageButton = () => {
1113
const fileInputRef = useRef<HTMLInputElement>(null)
1214
const t = useTranslations("uploads")
15+
const { uploadImage, isMutating } = useUploadImage()
1316

1417
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
1518
const file = e.target.files?.[0]
1619

1720
if (file) {
18-
const formData = new FormData()
19-
formData.append("file", file)
20-
21-
// Todo: replace with hook
22-
fetch("/api/protected/images", {
23-
method: "POST",
24-
body: formData,
25-
headers: {
26-
Authorization: `Bearer ${localStorage.getItem("token")}`,
27-
},
28-
})
29-
.then((res) => res.json())
30-
.then((data) => {
31-
toast.success(t("image_uploaded_successfully"))
32-
})
33-
.catch((error) => {
34-
toast.error(t("error_uploading_image"))
35-
})
21+
uploadImage(file)
3622
}
3723
}
3824

@@ -51,6 +37,7 @@ const UploadImageButton = () => {
5137
multiple={false}
5238
/>
5339
<LoadingButton
40+
loading={isMutating}
5441
variant="default"
5542
onClick={handleButtonClick}
5643
className="gap-1"

apps/web/app/api/protected/images/route.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,38 @@ export async function POST(request: NextRequest) {
8080

8181
// Resize and save images
8282
const sizes = [
83-
{ name: "large", width: 1024 },
84-
{ name: "medium", width: 640, height: 360 },
85-
{ name: "thumbnail", width: 320, height: 180 },
83+
{ name: "large", width: 1024, quality: 80 },
84+
{ name: "medium", width: 640, height: 360, quality: 70 },
85+
{ name: "thumbnail", width: 320, height: 180, quality: 60 },
8686
]
8787

8888
const urls = await Promise.all(
8989
sizes.map(async (size) => {
90-
const resizedBuffer = await sharp(buffer).resize(size.width).toBuffer()
90+
let resizedImage = sharp(buffer).resize(size.width, size.height)
91+
const format = file.type.split("/")[1]
92+
93+
switch (format) {
94+
case "jpeg":
95+
case "jpg":
96+
resizedImage = resizedImage.jpeg({ quality: size.quality })
97+
break
98+
case "png":
99+
resizedImage = resizedImage.png({ quality: size.quality })
100+
break
101+
case "webp":
102+
resizedImage = resizedImage.webp({ quality: size.quality })
103+
break
104+
// Add more cases for other formats if needed
105+
}
106+
107+
const resizedBuffer = await resizedImage.toBuffer()
91108

92109
const resizedFileName = `${size.name}-${fileName}`
93110
const filePath = path.join(uploadDir, resizedFileName)
94111

95112
await fs.writeFile(filePath, resizedBuffer)
96113

97-
return `/images/${folderName}/${resizedFileName}`
114+
return `/uploads/${folderName}/${resizedFileName}`
98115
})
99116
)
100117

@@ -118,8 +135,6 @@ export async function POST(request: NextRequest) {
118135
data: image,
119136
})
120137
} catch (error) {
121-
console.log(">>>>>", error)
122-
123138
// TODO: Log error
124139
// TODO: Return error message
125140
return Response.error()

0 commit comments

Comments
 (0)