From 68e8eb53c7368cad23a2b25ad0a6db0f4ac42ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 16:53:36 +0900 Subject: [PATCH 01/15] =?UTF-8?q?refactor:=20const=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/interview/const/interview-const.ts | 6 ++++++ .../const/participation-const.ts} | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) create mode 100644 src/features/study/interview/const/interview-const.ts rename src/features/study/{consts/study-const.ts => participation/const/participation-const.ts} (87%) diff --git a/src/features/study/interview/const/interview-const.ts b/src/features/study/interview/const/interview-const.ts new file mode 100644 index 00000000..69c334e1 --- /dev/null +++ b/src/features/study/interview/const/interview-const.ts @@ -0,0 +1,6 @@ +export const STUDY_PROGRESS_OPTIONS = [ + { label: '시작 전', value: 'PENDING' }, + { label: '불참', value: 'ABSENT' }, + { label: '진행중', value: 'IN_PROGRESS' }, + { label: '완료', value: 'COMPLETE' }, +]; diff --git a/src/features/study/consts/study-const.ts b/src/features/study/participation/const/participation-const.ts similarity index 87% rename from src/features/study/consts/study-const.ts rename to src/features/study/participation/const/participation-const.ts index 854748db..4171ccf3 100644 --- a/src/features/study/consts/study-const.ts +++ b/src/features/study/participation/const/participation-const.ts @@ -1,10 +1,3 @@ -export const STUDY_PROGRESS_OPTIONS = [ - { label: '시작 전', value: 'PENDING' }, - { label: '불참', value: 'ABSENT' }, - { label: '진행중', value: 'IN_PROGRESS' }, - { label: '완료', value: 'COMPLETE' }, -]; - export const studySteps = [ { title: '1. 면접 준비', From dba7562d3df7f05e1842e8c532a52b67e2a5d352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 16:54:55 +0900 Subject: [PATCH 02/15] =?UTF-8?q?refactor:=20lib=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/user/ui/my-profile-card.tsx | 4 ++-- .../study/{ => interview}/lib/use-reminder-review.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/features/study/{ => interview}/lib/use-reminder-review.tsx (93%) diff --git a/src/entities/user/ui/my-profile-card.tsx b/src/entities/user/ui/my-profile-card.tsx index cd2eac19..b1b90435 100644 --- a/src/entities/user/ui/my-profile-card.tsx +++ b/src/entities/user/ui/my-profile-card.tsx @@ -3,8 +3,8 @@ import Link from 'next/link'; import React, { useState } from 'react'; import { usePatchAutoMatchingMutation } from '@/entities/user/model/use-user-profile-query'; -import { useReviewReminder } from '@/features/study/lib/use-reminder-review'; -import StudyReviewModal from '@/features/study/ui/study-review-modal'; +import { useReviewReminder } from '@/features/study/interview/lib/use-reminder-review'; +import StudyReviewModal from '@/features/study/interview/ui/study-review-modal'; import { getSincerityPresetByLevelName } from '@/shared/config/sincerity-temp-presets'; import { cn } from '@/shared/shadcn/lib/utils'; import UserAvatar from '@/shared/ui/avatar'; diff --git a/src/features/study/lib/use-reminder-review.tsx b/src/features/study/interview/lib/use-reminder-review.tsx similarity index 93% rename from src/features/study/lib/use-reminder-review.tsx rename to src/features/study/interview/lib/use-reminder-review.tsx index 4ab66b54..076af1e4 100644 --- a/src/features/study/lib/use-reminder-review.tsx +++ b/src/features/study/interview/lib/use-reminder-review.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { getKoreaDate } from '@/shared/lib/time'; -import { useShouldReviewPartnerQuery } from '../model/use-review-query'; +import { useShouldReviewPartnerQuery } from '../../model/use-review-query'; export const useReviewReminder = () => { const { data: shouldReview, isFetching } = useShouldReviewPartnerQuery(); From 4b112dc45d0993d01e50f430e3513ab29248d456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 17:10:33 +0900 Subject: [PATCH 03/15] =?UTF-8?q?refactor:=20study=20api=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=B3=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/interview/api/get-interview.ts | 28 ++++++++++ .../study/{ => interview}/api/get-review.ts | 2 +- .../api/get-participation-data.ts | 24 ++++++++- .../api/get-study-schedule.tsx} | 54 ++----------------- 4 files changed, 54 insertions(+), 54 deletions(-) create mode 100644 src/features/study/interview/api/get-interview.ts rename src/features/study/{ => interview}/api/get-review.ts (98%) rename src/features/study/{api/get-study-data.ts => schedule/api/get-study-schedule.tsx} (50%) diff --git a/src/features/study/interview/api/get-interview.ts b/src/features/study/interview/api/get-interview.ts new file mode 100644 index 00000000..21336563 --- /dev/null +++ b/src/features/study/interview/api/get-interview.ts @@ -0,0 +1,28 @@ +import type { + CompleteStudyRequest, + PrepareStudyRequest, +} from '@/features/study/interview/api/interview-types'; +import { axiosInstance } from '@/shared/tanstack-query/axios'; + +// 면접 준비 시작 +export const putStudyDaily = async ( + dailyId: number, + body: PrepareStudyRequest, +) => { + const res = await axiosInstance.put(`/study/daily/${dailyId}/prepare`, body); + + return res.data; +}; + +// 면접 완료 및 회고 작성 +export const completeStudy = async ( + dailyStudyId: number, + body: CompleteStudyRequest, +) => { + const res = await axiosInstance.post( + `/study/daily/${dailyStudyId}/complete`, + body, + ); + + return res.data; +}; \ No newline at end of file diff --git a/src/features/study/api/get-review.ts b/src/features/study/interview/api/get-review.ts similarity index 98% rename from src/features/study/api/get-review.ts rename to src/features/study/interview/api/get-review.ts index 58b3a4cb..ff521549 100644 --- a/src/features/study/api/get-review.ts +++ b/src/features/study/interview/api/get-review.ts @@ -9,7 +9,7 @@ import type { MyReviewsResponse, MyReviewsRequest, ShouldReviewPartnerResponse, -} from './types'; +} from '../../api/types'; export const getPartnerStudyReview = async (): Promise => { diff --git a/src/features/study/participation/api/get-participation-data.ts b/src/features/study/participation/api/get-participation-data.ts index 82791ff4..57ab27fd 100644 --- a/src/features/study/participation/api/get-participation-data.ts +++ b/src/features/study/participation/api/get-participation-data.ts @@ -1,11 +1,13 @@ -import { axiosInstance } from '@/shared/tanstack-query/axios'; import { WeeklyReservationRequest, WeeklyReservationResponse, ReservationUserItem, Participant, -} from './participation-types'; + JoinStudyRequest, +} from '@/features/study/participation/api/participation-types'; +import { axiosInstance } from '@/shared/tanstack-query/axios'; +// 스터디 신청 목록 서버데이터 -> UI 매핑 함수 export function mapReservation(user: ReservationUserItem): Participant { const original = user.profileImage?.resizedImages.find( (img) => img.imageSizeType.imageTypeName === 'ORIGINAL', @@ -19,6 +21,7 @@ export function mapReservation(user: ReservationUserItem): Participant { }; } +// 스터디 신청 목록 export const getReservationMembers = async ( params: WeeklyReservationRequest, ): Promise => { @@ -37,8 +40,25 @@ export const getReservationMembers = async ( export type StudyStatus = 'RECRUITING' | 'STUDYING'; +// 스터디 시작/종료 유무 확인 export const getStudyStatus = async (): Promise => { const res = await axiosInstance.get('/matching/system-status'); return res.data.content.status as StudyStatus; }; + +// CS 스터디 매칭 신청 +export const postJoinStudy = async (payload: JoinStudyRequest) => { + const cleanPayload = Object.fromEntries( + Object.entries(payload).filter( + ([_, value]) => + value !== undefined && + value !== '' && + !(Array.isArray(value) && value.length === 0), + ), + ); + + const res = await axiosInstance.post('/matching/apply', cleanPayload); + + return res.data; +}; diff --git a/src/features/study/api/get-study-data.ts b/src/features/study/schedule/api/get-study-schedule.tsx similarity index 50% rename from src/features/study/api/get-study-data.ts rename to src/features/study/schedule/api/get-study-schedule.tsx index 89f1c674..f16093ac 100644 --- a/src/features/study/api/get-study-data.ts +++ b/src/features/study/schedule/api/get-study-schedule.tsx @@ -1,15 +1,12 @@ -import type { - CompleteStudyRequest, +// 매칭 결과 목록, 오늘의 스터디 상세 정보, 나의 스터디 캘린더 +import { DailyStudyDetail, GetDailyStudiesParams, GetDailyStudiesResponse, GetMonthlyCalendarParams, - JoinStudyRequest, MonthlyCalendarResponse, - PostDailyRetrospectRequest, - PrepareStudyRequest, WeeklyParticipationResponse, -} from '@/features/study/api/types'; +} from '@/features/study/schedule/api/schedule-types'; import { axiosInstance } from '@/shared/tanstack-query/axios'; // 스터디 상세 조회 @@ -39,51 +36,6 @@ export const getMonthlyStudyCalendar = async ( return res.data.content; }; -export const postDailyRetrospect = async (body: PostDailyRetrospectRequest) => { - const res = await axiosInstance.post('/study/daily/retrospect', body); - - return res.data; -}; - -// 면접 준비 시작 -export const putStudyDaily = async ( - dailyId: number, - body: PrepareStudyRequest, -) => { - const res = await axiosInstance.put(`/study/daily/${dailyId}/prepare`, body); - - return res.data; -}; - -// 면접 완료 및 회고 작성 -export const completeStudy = async ( - dailyStudyId: number, - body: CompleteStudyRequest, -) => { - const res = await axiosInstance.post( - `/study/daily/${dailyStudyId}/complete`, - body, - ); - - return res.data; -}; - -// CS 스터디 매칭 신청 -export const postJoinStudy = async (payload: JoinStudyRequest) => { - const cleanPayload = Object.fromEntries( - Object.entries(payload).filter( - ([_, value]) => - value !== undefined && - value !== '' && - !(Array.isArray(value) && value.length === 0), - ), - ); - - const res = await axiosInstance.post('/matching/apply', cleanPayload); - - return res.data; -}; - // 스터디 참여 유무 확인 export const getWeeklyParticipation = async ( studyDate: string, From 19f5c222a36a0946700b64f6213b1f1025efde5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 17:40:41 +0900 Subject: [PATCH 04/15] =?UTF-8?q?refactor:=20study=20type=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/interview-types.ts} | 69 ++----------------- .../participation/api/participation-types.ts | 14 ++++ .../study/schedule/api/schedule-types.ts | 58 ++++++++++++++++ 3 files changed, 76 insertions(+), 65 deletions(-) rename src/features/study/{api/types.ts => interview/api/interview-types.ts} (67%) create mode 100644 src/features/study/schedule/api/schedule-types.ts diff --git a/src/features/study/api/types.ts b/src/features/study/interview/api/interview-types.ts similarity index 67% rename from src/features/study/api/types.ts rename to src/features/study/interview/api/interview-types.ts index 70fd16c9..f508a71c 100644 --- a/src/features/study/api/types.ts +++ b/src/features/study/interview/api/interview-types.ts @@ -4,20 +4,7 @@ export type StudyProgressStatus = | 'COMPLETE' | 'ABSENT'; -export interface DailyStudy { - interviewer: string; - interviewerImage: string; - interviewee: string; - intervieweeImage: string; - dailyStudyId: number; - subject: string; - description: string; - link: string; - progressStatus: StudyProgressStatus; - studyDate: string; - feedback: string | undefined; -} - +// 오늘의 스터디 상세조회 관련 타입 export interface DailyStudyDetail { dailyStudyId: number; interviewerId: number; @@ -34,67 +21,19 @@ export interface DailyStudyDetail { feedback: string; } -export interface GetDailyStudiesParams { - cursor?: number; - pageSize?: number; - studyDate?: string; -} - -export interface GetDailyStudiesResponse { - items: DailyStudy[]; - nextCursor: number; - hasNext: boolean; -} - -export interface GetMonthlyCalendarParams { - year: number; - month: number; -} - -export interface StudyCalendarDay { - day: number; - hasStudy: boolean; - status: StudyProgressStatus | undefined; -} - -export interface MonthlyCalendarResponse { - calendar: StudyCalendarDay[]; - monthlyCompletedCount?: number; - totalCompletedCount?: number; -} - -export interface PostDailyRetrospectRequest { - description: string; - parentId: number; -} - +// 스터디 면접 준비 타입 export interface PrepareStudyRequest { subject: string; link: string; } -export interface JoinStudyRequest { - memberId: number; - selfIntroduction?: string; - studyPlan?: string; - preferredStudySubjectId?: string; - availableStudyTimeIds?: number[]; - techStackIds?: number[]; - tel?: string; - githubLink?: string; - blogOrSnsLink?: string; -} - -export interface WeeklyParticipationResponse { - memberId: number; - isParticipate: boolean; -} - +// 스터디 면접 완료 타입 export interface CompleteStudyRequest { feedback: string; progressStatus: StudyProgressStatus; } +// 리뷰 관련 타입 export interface EvalKeyword { id: number; keyword: string; diff --git a/src/features/study/participation/api/participation-types.ts b/src/features/study/participation/api/participation-types.ts index 0a5eb343..01fe8178 100644 --- a/src/features/study/participation/api/participation-types.ts +++ b/src/features/study/participation/api/participation-types.ts @@ -1,3 +1,4 @@ +// 다음주 신청 리스트 조회 관련 타입 export interface ReservationUserItem { memberId: number; memberName: string; @@ -37,3 +38,16 @@ export interface WeeklyReservationRequest { pageSize?: number; firstMemberId?: number; } + +// 스터디 참여 신청 타입 +export interface JoinStudyRequest { + memberId: number; + selfIntroduction?: string; + studyPlan?: string; + preferredStudySubjectId?: string; + availableStudyTimeIds?: number[]; + techStackIds?: number[]; + tel?: string; + githubLink?: string; + blogOrSnsLink?: string; +} \ No newline at end of file diff --git a/src/features/study/schedule/api/schedule-types.ts b/src/features/study/schedule/api/schedule-types.ts new file mode 100644 index 00000000..fbc248ef --- /dev/null +++ b/src/features/study/schedule/api/schedule-types.ts @@ -0,0 +1,58 @@ +export type StudyProgressStatus = + | 'PENDING' + | 'IN_PROGRESS' + | 'COMPLETE' + | 'ABSENT'; + +// 스터디 시작/종료 유무 타입 +export type StudyStatus = 'RECRUITING' | 'STUDYING'; + +// 스터디 매칭 리스트 관련 타입 +export interface GetDailyStudiesParams { + cursor?: number; + pageSize?: number; + studyDate?: string; +} + +export interface DailyStudy { + interviewer: string; + interviewerImage: string; + interviewee: string; + intervieweeImage: string; + dailyStudyId: number; + subject: string; + description: string; + link: string; + progressStatus: StudyProgressStatus; + studyDate: string; + feedback: string | undefined; +} + +export interface GetDailyStudiesResponse { + items: DailyStudy[]; + nextCursor: number; + hasNext: boolean; +} + +// 캘린더 관련 타입 +export interface GetMonthlyCalendarParams { + year: number; + month: number; +} + +export interface StudyCalendarDay { + day: number; + hasStudy: boolean; + status: StudyProgressStatus | undefined; +} + +export interface MonthlyCalendarResponse { + calendar: StudyCalendarDay[]; + monthlyCompletedCount?: number; + totalCompletedCount?: number; +} + +export interface WeeklyParticipationResponse { + memberId: number; + isParticipate: boolean; +} From f3638916bd6d09ee6094afef78904ba6edbbf1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 17:42:09 +0900 Subject: [PATCH 05/15] =?UTF-8?q?fix:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=20=EC=9C=A0=EB=AC=B4,=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/interview/api/get-interview.ts | 12 +++++++++++- .../api/get-participation-data.ts | 9 --------- .../study/schedule/api/get-study-schedule.tsx | 18 ++++++++---------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/features/study/interview/api/get-interview.ts b/src/features/study/interview/api/get-interview.ts index 21336563..c5feef00 100644 --- a/src/features/study/interview/api/get-interview.ts +++ b/src/features/study/interview/api/get-interview.ts @@ -1,9 +1,19 @@ import type { CompleteStudyRequest, + DailyStudyDetail, PrepareStudyRequest, } from '@/features/study/interview/api/interview-types'; import { axiosInstance } from '@/shared/tanstack-query/axios'; +// 스터디 상세 조회 +export const getDailyStudyDetail = async ( + params: string, +): Promise => { + const res = await axiosInstance.get(`/study/daily/mine/${params}`); + + return res.data.content; +}; + // 면접 준비 시작 export const putStudyDaily = async ( dailyId: number, @@ -25,4 +35,4 @@ export const completeStudy = async ( ); return res.data; -}; \ No newline at end of file +}; diff --git a/src/features/study/participation/api/get-participation-data.ts b/src/features/study/participation/api/get-participation-data.ts index 57ab27fd..ea71e138 100644 --- a/src/features/study/participation/api/get-participation-data.ts +++ b/src/features/study/participation/api/get-participation-data.ts @@ -38,15 +38,6 @@ export const getReservationMembers = async ( return res.data.content; }; -export type StudyStatus = 'RECRUITING' | 'STUDYING'; - -// 스터디 시작/종료 유무 확인 -export const getStudyStatus = async (): Promise => { - const res = await axiosInstance.get('/matching/system-status'); - - return res.data.content.status as StudyStatus; -}; - // CS 스터디 매칭 신청 export const postJoinStudy = async (payload: JoinStudyRequest) => { const cleanPayload = Object.fromEntries( diff --git a/src/features/study/schedule/api/get-study-schedule.tsx b/src/features/study/schedule/api/get-study-schedule.tsx index f16093ac..b2345f0d 100644 --- a/src/features/study/schedule/api/get-study-schedule.tsx +++ b/src/features/study/schedule/api/get-study-schedule.tsx @@ -1,23 +1,14 @@ // 매칭 결과 목록, 오늘의 스터디 상세 정보, 나의 스터디 캘린더 import { - DailyStudyDetail, GetDailyStudiesParams, GetDailyStudiesResponse, GetMonthlyCalendarParams, MonthlyCalendarResponse, + StudyStatus, WeeklyParticipationResponse, } from '@/features/study/schedule/api/schedule-types'; import { axiosInstance } from '@/shared/tanstack-query/axios'; -// 스터디 상세 조회 -export const getDailyStudyDetail = async ( - params: string, -): Promise => { - const res = await axiosInstance.get(`/study/daily/mine/${params}`); - - return res.data.content; -}; - // 스터디 전체 조회 export const getDailyStudies = async ( params?: GetDailyStudiesParams, @@ -46,3 +37,10 @@ export const getWeeklyParticipation = async ( return res.data.content; }; + +// 스터디 시작/종료 유무 확인 +export const getStudyStatus = async (): Promise => { + const res = await axiosInstance.get('/matching/system-status'); + + return res.data.content.status as StudyStatus; +}; From 99faeaebb6a0f21df83eb0b9913adc3ec011e459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 17:43:05 +0900 Subject: [PATCH 06/15] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=84=B0=EB=94=94?= =?UTF-8?q?=20query=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/use-interview-query.ts} | 50 +----------------- .../{ => interview}/model/use-review-query.ts | 8 +-- .../model/use-participation-query.ts | 28 +++++----- .../schedule/model/use-schedule-query.ts | 52 +++++++++++++++++++ 4 files changed, 73 insertions(+), 65 deletions(-) rename src/features/study/{model/use-study-query.ts => interview/model/use-interview-query.ts} (52%) rename src/features/study/{ => interview}/model/use-review-query.ts (97%) create mode 100644 src/features/study/schedule/model/use-schedule-query.ts diff --git a/src/features/study/model/use-study-query.ts b/src/features/study/interview/model/use-interview-query.ts similarity index 52% rename from src/features/study/model/use-study-query.ts rename to src/features/study/interview/model/use-interview-query.ts index 8976355c..4a3b32e1 100644 --- a/src/features/study/model/use-study-query.ts +++ b/src/features/study/interview/model/use-interview-query.ts @@ -1,31 +1,13 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { completeStudy, - getDailyStudies, getDailyStudyDetail, - getMonthlyStudyCalendar, - getWeeklyParticipation, - postJoinStudy, putStudyDaily, -} from '@/features/study/api/get-study-data'; +} from '@/features/study/interview/api/get-interview'; import { CompleteStudyRequest, - GetDailyStudiesParams, - GetMonthlyCalendarParams, - JoinStudyRequest, - MonthlyCalendarResponse, PrepareStudyRequest, -} from '../api/types'; - -// 스터디 주간 참여 유무 확인 query -export const useWeeklyParticipation = (params: string) => { - return useQuery({ - queryKey: ['weeklyParticipation', params], - queryFn: () => getWeeklyParticipation(params), - staleTime: 60 * 1000, - enabled: !!params, - }); -}; +} from '@/features/study/interview/api/interview-types'; // 스터디 상세 조회 query export const useDailyStudyDetailQuery = (params: string) => { @@ -37,34 +19,6 @@ export const useDailyStudyDetailQuery = (params: string) => { }); }; -// 스터디 전체 조회 query -export const useDailyStudiesQuery = (params?: GetDailyStudiesParams) => { - return useQuery({ - queryKey: ['dailyStudies', params], - queryFn: () => getDailyStudies(params), - staleTime: 60 * 1000, - }); -}; - -// 스터디 캘린더 조회 query -export const useMonthlyStudyCalendarQuery = ( - params: GetMonthlyCalendarParams, -) => { - return useQuery({ - queryKey: ['monthlyStudyCalendar', params], - queryFn: () => getMonthlyStudyCalendar(params), - staleTime: 60 * 1000, - enabled: !!params?.year && !!params?.month, - }); -}; - -// 스터디 신청 mutation -export const useJoinStudyMutation = () => { - return useMutation({ - mutationFn: (payload: JoinStudyRequest) => postJoinStudy(payload), - }); -}; - // 스터디 상세 & 리스트 업데이트 interface UpdateDailyStudyVariables { dailyStudyId: number; diff --git a/src/features/study/model/use-review-query.ts b/src/features/study/interview/model/use-review-query.ts similarity index 97% rename from src/features/study/model/use-review-query.ts rename to src/features/study/interview/model/use-review-query.ts index fe2fbfc7..984e518d 100644 --- a/src/features/study/model/use-review-query.ts +++ b/src/features/study/interview/model/use-review-query.ts @@ -4,6 +4,10 @@ import { useQuery, useSuspenseQuery, } from '@tanstack/react-query'; +import { + MyNegativeKeywordsRequest, + UserPositiveKeywordsRequest, +} from '@/features/study/interview/api/interview-types'; import { getKoreaDate } from '@/shared/lib/time'; import { addStudyReview, @@ -13,10 +17,6 @@ import { getMyReviews, getShouldReviewPartner, } from '../api/get-review'; -import { - MyNegativeKeywordsRequest, - UserPositiveKeywordsRequest, -} from '../api/types'; export const usePartnerStudyReviewQuery = () => { return useSuspenseQuery({ diff --git a/src/features/study/participation/model/use-participation-query.ts b/src/features/study/participation/model/use-participation-query.ts index c4d46719..b976e555 100644 --- a/src/features/study/participation/model/use-participation-query.ts +++ b/src/features/study/participation/model/use-participation-query.ts @@ -1,12 +1,22 @@ -import { useInfiniteQuery, useQuery } from '@tanstack/react-query'; +import { useInfiniteQuery, useMutation } from '@tanstack/react-query'; import { getReservationMembers, - getStudyStatus, mapReservation, - StudyStatus, -} from '../api/get-participation-data'; -import { WeeklyReservationResponse } from '../api/participation-types'; + postJoinStudy, +} from '@/features/study/participation/api/get-participation-data'; +import { + JoinStudyRequest, + WeeklyReservationResponse, +} from '@/features/study/participation/api/participation-types'; + +// 스터디 신청 mutation +export const useJoinStudyMutation = () => { + return useMutation({ + mutationFn: (payload: JoinStudyRequest) => postJoinStudy(payload), + }); +}; +// 다음주차 스터디 신청 무한 스크롤 export function useInfiniteReservation(firstMemberId?: number, pageSize = 50) { return useInfiniteQuery({ queryKey: ['weeklyReservationMembers', { firstMemberId, pageSize }], @@ -44,11 +54,3 @@ export function useInfiniteReservation(firstMemberId?: number, pageSize = 50) { staleTime: 60 * 1000, }); } - -export const useStudyStatusQuery = () => { - return useQuery({ - queryKey: ['studyStatus'], - queryFn: getStudyStatus, - staleTime: 60 * 1000, - }); -}; diff --git a/src/features/study/schedule/model/use-schedule-query.ts b/src/features/study/schedule/model/use-schedule-query.ts new file mode 100644 index 00000000..68c9d28a --- /dev/null +++ b/src/features/study/schedule/model/use-schedule-query.ts @@ -0,0 +1,52 @@ +import { useQuery } from '@tanstack/react-query'; +import { + getDailyStudies, + getMonthlyStudyCalendar, + getStudyStatus, + getWeeklyParticipation, +} from '@/features/study/schedule/api/get-study-schedule'; +import { + GetDailyStudiesParams, + GetMonthlyCalendarParams, + MonthlyCalendarResponse, + StudyStatus, +} from '@/features/study/schedule/api/schedule-types'; + +// 스터디 주간 참여 유무 확인 query +export const useWeeklyParticipation = (params: string) => { + return useQuery({ + queryKey: ['weeklyParticipation', params], + queryFn: () => getWeeklyParticipation(params), + staleTime: 60 * 1000, + enabled: !!params, + }); +}; + +// 스터디 매칭 결과 조회 query +export const useDailyStudiesQuery = (params?: GetDailyStudiesParams) => { + return useQuery({ + queryKey: ['dailyStudies', params], + queryFn: () => getDailyStudies(params), + staleTime: 60 * 1000, + }); +}; + +// 스터디 캘린더 조회 query +export const useMonthlyStudyCalendarQuery = ( + params: GetMonthlyCalendarParams, +) => { + return useQuery({ + queryKey: ['monthlyStudyCalendar', params], + queryFn: () => getMonthlyStudyCalendar(params), + staleTime: 60 * 1000, + enabled: !!params?.year && !!params?.month, + }); +}; + +export const useStudyStatusQuery = () => { + return useQuery({ + queryKey: ['studyStatus'], + queryFn: getStudyStatus, + staleTime: 60 * 1000, + }); +}; From 17f2a87d3e22d194ba0988de93f56d46e6d4c841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 17:43:21 +0900 Subject: [PATCH 07/15] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=82=A4=EB=A7=88?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/{ => interview}/model/interview.schema.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) rename src/features/study/{ => interview}/model/interview.schema.ts (85%) diff --git a/src/features/study/model/interview.schema.ts b/src/features/study/interview/model/interview.schema.ts similarity index 85% rename from src/features/study/model/interview.schema.ts rename to src/features/study/interview/model/interview.schema.ts index 4f8bef55..041d01c1 100644 --- a/src/features/study/model/interview.schema.ts +++ b/src/features/study/interview/model/interview.schema.ts @@ -1,7 +1,10 @@ import { z } from 'zod'; +import type { + DailyStudyDetail, + StudyProgressStatus, +} from '@/features/study/interview/api/interview-types'; +import { STUDY_PROGRESS_OPTIONS } from '@/features/study/interview/const/interview-const'; import { UrlSchema } from '@/shared/util/zod-schema'; -import type { DailyStudyDetail, StudyProgressStatus } from '../api/types'; -import { STUDY_PROGRESS_OPTIONS } from '../consts/study-const'; // 스터디 준비 스키마 export const StudyReadyFormSchema = z.object({ From 247a4adfa350f4ef951659dd9fde214b0a37f834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 17:44:03 +0900 Subject: [PATCH 08/15] =?UTF-8?q?refactor:=20=EC=9D=B8=ED=84=B0=EB=B7=B0?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20UI=20=ED=8C=8C=EC=9D=BC=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ => interview}/ui/status-badge-map.tsx | 2 +- .../{ => interview}/ui/study-done-modal.tsx | 17 ++++++++--------- .../{ => interview}/ui/study-ready-modal.tsx | 9 ++++++--- .../{ => interview}/ui/study-review-modal.tsx | 5 ++++- 4 files changed, 19 insertions(+), 14 deletions(-) rename src/features/study/{ => interview}/ui/status-badge-map.tsx (85%) rename src/features/study/{ => interview}/ui/study-done-modal.tsx (93%) rename src/features/study/{ => interview}/ui/study-ready-modal.tsx (93%) rename src/features/study/{ => interview}/ui/study-review-modal.tsx (99%) diff --git a/src/features/study/ui/status-badge-map.tsx b/src/features/study/interview/ui/status-badge-map.tsx similarity index 85% rename from src/features/study/ui/status-badge-map.tsx rename to src/features/study/interview/ui/status-badge-map.tsx index 19cbaa63..e786831e 100644 --- a/src/features/study/ui/status-badge-map.tsx +++ b/src/features/study/interview/ui/status-badge-map.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from 'react'; +import { StudyProgressStatus } from '@/features/study/interview/api/interview-types'; import Badge from '@/shared/ui/badge'; -import { StudyProgressStatus } from '../api/types'; export function getStatusBadge(status: StudyProgressStatus): ReactNode { switch (status) { diff --git a/src/features/study/ui/study-done-modal.tsx b/src/features/study/interview/ui/study-done-modal.tsx similarity index 93% rename from src/features/study/ui/study-done-modal.tsx rename to src/features/study/interview/ui/study-done-modal.tsx index b3825ca6..f73bc34d 100644 --- a/src/features/study/ui/study-done-modal.tsx +++ b/src/features/study/interview/ui/study-done-modal.tsx @@ -5,24 +5,23 @@ import { XIcon } from 'lucide-react'; import { useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; +import type { + CompleteStudyRequest, + DailyStudyDetail, + StudyProgressStatus, +} from '@/features/study/interview/api/interview-types'; +import { STUDY_PROGRESS_OPTIONS } from '@/features/study/interview/const/interview-const'; +import { useUpdateDailyStudyMutation } from '@/features/study/interview/model/use-interview-query'; import Button from '@/shared/ui/button'; import { SingleDropdown } from '@/shared/ui/dropdown'; import FormField from '@/shared/ui/form/form-field'; import { TextAreaInput } from '@/shared/ui/input'; import { Modal } from '@/shared/ui/modal'; - -import type { - CompleteStudyRequest, - DailyStudyDetail, - StudyProgressStatus, -} from '../api/types'; -import { STUDY_PROGRESS_OPTIONS } from '../consts/study-const'; import { StudyDoneFormSchema, type StudyDoneFormValues, buildStudyDoneDefaults, -} from '../model/interview.schema'; -import { useUpdateDailyStudyMutation } from '../model/use-study-query'; +} from '@/features/study/interview/model/interview.schema'; interface StudyDoneModalProps { data: DailyStudyDetail; diff --git a/src/features/study/ui/study-ready-modal.tsx b/src/features/study/interview/ui/study-ready-modal.tsx similarity index 93% rename from src/features/study/ui/study-ready-modal.tsx rename to src/features/study/interview/ui/study-ready-modal.tsx index 56631828..02d98ea6 100644 --- a/src/features/study/ui/study-ready-modal.tsx +++ b/src/features/study/interview/ui/study-ready-modal.tsx @@ -5,18 +5,21 @@ import { XIcon } from 'lucide-react'; import { useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; +import type { + DailyStudyDetail, + PrepareStudyRequest, +} from '@/features/study/interview/api/interview-types'; +import { useUpdateDailyStudyMutation } from '@/features/study/interview/model/use-interview-query'; import Button from '@/shared/ui/button'; import FormField from '@/shared/ui/form/form-field'; import { BaseInput } from '@/shared/ui/input'; import { Modal } from '@/shared/ui/modal'; -import type { DailyStudyDetail, PrepareStudyRequest } from '../api/types'; import { StudyReadyFormSchema, type StudyReadyFormValues, buildStudyReadyDefaults, -} from '../model/interview.schema'; -import { useUpdateDailyStudyMutation } from '../model/use-study-query'; +} from '@/features/study/interview/model/interview.schema'; interface StudyReadyModalProps { data: DailyStudyDetail; diff --git a/src/features/study/ui/study-review-modal.tsx b/src/features/study/interview/ui/study-review-modal.tsx similarity index 99% rename from src/features/study/ui/study-review-modal.tsx rename to src/features/study/interview/ui/study-review-modal.tsx index 4bfd7ace..aa7f9666 100644 --- a/src/features/study/ui/study-review-modal.tsx +++ b/src/features/study/interview/ui/study-review-modal.tsx @@ -3,13 +3,16 @@ import { XIcon } from 'lucide-react'; import Image from 'next/image'; import { useState } from 'react'; +import { + EvalKeyword, + StudyEvaluationResponse, +} from '@/features/study/interview/api/interview-types'; import UserAvatar from '@/shared/ui/avatar'; import Button from '@/shared/ui/button'; import Checkbox from '@/shared/ui/checkbox'; import { TextAreaInput } from '@/shared/ui/input'; import ListItem from '@/shared/ui/list-item'; import { Modal } from '@/shared/ui/modal'; -import { EvalKeyword, StudyEvaluationResponse } from '../api/types'; import { useAddStudyReviewMutation, usePartnerStudyReviewQuery, From 8479243f2eaf6fb02ea0a5e0f5d2be8182db5d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 17:44:36 +0900 Subject: [PATCH 09/15] =?UTF-8?q?refactor:=20=EC=8A=A4=EC=BC=80=EC=A5=B4?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20UI=20=ED=8C=8C=EC=9D=BC=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/{ => schedule}/ui/data-selector.tsx | 0 .../study/{ => schedule}/ui/study-card.tsx | 14 ++++++++------ .../study/{ => schedule}/ui/today-study-card.tsx | 10 ++++------ 3 files changed, 12 insertions(+), 12 deletions(-) rename src/features/study/{ => schedule}/ui/data-selector.tsx (100%) rename src/features/study/{ => schedule}/ui/study-card.tsx (87%) rename src/features/study/{ => schedule}/ui/today-study-card.tsx (89%) diff --git a/src/features/study/ui/data-selector.tsx b/src/features/study/schedule/ui/data-selector.tsx similarity index 100% rename from src/features/study/ui/data-selector.tsx rename to src/features/study/schedule/ui/data-selector.tsx diff --git a/src/features/study/ui/study-card.tsx b/src/features/study/schedule/ui/study-card.tsx similarity index 87% rename from src/features/study/ui/study-card.tsx rename to src/features/study/schedule/ui/study-card.tsx index 453ccd4c..50f27367 100644 --- a/src/features/study/ui/study-card.tsx +++ b/src/features/study/schedule/ui/study-card.tsx @@ -2,17 +2,19 @@ import { getMonth, getDay, startOfWeek, getDate } from 'date-fns'; import { useMemo, useState } from 'react'; +import ReservationList from '@/features/study/participation/ui/reservation-list'; +import { + useStudyStatusQuery, + useWeeklyParticipation, +} from '@/features/study/schedule/model/use-schedule-query'; +import DateSelector from '@/features/study/schedule/ui/data-selector'; +import TodayStudyCard from '@/features/study/schedule/ui/today-study-card'; import { formatKoreaYMD, getKoreaDate, getKoreaDisplayMonday, } from '@/shared/lib/time'; -import DateSelector from './data-selector'; -import TodayStudyCard from './today-study-card'; -import StudyListSection from '../../../widgets/home/study-list-table'; -import { useWeeklyParticipation } from '../model/use-study-query'; -import { useStudyStatusQuery } from '../participation/model/use-participation-query'; -import ReservationList from '../participation/ui/reservation-list'; +import StudyListSection from '../../../../widgets/home/study-list-table'; // 스터디 주차 구하는 함수 function getWeekly(date: Date): { month: number; week: number } { diff --git a/src/features/study/ui/today-study-card.tsx b/src/features/study/schedule/ui/today-study-card.tsx similarity index 89% rename from src/features/study/ui/today-study-card.tsx rename to src/features/study/schedule/ui/today-study-card.tsx index a1816bb4..9bb89839 100644 --- a/src/features/study/ui/today-study-card.tsx +++ b/src/features/study/schedule/ui/today-study-card.tsx @@ -2,14 +2,12 @@ import { useEffect, useState } from 'react'; import UserProfileModal from '@/entities/user/ui/user-profile-modal'; -import { getStatusBadge } from '@/features/study/ui/status-badge-map'; +import { useDailyStudyDetailQuery } from '@/features/study/interview/model/use-interview-query'; +import { getStatusBadge } from '@/features/study/interview/ui/status-badge-map'; +import StudyDoneModal from '@/features/study/interview/ui/study-done-modal'; +import StudyReadyModal from '@/features/study/interview/ui/study-ready-modal'; import { getCookie } from '@/shared/tanstack-query/cookie'; -// TODO: FSD 의 import 바운더리를 넘어서 import 해야하는데, -// 해당 UI를 shared 등으로 빼던지 수정 필요 import UserAvatar from '@/shared/ui/avatar'; -import StudyDoneModal from './study-done-modal'; -import StudyReadyModal from './study-ready-modal'; -import { useDailyStudyDetailQuery } from '../model/use-study-query'; export default function TodayStudyCard({ studyDate }: { studyDate: string }) { const [memberId, setMemberId] = useState(null); From 1bae87e687105235a0c6fdc3b6a4011b0cc4b622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 17:45:00 +0900 Subject: [PATCH 10/15] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=84=B0=EB=94=94?= =?UTF-8?q?=20=EC=B0=B8=EC=97=AC=20=EA=B4=80=EB=A0=A8=20UI=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/participation/ui/reservation-list.tsx | 4 ++-- .../ui/start-study-modal.tsx | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) rename src/features/study/{ => participation}/ui/start-study-modal.tsx (97%) diff --git a/src/features/study/participation/ui/reservation-list.tsx b/src/features/study/participation/ui/reservation-list.tsx index 912afdef..92c6fb13 100644 --- a/src/features/study/participation/ui/reservation-list.tsx +++ b/src/features/study/participation/ui/reservation-list.tsx @@ -7,9 +7,9 @@ import { useUserProfileQuery, } from '@/entities/user/model/use-user-profile-query'; import ProfileDefault from '@/entities/user/ui/icon/profile-default.svg'; +import ReservationCard from '@/features/study/participation/ui/reservation-user-card'; +import StartStudyModal from '@/features/study/participation/ui/start-study-modal'; import { getCookie } from '@/shared/tanstack-query/cookie'; -import ReservationCard from './reservation-user-card'; -import StartStudyModal from '../../ui/start-study-modal'; import { useInfiniteReservation } from '../model/use-participation-query'; interface ReservationListProps { diff --git a/src/features/study/ui/start-study-modal.tsx b/src/features/study/participation/ui/start-study-modal.tsx similarity index 97% rename from src/features/study/ui/start-study-modal.tsx rename to src/features/study/participation/ui/start-study-modal.tsx index 1330e84d..af53ff0d 100644 --- a/src/features/study/ui/start-study-modal.tsx +++ b/src/features/study/participation/ui/start-study-modal.tsx @@ -12,6 +12,14 @@ import { useTechStacksQuery, } from '@/features/my-page/model/use-update-user-profile-mutation'; +import { studySteps } from '@/features/study/participation/const/participation-const'; +import { + StartStudyFormSchema, + type StartStudyFormValues, + buildStartStudyDefaultValues, + toJoinStudyRequest, +} from '@/features/study/participation/model/start-study-form.schema'; +import { useJoinStudyMutation } from '@/features/study/participation/model/use-participation-query'; import Button from '@/shared/ui/button'; import { SingleDropdown, MultiDropdown } from '@/shared/ui/dropdown'; import FormField from '@/shared/ui/form/form-field'; @@ -19,15 +27,6 @@ import { BaseInput, TextAreaInput } from '@/shared/ui/input'; import { Modal } from '@/shared/ui/modal'; import { ToggleGroup } from '@/shared/ui/toggle'; -import { studySteps } from '../consts/study-const'; - -import { useJoinStudyMutation } from '../model/use-study-query'; -import { - StartStudyFormSchema, - type StartStudyFormValues, - buildStartStudyDefaultValues, - toJoinStudyRequest, -} from '../participation/model/start-study-form.schema'; interface StartStudyModalProps { memberId: number; From bf21c3930abc495743e7e5d36e9d0ff00e3397c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Thu, 4 Sep 2025 17:46:10 +0900 Subject: [PATCH 11/15] =?UTF-8?q?fix:=20=EB=B3=80=EA=B2=BD=EB=90=9C=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 8 ++++---- app/page.tsx | 2 +- src/entities/user/ui/user-profile-modal.tsx | 2 +- src/features/study/interview/lib/use-reminder-review.tsx | 2 +- src/widgets/home/calendar.tsx | 2 +- src/widgets/home/sidebar.tsx | 2 +- src/widgets/home/study-list-table.tsx | 6 +++--- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index 21cffeda..04dea53b 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -4,14 +4,14 @@ import Image from 'next/image'; import { useEffect, useRef, useState } from 'react'; import KeywordReview from '@/entities/user/ui/keyword-review'; import MoreKeywordReviewModal from '@/entities/user/ui/more-keyword-review-modal'; -import { MyReviewItem } from '@/features/study/api/types'; +import { MyReviewItem } from '@/features/study/interview/api/interview-types'; +import { formatKoreaRelativeTime } from '@/shared/lib/time'; +import UserAvatar from '@/shared/ui/avatar'; import { useMyNegativeKeywordsQuery, useMyReviewsInfinityQuery, useUserPositiveKeywordsQuery, -} from '@/features/study/model/use-review-query'; -import { formatKoreaRelativeTime } from '@/shared/lib/time'; -import UserAvatar from '@/shared/ui/avatar'; +} from '@/features/study/interview/model/use-review-query'; export default function MyStudyReview() { const { data: positiveKeywordsData } = useUserPositiveKeywordsQuery({ diff --git a/app/page.tsx b/app/page.tsx index 7c83339d..d3208bfd 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,6 +1,6 @@ import { Metadata } from 'next'; import { redirect } from 'next/navigation'; -import StudyCard from '@/features/study/ui/study-card'; +import StudyCard from '@/features/study/schedule/ui/study-card'; import { getLoginUserId } from '@/shared/lib/get-login-user'; import Banner from '@/widgets/home/banner'; import Sidebar from '@/widgets/home/sidebar'; diff --git a/src/entities/user/ui/user-profile-modal.tsx b/src/entities/user/ui/user-profile-modal.tsx index 041aaa84..d1d8ab70 100644 --- a/src/entities/user/ui/user-profile-modal.tsx +++ b/src/entities/user/ui/user-profile-modal.tsx @@ -9,11 +9,11 @@ import CakeIcon from '@/features/my-page/ui/icon/cake.svg'; import GithubIcon from '@/features/my-page/ui/icon/github-logo.svg'; import GlobeIcon from '@/features/my-page/ui/icon/globe-simple.svg'; import PhoneIcon from '@/features/my-page/ui/icon/phone.svg'; -import { useUserPositiveKeywordsQuery } from '@/features/study/model/use-review-query'; import { getSincerityPresetByLevelName } from '@/shared/config/sincerity-temp-presets'; import UserAvatar from '@/shared/ui/avatar'; import Badge from '@/shared/ui/badge'; import { Modal } from '@/shared/ui/modal'; +import { useUserPositiveKeywordsQuery } from '@/features/study/interview/model/use-review-query'; interface UserProfileModalProps { memberId: number; diff --git a/src/features/study/interview/lib/use-reminder-review.tsx b/src/features/study/interview/lib/use-reminder-review.tsx index 076af1e4..4ab66b54 100644 --- a/src/features/study/interview/lib/use-reminder-review.tsx +++ b/src/features/study/interview/lib/use-reminder-review.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { getKoreaDate } from '@/shared/lib/time'; -import { useShouldReviewPartnerQuery } from '../../model/use-review-query'; +import { useShouldReviewPartnerQuery } from '../model/use-review-query'; export const useReviewReminder = () => { const { data: shouldReview, isFetching } = useShouldReviewPartnerQuery(); diff --git a/src/widgets/home/calendar.tsx b/src/widgets/home/calendar.tsx index 402fd09d..9a0ba2a8 100644 --- a/src/widgets/home/calendar.tsx +++ b/src/widgets/home/calendar.tsx @@ -7,7 +7,7 @@ import { type CalendarDay as DayPickerDay, type Modifiers, } from 'react-day-picker'; -import { useMonthlyStudyCalendarQuery } from '@/features/study/model/use-study-query'; +import { useMonthlyStudyCalendarQuery } from '@/features/study/schedule/model/use-schedule-query'; import { cn } from '@/shared/shadcn/lib/utils'; import { Calendar as ShadcnCalendar } from '@/shared/shadcn/ui/calendar'; diff --git a/src/widgets/home/sidebar.tsx b/src/widgets/home/sidebar.tsx index d6713d28..d9d9c113 100644 --- a/src/widgets/home/sidebar.tsx +++ b/src/widgets/home/sidebar.tsx @@ -2,7 +2,7 @@ import Image from 'next/image'; import Link from 'next/link'; import { getUserProfile } from '@/entities/user/api/get-user-profile'; import MyProfileCard from '@/entities/user/ui/my-profile-card'; -import StartStudyModal from '@/features/study/ui/start-study-modal'; +import StartStudyModal from '@/features/study/participation/ui/start-study-modal'; import { getLoginUserId } from '@/shared/lib/get-login-user'; import Calendar from '@/widgets/home/calendar'; import TodoList from '@/widgets/home/todo-list'; diff --git a/src/widgets/home/study-list-table.tsx b/src/widgets/home/study-list-table.tsx index 12ec3d98..2e502322 100644 --- a/src/widgets/home/study-list-table.tsx +++ b/src/widgets/home/study-list-table.tsx @@ -1,9 +1,9 @@ -import { useDailyStudiesQuery } from '@/features/study/model/use-study-query'; -import { getStatusBadge } from '@/features/study/ui/status-badge-map'; +import { getStatusBadge } from '@/features/study/interview/ui/status-badge-map'; +import { DailyStudy } from '@/features/study/schedule/api/schedule-types'; +import { useDailyStudiesQuery } from '@/features/study/schedule/model/use-schedule-query'; import UserAvatar from '@/shared/ui/avatar'; import TableList from '@/shared/ui/table'; import LinkIcon from 'public/icons/Link.svg'; -import { DailyStudy } from '../../features/study/api/types'; const headers = [ '조', From 9a2f2d50fe4201dea032c4ccb543b368916d8d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EB=AF=BC=EC=A3=BC?= Date: Fri, 5 Sep 2025 21:30:23 +0900 Subject: [PATCH 12/15] =?UTF-8?q?fix:=20=ED=8C=8C=EC=9D=BC=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/interview/api/get-review.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/features/study/interview/api/get-review.ts b/src/features/study/interview/api/get-review.ts index ff521549..0bdeb90b 100644 --- a/src/features/study/interview/api/get-review.ts +++ b/src/features/study/interview/api/get-review.ts @@ -1,4 +1,3 @@ -import { axiosInstance } from '@/shared/tanstack-query/axios'; import type { AddStudyReviewRequest, UserPositiveKeywordsResponse, @@ -9,7 +8,8 @@ import type { MyReviewsResponse, MyReviewsRequest, ShouldReviewPartnerResponse, -} from '../../api/types'; +} from '@/features/study/interview/api/interview-types'; +import { axiosInstance } from '@/shared/tanstack-query/axios'; export const getPartnerStudyReview = async (): Promise => { From f920fa959bb92b7e394884fb71f1eca43a7a1869 Mon Sep 17 00:00:00 2001 From: Mimiminz Date: Sun, 14 Sep 2025 16:34:37 +0900 Subject: [PATCH 13/15] =?UTF-8?q?refactor:=20review=20feature=20->=20entit?= =?UTF-8?q?ies=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 4 +- .../review}/api/get-review.ts | 2 +- src/entities/review/api/review-types.ts | 91 ++++++++++++++++++ .../review}/lib/use-reminder-review.tsx | 0 .../review}/model/use-review-query.ts | 2 +- .../review}/ui/study-review-modal.tsx | 4 +- src/entities/user/ui/my-profile-card.tsx | 4 +- src/entities/user/ui/user-profile-modal.tsx | 2 +- .../study/interview/api/interview-types.ts | 92 ------------------- 9 files changed, 100 insertions(+), 101 deletions(-) rename src/{features/study/interview => entities/review}/api/get-review.ts (97%) create mode 100644 src/entities/review/api/review-types.ts rename src/{features/study/interview => entities/review}/lib/use-reminder-review.tsx (100%) rename src/{features/study/interview => entities/review}/model/use-review-query.ts (97%) rename src/{features/study/interview => entities/review}/ui/study-review-modal.tsx (99%) diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index 04dea53b..23c2bf88 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -2,16 +2,16 @@ import Image from 'next/image'; import { useEffect, useRef, useState } from 'react'; +import { MyReviewItem } from '@/entities/review/api/review-types'; import KeywordReview from '@/entities/user/ui/keyword-review'; import MoreKeywordReviewModal from '@/entities/user/ui/more-keyword-review-modal'; -import { MyReviewItem } from '@/features/study/interview/api/interview-types'; import { formatKoreaRelativeTime } from '@/shared/lib/time'; import UserAvatar from '@/shared/ui/avatar'; import { useMyNegativeKeywordsQuery, useMyReviewsInfinityQuery, useUserPositiveKeywordsQuery, -} from '@/features/study/interview/model/use-review-query'; +} from '@/entities/review/model/use-review-query'; export default function MyStudyReview() { const { data: positiveKeywordsData } = useUserPositiveKeywordsQuery({ diff --git a/src/features/study/interview/api/get-review.ts b/src/entities/review/api/get-review.ts similarity index 97% rename from src/features/study/interview/api/get-review.ts rename to src/entities/review/api/get-review.ts index 0bdeb90b..a53c290e 100644 --- a/src/features/study/interview/api/get-review.ts +++ b/src/entities/review/api/get-review.ts @@ -8,7 +8,7 @@ import type { MyReviewsResponse, MyReviewsRequest, ShouldReviewPartnerResponse, -} from '@/features/study/interview/api/interview-types'; +} from '@/entities/review/api/review-types'; import { axiosInstance } from '@/shared/tanstack-query/axios'; export const getPartnerStudyReview = diff --git a/src/entities/review/api/review-types.ts b/src/entities/review/api/review-types.ts new file mode 100644 index 00000000..20d478cc --- /dev/null +++ b/src/entities/review/api/review-types.ts @@ -0,0 +1,91 @@ +// 리뷰 관련 타입 +export interface EvalKeyword { + id: number; + keyword: string; + satisfactionId: number; + satisfactionLabel: string; +} + +interface Partner { + memberId: number; + memberName: string; + profileImageUrl: string; +} + +export interface StudyEvaluationResponse { + studySpaceId: number; + targetMembers: Partner[]; + studySubject: string; + startDate: string; // "yyyy-MM-dd" 형식 + endDate: string; // "yyyy-MM-dd" 형식 + satisfiedEvalKeywords: EvalKeyword[]; + notBadEvalKeywords: EvalKeyword[]; + unsatisfiedEvalKeywords: EvalKeyword[]; +} + +export interface AddStudyReviewRequest { + studySpaceId: number; + targetMemberId: number; + satisfactionId: 10 | 20 | 30; + keywordIds: number[]; + content?: string; +} + +interface Keyword { + id: number; + content: string; + count: number; +} + +export interface UserPositiveKeywordsRequest { + memberId?: number; + pageSize?: number; +} + +export interface UserPositiveKeywordsResponse { + totalCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null + reviewerCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null + keywords: Keyword[]; +} + +export interface MyNegativeKeywordsRequest { + pageSize?: number; +} + +export interface MyNegativeKeywordsResponse { + totalCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null + reviewerCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null + keywords: Keyword[]; +} + +export interface MyReviewWriter { + memberId: number; + memberName: string; + profileImageUrl: string; +} + +export interface MyReviewItem { + id: number; + writer: MyReviewWriter; + reviewedAt: string; // ISO 날짜 문자열 + content: string; + studySpaceId: number; + startDate: string; // YYYY-MM-DD + endDate: string; // YYYY-MM-DD + studySubjects: string[]; +} + +export interface MyReviewsRequest { + cursor: number | null; +} + +export interface MyReviewsResponse { + totalCount: number; + reviews: { + items: MyReviewItem[]; + nextCursor: number; + hasNext: boolean; + }; +} + +export type ShouldReviewPartnerResponse = boolean; diff --git a/src/features/study/interview/lib/use-reminder-review.tsx b/src/entities/review/lib/use-reminder-review.tsx similarity index 100% rename from src/features/study/interview/lib/use-reminder-review.tsx rename to src/entities/review/lib/use-reminder-review.tsx diff --git a/src/features/study/interview/model/use-review-query.ts b/src/entities/review/model/use-review-query.ts similarity index 97% rename from src/features/study/interview/model/use-review-query.ts rename to src/entities/review/model/use-review-query.ts index 984e518d..26d994a0 100644 --- a/src/features/study/interview/model/use-review-query.ts +++ b/src/entities/review/model/use-review-query.ts @@ -7,7 +7,7 @@ import { import { MyNegativeKeywordsRequest, UserPositiveKeywordsRequest, -} from '@/features/study/interview/api/interview-types'; +} from '@/entities/review/api/review-types'; import { getKoreaDate } from '@/shared/lib/time'; import { addStudyReview, diff --git a/src/features/study/interview/ui/study-review-modal.tsx b/src/entities/review/ui/study-review-modal.tsx similarity index 99% rename from src/features/study/interview/ui/study-review-modal.tsx rename to src/entities/review/ui/study-review-modal.tsx index aa7f9666..e5f7a0f8 100644 --- a/src/features/study/interview/ui/study-review-modal.tsx +++ b/src/entities/review/ui/study-review-modal.tsx @@ -6,7 +6,7 @@ import { useState } from 'react'; import { EvalKeyword, StudyEvaluationResponse, -} from '@/features/study/interview/api/interview-types'; +} from '@/entities/review/api/review-types'; import UserAvatar from '@/shared/ui/avatar'; import Button from '@/shared/ui/button'; import Checkbox from '@/shared/ui/checkbox'; @@ -16,7 +16,7 @@ import { Modal } from '@/shared/ui/modal'; import { useAddStudyReviewMutation, usePartnerStudyReviewQuery, -} from '../model/use-review-query'; +} from '@/entities/review/model/use-review-query'; interface FormState { studySpaceId: number; diff --git a/src/entities/user/ui/my-profile-card.tsx b/src/entities/user/ui/my-profile-card.tsx index b1b90435..606920eb 100644 --- a/src/entities/user/ui/my-profile-card.tsx +++ b/src/entities/user/ui/my-profile-card.tsx @@ -2,9 +2,9 @@ import Link from 'next/link'; import React, { useState } from 'react'; +import { useReviewReminder } from '@/entities/review/lib/use-reminder-review'; +import StudyReviewModal from '@/entities/review/ui/study-review-modal'; import { usePatchAutoMatchingMutation } from '@/entities/user/model/use-user-profile-query'; -import { useReviewReminder } from '@/features/study/interview/lib/use-reminder-review'; -import StudyReviewModal from '@/features/study/interview/ui/study-review-modal'; import { getSincerityPresetByLevelName } from '@/shared/config/sincerity-temp-presets'; import { cn } from '@/shared/shadcn/lib/utils'; import UserAvatar from '@/shared/ui/avatar'; diff --git a/src/entities/user/ui/user-profile-modal.tsx b/src/entities/user/ui/user-profile-modal.tsx index d1d8ab70..9385fbe2 100644 --- a/src/entities/user/ui/user-profile-modal.tsx +++ b/src/entities/user/ui/user-profile-modal.tsx @@ -13,7 +13,7 @@ import { getSincerityPresetByLevelName } from '@/shared/config/sincerity-temp-pr import UserAvatar from '@/shared/ui/avatar'; import Badge from '@/shared/ui/badge'; import { Modal } from '@/shared/ui/modal'; -import { useUserPositiveKeywordsQuery } from '@/features/study/interview/model/use-review-query'; +import { useUserPositiveKeywordsQuery } from '@/entities/review/model/use-review-query'; interface UserProfileModalProps { memberId: number; diff --git a/src/features/study/interview/api/interview-types.ts b/src/features/study/interview/api/interview-types.ts index f508a71c..1e4a678e 100644 --- a/src/features/study/interview/api/interview-types.ts +++ b/src/features/study/interview/api/interview-types.ts @@ -32,95 +32,3 @@ export interface CompleteStudyRequest { feedback: string; progressStatus: StudyProgressStatus; } - -// 리뷰 관련 타입 -export interface EvalKeyword { - id: number; - keyword: string; - satisfactionId: number; - satisfactionLabel: string; -} - -interface Partner { - memberId: number; - memberName: string; - profileImageUrl: string; -} - -export interface StudyEvaluationResponse { - studySpaceId: number; - targetMembers: Partner[]; - studySubject: string; - startDate: string; // "yyyy-MM-dd" 형식 - endDate: string; // "yyyy-MM-dd" 형식 - satisfiedEvalKeywords: EvalKeyword[]; - notBadEvalKeywords: EvalKeyword[]; - unsatisfiedEvalKeywords: EvalKeyword[]; -} - -export interface AddStudyReviewRequest { - studySpaceId: number; - targetMemberId: number; - satisfactionId: 10 | 20 | 30; - keywordIds: number[]; - content?: string; -} - -interface Keyword { - id: number; - content: string; - count: number; -} - -export interface UserPositiveKeywordsRequest { - memberId?: number; - pageSize?: number; -} - -export interface UserPositiveKeywordsResponse { - totalCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null - reviewerCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null - keywords: Keyword[]; -} - -export interface MyNegativeKeywordsRequest { - pageSize?: number; -} - -export interface MyNegativeKeywordsResponse { - totalCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null - reviewerCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null - keywords: Keyword[]; -} - -export interface MyReviewWriter { - memberId: number; - memberName: string; - profileImageUrl: string; -} - -export interface MyReviewItem { - id: number; - writer: MyReviewWriter; - reviewedAt: string; // ISO 날짜 문자열 - content: string; - studySpaceId: number; - startDate: string; // YYYY-MM-DD - endDate: string; // YYYY-MM-DD - studySubjects: string[]; -} - -export interface MyReviewsRequest { - cursor: number | null; -} - -export interface MyReviewsResponse { - totalCount: number; - reviews: { - items: MyReviewItem[]; - nextCursor: number; - hasNext: boolean; - }; -} - -export type ShouldReviewPartnerResponse = boolean; From 144b52201618608185d1aeac3cb33f0124ee6487 Mon Sep 17 00:00:00 2001 From: Mimiminz Date: Sun, 14 Sep 2025 16:35:10 +0900 Subject: [PATCH 14/15] =?UTF-8?q?fix:=20=EB=B3=80=EA=B2=BD=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20import=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/participation/model/start-study-form.schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/study/participation/model/start-study-form.schema.ts b/src/features/study/participation/model/start-study-form.schema.ts index 5f30714c..a08e6e93 100644 --- a/src/features/study/participation/model/start-study-form.schema.ts +++ b/src/features/study/participation/model/start-study-form.schema.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; +import { JoinStudyRequest } from '@/features/study/participation/api/participation-types'; import { UrlSchema } from '@/shared/util/zod-schema'; -import { JoinStudyRequest } from '../../api/types'; export const StartStudyFormSchema = z.object({ selfIntroduction: z From 17c3134ef6bf7d467d2f2e857dd52e66380f368f Mon Sep 17 00:00:00 2001 From: Mimiminz Date: Sun, 14 Sep 2025 16:40:48 +0900 Subject: [PATCH 15/15] =?UTF-8?q?fix:=20warning=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/user/model/use-user-profile-query.ts | 2 +- src/features/my-page/model/profile-form.schema.ts | 1 - src/features/my-page/ui/profile-edit-modal.tsx | 2 +- src/features/study/interview/ui/study-done-modal.tsx | 10 +++++----- src/features/study/interview/ui/study-ready-modal.tsx | 11 +++++------ 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/entities/user/model/use-user-profile-query.ts b/src/entities/user/model/use-user-profile-query.ts index d31a5f19..38d00741 100644 --- a/src/entities/user/model/use-user-profile-query.ts +++ b/src/entities/user/model/use-user-profile-query.ts @@ -42,7 +42,7 @@ export const usePatchAutoMatchingMutation = () => { }); } - return { prev }; + return { prev }; }, onError: (_err, { memberId }, ctx) => { diff --git a/src/features/my-page/model/profile-form.schema.ts b/src/features/my-page/model/profile-form.schema.ts index 51eee97d..5323a581 100644 --- a/src/features/my-page/model/profile-form.schema.ts +++ b/src/features/my-page/model/profile-form.schema.ts @@ -1,4 +1,3 @@ -import { FieldNamesMarkedBoolean } from 'react-hook-form'; import { z } from 'zod'; import type { MemberProfile } from '@/entities/user/api/types'; import { UrlSchema } from '@/shared/util/zod-schema'; diff --git a/src/features/my-page/ui/profile-edit-modal.tsx b/src/features/my-page/ui/profile-edit-modal.tsx index d6126b95..7d14986c 100644 --- a/src/features/my-page/ui/profile-edit-modal.tsx +++ b/src/features/my-page/ui/profile-edit-modal.tsx @@ -94,7 +94,7 @@ function ProfileEditForm({ const { handleSubmit, - formState: { isValid, isSubmitting, dirtyFields }, + formState: { isValid, isSubmitting }, } = methods; const onValidSubmit = async (values: ProfileFormValues) => { diff --git a/src/features/study/interview/ui/study-done-modal.tsx b/src/features/study/interview/ui/study-done-modal.tsx index f73bc34d..48583647 100644 --- a/src/features/study/interview/ui/study-done-modal.tsx +++ b/src/features/study/interview/ui/study-done-modal.tsx @@ -11,17 +11,17 @@ import type { StudyProgressStatus, } from '@/features/study/interview/api/interview-types'; import { STUDY_PROGRESS_OPTIONS } from '@/features/study/interview/const/interview-const'; +import { + StudyDoneFormSchema, + type StudyDoneFormValues, + buildStudyDoneDefaults, +} from '@/features/study/interview/model/interview.schema'; import { useUpdateDailyStudyMutation } from '@/features/study/interview/model/use-interview-query'; import Button from '@/shared/ui/button'; import { SingleDropdown } from '@/shared/ui/dropdown'; import FormField from '@/shared/ui/form/form-field'; import { TextAreaInput } from '@/shared/ui/input'; import { Modal } from '@/shared/ui/modal'; -import { - StudyDoneFormSchema, - type StudyDoneFormValues, - buildStudyDoneDefaults, -} from '@/features/study/interview/model/interview.schema'; interface StudyDoneModalProps { data: DailyStudyDetail; diff --git a/src/features/study/interview/ui/study-ready-modal.tsx b/src/features/study/interview/ui/study-ready-modal.tsx index 02d98ea6..46019b5f 100644 --- a/src/features/study/interview/ui/study-ready-modal.tsx +++ b/src/features/study/interview/ui/study-ready-modal.tsx @@ -9,17 +9,16 @@ import type { DailyStudyDetail, PrepareStudyRequest, } from '@/features/study/interview/api/interview-types'; -import { useUpdateDailyStudyMutation } from '@/features/study/interview/model/use-interview-query'; -import Button from '@/shared/ui/button'; -import FormField from '@/shared/ui/form/form-field'; -import { BaseInput } from '@/shared/ui/input'; -import { Modal } from '@/shared/ui/modal'; - import { StudyReadyFormSchema, type StudyReadyFormValues, buildStudyReadyDefaults, } from '@/features/study/interview/model/interview.schema'; +import { useUpdateDailyStudyMutation } from '@/features/study/interview/model/use-interview-query'; +import Button from '@/shared/ui/button'; +import FormField from '@/shared/ui/form/form-field'; +import { BaseInput } from '@/shared/ui/input'; +import { Modal } from '@/shared/ui/modal'; interface StudyReadyModalProps { data: DailyStudyDetail;