diff --git a/src/components/pages/premium-study-detail-page.tsx b/src/components/pages/premium-study-detail-page.tsx index cac6719d..7cda1c5c 100644 --- a/src/components/pages/premium-study-detail-page.tsx +++ b/src/components/pages/premium-study-detail-page.tsx @@ -42,8 +42,11 @@ export default function PremiumStudyDetailPage({ const activeTab = (searchParams.get('tab') as StudyTabValue) || 'intro'; - const { data: studyDetail, isLoading } = - useGroupStudyDetailQuery(groupStudyId); + const { + data: studyDetail, + isLoading, + refetch: refetchStudyDetail, + } = useGroupStudyDetailQuery(groupStudyId); const leaderId = studyDetail?.basicInfo.leader.memberId; @@ -120,6 +123,7 @@ export default function PremiumStudyDetailPage({ alert('스터디 삭제에 실패하였습니다.'); }, onSettled: () => { + refetchStudyDetail().catch(() => {}); router.push('/premium-study'); setShowModal(false); }, diff --git a/src/features/study/group/api/create-group-study.ts b/src/features/study/group/api/create-group-study.ts index 66c5c36f..20a8dd00 100644 --- a/src/features/study/group/api/create-group-study.ts +++ b/src/features/study/group/api/create-group-study.ts @@ -1,8 +1,8 @@ import { axiosInstance } from '@/api/client/axios'; -import { GroupStudyFormRequest } from './group-study-types'; +import { GroupStudyCreateRequest } from './group-study-types'; -// CS 스터디 매칭 신청 -export const createGroupStudy = async (payload: GroupStudyFormRequest) => { +// 그룹 스터디 개설 +export const createGroupStudy = async (payload: GroupStudyCreateRequest) => { try { const res = await axiosInstance.post('/group-studies', payload); diff --git a/src/features/study/group/api/group-study-types.ts b/src/features/study/group/api/group-study-types.ts index 71c92e42..696da154 100644 --- a/src/features/study/group/api/group-study-types.ts +++ b/src/features/study/group/api/group-study-types.ts @@ -56,7 +56,65 @@ export interface BasicInfo { updatedAt: string; } -// 요청용 BasicInfo (백엔드 request body에서 createdAt, updatedAt 제외됨) +// ============================================================ +// Create/Update API 공통 타입 +// ============================================================ + +/** Create/Update API에서 공통으로 사용되는 BasicInfo 필드 */ +export interface BasicInfoCommon { + type: StudyType; + targetRoles: TargetRole[]; + maxMembersCount: number; + experienceLevels: ExperienceLevel[]; + method: StudyMethod; + regularMeeting: RegularMeeting; + location: string; + startDate: string; + endDate: string; + price: number; + studyLeaderParticipation: boolean; +} + +/** Create/Update API에서 공통으로 사용되는 Request 구조 */ +export interface GroupStudyRequestCommon { + detailInfo: DetailInfo; + interviewPost: { + interviewPost: string[]; + }; + thumbnailExtension: ThumbnailExtension; +} + +// ============================================================ +// Create API 전용 타입 +// ============================================================ + +/** Create API용 BasicInfo (classification 필수) */ +export interface BasicInfoCreateRequest extends BasicInfoCommon { + classification: 'GROUP_STUDY' | 'PREMIUM_STUDY'; +} + +/** Create API 전체 Request */ +export interface GroupStudyCreateRequest extends GroupStudyRequestCommon { + basicInfo: BasicInfoCreateRequest; +} + +// ============================================================ +// Update API 전용 타입 +// ============================================================ + +/** Update API용 BasicInfo (classification 없음 - 수정 불가) */ +export type BasicInfoUpdateRequest = BasicInfoCommon; + +/** Update API 전체 Request */ +export interface GroupStudyUpdateRequest extends GroupStudyRequestCommon { + basicInfo: BasicInfoUpdateRequest; +} + +// ============================================================ +// 기존 타입 (하위 호환성 유지) +// ============================================================ + +/** @deprecated BasicInfoCreateRequest 사용 권장 */ export type BasicInfoRequest = Omit; export interface BasicInfoDetail extends BasicInfo { @@ -162,6 +220,7 @@ export interface ApplyGroupStudyResponse { createdAt: string; } +/** @deprecated GroupStudyCreateRequest 또는 GroupStudyUpdateRequest 사용 권장 */ export interface GroupStudyFormRequest { basicInfo: BasicInfoRequest; detailInfo: DetailInfo; diff --git a/src/features/study/group/api/update-group-study.ts b/src/features/study/group/api/update-group-study.ts index 3d4eb0d1..2cccdf1f 100644 --- a/src/features/study/group/api/update-group-study.ts +++ b/src/features/study/group/api/update-group-study.ts @@ -1,13 +1,13 @@ import { axiosInstance } from '@/api/client/axios'; import { GroupStudyCreationResponse, - GroupStudyFormRequest, + GroupStudyUpdateRequest, } from './group-study-types'; // 그룹 스터디 수정 export const updateGroupStudy = async ( groupStudyId: number, - payload: GroupStudyFormRequest, + payload: GroupStudyUpdateRequest, ): Promise => { try { const res = await axiosInstance.put( diff --git a/src/features/study/group/const/use-group-study-mutation.ts b/src/features/study/group/const/use-group-study-mutation.ts index 848ffd30..51fede36 100644 --- a/src/features/study/group/const/use-group-study-mutation.ts +++ b/src/features/study/group/const/use-group-study-mutation.ts @@ -1,19 +1,22 @@ import { useMutation } from '@tanstack/react-query'; import { createGroupStudy } from '../api/create-group-study'; -import { GroupStudyFormRequest } from '../api/group-study-types'; +import { + GroupStudyCreateRequest, + GroupStudyUpdateRequest, +} from '../api/group-study-types'; import { updateGroupStudy } from '../api/update-group-study'; // 그룹 스터디 개설 mutation export const useCreateGroupStudyMutation = () => { return useMutation({ - mutationFn: (payload: GroupStudyFormRequest) => createGroupStudy(payload), + mutationFn: (payload: GroupStudyCreateRequest) => createGroupStudy(payload), }); }; // 그룹 스터디 수정 mutation export const useUpdateGroupStudyMutation = (groupStudyId: number) => { return useMutation({ - mutationFn: (payload: GroupStudyFormRequest) => + mutationFn: (payload: GroupStudyUpdateRequest) => updateGroupStudy(groupStudyId, payload), }); }; diff --git a/src/features/study/group/model/group-study-form.schema.ts b/src/features/study/group/model/group-study-form.schema.ts index a9b8c4ba..fa3b61b9 100644 --- a/src/features/study/group/model/group-study-form.schema.ts +++ b/src/features/study/group/model/group-study-form.schema.ts @@ -1,5 +1,11 @@ import { z } from 'zod'; -import { GroupStudyFormRequest } from '../api/group-study-types'; +import { + BasicInfoCommon, + GroupStudyCreateRequest, + GroupStudyFormRequest, + GroupStudyRequestCommon, + GroupStudyUpdateRequest, +} from '../api/group-study-types'; import { STUDY_TYPES, TARGET_ROLE_OPTIONS, @@ -127,28 +133,35 @@ export function buildOpenGroupDefaultValues( }; } -export function toOpenGroupRequest( - v: GroupStudyFormValues, -): GroupStudyFormRequest { +// ============================================================ +// 변환 함수 (내부 헬퍼) +// ============================================================ + +/** 공통 BasicInfo 필드 변환 */ +function buildBasicInfoCommon(v: GroupStudyFormValues): BasicInfoCommon { const isPremiumStudy = v.classification === 'PREMIUM_STUDY'; + + return { + studyLeaderParticipation: v.studyLeaderParticipation, + type: v.type, + targetRoles: v.targetRoles, + maxMembersCount: Number(v.maxMembersCount), + experienceLevels: v.experienceLevels ?? [], + method: v.method, + regularMeeting: v.regularMeeting, + location: v.location.trim(), + startDate: v.startDate.trim(), + endDate: v.endDate.trim(), + price: isPremiumStudy ? Number(v.price) || 0 : 0, + }; +} + +/** 공통 Request 구조 변환 */ +function buildCommonRequest(v: GroupStudyFormValues): GroupStudyRequestCommon { const thumbnailExt = v.thumbnailExtension === 'DEFAULT' ? 'JPG' : v.thumbnailExtension; return { - basicInfo: { - studyLeaderParticipation: v.studyLeaderParticipation, - classification: v.classification, - type: v.type, - targetRoles: v.targetRoles, - maxMembersCount: Number(v.maxMembersCount), - experienceLevels: v.experienceLevels ?? [], - method: v.method, - regularMeeting: v.regularMeeting, - location: v.location.trim(), - startDate: v.startDate.trim(), - endDate: v.endDate.trim(), - price: isPremiumStudy ? Number(v.price) || 0 : 0, - }, detailInfo: { thumbnailExtension: thumbnailExt, title: v.title, @@ -161,3 +174,41 @@ export function toOpenGroupRequest( thumbnailExtension: thumbnailExt, }; } + +// ============================================================ +// Create/Update 전용 변환 함수 +// ============================================================ + +/** Create API용 Request 변환 */ +export function toCreateRequest( + v: GroupStudyFormValues, +): GroupStudyCreateRequest { + return { + ...buildCommonRequest(v), + basicInfo: { + ...buildBasicInfoCommon(v), + classification: v.classification, + }, + }; +} + +/** Update API용 Request 변환 */ +export function toUpdateRequest( + v: GroupStudyFormValues, +): GroupStudyUpdateRequest { + return { + ...buildCommonRequest(v), + basicInfo: buildBasicInfoCommon(v), + }; +} + +// ============================================================ +// 기존 함수 (하위 호환성 유지) +// ============================================================ + +/** @deprecated toCreateRequest 또는 toUpdateRequest 사용 권장 */ +export function toOpenGroupRequest( + v: GroupStudyFormValues, +): GroupStudyFormRequest { + return toCreateRequest(v); +} diff --git a/src/features/study/group/ui/group-study-form-modal.tsx b/src/features/study/group/ui/group-study-form-modal.tsx index ec98daec..ff19a2dd 100644 --- a/src/features/study/group/ui/group-study-form-modal.tsx +++ b/src/features/study/group/ui/group-study-form-modal.tsx @@ -20,7 +20,8 @@ import { buildOpenGroupDefaultValues, GroupStudyFormValues, StudyClassification, - toOpenGroupRequest, + toCreateRequest, + toUpdateRequest, } from '../model/group-study-form.schema'; import { useGroupStudyDetailQuery } from '../model/use-study-query'; @@ -140,7 +141,7 @@ export default function GroupStudyFormModal({ const handleCreate = async (values: GroupStudyFormValues) => { try { - const body = toOpenGroupRequest(values); + const body = toCreateRequest(values); const created = await createGroupStudy(body); if (values.thumbnailFile) { @@ -166,7 +167,7 @@ export default function GroupStudyFormModal({ const handleEdit = async (values: GroupStudyFormValues) => { try { - const body = toOpenGroupRequest(values); + const body = toUpdateRequest(values); const updated = await updateGroupStudy(body); if (values.thumbnailFile) {