Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions src/components/Modal/WineModal/AddWineModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ interface AddWineModalProps {
setShowRegisterModal: (state: boolean) => void;
}
const AddWineModal = ({ showRegisterModal, setShowRegisterModal }: AddWineModalProps) => {
const ALLOWED_IMAGE_TYPES = ['image/png', 'image/jpeg', 'image/webp'];

const [category, setCategory] = useState('');
const fileInputRef = useRef<HTMLInputElement | null>(null);
const [previewImage, setPreviewImage] = useState<string | null>(null);
Expand All @@ -38,6 +40,14 @@ const AddWineModal = ({ showRegisterModal, setShowRegisterModal }: AddWineModalP
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
if (!ALLOWED_IMAGE_TYPES.includes(file.type)) {
setPreviewImage(null);
setError('wineImage', {
type: 'manual',
message: '지원하지 않는 이미지 형식입니다. (png, jpg, webp)',
});
return;
}
const renamedFile = renameFileIfNeeded(file); //이미지파일 이름 정규화
const imageUrl = URL.createObjectURL(renamedFile);
setPreviewImage(imageUrl);
Expand All @@ -52,6 +62,7 @@ const AddWineModal = ({ showRegisterModal, setShowRegisterModal }: AddWineModalP
clearErrors,
trigger,
setValue,
setError,
reset,
} = useForm<WineForm>({
mode: 'onBlur',
Expand Down Expand Up @@ -97,11 +108,31 @@ const AddWineModal = ({ showRegisterModal, setShowRegisterModal }: AddWineModalP
},
});
const onSubmit = async (form: WineForm) => {
let file = form.wineImage[0];
file = renameFileIfNeeded(file); //이미지파일 이름 정규화
const file = form.wineImage?.[0];

// 1. 이미지 없을 때 막기 (선택사항: 이미 react-hook-form required로 막고 있음)
if (!file) {
setError('wineImage', {
type: 'manual',
message: '이미지를 업로드해 주세요.',
});
return;
}

// 2. 확장자 제한
if (!ALLOWED_IMAGE_TYPES.includes(file.type)) {
setError('wineImage', {
type: 'manual',
message: '지원하지 않는 이미지 형식입니다. (png, jpg, webp)',
});
return;
}

// 3. 파일 정규화 및 제출
const renamedFile = renameFileIfNeeded(file);
postWineMutation.mutate({
...form,
wineImage: [file] as unknown as FileList,
wineImage: [renamedFile] as unknown as FileList,
});
};
const categoryOptions = [
Expand Down Expand Up @@ -207,7 +238,7 @@ const AddWineModal = ({ showRegisterModal, setShowRegisterModal }: AddWineModalP
})}
id='wineImage'
type='file'
accept='image/*'
accept='.png, .jpg, .jpeg, .webp'
className='hidden'
ref={(e) => {
register('wineImage').ref(e);
Expand Down
24 changes: 23 additions & 1 deletion src/components/Modal/WineModal/EditWineModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ interface EditWineModalProps {
}

const EditWineModal = ({ wine, showEditModal, setShowEditModal }: EditWineModalProps) => {
const ALLOWED_IMAGE_TYPES = ['image/png', 'image/jpeg', 'image/webp'];

const [previewImage, setPreviewImage] = useState<string | null>(wine.image);
const fileInputRef = useRef<HTMLInputElement | null>(null);
const queryClient = useQueryClient();
Expand All @@ -49,6 +51,7 @@ const EditWineModal = ({ wine, showEditModal, setShowEditModal }: EditWineModalP
clearErrors,
reset,
setValue,
setError,
trigger,
watch,
} = useForm<WineForm>({
Expand Down Expand Up @@ -79,6 +82,15 @@ const EditWineModal = ({ wine, showEditModal, setShowEditModal }: EditWineModalP
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
if (!ALLOWED_IMAGE_TYPES.includes(file.type)) {
setPreviewImage(null);
setError('wineImage', {
type: 'manual',
message: '지원하지 않는 이미지 형식입니다. (png, jpg, webp)',
});
return;
}

const renamedFile = renameFileIfNeeded(file);
setPreviewImage(URL.createObjectURL(renamedFile));
}
Expand Down Expand Up @@ -108,6 +120,16 @@ const EditWineModal = ({ wine, showEditModal, setShowEditModal }: EditWineModalP
const onSubmit = async (form: WineForm) => {
try {
const file = form.wineImage?.[0];

//파일이 있을 때 확장자 검사
if (file && !ALLOWED_IMAGE_TYPES.includes(file.type)) {
setError('wineImage', {
type: 'manual',
message: '지원하지 않는 이미지 형식입니다. (png, jpg, webp)',
});
return; // 제출 막기
}

let imageUrl = wine.image;

if (file) {
Expand Down Expand Up @@ -254,7 +276,7 @@ const EditWineModal = ({ wine, showEditModal, setShowEditModal }: EditWineModalP
<Input
id='wineImage'
type='file'
accept='image/*'
accept='.png, .jpg, .jpeg, .webp'
className='custom-text-md-regular md:custom-text-lg-regular hidden'
{...register('wineImage', {
onChange: (e) => {
Expand Down
5 changes: 4 additions & 1 deletion src/components/my-profile/ProfileImageInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useRef } from 'react';

import Image from 'next/image';
import { toast } from 'sonner';

import Camera from '@/assets/camera.svg';
import UserDefaultImg from '@/assets/icons/userDefaultImg.svg';
Expand Down Expand Up @@ -45,7 +46,9 @@ export function ProfileImageInput({ imageUrl, onFileSelect }: ProfileImageInputP
if (file) {
const allowedTypes = ['image/png', 'image/jpeg', 'image/webp'];
if (!allowedTypes.includes(file.type)) {
alert('지원하지 않는 이미지 형식입니다.');
toast.warning('', {
description: '지원하지 않는 이미지 형식입니다.',
});
return;
}

Expand Down