From f889a790b95266aac8d809f90268d984e02caca0 Mon Sep 17 00:00:00 2001 From: harry kim <73218463+hanyugeon@users.noreply.github.com> Date: Tue, 23 Apr 2024 00:50:41 +0900 Subject: [PATCH] =?UTF-8?q?[#523]=20[=EB=AA=A8=EC=9E=84=20=EC=83=81?= =?UTF-8?q?=EC=84=B8]=20=EB=AA=A8=EC=9E=84=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20(#527)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: DatePicker, TextArea 컴포넌트 use client 지시문 작성 * refactor: InputLength 컴포넌트 수정 * feat: 독서모임 수정 페이지 마크업 * fix: ChakraUI theme에서 input[type="date"] 속성 제거 * fix: DatePicker 컴포넌트 gap 속성 추가 * feat: 모임 수정 페이지 폼 기능 구현 * refactor: 독서 모임 수정 페이지 개선 * chore: BookGroupTitleForm을 BookGroupEditTitleForm로 수정 * refactor: TextArea 컴포넌트 defaultValue props 타입 정의 * fix: 독서모임 수정 폼 수정(defaultValue 추가) * feat: useBookGroupEditCurrentInfo 쿼리 작성 * feat: 모임정보 수정 기능 구현 * fix: next.config에 images.unuptimized:true 옵션 추가 * chore: 불필요한 코드 제거 * fix: 빌드에러 수정 * fix: next.config 내부 images.unoptimized 옵션 제거 * feat: 독서 모임 수정 reqBody 타입 작성 * refactor: formContext 타입 정의 * feat: 그룹 정보 수정 mutation 쿼리 훅 작성 * feat: 모임수정 타입명 수정, isOwner 타입 추가 * feat: 페이지 접근 권한 추가 (로그인 & 모임 장) --- src/app/group/[groupId]/edit/page.tsx | 125 +++++++++++++----- src/queries/group/useBookGroupQuery.ts | 51 ++++++- src/styles/theme.tsx | 18 --- src/types/group.ts | 9 ++ src/v1/base/DatePicker.tsx | 4 +- src/v1/base/InputLength.tsx | 8 +- src/v1/base/TextArea.tsx | 10 +- .../bookGroup/edit/BookGroupEditDateForm.tsx | 50 +++++++ .../edit/BookGroupEditIntroduceForm.tsx | 40 ++++++ .../bookGroup/edit/BookGroupEditTitleForm.tsx | 47 +++++++ .../edit/BookGroupEditTopNavigation.tsx | 37 ++++++ 11 files changed, 333 insertions(+), 66 deletions(-) create mode 100644 src/v1/bookGroup/edit/BookGroupEditDateForm.tsx create mode 100644 src/v1/bookGroup/edit/BookGroupEditIntroduceForm.tsx create mode 100644 src/v1/bookGroup/edit/BookGroupEditTitleForm.tsx create mode 100644 src/v1/bookGroup/edit/BookGroupEditTopNavigation.tsx diff --git a/src/app/group/[groupId]/edit/page.tsx b/src/app/group/[groupId]/edit/page.tsx index 35d8efc5..beb48496 100644 --- a/src/app/group/[groupId]/edit/page.tsx +++ b/src/app/group/[groupId]/edit/page.tsx @@ -1,43 +1,102 @@ 'use client'; -import GroupAPI from '@/apis/group'; -import { APIGroupDetail } from '@/types/group'; -import AuthRequired from '@/ui/AuthRequired'; -import TopNavigation from '@/ui/common/TopNavigation'; -import EditGroupForm from '@/ui/Group/EditGroupForm'; -import { VStack } from '@chakra-ui/react'; -import { useCallback, useEffect, useState } from 'react'; - -const GroupEditPage = ({ +import { notFound, useRouter } from 'next/navigation'; +import { FormProvider, SubmitHandler, useForm } from 'react-hook-form'; + +import { + useBookGroupEditCurrentInfo, + useBookGroupInfoMutation, +} from '@/queries/group/useBookGroupQuery'; +import type { APIGroupDetail, APIEditBookGroup } from '@/types/group'; + +import { SERVICE_ERROR_MESSAGE } from '@/constants'; +import { + checkAuthentication, + isAxiosErrorWithCustomCode, +} from '@/utils/helpers'; + +import useToast from '@/v1/base/Toast/useToast'; +import BookGroupEditDateForm from '@/v1/bookGroup/edit/BookGroupEditDateForm'; +import BookGroupEditIntroduceForm from '@/v1/bookGroup/edit/BookGroupEditIntroduceForm'; +import BookGroupEditTitleForm from '@/v1/bookGroup/edit/BookGroupEditTitleForm'; +import BookGroupEditTopNavigation from '@/v1/bookGroup/edit/BookGroupEditTopNavigation'; + +const BookGroupEditPage = ({ params: { groupId }, }: { - params: { groupId: number }; + params: { groupId: APIGroupDetail['bookGroupId'] }; }) => { - const [group, setGroup] = useState(); - - const getGroup = useCallback(async () => { - try { - const { data } = await GroupAPI.getGroupDetailInfo({ - bookGroupId: groupId, - }); - setGroup(data); - } catch (error) { - console.error(error); - } - }, [groupId]); - - useEffect(() => { - getGroup(); - }, [getGroup]); + const router = useRouter(); + + const isAuthenticated = checkAuthentication(); + + const { data: bookGroupData } = useBookGroupEditCurrentInfo(groupId); + const { isOwner, title, description, maxMemberCount, startDate, endDate } = + bookGroupData; + + if (!isAuthenticated || !isOwner) { + notFound(); + } + + const bookGroupEdit = useBookGroupInfoMutation(groupId); + + const { show: showToast } = useToast(); + + const methods = useForm>({ + mode: 'all', + defaultValues: { + title: title, + introduce: description, + maxMemberCount: maxMemberCount ? maxMemberCount : 9999, + startDate: startDate, + endDate: endDate, + }, + }); + + const handleFormSubmit: SubmitHandler< + Omit + > = async ({ title, introduce, maxMemberCount, endDate }) => { + bookGroupEdit.mutate( + { title, introduce, maxMemberCount, endDate }, + { + onSuccess: () => { + router.push(`/group/${groupId}`); + + showToast({ type: 'success', message: '모임 정보를 수정했어요! 🎉' }); + return; + }, + onError: error => { + if (isAxiosErrorWithCustomCode(error)) { + const { code } = error.response.data; + const message = SERVICE_ERROR_MESSAGE[code]; + + showToast({ type: 'error', message }); + return; + } + + showToast({ + type: 'error', + message: '모임 정보 수정을 실패했어요 🥲', + }); + }, + } + ); + }; return ( - - - - {group && } - - + + + +
+ + + + +
); }; -export default GroupEditPage; +export default BookGroupEditPage; diff --git a/src/queries/group/useBookGroupQuery.ts b/src/queries/group/useBookGroupQuery.ts index 1d60ee5b..cacf376b 100644 --- a/src/queries/group/useBookGroupQuery.ts +++ b/src/queries/group/useBookGroupQuery.ts @@ -1,9 +1,17 @@ -import { UseQueryOptions } from '@tanstack/react-query'; +import { + useMutation, + useQueryClient, + UseQueryOptions, +} from '@tanstack/react-query'; -import { APIGroupDetail, BookGroupDetail } from '@/types/group'; -import { isExpired } from '@/utils/date'; -import GroupAPI from '@/apis/group'; +import type { + APIGroupDetail, + BookGroupDetail, + APIEditBookGroup, +} from '@/types/group'; import useQueryWithSuspense from '@/hooks/useQueryWithSuspense'; +import groupAPI from '@/apis/group'; +import { isExpired } from '@/utils/date'; import bookGroupKeys from './key'; @@ -26,9 +34,9 @@ export const useBookGroupQuery = ( useQueryWithSuspense( bookGroupKeys.detail(groupId), () => - GroupAPI.getGroupDetailInfo({ bookGroupId: groupId }).then( - ({ data }) => data - ), + groupAPI + .getGroupDetailInfo({ bookGroupId: groupId }) + .then(({ data }) => data), options ); @@ -56,3 +64,32 @@ export const useBookGroupJoinInfo = (groupId: APIGroupDetail['bookGroupId']) => question: data.joinQuestion, }), }); + +export const useBookGroupEditCurrentInfo = ( + groupId: APIGroupDetail['bookGroupId'] +) => + useBookGroupQuery(groupId, { + select: data => ({ + isOwner: data.isOwner, + title: data.title, + description: data.introduce, + maxMemberCount: data.maxMemberCount, + startDate: data.startDate, + endDate: data.endDate, + }), + }); + +export const useBookGroupInfoMutation = ( + bookGroupId: APIGroupDetail['bookGroupId'] +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (group: Omit) => + groupAPI.updateGroupInfo({ bookGroupId, group }).then(({ data }) => data), + onSuccess: () => + queryClient.invalidateQueries({ + queryKey: bookGroupKeys.detail(bookGroupId), + }), + }); +}; diff --git a/src/styles/theme.tsx b/src/styles/theme.tsx index 421b59b6..1dd5222d 100644 --- a/src/styles/theme.tsx +++ b/src/styles/theme.tsx @@ -107,24 +107,6 @@ const theme: ThemeOverride = extendTheme({ buttonSizes, colors, scheme, - styles: { - global: { - 'input[type="date"]': { - position: 'relative', - }, - 'input[type="date"]::-webkit-inner-spin-button, input[type="date"]::-webkit-calendar-picker-indicator': - { - position: 'absolute', - left: 0, - top: 0, - width: '100%', - height: '100%', - background: 'transparent', - color: 'transparent', - cursor: 'pointer', - }, - }, - }, shadows, }); diff --git a/src/types/group.ts b/src/types/group.ts index 998f138a..289b95c7 100644 --- a/src/types/group.ts +++ b/src/types/group.ts @@ -95,3 +95,12 @@ export type BookGroupComment = { createdAt: APIGroupComment['createdAt']; content: APIGroupComment['contents']; }; + +export type APIEditBookGroup = { + isOwner: APIGroupDetail['isOwner']; + title: APIGroupDetail['title']; + introduce: APIGroupDetail['introduce']; + maxMemberCount: APIGroupDetail['maxMemberCount']; + startDate: APIGroupDetail['startDate']; + endDate: APIGroupDetail['endDate']; +}; diff --git a/src/v1/base/DatePicker.tsx b/src/v1/base/DatePicker.tsx index b466a525..0465b2ba 100644 --- a/src/v1/base/DatePicker.tsx +++ b/src/v1/base/DatePicker.tsx @@ -1,3 +1,5 @@ +'use client'; + import { ChangeEventHandler, forwardRef, @@ -51,7 +53,7 @@ const DatePicker = ( return (