diff --git a/src/app/artwork/upload/page.tsx b/src/app/artwork/upload/page.tsx new file mode 100644 index 0000000..d90fc58 --- /dev/null +++ b/src/app/artwork/upload/page.tsx @@ -0,0 +1,260 @@ +'use client'; + +import { ChangeEvent, useState } from 'react'; + +import OvalButton from '@/components/Button/OvalButton'; +import FilterDropdown from '@/components/FilterDropdown'; +import Icon from '@/components/Icon/Icon'; +import BasicInput from '@/components/Input/BasicInput'; +import ARTWORK_FIELDS from '@/constants/artworkFields'; + +import Textarea from '../../../components/Input/Textarea'; + +interface ArtworkFieldsErrors { + artworkTitleError?: string; + selectedArtworkFieldError?: string; + uploadedImageError?: string; +} + +const MAX_TITLE_LENGTH = 50; +const MAX_DESCRIPTION_LENGTH = 1000; +const REQUIRED_FIELDS_ERROR_MESSAGE = '필수 항목입니다.'; + +const PRIVACY_SETTING_OPTIONS = [ + { name: '전체공개', value: 'PUBLIC' }, + { name: '비공개', value: 'PRIVATE' }, +]; + +const ArtworkUpload = () => { + const [artworkTitle, setArtworkTitle] = useState(''); + const [selectedArtworkField, setSelectedArtworkField] = useState(''); + const [privacySetting, setPrivacySetting] = useState<'전체공개' | '비공개'>( + '전체공개', + ); + const [uploadedImage, setUploadedImage] = useState(''); + const [artworkDescription, setArtworkDescription] = useState(''); + const [isSubmitting, setIsSubmitting] = useState(false); + const [errors, setErrors] = useState({ + artworkTitleError: '', + selectedArtworkFieldError: '', + uploadedImageError: '', + }); + + const clearErrorMessage = (targetField: string) => { + setErrors((prevErrors) => ({ ...prevErrors, [targetField]: '' })); + }; + + const handleArtworkTitleChanged = (e: ChangeEvent) => { + setArtworkTitle(e.target.value); + + if (errors.artworkTitleError) clearErrorMessage('artworkTitleError'); + }; + + const handleArtworkDescriptionOnChange = ( + e: ChangeEvent, + ) => { + setArtworkDescription(e.target.value); + }; + + const handleArtworkFieldClick = (artworkField: string) => { + setSelectedArtworkField(artworkField); + + if (!artworkTitle.trim()) { + setErrors((prevErrors) => ({ + ...prevErrors, + artworkTitleError: REQUIRED_FIELDS_ERROR_MESSAGE, + })); + } else { + clearErrorMessage('artworkTitleError'); + } + + if (errors.selectedArtworkFieldError) + clearErrorMessage('selectedArtworkFieldError'); + }; + + const handlePrivacySettingChange = ( + newPrivacySetting: '전체공개' | '비공개', + ) => { + setPrivacySetting(newPrivacySetting); + }; + + const handleImageUpload = () => { + // TODO: 실제 이미지 업로드 로직 구현 + setUploadedImage('uploaded-image-url'); // 테스트용 + + if (errors.uploadedImageError) clearErrorMessage('uploadedImageError'); + }; + + const validateArtworkUploadForm = () => { + const newErrors: ArtworkFieldsErrors = {}; + + if (!artworkTitle.trim()) + newErrors.artworkTitleError = REQUIRED_FIELDS_ERROR_MESSAGE; + if (!selectedArtworkField.trim()) + newErrors.selectedArtworkFieldError = REQUIRED_FIELDS_ERROR_MESSAGE; + if (!uploadedImage) + newErrors.uploadedImageError = REQUIRED_FIELDS_ERROR_MESSAGE; + setErrors(newErrors); + + return Object.keys(newErrors).length === 0; + }; + + const isRequiredFieldsValid = + artworkTitle && selectedArtworkField && uploadedImage && !isSubmitting; + + const handleScrollToTop = () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + const handleRequiredFieldsNotFilledOut = () => { + validateArtworkUploadForm(); + handleScrollToTop(); + }; + + const handleArtworkUpload = () => { + setIsSubmitting(true); + + console.log('업로드 완료'); // [테스트용] 업로드 처리 (API 호출) + // TODO: 작성한 글 상세 페이지로 이동 + }; + + return ( +
+

작품 업로드

+
+ +
+ +
+ field.name)} + selected={selectedArtworkField} + onChange={(value) => handleArtworkFieldClick(value)} + isInvalid={!!errors.selectedArtworkFieldError} + errorMessage={errors.selectedArtworkFieldError} + className='w-full' + /> + + option.name)} + selected={privacySetting} + onChange={() => handlePrivacySettingChange(privacySetting)} + className='w-full' + /> +
+ +
+
+

+ 첨부할 작품 이미지를 끌어오거나, +
+ 작품 업로드 버튼을 눌러 이미지를 선택하세요. +

+ + + 이미지 업로드 + +

+ 작품 이미지는 1장만 업로드 가능합니다. +

+ + {errors.uploadedImageError && ( +
+ +

+ {errors.uploadedImageError} +

+
+ )} + + {uploadedImage && ( + Uploaded Artwork + )} + + +
+
+ +