-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 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: 페이지 접근 권한 추가 (로그인 & 모임 장)
- Loading branch information
Showing
11 changed files
with
333 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<APIGroupDetail>(); | ||
|
||
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<Omit<APIEditBookGroup, 'isOwner'>>({ | ||
mode: 'all', | ||
defaultValues: { | ||
title: title, | ||
introduce: description, | ||
maxMemberCount: maxMemberCount ? maxMemberCount : 9999, | ||
startDate: startDate, | ||
endDate: endDate, | ||
}, | ||
}); | ||
|
||
const handleFormSubmit: SubmitHandler< | ||
Omit<APIEditBookGroup, 'isOwner' | 'startDate'> | ||
> = 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 ( | ||
<AuthRequired> | ||
<VStack justify="center" align="center"> | ||
<TopNavigation pageTitle="모임 수정" /> | ||
{group && <EditGroupForm group={group} />} | ||
</VStack> | ||
</AuthRequired> | ||
<FormProvider {...methods}> | ||
<BookGroupEditTopNavigation onSubmit={handleFormSubmit} /> | ||
|
||
<form | ||
className="mt-[2.5rem] flex flex-col gap-[3.2rem]" | ||
onSubmit={methods.handleSubmit(handleFormSubmit)} | ||
> | ||
<BookGroupEditTitleForm /> | ||
<BookGroupEditIntroduceForm /> | ||
<BookGroupEditDateForm /> | ||
</form> | ||
</FormProvider> | ||
); | ||
}; | ||
|
||
export default GroupEditPage; | ||
export default BookGroupEditPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { useFormContext } from 'react-hook-form'; | ||
|
||
import type { APIEditBookGroup } from '@/types/group'; | ||
|
||
import DatePicker from '@/v1/base/DatePicker'; | ||
import ErrorMessage from '@/v1/base/ErrorMessage'; | ||
|
||
type EditDateFormTypes = Pick<APIEditBookGroup, 'startDate' | 'endDate'>; | ||
|
||
const BookGroupEditDateForm = () => { | ||
const { | ||
register, | ||
formState: { errors, defaultValues }, | ||
} = useFormContext<EditDateFormTypes>(); | ||
|
||
return ( | ||
<> | ||
<section className="flex justify-between"> | ||
<div> | ||
<h2 className="text-md text-black-500">모임 시작일</h2> | ||
<p className="text-xs text-placeholder"> | ||
모임 시작일은 수정할 수 없어요 | ||
</p> | ||
</div> | ||
<DatePicker disabled={true} {...register('startDate')} /> | ||
</section> | ||
<section className="flex flex-col gap-[0.5rem]"> | ||
<div className="flex justify-between"> | ||
<h2 className="text-md text-black-700">모임 종료일</h2> | ||
<DatePicker | ||
{...register('endDate', { | ||
required: { value: true, message: '종료일을 입력해주세요' }, | ||
min: { | ||
value: defaultValues?.startDate as string, | ||
message: '종료일은 시작일보다 늦어야 해요', | ||
}, | ||
})} | ||
/> | ||
</div> | ||
<div> | ||
{errors.endDate && ( | ||
<ErrorMessage>{errors.endDate.message}</ErrorMessage> | ||
)} | ||
</div> | ||
</section> | ||
</> | ||
); | ||
}; | ||
|
||
export default BookGroupEditDateForm; |
Oops, something went wrong.