diff --git a/src/assets/icons/camera-gray.svg b/src/assets/icons/camera-gray.svg new file mode 100644 index 00000000..f222baaa --- /dev/null +++ b/src/assets/icons/camera-gray.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/camera-white.svg b/src/assets/icons/camera-white.svg new file mode 100644 index 00000000..22a0bdc0 --- /dev/null +++ b/src/assets/icons/camera-white.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/components/common/ImageInput.tsx b/src/components/common/ImageInput.tsx new file mode 100644 index 00000000..0d0326b3 --- /dev/null +++ b/src/components/common/ImageInput.tsx @@ -0,0 +1,84 @@ +import { useEffect, useState } from 'react'; +import CameraGray from '@/assets/icons/camera-gray.svg'; +import CameraWhite from '@/assets/icons/camera-white.svg'; + +interface ImageInputProps { + label: string; + imageUrl: string; + onImageChange: (file: File, previewUrl: string) => void; + mode?: 'create' | 'edit'; +} + +export default function ImageInput({ + label, + imageUrl, + onImageChange, + mode = 'create', +}: ImageInputProps) { + const [preview, setPreview] = useState(imageUrl); + + useEffect(() => { + setPreview(imageUrl); + }, [imageUrl]); + + const handleChangeFile = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + const previewUrl = URL.createObjectURL(file); + setPreview(previewUrl); + onImageChange(file, previewUrl); + }; + + useEffect(() => { + return () => { + if (preview?.startsWith('blob:')) { + URL.revokeObjectURL(preview); + } + }; + }, [preview]); + + return ( +
+ + + + + +
+ ); +}