Skip to content

Commit

Permalink
Merge pull request #58 from DDD-Community/fix/57
Browse files Browse the repository at this point in the history
[Feature/57] image compression
  • Loading branch information
hwanheejung authored Jul 24, 2024
2 parents feec5b7 + 35b2c45 commit f998be7
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 25 deletions.
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"dependencies": {
"@storybook/preview-api": "^8.1.11",
"@svgr/webpack": "^8.1.0",
"browser-image-compression": "^2.0.2",
"eslint-import-resolver-typescript": "^3.6.1",
"next": "14.2.4",
"prettier-plugin-tailwindcss": "^0.6.5",
Expand Down
30 changes: 19 additions & 11 deletions src/app/(board)/board/[boardId]/actions/uploadAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@
import { getPreSignedUrl, postPolaroid, uploadImage } from '@/lib'

export const uploadAction = async (id: string, formData: FormData) => {
const fileInput = formData.get('fileInput')
const oneLineMessage = formData.get('oneLineMessage')
try {
const fileInput = formData.get('fileInput')
const oneLineMessage = formData.get('oneLineMessage')

// upload image to S3
const { url, imageKey } = await getPreSignedUrl(id)
await uploadImage({ url, file: fileInput as File })
if (!fileInput || !(fileInput instanceof File)) {
throw new Error('Invalid file input')
}

// upload polaroid
const res = await postPolaroid(id, {
imageKey,
oneLineMessage: oneLineMessage as string,
})
return res
// upload image to S3
const { url, imageKey } = await getPreSignedUrl(id)
await uploadImage({ url, file: fileInput })
// upload polaroid
const res = await postPolaroid(id, {
imageKey,
oneLineMessage: oneLineMessage as string,
})
return res
} catch (error) {
console.error('Error in uploadAction:', error)
throw new Error(`Failed to upload polaroid`)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import PolaroidMaker from '@/components/Polaroid/PolaroidMaker'
import { useRef, useState } from 'react'
import rotateImageIfNeeded from '@/lib/utils/image'
import { uploadAction } from '../../actions/uploadAction'
import ArrowBack from './ArrowBack'
import { useModal } from './ModalContext'
Expand All @@ -16,18 +15,15 @@ const CreatePolaroid = ({ id }: CreatePolaroidProps) => {
const formRef = useRef<HTMLFormElement>(null)
const [btnDisabled, setBtnDisabled] = useState<boolean>(true)
const { closeModal } = useModal()
const [compressedFile, setCompressedFile] = useState<File | null>(null)

return (
<div className="mx-auto flex h-dvh max-w-md flex-1 flex-col justify-between px-5 py-10">
<ArrowBack />
<form
action={async (formData) => {
const fileInput = formData.get('fileInput')
if (fileInput && fileInput instanceof File) {
const rotatedFile = await rotateImageIfNeeded(fileInput)
if (rotatedFile !== fileInput) {
formData.set('fileInput', rotatedFile)
}
if (compressedFile) {
formData.set('fileInput', compressedFile)
}

const res = await uploadAction(id, formData)
Expand All @@ -38,7 +34,10 @@ const CreatePolaroid = ({ id }: CreatePolaroidProps) => {
ref={formRef}
>
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 transform">
<PolaroidMaker setBtnDisabled={setBtnDisabled} />
<PolaroidMaker
setBtnDisabled={setBtnDisabled}
setCompressedFile={setCompressedFile}
/>
</div>
<UploadBtn formRef={formRef} btnDisabled={btnDisabled} />
</form>
Expand Down
23 changes: 19 additions & 4 deletions src/components/Polaroid/PolaroidMaker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client'

import rotateImageIfNeeded from '@/lib/utils/image'
import imageCompression from 'browser-image-compression'
import AddPhotoIcon from 'public/icons/add_photo_alternate.svg'
import {
ChangeEvent,
Expand All @@ -13,35 +14,49 @@ import Base, { PolaroidImage } from './Base'

interface PolaroidMakerProps {
setBtnDisabled: Dispatch<SetStateAction<boolean>>
setCompressedFile: Dispatch<SetStateAction<File | null>>
}

const MAX_LENGTH = 20

const PolaroidMaker = ({ setBtnDisabled }: PolaroidMakerProps) => {
const PolaroidMaker = ({
setBtnDisabled,
setCompressedFile,
}: PolaroidMakerProps) => {
const [text, setText] = useState<string>('')
const [fileUrl, setFileUrl] = useState<string | null>(null)

const handleFileChange = async (
event: React.ChangeEvent<HTMLInputElement>,
) => {
setFileUrl(null)
if (event.target.files && event.target.files.length > 0) {
const file = event.target.files[0]
const rotatedFile = await rotateImageIfNeeded(file)

// image preview
const fileReader = new FileReader()
// image compression
const options = {
maxSizeMB: 0.2,
maxWidthOrHeight: 1920,
useWebWorker: true,
}
const compressedFile = await imageCompression(rotatedFile, options)
setCompressedFile(compressedFile)

// image preview
fileReader.onload = () => {
if (typeof fileReader.result === 'string') {
setFileUrl(fileReader.result)
}
}
fileReader.readAsDataURL(rotatedFile)
fileReader.readAsDataURL(compressedFile)
}
}

useEffect(() => {
setBtnDisabled(!fileUrl)
}, [fileUrl])
}, [fileUrl, setBtnDisabled])

return (
<Base className="m-4" size="lg">
Expand Down
16 changes: 14 additions & 2 deletions src/lib/api/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,26 @@ export const getPreSignedUrl = async (
return result.data
}

export const uploadImage = ({ url, file }: { url: string; file: File }) => {
return fetch(url, {
export const uploadImage = async ({
url,
file,
}: {
url: string
file: File
}) => {
const res = await fetch(url, {
method: 'PUT',
headers: {
'Content-Type': file.type,
},
body: file,
})

if (!res.ok) {
throw new Error('Failed to upload image')
}

return res
}

export const getImageUrl = (imageKey: string): Promise<string> => {
Expand Down

0 comments on commit f998be7

Please sign in to comment.