diff --git a/src/apis/index.ts b/src/apis/index.ts index 3252d671..367633f2 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import qs from 'qs'; const getToken = () => - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjUsInRlYW1JZCI6IjUtOSIsInNjb3BlIjoiYWNjZXNzIiwiaWF0IjoxNzIxNjE2Mjk3LCJleHAiOjE3MjE2MTgwOTcsImlzcyI6InNwLWVwaWdyYW0ifQ.kHIq9gdLbu2tE2H8VZXJ9xKQfVA95G9RY251qfXvJy8'; + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjUsInRlYW1JZCI6IjUtOSIsInNjb3BlIjoiYWNjZXNzIiwiaWF0IjoxNzIxODAxOTU1LCJleHAiOjE3MjE4MDM3NTUsImlzcyI6InNwLWVwaWdyYW0ifQ.z_QkXSBKp6gsWH7qs_wdNqQcbzIKAiJieihWfY9LZWY'; const httpClient = axios.create({ baseURL: process.env.NEXT_PUBLIC_BASE_URL, @@ -10,7 +10,6 @@ const httpClient = axios.create({ paramsSerializer: (parameters) => qs.stringify(parameters, { arrayFormat: 'repeat', encode: false }), }); -// NOTE: 유민님 interceptor 사용! httpClient.interceptors.request.use( (config) => { const newConfig = { ...config }; diff --git a/src/hooks/useTagManagementHook.ts b/src/hooks/useTagManagementHook.ts new file mode 100644 index 00000000..9d9c5f93 --- /dev/null +++ b/src/hooks/useTagManagementHook.ts @@ -0,0 +1,36 @@ +import { useState } from 'react'; +import { UseFormSetValue, UseFormGetValues, UseFormSetError } from 'react-hook-form'; +import { AddEpigramFormType } from '@/schema/addEpigram'; + +// NOTE: setError메서드로 FormField에 에러 설정 가능 +const useTagManagement = (setValue: UseFormSetValue, getValues: UseFormGetValues, setError: UseFormSetError) => { + const [currentTag, setCurrentTag] = useState(''); + + const handleAddTag = () => { + if (currentTag && currentTag.length <= 10) { + const currentTags = getValues('tags') || []; + if (currentTags.length < 3) { + // NOTE: 중복된 태그가 있는지 확인 + if (currentTags.includes(currentTag)) { + setError('tags', { type: 'manual', message: '이미 저장된 태그입니다.' }); + } else { + setValue('tags', [...currentTags, currentTag]); + setCurrentTag(''); + setError('tags', { type: 'manual', message: '' }); + } + } + } + }; + + const handleRemoveTag = (tagToRemove: string) => { + const currentTags = getValues('tags') || []; + setValue( + 'tags', + currentTags.filter((tag) => tag !== tagToRemove), + ); + }; + + return { currentTag, setCurrentTag, handleAddTag, handleRemoveTag }; +}; + +export default useTagManagement; diff --git a/src/pageLayout/Epigram/AddEpigram.tsx b/src/pageLayout/Epigram/AddEpigram.tsx index f087b5da..4f5cf246 100644 --- a/src/pageLayout/Epigram/AddEpigram.tsx +++ b/src/pageLayout/Epigram/AddEpigram.tsx @@ -1,4 +1,4 @@ -import React, { KeyboardEvent, useState } from 'react'; +import React, { KeyboardEvent, useCallback, useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import Header from '@/components/Header/Header'; @@ -11,12 +11,16 @@ import { AddEpigramFormSchema, AddEpigramFormType } from '@/schema/addEpigram'; import useAddEpigram from '@/hooks/epigramQueryHook'; import { useRouter } from 'next/router'; import { AlertDialog, AlertDialogAction, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog'; +import useTagManagement from '@/hooks/useTagManagementHook'; +import { useMeQuery } from '@/hooks/userQueryHooks'; function AddEpigram() { - const [currentTag, setCurrentTag] = useState(''); + const router = useRouter(); + const { data: userData, isPending, isError } = useMeQuery(); const [isAlertOpen, setIsAlertOpen] = useState(false); const [alertContent, setAlertContent] = useState({ title: '', description: '' }); - const router = useRouter(); + const [selectedAuthorOption, setSelectedAuthorOption] = useState('directly'); // 기본값을 'directly'로 설정 + const [isFormValid, setIsFormValid] = useState(false); const form = useForm({ resolver: zodResolver(AddEpigramFormSchema), @@ -29,12 +33,23 @@ function AddEpigram() { }, }); - const handleAlertClose = () => { - setIsAlertOpen(false); - if (alertContent.title === '등록 완료') { - router.push(`/epigram/${addEpigramMutation.data?.id}`); - } - }; + // NOTE: 필수항목들에 값이 들어있는지 확인 함수 + const checkFormEmpty = useCallback(() => { + const { content, author, tags } = form.getValues(); + return content.trim() !== '' && author.trim() !== '' && tags.length > 0; + }, [form]); + + // NOTE: form값이 변경될때 필수항목들이 들어있는지 확인 + const watchForm = useCallback(() => { + setIsFormValid(checkFormEmpty()); + }, [checkFormEmpty]); + + useEffect(() => { + const subscription = form.watch(watchForm); + return () => subscription.unsubscribe(); + }, [form, watchForm]); + + const { currentTag, setCurrentTag, handleAddTag, handleRemoveTag } = useTagManagement(form.setValue, form.getValues, form.setError); const addEpigramMutation = useAddEpigram({ onSuccess: () => { @@ -45,35 +60,56 @@ function AddEpigram() { setIsAlertOpen(true); form.reset(); }, - // TODO : 유효성검사 브랜치만들어서 alert창에 유효성검사 틀린부분을 보이게 할 예정 onError: () => { setAlertContent({ title: '등록 실패', - description: '다시 확인해주세요.', + description: '다시 시도해주세요.', }); setIsAlertOpen(true); }, }); - // TODO : 태그 관리 로직 분리 예정 - const handleAddTag = () => { - if (currentTag && currentTag.length <= 10) { - const currentTags = form.getValues('tags') || []; - if (currentTags.length < 3) { - form.setValue('tags', [...currentTags, currentTag]); - setCurrentTag(''); - } + const handleAlertClose = () => { + setIsAlertOpen(false); + if (alertContent.title === '등록 완료') { + router.push(`/epigram/${addEpigramMutation.data?.id}`); } }; - const handleRemoveTag = (tagToRemove: string) => { - const currentTags = form.getValues('tags') || []; - form.setValue( - 'tags', - currentTags.filter((tag) => tag !== tagToRemove), - ); + const authorOptions = [ + { value: 'directly', label: '직접 입력' }, + { value: 'unknown', label: '알 수 없음' }, + { value: 'me', label: '본인' }, + ]; + + // NOTE: default를 직접 입력으로 설정 + // NOTE: 본인을 선택 시 유저의 nickname이 들어감 + const handleAuthorChange = async (value: string) => { + setSelectedAuthorOption(value); + let authorValue = ''; + if (value === 'unknown') { + authorValue = '알 수 없음'; + } else if (value === 'me') { + if (isPending) { + authorValue = '로딩 중...'; + } else if (userData) { + authorValue = userData.nickname; + } else { + authorValue = '본인 (정보 없음)'; + } + } + form.setValue('author', authorValue); }; + if (isPending) { + return
사용자 정보를 불러오는 중...
; + } + + if (isError) { + return
사용자 정보를 불러오는 데 실패했습니다. 페이지를 새로고침 해주세요.
; + } + + // NOTE: 태그를 저장하려고 할때 enter키를 누르면 폼제출이 되는걸 방지 const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Enter') { e.preventDefault(); @@ -81,8 +117,19 @@ function AddEpigram() { } }; + // NOTE: url와title은 필수 항목이 아니라서 빈칸으로 제출할 때 항목에서 제외 const handleSubmit = (data: AddEpigramFormType) => { - addEpigramMutation.mutate(data); + const submitData = { ...data }; + + if (!submitData.referenceUrl) { + delete submitData.referenceUrl; + } + + if (!submitData.referenceTitle) { + delete submitData.referenceTitle; + } + + addEpigramMutation.mutate(submitData); }; return ( @@ -90,7 +137,7 @@ function AddEpigram() {
{}} />
- +