1616 <template #body >수정 사항을 삭제하고 이동하시겠습니까?</template >
1717 </ModalView >
1818
19+ <ModalView
20+ :isOpen =" isFailModalVisible"
21+ :type =" 'failType'"
22+ @click =" failModalToggle"
23+ @close =" failModalToggle" >
24+ <template #header >{{ failHeader }}</template >
25+ <template #body >{{ failBody }}</template >
26+ </ModalView >
27+
1928 <div class =" profile" >
2029 <p class =" text-body text-xs font-bold" >프로필 사진</p >
2130 <ImageContainer
6170 @blur =" validateName" />
6271 <div class =" mb-1" >
6372 <span
64- v-show =" isInvalid"
65- class =" absolute text-red-1 text-xs font-bold mt-1"
66- >이름에는 특수문자가 포함될 수 없습니다.</span
67- >
68- <span
69- v-show =" isFull"
73+ v-show =" isInvalid || isFull"
7074 class =" absolute text-red-1 text-xs font-bold mt-1"
71- >이름은 1글자 이상, 10글자이하만 가능합니다. </span
75+ >{{ nameError }} </span
7276 >
7377 </div >
7478 </div >
@@ -150,6 +154,12 @@ const nameInput = ref<HTMLInputElement | null>(null)
150154
151155const isModalVisible = ref (false )
152156const isWarnningModalVisible = ref (false )
157+ const isFailModalVisible = ref (false )
158+
159+ const failHeader = ref (' ' )
160+ const failBody = ref (' ' )
161+
162+ const nameError = ref (' ' )
153163
154164watchEffect (() => {
155165 if (info .value ) {
@@ -160,10 +170,14 @@ watchEffect(() => {
160170})
161171
162172const validateName = () => {
163- const regex = / [!@#$%^&*(),. ?":{}|<>] / g
173+ const regex = / [!@#$%^&*(),. ?":{}|<>\p {Emoji}] / gu
164174 isInvalid .value = regex .test (name .value )
175+ if (isInvalid .value == true ) {
176+ nameError .value = ' 이름에는 특수문자가 포함될 수 없습니다.'
177+ }
165178 if (name .value .length > 10 || name .value .length < 1 ) {
166179 isFull .value = true
180+ nameError .value = ' 이름은 1글자 이상, 10글자이하만 가능합니다.'
167181 } else {
168182 isFull .value = false
169183 }
@@ -199,13 +213,53 @@ const warningModalToggle = () => {
199213 isWarnningModalVisible .value = ! isWarnningModalVisible .value
200214}
201215
216+ const failModalToggle = () => {
217+ isFailModalVisible .value = ! isFailModalVisible .value
218+ }
219+
202220const handleFileUpload = (event : Event ) => {
203221 const target = event .target as HTMLInputElement
204222 if (target .files && target .files [0 ]) {
205- selectedFile .value = target .files [0 ]
206- previewUrl .value = URL .createObjectURL (selectedFile .value )
223+ const file = target .files [0 ]
224+
225+ const allowedMimeTypes = [
226+ ' image/jpeg' ,
227+ ' image/pjpeg' ,
228+ ' image/png' ,
229+ ' image/gif' ,
230+ ' image/bmp' ,
231+ ' image/x-windows-bmp'
232+ ]
233+ const allowedExtensions = [' jpg' , ' jpeg' , ' png' , ' gif' , ' bmp' ]
234+
235+ const fileName = file .name .toLowerCase ()
236+ const fileExtension = fileName .split (' .' ).pop ()
237+
238+ if (! fileExtension || ! allowedExtensions .includes (fileExtension )) {
239+ failHeader .value = ' 지원하지 않는 파일입니다'
240+ failBody .value = ' jpg, jpeg, png, gif, bmp 파일만 업로드 가능합니다'
241+ failModalToggle ()
242+ return
243+ }
244+ if (! allowedMimeTypes .includes (file .type )) {
245+ failHeader .value = ' 파일 타입을 확인해주세요'
246+ failBody .value = ' 파일 타입과 확장자명이 일치해야합니다'
247+ failModalToggle ()
248+ return
249+ }
250+
251+ const newFiles = Array .from (target .files ).filter (file => file .size <= 5 * 1024 * 1024 )
252+ if (newFiles .length !== target .files .length ) {
253+ failHeader .value = ' 이미지 용량을 확인해주세요'
254+ failBody .value = ' 이미지 용량은 5mb까지 가능합니다'
255+ failModalToggle ()
256+ return
257+ }
258+
259+ selectedFile .value = file
260+ previewUrl .value = URL .createObjectURL (file )
261+ imageDelete .value = false
207262 }
208- imageDelete .value = false
209263}
210264
211265const handleFileDelete = () => {
0 commit comments