From 613693be070f76843dc952433b5fd56db0c8c111 Mon Sep 17 00:00:00 2001 From: Jiseok Woo <115205098+jisurk@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:17:11 +0900 Subject: [PATCH] =?UTF-8?q?FE-72=20=E2=9C=A8=20=EC=97=90=ED=94=BC=EA=B7=B8?= =?UTF-8?q?=EB=9E=A8=20=EB=93=B1=EB=A1=9D=20api=EC=97=B0=EB=8F=99=20(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FE-72✨ 글작성페이지 스키마 추가 * FE-72✨ form태그 Form컴포넌트로 변경 * FE-72✨ 태그 저장기능 추가 * FE-72✨ 에피그램 등록 api연동 * FE-72✨ 에피그램 등록시 해당 에피그램 페이지로 이동 기능 추가 * FE-72✨ 등록 중일때의 로직추가 * FE-72✨ toast-> alert-dailog로 변경 * FE-72📝 TODO주석 추가 --------- Co-authored-by: 우지석 --- src/apis/add.ts | 9 + src/apis/index.ts | 23 ++ src/hooks/epigramQueryHook.ts | 24 ++ src/pageLayout/Epigram/AddEpigram.tsx | 309 +++++++++++++++++++++----- src/pages/epigram/[id].tsx | 10 + src/schema/addEpigram.ts | 40 ++++ 6 files changed, 355 insertions(+), 60 deletions(-) create mode 100644 src/apis/add.ts create mode 100644 src/hooks/epigramQueryHook.ts create mode 100644 src/pages/epigram/[id].tsx create mode 100644 src/schema/addEpigram.ts diff --git a/src/apis/add.ts b/src/apis/add.ts new file mode 100644 index 00000000..66a6b010 --- /dev/null +++ b/src/apis/add.ts @@ -0,0 +1,9 @@ +import { AddEpigramRequestType, AddEpigramResponseType } from '@/schema/addEpigram'; +import httpClient from '.'; + +const postEpigram = async (request: AddEpigramRequestType): Promise => { + const response = await httpClient.post('/epigrams', request); + return response.data; +}; + +export default postEpigram; diff --git a/src/apis/index.ts b/src/apis/index.ts index 29949fc2..3252d671 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -1,10 +1,33 @@ import axios from 'axios'; import qs from 'qs'; +const getToken = () => + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjUsInRlYW1JZCI6IjUtOSIsInNjb3BlIjoiYWNjZXNzIiwiaWF0IjoxNzIxNjE2Mjk3LCJleHAiOjE3MjE2MTgwOTcsImlzcyI6InNwLWVwaWdyYW0ifQ.kHIq9gdLbu2tE2H8VZXJ9xKQfVA95G9RY251qfXvJy8'; + const httpClient = axios.create({ baseURL: process.env.NEXT_PUBLIC_BASE_URL, headers: { 'Content-Type': 'application/json' }, paramsSerializer: (parameters) => qs.stringify(parameters, { arrayFormat: 'repeat', encode: false }), }); +// NOTE: 유민님 interceptor 사용! +httpClient.interceptors.request.use( + (config) => { + const newConfig = { ...config }; + const token = getToken(); + if (token) { + newConfig.headers.Authorization = `Bearer ${token}`; + } + + if (newConfig.data instanceof FormData) { + newConfig.headers['Content-Type'] = 'multipart/form-data'; + } else { + newConfig.headers['Content-Type'] = 'application/json'; + } + + return newConfig; + }, + (error) => Promise.reject(error), +); + export default httpClient; diff --git a/src/hooks/epigramQueryHook.ts b/src/hooks/epigramQueryHook.ts new file mode 100644 index 00000000..e2ca6679 --- /dev/null +++ b/src/hooks/epigramQueryHook.ts @@ -0,0 +1,24 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { AddEpigramFormType, AddEpigramResponseType } from '@/schema/addEpigram'; +import { MutationOptions } from '@/types/query'; +import postEpigram from '@/apis/add'; +import { AxiosError } from 'axios'; + +// TODO: 에피그램 수정과 삭제에도 사용 가능하게 훅 수정 예정 + +const useAddEpigram = (options?: MutationOptions) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (newEpigram: AddEpigramFormType) => postEpigram(newEpigram), + ...options, + onSuccess: (...args) => { + queryClient.invalidateQueries({ queryKey: ['epigrams'] }); + if (options?.onSuccess) { + options.onSuccess(...args); + } + }, + }); +}; + +export default useAddEpigram; diff --git a/src/pageLayout/Epigram/AddEpigram.tsx b/src/pageLayout/Epigram/AddEpigram.tsx index 954f6212..f087b5da 100644 --- a/src/pageLayout/Epigram/AddEpigram.tsx +++ b/src/pageLayout/Epigram/AddEpigram.tsx @@ -1,77 +1,266 @@ +import React, { KeyboardEvent, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; import Header from '@/components/Header/Header'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; -import Label from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { Textarea } from '@/components/ui/textarea'; +import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form'; +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'; function AddEpigram() { + const [currentTag, setCurrentTag] = useState(''); + const [isAlertOpen, setIsAlertOpen] = useState(false); + const [alertContent, setAlertContent] = useState({ title: '', description: '' }); + const router = useRouter(); + + const form = useForm({ + resolver: zodResolver(AddEpigramFormSchema), + defaultValues: { + content: '', + author: '', + referenceTitle: '', + referenceUrl: '', + tags: [], + }, + }); + + const handleAlertClose = () => { + setIsAlertOpen(false); + if (alertContent.title === '등록 완료') { + router.push(`/epigram/${addEpigramMutation.data?.id}`); + } + }; + + const addEpigramMutation = useAddEpigram({ + onSuccess: () => { + setAlertContent({ + title: '등록 완료', + description: '등록이 완료되었습니다.', + }); + setIsAlertOpen(true); + form.reset(); + }, + // TODO : 유효성검사 브랜치만들어서 alert창에 유효성검사 틀린부분을 보이게 할 예정 + onError: () => { + setAlertContent({ + title: '등록 실패', + 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 handleRemoveTag = (tagToRemove: string) => { + const currentTags = form.getValues('tags') || []; + form.setValue( + 'tags', + currentTags.filter((tag) => tag !== tagToRemove), + ); + }; + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Enter') { + e.preventDefault(); + handleAddTag(); + } + }; + + const handleSubmit = (data: AddEpigramFormType) => { + addEpigramMutation.mutate(data); + }; + return ( <>
{}} />
-
-
- -