diff --git a/src/app/components/ImgInputForm.client.tsx b/src/app/components/ImgInputForm.client.tsx deleted file mode 100644 index 7917fb5..0000000 --- a/src/app/components/ImgInputForm.client.tsx +++ /dev/null @@ -1,73 +0,0 @@ -'use client' - -import { useEffect, useRef, useState } from "react" -import { callServer } from "@/lib/Auth" -import { isLogin } from "@/utils/Login" - -const ImgInputForm_client = () => { - - //페이지 오픈 시 로그인 여부 확인 - useEffect(() => { - isLogin - }) - - const fileRef = useRef(null) - const [fileName, setFileName] = useState('') - const [preview, setPreview] = useState() - - const imgInput = (e: React.ChangeEvent) => { - const selected = e.target.files?.[0]; - if (selected != null) { - setFileName(selected?.name) - setPreview(URL.createObjectURL(selected)) - } - - } - - const inputFileClick = () => { - const file = fileRef.current; - if (file) file.click() - } - - const confirm = async () => { - const files = fileRef.current?.files - if (files) { - const file = files[0] - const fomrData = new FormData() - fomrData.append("image", file) - console.log("here") - console.log(file.size) - await fetch("http://localhost:9001/img/get-img", { - method: "POST", - body: fomrData - }) - } - } - - return ( - <> -
- { preview && - - } -
-
- - - - -
- - ) -} - -export default ImgInputForm_client \ No newline at end of file diff --git a/src/app/components/ImgInputForm.module.css b/src/app/components/ImgInputForm.module.css new file mode 100644 index 0000000..b1a3ad3 --- /dev/null +++ b/src/app/components/ImgInputForm.module.css @@ -0,0 +1,59 @@ +.wrapper { + @apply w-full max-w-md mx-auto p-4; +} + +.dropzone { + @apply border-2 rounded-lg p-4 flex flex-col items-center justify-center transition-colors duration-150; +} + +.normal { + @apply border-dashed border-gray-300 bg-white; +} + +.dragging { + @apply border-indigo-400 bg-indigo-50; +} + +.fileInput { + @apply hidden; +} + +.previewBox { + @apply w-32 h-32 rounded-md overflow-hidden bg-gray-100 flex items-center justify-center mb-3; +} + +.previewImg { + @apply object-cover w-full h-full cursor-pointer; +} + +.placeholder { + @apply text-gray-400 text-center text-sm px-2; +} + +.row { + @apply w-full flex gap-2 items-center; +} + +.textInput { + @apply flex-1 px-3 py-2 border rounded h-10 cursor-pointer bg-white text-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500; +} + +.btn { + @apply px-4 py-2 rounded text-white; +} + +.btnLoading { + @apply bg-indigo-300; +} + +.btnPrimary { + @apply bg-indigo-600 hover:bg-indigo-700; +} + +.errorMsg { + @apply mt-3 text-sm text-red-600; +} + +.successMsg { + @apply mt-3 text-sm text-green-600; +} diff --git a/src/app/components/ImgInputForm.server.tsx b/src/app/components/ImgInputForm.server.tsx deleted file mode 100644 index 639473e..0000000 --- a/src/app/components/ImgInputForm.server.tsx +++ /dev/null @@ -1,13 +0,0 @@ -'useClient' - -import axios from "axios" - -const ImgInputForm_server = () => { - -} - -export const isLogin = axios.create({ - -}) - -export default ImgInputForm_server \ No newline at end of file diff --git a/src/app/components/ImgInputForm.tsx b/src/app/components/ImgInputForm.tsx new file mode 100644 index 0000000..628e03a --- /dev/null +++ b/src/app/components/ImgInputForm.tsx @@ -0,0 +1,149 @@ +"use client" + +import { useCallback, useRef, useState } from 'react' +import styles from './ImgInputForm.module.css' + +const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB + +const ImgInputForm = () => { + const fileRef = useRef(null) + const [fileName, setFileName] = useState('') + const [preview, setPreview] = useState(null) + const [isDragging, setIsDragging] = useState(false) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const [success, setSuccess] = useState(null) + + const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:9001' + + const handleFile = useCallback((file: File) => { + setError(null) + setSuccess(null) + if (!file.type.startsWith('image/')) { + setError('이미지 파일만 업로드할 수 있습니다.') + return + } + if (file.size > MAX_FILE_SIZE) { + setError('파일 크기는 5MB 이하만 업로드 가능합니다.') + return + } + + setFileName(file.name) + setPreview(URL.createObjectURL(file)) + // keep the selected file in the hidden input + if (fileRef.current) { + const dataTransfer = new DataTransfer() + dataTransfer.items.add(file) + fileRef.current.files = dataTransfer.files + } + }, []) + + const onChange: React.ChangeEventHandler = (e) => { + const file = e.target.files?.[0] + if (file) handleFile(file) + } + + const onClickPick = () => fileRef.current?.click() + + const onDrop: React.DragEventHandler = (e) => { + e.preventDefault() + setIsDragging(false) + const file = e.dataTransfer.files?.[0] + if (file) handleFile(file) + } + + const onDragOver: React.DragEventHandler = (e) => { + e.preventDefault() + setIsDragging(true) + } + + const onDragLeave: React.DragEventHandler = () => { + setIsDragging(false) + } + + const upload = async () => { + setError(null) + setSuccess(null) + const files = fileRef.current?.files + if (!files || files.length === 0) { + setError('업로드할 파일을 선택해주세요.') + return + } + const file = files[0] + if (!file.type.startsWith('image/')) { + setError('이미지 파일만 업로드할 수 있습니다.') + return + } + setLoading(true) + try { + const fd = new FormData() + fd.append('image', file) + const res = await fetch(`${API_BASE}/img/get-img`, { + method: 'POST', + body: fd, + credentials: 'include' + }) + if (!res.ok) throw new Error('업로드 실패') + setSuccess('업로드 성공') + } catch (err) { + setError((err as Error).message || '업로드 중 오류가 발생했습니다') + } finally { + setLoading(false) + } + } + + return ( +
+
+ + +
+ {preview ? ( + // preview kept modest in size + // eslint-disable-next-line @next/next/no-img-element + preview + ) : ( +
+ 이미지를 끌어다 놓거나
+ 클릭해 선택하세요 +
+ )} +
+ +
+ + +
+ + {error &&

{error}

} + {success &&

{success}

} +
+
+ ) +} + +export default ImgInputForm diff --git a/src/app/main/page.tsx b/src/app/main/page.tsx index b0780d7..48b696d 100644 --- a/src/app/main/page.tsx +++ b/src/app/main/page.tsx @@ -1,16 +1,9 @@ -import ImgInputForm_client from '../components/ImgInputForm.client' -import ImgInputForm_server from '../components/ImgInputForm.server' +import ImgInputForm from '../components/ImgInputForm' const MainPage = () => { - return ( - <> - - - - - ) + return }