From 0e4bb7d9251732261d06156a886fbb0c1b9c5d90 Mon Sep 17 00:00:00 2001 From: "bruno-sync-app[bot]" Date: Sun, 25 Jan 2026 13:06:31 +0000 Subject: [PATCH] chore: sync API from Bruno --- src/apis/Admin/api.ts | 30 +- src/apis/Admin/getGpaList.ts | 6 +- src/apis/Admin/getLanguageTestList.ts | 6 +- src/apis/Admin/index.ts | 11 +- src/apis/Admin/legacy/getGpaList.CHANGES.md | 25 ++ src/apis/Admin/legacy/getGpaList.ts | 13 + .../legacy/getLanguageTestList.CHANGES.md | 25 ++ src/apis/Admin/legacy/getLanguageTestList.ts | 13 + src/apis/Admin/legacy/putVerifyGpa.CHANGES.md | 25 ++ src/apis/Admin/legacy/putVerifyGpa.ts | 11 + .../legacy/putVerifyLanguageTest.CHANGES.md | 25 ++ .../Admin/legacy/putVerifyLanguageTest.ts | 15 + src/apis/Admin/putVerifyGpa.ts | 6 +- src/apis/Admin/putVerifyLanguageTest.ts | 12 +- src/apis/Auth/api.ts | 121 +++----- src/apis/Auth/deleteAccount.ts | 38 +-- src/apis/Auth/index.ts | 35 +-- src/apis/Auth/legacy/deleteAccount.ts | 35 +++ src/apis/Auth/legacy/postAppleAuth.ts | 43 +++ src/apis/Auth/legacy/postEmailLogin.ts | 37 +++ .../legacy/postEmailVerification.CHANGES.md | 32 ++ src/apis/Auth/legacy/postEmailVerification.ts | 20 ++ src/apis/Auth/legacy/postKakaoAuth.ts | 44 +++ .../Auth/legacy/postRefreshToken.CHANGES.md | 25 ++ src/apis/Auth/legacy/postRefreshToken.ts | 11 + src/apis/Auth/legacy/postSignOut.CHANGES.md | 25 ++ src/apis/Auth/legacy/postSignOut.ts | 26 ++ src/apis/Auth/legacy/postSignUp.ts | 20 ++ src/apis/Auth/postAppleAuth.ts | 40 +-- src/apis/Auth/postEmailLogin.ts | 36 +-- src/apis/Auth/postEmailVerification.ts | 21 +- src/apis/Auth/postKakaoAuth.ts | 41 +-- src/apis/Auth/postRefreshToken.ts | 10 +- src/apis/Auth/postSignOut.ts | 29 +- src/apis/Auth/postSignUp.ts | 17 +- src/apis/MyPage/api.ts | 84 +++--- src/apis/MyPage/getProfile.ts | 40 +-- src/apis/MyPage/index.ts | 19 +- src/apis/MyPage/legacy/getProfile.CHANGES.md | 32 ++ src/apis/MyPage/legacy/getProfile.ts | 37 +++ .../legacy/patchInterestedRegionCountry.ts | 11 + .../MyPage/legacy/patchPassword.CHANGES.md | 25 ++ src/apis/MyPage/legacy/patchPassword.ts | 31 ++ .../MyPage/legacy/patchProfile.CHANGES.md | 32 ++ src/apis/MyPage/legacy/patchProfile.ts | 28 ++ .../MyPage/patchInterestedRegionCountry.ts | 8 +- src/apis/MyPage/patchPassword.ts | 34 +-- src/apis/MyPage/patchProfile.ts | 31 +- src/apis/Scores/api.ts | 115 ++++--- src/apis/Scores/getGpaList.ts | 20 +- src/apis/Scores/getLanguageTestList.ts | 20 +- src/apis/Scores/index.ts | 18 +- src/apis/Scores/legacy/getGpaList.CHANGES.md | 25 ++ src/apis/Scores/legacy/getGpaList.ts | 17 ++ .../legacy/getLanguageTestList.CHANGES.md | 25 ++ src/apis/Scores/legacy/getLanguageTestList.ts | 17 ++ .../Scores/legacy/postCreateGpa.CHANGES.md | 25 ++ src/apis/Scores/legacy/postCreateGpa.ts | 27 ++ .../legacy/postCreateLanguageTest.CHANGES.md | 25 ++ .../Scores/legacy/postCreateLanguageTest.ts | 27 ++ src/apis/Scores/postCreateGpa.ts | 30 +- src/apis/Scores/postCreateLanguageTest.ts | 30 +- src/apis/applications/api.ts | 171 ++++++++--- src/apis/applications/getApplicants.ts | 34 +-- src/apis/applications/getCompetitors.ts | 6 +- src/apis/applications/index.ts | 10 +- .../legacy/getApplicants.CHANGES.md | 25 ++ src/apis/applications/legacy/getApplicants.ts | 27 ++ .../legacy/getCompetitors.CHANGES.md | 25 ++ .../applications/legacy/getCompetitors.ts | 13 + .../legacy/postSubmitApplication.CHANGES.md | 25 ++ .../legacy/postSubmitApplication.ts | 37 +++ .../applications/postSubmitApplication.ts | 40 +-- src/apis/chat/api.ts | 80 ++--- src/apis/chat/getChatMessages.ts | 46 +-- src/apis/chat/getChatPartner.ts | 19 +- src/apis/chat/getChatRooms.ts | 20 +- src/apis/chat/index.ts | 12 +- .../chat/legacy/getChatMessages.CHANGES.md | 32 ++ src/apis/chat/legacy/getChatMessages.ts | 40 +++ .../chat/legacy/getChatPartner.CHANGES.md | 32 ++ src/apis/chat/legacy/getChatPartner.ts | 17 ++ src/apis/chat/legacy/getChatRooms.CHANGES.md | 32 ++ src/apis/chat/legacy/getChatRooms.ts | 17 ++ .../chat/legacy/putReadChatRoom.CHANGES.md | 39 +++ src/apis/chat/legacy/putReadChatRoom.ts | 23 ++ src/apis/chat/putReadChatRoom.ts | 26 +- src/apis/community/api.ts | 251 +++++++++------- src/apis/community/deleteComment.ts | 33 +-- src/apis/community/deleteLikePost.ts | 29 +- src/apis/community/deletePost.ts | 36 +-- src/apis/community/getBoard.ts | 8 +- src/apis/community/getBoardList.ts | 6 +- src/apis/community/getPostDetail.ts | 19 +- src/apis/community/index.ts | 41 +-- .../community/legacy/deleteComment.CHANGES.md | 32 ++ src/apis/community/legacy/deleteComment.ts | 32 ++ .../legacy/deleteLikePost.CHANGES.md | 32 ++ src/apis/community/legacy/deleteLikePost.ts | 26 ++ .../community/legacy/deletePost.CHANGES.md | 32 ++ src/apis/community/legacy/deletePost.ts | 35 +++ src/apis/community/legacy/getBoard.CHANGES.md | 25 ++ src/apis/community/legacy/getBoard.ts | 14 + .../community/legacy/getBoardList.CHANGES.md | 25 ++ src/apis/community/legacy/getBoardList.ts | 13 + .../community/legacy/getPostDetail.CHANGES.md | 32 ++ src/apis/community/legacy/getPostDetail.ts | 17 ++ .../legacy/patchUpdateComment.CHANGES.md | 32 ++ .../community/legacy/patchUpdateComment.ts | 11 + .../legacy/patchUpdatePost.CHANGES.md | 39 +++ src/apis/community/legacy/patchUpdatePost.ts | 33 +++ .../legacy/postCreateComment.CHANGES.md | 39 +++ .../community/legacy/postCreateComment.ts | 27 ++ .../legacy/postCreatePost.CHANGES.md | 39 +++ src/apis/community/legacy/postCreatePost.ts | 60 ++++ .../community/legacy/postLikePost.CHANGES.md | 39 +++ src/apis/community/legacy/postLikePost.ts | 26 ++ src/apis/community/patchUpdateComment.ts | 10 +- src/apis/community/patchUpdatePost.ts | 36 +-- src/apis/community/postCreateComment.ts | 30 +- src/apis/community/postCreatePost.ts | 63 +--- src/apis/community/postLikePost.ts | 29 +- src/apis/image-upload/api.ts | 84 +++--- src/apis/image-upload/index.ts | 15 +- .../legacy/postSlackNotification.ts | 11 + .../legacy/postUploadGpaReport.CHANGES.md | 25 ++ .../legacy/postUploadGpaReport.ts | 11 + .../postUploadLanguageTestReport.CHANGES.md | 25 ++ .../legacy/postUploadLanguageTestReport.ts | 11 + .../legacy/postUploadProfileImage.CHANGES.md | 25 ++ .../legacy/postUploadProfileImage.ts | 11 + ...tUploadProfileImageBeforeSignup.CHANGES.md | 32 ++ .../postUploadProfileImageBeforeSignup.ts | 20 ++ .../image-upload/postSlackNotification.ts | 6 +- src/apis/image-upload/postUploadGpaReport.ts | 10 +- .../postUploadLanguageTestReport.ts | 10 +- .../image-upload/postUploadProfileImage.ts | 10 +- .../postUploadProfileImageBeforeSignup.ts | 21 +- src/apis/kakao-api/api.ts | 21 +- src/apis/kakao-api/getKakaoInfo.ts | 8 +- src/apis/kakao-api/getKakaoUserIds.ts | 8 +- src/apis/kakao-api/index.ts | 9 +- .../kakao-api/legacy/getKakaoInfo.CHANGES.md | 25 ++ src/apis/kakao-api/legacy/getKakaoInfo.ts | 13 + .../legacy/getKakaoUserIds.CHANGES.md | 25 ++ src/apis/kakao-api/legacy/getKakaoUserIds.ts | 13 + src/apis/kakao-api/legacy/postKakaoUnlink.ts | 11 + src/apis/kakao-api/postKakaoUnlink.ts | 6 +- src/apis/mentor/api.ts | 280 ++++++++++-------- src/apis/mentor/getAppliedMentorings.ts | 49 +-- src/apis/mentor/getMatchedMentors.ts | 12 +- src/apis/mentor/getMentorDetail.ts | 21 +- src/apis/mentor/getMentorList.ts | 47 +-- src/apis/mentor/getMyMentorPage.ts | 19 +- src/apis/mentor/getReceivedMentorings.ts | 29 +- .../mentor/getUnconfirmedMentoringCount.ts | 22 +- src/apis/mentor/index.ts | 41 +-- .../legacy/getAppliedMentorings.CHANGES.md | 32 ++ .../mentor/legacy/getAppliedMentorings.ts | 41 +++ .../legacy/getMatchedMentors.CHANGES.md | 25 ++ src/apis/mentor/legacy/getMatchedMentors.ts | 18 ++ .../mentor/legacy/getMentorDetail.CHANGES.md | 32 ++ src/apis/mentor/legacy/getMentorDetail.ts | 17 ++ .../mentor/legacy/getMentorList.CHANGES.md | 25 ++ src/apis/mentor/legacy/getMentorList.ts | 39 +++ .../mentor/legacy/getMyMentorPage.CHANGES.md | 32 ++ src/apis/mentor/legacy/getMyMentorPage.ts | 16 + .../legacy/getReceivedMentorings.CHANGES.md | 32 ++ .../mentor/legacy/getReceivedMentorings.ts | 24 ++ .../getUnconfirmedMentoringCount.CHANGES.md | 32 ++ .../legacy/getUnconfirmedMentoringCount.ts | 19 ++ .../legacy/patchConfirmMentoring.CHANGES.md | 39 +++ .../mentor/legacy/patchConfirmMentoring.ts | 11 + .../legacy/patchMentoringStatus.CHANGES.md | 39 +++ .../mentor/legacy/patchMentoringStatus.ts | 63 ++++ .../legacy/postApplyMentoring.CHANGES.md | 39 +++ src/apis/mentor/legacy/postApplyMentoring.ts | 24 ++ .../legacy/putUpdateMyMentorPage.CHANGES.md | 39 +++ .../mentor/legacy/putUpdateMyMentorPage.ts | 22 ++ src/apis/mentor/patchConfirmMentoring.ts | 25 +- src/apis/mentor/patchMentoringStatus.ts | 66 +---- src/apis/mentor/postApplyMentoring.ts | 25 +- src/apis/mentor/putUpdateMyMentorPage.ts | 25 +- src/apis/news/api.ts | 139 ++++----- src/apis/news/deleteLikeNews.ts | 54 +--- src/apis/news/deleteNews.ts | 53 +--- src/apis/news/getNewsList.ts | 28 +- src/apis/news/index.ts | 23 +- .../news/legacy/deleteLikeNews.CHANGES.md | 25 ++ src/apis/news/legacy/deleteLikeNews.ts | 51 ++++ src/apis/news/legacy/deleteNews.CHANGES.md | 25 ++ src/apis/news/legacy/deleteNews.ts | 50 ++++ src/apis/news/legacy/getNewsList.CHANGES.md | 32 ++ src/apis/news/legacy/getNewsList.ts | 25 ++ .../news/legacy/postCreateNews.CHANGES.md | 25 ++ src/apis/news/legacy/postCreateNews.ts | 57 ++++ src/apis/news/legacy/postLikeNews.CHANGES.md | 25 ++ src/apis/news/legacy/postLikeNews.ts | 52 ++++ src/apis/news/legacy/putUpdateNews.CHANGES.md | 25 ++ src/apis/news/legacy/putUpdateNews.ts | 59 ++++ src/apis/news/postCreateNews.ts | 60 +--- src/apis/news/postLikeNews.ts | 55 +--- src/apis/news/putUpdateNews.ts | 62 +--- src/apis/queryKeys.ts | 196 ++++++------ src/apis/reports/api.ts | 26 +- src/apis/reports/index.ts | 6 +- src/apis/reports/legacy/postReport.CHANGES.md | 25 ++ src/apis/reports/legacy/postReport.ts | 26 ++ src/apis/reports/postReport.ts | 27 +- src/apis/universities/api.ts | 98 +++--- src/apis/universities/deleteWish.ts | 21 +- src/apis/universities/getByRegionCountry.ts | 6 +- src/apis/universities/getIsWish.ts | 6 +- .../getRecommendedUniversities.ts | 25 +- src/apis/universities/getSearchText.ts | 54 +--- src/apis/universities/getUniversityDetail.ts | 22 +- src/apis/universities/getWishList.ts | 22 +- src/apis/universities/index.ts | 21 +- .../universities/legacy/deleteWish.CHANGES.md | 25 ++ src/apis/universities/legacy/deleteWish.ts | 20 ++ .../legacy/getByRegionCountry.CHANGES.md | 25 ++ .../universities/legacy/getByRegionCountry.ts | 13 + .../universities/legacy/getIsWish.CHANGES.md | 25 ++ src/apis/universities/legacy/getIsWish.ts | 14 + .../getRecommendedUniversities.CHANGES.md | 25 ++ .../legacy/getRecommendedUniversities.ts | 24 ++ .../legacy/getSearchText.CHANGES.md | 25 ++ src/apis/universities/legacy/getSearchText.ts | 53 ++++ .../legacy/getUniversityDetail.CHANGES.md | 25 ++ .../legacy/getUniversityDetail.ts | 20 ++ .../legacy/getWishList.CHANGES.md | 25 ++ src/apis/universities/legacy/getWishList.ts | 21 ++ .../legacy/postAddWish.CHANGES.md | 32 ++ src/apis/universities/legacy/postAddWish.ts | 23 ++ src/apis/universities/postAddWish.ts | 24 +- src/apis/users/api.ts | 32 +- src/apis/users/deleteUnblockUser.ts | 6 +- src/apis/users/getBlockedUsers.ts | 6 +- src/apis/users/getNicknameExists.ts | 6 +- src/apis/users/index.ts | 11 +- src/apis/users/legacy/deleteUnblockUser.ts | 11 + .../users/legacy/getBlockedUsers.CHANGES.md | 25 ++ src/apis/users/legacy/getBlockedUsers.ts | 13 + .../users/legacy/getNicknameExists.CHANGES.md | 25 ++ src/apis/users/legacy/getNicknameExists.ts | 13 + .../users/legacy/postBlockUser.CHANGES.md | 25 ++ src/apis/users/legacy/postBlockUser.ts | 11 + src/apis/users/postBlockUser.ts | 6 +- 248 files changed, 5300 insertions(+), 2463 deletions(-) create mode 100644 src/apis/Admin/legacy/getGpaList.CHANGES.md create mode 100644 src/apis/Admin/legacy/getGpaList.ts create mode 100644 src/apis/Admin/legacy/getLanguageTestList.CHANGES.md create mode 100644 src/apis/Admin/legacy/getLanguageTestList.ts create mode 100644 src/apis/Admin/legacy/putVerifyGpa.CHANGES.md create mode 100644 src/apis/Admin/legacy/putVerifyGpa.ts create mode 100644 src/apis/Admin/legacy/putVerifyLanguageTest.CHANGES.md create mode 100644 src/apis/Admin/legacy/putVerifyLanguageTest.ts create mode 100644 src/apis/Auth/legacy/deleteAccount.ts create mode 100644 src/apis/Auth/legacy/postAppleAuth.ts create mode 100644 src/apis/Auth/legacy/postEmailLogin.ts create mode 100644 src/apis/Auth/legacy/postEmailVerification.CHANGES.md create mode 100644 src/apis/Auth/legacy/postEmailVerification.ts create mode 100644 src/apis/Auth/legacy/postKakaoAuth.ts create mode 100644 src/apis/Auth/legacy/postRefreshToken.CHANGES.md create mode 100644 src/apis/Auth/legacy/postRefreshToken.ts create mode 100644 src/apis/Auth/legacy/postSignOut.CHANGES.md create mode 100644 src/apis/Auth/legacy/postSignOut.ts create mode 100644 src/apis/Auth/legacy/postSignUp.ts create mode 100644 src/apis/MyPage/legacy/getProfile.CHANGES.md create mode 100644 src/apis/MyPage/legacy/getProfile.ts create mode 100644 src/apis/MyPage/legacy/patchInterestedRegionCountry.ts create mode 100644 src/apis/MyPage/legacy/patchPassword.CHANGES.md create mode 100644 src/apis/MyPage/legacy/patchPassword.ts create mode 100644 src/apis/MyPage/legacy/patchProfile.CHANGES.md create mode 100644 src/apis/MyPage/legacy/patchProfile.ts create mode 100644 src/apis/Scores/legacy/getGpaList.CHANGES.md create mode 100644 src/apis/Scores/legacy/getGpaList.ts create mode 100644 src/apis/Scores/legacy/getLanguageTestList.CHANGES.md create mode 100644 src/apis/Scores/legacy/getLanguageTestList.ts create mode 100644 src/apis/Scores/legacy/postCreateGpa.CHANGES.md create mode 100644 src/apis/Scores/legacy/postCreateGpa.ts create mode 100644 src/apis/Scores/legacy/postCreateLanguageTest.CHANGES.md create mode 100644 src/apis/Scores/legacy/postCreateLanguageTest.ts create mode 100644 src/apis/applications/legacy/getApplicants.CHANGES.md create mode 100644 src/apis/applications/legacy/getApplicants.ts create mode 100644 src/apis/applications/legacy/getCompetitors.CHANGES.md create mode 100644 src/apis/applications/legacy/getCompetitors.ts create mode 100644 src/apis/applications/legacy/postSubmitApplication.CHANGES.md create mode 100644 src/apis/applications/legacy/postSubmitApplication.ts create mode 100644 src/apis/chat/legacy/getChatMessages.CHANGES.md create mode 100644 src/apis/chat/legacy/getChatMessages.ts create mode 100644 src/apis/chat/legacy/getChatPartner.CHANGES.md create mode 100644 src/apis/chat/legacy/getChatPartner.ts create mode 100644 src/apis/chat/legacy/getChatRooms.CHANGES.md create mode 100644 src/apis/chat/legacy/getChatRooms.ts create mode 100644 src/apis/chat/legacy/putReadChatRoom.CHANGES.md create mode 100644 src/apis/chat/legacy/putReadChatRoom.ts create mode 100644 src/apis/community/legacy/deleteComment.CHANGES.md create mode 100644 src/apis/community/legacy/deleteComment.ts create mode 100644 src/apis/community/legacy/deleteLikePost.CHANGES.md create mode 100644 src/apis/community/legacy/deleteLikePost.ts create mode 100644 src/apis/community/legacy/deletePost.CHANGES.md create mode 100644 src/apis/community/legacy/deletePost.ts create mode 100644 src/apis/community/legacy/getBoard.CHANGES.md create mode 100644 src/apis/community/legacy/getBoard.ts create mode 100644 src/apis/community/legacy/getBoardList.CHANGES.md create mode 100644 src/apis/community/legacy/getBoardList.ts create mode 100644 src/apis/community/legacy/getPostDetail.CHANGES.md create mode 100644 src/apis/community/legacy/getPostDetail.ts create mode 100644 src/apis/community/legacy/patchUpdateComment.CHANGES.md create mode 100644 src/apis/community/legacy/patchUpdateComment.ts create mode 100644 src/apis/community/legacy/patchUpdatePost.CHANGES.md create mode 100644 src/apis/community/legacy/patchUpdatePost.ts create mode 100644 src/apis/community/legacy/postCreateComment.CHANGES.md create mode 100644 src/apis/community/legacy/postCreateComment.ts create mode 100644 src/apis/community/legacy/postCreatePost.CHANGES.md create mode 100644 src/apis/community/legacy/postCreatePost.ts create mode 100644 src/apis/community/legacy/postLikePost.CHANGES.md create mode 100644 src/apis/community/legacy/postLikePost.ts create mode 100644 src/apis/image-upload/legacy/postSlackNotification.ts create mode 100644 src/apis/image-upload/legacy/postUploadGpaReport.CHANGES.md create mode 100644 src/apis/image-upload/legacy/postUploadGpaReport.ts create mode 100644 src/apis/image-upload/legacy/postUploadLanguageTestReport.CHANGES.md create mode 100644 src/apis/image-upload/legacy/postUploadLanguageTestReport.ts create mode 100644 src/apis/image-upload/legacy/postUploadProfileImage.CHANGES.md create mode 100644 src/apis/image-upload/legacy/postUploadProfileImage.ts create mode 100644 src/apis/image-upload/legacy/postUploadProfileImageBeforeSignup.CHANGES.md create mode 100644 src/apis/image-upload/legacy/postUploadProfileImageBeforeSignup.ts create mode 100644 src/apis/kakao-api/legacy/getKakaoInfo.CHANGES.md create mode 100644 src/apis/kakao-api/legacy/getKakaoInfo.ts create mode 100644 src/apis/kakao-api/legacy/getKakaoUserIds.CHANGES.md create mode 100644 src/apis/kakao-api/legacy/getKakaoUserIds.ts create mode 100644 src/apis/kakao-api/legacy/postKakaoUnlink.ts create mode 100644 src/apis/mentor/legacy/getAppliedMentorings.CHANGES.md create mode 100644 src/apis/mentor/legacy/getAppliedMentorings.ts create mode 100644 src/apis/mentor/legacy/getMatchedMentors.CHANGES.md create mode 100644 src/apis/mentor/legacy/getMatchedMentors.ts create mode 100644 src/apis/mentor/legacy/getMentorDetail.CHANGES.md create mode 100644 src/apis/mentor/legacy/getMentorDetail.ts create mode 100644 src/apis/mentor/legacy/getMentorList.CHANGES.md create mode 100644 src/apis/mentor/legacy/getMentorList.ts create mode 100644 src/apis/mentor/legacy/getMyMentorPage.CHANGES.md create mode 100644 src/apis/mentor/legacy/getMyMentorPage.ts create mode 100644 src/apis/mentor/legacy/getReceivedMentorings.CHANGES.md create mode 100644 src/apis/mentor/legacy/getReceivedMentorings.ts create mode 100644 src/apis/mentor/legacy/getUnconfirmedMentoringCount.CHANGES.md create mode 100644 src/apis/mentor/legacy/getUnconfirmedMentoringCount.ts create mode 100644 src/apis/mentor/legacy/patchConfirmMentoring.CHANGES.md create mode 100644 src/apis/mentor/legacy/patchConfirmMentoring.ts create mode 100644 src/apis/mentor/legacy/patchMentoringStatus.CHANGES.md create mode 100644 src/apis/mentor/legacy/patchMentoringStatus.ts create mode 100644 src/apis/mentor/legacy/postApplyMentoring.CHANGES.md create mode 100644 src/apis/mentor/legacy/postApplyMentoring.ts create mode 100644 src/apis/mentor/legacy/putUpdateMyMentorPage.CHANGES.md create mode 100644 src/apis/mentor/legacy/putUpdateMyMentorPage.ts create mode 100644 src/apis/news/legacy/deleteLikeNews.CHANGES.md create mode 100644 src/apis/news/legacy/deleteLikeNews.ts create mode 100644 src/apis/news/legacy/deleteNews.CHANGES.md create mode 100644 src/apis/news/legacy/deleteNews.ts create mode 100644 src/apis/news/legacy/getNewsList.CHANGES.md create mode 100644 src/apis/news/legacy/getNewsList.ts create mode 100644 src/apis/news/legacy/postCreateNews.CHANGES.md create mode 100644 src/apis/news/legacy/postCreateNews.ts create mode 100644 src/apis/news/legacy/postLikeNews.CHANGES.md create mode 100644 src/apis/news/legacy/postLikeNews.ts create mode 100644 src/apis/news/legacy/putUpdateNews.CHANGES.md create mode 100644 src/apis/news/legacy/putUpdateNews.ts create mode 100644 src/apis/reports/legacy/postReport.CHANGES.md create mode 100644 src/apis/reports/legacy/postReport.ts create mode 100644 src/apis/universities/legacy/deleteWish.CHANGES.md create mode 100644 src/apis/universities/legacy/deleteWish.ts create mode 100644 src/apis/universities/legacy/getByRegionCountry.CHANGES.md create mode 100644 src/apis/universities/legacy/getByRegionCountry.ts create mode 100644 src/apis/universities/legacy/getIsWish.CHANGES.md create mode 100644 src/apis/universities/legacy/getIsWish.ts create mode 100644 src/apis/universities/legacy/getRecommendedUniversities.CHANGES.md create mode 100644 src/apis/universities/legacy/getRecommendedUniversities.ts create mode 100644 src/apis/universities/legacy/getSearchText.CHANGES.md create mode 100644 src/apis/universities/legacy/getSearchText.ts create mode 100644 src/apis/universities/legacy/getUniversityDetail.CHANGES.md create mode 100644 src/apis/universities/legacy/getUniversityDetail.ts create mode 100644 src/apis/universities/legacy/getWishList.CHANGES.md create mode 100644 src/apis/universities/legacy/getWishList.ts create mode 100644 src/apis/universities/legacy/postAddWish.CHANGES.md create mode 100644 src/apis/universities/legacy/postAddWish.ts create mode 100644 src/apis/users/legacy/deleteUnblockUser.ts create mode 100644 src/apis/users/legacy/getBlockedUsers.CHANGES.md create mode 100644 src/apis/users/legacy/getBlockedUsers.ts create mode 100644 src/apis/users/legacy/getNicknameExists.CHANGES.md create mode 100644 src/apis/users/legacy/getNicknameExists.ts create mode 100644 src/apis/users/legacy/postBlockUser.CHANGES.md create mode 100644 src/apis/users/legacy/postBlockUser.ts diff --git a/src/apis/Admin/api.ts b/src/apis/Admin/api.ts index 74b67368..48752a1d 100644 --- a/src/apis/Admin/api.ts +++ b/src/apis/Admin/api.ts @@ -143,34 +143,32 @@ export interface GpaListResponse { } export const adminApi = { - putVerifyLanguageTest: async (params: { - languageTestScoreId: string | number; - data?: VerifyLanguageTestRequest; - }): Promise => { + putVerifyLanguageTest: async (params: { languageTestScoreId: string | number, data?: VerifyLanguageTestRequest }): Promise => { const res = await axiosInstance.put( - `/admin/scores/language-tests/${params.languageTestScoreId}`, - params?.data, + `/admin/scores/language-tests/${params.languageTestScoreId}`, params?.data ); return res.data; }, getLanguageTestList: async (params: { params?: Record }): Promise => { - const res = await axiosInstance.get(`/admin/scores/language-tests?page=1&size=10`, { - params: params?.params, - }); + const res = await axiosInstance.get( + `/admin/scores/language-tests?page=1&size=10`, { params: params?.params } + ); return res.data; }, - putVerifyGpa: async (params: { - gpaScoreId: string | number; - data?: VerifyGpaRequest; - }): Promise => { - const res = await axiosInstance.put(`/admin/scores/gpas/${params.gpaScoreId}`, params?.data); + putVerifyGpa: async (params: { gpaScoreId: string | number, data?: VerifyGpaRequest }): Promise => { + const res = await axiosInstance.put( + `/admin/scores/gpas/${params.gpaScoreId}`, params?.data + ); return res.data; }, getGpaList: async (params: { params?: Record }): Promise => { - const res = await axiosInstance.get(`/admin/scores/gpas`, { params: params?.params }); + const res = await axiosInstance.get( + `/admin/scores/gpas`, { params: params?.params } + ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/Admin/getGpaList.ts b/src/apis/Admin/getGpaList.ts index bb3448f8..d3ae89e6 100644 --- a/src/apis/Admin/getGpaList.ts +++ b/src/apis/Admin/getGpaList.ts @@ -1,7 +1,7 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { adminApi, GpaListResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { adminApi, type GpaListResponse } from "./api"; const useGetGpaList = (params?: Record) => { return useQuery({ @@ -10,4 +10,4 @@ const useGetGpaList = (params?: Record) => { }); }; -export default useGetGpaList; +export default useGetGpaList; \ No newline at end of file diff --git a/src/apis/Admin/getLanguageTestList.ts b/src/apis/Admin/getLanguageTestList.ts index 3192c406..6d9325d8 100644 --- a/src/apis/Admin/getLanguageTestList.ts +++ b/src/apis/Admin/getLanguageTestList.ts @@ -1,7 +1,7 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { adminApi, LanguageTestListResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { adminApi, type LanguageTestListResponse } from "./api"; const useGetLanguageTestList = (params?: Record) => { return useQuery({ @@ -10,4 +10,4 @@ const useGetLanguageTestList = (params?: Record) => { }); }; -export default useGetLanguageTestList; +export default useGetLanguageTestList; \ No newline at end of file diff --git a/src/apis/Admin/index.ts b/src/apis/Admin/index.ts index f7d22c2a..54a68092 100644 --- a/src/apis/Admin/index.ts +++ b/src/apis/Admin/index.ts @@ -1,5 +1,6 @@ -export { adminApi } from "./api"; -export { default as getGpaList } from "./getGpaList"; -export { default as getLanguageTestList } from "./getLanguageTestList"; -export { default as putVerifyGpa } from "./putVerifyGpa"; -export { default as putVerifyLanguageTest } from "./putVerifyLanguageTest"; +export { adminApi } from './api'; +export { default as getGpaList } from './getGpaList'; +export { default as getLanguageTestList } from './getLanguageTestList'; +export { default as index } from './index'; +export { default as putVerifyGpa } from './putVerifyGpa'; +export { default as putVerifyLanguageTest } from './putVerifyLanguageTest'; diff --git a/src/apis/Admin/legacy/getGpaList.CHANGES.md b/src/apis/Admin/legacy/getGpaList.CHANGES.md new file mode 100644 index 00000000..b5d7ae9d --- /dev/null +++ b/src/apis/Admin/legacy/getGpaList.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getGpaList.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/admin/scores/gpas +- Method: GET +- Function: getGpaList + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.Admin.gpaList, params` +- 현재: `QueryKeys.admin.getGpaList, URL, params` + +## 권장 조치 + +1. `legacy/getGpaList.ts` 파일의 비즈니스 로직 확인 +2. 새 `getGpaList.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getGpaList.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Admin/legacy/getGpaList.ts b/src/apis/Admin/legacy/getGpaList.ts new file mode 100644 index 00000000..bb3448f8 --- /dev/null +++ b/src/apis/Admin/legacy/getGpaList.ts @@ -0,0 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { adminApi, type GpaListResponse } from "./api"; + +const useGetGpaList = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.Admin.gpaList, params], + queryFn: () => adminApi.getGpaList(params ? { params } : {}), + }); +}; + +export default useGetGpaList; diff --git a/src/apis/Admin/legacy/getLanguageTestList.CHANGES.md b/src/apis/Admin/legacy/getLanguageTestList.CHANGES.md new file mode 100644 index 00000000..45c7b929 --- /dev/null +++ b/src/apis/Admin/legacy/getLanguageTestList.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getLanguageTestList.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/admin/scores/language-tests?page=1&size=10 +- Method: GET +- Function: getLanguageTestList + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.Admin.languageTestList, params` +- 현재: `QueryKeys.admin.getLanguageTestList, URL, params` + +## 권장 조치 + +1. `legacy/getLanguageTestList.ts` 파일의 비즈니스 로직 확인 +2. 새 `getLanguageTestList.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getLanguageTestList.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Admin/legacy/getLanguageTestList.ts b/src/apis/Admin/legacy/getLanguageTestList.ts new file mode 100644 index 00000000..3192c406 --- /dev/null +++ b/src/apis/Admin/legacy/getLanguageTestList.ts @@ -0,0 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { adminApi, type LanguageTestListResponse } from "./api"; + +const useGetLanguageTestList = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.Admin.languageTestList, params], + queryFn: () => adminApi.getLanguageTestList(params ? { params } : {}), + }); +}; + +export default useGetLanguageTestList; diff --git a/src/apis/Admin/legacy/putVerifyGpa.CHANGES.md b/src/apis/Admin/legacy/putVerifyGpa.CHANGES.md new file mode 100644 index 00000000..5f1a5250 --- /dev/null +++ b/src/apis/Admin/legacy/putVerifyGpa.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: putVerifyGpa.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/admin/scores/gpas/{{gpa-score-id}} +- Method: PUT +- Function: putVerifyGpa + +## 변경 내용 + +### request-type + +**Request 타입 변경** + +- 이전: `{ gpaScoreId: string | number; data: VerifyGpaRequest }` +- 현재: `VerifyGpaRequest` + +## 권장 조치 + +1. `legacy/putVerifyGpa.ts` 파일의 비즈니스 로직 확인 +2. 새 `putVerifyGpa.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/putVerifyGpa.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Admin/legacy/putVerifyGpa.ts b/src/apis/Admin/legacy/putVerifyGpa.ts new file mode 100644 index 00000000..9d834b2f --- /dev/null +++ b/src/apis/Admin/legacy/putVerifyGpa.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { adminApi, type VerifyGpaRequest, type VerifyGpaResponse } from "./api"; + +const usePutVerifyGpa = () => { + return useMutation({ + mutationFn: (variables) => adminApi.putVerifyGpa(variables), + }); +}; + +export default usePutVerifyGpa; diff --git a/src/apis/Admin/legacy/putVerifyLanguageTest.CHANGES.md b/src/apis/Admin/legacy/putVerifyLanguageTest.CHANGES.md new file mode 100644 index 00000000..0063c680 --- /dev/null +++ b/src/apis/Admin/legacy/putVerifyLanguageTest.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: putVerifyLanguageTest.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/admin/scores/language-tests/{{language-test-score-id}} +- Method: PUT +- Function: putVerifyLanguageTest + +## 변경 내용 + +### request-type + +**Request 타입 변경** + +- 이전: `{ languageTestScoreId: string | number; data: VerifyLanguageTestRequest }` +- 현재: `VerifyLanguageTestRequest` + +## 권장 조치 + +1. `legacy/putVerifyLanguageTest.ts` 파일의 비즈니스 로직 확인 +2. 새 `putVerifyLanguageTest.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/putVerifyLanguageTest.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Admin/legacy/putVerifyLanguageTest.ts b/src/apis/Admin/legacy/putVerifyLanguageTest.ts new file mode 100644 index 00000000..0e04811c --- /dev/null +++ b/src/apis/Admin/legacy/putVerifyLanguageTest.ts @@ -0,0 +1,15 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { adminApi, type VerifyLanguageTestRequest, type VerifyLanguageTestResponse } from "./api"; + +const usePutVerifyLanguageTest = () => { + return useMutation< + VerifyLanguageTestResponse, + AxiosError, + { languageTestScoreId: string | number; data: VerifyLanguageTestRequest } + >({ + mutationFn: (variables) => adminApi.putVerifyLanguageTest(variables), + }); +}; + +export default usePutVerifyLanguageTest; diff --git a/src/apis/Admin/putVerifyGpa.ts b/src/apis/Admin/putVerifyGpa.ts index 9d834b2f..8073d81a 100644 --- a/src/apis/Admin/putVerifyGpa.ts +++ b/src/apis/Admin/putVerifyGpa.ts @@ -1,6 +1,6 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { adminApi, type VerifyGpaRequest, type VerifyGpaResponse } from "./api"; +import { adminApi, VerifyGpaResponse, VerifyGpaRequest } from "./api"; const usePutVerifyGpa = () => { return useMutation({ @@ -8,4 +8,4 @@ const usePutVerifyGpa = () => { }); }; -export default usePutVerifyGpa; +export default usePutVerifyGpa; \ No newline at end of file diff --git a/src/apis/Admin/putVerifyLanguageTest.ts b/src/apis/Admin/putVerifyLanguageTest.ts index 0e04811c..fa37c5e4 100644 --- a/src/apis/Admin/putVerifyLanguageTest.ts +++ b/src/apis/Admin/putVerifyLanguageTest.ts @@ -1,15 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { adminApi, type VerifyLanguageTestRequest, type VerifyLanguageTestResponse } from "./api"; +import { adminApi, VerifyLanguageTestResponse, VerifyLanguageTestRequest } from "./api"; const usePutVerifyLanguageTest = () => { - return useMutation< - VerifyLanguageTestResponse, - AxiosError, - { languageTestScoreId: string | number; data: VerifyLanguageTestRequest } - >({ + return useMutation({ mutationFn: (variables) => adminApi.putVerifyLanguageTest(variables), }); }; -export default usePutVerifyLanguageTest; +export default usePutVerifyLanguageTest; \ No newline at end of file diff --git a/src/apis/Auth/api.ts b/src/apis/Auth/api.ts index 3f04e115..7d6ac3be 100644 --- a/src/apis/Auth/api.ts +++ b/src/apis/Auth/api.ts @@ -1,29 +1,18 @@ -import { axiosInstance, publicAxiosInstance } from "@/utils/axiosInstance"; +import { axiosInstance } from "@/utils/axiosInstance"; export type SignOutResponse = Record; export type SignOutRequest = Record; -// Apple Auth Types -export interface RegisteredAppleAuthResponse { - isRegistered: true; - accessToken: string; - refreshToken: string; -} - -export interface UnregisteredAppleAuthResponse { - isRegistered: false; +export interface AppleAuthResponse { + isRegistered: boolean; nickname: null; email: string; profileImageUrl: null; signUpToken: string; } -export type AppleAuthResponse = RegisteredAppleAuthResponse | UnregisteredAppleAuthResponse; - -export interface AppleAuthRequest { - code: string; -} +export type AppleAuthRequest = Record; export interface RefreshTokenResponse { accessToken: string; @@ -36,110 +25,88 @@ export interface EmailLoginResponse { refreshToken: string; } -export interface EmailLoginRequest { - email: string; - password: string; -} +export type EmailLoginRequest = Record; export interface EmailVerificationResponse { signUpToken: string; } -export interface EmailVerificationRequest { - email: string; - verificationCode: string; -} - -// Kakao Auth Types -export interface RegisteredKakaoAuthResponse { - isRegistered: true; - accessToken: string; - refreshToken: string; -} +export type EmailVerificationRequest = Record; -export interface UnregisteredKakaoAuthResponse { - isRegistered: false; +export interface KakaoAuthResponse { + isRegistered: boolean; nickname: string; email: string; profileImageUrl: string; signUpToken: string; } -export type KakaoAuthResponse = RegisteredKakaoAuthResponse | UnregisteredKakaoAuthResponse; +export type KakaoAuthRequest = Record; -export interface KakaoAuthRequest { - code: string; -} - -export type AccountResponse = undefined; +export type AccountResponse = void; export interface SignUpResponse { accessToken: string; refreshToken: string; } -export interface SignUpRequest { - signUpToken: string; - nickname: string; - profileImageUrl: string; - preparationStatus: string; - interestedRegions: string[]; - interestedCountries: string[]; -} - -export interface EmailSignUpRequest { - email: string; - password: string; -} - -export interface EmailSignUpResponse { - signUpToken: string; -} +export type SignUpRequest = Record; export const authApi = { - postSignOut: async (): Promise => { - const res = await axiosInstance.post(`/auth/sign-out`); + postSignOut: async (params: { data?: SignOutRequest }): Promise => { + const res = await axiosInstance.post( + `/auth/sign-out`, params?.data + ); return res.data; }, - postAppleAuth: async (data: AppleAuthRequest): Promise => { - const res = await publicAxiosInstance.post(`/auth/apple`, data); + postAppleAuth: async (params: { data?: AppleAuthRequest }): Promise => { + const res = await axiosInstance.post( + `/auth/apple`, params?.data + ); return res.data; }, - postRefreshToken: async (): Promise => { - const res = await publicAxiosInstance.post(`/auth/reissue`); + postRefreshToken: async (params: { data?: RefreshTokenRequest }): Promise => { + const res = await axiosInstance.post( + `/auth/reissue`, params?.data + ); return res.data; }, - postEmailLogin: async (data: EmailLoginRequest): Promise => { - const res = await publicAxiosInstance.post(`/auth/email/sign-in`, data); + postEmailLogin: async (params: { data?: EmailLoginRequest }): Promise => { + const res = await axiosInstance.post( + `/auth/email/sign-in`, params?.data + ); return res.data; }, - postEmailSignUp: async (data: EmailSignUpRequest): Promise => { - const res = await publicAxiosInstance.post(`/auth/email/sign-up`, data); + postEmailVerification: async (params: { data?: EmailVerificationRequest }): Promise => { + const res = await axiosInstance.post( + `/auth/email/sign-up`, params?.data + ); return res.data; }, - postKakaoAuth: async (data: KakaoAuthRequest): Promise => { - const res = await publicAxiosInstance.post(`/auth/kakao`, data); + postKakaoAuth: async (params: { data?: KakaoAuthRequest }): Promise => { + const res = await axiosInstance.post( + `/auth/kakao`, params?.data + ); return res.data; }, deleteAccount: async (): Promise => { - const res = await axiosInstance.delete(`/auth/quit`); + const res = await axiosInstance.delete( + `/auth/quit` + ); return res.data; }, - postSignUp: async (data: SignUpRequest): Promise => { - // 임시 성별, 생년월일 추가. API 변경 시 삭제 - const payload = { - ...data, - birth: "2000-01-01", - gender: "PREFER_NOT_TO_SAY", - }; - const res = await publicAxiosInstance.post(`/auth/sign-up`, payload); + postSignUp: async (params: { data?: SignUpRequest }): Promise => { + const res = await axiosInstance.post( + `/auth/sign-up`, params?.data + ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/Auth/deleteAccount.ts b/src/apis/Auth/deleteAccount.ts index 546282a4..00038562 100644 --- a/src/apis/Auth/deleteAccount.ts +++ b/src/apis/Auth/deleteAccount.ts @@ -1,35 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { authApi, AccountResponse, AccountRequest } from "./api"; -import type { AxiosError } from "axios"; -import { useRouter } from "next/navigation"; - -import useAuthStore from "@/lib/zustand/useAuthStore"; -import { toast } from "@/lib/zustand/useToastStore"; -import { type AccountResponse, authApi } from "./api"; - -/** - * @description 회원탈퇴를 위한 useMutation 커스텀 훅 - */ -const useDeleteUserAccount = () => { - const router = useRouter(); - const { clearAccessToken } = useAuthStore(); - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: () => authApi.deleteAccount(), - onMutate: () => { - // 낙관적 업데이트: 요청이 시작되면 바로 홈으로 이동 - router.replace("/"); - }, - onSuccess: () => { - // Zustand persist가 자동으로 localStorage에서 제거 - clearAccessToken(); - queryClient.clear(); - }, - onError: () => { - toast.error("회원탈퇴에 실패했습니다. 잠시 후 다시 시도해주세요."); - }, +const useDeleteAccount = () => { + return useMutation({ + mutationFn: (data) => authApi.deleteAccount({ data }), }); }; -export default useDeleteUserAccount; +export default useDeleteAccount; \ No newline at end of file diff --git a/src/apis/Auth/index.ts b/src/apis/Auth/index.ts index cd56347d..a6b7c98a 100644 --- a/src/apis/Auth/index.ts +++ b/src/apis/Auth/index.ts @@ -1,25 +1,10 @@ -export type { - AppleAuthRequest, - AppleAuthResponse, - EmailLoginRequest, - EmailLoginResponse, - EmailSignUpRequest, - EmailSignUpResponse, - KakaoAuthRequest, - KakaoAuthResponse, - SignUpRequest, - SignUpResponse, -} from "./api"; -export { authApi } from "./api"; - -// Client-side hooks -export { default as useDeleteUserAccount } from "./deleteAccount"; -export { default as usePostAppleAuth } from "./postAppleAuth"; -export { default as usePostEmailAuth } from "./postEmailLogin"; -export { default as usePostEmailSignUp } from "./postEmailVerification"; -export { default as usePostKakaoAuth } from "./postKakaoAuth"; -export { default as usePostLogout } from "./postSignOut"; -export { default as usePostSignUp } from "./postSignUp"; - -// Server-side functions -export { postReissueToken } from "./server"; +export { authApi } from './api'; +export { default as deleteAccount } from './deleteAccount'; +export { default as index } from './index'; +export { default as postAppleAuth } from './postAppleAuth'; +export { default as postEmailLogin } from './postEmailLogin'; +export { default as postEmailVerification } from './postEmailVerification'; +export { default as postKakaoAuth } from './postKakaoAuth'; +export { default as postRefreshToken } from './postRefreshToken'; +export { default as postSignOut } from './postSignOut'; +export { default as postSignUp } from './postSignUp'; diff --git a/src/apis/Auth/legacy/deleteAccount.ts b/src/apis/Auth/legacy/deleteAccount.ts new file mode 100644 index 00000000..546282a4 --- /dev/null +++ b/src/apis/Auth/legacy/deleteAccount.ts @@ -0,0 +1,35 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; + +import type { AxiosError } from "axios"; +import { useRouter } from "next/navigation"; + +import useAuthStore from "@/lib/zustand/useAuthStore"; +import { toast } from "@/lib/zustand/useToastStore"; +import { type AccountResponse, authApi } from "./api"; + +/** + * @description 회원탈퇴를 위한 useMutation 커스텀 훅 + */ +const useDeleteUserAccount = () => { + const router = useRouter(); + const { clearAccessToken } = useAuthStore(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: () => authApi.deleteAccount(), + onMutate: () => { + // 낙관적 업데이트: 요청이 시작되면 바로 홈으로 이동 + router.replace("/"); + }, + onSuccess: () => { + // Zustand persist가 자동으로 localStorage에서 제거 + clearAccessToken(); + queryClient.clear(); + }, + onError: () => { + toast.error("회원탈퇴에 실패했습니다. 잠시 후 다시 시도해주세요."); + }, + }); +}; + +export default useDeleteUserAccount; diff --git a/src/apis/Auth/legacy/postAppleAuth.ts b/src/apis/Auth/legacy/postAppleAuth.ts new file mode 100644 index 00000000..c62cfdd9 --- /dev/null +++ b/src/apis/Auth/legacy/postAppleAuth.ts @@ -0,0 +1,43 @@ +import { useMutation } from "@tanstack/react-query"; + +import type { AxiosError } from "axios"; +import { useRouter, useSearchParams } from "next/navigation"; +import useAuthStore from "@/lib/zustand/useAuthStore"; +import { toast } from "@/lib/zustand/useToastStore"; +import { validateSafeRedirect } from "@/utils/authUtils"; +import { type AppleAuthRequest, type AppleAuthResponse, authApi } from "./api"; + +/** + * @description 애플 로그인을 위한 useMutation 커스텀 훅 + */ +const usePostAppleAuth = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + + return useMutation({ + mutationFn: (data) => authApi.postAppleAuth(data), + onSuccess: (data) => { + if (data.isRegistered) { + // 기존 회원일 시 - Zustand persist가 자동으로 localStorage에 저장 + // refreshToken은 서버에서 HTTP-only 쿠키로 자동 설정됨 + useAuthStore.getState().setAccessToken(data.accessToken); + + // 안전한 리다이렉트 처리 - 오픈 리다이렉트 방지 + const redirectParam = searchParams.get("redirect"); + const safeRedirect = validateSafeRedirect(redirectParam); + + toast.success("로그인에 성공했습니다."); + router.replace(safeRedirect); + } else { + // 새로운 회원일 시 - 회원가입 페이지로 이동 + router.push(`/sign-up?token=${data.signUpToken}`); + } + }, + onError: () => { + toast.error("애플 로그인 중 오류가 발생했습니다. 다시 시도해주세요."); + router.push("/login"); + }, + }); +}; + +export default usePostAppleAuth; diff --git a/src/apis/Auth/legacy/postEmailLogin.ts b/src/apis/Auth/legacy/postEmailLogin.ts new file mode 100644 index 00000000..1597a15c --- /dev/null +++ b/src/apis/Auth/legacy/postEmailLogin.ts @@ -0,0 +1,37 @@ +import { useMutation } from "@tanstack/react-query"; + +import type { AxiosError } from "axios"; +import { useRouter, useSearchParams } from "next/navigation"; +import useAuthStore from "@/lib/zustand/useAuthStore"; +import { toast } from "@/lib/zustand/useToastStore"; +import { validateSafeRedirect } from "@/utils/authUtils"; +import { authApi, type EmailLoginRequest, type EmailLoginResponse } from "./api"; + +/** + * @description 이메일 로그인을 위한 useMutation 커스텀 훅 + */ +const usePostEmailAuth = () => { + const { setAccessToken } = useAuthStore(); + const searchParams = useSearchParams(); + const router = useRouter(); + + return useMutation({ + mutationFn: (data) => authApi.postEmailLogin(data), + onSuccess: (data) => { + const { accessToken } = data; + + // Zustand persist가 자동으로 localStorage에 저장 + // refreshToken은 서버에서 HTTP-only 쿠키로 자동 설정됨 + setAccessToken(accessToken); + + // 안전한 리다이렉트 처리 - 오픈 리다이렉트 방지 + const redirectParam = searchParams.get("redirect"); + const safeRedirect = validateSafeRedirect(redirectParam); + + toast.success("로그인에 성공했습니다."); + router.replace(safeRedirect); + }, + }); +}; + +export default usePostEmailAuth; diff --git a/src/apis/Auth/legacy/postEmailVerification.CHANGES.md b/src/apis/Auth/legacy/postEmailVerification.CHANGES.md new file mode 100644 index 00000000..311bad3f --- /dev/null +++ b/src/apis/Auth/legacy/postEmailVerification.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: postEmailVerification.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/auth/email/sign-up +- Method: POST +- Function: postEmailVerification + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `EmailSignUpResponse` +- 현재: `EmailVerificationResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `EmailSignUpRequest` +- 현재: `EmailVerificationRequest` + +## 권장 조치 + +1. `legacy/postEmailVerification.ts` 파일의 비즈니스 로직 확인 +2. 새 `postEmailVerification.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postEmailVerification.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Auth/legacy/postEmailVerification.ts b/src/apis/Auth/legacy/postEmailVerification.ts new file mode 100644 index 00000000..e9fe17f6 --- /dev/null +++ b/src/apis/Auth/legacy/postEmailVerification.ts @@ -0,0 +1,20 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { authApi, type EmailSignUpRequest, type EmailSignUpResponse } from "./api"; + +/** + * @description 이메일 회원가입을 위한 useMutation 커스텀 훅 + */ +const usePostEmailSignUp = () => { + return useMutation({ + mutationFn: (data) => authApi.postEmailSignUp(data), + onError: (error) => { + console.error("이메일 회원가입 실패:", error); + toast.error("회원가입에 실패했습니다."); + }, + }); +}; + +export default usePostEmailSignUp; diff --git a/src/apis/Auth/legacy/postKakaoAuth.ts b/src/apis/Auth/legacy/postKakaoAuth.ts new file mode 100644 index 00000000..ee5e22b6 --- /dev/null +++ b/src/apis/Auth/legacy/postKakaoAuth.ts @@ -0,0 +1,44 @@ +import { useMutation } from "@tanstack/react-query"; + +import type { AxiosError } from "axios"; +import { useRouter, useSearchParams } from "next/navigation"; +import useAuthStore from "@/lib/zustand/useAuthStore"; +import { toast } from "@/lib/zustand/useToastStore"; +import { validateSafeRedirect } from "@/utils/authUtils"; +import { authApi, type KakaoAuthRequest, type KakaoAuthResponse } from "./api"; + +/** + * @description 카카오 로그인을 위한 useMutation 커스텀 훅 + */ +const usePostKakaoAuth = () => { + const { setAccessToken } = useAuthStore(); + const router = useRouter(); + const searchParams = useSearchParams(); + + return useMutation({ + mutationFn: (data) => authApi.postKakaoAuth(data), + onSuccess: (data) => { + if (data.isRegistered) { + // 기존 회원일 시 - Zustand persist가 자동으로 localStorage에 저장 + // refreshToken은 서버에서 HTTP-only 쿠키로 자동 설정됨 + setAccessToken(data.accessToken); + + // 안전한 리다이렉트 처리 - 오픈 리다이렉트 방지 + const redirectParam = searchParams.get("redirect"); + const safeRedirect = validateSafeRedirect(redirectParam); + + toast.success("로그인에 성공했습니다."); + router.replace(safeRedirect); + } else { + // 새로운 회원일 시 - 회원가입 페이지로 이동 + router.push(`/sign-up?token=${data.signUpToken}`); + } + }, + onError: () => { + toast.error("카카오 로그인 중 오류가 발생했습니다. 다시 시도해주세요."); + router.push("/login"); + }, + }); +}; + +export default usePostKakaoAuth; diff --git a/src/apis/Auth/legacy/postRefreshToken.CHANGES.md b/src/apis/Auth/legacy/postRefreshToken.CHANGES.md new file mode 100644 index 00000000..14e60910 --- /dev/null +++ b/src/apis/Auth/legacy/postRefreshToken.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postRefreshToken.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/auth/reissue +- Method: POST +- Function: postRefreshToken + +## 변경 내용 + +### request-type + +**Request 타입 변경** + +- 이전: `void` +- 현재: `RefreshTokenRequest` + +## 권장 조치 + +1. `legacy/postRefreshToken.ts` 파일의 비즈니스 로직 확인 +2. 새 `postRefreshToken.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postRefreshToken.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Auth/legacy/postRefreshToken.ts b/src/apis/Auth/legacy/postRefreshToken.ts new file mode 100644 index 00000000..68fbf570 --- /dev/null +++ b/src/apis/Auth/legacy/postRefreshToken.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { authApi, type RefreshTokenResponse } from "./api"; + +const usePostRefreshToken = () => { + return useMutation({ + mutationFn: () => authApi.postRefreshToken(), + }); +}; + +export default usePostRefreshToken; diff --git a/src/apis/Auth/legacy/postSignOut.CHANGES.md b/src/apis/Auth/legacy/postSignOut.CHANGES.md new file mode 100644 index 00000000..bcd0f7e6 --- /dev/null +++ b/src/apis/Auth/legacy/postSignOut.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postSignOut.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/auth/sign-out +- Method: POST +- Function: postSignOut + +## 변경 내용 + +### request-type + +**Request 타입 변경** + +- 이전: `void` +- 현재: `SignOutRequest` + +## 권장 조치 + +1. `legacy/postSignOut.ts` 파일의 비즈니스 로직 확인 +2. 새 `postSignOut.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postSignOut.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Auth/legacy/postSignOut.ts b/src/apis/Auth/legacy/postSignOut.ts new file mode 100644 index 00000000..a983f61a --- /dev/null +++ b/src/apis/Auth/legacy/postSignOut.ts @@ -0,0 +1,26 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import useAuthStore from "@/lib/zustand/useAuthStore"; +import { authApi, type SignOutResponse } from "./api"; + +/** + * @description 로그아웃을 위한 useMutation 커스텀 훅 + */ +const usePostLogout = () => { + const { clearAccessToken } = useAuthStore(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: () => authApi.postSignOut(), + onSuccess: () => { + // Zustand persist가 자동으로 localStorage에서 제거 + clearAccessToken(); + queryClient.clear(); + // 로그아웃 후 홈으로 리다이렉트 + window.location.href = "/"; + }, + }); +}; + +export default usePostLogout; diff --git a/src/apis/Auth/legacy/postSignUp.ts b/src/apis/Auth/legacy/postSignUp.ts new file mode 100644 index 00000000..c5068006 --- /dev/null +++ b/src/apis/Auth/legacy/postSignUp.ts @@ -0,0 +1,20 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { authApi, type SignUpRequest, type SignUpResponse } from "./api"; + +/** + * @description 회원가입을 위한 useMutation 커스텀 훅 + */ +const usePostSignUp = () => { + return useMutation({ + mutationFn: (data) => authApi.postSignUp(data), + onError: (error) => { + console.error("회원가입 실패:", error); + toast.error("회원가입에 실패했습니다."); + }, + }); +}; + +export default usePostSignUp; diff --git a/src/apis/Auth/postAppleAuth.ts b/src/apis/Auth/postAppleAuth.ts index c62cfdd9..cb30b87b 100644 --- a/src/apis/Auth/postAppleAuth.ts +++ b/src/apis/Auth/postAppleAuth.ts @@ -1,43 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; +import { authApi, AppleAuthResponse, AppleAuthRequest } from "./api"; -import type { AxiosError } from "axios"; -import { useRouter, useSearchParams } from "next/navigation"; -import useAuthStore from "@/lib/zustand/useAuthStore"; -import { toast } from "@/lib/zustand/useToastStore"; -import { validateSafeRedirect } from "@/utils/authUtils"; -import { type AppleAuthRequest, type AppleAuthResponse, authApi } from "./api"; - -/** - * @description 애플 로그인을 위한 useMutation 커스텀 훅 - */ const usePostAppleAuth = () => { - const router = useRouter(); - const searchParams = useSearchParams(); - return useMutation({ - mutationFn: (data) => authApi.postAppleAuth(data), - onSuccess: (data) => { - if (data.isRegistered) { - // 기존 회원일 시 - Zustand persist가 자동으로 localStorage에 저장 - // refreshToken은 서버에서 HTTP-only 쿠키로 자동 설정됨 - useAuthStore.getState().setAccessToken(data.accessToken); - - // 안전한 리다이렉트 처리 - 오픈 리다이렉트 방지 - const redirectParam = searchParams.get("redirect"); - const safeRedirect = validateSafeRedirect(redirectParam); - - toast.success("로그인에 성공했습니다."); - router.replace(safeRedirect); - } else { - // 새로운 회원일 시 - 회원가입 페이지로 이동 - router.push(`/sign-up?token=${data.signUpToken}`); - } - }, - onError: () => { - toast.error("애플 로그인 중 오류가 발생했습니다. 다시 시도해주세요."); - router.push("/login"); - }, + mutationFn: (data) => authApi.postAppleAuth({ data }), }); }; -export default usePostAppleAuth; +export default usePostAppleAuth; \ No newline at end of file diff --git a/src/apis/Auth/postEmailLogin.ts b/src/apis/Auth/postEmailLogin.ts index 1597a15c..d8ef06df 100644 --- a/src/apis/Auth/postEmailLogin.ts +++ b/src/apis/Auth/postEmailLogin.ts @@ -1,37 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; +import { authApi, EmailLoginResponse, EmailLoginRequest } from "./api"; -import type { AxiosError } from "axios"; -import { useRouter, useSearchParams } from "next/navigation"; -import useAuthStore from "@/lib/zustand/useAuthStore"; -import { toast } from "@/lib/zustand/useToastStore"; -import { validateSafeRedirect } from "@/utils/authUtils"; -import { authApi, type EmailLoginRequest, type EmailLoginResponse } from "./api"; - -/** - * @description 이메일 로그인을 위한 useMutation 커스텀 훅 - */ -const usePostEmailAuth = () => { - const { setAccessToken } = useAuthStore(); - const searchParams = useSearchParams(); - const router = useRouter(); - +const usePostEmailLogin = () => { return useMutation({ - mutationFn: (data) => authApi.postEmailLogin(data), - onSuccess: (data) => { - const { accessToken } = data; - - // Zustand persist가 자동으로 localStorage에 저장 - // refreshToken은 서버에서 HTTP-only 쿠키로 자동 설정됨 - setAccessToken(accessToken); - - // 안전한 리다이렉트 처리 - 오픈 리다이렉트 방지 - const redirectParam = searchParams.get("redirect"); - const safeRedirect = validateSafeRedirect(redirectParam); - - toast.success("로그인에 성공했습니다."); - router.replace(safeRedirect); - }, + mutationFn: (data) => authApi.postEmailLogin({ data }), }); }; -export default usePostEmailAuth; +export default usePostEmailLogin; \ No newline at end of file diff --git a/src/apis/Auth/postEmailVerification.ts b/src/apis/Auth/postEmailVerification.ts index e9fe17f6..99aefafe 100644 --- a/src/apis/Auth/postEmailVerification.ts +++ b/src/apis/Auth/postEmailVerification.ts @@ -1,20 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { authApi, EmailVerificationResponse, EmailVerificationRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { authApi, type EmailSignUpRequest, type EmailSignUpResponse } from "./api"; - -/** - * @description 이메일 회원가입을 위한 useMutation 커스텀 훅 - */ -const usePostEmailSignUp = () => { - return useMutation({ - mutationFn: (data) => authApi.postEmailSignUp(data), - onError: (error) => { - console.error("이메일 회원가입 실패:", error); - toast.error("회원가입에 실패했습니다."); - }, +const usePostEmailVerification = () => { + return useMutation({ + mutationFn: (data) => authApi.postEmailVerification({ data }), }); }; -export default usePostEmailSignUp; +export default usePostEmailVerification; \ No newline at end of file diff --git a/src/apis/Auth/postKakaoAuth.ts b/src/apis/Auth/postKakaoAuth.ts index ee5e22b6..2aaebd97 100644 --- a/src/apis/Auth/postKakaoAuth.ts +++ b/src/apis/Auth/postKakaoAuth.ts @@ -1,44 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; +import { authApi, KakaoAuthResponse, KakaoAuthRequest } from "./api"; -import type { AxiosError } from "axios"; -import { useRouter, useSearchParams } from "next/navigation"; -import useAuthStore from "@/lib/zustand/useAuthStore"; -import { toast } from "@/lib/zustand/useToastStore"; -import { validateSafeRedirect } from "@/utils/authUtils"; -import { authApi, type KakaoAuthRequest, type KakaoAuthResponse } from "./api"; - -/** - * @description 카카오 로그인을 위한 useMutation 커스텀 훅 - */ const usePostKakaoAuth = () => { - const { setAccessToken } = useAuthStore(); - const router = useRouter(); - const searchParams = useSearchParams(); - return useMutation({ - mutationFn: (data) => authApi.postKakaoAuth(data), - onSuccess: (data) => { - if (data.isRegistered) { - // 기존 회원일 시 - Zustand persist가 자동으로 localStorage에 저장 - // refreshToken은 서버에서 HTTP-only 쿠키로 자동 설정됨 - setAccessToken(data.accessToken); - - // 안전한 리다이렉트 처리 - 오픈 리다이렉트 방지 - const redirectParam = searchParams.get("redirect"); - const safeRedirect = validateSafeRedirect(redirectParam); - - toast.success("로그인에 성공했습니다."); - router.replace(safeRedirect); - } else { - // 새로운 회원일 시 - 회원가입 페이지로 이동 - router.push(`/sign-up?token=${data.signUpToken}`); - } - }, - onError: () => { - toast.error("카카오 로그인 중 오류가 발생했습니다. 다시 시도해주세요."); - router.push("/login"); - }, + mutationFn: (data) => authApi.postKakaoAuth({ data }), }); }; -export default usePostKakaoAuth; +export default usePostKakaoAuth; \ No newline at end of file diff --git a/src/apis/Auth/postRefreshToken.ts b/src/apis/Auth/postRefreshToken.ts index 68fbf570..ae86a780 100644 --- a/src/apis/Auth/postRefreshToken.ts +++ b/src/apis/Auth/postRefreshToken.ts @@ -1,11 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { authApi, type RefreshTokenResponse } from "./api"; +import { authApi, RefreshTokenResponse, RefreshTokenRequest } from "./api"; const usePostRefreshToken = () => { - return useMutation({ - mutationFn: () => authApi.postRefreshToken(), + return useMutation({ + mutationFn: (data) => authApi.postRefreshToken({ data }), }); }; -export default usePostRefreshToken; +export default usePostRefreshToken; \ No newline at end of file diff --git a/src/apis/Auth/postSignOut.ts b/src/apis/Auth/postSignOut.ts index a983f61a..8d31dc93 100644 --- a/src/apis/Auth/postSignOut.ts +++ b/src/apis/Auth/postSignOut.ts @@ -1,26 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { authApi, SignOutResponse, SignOutRequest } from "./api"; -import useAuthStore from "@/lib/zustand/useAuthStore"; -import { authApi, type SignOutResponse } from "./api"; - -/** - * @description 로그아웃을 위한 useMutation 커스텀 훅 - */ -const usePostLogout = () => { - const { clearAccessToken } = useAuthStore(); - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: () => authApi.postSignOut(), - onSuccess: () => { - // Zustand persist가 자동으로 localStorage에서 제거 - clearAccessToken(); - queryClient.clear(); - // 로그아웃 후 홈으로 리다이렉트 - window.location.href = "/"; - }, +const usePostSignOut = () => { + return useMutation({ + mutationFn: (data) => authApi.postSignOut({ data }), }); }; -export default usePostLogout; +export default usePostSignOut; \ No newline at end of file diff --git a/src/apis/Auth/postSignUp.ts b/src/apis/Auth/postSignUp.ts index c5068006..eadc9cb8 100644 --- a/src/apis/Auth/postSignUp.ts +++ b/src/apis/Auth/postSignUp.ts @@ -1,20 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { authApi, SignUpResponse, SignUpRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { authApi, type SignUpRequest, type SignUpResponse } from "./api"; - -/** - * @description 회원가입을 위한 useMutation 커스텀 훅 - */ const usePostSignUp = () => { return useMutation({ - mutationFn: (data) => authApi.postSignUp(data), - onError: (error) => { - console.error("회원가입 실패:", error); - toast.error("회원가입에 실패했습니다."); - }, + mutationFn: (data) => authApi.postSignUp({ data }), }); }; -export default usePostSignUp; +export default usePostSignUp; \ No newline at end of file diff --git a/src/apis/MyPage/api.ts b/src/apis/MyPage/api.ts index 8586b26d..d6f5f956 100644 --- a/src/apis/MyPage/api.ts +++ b/src/apis/MyPage/api.ts @@ -1,68 +1,56 @@ -import type { AxiosResponse } from "axios"; -import type { UserRole } from "@/types/mentor"; -import type { BaseUserInfo } from "@/types/myInfo"; import { axiosInstance } from "@/utils/axiosInstance"; -// --- 타입 정의 --- -export interface MenteeInfo extends BaseUserInfo { - role: UserRole.MENTEE; - interestedCountries: string[]; -} - -export interface MentorInfo extends BaseUserInfo { - role: UserRole.MENTOR; - attendedUniversity: string; -} - -export interface AdminInfo extends BaseUserInfo { - role: UserRole.ADMIN; - attendedUniversity: string; -} +export type InterestedRegionCountryResponse = void; -export type MyInfoResponse = MenteeInfo | MentorInfo | AdminInfo; +export type InterestedRegionCountryRequest = Record; -export type InterestedRegionCountryResponse = undefined; +export type ProfileResponse = Record; -export type InterestedRegionCountryRequest = string[]; +export type ProfileRequest = Record; -export interface ProfilePatchRequest { - nickname?: string; - file?: File; +export interface ProfileResponse { + likedUniversityCount: number; + nickname: string; + profileImageUrl: string; + role: string; + authType: string; + email: string; + likedPostCount: number; + likedMentorCount: number; + interestedCountries: string[]; } -export interface PasswordPatchRequest { - currentPassword: string; - newPassword: string; - newPasswordConfirmation: string; -} +export type PasswordResponse = void; + +export type PasswordRequest = Record; export const myPageApi = { - getProfile: async (): Promise => { - const response: AxiosResponse = await axiosInstance.get("/my"); - return response.data; + patchInterestedRegionCountry: async (params: { data?: InterestedRegionCountryRequest }): Promise => { + const res = await axiosInstance.patch( + `/my/interested-location`, params?.data + ); + return res.data; }, - patchProfile: async (data: ProfilePatchRequest): Promise => { - const formData = new FormData(); - if (data.nickname) { - formData.append("nickname", data.nickname); - } - if (data.file) { - formData.append("file", data.file); - } - const res = await axiosInstance.patch("/my", formData); + patchProfile: async (params: { data?: ProfileRequest }): Promise => { + const res = await axiosInstance.patch( + `/my`, params?.data + ); return res.data; }, - patchPassword: async (data: PasswordPatchRequest): Promise => { - const res = await axiosInstance.patch("/my/password", data); + getProfile: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/my`, { params: params?.params } + ); return res.data; }, - patchInterestedRegionCountry: async ( - data: InterestedRegionCountryRequest, - ): Promise => { - const res = await axiosInstance.patch(`/my/interested-location`, data); + patchPassword: async (params: { data?: PasswordRequest }): Promise => { + const res = await axiosInstance.patch( + `/my/password`, params?.data + ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/MyPage/getProfile.ts b/src/apis/MyPage/getProfile.ts index 3ca32d82..042c0767 100644 --- a/src/apis/MyPage/getProfile.ts +++ b/src/apis/MyPage/getProfile.ts @@ -1,37 +1,13 @@ -import { type UseQueryResult, useMutationState, useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useQuery } from "@tanstack/react-query"; +import { myPageApi, ProfileResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type MyInfoResponse, myPageApi } from "./api"; -type UseGetMyInfoResult = Omit, "data"> & { - data: MyInfoResponse | undefined; -}; - -const useGetMyInfo = (): UseGetMyInfoResult => { - const queryResult = useQuery({ - queryKey: [QueryKeys.MyPage.profile], - queryFn: () => myPageApi.getProfile(), - // staleTime을 무한으로 설정하여 불필요한 자동 refetch를 방지합니다. - staleTime: Infinity, - gcTime: 1000 * 60 * 30, // 예: 30분 - }); - - const pendingMutations = useMutationState({ - filters: { - mutationKey: [QueryKeys.MyPage.profile, "patch"], - status: "pending", - }, - select: (mutation) => { - return mutation.state.variables as Partial; - }, +const useGetProfile = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.MyPage.profile, params], + queryFn: () => myPageApi.getProfile(params ? { params } : {}), }); - - const isOptimistic = pendingMutations.length > 0; - const pendingData = isOptimistic ? pendingMutations[0] : null; - - const displayData = isOptimistic && queryResult.data ? { ...queryResult.data, ...pendingData } : queryResult.data; - - return { ...queryResult, data: displayData as MyInfoResponse | undefined }; }; -export default useGetMyInfo; +export default useGetProfile; \ No newline at end of file diff --git a/src/apis/MyPage/index.ts b/src/apis/MyPage/index.ts index f431945c..0f1aafd8 100644 --- a/src/apis/MyPage/index.ts +++ b/src/apis/MyPage/index.ts @@ -1,13 +1,6 @@ -export { - type AdminInfo, - type MenteeInfo, - type MentorInfo, - type MyInfoResponse, - myPageApi, - type PasswordPatchRequest, - type ProfilePatchRequest, -} from "./api"; -export { default as useGetMyInfo } from "./getProfile"; -export { default as usePatchInterestedRegionCountry } from "./patchInterestedRegionCountry"; -export { default as usePatchMyPassword } from "./patchPassword"; -export { default as usePatchMyInfo } from "./patchProfile"; +export { myPageApi } from './api'; +export { default as getProfile } from './getProfile'; +export { default as index } from './index'; +export { default as patchInterestedRegionCountry } from './patchInterestedRegionCountry'; +export { default as patchPassword } from './patchPassword'; +export { default as patchProfile } from './patchProfile'; diff --git a/src/apis/MyPage/legacy/getProfile.CHANGES.md b/src/apis/MyPage/legacy/getProfile.CHANGES.md new file mode 100644 index 00000000..1faf7cbd --- /dev/null +++ b/src/apis/MyPage/legacy/getProfile.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getProfile.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/my +- Method: GET +- Function: getProfile + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `MyInfoResponse` +- 현재: `ProfileResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.MyPage.profile` +- 현재: `QueryKeys.myPage.getProfile, URL, params` + +## 권장 조치 + +1. `legacy/getProfile.ts` 파일의 비즈니스 로직 확인 +2. 새 `getProfile.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getProfile.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/MyPage/legacy/getProfile.ts b/src/apis/MyPage/legacy/getProfile.ts new file mode 100644 index 00000000..3ca32d82 --- /dev/null +++ b/src/apis/MyPage/legacy/getProfile.ts @@ -0,0 +1,37 @@ +import { type UseQueryResult, useMutationState, useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type MyInfoResponse, myPageApi } from "./api"; + +type UseGetMyInfoResult = Omit, "data"> & { + data: MyInfoResponse | undefined; +}; + +const useGetMyInfo = (): UseGetMyInfoResult => { + const queryResult = useQuery({ + queryKey: [QueryKeys.MyPage.profile], + queryFn: () => myPageApi.getProfile(), + // staleTime을 무한으로 설정하여 불필요한 자동 refetch를 방지합니다. + staleTime: Infinity, + gcTime: 1000 * 60 * 30, // 예: 30분 + }); + + const pendingMutations = useMutationState({ + filters: { + mutationKey: [QueryKeys.MyPage.profile, "patch"], + status: "pending", + }, + select: (mutation) => { + return mutation.state.variables as Partial; + }, + }); + + const isOptimistic = pendingMutations.length > 0; + const pendingData = isOptimistic ? pendingMutations[0] : null; + + const displayData = isOptimistic && queryResult.data ? { ...queryResult.data, ...pendingData } : queryResult.data; + + return { ...queryResult, data: displayData as MyInfoResponse | undefined }; +}; + +export default useGetMyInfo; diff --git a/src/apis/MyPage/legacy/patchInterestedRegionCountry.ts b/src/apis/MyPage/legacy/patchInterestedRegionCountry.ts new file mode 100644 index 00000000..0b15e70f --- /dev/null +++ b/src/apis/MyPage/legacy/patchInterestedRegionCountry.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type InterestedRegionCountryRequest, type InterestedRegionCountryResponse, myPageApi } from "./api"; + +const usePatchInterestedRegionCountry = () => { + return useMutation({ + mutationFn: (data) => myPageApi.patchInterestedRegionCountry(data), + }); +}; + +export default usePatchInterestedRegionCountry; diff --git a/src/apis/MyPage/legacy/patchPassword.CHANGES.md b/src/apis/MyPage/legacy/patchPassword.CHANGES.md new file mode 100644 index 00000000..537a1f6a --- /dev/null +++ b/src/apis/MyPage/legacy/patchPassword.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: patchPassword.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/my/password +- Method: PATCH +- Function: patchPassword + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `void` +- 현재: `PasswordResponse` + +## 권장 조치 + +1. `legacy/patchPassword.ts` 파일의 비즈니스 로직 확인 +2. 새 `patchPassword.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/patchPassword.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/MyPage/legacy/patchPassword.ts b/src/apis/MyPage/legacy/patchPassword.ts new file mode 100644 index 00000000..ac8096f8 --- /dev/null +++ b/src/apis/MyPage/legacy/patchPassword.ts @@ -0,0 +1,31 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; + +import type { AxiosError } from "axios"; +import { useRouter } from "next/navigation"; +import useAuthStore from "@/lib/zustand/useAuthStore"; +import { toast } from "@/lib/zustand/useToastStore"; +import { QueryKeys } from "../queryKeys"; +import { myPageApi, type PasswordPatchRequest } from "./api"; + +const usePatchMyPassword = () => { + const queryClient = useQueryClient(); + const router = useRouter(); + const { clearAccessToken } = useAuthStore(); + + return useMutation, PasswordPatchRequest>({ + mutationKey: [QueryKeys.MyPage.password, "patch"], + mutationFn: (data) => myPageApi.patchPassword(data), + onSuccess: () => { + clearAccessToken(); + queryClient.clear(); + toast.success("비밀번호가 성공적으로 변경되었습니다."); + router.replace("/"); + }, + onError: (error) => { + const errorMessage = error.response?.data?.message; + toast.error(errorMessage || "비밀번호 변경에 실패했습니다. 다시 시도해주세요."); + }, + }); +}; + +export default usePatchMyPassword; diff --git a/src/apis/MyPage/legacy/patchProfile.CHANGES.md b/src/apis/MyPage/legacy/patchProfile.CHANGES.md new file mode 100644 index 00000000..22df967d --- /dev/null +++ b/src/apis/MyPage/legacy/patchProfile.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: patchProfile.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/my +- Method: PATCH +- Function: patchProfile + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `void` +- 현재: `ProfileResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.MyPage.profile` +- 현재: `QueryKeys.myPage.patchProfile, URL, params` + +## 권장 조치 + +1. `legacy/patchProfile.ts` 파일의 비즈니스 로직 확인 +2. 새 `patchProfile.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/patchProfile.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/MyPage/legacy/patchProfile.ts b/src/apis/MyPage/legacy/patchProfile.ts new file mode 100644 index 00000000..ce26560c --- /dev/null +++ b/src/apis/MyPage/legacy/patchProfile.ts @@ -0,0 +1,28 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { toast } from "@/lib/zustand/useToastStore"; +import { QueryKeys } from "../queryKeys"; +import { myPageApi, type ProfilePatchRequest } from "./api"; + +const usePatchMyInfo = () => { + const queryClient = useQueryClient(); + + return useMutation, ProfilePatchRequest>({ + mutationKey: [QueryKeys.MyPage.profile, "patch"], + mutationFn: (data) => myPageApi.patchProfile(data), + onSettled: () => { + queryClient.invalidateQueries({ + queryKey: [QueryKeys.MyPage.profile], + }); + }, + onSuccess: () => { + toast.success("프로필이 성공적으로 수정되었습니다."); + }, + onError: (error) => { + const errorMessage = error.response?.data?.message; + toast.error(errorMessage || "프로필 수정에 실패했습니다. 다시 시도해주세요."); + }, + }); +}; + +export default usePatchMyInfo; diff --git a/src/apis/MyPage/patchInterestedRegionCountry.ts b/src/apis/MyPage/patchInterestedRegionCountry.ts index 0b15e70f..0ea8b18f 100644 --- a/src/apis/MyPage/patchInterestedRegionCountry.ts +++ b/src/apis/MyPage/patchInterestedRegionCountry.ts @@ -1,11 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type InterestedRegionCountryRequest, type InterestedRegionCountryResponse, myPageApi } from "./api"; +import { myPageApi, InterestedRegionCountryResponse, InterestedRegionCountryRequest } from "./api"; const usePatchInterestedRegionCountry = () => { return useMutation({ - mutationFn: (data) => myPageApi.patchInterestedRegionCountry(data), + mutationFn: (data) => myPageApi.patchInterestedRegionCountry({ data }), }); }; -export default usePatchInterestedRegionCountry; +export default usePatchInterestedRegionCountry; \ No newline at end of file diff --git a/src/apis/MyPage/patchPassword.ts b/src/apis/MyPage/patchPassword.ts index ac8096f8..8592b77e 100644 --- a/src/apis/MyPage/patchPassword.ts +++ b/src/apis/MyPage/patchPassword.ts @@ -1,31 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { myPageApi, PasswordResponse, PasswordRequest } from "./api"; -import type { AxiosError } from "axios"; -import { useRouter } from "next/navigation"; -import useAuthStore from "@/lib/zustand/useAuthStore"; -import { toast } from "@/lib/zustand/useToastStore"; -import { QueryKeys } from "../queryKeys"; -import { myPageApi, type PasswordPatchRequest } from "./api"; - -const usePatchMyPassword = () => { - const queryClient = useQueryClient(); - const router = useRouter(); - const { clearAccessToken } = useAuthStore(); - - return useMutation, PasswordPatchRequest>({ - mutationKey: [QueryKeys.MyPage.password, "patch"], - mutationFn: (data) => myPageApi.patchPassword(data), - onSuccess: () => { - clearAccessToken(); - queryClient.clear(); - toast.success("비밀번호가 성공적으로 변경되었습니다."); - router.replace("/"); - }, - onError: (error) => { - const errorMessage = error.response?.data?.message; - toast.error(errorMessage || "비밀번호 변경에 실패했습니다. 다시 시도해주세요."); - }, +const usePatchPassword = () => { + return useMutation({ + mutationFn: (data) => myPageApi.patchPassword({ data }), }); }; -export default usePatchMyPassword; +export default usePatchPassword; \ No newline at end of file diff --git a/src/apis/MyPage/patchProfile.ts b/src/apis/MyPage/patchProfile.ts index ce26560c..20204ad8 100644 --- a/src/apis/MyPage/patchProfile.ts +++ b/src/apis/MyPage/patchProfile.ts @@ -1,28 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { toast } from "@/lib/zustand/useToastStore"; -import { QueryKeys } from "../queryKeys"; -import { myPageApi, type ProfilePatchRequest } from "./api"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { myPageApi, ProfileResponse, ProfileRequest } from "./api"; -const usePatchMyInfo = () => { - const queryClient = useQueryClient(); - - return useMutation, ProfilePatchRequest>({ - mutationKey: [QueryKeys.MyPage.profile, "patch"], - mutationFn: (data) => myPageApi.patchProfile(data), - onSettled: () => { - queryClient.invalidateQueries({ - queryKey: [QueryKeys.MyPage.profile], - }); - }, - onSuccess: () => { - toast.success("프로필이 성공적으로 수정되었습니다."); - }, - onError: (error) => { - const errorMessage = error.response?.data?.message; - toast.error(errorMessage || "프로필 수정에 실패했습니다. 다시 시도해주세요."); - }, +const usePatchProfile = () => { + return useMutation({ + mutationFn: (data) => myPageApi.patchProfile({ data }), }); }; -export default usePatchMyInfo; +export default usePatchProfile; \ No newline at end of file diff --git a/src/apis/Scores/api.ts b/src/apis/Scores/api.ts index e1961939..5b45182c 100644 --- a/src/apis/Scores/api.ts +++ b/src/apis/Scores/api.ts @@ -1,79 +1,78 @@ -import type { AxiosResponse } from "axios"; -import type { GpaScore, LanguageTestEnum, LanguageTestScore } from "@/types/score"; import { axiosInstance } from "@/utils/axiosInstance"; -// ====== Query Keys ====== -export const ScoresQueryKeys = { - myGpaScore: "myGpaScore", - myLanguageTestScore: "myLanguageTestScore", -} as const; +export interface CreateLanguageTestResponse { + id: number; +} + +export type CreateLanguageTestRequest = Record; + +export interface LanguageTestListResponseLanguageTestScoreStatusResponseListItem { + id: number; + languageTestResponse: LanguageTestListResponseLanguageTestScoreStatusResponseListItemLanguageTestResponse; + verifyStatus: string; + rejectedReason: null; +} + +export interface LanguageTestListResponseLanguageTestScoreStatusResponseListItemLanguageTestResponse { + languageTestType: string; + languageTestScore: string; + languageTestReportUrl: string; +} -// ====== Types ====== -export interface UseMyGpaScoreResponse { - gpaScoreStatusResponseList: GpaScore[]; +export interface LanguageTestListResponse { + languageTestScoreStatusResponseList: LanguageTestListResponseLanguageTestScoreStatusResponseListItem[]; } -export interface UseGetMyLanguageTestScoreResponse { - languageTestScoreStatusResponseList: LanguageTestScore[]; +export interface CreateGpaResponse { + id: number; } -export interface UsePostGpaScoreRequest { - gpaScoreRequest: { - gpa: number; - gpaCriteria: number; - issueDate: string; // yyyy-MM-dd - }; - file: Blob; +export type CreateGpaRequest = Record; + +export interface GpaListResponseGpaScoreStatusResponseListItem { + id: number; + gpaResponse: GpaListResponseGpaScoreStatusResponseListItemGpaResponse; + verifyStatus: string; + rejectedReason: null; +} + +export interface GpaListResponseGpaScoreStatusResponseListItemGpaResponse { + gpa: number; + gpaCriteria: number; + gpaReportUrl: string; } -export interface UsePostLanguageTestScoreRequest { - languageTestScoreRequest: { - languageTestType: LanguageTestEnum; - languageTestScore: string; - issueDate: string; // yyyy-MM-dd - }; - file: File; +export interface GpaListResponse { + gpaScoreStatusResponseList: GpaListResponseGpaScoreStatusResponseListItem[]; } -// ====== API Functions ====== export const scoresApi = { - /** - * 내 학점 점수 조회 - */ - getMyGpaScore: async (): Promise> => { - return axiosInstance.get("/scores/gpas"); + postCreateLanguageTest: async (params: { data?: CreateLanguageTestRequest }): Promise => { + const res = await axiosInstance.post( + `/scores/language-tests`, params?.data + ); + return res.data; }, - /** - * 내 어학 점수 조회 - */ - getMyLanguageTestScore: async (): Promise> => { - return axiosInstance.get("/scores/language-tests"); + getLanguageTestList: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/scores/language-tests`, { params: params?.params } + ); + return res.data; }, - /** - * 학점 점수 제출 - */ - postGpaScore: async (request: UsePostGpaScoreRequest): Promise> => { - const formData = new FormData(); - formData.append( - "gpaScoreRequest", - new Blob([JSON.stringify(request.gpaScoreRequest)], { type: "application/json" }), + postCreateGpa: async (params: { data?: CreateGpaRequest }): Promise => { + const res = await axiosInstance.post( + `/scores/gpas`, params?.data ); - formData.append("file", request.file); - return axiosInstance.post("/scores/gpas", formData); + return res.data; }, - /** - * 어학 점수 제출 - */ - postLanguageTestScore: async (request: UsePostLanguageTestScoreRequest): Promise> => { - const formData = new FormData(); - formData.append( - "languageTestScoreRequest", - new Blob([JSON.stringify(request.languageTestScoreRequest)], { type: "application/json" }), + getGpaList: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/scores/gpas`, { params: params?.params } ); - formData.append("file", request.file); - return axiosInstance.post("/scores/language-tests", formData); + return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/Scores/getGpaList.ts b/src/apis/Scores/getGpaList.ts index 00437ae8..b402a643 100644 --- a/src/apis/Scores/getGpaList.ts +++ b/src/apis/Scores/getGpaList.ts @@ -1,17 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; +import { scoresApi, GpaListResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -import { ScoresQueryKeys, scoresApi } from "./api"; - -/** - * @description 내 학점 점수 조회 훅 - */ -const useGetMyGpaScore = () => { - return useQuery({ - queryKey: [ScoresQueryKeys.myGpaScore], - queryFn: scoresApi.getMyGpaScore, - staleTime: Infinity, - select: (data) => data.data.gpaScoreStatusResponseList, +const useGetGpaList = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.Scores.gpaList, params], + queryFn: () => scoresApi.getGpaList(params ? { params } : {}), }); }; -export default useGetMyGpaScore; +export default useGetGpaList; \ No newline at end of file diff --git a/src/apis/Scores/getLanguageTestList.ts b/src/apis/Scores/getLanguageTestList.ts index 22a42549..ace30a13 100644 --- a/src/apis/Scores/getLanguageTestList.ts +++ b/src/apis/Scores/getLanguageTestList.ts @@ -1,17 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; +import { scoresApi, LanguageTestListResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -import { ScoresQueryKeys, scoresApi } from "./api"; - -/** - * @description 내 어학 점수 조회 훅 - */ -const useGetMyLanguageTestScore = () => { - return useQuery({ - queryKey: [ScoresQueryKeys.myLanguageTestScore], - queryFn: scoresApi.getMyLanguageTestScore, - staleTime: Infinity, - select: (data) => data.data.languageTestScoreStatusResponseList, +const useGetLanguageTestList = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.Scores.languageTestList, params], + queryFn: () => scoresApi.getLanguageTestList(params ? { params } : {}), }); }; -export default useGetMyLanguageTestScore; +export default useGetLanguageTestList; \ No newline at end of file diff --git a/src/apis/Scores/index.ts b/src/apis/Scores/index.ts index 529612eb..28d1ffa4 100644 --- a/src/apis/Scores/index.ts +++ b/src/apis/Scores/index.ts @@ -1,12 +1,6 @@ -export type { - UseGetMyLanguageTestScoreResponse, - UseMyGpaScoreResponse, - UsePostGpaScoreRequest, - UsePostLanguageTestScoreRequest, -} from "./api"; -export { ScoresQueryKeys, scoresApi } from "./api"; - -export { default as useGetMyGpaScore } from "./getGpaList"; -export { default as useGetMyLanguageTestScore } from "./getLanguageTestList"; -export { default as usePostGpaScore } from "./postCreateGpa"; -export { default as usePostLanguageTestScore } from "./postCreateLanguageTest"; +export { scoresApi } from './api'; +export { default as getGpaList } from './getGpaList'; +export { default as getLanguageTestList } from './getLanguageTestList'; +export { default as index } from './index'; +export { default as postCreateGpa } from './postCreateGpa'; +export { default as postCreateLanguageTest } from './postCreateLanguageTest'; diff --git a/src/apis/Scores/legacy/getGpaList.CHANGES.md b/src/apis/Scores/legacy/getGpaList.CHANGES.md new file mode 100644 index 00000000..db5bb091 --- /dev/null +++ b/src/apis/Scores/legacy/getGpaList.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getGpaList.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/scores/gpas +- Method: GET +- Function: getGpaList + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `ScoresQueryKeys.myGpaScore` +- 현재: `QueryKeys.scores.getGpaList, URL, params` + +## 권장 조치 + +1. `legacy/getGpaList.ts` 파일의 비즈니스 로직 확인 +2. 새 `getGpaList.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getGpaList.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Scores/legacy/getGpaList.ts b/src/apis/Scores/legacy/getGpaList.ts new file mode 100644 index 00000000..00437ae8 --- /dev/null +++ b/src/apis/Scores/legacy/getGpaList.ts @@ -0,0 +1,17 @@ +import { useQuery } from "@tanstack/react-query"; + +import { ScoresQueryKeys, scoresApi } from "./api"; + +/** + * @description 내 학점 점수 조회 훅 + */ +const useGetMyGpaScore = () => { + return useQuery({ + queryKey: [ScoresQueryKeys.myGpaScore], + queryFn: scoresApi.getMyGpaScore, + staleTime: Infinity, + select: (data) => data.data.gpaScoreStatusResponseList, + }); +}; + +export default useGetMyGpaScore; diff --git a/src/apis/Scores/legacy/getLanguageTestList.CHANGES.md b/src/apis/Scores/legacy/getLanguageTestList.CHANGES.md new file mode 100644 index 00000000..412611b8 --- /dev/null +++ b/src/apis/Scores/legacy/getLanguageTestList.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getLanguageTestList.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/scores/language-tests +- Method: GET +- Function: getLanguageTestList + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `ScoresQueryKeys.myLanguageTestScore` +- 현재: `QueryKeys.scores.getLanguageTestList, URL, params` + +## 권장 조치 + +1. `legacy/getLanguageTestList.ts` 파일의 비즈니스 로직 확인 +2. 새 `getLanguageTestList.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getLanguageTestList.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Scores/legacy/getLanguageTestList.ts b/src/apis/Scores/legacy/getLanguageTestList.ts new file mode 100644 index 00000000..22a42549 --- /dev/null +++ b/src/apis/Scores/legacy/getLanguageTestList.ts @@ -0,0 +1,17 @@ +import { useQuery } from "@tanstack/react-query"; + +import { ScoresQueryKeys, scoresApi } from "./api"; + +/** + * @description 내 어학 점수 조회 훅 + */ +const useGetMyLanguageTestScore = () => { + return useQuery({ + queryKey: [ScoresQueryKeys.myLanguageTestScore], + queryFn: scoresApi.getMyLanguageTestScore, + staleTime: Infinity, + select: (data) => data.data.languageTestScoreStatusResponseList, + }); +}; + +export default useGetMyLanguageTestScore; diff --git a/src/apis/Scores/legacy/postCreateGpa.CHANGES.md b/src/apis/Scores/legacy/postCreateGpa.CHANGES.md new file mode 100644 index 00000000..efcd2288 --- /dev/null +++ b/src/apis/Scores/legacy/postCreateGpa.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postCreateGpa.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/scores/gpas +- Method: POST +- Function: postCreateGpa + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `ScoresQueryKeys.myGpaScore` +- 현재: `QueryKeys.scores.postCreateGpa, URL, params` + +## 권장 조치 + +1. `legacy/postCreateGpa.ts` 파일의 비즈니스 로직 확인 +2. 새 `postCreateGpa.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postCreateGpa.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Scores/legacy/postCreateGpa.ts b/src/apis/Scores/legacy/postCreateGpa.ts new file mode 100644 index 00000000..7cf6174a --- /dev/null +++ b/src/apis/Scores/legacy/postCreateGpa.ts @@ -0,0 +1,27 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { ScoresQueryKeys, scoresApi, type UsePostGpaScoreRequest } from "./api"; + +/** + * @description 학점 점수 제출 훅 + */ +export const usePostGpaScore = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (request: UsePostGpaScoreRequest) => scoresApi.postGpaScore(request), + + onSuccess: () => { + toast.success("학점 정보가 성공적으로 제출되었습니다."); + queryClient.invalidateQueries({ queryKey: [ScoresQueryKeys.myGpaScore] }); + }, + + onError: (error) => { + console.error("학점 제출 중 오류 발생:", error); + toast.error("오류가 발생했습니다. 다시 시도해주세요."); + }, + }); +}; + +export default usePostGpaScore; diff --git a/src/apis/Scores/legacy/postCreateLanguageTest.CHANGES.md b/src/apis/Scores/legacy/postCreateLanguageTest.CHANGES.md new file mode 100644 index 00000000..e16e41a5 --- /dev/null +++ b/src/apis/Scores/legacy/postCreateLanguageTest.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postCreateLanguageTest.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/scores/language-tests +- Method: POST +- Function: postCreateLanguageTest + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `ScoresQueryKeys.myLanguageTestScore` +- 현재: `QueryKeys.scores.postCreateLanguageTest, URL, params` + +## 권장 조치 + +1. `legacy/postCreateLanguageTest.ts` 파일의 비즈니스 로직 확인 +2. 새 `postCreateLanguageTest.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postCreateLanguageTest.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/Scores/legacy/postCreateLanguageTest.ts b/src/apis/Scores/legacy/postCreateLanguageTest.ts new file mode 100644 index 00000000..d4ebbc42 --- /dev/null +++ b/src/apis/Scores/legacy/postCreateLanguageTest.ts @@ -0,0 +1,27 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { ScoresQueryKeys, scoresApi, type UsePostLanguageTestScoreRequest } from "./api"; + +/** + * @description 어학 점수 제출 훅 + */ +export const usePostLanguageTestScore = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (request: UsePostLanguageTestScoreRequest) => scoresApi.postLanguageTestScore(request), + + onSuccess: () => { + toast.success("어학 성적이 성공적으로 제출되었습니다."); + queryClient.invalidateQueries({ queryKey: [ScoresQueryKeys.myLanguageTestScore] }); + }, + + onError: (error) => { + console.error("어학 성적 제출 중 오류 발생:", error); + toast.error("오류가 발생했습니다. 다시 시도해주세요."); + }, + }); +}; + +export default usePostLanguageTestScore; diff --git a/src/apis/Scores/postCreateGpa.ts b/src/apis/Scores/postCreateGpa.ts index 7cf6174a..6255a5d0 100644 --- a/src/apis/Scores/postCreateGpa.ts +++ b/src/apis/Scores/postCreateGpa.ts @@ -1,27 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { scoresApi, CreateGpaResponse, CreateGpaRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { ScoresQueryKeys, scoresApi, type UsePostGpaScoreRequest } from "./api"; - -/** - * @description 학점 점수 제출 훅 - */ -export const usePostGpaScore = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: (request: UsePostGpaScoreRequest) => scoresApi.postGpaScore(request), - - onSuccess: () => { - toast.success("학점 정보가 성공적으로 제출되었습니다."); - queryClient.invalidateQueries({ queryKey: [ScoresQueryKeys.myGpaScore] }); - }, - - onError: (error) => { - console.error("학점 제출 중 오류 발생:", error); - toast.error("오류가 발생했습니다. 다시 시도해주세요."); - }, +const usePostCreateGpa = () => { + return useMutation({ + mutationFn: (data) => scoresApi.postCreateGpa({ data }), }); }; -export default usePostGpaScore; +export default usePostCreateGpa; \ No newline at end of file diff --git a/src/apis/Scores/postCreateLanguageTest.ts b/src/apis/Scores/postCreateLanguageTest.ts index d4ebbc42..b6201433 100644 --- a/src/apis/Scores/postCreateLanguageTest.ts +++ b/src/apis/Scores/postCreateLanguageTest.ts @@ -1,27 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { scoresApi, CreateLanguageTestResponse, CreateLanguageTestRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { ScoresQueryKeys, scoresApi, type UsePostLanguageTestScoreRequest } from "./api"; - -/** - * @description 어학 점수 제출 훅 - */ -export const usePostLanguageTestScore = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: (request: UsePostLanguageTestScoreRequest) => scoresApi.postLanguageTestScore(request), - - onSuccess: () => { - toast.success("어학 성적이 성공적으로 제출되었습니다."); - queryClient.invalidateQueries({ queryKey: [ScoresQueryKeys.myLanguageTestScore] }); - }, - - onError: (error) => { - console.error("어학 성적 제출 중 오류 발생:", error); - toast.error("오류가 발생했습니다. 다시 시도해주세요."); - }, +const usePostCreateLanguageTest = () => { + return useMutation({ + mutationFn: (data) => scoresApi.postCreateLanguageTest({ data }), }); }; -export default usePostLanguageTestScore; +export default usePostCreateLanguageTest; \ No newline at end of file diff --git a/src/apis/applications/api.ts b/src/apis/applications/api.ts index 5837a038..f4879dd1 100644 --- a/src/apis/applications/api.ts +++ b/src/apis/applications/api.ts @@ -1,58 +1,147 @@ -import type { AxiosResponse } from "axios"; -import type { ApplicationListResponse } from "@/types/application"; import { axiosInstance } from "@/utils/axiosInstance"; -// ====== Query Keys ====== -export const ApplicationsQueryKeys = { - competitorsApplicationList: "competitorsApplicationList", -} as const; +export interface CompetitorsResponseThirdChoiceItem { + koreanName: string; + studentCapacity: number; + region: string; + country: string; + applicants: CompetitorsResponseThirdChoiceItemApplicantsItem[]; +} + +export interface CompetitorsResponseThirdChoiceItemApplicantsItem { + nicknameForApply: string; + gpa: number; + testType: string; + testScore: string; + isMine: boolean; +} + +export interface CompetitorsResponseSecondChoiceItem { + koreanName: string; + studentCapacity: number; + region: string; + country: string; + applicants: CompetitorsResponseSecondChoiceItemApplicantsItem[]; +} + +export interface CompetitorsResponseSecondChoiceItemApplicantsItem { + nicknameForApply: string; + gpa: number; + testType: string; + testScore: string; + isMine: boolean; +} -// ====== Types ====== -export interface UseSubmitApplicationResponse { - isSuccess: boolean; +export interface CompetitorsResponseFirstChoiceItem { + koreanName: string; + studentCapacity: number; + region: string; + country: string; + applicants: CompetitorsResponseFirstChoiceItemApplicantsItem[]; } -export interface UseSubmitApplicationRequest { - gpaScoreId: number; - languageTestScoreId: number; - universityChoiceRequest: { - firstChoiceUniversityId: number | null; - secondChoiceUniversityId: number | null; - thirdChoiceUniversityId: number | null; - }; +export interface CompetitorsResponseFirstChoiceItemApplicantsItem { + nicknameForApply: string; + gpa: number; + testType: string; + testScore: string; + isMine: boolean; } export interface CompetitorsResponse { - competitors: Array<{ - id: number; - name: string; - score: number; - }>; + firstChoice: CompetitorsResponseFirstChoiceItem[]; + secondChoice: CompetitorsResponseSecondChoiceItem[]; + thirdChoice: CompetitorsResponseThirdChoiceItem[]; +} + +export interface SubmitApplicationResponseAppliedUniversities { + firstChoiceUniversity: string; + secondChoiceUniversity: string; + thirdChoiceUniversity: string; +} + +export interface SubmitApplicationResponse { + totalApplyCount: number; + applyCount: number; + appliedUniversities: SubmitApplicationResponseAppliedUniversities; +} + +export type SubmitApplicationRequest = Record; + +export interface ApplicantsResponseThirdChoiceItem { + koreanName: string; + studentCapacity: number; + region: string; + country: string; + applicants: ApplicantsResponseThirdChoiceItemApplicantsItem[]; +} + +export interface ApplicantsResponseThirdChoiceItemApplicantsItem { + nicknameForApply: string; + gpa: number; + testType: string; + testScore: string; + isMine: boolean; +} + +export interface ApplicantsResponseSecondChoiceItem { + koreanName: string; + studentCapacity: number; + region: string; + country: string; + applicants: ApplicantsResponseSecondChoiceItemApplicantsItem[]; +} + +export interface ApplicantsResponseSecondChoiceItemApplicantsItem { + nicknameForApply: string; + gpa: number; + testType: string; + testScore: string; + isMine: boolean; +} + +export interface ApplicantsResponseFirstChoiceItem { + koreanName: string; + studentCapacity: number; + region: string; + country: string; + applicants: ApplicantsResponseFirstChoiceItemApplicantsItem[]; +} + +export interface ApplicantsResponseFirstChoiceItemApplicantsItem { + nicknameForApply: string; + gpa: number; + testType: string; + testScore: string; + isMine: boolean; +} + +export interface ApplicantsResponse { + firstChoice: ApplicantsResponseFirstChoiceItem[]; + secondChoice: ApplicantsResponseSecondChoiceItem[]; + thirdChoice: ApplicantsResponseThirdChoiceItem[]; } -// ====== API Functions ====== export const applicationsApi = { - /** - * 지원 목록 조회 - */ - getApplicationsList: async (): Promise> => { - return axiosInstance.get("/applications"); + getCompetitors: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/applications/competitors`, { params: params?.params } + ); + return res.data; }, - /** - * 지원 제출 - */ - postSubmitApplication: async ( - request: UseSubmitApplicationRequest, - ): Promise> => { - return axiosInstance.post("/applications", request); + postSubmitApplication: async (params: { data?: SubmitApplicationRequest }): Promise => { + const res = await axiosInstance.post( + `/applications`, params?.data + ); + return res.data; }, - /** - * 경쟁자 목록 조회 - */ - getCompetitors: async (config?: { params?: Record }): Promise => { - const res = await axiosInstance.get("/applications/competitors", config); + getApplicants: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/applications`, { params: params?.params } + ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/applications/getApplicants.ts b/src/apis/applications/getApplicants.ts index f7da9024..2a266ec3 100644 --- a/src/apis/applications/getApplicants.ts +++ b/src/apis/applications/getApplicants.ts @@ -1,27 +1,13 @@ -import { type UseQueryOptions, type UseQueryResult, useQuery } from "@tanstack/react-query"; -import type { AxiosError, AxiosResponse } from "axios"; - -import type { ApplicationListResponse } from "@/types/application"; -import { ApplicationsQueryKeys, applicationsApi } from "./api"; - -type UseGetApplicationsListOptions = Omit< - UseQueryOptions, AxiosError<{ message: string }>, ApplicationListResponse>, - "queryKey" | "queryFn" ->; - -/** - * @description 지원 목록 조회 훅 - */ -const useGetApplicationsList = ( - props?: UseGetApplicationsListOptions, -): UseQueryResult> => { - return useQuery({ - queryKey: [ApplicationsQueryKeys.competitorsApplicationList], - queryFn: applicationsApi.getApplicationsList, - staleTime: 1000 * 60 * 5, // 5분간 캐시 - select: (response) => response.data, - ...props, +import { AxiosError } from "axios"; +import { useQuery } from "@tanstack/react-query"; +import { applicationsApi, ApplicantsResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; + +const useGetApplicants = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.applications.applicants, params], + queryFn: () => applicationsApi.getApplicants(params ? { params } : {}), }); }; -export default useGetApplicationsList; +export default useGetApplicants; \ No newline at end of file diff --git a/src/apis/applications/getCompetitors.ts b/src/apis/applications/getCompetitors.ts index e137b9bd..4d3ccbc9 100644 --- a/src/apis/applications/getCompetitors.ts +++ b/src/apis/applications/getCompetitors.ts @@ -1,7 +1,7 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { applicationsApi, CompetitorsResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { applicationsApi, type CompetitorsResponse } from "./api"; const useGetCompetitors = (params?: Record) => { return useQuery({ @@ -10,4 +10,4 @@ const useGetCompetitors = (params?: Record) => { }); }; -export default useGetCompetitors; +export default useGetCompetitors; \ No newline at end of file diff --git a/src/apis/applications/index.ts b/src/apis/applications/index.ts index f0b0f16b..842f4b73 100644 --- a/src/apis/applications/index.ts +++ b/src/apis/applications/index.ts @@ -1,5 +1,5 @@ -export type { UseSubmitApplicationRequest, UseSubmitApplicationResponse } from "./api"; -export { ApplicationsQueryKeys, applicationsApi } from "./api"; -export { default as useGetApplicationsList } from "./getApplicants"; -export { default as useGetCompetitors } from "./getCompetitors"; -export { default as usePostSubmitApplication } from "./postSubmitApplication"; +export { applicationsApi } from './api'; +export { default as getApplicants } from './getApplicants'; +export { default as getCompetitors } from './getCompetitors'; +export { default as index } from './index'; +export { default as postSubmitApplication } from './postSubmitApplication'; diff --git a/src/apis/applications/legacy/getApplicants.CHANGES.md b/src/apis/applications/legacy/getApplicants.CHANGES.md new file mode 100644 index 00000000..2be681f9 --- /dev/null +++ b/src/apis/applications/legacy/getApplicants.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getApplicants.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/applications +- Method: GET +- Function: getApplicants + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `ApplicationsQueryKeys.competitorsApplicationList` +- 현재: `QueryKeys.applications.getApplicants, URL, params` + +## 권장 조치 + +1. `legacy/getApplicants.ts` 파일의 비즈니스 로직 확인 +2. 새 `getApplicants.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getApplicants.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/applications/legacy/getApplicants.ts b/src/apis/applications/legacy/getApplicants.ts new file mode 100644 index 00000000..f7da9024 --- /dev/null +++ b/src/apis/applications/legacy/getApplicants.ts @@ -0,0 +1,27 @@ +import { type UseQueryOptions, type UseQueryResult, useQuery } from "@tanstack/react-query"; +import type { AxiosError, AxiosResponse } from "axios"; + +import type { ApplicationListResponse } from "@/types/application"; +import { ApplicationsQueryKeys, applicationsApi } from "./api"; + +type UseGetApplicationsListOptions = Omit< + UseQueryOptions, AxiosError<{ message: string }>, ApplicationListResponse>, + "queryKey" | "queryFn" +>; + +/** + * @description 지원 목록 조회 훅 + */ +const useGetApplicationsList = ( + props?: UseGetApplicationsListOptions, +): UseQueryResult> => { + return useQuery({ + queryKey: [ApplicationsQueryKeys.competitorsApplicationList], + queryFn: applicationsApi.getApplicationsList, + staleTime: 1000 * 60 * 5, // 5분간 캐시 + select: (response) => response.data, + ...props, + }); +}; + +export default useGetApplicationsList; diff --git a/src/apis/applications/legacy/getCompetitors.CHANGES.md b/src/apis/applications/legacy/getCompetitors.CHANGES.md new file mode 100644 index 00000000..9ecbf69e --- /dev/null +++ b/src/apis/applications/legacy/getCompetitors.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getCompetitors.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/applications/competitors +- Method: GET +- Function: getCompetitors + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.applications.competitors, params` +- 현재: `QueryKeys.applications.getCompetitors, URL, params` + +## 권장 조치 + +1. `legacy/getCompetitors.ts` 파일의 비즈니스 로직 확인 +2. 새 `getCompetitors.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getCompetitors.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/applications/legacy/getCompetitors.ts b/src/apis/applications/legacy/getCompetitors.ts new file mode 100644 index 00000000..e137b9bd --- /dev/null +++ b/src/apis/applications/legacy/getCompetitors.ts @@ -0,0 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { applicationsApi, type CompetitorsResponse } from "./api"; + +const useGetCompetitors = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.applications.competitors, params], + queryFn: () => applicationsApi.getCompetitors(params ? { params } : {}), + }); +}; + +export default useGetCompetitors; diff --git a/src/apis/applications/legacy/postSubmitApplication.CHANGES.md b/src/apis/applications/legacy/postSubmitApplication.CHANGES.md new file mode 100644 index 00000000..4a91691e --- /dev/null +++ b/src/apis/applications/legacy/postSubmitApplication.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postSubmitApplication.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/applications +- Method: POST +- Function: postSubmitApplication + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `AxiosResponse, + AxiosError<{ message: string }>, + UseSubmitApplicationRequest, + unknown + >, +): UseMutationResult< + AxiosResponse, + AxiosError<{ message: string }>, + UseSubmitApplicationRequest, + unknown +> => { + return useMutation< + AxiosResponse, + AxiosError<{ message: string }>, + UseSubmitApplicationRequest + >({ + ...props, + mutationFn: applicationsApi.postSubmitApplication, + onError: (error) => { + const errorMessage = error?.response?.data?.message; + toast.error(errorMessage || "지원 중 오류가 발생했습니다. 다시 시도해주세요."); + }, + }); +}; + +export default usePostSubmitApplication; diff --git a/src/apis/applications/postSubmitApplication.ts b/src/apis/applications/postSubmitApplication.ts index 4c8d374a..5434d6ee 100644 --- a/src/apis/applications/postSubmitApplication.ts +++ b/src/apis/applications/postSubmitApplication.ts @@ -1,37 +1,11 @@ -import { type UseMutationOptions, type UseMutationResult, useMutation } from "@tanstack/react-query"; -import type { AxiosError, AxiosResponse } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { applicationsApi, SubmitApplicationResponse, SubmitApplicationRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { applicationsApi, type UseSubmitApplicationRequest, type UseSubmitApplicationResponse } from "./api"; - -/** - * @description 지원 제출 훅 - */ -const usePostSubmitApplication = ( - props?: UseMutationOptions< - AxiosResponse, - AxiosError<{ message: string }>, - UseSubmitApplicationRequest, - unknown - >, -): UseMutationResult< - AxiosResponse, - AxiosError<{ message: string }>, - UseSubmitApplicationRequest, - unknown -> => { - return useMutation< - AxiosResponse, - AxiosError<{ message: string }>, - UseSubmitApplicationRequest - >({ - ...props, - mutationFn: applicationsApi.postSubmitApplication, - onError: (error) => { - const errorMessage = error?.response?.data?.message; - toast.error(errorMessage || "지원 중 오류가 발생했습니다. 다시 시도해주세요."); - }, +const usePostSubmitApplication = () => { + return useMutation({ + mutationFn: (data) => applicationsApi.postSubmitApplication({ data }), }); }; -export default usePostSubmitApplication; +export default usePostSubmitApplication; \ No newline at end of file diff --git a/src/apis/chat/api.ts b/src/apis/chat/api.ts index 1fa093d0..11da37af 100644 --- a/src/apis/chat/api.ts +++ b/src/apis/chat/api.ts @@ -1,55 +1,65 @@ -import type { AxiosResponse } from "axios"; -import type { ChatMessage, ChatPartner, ChatRoom } from "@/types/chat"; import { axiosInstance } from "@/utils/axiosInstance"; -// QueryKeys for chat domain -export const ChatQueryKeys = { - chatRooms: "chatRooms", - chatHistories: "chatHistories", - partnerInfo: "partnerInfo", -} as const; - -// Re-export types from @/types/chat -export type { ChatMessage, ChatRoom, ChatPartner }; +export interface ChatMessagesResponseContentItem { + id: number; + content: string; + senderId: number; + createdAt: string; + attachments: ChatMessagesResponseContentItemAttachmentsItem[]; +} -export interface ChatHistoriesResponse { - nextPageNumber: number; // 다음 페이지가 없다면 -1 - content: ChatMessage[]; +export interface ChatMessagesResponseContentItemAttachmentsItem { + id: number; + isImage: boolean; + url: string; + thumbnailUrl: string | null; + createdAt: string; } -export interface ChatRoomListResponse { - chatRooms: ChatRoom[]; +export interface ChatMessagesResponse { + nextPageNumber: number; + content: ChatMessagesResponseContentItem[]; } -interface GetChatHistoriesParams { - roomId: number; - size?: number; - page?: number; +export type ChatRoomsResponse = void; + +export type ReadChatRoomResponse = void; + +export type ReadChatRoomRequest = Record; + +export interface ChatPartnerResponse { + partnerId: number; + nickname: string; + profileUrl: string; } export const chatApi = { - getChatHistories: async ({ roomId, size = 20, page = 0 }: GetChatHistoriesParams): Promise => { - const res = await axiosInstance.get(`/chats/rooms/${roomId}`, { - params: { - size, - page, - }, - }); + getChatMessages: async (params: { roomId: string | number, defaultSize: string | number, defaultPage: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/chats/rooms/${params.roomId}?size=${params.defaultSize}&page=${params.defaultPage}`, { params: params?.params } + ); return res.data; }, - getChatRooms: async (): Promise => { - const res = await axiosInstance.get("/chats/rooms"); + getChatRooms: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/chats/rooms`, { params: params?.params } + ); return res.data; }, - putReadChatRoom: async (roomId: number): Promise => { - const response: AxiosResponse = await axiosInstance.put(`/chats/rooms/${roomId}/read`); - return response.data; + putReadChatRoom: async (params: { roomId: string | number, data?: ReadChatRoomRequest }): Promise => { + const res = await axiosInstance.put( + `/chats/rooms/${params.roomId}/read`, params?.data + ); + return res.data; }, - getChatPartner: async (roomId: number): Promise => { - const res = await axiosInstance.get(`/chats/rooms/${roomId}/partner`); + getChatPartner: async (params: { roomId: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/chats/rooms/${params.roomId}/partner`, { params: params?.params } + ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/chat/getChatMessages.ts b/src/apis/chat/getChatMessages.ts index 1b01ab23..2cf05b68 100644 --- a/src/apis/chat/getChatMessages.ts +++ b/src/apis/chat/getChatMessages.ts @@ -1,40 +1,14 @@ -import { useInfiniteQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type ChatHistoriesResponse, type ChatMessage, ChatQueryKeys, chatApi } from "./api"; +import { AxiosError } from "axios"; +import { useQuery } from "@tanstack/react-query"; +import { chatApi, ChatMessagesResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -/** - * @description 채팅 히스토리를 무한 스크롤로 가져오는 훅 - */ -const useGetChatHistories = (roomId: number, size: number = 20) => { - return useInfiniteQuery< - ChatHistoriesResponse, - AxiosError, - { - pages: ChatHistoriesResponse[]; - pageParams: number[]; - messages: ChatMessage[]; - }, - [string, number], - number - >({ - queryKey: [ChatQueryKeys.chatHistories, roomId], - queryFn: ({ pageParam = 0 }: { pageParam?: number }) => chatApi.getChatHistories({ roomId, size, page: pageParam }), - initialPageParam: 0, - getNextPageParam: (lastPage: ChatHistoriesResponse) => { - // nextPageNumber가 -1이면 더 이상 페이지가 없음 - return lastPage.nextPageNumber === -1 ? undefined : lastPage.nextPageNumber; - }, - staleTime: 1000 * 60 * 5, // 5분간 캐시 - enabled: !!roomId, // roomId가 있을 때만 쿼리 실행 - meta: { - disableGlobalLoading: true, // 전역 로딩 비활성화 - }, - select: (data) => ({ - pages: data.pages, - pageParams: data.pageParams, - messages: data.pages.flatMap((page) => page.content), - }), +const useGetChatMessages = (roomId: string | number, defaultSize: string | number, defaultPage: string | number, params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.chat.chatMessages, roomId, defaultSize, defaultPage, params], + queryFn: () => chatApi.getChatMessages({ roomId, defaultSize, defaultPage, params }), + enabled: !!roomId && !!defaultSize && !!defaultPage, }); }; -export default useGetChatHistories; +export default useGetChatMessages; \ No newline at end of file diff --git a/src/apis/chat/getChatPartner.ts b/src/apis/chat/getChatPartner.ts index 56be7d48..ab3ab0c0 100644 --- a/src/apis/chat/getChatPartner.ts +++ b/src/apis/chat/getChatPartner.ts @@ -1,17 +1,14 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type ChatPartner, ChatQueryKeys, chatApi } from "./api"; +import { chatApi, ChatPartnerResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -/** - * @description 채팅 상대방 정보를 가져오는 훅 - */ -const useGetPartnerInfo = (roomId: number) => { - return useQuery({ - queryKey: [ChatQueryKeys.partnerInfo, roomId], - queryFn: () => chatApi.getChatPartner(roomId), - staleTime: 1000 * 60 * 5, +const useGetChatPartner = (roomId: string | number, params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.chat.chatPartner, roomId, params], + queryFn: () => chatApi.getChatPartner({ roomId, params }), enabled: !!roomId, }); }; -export default useGetPartnerInfo; +export default useGetChatPartner; \ No newline at end of file diff --git a/src/apis/chat/getChatRooms.ts b/src/apis/chat/getChatRooms.ts index b96a43d2..b2c6c0c4 100644 --- a/src/apis/chat/getChatRooms.ts +++ b/src/apis/chat/getChatRooms.ts @@ -1,17 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { ChatQueryKeys, type ChatRoom, type ChatRoomListResponse, chatApi } from "./api"; +import { chatApi, ChatRoomsResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -/** - * @description 채팅방 목록을 가져오는 훅 - */ -const useGetChatRooms = () => { - return useQuery({ - queryKey: [ChatQueryKeys.chatRooms], - queryFn: chatApi.getChatRooms, - staleTime: 1000 * 60 * 5, // 5분간 캐시 - select: (data) => data.chatRooms, +const useGetChatRooms = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.chat.chatRooms, params], + queryFn: () => chatApi.getChatRooms(params ? { params } : {}), }); }; -export default useGetChatRooms; +export default useGetChatRooms; \ No newline at end of file diff --git a/src/apis/chat/index.ts b/src/apis/chat/index.ts index e1a190a4..6f80e4be 100644 --- a/src/apis/chat/index.ts +++ b/src/apis/chat/index.ts @@ -1,6 +1,6 @@ -export type { ChatHistoriesResponse, ChatMessage, ChatPartner, ChatRoom, ChatRoomListResponse } from "./api"; -export { ChatQueryKeys, chatApi } from "./api"; -export { default as useGetChatHistories } from "./getChatMessages"; -export { default as useGetPartnerInfo } from "./getChatPartner"; -export { default as useGetChatRooms } from "./getChatRooms"; -export { default as usePutChatRead } from "./putReadChatRoom"; +export { chatApi } from './api'; +export { default as getChatMessages } from './getChatMessages'; +export { default as getChatPartner } from './getChatPartner'; +export { default as getChatRooms } from './getChatRooms'; +export { default as index } from './index'; +export { default as putReadChatRoom } from './putReadChatRoom'; diff --git a/src/apis/chat/legacy/getChatMessages.CHANGES.md b/src/apis/chat/legacy/getChatMessages.CHANGES.md new file mode 100644 index 00000000..9d728a4d --- /dev/null +++ b/src/apis/chat/legacy/getChatMessages.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getChatMessages.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/chats/rooms/{{room-id}}?size={{default-size}}&page={{default-page}} +- Method: GET +- Function: getChatMessages + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `ChatHistoriesResponse` +- 현재: `ChatMessagesResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `ChatQueryKeys.chatHistories, roomId` +- 현재: `QueryKeys.chat.getChatMessages, URL, params` + +## 권장 조치 + +1. `legacy/getChatMessages.ts` 파일의 비즈니스 로직 확인 +2. 새 `getChatMessages.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getChatMessages.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/chat/legacy/getChatMessages.ts b/src/apis/chat/legacy/getChatMessages.ts new file mode 100644 index 00000000..1b01ab23 --- /dev/null +++ b/src/apis/chat/legacy/getChatMessages.ts @@ -0,0 +1,40 @@ +import { useInfiniteQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type ChatHistoriesResponse, type ChatMessage, ChatQueryKeys, chatApi } from "./api"; + +/** + * @description 채팅 히스토리를 무한 스크롤로 가져오는 훅 + */ +const useGetChatHistories = (roomId: number, size: number = 20) => { + return useInfiniteQuery< + ChatHistoriesResponse, + AxiosError, + { + pages: ChatHistoriesResponse[]; + pageParams: number[]; + messages: ChatMessage[]; + }, + [string, number], + number + >({ + queryKey: [ChatQueryKeys.chatHistories, roomId], + queryFn: ({ pageParam = 0 }: { pageParam?: number }) => chatApi.getChatHistories({ roomId, size, page: pageParam }), + initialPageParam: 0, + getNextPageParam: (lastPage: ChatHistoriesResponse) => { + // nextPageNumber가 -1이면 더 이상 페이지가 없음 + return lastPage.nextPageNumber === -1 ? undefined : lastPage.nextPageNumber; + }, + staleTime: 1000 * 60 * 5, // 5분간 캐시 + enabled: !!roomId, // roomId가 있을 때만 쿼리 실행 + meta: { + disableGlobalLoading: true, // 전역 로딩 비활성화 + }, + select: (data) => ({ + pages: data.pages, + pageParams: data.pageParams, + messages: data.pages.flatMap((page) => page.content), + }), + }); +}; + +export default useGetChatHistories; diff --git a/src/apis/chat/legacy/getChatPartner.CHANGES.md b/src/apis/chat/legacy/getChatPartner.CHANGES.md new file mode 100644 index 00000000..0127a740 --- /dev/null +++ b/src/apis/chat/legacy/getChatPartner.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getChatPartner.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/chats/rooms/{{room-id}}/partner +- Method: GET +- Function: getChatPartner + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `ChatPartner` +- 현재: `ChatPartnerResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `ChatQueryKeys.partnerInfo, roomId` +- 현재: `QueryKeys.chat.getChatPartner, URL, params` + +## 권장 조치 + +1. `legacy/getChatPartner.ts` 파일의 비즈니스 로직 확인 +2. 새 `getChatPartner.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getChatPartner.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/chat/legacy/getChatPartner.ts b/src/apis/chat/legacy/getChatPartner.ts new file mode 100644 index 00000000..56be7d48 --- /dev/null +++ b/src/apis/chat/legacy/getChatPartner.ts @@ -0,0 +1,17 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type ChatPartner, ChatQueryKeys, chatApi } from "./api"; + +/** + * @description 채팅 상대방 정보를 가져오는 훅 + */ +const useGetPartnerInfo = (roomId: number) => { + return useQuery({ + queryKey: [ChatQueryKeys.partnerInfo, roomId], + queryFn: () => chatApi.getChatPartner(roomId), + staleTime: 1000 * 60 * 5, + enabled: !!roomId, + }); +}; + +export default useGetPartnerInfo; diff --git a/src/apis/chat/legacy/getChatRooms.CHANGES.md b/src/apis/chat/legacy/getChatRooms.CHANGES.md new file mode 100644 index 00000000..cb61ead2 --- /dev/null +++ b/src/apis/chat/legacy/getChatRooms.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getChatRooms.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/chats/rooms +- Method: GET +- Function: getChatRooms + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `ChatRoomListResponse` +- 현재: `ChatRoomsResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `ChatQueryKeys.chatRooms` +- 현재: `QueryKeys.chat.getChatRooms, URL, params` + +## 권장 조치 + +1. `legacy/getChatRooms.ts` 파일의 비즈니스 로직 확인 +2. 새 `getChatRooms.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getChatRooms.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/chat/legacy/getChatRooms.ts b/src/apis/chat/legacy/getChatRooms.ts new file mode 100644 index 00000000..b96a43d2 --- /dev/null +++ b/src/apis/chat/legacy/getChatRooms.ts @@ -0,0 +1,17 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { ChatQueryKeys, type ChatRoom, type ChatRoomListResponse, chatApi } from "./api"; + +/** + * @description 채팅방 목록을 가져오는 훅 + */ +const useGetChatRooms = () => { + return useQuery({ + queryKey: [ChatQueryKeys.chatRooms], + queryFn: chatApi.getChatRooms, + staleTime: 1000 * 60 * 5, // 5분간 캐시 + select: (data) => data.chatRooms, + }); +}; + +export default useGetChatRooms; diff --git a/src/apis/chat/legacy/putReadChatRoom.CHANGES.md b/src/apis/chat/legacy/putReadChatRoom.CHANGES.md new file mode 100644 index 00000000..0e7f52b9 --- /dev/null +++ b/src/apis/chat/legacy/putReadChatRoom.CHANGES.md @@ -0,0 +1,39 @@ +# 변경사항: putReadChatRoom.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/chats/rooms/{{room-id}}/read +- Method: PUT +- Function: putReadChatRoom + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `void` +- 현재: `ReadChatRoomResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `number` +- 현재: `ReadChatRoomRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `ChatQueryKeys.chatRooms` +- 현재: `QueryKeys.chat.putReadChatRoom, URL, params` + +## 권장 조치 + +1. `legacy/putReadChatRoom.ts` 파일의 비즈니스 로직 확인 +2. 새 `putReadChatRoom.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/putReadChatRoom.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/chat/legacy/putReadChatRoom.ts b/src/apis/chat/legacy/putReadChatRoom.ts new file mode 100644 index 00000000..3aea8922 --- /dev/null +++ b/src/apis/chat/legacy/putReadChatRoom.ts @@ -0,0 +1,23 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { ChatQueryKeys, chatApi } from "./api"; + +/** + * @description 채팅방 읽음 처리 훅 + */ +const usePutChatRead = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: chatApi.putReadChatRoom, + onSuccess: () => { + // 채팅방 목록 쿼리를 무효화하여 새로 고침 + queryClient.invalidateQueries({ queryKey: [ChatQueryKeys.chatRooms] }); + }, + onError: (error) => { + console.error("채팅방 진입 읽기 실패", error); + }, + }); +}; + +export default usePutChatRead; diff --git a/src/apis/chat/putReadChatRoom.ts b/src/apis/chat/putReadChatRoom.ts index 3aea8922..02af78df 100644 --- a/src/apis/chat/putReadChatRoom.ts +++ b/src/apis/chat/putReadChatRoom.ts @@ -1,23 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { ChatQueryKeys, chatApi } from "./api"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { chatApi, ReadChatRoomResponse, ReadChatRoomRequest } from "./api"; -/** - * @description 채팅방 읽음 처리 훅 - */ -const usePutChatRead = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: chatApi.putReadChatRoom, - onSuccess: () => { - // 채팅방 목록 쿼리를 무효화하여 새로 고침 - queryClient.invalidateQueries({ queryKey: [ChatQueryKeys.chatRooms] }); - }, - onError: (error) => { - console.error("채팅방 진입 읽기 실패", error); - }, +const usePutReadChatRoom = () => { + return useMutation({ + mutationFn: (variables) => chatApi.putReadChatRoom(variables), }); }; -export default usePutChatRead; +export default usePutReadChatRoom; \ No newline at end of file diff --git a/src/apis/community/api.ts b/src/apis/community/api.ts index 0ffc27fb..52eaec57 100644 --- a/src/apis/community/api.ts +++ b/src/apis/community/api.ts @@ -1,21 +1,4 @@ -import type { AxiosResponse } from "axios"; -import type { - CommentCreateRequest, - CommentIdResponse, - ListPost, - Post, - PostCreateRequest, - PostIdResponse, - PostLikeResponse, - PostUpdateRequest, -} from "@/types/community"; -import { axiosInstance, publicAxiosInstance } from "@/utils/axiosInstance"; - -// QueryKeys for community domain -export const CommunityQueryKeys = { - posts: "posts", - postList: "postList1", // 기존 api/boards와 동일한 키 유지 -} as const; +import { axiosInstance } from "@/utils/axiosInstance"; export interface BoardListResponse { 0: string; @@ -37,116 +20,178 @@ export interface BoardResponseItem { } export interface BoardResponse { - 0: BoardResponseItem[]; - 1: BoardResponseItem[]; - 2: BoardResponseItem[]; - 3: BoardResponseItem[]; -} - -// Delete response types -export interface DeletePostResponse { - message: string; - postId: number; -} - -// Re-export types from @/types/community for convenience -export type { - Post, - PostCreateRequest, - PostIdResponse, - PostUpdateRequest, - PostLikeResponse, - CommentCreateRequest, - CommentIdResponse, - ListPost, -}; + 0: BoardResponse0; + 1: BoardResponse1; + 2: BoardResponse2; + 3: BoardResponse3; +} -export const communityApi = { - /** - * 게시글 목록 조회 (클라이언트) - */ - getPostList: (boardCode: string, category: string | null = null): Promise> => { - const params = category && category !== "전체" ? { category } : {}; - return publicAxiosInstance.get(`/boards/${boardCode}`, { params }); - }, +export interface CommentResponse { + id: number; +} + +export interface UpdateCommentResponse { + id: number; +} + +export type UpdateCommentRequest = Record; + +export interface CreateCommentResponse { + id: number; +} + +export type CreateCommentRequest = Record; + +export interface PostResponse { + id: number; +} + +export interface UpdatePostResponse { + id: number; +} + +export type UpdatePostRequest = Record; + +export interface CreatePostResponse { + id: number; +} + +export type CreatePostRequest = Record; + +export interface PostDetailResponsePostFindPostImageResponsesItem { + id: number; + imageUrl: string; +} + +export interface PostDetailResponsePostFindCommentResponsesItem { + id: number; + parentId: null | number; + content: string; + isOwner: boolean; + createdAt: string; + updatedAt: string; + postFindSiteUserResponse: PostDetailResponsePostFindCommentResponsesItemPostFindSiteUserResponse; +} + +export interface PostDetailResponsePostFindCommentResponsesItemPostFindSiteUserResponse { + id: number; + nickname: string; + profileImageUrl: string; +} + +export interface PostDetailResponsePostFindSiteUserResponse { + id: number; + nickname: string; + profileImageUrl: string; +} - getBoardList: async (params?: Record): Promise => { - const res = await axiosInstance.get(`/boards`, { params }); +export interface PostDetailResponsePostFindBoardResponse { + code: string; + koreanName: string; +} + +export interface PostDetailResponse { + id: number; + title: string; + content: string; + isQuestion: boolean; + likeCount: number; + viewCount: number; + commentCount: number; + postCategory: string; + isOwner: boolean; + isLiked: boolean; + createdAt: string; + updatedAt: string; + postFindBoardResponse: PostDetailResponsePostFindBoardResponse; + postFindSiteUserResponse: PostDetailResponsePostFindSiteUserResponse; + postFindCommentResponses: PostDetailResponsePostFindCommentResponsesItem[]; + postFindPostImageResponses: PostDetailResponsePostFindPostImageResponsesItem[]; +} + +export interface LikePostResponse { + likeCount: number; + isLiked: boolean; +} + +export type LikePostRequest = Record; + +export const communityApi = { + getBoardList: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/boards`, { params: params?.params } + ); return res.data; }, - getBoard: async (boardCode: string, params?: Record): Promise => { - const res = await axiosInstance.get(`/boards/${boardCode}`, { params }); + getBoard: async (params: { boardCode: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/boards/${params.boardCode}`, { params: params?.params } + ); return res.data; }, - getPostDetail: async (postId: number): Promise => { - const response: AxiosResponse = await axiosInstance.get(`/posts/${postId}`); - return response.data; + deleteComment: async (params: { commentId: string | number }): Promise => { + const res = await axiosInstance.delete( + `/comments/${params.commentId}` + ); + return res.data; }, - createPost: async (request: PostCreateRequest): Promise => { - const convertedRequest: FormData = new FormData(); - convertedRequest.append( - "postCreateRequest", - new Blob([JSON.stringify(request.postCreateRequest)], { type: "application/json" }), + patchUpdateComment: async (params: { commentId: string | number, data?: UpdateCommentRequest }): Promise => { + const res = await axiosInstance.patch( + `/comments/${params.commentId}`, params?.data ); - request.file.forEach((file) => { - convertedRequest.append("file", file); - }); - - const response: AxiosResponse = await axiosInstance.post(`/posts`, convertedRequest, { - headers: { "Content-Type": "multipart/form-data" }, - }); - - return { - ...response.data, - boardCode: request.postCreateRequest.boardCode, - }; + return res.data; }, - updatePost: async (postId: number, request: PostUpdateRequest): Promise => { - const convertedRequest: FormData = new FormData(); - convertedRequest.append( - "postUpdateRequest", - new Blob([JSON.stringify(request.postUpdateRequest)], { type: "application/json" }), + postCreateComment: async (params: { data?: CreateCommentRequest }): Promise => { + const res = await axiosInstance.post( + `/comments`, params?.data ); - request.file.forEach((file) => { - convertedRequest.append("file", file); - }); - - const response: AxiosResponse = await axiosInstance.patch(`/posts/${postId}`, convertedRequest, { - headers: { "Content-Type": "multipart/form-data" }, - }); - return response.data; + return res.data; }, - deletePost: async (postId: number): Promise> => { - return axiosInstance.delete(`/posts/${postId}`); + deletePost: async (params: { postId: string | number }): Promise => { + const res = await axiosInstance.delete( + `/posts/${params.postId}` + ); + return res.data; }, - likePost: async (postId: number): Promise => { - const response: AxiosResponse = await axiosInstance.post(`/posts/${postId}/like`); - return response.data; + patchUpdatePost: async (params: { postId: string | number, data?: UpdatePostRequest }): Promise => { + const res = await axiosInstance.patch( + `/posts/${params.postId}`, params?.data + ); + return res.data; }, - unlikePost: async (postId: number): Promise => { - const response: AxiosResponse = await axiosInstance.delete(`/posts/${postId}/like`); - return response.data; + postCreatePost: async (params: { data?: CreatePostRequest }): Promise => { + const res = await axiosInstance.post( + `/posts`, params?.data + ); + return res.data; }, - createComment: async (request: CommentCreateRequest): Promise => { - const response: AxiosResponse = await axiosInstance.post(`/comments`, request); - return response.data; + getPostDetail: async (params: { postId: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/posts/${params.postId}`, { params: params?.params } + ); + return res.data; }, - deleteComment: async (commentId: number): Promise => { - const response: AxiosResponse = await axiosInstance.delete(`/comments/${commentId}`); - return response.data; + postLikePost: async (params: { postId: string | number, data?: LikePostRequest }): Promise => { + const res = await axiosInstance.post( + `/posts/${params.postId}/like`, params?.data + ); + return res.data; }, - updateComment: async (commentId: number, data: { content: string }): Promise => { - const res = await axiosInstance.patch(`/comments/${commentId}`, data); + deleteLikePost: async (params: { postId: string | number }): Promise => { + const res = await axiosInstance.delete( + `/posts/${params.postId}/like` + ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/community/deleteComment.ts b/src/apis/community/deleteComment.ts index 77ca58ca..6bea8c7e 100644 --- a/src/apis/community/deleteComment.ts +++ b/src/apis/community/deleteComment.ts @@ -1,32 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { communityApi, CommentResponse, CommentRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { type CommentIdResponse, CommunityQueryKeys, communityApi } from "./api"; - -interface DeleteCommentRequest { - commentId: number; - postId: number; -} - -/** - * @description 댓글 삭제를 위한 useMutation 커스텀 훅 - */ const useDeleteComment = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: ({ commentId }) => communityApi.deleteComment(commentId), - onSuccess: (_data, variables) => { - // 해당 게시글 상세 쿼리를 무효화하여 댓글 목록 갱신 - queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, variables.postId] }); - toast.success("댓글이 삭제되었습니다."); - }, - onError: (error) => { - console.error("댓글 삭제 실패:", error); - toast.error("댓글 삭제에 실패했습니다."); - }, + return useMutation({ + mutationFn: (variables) => communityApi.deleteComment(variables), }); }; -export default useDeleteComment; +export default useDeleteComment; \ No newline at end of file diff --git a/src/apis/community/deleteLikePost.ts b/src/apis/community/deleteLikePost.ts index 0c6a81b6..63036f50 100644 --- a/src/apis/community/deleteLikePost.ts +++ b/src/apis/community/deleteLikePost.ts @@ -1,26 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { communityApi, LikePostResponse, LikePostRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { CommunityQueryKeys, communityApi, type PostLikeResponse } from "./api"; - -/** - * @description 게시글 좋아요 취소를 위한 useMutation 커스텀 훅 - */ -const useDeleteLike = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: communityApi.unlikePost, - onSuccess: (_data, postId) => { - // 해당 게시글 상세 쿼리를 무효화하여 최신 데이터 반영 - queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, postId] }); - }, - onError: (error) => { - console.error("게시글 좋아요 취소 실패:", error); - toast.error("좋아요 취소 처리에 실패했습니다."); - }, +const useDeleteLikePost = () => { + return useMutation({ + mutationFn: (variables) => communityApi.deleteLikePost(variables), }); }; -export default useDeleteLike; +export default useDeleteLikePost; \ No newline at end of file diff --git a/src/apis/community/deletePost.ts b/src/apis/community/deletePost.ts index a3307b17..1b194b65 100644 --- a/src/apis/community/deletePost.ts +++ b/src/apis/community/deletePost.ts @@ -1,35 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { communityApi, PostResponse, PostRequest } from "./api"; -import type { AxiosError, AxiosResponse } from "axios"; -import { useRouter } from "next/navigation"; - -import { toast } from "@/lib/zustand/useToastStore"; -import { CommunityQueryKeys, communityApi, type DeletePostResponse } from "./api"; - -/** - * @description 게시글 삭제를 위한 useMutation 커스텀 훅 - */ const useDeletePost = () => { - const router = useRouter(); - const queryClient = useQueryClient(); - - return useMutation, AxiosError, number>({ - mutationFn: communityApi.deletePost, - onSuccess: () => { - // 'posts' 쿼리 키를 가진 모든 쿼리를 무효화하여 - // 게시글 목록을 다시 불러오도록 합니다. - queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts] }); - - toast.success("게시글이 성공적으로 삭제되었습니다."); - - // 게시글 목록 페이지 이동 - router.replace("/community/FREE"); - }, - onError: (error) => { - console.error("게시글 삭제 실패:", error); - toast.error("게시글 삭제에 실패했습니다. 잠시 후 다시 시도해주세요."); - }, + return useMutation({ + mutationFn: (variables) => communityApi.deletePost(variables), }); }; -export default useDeletePost; +export default useDeletePost; \ No newline at end of file diff --git a/src/apis/community/getBoard.ts b/src/apis/community/getBoard.ts index 7e3174e5..1ea2869d 100644 --- a/src/apis/community/getBoard.ts +++ b/src/apis/community/getBoard.ts @@ -1,14 +1,14 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { communityApi, BoardResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type BoardResponse, communityApi } from "./api"; const useGetBoard = (boardCode: string | number, params?: Record) => { return useQuery({ queryKey: [QueryKeys.community.board, boardCode, params], - queryFn: () => communityApi.getBoard(boardCode as string, params), + queryFn: () => communityApi.getBoard({ boardCode, params }), enabled: !!boardCode, }); }; -export default useGetBoard; +export default useGetBoard; \ No newline at end of file diff --git a/src/apis/community/getBoardList.ts b/src/apis/community/getBoardList.ts index e1455822..bcb0d65b 100644 --- a/src/apis/community/getBoardList.ts +++ b/src/apis/community/getBoardList.ts @@ -1,7 +1,7 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { communityApi, BoardListResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type BoardListResponse, communityApi } from "./api"; const useGetBoardList = (params?: Record) => { return useQuery({ @@ -10,4 +10,4 @@ const useGetBoardList = (params?: Record) => { }); }; -export default useGetBoardList; +export default useGetBoardList; \ No newline at end of file diff --git a/src/apis/community/getPostDetail.ts b/src/apis/community/getPostDetail.ts index fcc71ef7..ba5cc61a 100644 --- a/src/apis/community/getPostDetail.ts +++ b/src/apis/community/getPostDetail.ts @@ -1,17 +1,14 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { CommunityQueryKeys, communityApi, type Post } from "./api"; +import { communityApi, PostDetailResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -/** - * @description 게시글 상세 조회를 위한 useQuery 커스텀 훅 - */ -const useGetPostDetail = (postId: number) => { - return useQuery({ - queryKey: [CommunityQueryKeys.posts, postId], - queryFn: () => communityApi.getPostDetail(postId), +const useGetPostDetail = (postId: string | number, params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.community.postDetail, postId, params], + queryFn: () => communityApi.getPostDetail({ postId, params }), enabled: !!postId, - meta: { showGlobalSpinner: false }, }); }; -export default useGetPostDetail; +export default useGetPostDetail; \ No newline at end of file diff --git a/src/apis/community/index.ts b/src/apis/community/index.ts index d396a31d..071824ed 100644 --- a/src/apis/community/index.ts +++ b/src/apis/community/index.ts @@ -1,26 +1,15 @@ -export type { - CommentCreateRequest, - CommentIdResponse, - ListPost, - Post, - PostCreateRequest, - PostIdResponse, - PostLikeResponse, - PostUpdateRequest, -} from "./api"; -export { CommunityQueryKeys, communityApi } from "./api"; -export { default as useDeleteComment } from "./deleteComment"; -export { default as useDeleteLike } from "./deleteLikePost"; -export { default as useDeletePost } from "./deletePost"; -export { default as useGetBoard } from "./getBoard"; -export { default as useGetBoardList } from "./getBoardList"; -export { default as useGetPostDetail } from "./getPostDetail"; -export { default as useGetPostList } from "./getPostList"; -export { default as usePatchUpdateComment } from "./patchUpdateComment"; -export { default as useUpdatePost } from "./patchUpdatePost"; -export { default as useCreateComment } from "./postCreateComment"; -export { default as useCreatePost } from "./postCreatePost"; -export { default as usePostLike } from "./postLikePost"; - -// Server-side functions -export { getPostListServer } from "./server"; +export { communityApi } from './api'; +export { default as deleteComment } from './deleteComment'; +export { default as deleteLikePost } from './deleteLikePost'; +export { default as deletePost } from './deletePost'; +export { default as getBoard } from './getBoard'; +export { default as getBoardList } from './getBoardList'; +export { default as getPostDetail } from './getPostDetail'; +export { default as getPostList } from './getPostList'; +export { default as index } from './index'; +export { default as patchUpdateComment } from './patchUpdateComment'; +export { default as patchUpdatePost } from './patchUpdatePost'; +export { default as postCreateComment } from './postCreateComment'; +export { default as postCreatePost } from './postCreatePost'; +export { default as postLikePost } from './postLikePost'; +export { default as server } from './server'; diff --git a/src/apis/community/legacy/deleteComment.CHANGES.md b/src/apis/community/legacy/deleteComment.CHANGES.md new file mode 100644 index 00000000..a772ebcb --- /dev/null +++ b/src/apis/community/legacy/deleteComment.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: deleteComment.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/comments/{{comment-id}} +- Method: DELETE +- Function: deleteComment + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `CommentIdResponse` +- 현재: `CommentResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `CommunityQueryKeys.posts, variables.postId` +- 현재: `QueryKeys.community.deleteComment, URL, params` + +## 권장 조치 + +1. `legacy/deleteComment.ts` 파일의 비즈니스 로직 확인 +2. 새 `deleteComment.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/deleteComment.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/deleteComment.ts b/src/apis/community/legacy/deleteComment.ts new file mode 100644 index 00000000..77ca58ca --- /dev/null +++ b/src/apis/community/legacy/deleteComment.ts @@ -0,0 +1,32 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { type CommentIdResponse, CommunityQueryKeys, communityApi } from "./api"; + +interface DeleteCommentRequest { + commentId: number; + postId: number; +} + +/** + * @description 댓글 삭제를 위한 useMutation 커스텀 훅 + */ +const useDeleteComment = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ commentId }) => communityApi.deleteComment(commentId), + onSuccess: (_data, variables) => { + // 해당 게시글 상세 쿼리를 무효화하여 댓글 목록 갱신 + queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, variables.postId] }); + toast.success("댓글이 삭제되었습니다."); + }, + onError: (error) => { + console.error("댓글 삭제 실패:", error); + toast.error("댓글 삭제에 실패했습니다."); + }, + }); +}; + +export default useDeleteComment; diff --git a/src/apis/community/legacy/deleteLikePost.CHANGES.md b/src/apis/community/legacy/deleteLikePost.CHANGES.md new file mode 100644 index 00000000..da45a6bc --- /dev/null +++ b/src/apis/community/legacy/deleteLikePost.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: deleteLikePost.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/posts/{{post-id}}/like +- Method: DELETE +- Function: deleteLikePost + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `PostLikeResponse` +- 현재: `LikePostResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `CommunityQueryKeys.posts, postId` +- 현재: `QueryKeys.community.deleteLikePost, URL, params` + +## 권장 조치 + +1. `legacy/deleteLikePost.ts` 파일의 비즈니스 로직 확인 +2. 새 `deleteLikePost.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/deleteLikePost.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/deleteLikePost.ts b/src/apis/community/legacy/deleteLikePost.ts new file mode 100644 index 00000000..0c6a81b6 --- /dev/null +++ b/src/apis/community/legacy/deleteLikePost.ts @@ -0,0 +1,26 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { CommunityQueryKeys, communityApi, type PostLikeResponse } from "./api"; + +/** + * @description 게시글 좋아요 취소를 위한 useMutation 커스텀 훅 + */ +const useDeleteLike = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: communityApi.unlikePost, + onSuccess: (_data, postId) => { + // 해당 게시글 상세 쿼리를 무효화하여 최신 데이터 반영 + queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, postId] }); + }, + onError: (error) => { + console.error("게시글 좋아요 취소 실패:", error); + toast.error("좋아요 취소 처리에 실패했습니다."); + }, + }); +}; + +export default useDeleteLike; diff --git a/src/apis/community/legacy/deletePost.CHANGES.md b/src/apis/community/legacy/deletePost.CHANGES.md new file mode 100644 index 00000000..64e899ff --- /dev/null +++ b/src/apis/community/legacy/deletePost.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: deletePost.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/posts/{{post-id}} +- Method: DELETE +- Function: deletePost + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `AxiosResponse { + const router = useRouter(); + const queryClient = useQueryClient(); + + return useMutation, AxiosError, number>({ + mutationFn: communityApi.deletePost, + onSuccess: () => { + // 'posts' 쿼리 키를 가진 모든 쿼리를 무효화하여 + // 게시글 목록을 다시 불러오도록 합니다. + queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts] }); + + toast.success("게시글이 성공적으로 삭제되었습니다."); + + // 게시글 목록 페이지 이동 + router.replace("/community/FREE"); + }, + onError: (error) => { + console.error("게시글 삭제 실패:", error); + toast.error("게시글 삭제에 실패했습니다. 잠시 후 다시 시도해주세요."); + }, + }); +}; + +export default useDeletePost; diff --git a/src/apis/community/legacy/getBoard.CHANGES.md b/src/apis/community/legacy/getBoard.CHANGES.md new file mode 100644 index 00000000..4e9426c8 --- /dev/null +++ b/src/apis/community/legacy/getBoard.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getBoard.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/boards/{{board-code}} +- Method: GET +- Function: getBoard + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.community.board, boardCode, params` +- 현재: `QueryKeys.community.getBoard, URL, params` + +## 권장 조치 + +1. `legacy/getBoard.ts` 파일의 비즈니스 로직 확인 +2. 새 `getBoard.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getBoard.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/getBoard.ts b/src/apis/community/legacy/getBoard.ts new file mode 100644 index 00000000..7e3174e5 --- /dev/null +++ b/src/apis/community/legacy/getBoard.ts @@ -0,0 +1,14 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type BoardResponse, communityApi } from "./api"; + +const useGetBoard = (boardCode: string | number, params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.community.board, boardCode, params], + queryFn: () => communityApi.getBoard(boardCode as string, params), + enabled: !!boardCode, + }); +}; + +export default useGetBoard; diff --git a/src/apis/community/legacy/getBoardList.CHANGES.md b/src/apis/community/legacy/getBoardList.CHANGES.md new file mode 100644 index 00000000..0ee019e5 --- /dev/null +++ b/src/apis/community/legacy/getBoardList.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getBoardList.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/boards +- Method: GET +- Function: getBoardList + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.community.boardList, params` +- 현재: `QueryKeys.community.getBoardList, URL, params` + +## 권장 조치 + +1. `legacy/getBoardList.ts` 파일의 비즈니스 로직 확인 +2. 새 `getBoardList.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getBoardList.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/getBoardList.ts b/src/apis/community/legacy/getBoardList.ts new file mode 100644 index 00000000..e1455822 --- /dev/null +++ b/src/apis/community/legacy/getBoardList.ts @@ -0,0 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type BoardListResponse, communityApi } from "./api"; + +const useGetBoardList = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.community.boardList, params], + queryFn: () => communityApi.getBoardList(params ? { params } : {}), + }); +}; + +export default useGetBoardList; diff --git a/src/apis/community/legacy/getPostDetail.CHANGES.md b/src/apis/community/legacy/getPostDetail.CHANGES.md new file mode 100644 index 00000000..5da75ebc --- /dev/null +++ b/src/apis/community/legacy/getPostDetail.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getPostDetail.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/posts/{{post-id}} +- Method: GET +- Function: getPostDetail + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `Post` +- 현재: `PostDetailResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `CommunityQueryKeys.posts, postId` +- 현재: `QueryKeys.community.getPostDetail, URL, params` + +## 권장 조치 + +1. `legacy/getPostDetail.ts` 파일의 비즈니스 로직 확인 +2. 새 `getPostDetail.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getPostDetail.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/getPostDetail.ts b/src/apis/community/legacy/getPostDetail.ts new file mode 100644 index 00000000..fcc71ef7 --- /dev/null +++ b/src/apis/community/legacy/getPostDetail.ts @@ -0,0 +1,17 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { CommunityQueryKeys, communityApi, type Post } from "./api"; + +/** + * @description 게시글 상세 조회를 위한 useQuery 커스텀 훅 + */ +const useGetPostDetail = (postId: number) => { + return useQuery({ + queryKey: [CommunityQueryKeys.posts, postId], + queryFn: () => communityApi.getPostDetail(postId), + enabled: !!postId, + meta: { showGlobalSpinner: false }, + }); +}; + +export default useGetPostDetail; diff --git a/src/apis/community/legacy/patchUpdateComment.CHANGES.md b/src/apis/community/legacy/patchUpdateComment.CHANGES.md new file mode 100644 index 00000000..d33c7c00 --- /dev/null +++ b/src/apis/community/legacy/patchUpdateComment.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: patchUpdateComment.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/comments/{{comment-id}} +- Method: PATCH +- Function: patchUpdateComment + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `CommentIdResponse` +- 현재: `UpdateCommentResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `{ commentId: number; content: string }` +- 현재: `UpdateCommentRequest` + +## 권장 조치 + +1. `legacy/patchUpdateComment.ts` 파일의 비즈니스 로직 확인 +2. 새 `patchUpdateComment.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/patchUpdateComment.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/patchUpdateComment.ts b/src/apis/community/legacy/patchUpdateComment.ts new file mode 100644 index 00000000..8b235b55 --- /dev/null +++ b/src/apis/community/legacy/patchUpdateComment.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type CommentIdResponse, communityApi } from "./api"; + +const usePatchUpdateComment = () => { + return useMutation({ + mutationFn: ({ commentId, content }) => communityApi.updateComment(commentId, { content }), + }); +}; + +export default usePatchUpdateComment; diff --git a/src/apis/community/legacy/patchUpdatePost.CHANGES.md b/src/apis/community/legacy/patchUpdatePost.CHANGES.md new file mode 100644 index 00000000..050b071e --- /dev/null +++ b/src/apis/community/legacy/patchUpdatePost.CHANGES.md @@ -0,0 +1,39 @@ +# 변경사항: patchUpdatePost.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/posts/{{post-id}} +- Method: PATCH +- Function: patchUpdatePost + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `PostIdResponse` +- 현재: `UpdatePostResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `UpdatePostVariables` +- 현재: `UpdatePostRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `CommunityQueryKeys.posts, variables.postId` +- 현재: `QueryKeys.community.patchUpdatePost, URL, params` + +## 권장 조치 + +1. `legacy/patchUpdatePost.ts` 파일의 비즈니스 로직 확인 +2. 새 `patchUpdatePost.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/patchUpdatePost.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/patchUpdatePost.ts b/src/apis/community/legacy/patchUpdatePost.ts new file mode 100644 index 00000000..ba2be8a0 --- /dev/null +++ b/src/apis/community/legacy/patchUpdatePost.ts @@ -0,0 +1,33 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { CommunityQueryKeys, communityApi, type PostIdResponse, type PostUpdateRequest } from "./api"; + +interface UpdatePostVariables { + postId: number; + data: PostUpdateRequest; +} + +/** + * @description 게시글 수정을 위한 useMutation 커스텀 훅 + */ +const useUpdatePost = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ postId, data }) => communityApi.updatePost(postId, data), + onSuccess: (_result, variables) => { + // 해당 게시글 상세 쿼리와 목록 쿼리를 무효화 + queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, variables.postId] }); + queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts] }); + toast.success("게시글이 수정되었습니다."); + }, + onError: (error) => { + console.error("게시글 수정 실패:", error); + toast.error("게시글 수정에 실패했습니다."); + }, + }); +}; + +export default useUpdatePost; diff --git a/src/apis/community/legacy/postCreateComment.CHANGES.md b/src/apis/community/legacy/postCreateComment.CHANGES.md new file mode 100644 index 00000000..defd01dd --- /dev/null +++ b/src/apis/community/legacy/postCreateComment.CHANGES.md @@ -0,0 +1,39 @@ +# 변경사항: postCreateComment.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/comments +- Method: POST +- Function: postCreateComment + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `CommentIdResponse` +- 현재: `CreateCommentResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `CommentCreateRequest` +- 현재: `CreateCommentRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `CommunityQueryKeys.posts, variables.postId` +- 현재: `QueryKeys.community.postCreateComment, URL, params` + +## 권장 조치 + +1. `legacy/postCreateComment.ts` 파일의 비즈니스 로직 확인 +2. 새 `postCreateComment.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postCreateComment.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/postCreateComment.ts b/src/apis/community/legacy/postCreateComment.ts new file mode 100644 index 00000000..2004f1a1 --- /dev/null +++ b/src/apis/community/legacy/postCreateComment.ts @@ -0,0 +1,27 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { type CommentCreateRequest, type CommentIdResponse, CommunityQueryKeys, communityApi } from "./api"; + +/** + * @description 댓글 생성을 위한 useMutation 커스텀 훅 + */ +const useCreateComment = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: communityApi.createComment, + onSuccess: (_data, variables) => { + // 해당 게시글 상세 쿼리를 무효화하여 댓글 목록 갱신 + queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, variables.postId] }); + toast.success("댓글이 등록되었습니다."); + }, + onError: (error) => { + console.error("댓글 생성 실패:", error); + toast.error("댓글 등록에 실패했습니다."); + }, + }); +}; + +export default useCreateComment; diff --git a/src/apis/community/legacy/postCreatePost.CHANGES.md b/src/apis/community/legacy/postCreatePost.CHANGES.md new file mode 100644 index 00000000..9384fe83 --- /dev/null +++ b/src/apis/community/legacy/postCreatePost.CHANGES.md @@ -0,0 +1,39 @@ +# 변경사항: postCreatePost.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/posts +- Method: POST +- Function: postCreatePost + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `PostIdResponse & { boardCode: string }` +- 현재: `CreatePostResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `PostCreateRequest` +- 현재: `CreatePostRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `CommunityQueryKeys.posts` +- 현재: `QueryKeys.community.postCreatePost, URL, params` + +## 권장 조치 + +1. `legacy/postCreatePost.ts` 파일의 비즈니스 로직 확인 +2. 새 `postCreatePost.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postCreatePost.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/postCreatePost.ts b/src/apis/community/legacy/postCreatePost.ts new file mode 100644 index 00000000..8a8d29ab --- /dev/null +++ b/src/apis/community/legacy/postCreatePost.ts @@ -0,0 +1,60 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import useAuthStore from "@/lib/zustand/useAuthStore"; +import { toast } from "@/lib/zustand/useToastStore"; +import { CommunityQueryKeys, communityApi, type PostCreateRequest, type PostIdResponse } from "./api"; + +/** + * @description ISR 페이지를 revalidate하는 함수 + * @param boardCode - 게시판 코드 + * @param accessToken - 사용자 인증 토큰 + */ +const revalidateCommunityPage = async (boardCode: string, accessToken: string) => { + try { + if (!accessToken) { + console.warn("Revalidation skipped: No access token available"); + return; + } + + await fetch("/api/revalidate", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${accessToken}`, + }, + body: JSON.stringify({ boardCode }), + }); + } catch (error) { + console.error("Revalidate failed:", error); + } +}; + +/** + * @description 게시글 생성을 위한 useMutation 커스텀 훅 + */ +const useCreatePost = () => { + const queryClient = useQueryClient(); + const { accessToken } = useAuthStore(); + + return useMutation({ + mutationFn: communityApi.createPost, + onSuccess: async (data) => { + // 게시글 목록 쿼리를 무효화하여 최신 목록 반영 + queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts] }); + + // ISR 페이지 revalidate (사용자 인증 토큰 사용) + if (accessToken) { + await revalidateCommunityPage(data.boardCode, accessToken); + } + + toast.success("게시글이 등록되었습니다."); + }, + onError: (error) => { + console.error("게시글 생성 실패:", error); + toast.error("게시글 등록에 실패했습니다."); + }, + }); +}; + +export default useCreatePost; diff --git a/src/apis/community/legacy/postLikePost.CHANGES.md b/src/apis/community/legacy/postLikePost.CHANGES.md new file mode 100644 index 00000000..ba0daa9b --- /dev/null +++ b/src/apis/community/legacy/postLikePost.CHANGES.md @@ -0,0 +1,39 @@ +# 변경사항: postLikePost.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/posts/{{post-id}}/like +- Method: POST +- Function: postLikePost + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `PostLikeResponse` +- 현재: `LikePostResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `number` +- 현재: `LikePostRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `CommunityQueryKeys.posts, postId` +- 현재: `QueryKeys.community.postLikePost, URL, params` + +## 권장 조치 + +1. `legacy/postLikePost.ts` 파일의 비즈니스 로직 확인 +2. 새 `postLikePost.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postLikePost.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/community/legacy/postLikePost.ts b/src/apis/community/legacy/postLikePost.ts new file mode 100644 index 00000000..a723c7dd --- /dev/null +++ b/src/apis/community/legacy/postLikePost.ts @@ -0,0 +1,26 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { CommunityQueryKeys, communityApi, type PostLikeResponse } from "./api"; + +/** + * @description 게시글 좋아요를 위한 useMutation 커스텀 훅 + */ +const usePostLike = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: communityApi.likePost, + onSuccess: (_data, postId) => { + // 해당 게시글 상세 쿼리를 무효화하여 최신 데이터 반영 + queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, postId] }); + }, + onError: (error) => { + console.error("게시글 좋아요 실패:", error); + toast.error("좋아요 처리에 실패했습니다."); + }, + }); +}; + +export default usePostLike; diff --git a/src/apis/community/patchUpdateComment.ts b/src/apis/community/patchUpdateComment.ts index 8b235b55..3a0fbfe6 100644 --- a/src/apis/community/patchUpdateComment.ts +++ b/src/apis/community/patchUpdateComment.ts @@ -1,11 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type CommentIdResponse, communityApi } from "./api"; +import { communityApi, UpdateCommentResponse, UpdateCommentRequest } from "./api"; const usePatchUpdateComment = () => { - return useMutation({ - mutationFn: ({ commentId, content }) => communityApi.updateComment(commentId, { content }), + return useMutation({ + mutationFn: (variables) => communityApi.patchUpdateComment(variables), }); }; -export default usePatchUpdateComment; +export default usePatchUpdateComment; \ No newline at end of file diff --git a/src/apis/community/patchUpdatePost.ts b/src/apis/community/patchUpdatePost.ts index ba2be8a0..acbdf578 100644 --- a/src/apis/community/patchUpdatePost.ts +++ b/src/apis/community/patchUpdatePost.ts @@ -1,33 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { communityApi, UpdatePostResponse, UpdatePostRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { CommunityQueryKeys, communityApi, type PostIdResponse, type PostUpdateRequest } from "./api"; - -interface UpdatePostVariables { - postId: number; - data: PostUpdateRequest; -} - -/** - * @description 게시글 수정을 위한 useMutation 커스텀 훅 - */ -const useUpdatePost = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: ({ postId, data }) => communityApi.updatePost(postId, data), - onSuccess: (_result, variables) => { - // 해당 게시글 상세 쿼리와 목록 쿼리를 무효화 - queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, variables.postId] }); - queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts] }); - toast.success("게시글이 수정되었습니다."); - }, - onError: (error) => { - console.error("게시글 수정 실패:", error); - toast.error("게시글 수정에 실패했습니다."); - }, +const usePatchUpdatePost = () => { + return useMutation({ + mutationFn: (variables) => communityApi.patchUpdatePost(variables), }); }; -export default useUpdatePost; +export default usePatchUpdatePost; \ No newline at end of file diff --git a/src/apis/community/postCreateComment.ts b/src/apis/community/postCreateComment.ts index 2004f1a1..215cd41e 100644 --- a/src/apis/community/postCreateComment.ts +++ b/src/apis/community/postCreateComment.ts @@ -1,27 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { communityApi, CreateCommentResponse, CreateCommentRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { type CommentCreateRequest, type CommentIdResponse, CommunityQueryKeys, communityApi } from "./api"; - -/** - * @description 댓글 생성을 위한 useMutation 커스텀 훅 - */ -const useCreateComment = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: communityApi.createComment, - onSuccess: (_data, variables) => { - // 해당 게시글 상세 쿼리를 무효화하여 댓글 목록 갱신 - queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, variables.postId] }); - toast.success("댓글이 등록되었습니다."); - }, - onError: (error) => { - console.error("댓글 생성 실패:", error); - toast.error("댓글 등록에 실패했습니다."); - }, +const usePostCreateComment = () => { + return useMutation({ + mutationFn: (data) => communityApi.postCreateComment({ data }), }); }; -export default useCreateComment; +export default usePostCreateComment; \ No newline at end of file diff --git a/src/apis/community/postCreatePost.ts b/src/apis/community/postCreatePost.ts index 8a8d29ab..e83b02c4 100644 --- a/src/apis/community/postCreatePost.ts +++ b/src/apis/community/postCreatePost.ts @@ -1,60 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { communityApi, CreatePostResponse, CreatePostRequest } from "./api"; -import useAuthStore from "@/lib/zustand/useAuthStore"; -import { toast } from "@/lib/zustand/useToastStore"; -import { CommunityQueryKeys, communityApi, type PostCreateRequest, type PostIdResponse } from "./api"; - -/** - * @description ISR 페이지를 revalidate하는 함수 - * @param boardCode - 게시판 코드 - * @param accessToken - 사용자 인증 토큰 - */ -const revalidateCommunityPage = async (boardCode: string, accessToken: string) => { - try { - if (!accessToken) { - console.warn("Revalidation skipped: No access token available"); - return; - } - - await fetch("/api/revalidate", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - }, - body: JSON.stringify({ boardCode }), - }); - } catch (error) { - console.error("Revalidate failed:", error); - } -}; - -/** - * @description 게시글 생성을 위한 useMutation 커스텀 훅 - */ -const useCreatePost = () => { - const queryClient = useQueryClient(); - const { accessToken } = useAuthStore(); - - return useMutation({ - mutationFn: communityApi.createPost, - onSuccess: async (data) => { - // 게시글 목록 쿼리를 무효화하여 최신 목록 반영 - queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts] }); - - // ISR 페이지 revalidate (사용자 인증 토큰 사용) - if (accessToken) { - await revalidateCommunityPage(data.boardCode, accessToken); - } - - toast.success("게시글이 등록되었습니다."); - }, - onError: (error) => { - console.error("게시글 생성 실패:", error); - toast.error("게시글 등록에 실패했습니다."); - }, +const usePostCreatePost = () => { + return useMutation({ + mutationFn: (data) => communityApi.postCreatePost({ data }), }); }; -export default useCreatePost; +export default usePostCreatePost; \ No newline at end of file diff --git a/src/apis/community/postLikePost.ts b/src/apis/community/postLikePost.ts index a723c7dd..f88f4c4c 100644 --- a/src/apis/community/postLikePost.ts +++ b/src/apis/community/postLikePost.ts @@ -1,26 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { communityApi, LikePostResponse, LikePostRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { CommunityQueryKeys, communityApi, type PostLikeResponse } from "./api"; - -/** - * @description 게시글 좋아요를 위한 useMutation 커스텀 훅 - */ -const usePostLike = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: communityApi.likePost, - onSuccess: (_data, postId) => { - // 해당 게시글 상세 쿼리를 무효화하여 최신 데이터 반영 - queryClient.invalidateQueries({ queryKey: [CommunityQueryKeys.posts, postId] }); - }, - onError: (error) => { - console.error("게시글 좋아요 실패:", error); - toast.error("좋아요 처리에 실패했습니다."); - }, +const usePostLikePost = () => { + return useMutation({ + mutationFn: (variables) => communityApi.postLikePost(variables), }); }; -export default usePostLike; +export default usePostLikePost; \ No newline at end of file diff --git a/src/apis/image-upload/api.ts b/src/apis/image-upload/api.ts index 932d1a69..a2024dda 100644 --- a/src/apis/image-upload/api.ts +++ b/src/apis/image-upload/api.ts @@ -1,81 +1,67 @@ -import type { AxiosResponse } from "axios"; -import type { FileResponse } from "@/types/file"; -import { axiosInstance, publicAxiosInstance } from "@/utils/axiosInstance"; +import { axiosInstance } from "@/utils/axiosInstance"; + +export type SlackNotificationResponse = void; -// ====== Types ====== -export type SlackNotificationResponse = undefined; export type SlackNotificationRequest = Record; export interface UploadLanguageTestReportResponse { fileUrl: string; } +export type UploadLanguageTestReportRequest = Record; + export interface UploadProfileImageResponse { fileUrl: string; } +export type UploadProfileImageRequest = Record; + +export interface UploadProfileImageBeforeSignupResponse { + fileUrl: string; +} + +export type UploadProfileImageBeforeSignupRequest = Record; + export interface UploadGpaReportResponse { fileUrl: string; } -// ====== API Functions ====== +export type UploadGpaReportRequest = Record; + export const imageUploadApi = { - /** - * 슬랙 알림 전송 - */ postSlackNotification: async (params: { data?: SlackNotificationRequest }): Promise => { const res = await axiosInstance.post( - `https://hooks.slack.com/services/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`, - params?.data, + `https://hooks.slack.com/services/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`, params?.data ); return res.data; }, - /** - * 어학 성적 증명서 업로드 - */ - postUploadLanguageTestReport: async (file: File): Promise => { - const formData = new FormData(); - formData.append("file", file); - const res = await axiosInstance.post(`/file/language-test`, formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); + postUploadLanguageTestReport: async (params: { data?: UploadLanguageTestReportRequest }): Promise => { + const res = await axiosInstance.post( + `/file/language-test`, params?.data + ); return res.data; }, - /** - * 프로필 이미지 업로드 (로그인 후) - */ - postUploadProfileImage: async (file: File): Promise => { - const formData = new FormData(); - formData.append("file", file); - const res = await axiosInstance.post(`/file/profile/post`, formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); + postUploadProfileImage: async (params: { data?: UploadProfileImageRequest }): Promise => { + const res = await axiosInstance.post( + `/file/profile/post`, params?.data + ); return res.data; }, - /** - * 프로필 이미지 업로드 (회원가입 전, 공개 API) - */ - postUploadProfileImageBeforeSignup: async (file: File): Promise => { - const formData = new FormData(); - formData.append("file", file); - const response: AxiosResponse = await publicAxiosInstance.post("/file/profile/pre", formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); - return response.data; + postUploadProfileImageBeforeSignup: async (params: { data?: UploadProfileImageBeforeSignupRequest }): Promise => { + const res = await axiosInstance.post( + `/file/profile/pre`, params?.data + ); + return res.data; }, - /** - * 학점 증명서 업로드 - */ - postUploadGpaReport: async (file: File): Promise => { - const formData = new FormData(); - formData.append("file", file); - const res = await axiosInstance.post(`/file/gpa`, formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); + postUploadGpaReport: async (params: { data?: UploadGpaReportRequest }): Promise => { + const res = await axiosInstance.post( + `/file/gpa`, params?.data + ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/image-upload/index.ts b/src/apis/image-upload/index.ts index d6ee6647..0316fc85 100644 --- a/src/apis/image-upload/index.ts +++ b/src/apis/image-upload/index.ts @@ -1,8 +1,7 @@ -export type { UploadGpaReportResponse, UploadLanguageTestReportResponse, UploadProfileImageResponse } from "./api"; -export { imageUploadApi } from "./api"; - -export { default as useSlackNotification } from "./postSlackNotification"; -export { default as useUploadGpaReport } from "./postUploadGpaReport"; -export { default as useUploadLanguageTestReport } from "./postUploadLanguageTestReport"; -export { default as useUploadProfileImage } from "./postUploadProfileImage"; -export { default as useUploadProfileImagePublic } from "./postUploadProfileImageBeforeSignup"; +export { imageUploadApi } from './api'; +export { default as index } from './index'; +export { default as postSlackNotification } from './postSlackNotification'; +export { default as postUploadGpaReport } from './postUploadGpaReport'; +export { default as postUploadLanguageTestReport } from './postUploadLanguageTestReport'; +export { default as postUploadProfileImage } from './postUploadProfileImage'; +export { default as postUploadProfileImageBeforeSignup } from './postUploadProfileImageBeforeSignup'; diff --git a/src/apis/image-upload/legacy/postSlackNotification.ts b/src/apis/image-upload/legacy/postSlackNotification.ts new file mode 100644 index 00000000..f4b397a8 --- /dev/null +++ b/src/apis/image-upload/legacy/postSlackNotification.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { imageUploadApi, type SlackNotificationRequest, type SlackNotificationResponse } from "./api"; + +const usePostSlackNotification = () => { + return useMutation({ + mutationFn: (data) => imageUploadApi.postSlackNotification({ data }), + }); +}; + +export default usePostSlackNotification; diff --git a/src/apis/image-upload/legacy/postUploadGpaReport.CHANGES.md b/src/apis/image-upload/legacy/postUploadGpaReport.CHANGES.md new file mode 100644 index 00000000..63ed7b53 --- /dev/null +++ b/src/apis/image-upload/legacy/postUploadGpaReport.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postUploadGpaReport.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/file/gpa +- Method: POST +- Function: postUploadGpaReport + +## 변경 내용 + +### request-type + +**Request 타입 변경** + +- 이전: `File` +- 현재: `UploadGpaReportRequest` + +## 권장 조치 + +1. `legacy/postUploadGpaReport.ts` 파일의 비즈니스 로직 확인 +2. 새 `postUploadGpaReport.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postUploadGpaReport.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/image-upload/legacy/postUploadGpaReport.ts b/src/apis/image-upload/legacy/postUploadGpaReport.ts new file mode 100644 index 00000000..f8ef7529 --- /dev/null +++ b/src/apis/image-upload/legacy/postUploadGpaReport.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { imageUploadApi, type UploadGpaReportResponse } from "./api"; + +const usePostUploadGpaReport = () => { + return useMutation({ + mutationFn: (file) => imageUploadApi.postUploadGpaReport(file), + }); +}; + +export default usePostUploadGpaReport; diff --git a/src/apis/image-upload/legacy/postUploadLanguageTestReport.CHANGES.md b/src/apis/image-upload/legacy/postUploadLanguageTestReport.CHANGES.md new file mode 100644 index 00000000..972a4745 --- /dev/null +++ b/src/apis/image-upload/legacy/postUploadLanguageTestReport.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postUploadLanguageTestReport.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/file/language-test +- Method: POST +- Function: postUploadLanguageTestReport + +## 변경 내용 + +### request-type + +**Request 타입 변경** + +- 이전: `File` +- 현재: `UploadLanguageTestReportRequest` + +## 권장 조치 + +1. `legacy/postUploadLanguageTestReport.ts` 파일의 비즈니스 로직 확인 +2. 새 `postUploadLanguageTestReport.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postUploadLanguageTestReport.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/image-upload/legacy/postUploadLanguageTestReport.ts b/src/apis/image-upload/legacy/postUploadLanguageTestReport.ts new file mode 100644 index 00000000..6a939941 --- /dev/null +++ b/src/apis/image-upload/legacy/postUploadLanguageTestReport.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { imageUploadApi, type UploadLanguageTestReportResponse } from "./api"; + +const usePostUploadLanguageTestReport = () => { + return useMutation({ + mutationFn: (file) => imageUploadApi.postUploadLanguageTestReport(file), + }); +}; + +export default usePostUploadLanguageTestReport; diff --git a/src/apis/image-upload/legacy/postUploadProfileImage.CHANGES.md b/src/apis/image-upload/legacy/postUploadProfileImage.CHANGES.md new file mode 100644 index 00000000..6b0346c2 --- /dev/null +++ b/src/apis/image-upload/legacy/postUploadProfileImage.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postUploadProfileImage.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/file/profile/post +- Method: POST +- Function: postUploadProfileImage + +## 변경 내용 + +### request-type + +**Request 타입 변경** + +- 이전: `File` +- 현재: `UploadProfileImageRequest` + +## 권장 조치 + +1. `legacy/postUploadProfileImage.ts` 파일의 비즈니스 로직 확인 +2. 새 `postUploadProfileImage.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postUploadProfileImage.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/image-upload/legacy/postUploadProfileImage.ts b/src/apis/image-upload/legacy/postUploadProfileImage.ts new file mode 100644 index 00000000..0b8e35a9 --- /dev/null +++ b/src/apis/image-upload/legacy/postUploadProfileImage.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { imageUploadApi, type UploadProfileImageResponse } from "./api"; + +const usePostUploadProfileImage = () => { + return useMutation({ + mutationFn: (file) => imageUploadApi.postUploadProfileImage(file), + }); +}; + +export default usePostUploadProfileImage; diff --git a/src/apis/image-upload/legacy/postUploadProfileImageBeforeSignup.CHANGES.md b/src/apis/image-upload/legacy/postUploadProfileImageBeforeSignup.CHANGES.md new file mode 100644 index 00000000..0c78a336 --- /dev/null +++ b/src/apis/image-upload/legacy/postUploadProfileImageBeforeSignup.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: postUploadProfileImageBeforeSignup.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/file/profile/pre +- Method: POST +- Function: postUploadProfileImageBeforeSignup + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `FileResponse` +- 현재: `UploadProfileImageBeforeSignupResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `File` +- 현재: `UploadProfileImageBeforeSignupRequest` + +## 권장 조치 + +1. `legacy/postUploadProfileImageBeforeSignup.ts` 파일의 비즈니스 로직 확인 +2. 새 `postUploadProfileImageBeforeSignup.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postUploadProfileImageBeforeSignup.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/image-upload/legacy/postUploadProfileImageBeforeSignup.ts b/src/apis/image-upload/legacy/postUploadProfileImageBeforeSignup.ts new file mode 100644 index 00000000..88eb117d --- /dev/null +++ b/src/apis/image-upload/legacy/postUploadProfileImageBeforeSignup.ts @@ -0,0 +1,20 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { toast } from "@/lib/zustand/useToastStore"; +import type { FileResponse } from "@/types/file"; +import { imageUploadApi } from "./api"; + +/** + * @description 프로필 이미지 업로드를 위한 useMutation 커스텀 훅 (회원가입 전 공개 API) + */ +const useUploadProfileImagePublic = () => { + return useMutation({ + mutationFn: imageUploadApi.postUploadProfileImageBeforeSignup, + onError: (error) => { + console.error("프로필 이미지 업로드 실패:", error); + toast.error("이미지 업로드에 실패했습니다."); + }, + }); +}; + +export default useUploadProfileImagePublic; diff --git a/src/apis/image-upload/postSlackNotification.ts b/src/apis/image-upload/postSlackNotification.ts index f4b397a8..c973ec12 100644 --- a/src/apis/image-upload/postSlackNotification.ts +++ b/src/apis/image-upload/postSlackNotification.ts @@ -1,6 +1,6 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { imageUploadApi, type SlackNotificationRequest, type SlackNotificationResponse } from "./api"; +import { imageUploadApi, SlackNotificationResponse, SlackNotificationRequest } from "./api"; const usePostSlackNotification = () => { return useMutation({ @@ -8,4 +8,4 @@ const usePostSlackNotification = () => { }); }; -export default usePostSlackNotification; +export default usePostSlackNotification; \ No newline at end of file diff --git a/src/apis/image-upload/postUploadGpaReport.ts b/src/apis/image-upload/postUploadGpaReport.ts index f8ef7529..06ed6ece 100644 --- a/src/apis/image-upload/postUploadGpaReport.ts +++ b/src/apis/image-upload/postUploadGpaReport.ts @@ -1,11 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { imageUploadApi, type UploadGpaReportResponse } from "./api"; +import { imageUploadApi, UploadGpaReportResponse, UploadGpaReportRequest } from "./api"; const usePostUploadGpaReport = () => { - return useMutation({ - mutationFn: (file) => imageUploadApi.postUploadGpaReport(file), + return useMutation({ + mutationFn: (data) => imageUploadApi.postUploadGpaReport({ data }), }); }; -export default usePostUploadGpaReport; +export default usePostUploadGpaReport; \ No newline at end of file diff --git a/src/apis/image-upload/postUploadLanguageTestReport.ts b/src/apis/image-upload/postUploadLanguageTestReport.ts index 6a939941..7b36f675 100644 --- a/src/apis/image-upload/postUploadLanguageTestReport.ts +++ b/src/apis/image-upload/postUploadLanguageTestReport.ts @@ -1,11 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { imageUploadApi, type UploadLanguageTestReportResponse } from "./api"; +import { imageUploadApi, UploadLanguageTestReportResponse, UploadLanguageTestReportRequest } from "./api"; const usePostUploadLanguageTestReport = () => { - return useMutation({ - mutationFn: (file) => imageUploadApi.postUploadLanguageTestReport(file), + return useMutation({ + mutationFn: (data) => imageUploadApi.postUploadLanguageTestReport({ data }), }); }; -export default usePostUploadLanguageTestReport; +export default usePostUploadLanguageTestReport; \ No newline at end of file diff --git a/src/apis/image-upload/postUploadProfileImage.ts b/src/apis/image-upload/postUploadProfileImage.ts index 0b8e35a9..72db4ae2 100644 --- a/src/apis/image-upload/postUploadProfileImage.ts +++ b/src/apis/image-upload/postUploadProfileImage.ts @@ -1,11 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { imageUploadApi, type UploadProfileImageResponse } from "./api"; +import { imageUploadApi, UploadProfileImageResponse, UploadProfileImageRequest } from "./api"; const usePostUploadProfileImage = () => { - return useMutation({ - mutationFn: (file) => imageUploadApi.postUploadProfileImage(file), + return useMutation({ + mutationFn: (data) => imageUploadApi.postUploadProfileImage({ data }), }); }; -export default usePostUploadProfileImage; +export default usePostUploadProfileImage; \ No newline at end of file diff --git a/src/apis/image-upload/postUploadProfileImageBeforeSignup.ts b/src/apis/image-upload/postUploadProfileImageBeforeSignup.ts index 88eb117d..edf2b95c 100644 --- a/src/apis/image-upload/postUploadProfileImageBeforeSignup.ts +++ b/src/apis/image-upload/postUploadProfileImageBeforeSignup.ts @@ -1,20 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { toast } from "@/lib/zustand/useToastStore"; -import type { FileResponse } from "@/types/file"; -import { imageUploadApi } from "./api"; +import { imageUploadApi, UploadProfileImageBeforeSignupResponse, UploadProfileImageBeforeSignupRequest } from "./api"; -/** - * @description 프로필 이미지 업로드를 위한 useMutation 커스텀 훅 (회원가입 전 공개 API) - */ -const useUploadProfileImagePublic = () => { - return useMutation({ - mutationFn: imageUploadApi.postUploadProfileImageBeforeSignup, - onError: (error) => { - console.error("프로필 이미지 업로드 실패:", error); - toast.error("이미지 업로드에 실패했습니다."); - }, +const usePostUploadProfileImageBeforeSignup = () => { + return useMutation({ + mutationFn: (data) => imageUploadApi.postUploadProfileImageBeforeSignup({ data }), }); }; -export default useUploadProfileImagePublic; +export default usePostUploadProfileImageBeforeSignup; \ No newline at end of file diff --git a/src/apis/kakao-api/api.ts b/src/apis/kakao-api/api.ts index 935a1bc6..51eda46d 100644 --- a/src/apis/kakao-api/api.ts +++ b/src/apis/kakao-api/api.ts @@ -1,34 +1,33 @@ import { axiosInstance } from "@/utils/axiosInstance"; -export type KakaoUserIdsResponse = undefined; +export type KakaoUserIdsResponse = void; -export type KakaoUnlinkResponse = undefined; +export type KakaoUnlinkResponse = void; export type KakaoUnlinkRequest = Record; -export type KakaoInfoResponse = undefined; +export type KakaoInfoResponse = void; export const kakaoApiApi = { getKakaoUserIds: async (params: { params?: Record }): Promise => { - const res = await axiosInstance.get(`https://kapi.kakao.com/v1/user/ids?order=dsc`, { - params: params?.params, - }); + const res = await axiosInstance.get( + `https://kapi.kakao.com/v1/user/ids?order=dsc`, { params: params?.params } + ); return res.data; }, postKakaoUnlink: async (params: { data?: KakaoUnlinkRequest }): Promise => { const res = await axiosInstance.post( - `https://kapi.kakao.com/v1/user/unlink?target_id_type=user_id&target_id=3715136239`, - params?.data, + `https://kapi.kakao.com/v1/user/unlink?target_id_type=user_id&target_id=3715136239`, params?.data ); return res.data; }, getKakaoInfo: async (params: { params?: Record }): Promise => { const res = await axiosInstance.get( - `https://kapi.kakao.com/v2/user/me?property_keys=["kakao_account.email"]&target_id_type=user_id&target_id=3715136239`, - { params: params?.params }, + `https://kapi.kakao.com/v2/user/me?property_keys=["kakao_account.email"]&target_id_type=user_id&target_id=3715136239`, { params: params?.params } ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/kakao-api/getKakaoInfo.ts b/src/apis/kakao-api/getKakaoInfo.ts index 2c5482dc..92c82449 100644 --- a/src/apis/kakao-api/getKakaoInfo.ts +++ b/src/apis/kakao-api/getKakaoInfo.ts @@ -1,13 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { kakaoApiApi, KakaoInfoResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type KakaoInfoResponse, kakaoApiApi } from "./api"; const useGetKakaoInfo = (params?: Record) => { return useQuery({ - queryKey: [QueryKeys["kakao-api"].kakaoInfo, params], + queryKey: [QueryKeys['kakao-api'].kakaoInfo, params], queryFn: () => kakaoApiApi.getKakaoInfo(params ? { params } : {}), }); }; -export default useGetKakaoInfo; +export default useGetKakaoInfo; \ No newline at end of file diff --git a/src/apis/kakao-api/getKakaoUserIds.ts b/src/apis/kakao-api/getKakaoUserIds.ts index 89159426..dc85cac5 100644 --- a/src/apis/kakao-api/getKakaoUserIds.ts +++ b/src/apis/kakao-api/getKakaoUserIds.ts @@ -1,13 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { kakaoApiApi, KakaoUserIdsResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type KakaoUserIdsResponse, kakaoApiApi } from "./api"; const useGetKakaoUserIds = (params?: Record) => { return useQuery({ - queryKey: [QueryKeys["kakao-api"].kakaoUserIds, params], + queryKey: [QueryKeys['kakao-api'].kakaoUserIds, params], queryFn: () => kakaoApiApi.getKakaoUserIds(params ? { params } : {}), }); }; -export default useGetKakaoUserIds; +export default useGetKakaoUserIds; \ No newline at end of file diff --git a/src/apis/kakao-api/index.ts b/src/apis/kakao-api/index.ts index 0acb2db7..1200da9b 100644 --- a/src/apis/kakao-api/index.ts +++ b/src/apis/kakao-api/index.ts @@ -1,4 +1,5 @@ -export { kakaoApiApi } from "./api"; -export { default as getKakaoInfo } from "./getKakaoInfo"; -export { default as getKakaoUserIds } from "./getKakaoUserIds"; -export { default as postKakaoUnlink } from "./postKakaoUnlink"; +export { kakaoApiApi } from './api'; +export { default as getKakaoInfo } from './getKakaoInfo'; +export { default as getKakaoUserIds } from './getKakaoUserIds'; +export { default as index } from './index'; +export { default as postKakaoUnlink } from './postKakaoUnlink'; diff --git a/src/apis/kakao-api/legacy/getKakaoInfo.CHANGES.md b/src/apis/kakao-api/legacy/getKakaoInfo.CHANGES.md new file mode 100644 index 00000000..29bccc2e --- /dev/null +++ b/src/apis/kakao-api/legacy/getKakaoInfo.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getKakaoInfo.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: https://kapi.kakao.com/v2/user/me?property_keys=["kakao_account.email"]&target_id_type=user_id&target_id=3715136239 +- Method: GET +- Function: getKakaoInfo + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys["kakao-api"` +- 현재: `QueryKeys.kakao-api.getKakaoInfo, params` + +## 권장 조치 + +1. `legacy/getKakaoInfo.ts` 파일의 비즈니스 로직 확인 +2. 새 `getKakaoInfo.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getKakaoInfo.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/kakao-api/legacy/getKakaoInfo.ts b/src/apis/kakao-api/legacy/getKakaoInfo.ts new file mode 100644 index 00000000..2c5482dc --- /dev/null +++ b/src/apis/kakao-api/legacy/getKakaoInfo.ts @@ -0,0 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type KakaoInfoResponse, kakaoApiApi } from "./api"; + +const useGetKakaoInfo = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys["kakao-api"].kakaoInfo, params], + queryFn: () => kakaoApiApi.getKakaoInfo(params ? { params } : {}), + }); +}; + +export default useGetKakaoInfo; diff --git a/src/apis/kakao-api/legacy/getKakaoUserIds.CHANGES.md b/src/apis/kakao-api/legacy/getKakaoUserIds.CHANGES.md new file mode 100644 index 00000000..1256b6e7 --- /dev/null +++ b/src/apis/kakao-api/legacy/getKakaoUserIds.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getKakaoUserIds.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: https://kapi.kakao.com/v1/user/ids?order=dsc +- Method: GET +- Function: getKakaoUserIds + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys["kakao-api"` +- 현재: `QueryKeys.kakao-api.getKakaoUserIds, params` + +## 권장 조치 + +1. `legacy/getKakaoUserIds.ts` 파일의 비즈니스 로직 확인 +2. 새 `getKakaoUserIds.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getKakaoUserIds.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/kakao-api/legacy/getKakaoUserIds.ts b/src/apis/kakao-api/legacy/getKakaoUserIds.ts new file mode 100644 index 00000000..89159426 --- /dev/null +++ b/src/apis/kakao-api/legacy/getKakaoUserIds.ts @@ -0,0 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type KakaoUserIdsResponse, kakaoApiApi } from "./api"; + +const useGetKakaoUserIds = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys["kakao-api"].kakaoUserIds, params], + queryFn: () => kakaoApiApi.getKakaoUserIds(params ? { params } : {}), + }); +}; + +export default useGetKakaoUserIds; diff --git a/src/apis/kakao-api/legacy/postKakaoUnlink.ts b/src/apis/kakao-api/legacy/postKakaoUnlink.ts new file mode 100644 index 00000000..35714879 --- /dev/null +++ b/src/apis/kakao-api/legacy/postKakaoUnlink.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type KakaoUnlinkRequest, type KakaoUnlinkResponse, kakaoApiApi } from "./api"; + +const usePostKakaoUnlink = () => { + return useMutation({ + mutationFn: (data) => kakaoApiApi.postKakaoUnlink({ data }), + }); +}; + +export default usePostKakaoUnlink; diff --git a/src/apis/kakao-api/postKakaoUnlink.ts b/src/apis/kakao-api/postKakaoUnlink.ts index 35714879..c20d19d0 100644 --- a/src/apis/kakao-api/postKakaoUnlink.ts +++ b/src/apis/kakao-api/postKakaoUnlink.ts @@ -1,6 +1,6 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type KakaoUnlinkRequest, type KakaoUnlinkResponse, kakaoApiApi } from "./api"; +import { kakaoApiApi, KakaoUnlinkResponse, KakaoUnlinkRequest } from "./api"; const usePostKakaoUnlink = () => { return useMutation({ @@ -8,4 +8,4 @@ const usePostKakaoUnlink = () => { }); }; -export default usePostKakaoUnlink; +export default usePostKakaoUnlink; \ No newline at end of file diff --git a/src/apis/mentor/api.ts b/src/apis/mentor/api.ts index d4069700..1a11d710 100644 --- a/src/apis/mentor/api.ts +++ b/src/apis/mentor/api.ts @@ -1,196 +1,230 @@ -import type { MentoringListItem, VerifyStatus } from "@/types/mentee"; -import { - type MentorCardDetail, - type MentorCardPreview, - MentoringApprovalStatus, - type MentoringItem, -} from "@/types/mentor"; import { axiosInstance } from "@/utils/axiosInstance"; -// QueryKeys for mentor domain -export const MentorQueryKeys = { - myMentorProfile: "myMentorProfile", - mentoringList: "mentoringList", - mentoringNewCount: "mentoringNewCount", - applyMentoringList: "applyMentoringList", - mentorList: "mentorList", - mentorDetail: "mentorDetail", -} as const; - -// Re-export types -export type { MentorCardPreview, MentorCardDetail, MentoringItem }; -export type { MentoringListItem, VerifyStatus }; -export { MentoringApprovalStatus }; - -// Response types -export interface MentoringListResponse { - content: MentoringItem[]; - nextPageNumber: number; +export interface MatchedMentorsResponseContentItem { + id: number; + roomId: number; + nickname: string; + profileImageUrl: string; + country: string; + universityName: string; + term: string; + menteeCount: number; + hasBadge: boolean; + introduction: string; + channels: MatchedMentorsResponseContentItemChannelsItem[]; + isApplied: boolean; } -export interface GetMentoringNewCountResponse { - uncheckedCount: number; +export interface MatchedMentorsResponseContentItemChannelsItem { + type: string; + url: string; } -export interface ApplyMentoringListResponse { - content: MentoringListItem[]; +export interface MatchedMentorsResponse { + content: MatchedMentorsResponseContentItem[]; nextPageNumber: number; } -export interface MentorListResponse { - nextPageNumber: number; - content: MentorCardDetail[]; +export interface ApplyMentoringResponse { + mentoringId: number; } -export interface MatchedMentorsResponse { - content: MentorCardDetail[]; - nextPageNumber: number; - totalElements: number; -} +export type ApplyMentoringRequest = Record; -export interface PatchApprovalStatusRequest { - status: MentoringApprovalStatus; - mentoringId: number; +export interface ConfirmMentoringResponse { + checkedMentoringIds: number[]; } -export interface PatchApprovalStatusResponse { +export type ConfirmMentoringRequest = Record; + +export interface AppliedMentoringsResponseContentItem { mentoringId: number; + profileImageUrl: null; + nickname: string; + isChecked: boolean; + createdAt: string; chatRoomId: number; } -export interface PatchCheckMentoringsRequest { - checkedMentoringIds: number[]; +export interface AppliedMentoringsResponse { + content: AppliedMentoringsResponseContentItem[]; + nextPageNumber: number; } -export interface PatchCheckMentoringsResponse { - checkedMentoringIds: number[]; +export interface MentorListResponseContentItem { + id: number; + profileImageUrl: string; + nickname: string; + country: string; + universityName: string; + term: string; + menteeCount: number; + hasBadge: boolean; + introduction: string; + channels: MentorListResponseContentItemChannelsItem[]; + isApplied: boolean; } -export interface PostApplyMentoringRequest { - mentorId: number; +export interface MentorListResponseContentItemChannelsItem { + type: string; + url: string; } -export interface PostApplyMentoringResponse { - mentoringId: number; +export interface MentorListResponse { + nextPageNumber: number; + content: MentorListResponseContentItem[]; } -export interface PostMentorApplicationRequest { - interestedCountries: string[]; +export interface MentorDetailResponseChannelsItem { + type: string; + url: string; +} + +export interface MentorDetailResponse { + id: number; + profileImageUrl: string; + nickname: string; country: string; universityName: string; - studyStatus: "STUDYING" | "PLANNING" | "COMPLETED"; - verificationFile: File; + term: string; + menteeCount: number; + hasBadge: boolean; + introduction: string; + channels: MentorDetailResponseChannelsItem[]; + passTip: string; + isApplied: boolean; } -export interface PutMyMentorProfileRequest { - channels: { type: string; url: string }[]; - passTip: string; +export interface MyMentorPageResponseChannelsItem { + type: string; + url: string; +} + +export interface MyMentorPageResponse { + id: number; + profileImageUrl: null; + nickname: string; + country: string; + universityName: string; + term: string; + menteeCount: number; + hasBadge: boolean; introduction: string; + passTip: string; + channels: MyMentorPageResponseChannelsItem[]; } -const OFFSET = 5; -const MENTORS_OFFSET = 10; -const MENTEE_OFFSET = 3; +export type UpdateMyMentorPageResponse = Record; -export const mentorApi = { - // === Mentor (멘토) APIs === - getMentorMyProfile: async (): Promise => { - const res = await axiosInstance.get("/mentor/my"); - return res.data; - }, +export type UpdateMyMentorPageRequest = Record; + +export interface MentoringStatusResponse { + mentoringId: number; +} - getMentoringList: async (page: number, size: number = OFFSET): Promise => { - const endpoint = `/mentor/mentorings?size=${size}&page=${page}`; - const res = await axiosInstance.get(endpoint); +export type MentoringStatusRequest = Record; + +export interface ReceivedMentoringsResponseContentItem { + mentoringId: number; + profileImageUrl: null; + nickname: string; + isChecked: boolean; + verifyStatus: string; + createdAt: string; +} + +export interface ReceivedMentoringsResponse { + content: ReceivedMentoringsResponseContentItem[]; + nextPageNumber: number; +} + +export interface UnconfirmedMentoringCountResponse { + uncheckedCount: number; +} + +export const mentorApi = { + getMatchedMentors: async (params: { defaultSize: string | number, defaultPage: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/mentee/mentorings/matched-mentors?size=${params.defaultSize}&page=${params.defaultPage}`, { params: params?.params } + ); return res.data; }, - getMentoringUncheckedCount: async (): Promise => { - const endpoint = "/mentor/mentorings/check"; - const res = await axiosInstance.get(endpoint); + postApplyMentoring: async (params: { data?: ApplyMentoringRequest }): Promise => { + const res = await axiosInstance.post( + `/mentee/mentorings`, params?.data + ); return res.data; }, - patchApprovalStatus: async (props: PatchApprovalStatusRequest): Promise => { - const { status, mentoringId } = props; - const res = await axiosInstance.patch(`/mentor/mentorings/${mentoringId}`, { - status, - }); + patchConfirmMentoring: async (params: { data?: ConfirmMentoringRequest }): Promise => { + const res = await axiosInstance.patch( + `/mentee/mentorings/check`, params?.data + ); return res.data; }, - patchMentorCheckMentorings: async (body: PatchCheckMentoringsRequest): Promise => { - const res = await axiosInstance.patch("/mentor/mentorings/check", body); + getAppliedMentorings: async (params: { verifyStatus: string | number, defaultSize: string | number, defaultPage: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/mentee/mentorings?verify-status=${params.verifyStatus}&size=${params.defaultSize}&page=${params.defaultPage}`, { params: params?.params } + ); return res.data; }, - postMentorApplication: async (body: PostMentorApplicationRequest): Promise => { - const formData = new FormData(); - const applicationData = { - interestedCountries: body.interestedCountries, - country: body.country, - universityName: body.universityName, - studyStatus: body.studyStatus, - }; - formData.append( - "mentorApplicationRequest", - new Blob([JSON.stringify(applicationData)], { type: "application/json" }), + getMentorList: async (params: { defaultSize: string | number, defaultPage: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/mentors?region=미주권&size=${params.defaultSize}&page=${params.defaultPage}`, { params: params?.params } ); - formData.append("file", body.verificationFile); - const res = await axiosInstance.post("/mentor/verification", formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); return res.data; }, - putMyMentorProfile: async (body: PutMyMentorProfileRequest): Promise => { - const res = await axiosInstance.put("/mentor/my", body); + getMentorDetail: async (params: { mentorId: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/mentors/${params.mentorId}`, { params: params?.params } + ); return res.data; }, - // === Mentee (멘티) APIs === - getApplyMentoringList: async ( - verifyStatus: VerifyStatus, - page: number, - size: number = MENTEE_OFFSET, - ): Promise => { - const res = await axiosInstance.get( - `/mentee/mentorings?verify-status=${verifyStatus}&size=${size}&page=${page}`, + getMyMentorPage: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/mentor/my`, { params: params?.params } ); return res.data; }, - patchMenteeCheckMentorings: async (body: PatchCheckMentoringsRequest): Promise => { - const res = await axiosInstance.patch("/mentee/mentorings/check", body); + putUpdateMyMentorPage: async (params: { data?: UpdateMyMentorPageRequest }): Promise => { + const res = await axiosInstance.put( + `/mentor/my`, params?.data + ); return res.data; }, - postApplyMentoring: async (body: PostApplyMentoringRequest): Promise => { - const res = await axiosInstance.post("/mentee/mentorings", body); + patchMentoringStatus: async (params: { mentoringId: string | number, data?: MentoringStatusRequest }): Promise => { + const res = await axiosInstance.patch( + `/mentor/mentorings/${params.mentoringId}`, params?.data + ); return res.data; }, - // === Mentors (멘토 목록) APIs === - getMentorList: async (region: string, page: number, size: number = MENTORS_OFFSET): Promise => { - const res = await axiosInstance.get(`/mentors?region=${region}&page=${page}&size=${size}`); + patchConfirmMentoring: async (params: { data?: ConfirmMentoringRequest }): Promise => { + const res = await axiosInstance.patch( + `/mentor/mentorings/check`, params?.data + ); return res.data; }, - getMentorDetail: async (mentorId: number): Promise => { - const res = await axiosInstance.get(`/mentors/${mentorId}`); + getReceivedMentorings: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/mentor/mentorings`, { params: params?.params } + ); return res.data; }, - getMatchedMentors: async (params: { - defaultSize: string | number; - defaultPage: string | number; - params?: Record; - }): Promise => { - const { defaultSize, defaultPage, params: queryParams } = params; - const res = await axiosInstance.get( - `/mentors/matched?size=${defaultSize}&page=${defaultPage}`, - { params: queryParams }, + getUnconfirmedMentoringCount: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/mentor/mentorings/check`, { params: params?.params } ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/mentor/getAppliedMentorings.ts b/src/apis/mentor/getAppliedMentorings.ts index 17ee3b3f..54a9d70b 100644 --- a/src/apis/mentor/getAppliedMentorings.ts +++ b/src/apis/mentor/getAppliedMentorings.ts @@ -1,41 +1,14 @@ -import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { - type ApplyMentoringListResponse, - type MentoringListItem, - MentorQueryKeys, - mentorApi, - type VerifyStatus, -} from "./api"; - -/** - * @description 신청한 멘토링 목록 조회 훅 (무한 스크롤) - */ -const useGetApplyMentoringList = (verifyStatus: VerifyStatus) => { - return useInfiniteQuery({ - queryKey: [MentorQueryKeys.applyMentoringList, verifyStatus], - queryFn: ({ pageParam = 0 }) => mentorApi.getApplyMentoringList(verifyStatus, pageParam), - initialPageParam: 0, - getNextPageParam: (lastPage) => (lastPage.nextPageNumber === -1 ? undefined : lastPage.nextPageNumber), - staleTime: 1000 * 60 * 5, // 5분간 캐시 - select: (data) => data.pages.flatMap((p) => p.content), +import { AxiosError } from "axios"; +import { useQuery } from "@tanstack/react-query"; +import { mentorApi, AppliedMentoringsResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; + +const useGetAppliedMentorings = (verifyStatus: string | number, defaultSize: string | number, defaultPage: string | number, params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.mentor.appliedMentorings, verifyStatus, defaultSize, defaultPage, params], + queryFn: () => mentorApi.getAppliedMentorings({ verifyStatus, defaultSize, defaultPage, params }), + enabled: !!verifyStatus && !!defaultSize && !!defaultPage, }); }; -// 멘토링 리스트 프리페치용 훅 -export const usePrefetchApplyMentoringList = () => { - const queryClient = useQueryClient(); - - const prefetchList = (verifyStatus: VerifyStatus) => { - queryClient.prefetchInfiniteQuery({ - queryKey: [MentorQueryKeys.applyMentoringList, verifyStatus], - queryFn: ({ pageParam = 0 }) => mentorApi.getApplyMentoringList(verifyStatus, pageParam as number), - initialPageParam: 0, - staleTime: 1000 * 60 * 5, - }); - }; - - return { prefetchList }; -}; - -export default useGetApplyMentoringList; +export default useGetAppliedMentorings; \ No newline at end of file diff --git a/src/apis/mentor/getMatchedMentors.ts b/src/apis/mentor/getMatchedMentors.ts index c89239f1..40ff31b9 100644 --- a/src/apis/mentor/getMatchedMentors.ts +++ b/src/apis/mentor/getMatchedMentors.ts @@ -1,13 +1,9 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { mentorApi, MatchedMentorsResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type MatchedMentorsResponse, mentorApi } from "./api"; -const useGetMatchedMentors = ( - defaultSize: string | number, - defaultPage: string | number, - params?: Record, -) => { +const useGetMatchedMentors = (defaultSize: string | number, defaultPage: string | number, params?: Record) => { return useQuery({ queryKey: [QueryKeys.mentor.matchedMentors, defaultSize, defaultPage, params], queryFn: () => mentorApi.getMatchedMentors({ defaultSize, defaultPage, params }), @@ -15,4 +11,4 @@ const useGetMatchedMentors = ( }); }; -export default useGetMatchedMentors; +export default useGetMatchedMentors; \ No newline at end of file diff --git a/src/apis/mentor/getMentorDetail.ts b/src/apis/mentor/getMentorDetail.ts index 75cbc778..88f22b9e 100644 --- a/src/apis/mentor/getMentorDetail.ts +++ b/src/apis/mentor/getMentorDetail.ts @@ -1,17 +1,14 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type MentorCardDetail, MentorQueryKeys, mentorApi } from "./api"; +import { mentorApi, MentorDetailResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -/** - * @description 멘토 상세 조회 훅 - */ -const useGetMentorDetail = (mentorId: number | null) => { - return useQuery({ - queryKey: [MentorQueryKeys.mentorDetail, mentorId!], - queryFn: () => mentorApi.getMentorDetail(mentorId!), - enabled: mentorId !== null, - staleTime: 1000 * 60 * 5, // 5분간 캐시 +const useGetMentorDetail = (mentorId: string | number, params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.mentor.mentorDetail, mentorId, params], + queryFn: () => mentorApi.getMentorDetail({ mentorId, params }), + enabled: !!mentorId, }); }; -export default useGetMentorDetail; +export default useGetMentorDetail; \ No newline at end of file diff --git a/src/apis/mentor/getMentorList.ts b/src/apis/mentor/getMentorList.ts index 8e41e741..465458c0 100644 --- a/src/apis/mentor/getMentorList.ts +++ b/src/apis/mentor/getMentorList.ts @@ -1,39 +1,14 @@ -import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type MentorCardDetail, type MentorListResponse, MentorQueryKeys, mentorApi } from "./api"; - -interface UseGetMentorListRequest { - region?: string; -} - -/** - * @description 멘토 목록 조회 훅 (무한 스크롤) - */ -const useGetMentorList = ({ region = "" }: UseGetMentorListRequest = {}) => { - return useInfiniteQuery({ - queryKey: [MentorQueryKeys.mentorList, region], - queryFn: ({ pageParam = 0 }) => mentorApi.getMentorList(region, pageParam), - initialPageParam: 0, - getNextPageParam: (lastPage) => (lastPage.nextPageNumber === -1 ? undefined : lastPage.nextPageNumber), - staleTime: 1000 * 60 * 5, - select: (data) => data.pages.flatMap((p) => p.content), +import { AxiosError } from "axios"; +import { useQuery } from "@tanstack/react-query"; +import { mentorApi, MentorListResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; + +const useGetMentorList = (defaultSize: string | number, defaultPage: string | number, params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.mentor.mentorList, defaultSize, defaultPage, params], + queryFn: () => mentorApi.getMentorList({ defaultSize, defaultPage, params }), + enabled: !!defaultSize && !!defaultPage, }); }; -// 탭 프리페치용 훅 -export const usePrefetchMentorList = () => { - const queryClient = useQueryClient(); - - const prefetchMentorList = (region: string) => { - queryClient.prefetchInfiniteQuery({ - queryKey: [MentorQueryKeys.mentorList, region], - queryFn: ({ pageParam = 0 }) => mentorApi.getMentorList(region, pageParam as number), - initialPageParam: 0, - staleTime: 1000 * 60 * 5, - }); - }; - - return { prefetchMentorList }; -}; - -export default useGetMentorList; +export default useGetMentorList; \ No newline at end of file diff --git a/src/apis/mentor/getMyMentorPage.ts b/src/apis/mentor/getMyMentorPage.ts index 7f0a7448..db6d1b42 100644 --- a/src/apis/mentor/getMyMentorPage.ts +++ b/src/apis/mentor/getMyMentorPage.ts @@ -1,16 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type MentorCardPreview, MentorQueryKeys, mentorApi } from "./api"; +import { mentorApi, MyMentorPageResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -/** - * @description 멘토 마이 프로필 조회 훅 - */ -const useGetMentorMyProfile = () => { - return useQuery({ - queryKey: [MentorQueryKeys.myMentorProfile], - queryFn: mentorApi.getMentorMyProfile, - staleTime: 1000 * 60 * 5, // 5분간 캐시 +const useGetMyMentorPage = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.mentor.myMentorPage, params], + queryFn: () => mentorApi.getMyMentorPage(params ? { params } : {}), }); }; -export default useGetMentorMyProfile; +export default useGetMyMentorPage; \ No newline at end of file diff --git a/src/apis/mentor/getReceivedMentorings.ts b/src/apis/mentor/getReceivedMentorings.ts index 7355a7a1..81d875cf 100644 --- a/src/apis/mentor/getReceivedMentorings.ts +++ b/src/apis/mentor/getReceivedMentorings.ts @@ -1,24 +1,13 @@ -import { useInfiniteQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type MentoringItem, type MentoringListResponse, MentorQueryKeys, mentorApi } from "./api"; +import { AxiosError } from "axios"; +import { useQuery } from "@tanstack/react-query"; +import { mentorApi, ReceivedMentoringsResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -const OFFSET = 5; - -/** - * @description 받은 멘토링 목록 조회 훅 (무한 스크롤) - */ -const useGetMentoringList = ({ size = OFFSET }: { size?: number } = {}) => { - return useInfiniteQuery({ - queryKey: [MentorQueryKeys.mentoringList, size], - queryFn: ({ pageParam = 0 }) => mentorApi.getMentoringList(pageParam, size), - initialPageParam: 0, - getNextPageParam: (lastPage) => { - return lastPage.nextPageNumber !== -1 ? lastPage.nextPageNumber : undefined; - }, - refetchInterval: 1000 * 60 * 10, // ⏱️ 10분마다 자동 재요청 - staleTime: 1000 * 60 * 5, // fresh 상태 유지 - select: (data) => data.pages.flatMap((page) => page.content), +const useGetReceivedMentorings = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.mentor.receivedMentorings, params], + queryFn: () => mentorApi.getReceivedMentorings(params ? { params } : {}), }); }; -export default useGetMentoringList; +export default useGetReceivedMentorings; \ No newline at end of file diff --git a/src/apis/mentor/getUnconfirmedMentoringCount.ts b/src/apis/mentor/getUnconfirmedMentoringCount.ts index 5d55d649..7c3b9c1b 100644 --- a/src/apis/mentor/getUnconfirmedMentoringCount.ts +++ b/src/apis/mentor/getUnconfirmedMentoringCount.ts @@ -1,19 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type GetMentoringNewCountResponse, MentorQueryKeys, mentorApi } from "./api"; +import { mentorApi, UnconfirmedMentoringCountResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -/** - * @description 미확인 멘토링 수 조회 훅 - */ -const useGetMentoringUncheckedCount = (isEnable: boolean) => { - return useQuery({ - queryKey: [MentorQueryKeys.mentoringNewCount], - queryFn: mentorApi.getMentoringUncheckedCount, - enabled: isEnable, - refetchInterval: 1000 * 60 * 10, // ⏱️ 10분마다 자동 재요청 - staleTime: 1000 * 60 * 5, // fresh 상태 유지 - select: (data) => data.uncheckedCount, +const useGetUnconfirmedMentoringCount = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.mentor.unconfirmedMentoringCount, params], + queryFn: () => mentorApi.getUnconfirmedMentoringCount(params ? { params } : {}), }); }; -export default useGetMentoringUncheckedCount; +export default useGetUnconfirmedMentoringCount; \ No newline at end of file diff --git a/src/apis/mentor/index.ts b/src/apis/mentor/index.ts index 7986dd51..fd67218d 100644 --- a/src/apis/mentor/index.ts +++ b/src/apis/mentor/index.ts @@ -1,26 +1,15 @@ -export type { - MentorCardDetail, - MentorCardPreview, - MentoringApprovalStatus, - MentoringItem, - MentoringListItem, - PostMentorApplicationRequest, - PutMyMentorProfileRequest, - VerifyStatus, -} from "./api"; -export { MentorQueryKeys, mentorApi } from "./api"; -// Mentee (멘티) hooks -export { default as useGetApplyMentoringList, usePrefetchApplyMentoringList } from "./getAppliedMentorings"; -export { default as useGetMentorDetail } from "./getMentorDetail"; -// Mentors (멘토 목록) hooks -export { default as useGetMentorList, usePrefetchMentorList } from "./getMentorList"; -// Mentor (멘토) hooks -export { default as useGetMentorMyProfile } from "./getMyMentorPage"; -export { default as useGetMentoringList } from "./getReceivedMentorings"; -export { default as useGetMentoringUncheckedCount } from "./getUnconfirmedMentoringCount"; -export { default as usePatchMentorCheckMentorings } from "./patchConfirmMentoring"; -export { default as usePatchMenteeCheckMentorings } from "./patchMenteeCheckMentorings"; -export { default as usePatchApprovalStatus } from "./patchMentoringStatus"; -export { default as usePostApplyMentoring } from "./postApplyMentoring"; -export { default as usePostMentorApplication } from "./postMentorApplication"; -export { default as usePutMyMentorProfile } from "./putUpdateMyMentorPage"; +export { mentorApi } from './api'; +export { default as getAppliedMentorings } from './getAppliedMentorings'; +export { default as getMatchedMentors } from './getMatchedMentors'; +export { default as getMentorDetail } from './getMentorDetail'; +export { default as getMentorList } from './getMentorList'; +export { default as getMyMentorPage } from './getMyMentorPage'; +export { default as getReceivedMentorings } from './getReceivedMentorings'; +export { default as getUnconfirmedMentoringCount } from './getUnconfirmedMentoringCount'; +export { default as index } from './index'; +export { default as patchConfirmMentoring } from './patchConfirmMentoring'; +export { default as patchMenteeCheckMentorings } from './patchMenteeCheckMentorings'; +export { default as patchMentoringStatus } from './patchMentoringStatus'; +export { default as postApplyMentoring } from './postApplyMentoring'; +export { default as postMentorApplication } from './postMentorApplication'; +export { default as putUpdateMyMentorPage } from './putUpdateMyMentorPage'; diff --git a/src/apis/mentor/legacy/getAppliedMentorings.CHANGES.md b/src/apis/mentor/legacy/getAppliedMentorings.CHANGES.md new file mode 100644 index 00000000..8c0fe91a --- /dev/null +++ b/src/apis/mentor/legacy/getAppliedMentorings.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getAppliedMentorings.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentee/mentorings?verify-status={{verify-status}}&size={{default-size}}&page={{default-page}} +- Method: GET +- Function: getAppliedMentorings + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `ApplyMentoringListResponse` +- 현재: `AppliedMentoringsResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.applyMentoringList, verifyStatus` +- 현재: `QueryKeys.mentor.getAppliedMentorings, URL, params` + +## 권장 조치 + +1. `legacy/getAppliedMentorings.ts` 파일의 비즈니스 로직 확인 +2. 새 `getAppliedMentorings.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getAppliedMentorings.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/getAppliedMentorings.ts b/src/apis/mentor/legacy/getAppliedMentorings.ts new file mode 100644 index 00000000..17ee3b3f --- /dev/null +++ b/src/apis/mentor/legacy/getAppliedMentorings.ts @@ -0,0 +1,41 @@ +import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { + type ApplyMentoringListResponse, + type MentoringListItem, + MentorQueryKeys, + mentorApi, + type VerifyStatus, +} from "./api"; + +/** + * @description 신청한 멘토링 목록 조회 훅 (무한 스크롤) + */ +const useGetApplyMentoringList = (verifyStatus: VerifyStatus) => { + return useInfiniteQuery({ + queryKey: [MentorQueryKeys.applyMentoringList, verifyStatus], + queryFn: ({ pageParam = 0 }) => mentorApi.getApplyMentoringList(verifyStatus, pageParam), + initialPageParam: 0, + getNextPageParam: (lastPage) => (lastPage.nextPageNumber === -1 ? undefined : lastPage.nextPageNumber), + staleTime: 1000 * 60 * 5, // 5분간 캐시 + select: (data) => data.pages.flatMap((p) => p.content), + }); +}; + +// 멘토링 리스트 프리페치용 훅 +export const usePrefetchApplyMentoringList = () => { + const queryClient = useQueryClient(); + + const prefetchList = (verifyStatus: VerifyStatus) => { + queryClient.prefetchInfiniteQuery({ + queryKey: [MentorQueryKeys.applyMentoringList, verifyStatus], + queryFn: ({ pageParam = 0 }) => mentorApi.getApplyMentoringList(verifyStatus, pageParam as number), + initialPageParam: 0, + staleTime: 1000 * 60 * 5, + }); + }; + + return { prefetchList }; +}; + +export default useGetApplyMentoringList; diff --git a/src/apis/mentor/legacy/getMatchedMentors.CHANGES.md b/src/apis/mentor/legacy/getMatchedMentors.CHANGES.md new file mode 100644 index 00000000..706ef8dd --- /dev/null +++ b/src/apis/mentor/legacy/getMatchedMentors.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getMatchedMentors.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentee/mentorings/matched-mentors?size={{default-size}}&page={{default-page}} +- Method: GET +- Function: getMatchedMentors + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.mentor.matchedMentors, defaultSize, defaultPage, params` +- 현재: `QueryKeys.mentor.getMatchedMentors, URL, params` + +## 권장 조치 + +1. `legacy/getMatchedMentors.ts` 파일의 비즈니스 로직 확인 +2. 새 `getMatchedMentors.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getMatchedMentors.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/getMatchedMentors.ts b/src/apis/mentor/legacy/getMatchedMentors.ts new file mode 100644 index 00000000..c89239f1 --- /dev/null +++ b/src/apis/mentor/legacy/getMatchedMentors.ts @@ -0,0 +1,18 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type MatchedMentorsResponse, mentorApi } from "./api"; + +const useGetMatchedMentors = ( + defaultSize: string | number, + defaultPage: string | number, + params?: Record, +) => { + return useQuery({ + queryKey: [QueryKeys.mentor.matchedMentors, defaultSize, defaultPage, params], + queryFn: () => mentorApi.getMatchedMentors({ defaultSize, defaultPage, params }), + enabled: !!defaultSize && !!defaultPage, + }); +}; + +export default useGetMatchedMentors; diff --git a/src/apis/mentor/legacy/getMentorDetail.CHANGES.md b/src/apis/mentor/legacy/getMentorDetail.CHANGES.md new file mode 100644 index 00000000..b53436e0 --- /dev/null +++ b/src/apis/mentor/legacy/getMentorDetail.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getMentorDetail.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentors/{{mentor-id}} +- Method: GET +- Function: getMentorDetail + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `MentorCardDetail` +- 현재: `MentorDetailResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.mentorDetail, mentorId!` +- 현재: `QueryKeys.mentor.getMentorDetail, URL, params` + +## 권장 조치 + +1. `legacy/getMentorDetail.ts` 파일의 비즈니스 로직 확인 +2. 새 `getMentorDetail.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getMentorDetail.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/getMentorDetail.ts b/src/apis/mentor/legacy/getMentorDetail.ts new file mode 100644 index 00000000..75cbc778 --- /dev/null +++ b/src/apis/mentor/legacy/getMentorDetail.ts @@ -0,0 +1,17 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type MentorCardDetail, MentorQueryKeys, mentorApi } from "./api"; + +/** + * @description 멘토 상세 조회 훅 + */ +const useGetMentorDetail = (mentorId: number | null) => { + return useQuery({ + queryKey: [MentorQueryKeys.mentorDetail, mentorId!], + queryFn: () => mentorApi.getMentorDetail(mentorId!), + enabled: mentorId !== null, + staleTime: 1000 * 60 * 5, // 5분간 캐시 + }); +}; + +export default useGetMentorDetail; diff --git a/src/apis/mentor/legacy/getMentorList.CHANGES.md b/src/apis/mentor/legacy/getMentorList.CHANGES.md new file mode 100644 index 00000000..8422ebe3 --- /dev/null +++ b/src/apis/mentor/legacy/getMentorList.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getMentorList.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentors?region=미주권&size={{default-size}}&page={{default-page}} +- Method: GET +- Function: getMentorList + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.mentorList, region` +- 현재: `QueryKeys.mentor.getMentorList, URL, params` + +## 권장 조치 + +1. `legacy/getMentorList.ts` 파일의 비즈니스 로직 확인 +2. 새 `getMentorList.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getMentorList.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/getMentorList.ts b/src/apis/mentor/legacy/getMentorList.ts new file mode 100644 index 00000000..8e41e741 --- /dev/null +++ b/src/apis/mentor/legacy/getMentorList.ts @@ -0,0 +1,39 @@ +import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type MentorCardDetail, type MentorListResponse, MentorQueryKeys, mentorApi } from "./api"; + +interface UseGetMentorListRequest { + region?: string; +} + +/** + * @description 멘토 목록 조회 훅 (무한 스크롤) + */ +const useGetMentorList = ({ region = "" }: UseGetMentorListRequest = {}) => { + return useInfiniteQuery({ + queryKey: [MentorQueryKeys.mentorList, region], + queryFn: ({ pageParam = 0 }) => mentorApi.getMentorList(region, pageParam), + initialPageParam: 0, + getNextPageParam: (lastPage) => (lastPage.nextPageNumber === -1 ? undefined : lastPage.nextPageNumber), + staleTime: 1000 * 60 * 5, + select: (data) => data.pages.flatMap((p) => p.content), + }); +}; + +// 탭 프리페치용 훅 +export const usePrefetchMentorList = () => { + const queryClient = useQueryClient(); + + const prefetchMentorList = (region: string) => { + queryClient.prefetchInfiniteQuery({ + queryKey: [MentorQueryKeys.mentorList, region], + queryFn: ({ pageParam = 0 }) => mentorApi.getMentorList(region, pageParam as number), + initialPageParam: 0, + staleTime: 1000 * 60 * 5, + }); + }; + + return { prefetchMentorList }; +}; + +export default useGetMentorList; diff --git a/src/apis/mentor/legacy/getMyMentorPage.CHANGES.md b/src/apis/mentor/legacy/getMyMentorPage.CHANGES.md new file mode 100644 index 00000000..00b1b342 --- /dev/null +++ b/src/apis/mentor/legacy/getMyMentorPage.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getMyMentorPage.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentor/my +- Method: GET +- Function: getMyMentorPage + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `MentorCardPreview` +- 현재: `MyMentorPageResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.myMentorProfile` +- 현재: `QueryKeys.mentor.getMyMentorPage, URL, params` + +## 권장 조치 + +1. `legacy/getMyMentorPage.ts` 파일의 비즈니스 로직 확인 +2. 새 `getMyMentorPage.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getMyMentorPage.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/getMyMentorPage.ts b/src/apis/mentor/legacy/getMyMentorPage.ts new file mode 100644 index 00000000..7f0a7448 --- /dev/null +++ b/src/apis/mentor/legacy/getMyMentorPage.ts @@ -0,0 +1,16 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type MentorCardPreview, MentorQueryKeys, mentorApi } from "./api"; + +/** + * @description 멘토 마이 프로필 조회 훅 + */ +const useGetMentorMyProfile = () => { + return useQuery({ + queryKey: [MentorQueryKeys.myMentorProfile], + queryFn: mentorApi.getMentorMyProfile, + staleTime: 1000 * 60 * 5, // 5분간 캐시 + }); +}; + +export default useGetMentorMyProfile; diff --git a/src/apis/mentor/legacy/getReceivedMentorings.CHANGES.md b/src/apis/mentor/legacy/getReceivedMentorings.CHANGES.md new file mode 100644 index 00000000..0e36b89d --- /dev/null +++ b/src/apis/mentor/legacy/getReceivedMentorings.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getReceivedMentorings.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentor/mentorings +- Method: GET +- Function: getReceivedMentorings + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `MentoringListResponse` +- 현재: `ReceivedMentoringsResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.mentoringList, size` +- 현재: `QueryKeys.mentor.getReceivedMentorings, URL, params` + +## 권장 조치 + +1. `legacy/getReceivedMentorings.ts` 파일의 비즈니스 로직 확인 +2. 새 `getReceivedMentorings.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getReceivedMentorings.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/getReceivedMentorings.ts b/src/apis/mentor/legacy/getReceivedMentorings.ts new file mode 100644 index 00000000..7355a7a1 --- /dev/null +++ b/src/apis/mentor/legacy/getReceivedMentorings.ts @@ -0,0 +1,24 @@ +import { useInfiniteQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type MentoringItem, type MentoringListResponse, MentorQueryKeys, mentorApi } from "./api"; + +const OFFSET = 5; + +/** + * @description 받은 멘토링 목록 조회 훅 (무한 스크롤) + */ +const useGetMentoringList = ({ size = OFFSET }: { size?: number } = {}) => { + return useInfiniteQuery({ + queryKey: [MentorQueryKeys.mentoringList, size], + queryFn: ({ pageParam = 0 }) => mentorApi.getMentoringList(pageParam, size), + initialPageParam: 0, + getNextPageParam: (lastPage) => { + return lastPage.nextPageNumber !== -1 ? lastPage.nextPageNumber : undefined; + }, + refetchInterval: 1000 * 60 * 10, // ⏱️ 10분마다 자동 재요청 + staleTime: 1000 * 60 * 5, // fresh 상태 유지 + select: (data) => data.pages.flatMap((page) => page.content), + }); +}; + +export default useGetMentoringList; diff --git a/src/apis/mentor/legacy/getUnconfirmedMentoringCount.CHANGES.md b/src/apis/mentor/legacy/getUnconfirmedMentoringCount.CHANGES.md new file mode 100644 index 00000000..9167304a --- /dev/null +++ b/src/apis/mentor/legacy/getUnconfirmedMentoringCount.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getUnconfirmedMentoringCount.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentor/mentorings/check +- Method: GET +- Function: getUnconfirmedMentoringCount + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `GetMentoringNewCountResponse` +- 현재: `UnconfirmedMentoringCountResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.mentoringNewCount` +- 현재: `QueryKeys.mentor.getUnconfirmedMentoringCount, URL, params` + +## 권장 조치 + +1. `legacy/getUnconfirmedMentoringCount.ts` 파일의 비즈니스 로직 확인 +2. 새 `getUnconfirmedMentoringCount.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getUnconfirmedMentoringCount.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/getUnconfirmedMentoringCount.ts b/src/apis/mentor/legacy/getUnconfirmedMentoringCount.ts new file mode 100644 index 00000000..5d55d649 --- /dev/null +++ b/src/apis/mentor/legacy/getUnconfirmedMentoringCount.ts @@ -0,0 +1,19 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type GetMentoringNewCountResponse, MentorQueryKeys, mentorApi } from "./api"; + +/** + * @description 미확인 멘토링 수 조회 훅 + */ +const useGetMentoringUncheckedCount = (isEnable: boolean) => { + return useQuery({ + queryKey: [MentorQueryKeys.mentoringNewCount], + queryFn: mentorApi.getMentoringUncheckedCount, + enabled: isEnable, + refetchInterval: 1000 * 60 * 10, // ⏱️ 10분마다 자동 재요청 + staleTime: 1000 * 60 * 5, // fresh 상태 유지 + select: (data) => data.uncheckedCount, + }); +}; + +export default useGetMentoringUncheckedCount; diff --git a/src/apis/mentor/legacy/patchConfirmMentoring.CHANGES.md b/src/apis/mentor/legacy/patchConfirmMentoring.CHANGES.md new file mode 100644 index 00000000..f2aa947f --- /dev/null +++ b/src/apis/mentor/legacy/patchConfirmMentoring.CHANGES.md @@ -0,0 +1,39 @@ +# 변경사항: patchConfirmMentoring.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentee/mentorings/check +- Method: PATCH +- Function: patchConfirmMentoring + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `PatchCheckMentoringsResponse` +- 현재: `ConfirmMentoringResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `PatchCheckMentoringsRequest` +- 현재: `ConfirmMentoringRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.mentoringList` +- 현재: `QueryKeys.mentor.patchConfirmMentoring, URL, params` + +## 권장 조치 + +1. `legacy/patchConfirmMentoring.ts` 파일의 비즈니스 로직 확인 +2. 새 `patchConfirmMentoring.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/patchConfirmMentoring.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/patchConfirmMentoring.ts b/src/apis/mentor/legacy/patchConfirmMentoring.ts new file mode 100644 index 00000000..43e07f3f --- /dev/null +++ b/src/apis/mentor/legacy/patchConfirmMentoring.ts @@ -0,0 +1,11 @@ +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { mentorApi, ConfirmMentoringResponse, ConfirmMentoringRequest } from "./api"; + +const usePatchConfirmMentoring = () => { + return useMutation({ + mutationFn: (data) => mentorApi.patchConfirmMentoring({ data }), + }); +}; + +export default usePatchConfirmMentoring; \ No newline at end of file diff --git a/src/apis/mentor/legacy/patchMentoringStatus.CHANGES.md b/src/apis/mentor/legacy/patchMentoringStatus.CHANGES.md new file mode 100644 index 00000000..f3c125ae --- /dev/null +++ b/src/apis/mentor/legacy/patchMentoringStatus.CHANGES.md @@ -0,0 +1,39 @@ +# 변경사항: patchMentoringStatus.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentor/mentorings/{{mentoring-id}} +- Method: PATCH +- Function: patchMentoringStatus + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `PatchApprovalStatusResponse` +- 현재: `MentoringStatusResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `PatchApprovalStatusRequest` +- 현재: `MentoringStatusRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.mentoringList` +- 현재: `QueryKeys.mentor.patchMentoringStatus, URL, params` + +## 권장 조치 + +1. `legacy/patchMentoringStatus.ts` 파일의 비즈니스 로직 확인 +2. 새 `patchMentoringStatus.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/patchMentoringStatus.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/patchMentoringStatus.ts b/src/apis/mentor/legacy/patchMentoringStatus.ts new file mode 100644 index 00000000..76fb6cd9 --- /dev/null +++ b/src/apis/mentor/legacy/patchMentoringStatus.ts @@ -0,0 +1,63 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; + +import type { AxiosError } from "axios"; +import { useRouter } from "next/navigation"; + +import { customAlert } from "@/lib/zustand/useAlertModalStore"; +import { customConfirm } from "@/lib/zustand/useConfirmModalStore"; +import { IconSmile, IconUnSmile } from "@/public/svgs/mentor"; +import { + MentoringApprovalStatus, + MentorQueryKeys, + mentorApi, + type PatchApprovalStatusRequest, + type PatchApprovalStatusResponse, +} from "./api"; + +/** + * @description 멘토링 승인/거절 훅 + */ +const usePatchApprovalStatus = () => { + const router = useRouter(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: mentorApi.patchApprovalStatus, + onSuccess: async (data, variables) => { + // 멘토링 상태 변경 후 쿼리 무효화 + await Promise.all([ + queryClient.invalidateQueries({ queryKey: [MentorQueryKeys.mentoringList] }), + queryClient.invalidateQueries({ queryKey: [MentorQueryKeys.mentoringNewCount] }), + ]); + + if (variables.status === MentoringApprovalStatus.REJECTED) { + customAlert({ + title: "멘티 신청을 거절했어요.", + icon: IconUnSmile, + content: "현재까지 누적해서 거절했어요. 누적 5회 거절 시 활동에 제약이 있으니 유의해주세요.", + buttonText: "닫기", + }); + } else if (variables.status === MentoringApprovalStatus.APPROVED) { + const ok = await customConfirm({ + title: "멘티 신청이 완료되었어요!", + content: "지금 바로 멘티에게 메시지를 전송해보세요", + icon: IconSmile, + rejectMessage: "닫기", + approveMessage: "1:1 채팅 바로가기", + }); + if (ok) { + router.push(`/mentor/chat/${data.chatRoomId}`); + } + } + }, + onError: (_error) => { + customAlert({ + title: "멘토링 상태 변경 실패", + content: "멘토링 상태 변경 중 오류가 발생했습니다. 다시 시도해주세요.", + buttonText: "확인", + }); + }, + }); +}; + +export default usePatchApprovalStatus; diff --git a/src/apis/mentor/legacy/postApplyMentoring.CHANGES.md b/src/apis/mentor/legacy/postApplyMentoring.CHANGES.md new file mode 100644 index 00000000..00bf0473 --- /dev/null +++ b/src/apis/mentor/legacy/postApplyMentoring.CHANGES.md @@ -0,0 +1,39 @@ +# 변경사항: postApplyMentoring.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentee/mentorings +- Method: POST +- Function: postApplyMentoring + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `PostApplyMentoringResponse` +- 현재: `ApplyMentoringResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `PostApplyMentoringRequest` +- 현재: `ApplyMentoringRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.applyMentoringList` +- 현재: `QueryKeys.mentor.postApplyMentoring, URL, params` + +## 권장 조치 + +1. `legacy/postApplyMentoring.ts` 파일의 비즈니스 로직 확인 +2. 새 `postApplyMentoring.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postApplyMentoring.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/postApplyMentoring.ts b/src/apis/mentor/legacy/postApplyMentoring.ts new file mode 100644 index 00000000..6be451f4 --- /dev/null +++ b/src/apis/mentor/legacy/postApplyMentoring.ts @@ -0,0 +1,24 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { MentorQueryKeys, mentorApi, type PostApplyMentoringRequest, type PostApplyMentoringResponse } from "./api"; + +/** + * @description 멘토링 신청 훅 + */ +const usePostApplyMentoring = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: mentorApi.postApplyMentoring, + onSuccess: async () => { + // 멘토링 신청 후 멘토 목록을 새로고침 + await queryClient.invalidateQueries({ queryKey: [MentorQueryKeys.applyMentoringList] }); + }, + onError: () => { + toast.error("멘토 신청에 실패했습니다. 다시 시도해주세요."); + }, + }); +}; + +export default usePostApplyMentoring; diff --git a/src/apis/mentor/legacy/putUpdateMyMentorPage.CHANGES.md b/src/apis/mentor/legacy/putUpdateMyMentorPage.CHANGES.md new file mode 100644 index 00000000..4f75b363 --- /dev/null +++ b/src/apis/mentor/legacy/putUpdateMyMentorPage.CHANGES.md @@ -0,0 +1,39 @@ +# 변경사항: putUpdateMyMentorPage.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/mentor/my +- Method: PUT +- Function: putUpdateMyMentorPage + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `void` +- 현재: `UpdateMyMentorPageResponse` + +### request-type + +**Request 타입 변경** + +- 이전: `PutMyMentorProfileRequest` +- 현재: `UpdateMyMentorPageRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `MentorQueryKeys.myMentorProfile` +- 현재: `QueryKeys.mentor.putUpdateMyMentorPage, URL, params` + +## 권장 조치 + +1. `legacy/putUpdateMyMentorPage.ts` 파일의 비즈니스 로직 확인 +2. 새 `putUpdateMyMentorPage.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/putUpdateMyMentorPage.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/mentor/legacy/putUpdateMyMentorPage.ts b/src/apis/mentor/legacy/putUpdateMyMentorPage.ts new file mode 100644 index 00000000..69a59090 --- /dev/null +++ b/src/apis/mentor/legacy/putUpdateMyMentorPage.ts @@ -0,0 +1,22 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { MentorQueryKeys, mentorApi, type PutMyMentorProfileRequest } from "./api"; + +/** + * @description 내 멘토 프로필 수정 훅 + */ +const usePutMyMentorProfile = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: mentorApi.putMyMentorProfile, + onSuccess: () => { + // 멘토 프로필 데이터를 stale로 만들어 다음 요청 시 새로운 데이터를 가져오도록 함 + queryClient.invalidateQueries({ + queryKey: [MentorQueryKeys.myMentorProfile], + }); + }, + }); +}; + +export default usePutMyMentorProfile; diff --git a/src/apis/mentor/patchConfirmMentoring.ts b/src/apis/mentor/patchConfirmMentoring.ts index a423e814..43e07f3f 100644 --- a/src/apis/mentor/patchConfirmMentoring.ts +++ b/src/apis/mentor/patchConfirmMentoring.ts @@ -1,22 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { MentorQueryKeys, mentorApi, type PatchCheckMentoringsRequest, type PatchCheckMentoringsResponse } from "./api"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { mentorApi, ConfirmMentoringResponse, ConfirmMentoringRequest } from "./api"; -/** - * @description 멘토 멘토링 확인 처리 훅 - */ -const usePatchMentorCheckMentorings = () => { - const queriesClient = useQueryClient(); - return useMutation({ - onSuccess: () => { - // 멘토링 체크 상태 변경 후 멘토링 목록 쿼리 무효화 - Promise.all([ - queriesClient.invalidateQueries({ queryKey: [MentorQueryKeys.mentoringList] }), - queriesClient.invalidateQueries({ queryKey: [MentorQueryKeys.mentoringNewCount] }), - ]); - }, - mutationFn: mentorApi.patchMentorCheckMentorings, +const usePatchConfirmMentoring = () => { + return useMutation({ + mutationFn: (data) => mentorApi.patchConfirmMentoring({ data }), }); }; -export default usePatchMentorCheckMentorings; +export default usePatchConfirmMentoring; \ No newline at end of file diff --git a/src/apis/mentor/patchMentoringStatus.ts b/src/apis/mentor/patchMentoringStatus.ts index 76fb6cd9..eec04d74 100644 --- a/src/apis/mentor/patchMentoringStatus.ts +++ b/src/apis/mentor/patchMentoringStatus.ts @@ -1,63 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { mentorApi, MentoringStatusResponse, MentoringStatusRequest } from "./api"; -import type { AxiosError } from "axios"; -import { useRouter } from "next/navigation"; - -import { customAlert } from "@/lib/zustand/useAlertModalStore"; -import { customConfirm } from "@/lib/zustand/useConfirmModalStore"; -import { IconSmile, IconUnSmile } from "@/public/svgs/mentor"; -import { - MentoringApprovalStatus, - MentorQueryKeys, - mentorApi, - type PatchApprovalStatusRequest, - type PatchApprovalStatusResponse, -} from "./api"; - -/** - * @description 멘토링 승인/거절 훅 - */ -const usePatchApprovalStatus = () => { - const router = useRouter(); - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: mentorApi.patchApprovalStatus, - onSuccess: async (data, variables) => { - // 멘토링 상태 변경 후 쿼리 무효화 - await Promise.all([ - queryClient.invalidateQueries({ queryKey: [MentorQueryKeys.mentoringList] }), - queryClient.invalidateQueries({ queryKey: [MentorQueryKeys.mentoringNewCount] }), - ]); - - if (variables.status === MentoringApprovalStatus.REJECTED) { - customAlert({ - title: "멘티 신청을 거절했어요.", - icon: IconUnSmile, - content: "현재까지 누적해서 거절했어요. 누적 5회 거절 시 활동에 제약이 있으니 유의해주세요.", - buttonText: "닫기", - }); - } else if (variables.status === MentoringApprovalStatus.APPROVED) { - const ok = await customConfirm({ - title: "멘티 신청이 완료되었어요!", - content: "지금 바로 멘티에게 메시지를 전송해보세요", - icon: IconSmile, - rejectMessage: "닫기", - approveMessage: "1:1 채팅 바로가기", - }); - if (ok) { - router.push(`/mentor/chat/${data.chatRoomId}`); - } - } - }, - onError: (_error) => { - customAlert({ - title: "멘토링 상태 변경 실패", - content: "멘토링 상태 변경 중 오류가 발생했습니다. 다시 시도해주세요.", - buttonText: "확인", - }); - }, +const usePatchMentoringStatus = () => { + return useMutation({ + mutationFn: (variables) => mentorApi.patchMentoringStatus(variables), }); }; -export default usePatchApprovalStatus; +export default usePatchMentoringStatus; \ No newline at end of file diff --git a/src/apis/mentor/postApplyMentoring.ts b/src/apis/mentor/postApplyMentoring.ts index 6be451f4..f5a54e52 100644 --- a/src/apis/mentor/postApplyMentoring.ts +++ b/src/apis/mentor/postApplyMentoring.ts @@ -1,24 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { mentorApi, ApplyMentoringResponse, ApplyMentoringRequest } from "./api"; -import { toast } from "@/lib/zustand/useToastStore"; -import { MentorQueryKeys, mentorApi, type PostApplyMentoringRequest, type PostApplyMentoringResponse } from "./api"; - -/** - * @description 멘토링 신청 훅 - */ const usePostApplyMentoring = () => { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: mentorApi.postApplyMentoring, - onSuccess: async () => { - // 멘토링 신청 후 멘토 목록을 새로고침 - await queryClient.invalidateQueries({ queryKey: [MentorQueryKeys.applyMentoringList] }); - }, - onError: () => { - toast.error("멘토 신청에 실패했습니다. 다시 시도해주세요."); - }, + return useMutation({ + mutationFn: (data) => mentorApi.postApplyMentoring({ data }), }); }; -export default usePostApplyMentoring; +export default usePostApplyMentoring; \ No newline at end of file diff --git a/src/apis/mentor/putUpdateMyMentorPage.ts b/src/apis/mentor/putUpdateMyMentorPage.ts index 69a59090..a3cd5a31 100644 --- a/src/apis/mentor/putUpdateMyMentorPage.ts +++ b/src/apis/mentor/putUpdateMyMentorPage.ts @@ -1,22 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { MentorQueryKeys, mentorApi, type PutMyMentorProfileRequest } from "./api"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { mentorApi, UpdateMyMentorPageResponse, UpdateMyMentorPageRequest } from "./api"; -/** - * @description 내 멘토 프로필 수정 훅 - */ -const usePutMyMentorProfile = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: mentorApi.putMyMentorProfile, - onSuccess: () => { - // 멘토 프로필 데이터를 stale로 만들어 다음 요청 시 새로운 데이터를 가져오도록 함 - queryClient.invalidateQueries({ - queryKey: [MentorQueryKeys.myMentorProfile], - }); - }, +const usePutUpdateMyMentorPage = () => { + return useMutation({ + mutationFn: (data) => mentorApi.putUpdateMyMentorPage({ data }), }); }; -export default usePutMyMentorProfile; +export default usePutUpdateMyMentorPage; \ No newline at end of file diff --git a/src/apis/news/api.ts b/src/apis/news/api.ts index dccf7dc5..13a68b0b 100644 --- a/src/apis/news/api.ts +++ b/src/apis/news/api.ts @@ -1,106 +1,79 @@ -import type { AxiosResponse } from "axios"; -import type { ArticleFormData } from "@/components/mentor/ArticleBottomSheetModal/lib/schema"; -import type { Article } from "@/types/news"; import { axiosInstance } from "@/utils/axiosInstance"; -// ====== Query Keys ====== -export const NewsQueryKeys = { - articleList: "articleList", - postAddArticle: "postAddArticle", - putModifyArticle: "putModifyArticle", -} as const; +export interface NewsListResponseNewsResponseListItem { + id: number; + title: string; + description: string; + url: string; + thumbnailUrl: string; + updatedAt: string; +} -// ====== Types ====== -export interface ArticleListResponse { - newsResponseList: Article[]; +export interface NewsListResponse { + newsResponseList: NewsListResponseNewsResponseListItem[]; } -export interface PostArticleLikeResponse { - isLiked: boolean; - likeCount: number; +export interface NewsResponse { + id: number; } -export interface DeleteArticleLikeResponse { - isLiked: boolean; - likeCount: number; +export interface UpdateNewsResponse { + id: number; } -export type UsePostAddArticleRequest = ArticleFormData; +export type UpdateNewsRequest = Record; + +export type LikeNewsResponse = void; + +export type LikeNewsRequest = Record; -export type UsePutModifyArticleRequest = { - body: ArticleFormData & { isImageDeleted?: boolean }; - articleId: number; -}; +export interface CreateNewsResponse { + id: number; +} + +export type CreateNewsRequest = Record; -// ====== API Functions ====== export const newsApi = { - /** - * 아티클 목록 조회 - */ - getArticleList: async (userId: number): Promise => { - const response: AxiosResponse = await axiosInstance.get(`/news?author-id=${userId}`); - return response.data; + getNewsList: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/news?author-id=6`, { params: params?.params } + ); + return res.data; }, - /** - * 아티클 추가 - */ - postAddArticle: async (body: UsePostAddArticleRequest): Promise
=> { - const newsCreateRequest = { - title: body.title, - description: body.description, - url: body.url || "", - }; - - const formData = new FormData(); - formData.append("newsCreateRequest", new Blob([JSON.stringify(newsCreateRequest)], { type: "application/json" })); - if (body.file) { - formData.append("file", body.file); - } - const response: AxiosResponse
= await axiosInstance.post("/news", formData); - return response.data; + deleteNews: async (params: { newsId: string | number }): Promise => { + const res = await axiosInstance.delete( + `/news/${params.newsId}` + ); + return res.data; }, - /** - * 아티클 수정 - */ - putModifyArticle: async (props: UsePutModifyArticleRequest): Promise
=> { - const { body, articleId } = props; - const newsUpdateRequest = { - title: body.title, - description: body.description, - url: body.url || "", - resetToDefaultImage: body.isImageDeleted === true, - }; - const formData = new FormData(); - formData.append("newsUpdateRequest", new Blob([JSON.stringify(newsUpdateRequest)], { type: "application/json" })); - if (body.file) formData.append("file", body.file); - - const response: AxiosResponse
= await axiosInstance.put(`/news/${articleId}`, formData); - return response.data; + putUpdateNews: async (params: { newsId: string | number, data?: UpdateNewsRequest }): Promise => { + const res = await axiosInstance.put( + `/news/${params.newsId}`, params?.data + ); + return res.data; }, - /** - * 아티클 삭제 - */ - deleteArticle: async (articleId: number): Promise => { - const response: AxiosResponse = await axiosInstance.delete(`/news/${articleId}`); - return response.data; + postLikeNews: async (params: { newsId: string | number, data?: LikeNewsRequest }): Promise => { + const res = await axiosInstance.post( + `/news/${params.newsId}/like`, params?.data + ); + return res.data; }, - /** - * 아티클 좋아요 - */ - postArticleLike: async (articleId: number): Promise => { - const response: AxiosResponse = await axiosInstance.post(`/news/${articleId}/like`); - return response.data; + deleteLikeNews: async (params: { newsId: string | number }): Promise => { + const res = await axiosInstance.delete( + `/news/${params.newsId}/like` + ); + return res.data; }, - /** - * 아티클 좋아요 취소 - */ - deleteArticleLike: async (articleId: number): Promise => { - const response: AxiosResponse = await axiosInstance.delete(`/news/${articleId}/like`); - return response.data; + postCreateNews: async (params: { data?: CreateNewsRequest }): Promise => { + const res = await axiosInstance.post( + `/news`, params?.data + ); + return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/news/deleteLikeNews.ts b/src/apis/news/deleteLikeNews.ts index 67898dba..9e0ad49c 100644 --- a/src/apis/news/deleteLikeNews.ts +++ b/src/apis/news/deleteLikeNews.ts @@ -1,51 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { newsApi, LikeNewsResponse, LikeNewsRequest } from "./api"; -import { type ArticleListResponse, type DeleteArticleLikeResponse, NewsQueryKeys, newsApi } from "./api"; - -type ArticleLikeMutationContext = { - previousArticleList?: ArticleListResponse; -}; - -/** - * @description 아티클 좋아요 취소 훅 - */ -const useDeleteArticleLike = (userId: number | null) => { - const queryClient = useQueryClient(); - const queryKey = [NewsQueryKeys.articleList, userId]; - - return useMutation, number, ArticleLikeMutationContext>({ - mutationFn: newsApi.deleteArticleLike, - - onMutate: async (unlikedArticleId) => { - await queryClient.cancelQueries({ queryKey }); - - const previousArticleList = queryClient.getQueryData(queryKey); - - queryClient.setQueryData(queryKey, (oldData) => { - if (!oldData) return { newsResponseList: [] }; - return { - newsResponseList: oldData.newsResponseList.map((article) => - article.id === unlikedArticleId - ? { - ...article, - isLiked: false, - likeCount: Math.max(0, (article.likeCount ?? 1) - 1), - } - : article, - ), - }; - }); - - return { previousArticleList }; - }, - - onError: (_err, _variables, context) => { - if (context?.previousArticleList) { - queryClient.setQueryData(queryKey, context.previousArticleList); - } - }, +const useDeleteLikeNews = () => { + return useMutation({ + mutationFn: (variables) => newsApi.deleteLikeNews(variables), }); }; -export default useDeleteArticleLike; +export default useDeleteLikeNews; \ No newline at end of file diff --git a/src/apis/news/deleteNews.ts b/src/apis/news/deleteNews.ts index ba0542de..854b6392 100644 --- a/src/apis/news/deleteNews.ts +++ b/src/apis/news/deleteNews.ts @@ -1,50 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { toast } from "@/lib/zustand/useToastStore"; -import type { Article } from "@/types/news"; -import { type ArticleListResponse, NewsQueryKeys, newsApi } from "./api"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { newsApi, NewsResponse, NewsRequest } from "./api"; -type ArticleDeleteMutationContext = { - previousArticleList?: Article[]; -}; - -/** - * @description 아티클 삭제 훅 - */ -const useDeleteArticle = (userId: number | null) => { - const queryClient = useQueryClient(); - const queryKey = [NewsQueryKeys.articleList, userId]; - - return useMutation, number, ArticleDeleteMutationContext>({ - mutationFn: newsApi.deleteArticle, - - onMutate: async (deletedArticleId) => { - await queryClient.cancelQueries({ queryKey }); - - const previousArticleList = queryClient.getQueryData(queryKey); - - queryClient.setQueryData(queryKey, (oldData) => { - if (!oldData) return { newsResponseList: [] }; - return { - newsResponseList: oldData.newsResponseList.filter((article) => article.id !== deletedArticleId), - }; - }); - - return { previousArticleList }; - }, - - onError: (error, _variables, context) => { - if (context?.previousArticleList) { - queryClient.setQueryData(queryKey, context.previousArticleList); - } - toast.error("아티클 삭제에 실패했습니다. 다시 시도해주세요."); - console.error("Failed to delete article:", error); - }, - - onSettled: () => { - queryClient.invalidateQueries({ queryKey }); - }, +const useDeleteNews = () => { + return useMutation({ + mutationFn: (variables) => newsApi.deleteNews(variables), }); }; -export default useDeleteArticle; +export default useDeleteNews; \ No newline at end of file diff --git a/src/apis/news/getNewsList.ts b/src/apis/news/getNewsList.ts index fcbc7832..bd2f587d 100644 --- a/src/apis/news/getNewsList.ts +++ b/src/apis/news/getNewsList.ts @@ -1,25 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { newsApi, NewsListResponse } from "./api"; +import { QueryKeys } from "../queryKeys"; -import type { Article } from "@/types/news"; -import { type ArticleListResponse, NewsQueryKeys, newsApi } from "./api"; - -/** - * @description 아티클 목록 조회 훅 - */ -const useGetArticleList = (userId: number) => { - return useQuery({ - queryKey: [NewsQueryKeys.articleList, userId], - queryFn: () => { - if (userId === null) { - return Promise.reject(new Error("User ID is null")); - } - return newsApi.getArticleList(userId); - }, - staleTime: 1000 * 60 * 10, // 10분 - enabled: userId !== null && userId !== 0, - select: (data) => data.newsResponseList, +const useGetNewsList = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.news.newsList, params], + queryFn: () => newsApi.getNewsList(params ? { params } : {}), }); }; -export default useGetArticleList; +export default useGetNewsList; \ No newline at end of file diff --git a/src/apis/news/index.ts b/src/apis/news/index.ts index 000e3daa..415c3d9f 100644 --- a/src/apis/news/index.ts +++ b/src/apis/news/index.ts @@ -1,15 +1,8 @@ -export type { - ArticleListResponse, - DeleteArticleLikeResponse, - PostArticleLikeResponse, - UsePostAddArticleRequest, - UsePutModifyArticleRequest, -} from "./api"; -export { NewsQueryKeys, newsApi } from "./api"; -export { default as useDeleteArticleLike } from "./deleteLikeNews"; -export { default as useDeleteArticle } from "./deleteNews"; -// News (아티클) hooks -export { default as useGetArticleList } from "./getNewsList"; -export { default as usePostAddArticle } from "./postCreateNews"; -export { default as usePostArticleLike } from "./postLikeNews"; -export { default as usePutModifyArticle } from "./putUpdateNews"; +export { newsApi } from './api'; +export { default as deleteLikeNews } from './deleteLikeNews'; +export { default as deleteNews } from './deleteNews'; +export { default as getNewsList } from './getNewsList'; +export { default as index } from './index'; +export { default as postCreateNews } from './postCreateNews'; +export { default as postLikeNews } from './postLikeNews'; +export { default as putUpdateNews } from './putUpdateNews'; diff --git a/src/apis/news/legacy/deleteLikeNews.CHANGES.md b/src/apis/news/legacy/deleteLikeNews.CHANGES.md new file mode 100644 index 00000000..56950a5b --- /dev/null +++ b/src/apis/news/legacy/deleteLikeNews.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: deleteLikeNews.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/news/{{news-id}}/like +- Method: DELETE +- Function: deleteLikeNews + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `DeleteArticleLikeResponse` +- 현재: `LikeNewsResponse` + +## 권장 조치 + +1. `legacy/deleteLikeNews.ts` 파일의 비즈니스 로직 확인 +2. 새 `deleteLikeNews.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/deleteLikeNews.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/news/legacy/deleteLikeNews.ts b/src/apis/news/legacy/deleteLikeNews.ts new file mode 100644 index 00000000..67898dba --- /dev/null +++ b/src/apis/news/legacy/deleteLikeNews.ts @@ -0,0 +1,51 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import { type ArticleListResponse, type DeleteArticleLikeResponse, NewsQueryKeys, newsApi } from "./api"; + +type ArticleLikeMutationContext = { + previousArticleList?: ArticleListResponse; +}; + +/** + * @description 아티클 좋아요 취소 훅 + */ +const useDeleteArticleLike = (userId: number | null) => { + const queryClient = useQueryClient(); + const queryKey = [NewsQueryKeys.articleList, userId]; + + return useMutation, number, ArticleLikeMutationContext>({ + mutationFn: newsApi.deleteArticleLike, + + onMutate: async (unlikedArticleId) => { + await queryClient.cancelQueries({ queryKey }); + + const previousArticleList = queryClient.getQueryData(queryKey); + + queryClient.setQueryData(queryKey, (oldData) => { + if (!oldData) return { newsResponseList: [] }; + return { + newsResponseList: oldData.newsResponseList.map((article) => + article.id === unlikedArticleId + ? { + ...article, + isLiked: false, + likeCount: Math.max(0, (article.likeCount ?? 1) - 1), + } + : article, + ), + }; + }); + + return { previousArticleList }; + }, + + onError: (_err, _variables, context) => { + if (context?.previousArticleList) { + queryClient.setQueryData(queryKey, context.previousArticleList); + } + }, + }); +}; + +export default useDeleteArticleLike; diff --git a/src/apis/news/legacy/deleteNews.CHANGES.md b/src/apis/news/legacy/deleteNews.CHANGES.md new file mode 100644 index 00000000..28b42ea9 --- /dev/null +++ b/src/apis/news/legacy/deleteNews.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: deleteNews.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/news/{{news-id}} +- Method: DELETE +- Function: deleteNews + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `void` +- 현재: `NewsResponse` + +## 권장 조치 + +1. `legacy/deleteNews.ts` 파일의 비즈니스 로직 확인 +2. 새 `deleteNews.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/deleteNews.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/news/legacy/deleteNews.ts b/src/apis/news/legacy/deleteNews.ts new file mode 100644 index 00000000..ba0542de --- /dev/null +++ b/src/apis/news/legacy/deleteNews.ts @@ -0,0 +1,50 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { toast } from "@/lib/zustand/useToastStore"; +import type { Article } from "@/types/news"; +import { type ArticleListResponse, NewsQueryKeys, newsApi } from "./api"; + +type ArticleDeleteMutationContext = { + previousArticleList?: Article[]; +}; + +/** + * @description 아티클 삭제 훅 + */ +const useDeleteArticle = (userId: number | null) => { + const queryClient = useQueryClient(); + const queryKey = [NewsQueryKeys.articleList, userId]; + + return useMutation, number, ArticleDeleteMutationContext>({ + mutationFn: newsApi.deleteArticle, + + onMutate: async (deletedArticleId) => { + await queryClient.cancelQueries({ queryKey }); + + const previousArticleList = queryClient.getQueryData(queryKey); + + queryClient.setQueryData(queryKey, (oldData) => { + if (!oldData) return { newsResponseList: [] }; + return { + newsResponseList: oldData.newsResponseList.filter((article) => article.id !== deletedArticleId), + }; + }); + + return { previousArticleList }; + }, + + onError: (error, _variables, context) => { + if (context?.previousArticleList) { + queryClient.setQueryData(queryKey, context.previousArticleList); + } + toast.error("아티클 삭제에 실패했습니다. 다시 시도해주세요."); + console.error("Failed to delete article:", error); + }, + + onSettled: () => { + queryClient.invalidateQueries({ queryKey }); + }, + }); +}; + +export default useDeleteArticle; diff --git a/src/apis/news/legacy/getNewsList.CHANGES.md b/src/apis/news/legacy/getNewsList.CHANGES.md new file mode 100644 index 00000000..d646a700 --- /dev/null +++ b/src/apis/news/legacy/getNewsList.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: getNewsList.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/news?author-id=6 +- Method: GET +- Function: getNewsList + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `ArticleListResponse` +- 현재: `NewsListResponse` + +### query-key + +**QueryKey 변경** + +- 이전: `NewsQueryKeys.articleList, userId` +- 현재: `QueryKeys.news.getNewsList, URL, params` + +## 권장 조치 + +1. `legacy/getNewsList.ts` 파일의 비즈니스 로직 확인 +2. 새 `getNewsList.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getNewsList.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/news/legacy/getNewsList.ts b/src/apis/news/legacy/getNewsList.ts new file mode 100644 index 00000000..fcbc7832 --- /dev/null +++ b/src/apis/news/legacy/getNewsList.ts @@ -0,0 +1,25 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import type { Article } from "@/types/news"; +import { type ArticleListResponse, NewsQueryKeys, newsApi } from "./api"; + +/** + * @description 아티클 목록 조회 훅 + */ +const useGetArticleList = (userId: number) => { + return useQuery({ + queryKey: [NewsQueryKeys.articleList, userId], + queryFn: () => { + if (userId === null) { + return Promise.reject(new Error("User ID is null")); + } + return newsApi.getArticleList(userId); + }, + staleTime: 1000 * 60 * 10, // 10분 + enabled: userId !== null && userId !== 0, + select: (data) => data.newsResponseList, + }); +}; + +export default useGetArticleList; diff --git a/src/apis/news/legacy/postCreateNews.CHANGES.md b/src/apis/news/legacy/postCreateNews.CHANGES.md new file mode 100644 index 00000000..2c2fa366 --- /dev/null +++ b/src/apis/news/legacy/postCreateNews.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postCreateNews.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/news +- Method: POST +- Function: postCreateNews + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `Article` +- 현재: `CreateNewsResponse` + +## 권장 조치 + +1. `legacy/postCreateNews.ts` 파일의 비즈니스 로직 확인 +2. 새 `postCreateNews.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postCreateNews.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/news/legacy/postCreateNews.ts b/src/apis/news/legacy/postCreateNews.ts new file mode 100644 index 00000000..95621848 --- /dev/null +++ b/src/apis/news/legacy/postCreateNews.ts @@ -0,0 +1,57 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { toast } from "@/lib/zustand/useToastStore"; +import ArticleThumbUrlPng from "@/public/images/article-thumb.png"; +import type { Article } from "@/types/news"; +import { type ArticleListResponse, NewsQueryKeys, newsApi, type UsePostAddArticleRequest } from "./api"; + +type ArticleMutationContext = { + previousArticleContainer?: ArticleListResponse; +}; + +/** + * @description 아티클 추가 훅 + */ +const usePostAddArticle = (userId: number | null) => { + const queryClient = useQueryClient(); + const queryKey = [NewsQueryKeys.articleList, userId]; + + return useMutation, UsePostAddArticleRequest, ArticleMutationContext>({ + mutationFn: newsApi.postAddArticle, + onMutate: async (newArticle) => { + await queryClient.cancelQueries({ queryKey }); + + const previousArticleContainer = queryClient.getQueryData(queryKey); + + queryClient.setQueryData(queryKey, (oldData) => { + if (!oldData) return { newsResponseList: [] }; + + const optimisticArticle: Article = { + id: Date.now(), // 임시 ID + title: newArticle.title, + description: newArticle.description, + url: newArticle.url || "", + thumbnailUrl: newArticle.file ? URL.createObjectURL(newArticle.file) : ArticleThumbUrlPng.src, + updatedAt: new Date().toISOString(), + }; + + return { + newsResponseList: [optimisticArticle, ...oldData.newsResponseList], + }; + }); + return { previousArticleContainer }; + }, + onError: (error, _variables, context) => { + const errorMessage = error.response?.data?.message || ""; + if (context?.previousArticleContainer) { + queryClient.setQueryData(queryKey, context.previousArticleContainer); + } + toast.error(`아티클 추가에 실패했습니다: ${errorMessage}`); + }, + onSettled: () => { + queryClient.invalidateQueries({ queryKey }); + }, + }); +}; + +export default usePostAddArticle; diff --git a/src/apis/news/legacy/postLikeNews.CHANGES.md b/src/apis/news/legacy/postLikeNews.CHANGES.md new file mode 100644 index 00000000..bd730c03 --- /dev/null +++ b/src/apis/news/legacy/postLikeNews.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postLikeNews.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/news/{{news-id}}/like +- Method: POST +- Function: postLikeNews + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `PostArticleLikeResponse` +- 현재: `LikeNewsResponse` + +## 권장 조치 + +1. `legacy/postLikeNews.ts` 파일의 비즈니스 로직 확인 +2. 새 `postLikeNews.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postLikeNews.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/news/legacy/postLikeNews.ts b/src/apis/news/legacy/postLikeNews.ts new file mode 100644 index 00000000..86adc752 --- /dev/null +++ b/src/apis/news/legacy/postLikeNews.ts @@ -0,0 +1,52 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; + +import type { Article } from "@/types/news"; +import { type ArticleListResponse, NewsQueryKeys, newsApi, type PostArticleLikeResponse } from "./api"; + +type ArticleLikeMutationContext = { + previousArticleList?: Article[]; +}; + +/** + * @description 아티클 좋아요 훅 + */ +const usePostArticleLike = (userId: number | null) => { + const queryClient = useQueryClient(); + const queryKey = [NewsQueryKeys.articleList, userId]; + + return useMutation, number, ArticleLikeMutationContext>({ + mutationFn: newsApi.postArticleLike, + + onMutate: async (likedArticleId) => { + await queryClient.cancelQueries({ queryKey }); + + const previousArticleList = queryClient.getQueryData(queryKey); + + queryClient.setQueryData(queryKey, (oldData) => { + if (!oldData) return { newsResponseList: [] }; + return { + newsResponseList: oldData.newsResponseList.map((article) => + article.id === likedArticleId + ? { + ...article, + isLiked: true, + likeCount: (article.likeCount ?? 0) + 1, + } + : article, + ), + }; + }); + + return { previousArticleList }; + }, + + onError: (_err, _variables, context) => { + if (context?.previousArticleList) { + queryClient.setQueryData(queryKey, context.previousArticleList); + } + }, + }); +}; + +export default usePostArticleLike; diff --git a/src/apis/news/legacy/putUpdateNews.CHANGES.md b/src/apis/news/legacy/putUpdateNews.CHANGES.md new file mode 100644 index 00000000..cb010e9d --- /dev/null +++ b/src/apis/news/legacy/putUpdateNews.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: putUpdateNews.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/news/{{news-id}} +- Method: PUT +- Function: putUpdateNews + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `Article` +- 현재: `UpdateNewsResponse` + +## 권장 조치 + +1. `legacy/putUpdateNews.ts` 파일의 비즈니스 로직 확인 +2. 새 `putUpdateNews.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/putUpdateNews.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/news/legacy/putUpdateNews.ts b/src/apis/news/legacy/putUpdateNews.ts new file mode 100644 index 00000000..614bc5d6 --- /dev/null +++ b/src/apis/news/legacy/putUpdateNews.ts @@ -0,0 +1,59 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { toast } from "@/lib/zustand/useToastStore"; +import type { Article } from "@/types/news"; +import { type ArticleListResponse, NewsQueryKeys, newsApi, type UsePutModifyArticleRequest } from "./api"; + +type ArticleMutationContext = { + previousArticleList?: Article[]; +}; + +/** + * @description 아티클 수정 훅 + */ +const usePutModifyArticle = (userId: number | null) => { + const queryClient = useQueryClient(); + const queryKey = [NewsQueryKeys.articleList, userId]; + + return useMutation, UsePutModifyArticleRequest, ArticleMutationContext>({ + mutationFn: newsApi.putModifyArticle, + onMutate: async (variables) => { + await queryClient.cancelQueries({ queryKey }); + const previousArticleList = queryClient.getQueryData(queryKey); + + queryClient.setQueryData(queryKey, (oldData) => { + if (!oldData) return { newsResponseList: [] }; + + return { + newsResponseList: oldData.newsResponseList.map((article) => { + if (article.id === variables.articleId) { + const optimisticData = variables.body; + + return { + ...article, + title: optimisticData.title, + description: optimisticData.description, + url: optimisticData.url || "", + thumbnailUrl: optimisticData.file ? URL.createObjectURL(optimisticData.file) : article.thumbnailUrl, + }; + } + return article; + }), + }; + }); + return { previousArticleList }; + }, + onError: (error, _variables, context) => { + const errorMessage = error.response?.data?.message || ""; + if (context?.previousArticleList) { + queryClient.setQueryData(queryKey, context.previousArticleList); + } + toast.error(`아티클 수정에 실패했습니다.${errorMessage}`); + }, + onSettled: () => { + queryClient.invalidateQueries({ queryKey }); + }, + }); +}; + +export default usePutModifyArticle; diff --git a/src/apis/news/postCreateNews.ts b/src/apis/news/postCreateNews.ts index 95621848..075351f2 100644 --- a/src/apis/news/postCreateNews.ts +++ b/src/apis/news/postCreateNews.ts @@ -1,57 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { toast } from "@/lib/zustand/useToastStore"; -import ArticleThumbUrlPng from "@/public/images/article-thumb.png"; -import type { Article } from "@/types/news"; -import { type ArticleListResponse, NewsQueryKeys, newsApi, type UsePostAddArticleRequest } from "./api"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { newsApi, CreateNewsResponse, CreateNewsRequest } from "./api"; -type ArticleMutationContext = { - previousArticleContainer?: ArticleListResponse; -}; - -/** - * @description 아티클 추가 훅 - */ -const usePostAddArticle = (userId: number | null) => { - const queryClient = useQueryClient(); - const queryKey = [NewsQueryKeys.articleList, userId]; - - return useMutation, UsePostAddArticleRequest, ArticleMutationContext>({ - mutationFn: newsApi.postAddArticle, - onMutate: async (newArticle) => { - await queryClient.cancelQueries({ queryKey }); - - const previousArticleContainer = queryClient.getQueryData(queryKey); - - queryClient.setQueryData(queryKey, (oldData) => { - if (!oldData) return { newsResponseList: [] }; - - const optimisticArticle: Article = { - id: Date.now(), // 임시 ID - title: newArticle.title, - description: newArticle.description, - url: newArticle.url || "", - thumbnailUrl: newArticle.file ? URL.createObjectURL(newArticle.file) : ArticleThumbUrlPng.src, - updatedAt: new Date().toISOString(), - }; - - return { - newsResponseList: [optimisticArticle, ...oldData.newsResponseList], - }; - }); - return { previousArticleContainer }; - }, - onError: (error, _variables, context) => { - const errorMessage = error.response?.data?.message || ""; - if (context?.previousArticleContainer) { - queryClient.setQueryData(queryKey, context.previousArticleContainer); - } - toast.error(`아티클 추가에 실패했습니다: ${errorMessage}`); - }, - onSettled: () => { - queryClient.invalidateQueries({ queryKey }); - }, +const usePostCreateNews = () => { + return useMutation({ + mutationFn: (data) => newsApi.postCreateNews({ data }), }); }; -export default usePostAddArticle; +export default usePostCreateNews; \ No newline at end of file diff --git a/src/apis/news/postLikeNews.ts b/src/apis/news/postLikeNews.ts index 86adc752..9aaf4c53 100644 --- a/src/apis/news/postLikeNews.ts +++ b/src/apis/news/postLikeNews.ts @@ -1,52 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { newsApi, LikeNewsResponse, LikeNewsRequest } from "./api"; -import type { Article } from "@/types/news"; -import { type ArticleListResponse, NewsQueryKeys, newsApi, type PostArticleLikeResponse } from "./api"; - -type ArticleLikeMutationContext = { - previousArticleList?: Article[]; -}; - -/** - * @description 아티클 좋아요 훅 - */ -const usePostArticleLike = (userId: number | null) => { - const queryClient = useQueryClient(); - const queryKey = [NewsQueryKeys.articleList, userId]; - - return useMutation, number, ArticleLikeMutationContext>({ - mutationFn: newsApi.postArticleLike, - - onMutate: async (likedArticleId) => { - await queryClient.cancelQueries({ queryKey }); - - const previousArticleList = queryClient.getQueryData(queryKey); - - queryClient.setQueryData(queryKey, (oldData) => { - if (!oldData) return { newsResponseList: [] }; - return { - newsResponseList: oldData.newsResponseList.map((article) => - article.id === likedArticleId - ? { - ...article, - isLiked: true, - likeCount: (article.likeCount ?? 0) + 1, - } - : article, - ), - }; - }); - - return { previousArticleList }; - }, - - onError: (_err, _variables, context) => { - if (context?.previousArticleList) { - queryClient.setQueryData(queryKey, context.previousArticleList); - } - }, +const usePostLikeNews = () => { + return useMutation({ + mutationFn: (variables) => newsApi.postLikeNews(variables), }); }; -export default usePostArticleLike; +export default usePostLikeNews; \ No newline at end of file diff --git a/src/apis/news/putUpdateNews.ts b/src/apis/news/putUpdateNews.ts index 614bc5d6..d7fedea7 100644 --- a/src/apis/news/putUpdateNews.ts +++ b/src/apis/news/putUpdateNews.ts @@ -1,59 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { toast } from "@/lib/zustand/useToastStore"; -import type { Article } from "@/types/news"; -import { type ArticleListResponse, NewsQueryKeys, newsApi, type UsePutModifyArticleRequest } from "./api"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { newsApi, UpdateNewsResponse, UpdateNewsRequest } from "./api"; -type ArticleMutationContext = { - previousArticleList?: Article[]; -}; - -/** - * @description 아티클 수정 훅 - */ -const usePutModifyArticle = (userId: number | null) => { - const queryClient = useQueryClient(); - const queryKey = [NewsQueryKeys.articleList, userId]; - - return useMutation, UsePutModifyArticleRequest, ArticleMutationContext>({ - mutationFn: newsApi.putModifyArticle, - onMutate: async (variables) => { - await queryClient.cancelQueries({ queryKey }); - const previousArticleList = queryClient.getQueryData(queryKey); - - queryClient.setQueryData(queryKey, (oldData) => { - if (!oldData) return { newsResponseList: [] }; - - return { - newsResponseList: oldData.newsResponseList.map((article) => { - if (article.id === variables.articleId) { - const optimisticData = variables.body; - - return { - ...article, - title: optimisticData.title, - description: optimisticData.description, - url: optimisticData.url || "", - thumbnailUrl: optimisticData.file ? URL.createObjectURL(optimisticData.file) : article.thumbnailUrl, - }; - } - return article; - }), - }; - }); - return { previousArticleList }; - }, - onError: (error, _variables, context) => { - const errorMessage = error.response?.data?.message || ""; - if (context?.previousArticleList) { - queryClient.setQueryData(queryKey, context.previousArticleList); - } - toast.error(`아티클 수정에 실패했습니다.${errorMessage}`); - }, - onSettled: () => { - queryClient.invalidateQueries({ queryKey }); - }, +const usePutUpdateNews = () => { + return useMutation({ + mutationFn: (variables) => newsApi.putUpdateNews(variables), }); }; -export default usePutModifyArticle; +export default usePutUpdateNews; \ No newline at end of file diff --git a/src/apis/queryKeys.ts b/src/apis/queryKeys.ts index 3963ad5a..c9d4ac43 100644 --- a/src/apis/queryKeys.ts +++ b/src/apis/queryKeys.ts @@ -5,128 +5,128 @@ export const QueryKeys = { Auth: { - folder: "Auth.folder" as const, - signOut: "Auth.signOut" as const, - appleAuth: "Auth.appleAuth" as const, - refreshToken: "Auth.refreshToken" as const, - emailLogin: "Auth.emailLogin" as const, - emailVerification: "Auth.emailVerification" as const, - kakaoAuth: "Auth.kakaoAuth" as const, - account: "Auth.account" as const, - signUp: "Auth.signUp" as const, + folder: 'Auth.folder' as const, + signOut: 'Auth.signOut' as const, + appleAuth: 'Auth.appleAuth' as const, + refreshToken: 'Auth.refreshToken' as const, + emailLogin: 'Auth.emailLogin' as const, + emailVerification: 'Auth.emailVerification' as const, + kakaoAuth: 'Auth.kakaoAuth' as const, + account: 'Auth.account' as const, + signUp: 'Auth.signUp' as const, }, news: { - folder: "news.folder" as const, - newsList: "news.newsList" as const, - news: "news.news" as const, - updateNews: "news.updateNews" as const, - likeNews: "news.likeNews" as const, - createNews: "news.createNews" as const, + folder: 'news.folder' as const, + newsList: 'news.newsList' as const, + news: 'news.news' as const, + updateNews: 'news.updateNews' as const, + likeNews: 'news.likeNews' as const, + createNews: 'news.createNews' as const, }, reports: { - folder: "reports.folder" as const, - report: "reports.report" as const, + folder: 'reports.folder' as const, + report: 'reports.report' as const, }, chat: { - folder: "chat.folder" as const, - chatMessages: "chat.chatMessages" as const, - chatRooms: "chat.chatRooms" as const, - readChatRoom: "chat.readChatRoom" as const, - chatPartner: "chat.chatPartner" as const, + folder: 'chat.folder' as const, + chatMessages: 'chat.chatMessages' as const, + chatRooms: 'chat.chatRooms' as const, + readChatRoom: 'chat.readChatRoom' as const, + chatPartner: 'chat.chatPartner' as const, }, universities: { - folder: "universities.folder" as const, - recommendedUniversities: "universities.recommendedUniversities" as const, - wishList: "universities.wishList" as const, - wish: "universities.wish" as const, - addWish: "universities.addWish" as const, - isWish: "universities.isWish" as const, - universityDetail: "universities.universityDetail" as const, - searchText: "universities.searchText" as const, - searchFilter: "universities.searchFilter" as const, - byRegionCountry: "universities.byRegionCountry" as const, + folder: 'universities.folder' as const, + recommendedUniversities: 'universities.recommendedUniversities' as const, + wishList: 'universities.wishList' as const, + wish: 'universities.wish' as const, + addWish: 'universities.addWish' as const, + isWish: 'universities.isWish' as const, + universityDetail: 'universities.universityDetail' as const, + searchText: 'universities.searchText' as const, + byRegionCountry: 'universities.byRegionCountry' as const, }, MyPage: { - folder: "MyPage.folder" as const, - interestedRegionCountry: "MyPage.interestedRegionCountry" as const, - profile: "MyPage.profile" as const, - password: "MyPage.password" as const, + folder: 'MyPage.folder' as const, + interestedRegionCountry: 'MyPage.interestedRegionCountry' as const, + profile: 'MyPage.profile' as const, + password: 'MyPage.password' as const, }, applications: { - folder: "applications.folder" as const, - competitors: "applications.competitors" as const, - submitApplication: "applications.submitApplication" as const, - applicants: "applications.applicants" as const, + folder: 'applications.folder' as const, + competitors: 'applications.competitors' as const, + submitApplication: 'applications.submitApplication' as const, + applicants: 'applications.applicants' as const, }, community: { - folder: "community.folder" as const, - boardList: "community.boardList" as const, - board: "community.board" as const, - comment: "community.comment" as const, - updateComment: "community.updateComment" as const, - createComment: "community.createComment" as const, - post: "community.post" as const, - updatePost: "community.updatePost" as const, - createPost: "community.createPost" as const, - postDetail: "community.postDetail" as const, - likePost: "community.likePost" as const, + folder: 'community.folder' as const, + boardList: 'community.boardList' as const, + board: 'community.board' as const, + comment: 'community.comment' as const, + updateComment: 'community.updateComment' as const, + createComment: 'community.createComment' as const, + post: 'community.post' as const, + updatePost: 'community.updatePost' as const, + createPost: 'community.createPost' as const, + postDetail: 'community.postDetail' as const, + likePost: 'community.likePost' as const, }, Scores: { - folder: "Scores.folder" as const, - createLanguageTest: "Scores.createLanguageTest" as const, - languageTestList: "Scores.languageTestList" as const, - createGpa: "Scores.createGpa" as const, - gpaList: "Scores.gpaList" as const, + folder: 'Scores.folder' as const, + createLanguageTest: 'Scores.createLanguageTest' as const, + languageTestList: 'Scores.languageTestList' as const, + createGpa: 'Scores.createGpa' as const, + gpaList: 'Scores.gpaList' as const, }, Admin: { - folder: "Admin.folder" as const, - verifyLanguageTest: "Admin.verifyLanguageTest" as const, - languageTestList: "Admin.languageTestList" as const, - verifyGpa: "Admin.verifyGpa" as const, - gpaList: "Admin.gpaList" as const, + folder: 'Admin.folder' as const, + verifyLanguageTest: 'Admin.verifyLanguageTest' as const, + languageTestList: 'Admin.languageTestList' as const, + verifyGpa: 'Admin.verifyGpa' as const, + gpaList: 'Admin.gpaList' as const, }, users: { - folder: "users.folder" as const, - nicknameExists: "users.nicknameExists" as const, - blockUser: "users.blockUser" as const, - unblockUser: "users.unblockUser" as const, - blockedUsers: "users.blockedUsers" as const, + folder: 'users.folder' as const, + nicknameExists: 'users.nicknameExists' as const, + blockUser: 'users.blockUser' as const, + unblockUser: 'users.unblockUser' as const, + blockedUsers: 'users.blockedUsers' as const, }, mentor: { - folder: "mentor.folder" as const, - matchedMentors: "mentor.matchedMentors" as const, - applyMentoring: "mentor.applyMentoring" as const, - confirmMentoring: "mentor.confirmMentoring" as const, - appliedMentorings: "mentor.appliedMentorings" as const, - mentorList: "mentor.mentorList" as const, - mentorDetail: "mentor.mentorDetail" as const, - myMentorPage: "mentor.myMentorPage" as const, - updateMyMentorPage: "mentor.updateMyMentorPage" as const, - mentoringStatus: "mentor.mentoringStatus" as const, - receivedMentorings: "mentor.receivedMentorings" as const, - unconfirmedMentoringCount: "mentor.unconfirmedMentoringCount" as const, - }, - "kakao-api": { - folder: "kakao-api.folder" as const, - kakaoUserIds: "kakao-api.kakaoUserIds" as const, - kakaoUnlink: "kakao-api.kakaoUnlink" as const, - kakaoInfo: "kakao-api.kakaoInfo" as const, - }, - "collection.bru": { - collection: "collection.bru.collection" as const, + folder: 'mentor.folder' as const, + matchedMentors: 'mentor.matchedMentors' as const, + applyMentoring: 'mentor.applyMentoring' as const, + confirmMentoring: 'mentor.confirmMentoring' as const, + appliedMentorings: 'mentor.appliedMentorings' as const, + mentorList: 'mentor.mentorList' as const, + mentorDetail: 'mentor.mentorDetail' as const, + myMentorPage: 'mentor.myMentorPage' as const, + updateMyMentorPage: 'mentor.updateMyMentorPage' as const, + mentoringStatus: 'mentor.mentoringStatus' as const, + receivedMentorings: 'mentor.receivedMentorings' as const, + unconfirmedMentoringCount: 'mentor.unconfirmedMentoringCount' as const, + }, + 'kakao-api': { + folder: 'kakao-api.folder' as const, + kakaoUserIds: 'kakao-api.kakaoUserIds' as const, + kakaoUnlink: 'kakao-api.kakaoUnlink' as const, + kakaoInfo: 'kakao-api.kakaoInfo' as const, + }, + 'collection.bru': { + collection: 'collection.bru.collection' as const, }, environments: { - dev: "environments.dev" as const, - local: "environments.local" as const, - }, - "image-upload": { - folder: "image-upload.folder" as const, - slackNotification: "image-upload.slackNotification" as const, - uploadLanguageTestReport: "image-upload.uploadLanguageTestReport" as const, - uploadProfileImage: "image-upload.uploadProfileImage" as const, - uploadProfileImageBeforeSignup: "image-upload.uploadProfileImageBeforeSignup" as const, - uploadGpaReport: "image-upload.uploadGpaReport" as const, + dev: 'environments.dev' as const, + local: 'environments.local' as const, + prod: 'environments.prod' as const, + }, + 'image-upload': { + folder: 'image-upload.folder' as const, + slackNotification: 'image-upload.slackNotification' as const, + uploadLanguageTestReport: 'image-upload.uploadLanguageTestReport' as const, + uploadProfileImage: 'image-upload.uploadProfileImage' as const, + uploadProfileImageBeforeSignup: 'image-upload.uploadProfileImageBeforeSignup' as const, + uploadGpaReport: 'image-upload.uploadGpaReport' as const, }, } as const; -export type QueryKey = (typeof QueryKeys)[keyof typeof QueryKeys]; +export type QueryKey = typeof QueryKeys[keyof typeof QueryKeys]; \ No newline at end of file diff --git a/src/apis/reports/api.ts b/src/apis/reports/api.ts index c1417589..39bd649c 100644 --- a/src/apis/reports/api.ts +++ b/src/apis/reports/api.ts @@ -1,21 +1,15 @@ -import type { AxiosResponse } from "axios"; -import type { ReportType } from "@/types/reports"; import { axiosInstance } from "@/utils/axiosInstance"; -// ====== Types ====== -export interface UsePostReportsRequest { - targetType: "POST"; // 지금은 게시글 신고 기능만 존재 - targetId: number; // 신고하려는 리소스의 ID - reportType: ReportType; -} +export type ReportResponse = Record; + +export type ReportRequest = Record; -// ====== API Functions ====== export const reportsApi = { - /** - * 신고 등록 - */ - postReport: async (body: UsePostReportsRequest): Promise => { - const response: AxiosResponse = await axiosInstance.post(`/reports`, body); - return response.data; + postReport: async (params: { data?: ReportRequest }): Promise => { + const res = await axiosInstance.post( + `/reports`, params?.data + ); + return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/reports/index.ts b/src/apis/reports/index.ts index 25277463..34b11506 100644 --- a/src/apis/reports/index.ts +++ b/src/apis/reports/index.ts @@ -1,3 +1,3 @@ -export type { UsePostReportsRequest } from "./api"; -export { reportsApi } from "./api"; -export { default as usePostReports } from "./postReport"; +export { reportsApi } from './api'; +export { default as index } from './index'; +export { default as postReport } from './postReport'; diff --git a/src/apis/reports/legacy/postReport.CHANGES.md b/src/apis/reports/legacy/postReport.CHANGES.md new file mode 100644 index 00000000..ef96ded6 --- /dev/null +++ b/src/apis/reports/legacy/postReport.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postReport.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/reports +- Method: POST +- Function: postReport + +## 변경 내용 + +### response-type + +**Response 타입 변경** + +- 이전: `void` +- 현재: `ReportResponse` + +## 권장 조치 + +1. `legacy/postReport.ts` 파일의 비즈니스 로직 확인 +2. 새 `postReport.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postReport.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/reports/legacy/postReport.ts b/src/apis/reports/legacy/postReport.ts new file mode 100644 index 00000000..acb3f013 --- /dev/null +++ b/src/apis/reports/legacy/postReport.ts @@ -0,0 +1,26 @@ +import { useMutation } from "@tanstack/react-query"; + +import type { AxiosError } from "axios"; +import { useRouter } from "next/navigation"; + +import { toast } from "@/lib/zustand/useToastStore"; +import { reportsApi, type UsePostReportsRequest } from "./api"; + +/** + * @description 신고 등록 훅 + */ +const usePostReports = () => { + const router = useRouter(); + return useMutation, UsePostReportsRequest>({ + mutationFn: reportsApi.postReport, + onSuccess: () => { + toast.success("신고가 성공적으로 등록되었습니다."); + router.back(); + }, + onError: (_error) => { + toast.error("신고 등록에 실패했습니다. 잠시 후 다시 시도해주세요."); + }, + }); +}; + +export default usePostReports; diff --git a/src/apis/reports/postReport.ts b/src/apis/reports/postReport.ts index acb3f013..76fd804f 100644 --- a/src/apis/reports/postReport.ts +++ b/src/apis/reports/postReport.ts @@ -1,26 +1,11 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; +import { reportsApi, ReportResponse, ReportRequest } from "./api"; -import type { AxiosError } from "axios"; -import { useRouter } from "next/navigation"; - -import { toast } from "@/lib/zustand/useToastStore"; -import { reportsApi, type UsePostReportsRequest } from "./api"; - -/** - * @description 신고 등록 훅 - */ -const usePostReports = () => { - const router = useRouter(); - return useMutation, UsePostReportsRequest>({ - mutationFn: reportsApi.postReport, - onSuccess: () => { - toast.success("신고가 성공적으로 등록되었습니다."); - router.back(); - }, - onError: (_error) => { - toast.error("신고 등록에 실패했습니다. 잠시 후 다시 시도해주세요."); - }, +const usePostReport = () => { + return useMutation({ + mutationFn: (data) => reportsApi.postReport({ data }), }); }; -export default usePostReports; +export default usePostReport; \ No newline at end of file diff --git a/src/apis/universities/api.ts b/src/apis/universities/api.ts index cde9f708..35419bc6 100644 --- a/src/apis/universities/api.ts +++ b/src/apis/universities/api.ts @@ -1,4 +1,4 @@ -import { axiosInstance, publicAxiosInstance } from "@/utils/axiosInstance"; +import { axiosInstance } from "@/utils/axiosInstance"; export interface RecommendedUniversitiesResponseRecommendedUniversitiesItem { id: number; @@ -39,17 +39,17 @@ export interface WishListResponseItemLanguageRequirementsItem { } export interface WishListResponse { - 0: WishListResponseItem[]; - 1: WishListResponseItem[]; + 0: WishListResponse0; + 1: WishListResponse1; } -export type WishResponse = undefined; +export type WishResponse = void; -export type AddWishResponse = undefined; +export type AddWishResponse = void; export type AddWishRequest = Record; -export type IsWishResponse = undefined; +export type IsWishResponse = void; export interface UniversityDetailResponseLanguageRequirementsItem { languageTestType: string; @@ -89,6 +89,7 @@ export interface SearchTextResponseUnivApplyInfoPreviewsItem { id: number; term: string; koreanName: string; + homeUniversityName: string; region: string; country: string; logoImageUrl: string; @@ -106,88 +107,63 @@ export interface SearchTextResponse { univApplyInfoPreviews: SearchTextResponseUnivApplyInfoPreviewsItem[]; } -export interface SearchFilterResponseUnivApplyInfoPreviewsItem { - id: number; - term: string; - koreanName: string; - region: string; - country: string; - logoImageUrl: string; - backgroundImageUrl: string; - studentCapacity: number; - languageRequirements: SearchFilterResponseUnivApplyInfoPreviewsItemLanguageRequirementsItem[]; -} - -export interface SearchFilterResponseUnivApplyInfoPreviewsItemLanguageRequirementsItem { - languageTestType: string; - minScore: string; -} - -export interface SearchFilterResponse { - univApplyInfoPreviews: SearchFilterResponseUnivApplyInfoPreviewsItem[]; -} - -export type ByRegionCountryResponse = undefined; +export type ByRegionCountryResponse = void; export const universitiesApi = { - getRecommendedUniversities: async (params?: { isLogin?: boolean }): Promise => { - const instance = params?.isLogin ? axiosInstance : publicAxiosInstance; - const res = await instance.get(`/univ-apply-infos/recommend`); + getRecommendedUniversities: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/univ-apply-infos/recommend`, { params: params?.params } + ); return res.data; }, getWishList: async (params: { params?: Record }): Promise => { - const res = await axiosInstance.get(`/univ-apply-infos/like`, { params: params?.params }); + const res = await axiosInstance.get( + `/univ-apply-infos/like`, { params: params?.params } + ); return res.data; }, deleteWish: async (params: { univApplyInfoId: string | number }): Promise => { - const res = await axiosInstance.delete(`/univ-apply-infos/${params.univApplyInfoId}/like`); + const res = await axiosInstance.delete( + `/univ-apply-infos/${params.univApplyInfoId}/like` + ); return res.data; }, - postAddWish: async (params: { - univApplyInfoId: string | number; - data?: AddWishRequest; - }): Promise => { + postAddWish: async (params: { univApplyInfoId: string | number, data?: AddWishRequest }): Promise => { const res = await axiosInstance.post( - `/univ-apply-infos/${params.univApplyInfoId}/like`, - params?.data, + `/univ-apply-infos/${params.univApplyInfoId}/like`, params?.data ); return res.data; }, - getIsWish: async (params: { - univApplyInfoId: string | number; - params?: Record; - }): Promise => { - const res = await axiosInstance.get(`/univ-apply-infos/${params.univApplyInfoId}/like`, { - params: params?.params, - }); - return res.data; - }, - - getUniversityDetail: async (params: { univApplyInfoId: string | number }): Promise => { - const res = await publicAxiosInstance.get(`/univ-apply-infos/${params.univApplyInfoId}`); + getIsWish: async (params: { univApplyInfoId: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/univ-apply-infos/${params.univApplyInfoId}/like`, { params: params?.params } + ); return res.data; }, - getSearchText: async (params?: { value?: string }): Promise => { - const res = await publicAxiosInstance.get(`/univ-apply-infos/search/text`, { - params: { value: params?.value ?? "" }, - }); + getUniversityDetail: async (params: { univApplyInfoId: string | number, params?: Record }): Promise => { + const res = await axiosInstance.get( + `/univ-apply-infos/${params.univApplyInfoId}`, { params: params?.params } + ); return res.data; }, - getSearchFilter: async (params?: { params?: Record }): Promise => { - const res = await publicAxiosInstance.get(`/univ-apply-infos/search/filter`, { - params: params?.params, - }); + getSearchText: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get( + `/univ-apply-infos/search/text?value=일본`, { params: params?.params } + ); return res.data; }, getByRegionCountry: async (params: { params?: Record }): Promise => { - const res = await axiosInstance.get(`/universities/search`, { params: params?.params }); + const res = await axiosInstance.get( + `/universities/search`, { params: params?.params } + ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/universities/deleteWish.ts b/src/apis/universities/deleteWish.ts index c76c58ec..e4c88b1f 100644 --- a/src/apis/universities/deleteWish.ts +++ b/src/apis/universities/deleteWish.ts @@ -1,20 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { QueryKeys } from "../queryKeys"; -import { universitiesApi, type WishResponse } from "./api"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { universitiesApi, WishResponse, WishRequest } from "./api"; -/** - * @description 위시리스트에서 학교를 삭제하는 useMutation 커스텀 훅 - */ const useDeleteWish = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: (universityInfoForApplyId) => universitiesApi.deleteWish({ univApplyInfoId: universityInfoForApplyId }), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: [QueryKeys.universities.wishList] }); - }, + return useMutation({ + mutationFn: (variables) => universitiesApi.deleteWish(variables), }); }; -export default useDeleteWish; +export default useDeleteWish; \ No newline at end of file diff --git a/src/apis/universities/getByRegionCountry.ts b/src/apis/universities/getByRegionCountry.ts index 43e04cbf..baa84596 100644 --- a/src/apis/universities/getByRegionCountry.ts +++ b/src/apis/universities/getByRegionCountry.ts @@ -1,7 +1,7 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { universitiesApi, ByRegionCountryResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type ByRegionCountryResponse, universitiesApi } from "./api"; const useGetByRegionCountry = (params?: Record) => { return useQuery({ @@ -10,4 +10,4 @@ const useGetByRegionCountry = (params?: Record) => { }); }; -export default useGetByRegionCountry; +export default useGetByRegionCountry; \ No newline at end of file diff --git a/src/apis/universities/getIsWish.ts b/src/apis/universities/getIsWish.ts index a1d54a65..567a0887 100644 --- a/src/apis/universities/getIsWish.ts +++ b/src/apis/universities/getIsWish.ts @@ -1,7 +1,7 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { universitiesApi, IsWishResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type IsWishResponse, universitiesApi } from "./api"; const useGetIsWish = (univApplyInfoId: string | number, params?: Record) => { return useQuery({ @@ -11,4 +11,4 @@ const useGetIsWish = (univApplyInfoId: string | number, params?: Record { - return useQuery({ - queryKey: [QueryKeys.universities.recommendedUniversities, isLogin], - queryFn: () => universitiesApi.getRecommendedUniversities({ isLogin }), - staleTime: 1000 * 60 * 5, - select: (data) => data.recommendedUniversities as unknown as ListUniversity[], +const useGetRecommendedUniversities = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.universities.recommendedUniversities, params], + queryFn: () => universitiesApi.getRecommendedUniversities(params ? { params } : {}), }); }; -export default useGetRecommendedUniversities; +export default useGetRecommendedUniversities; \ No newline at end of file diff --git a/src/apis/universities/getSearchText.ts b/src/apis/universities/getSearchText.ts index ad2bab9d..30967c5e 100644 --- a/src/apis/universities/getSearchText.ts +++ b/src/apis/universities/getSearchText.ts @@ -1,53 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; - -import type { AxiosError } from "axios"; -import { useMemo } from "react"; -import type { ListUniversity } from "@/types/university"; +import { universitiesApi, SearchTextResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type SearchTextResponse, universitiesApi } from "./api"; -/** - * @description 대학 검색을 위한 useQuery 커스텀 훅 - * 모든 대학 데이터를 한 번만 가져와 캐싱하고, 검색어에 따라 클라이언트에서 필터링합니다. - * @param searchValue - 검색어 - */ -const useUniversitySearch = (searchValue: string) => { - // 1. 모든 대학 데이터를 한 번만 가져와 'Infinity' 캐시로 저장합니다. - const { - data: allUniversities, - isLoading, - isError, - error, - } = useQuery({ - queryKey: [QueryKeys.universities.searchText], - queryFn: () => universitiesApi.getSearchText({ value: "" }), - staleTime: Infinity, - gcTime: Infinity, - select: (data) => data.univApplyInfoPreviews as unknown as ListUniversity[], +const useGetSearchText = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.universities.searchText, params], + queryFn: () => universitiesApi.getSearchText(params ? { params } : {}), }); - - // 2. 검색어가 변경될 때만 캐시된 데이터를 필터링합니다. - const filteredUniversities = useMemo(() => { - const normalizedSearchValue = searchValue.trim().toLowerCase(); - - if (!normalizedSearchValue) { - return allUniversities; - } - - if (!allUniversities) { - return []; - } - - return allUniversities.filter((university) => university.koreanName.toLowerCase().includes(normalizedSearchValue)); - }, [allUniversities, searchValue]); - - return { - data: filteredUniversities, - isLoading, - isError, - error, - totalCount: allUniversities?.length || 0, - }; }; -export default useUniversitySearch; +export default useGetSearchText; \ No newline at end of file diff --git a/src/apis/universities/getUniversityDetail.ts b/src/apis/universities/getUniversityDetail.ts index e5a3c6d1..f5601ea6 100644 --- a/src/apis/universities/getUniversityDetail.ts +++ b/src/apis/universities/getUniversityDetail.ts @@ -1,20 +1,14 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import type { University } from "@/types/university"; +import { universitiesApi, UniversityDetailResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type UniversityDetailResponse, universitiesApi } from "./api"; -/** - * @description 대학 상세 조회를 위한 useQuery 커스텀 훅 - * @param universityInfoForApplyId - 대학 ID - */ -const useGetUniversityDetail = (universityInfoForApplyId: number) => { - return useQuery({ - queryKey: [QueryKeys.universities.universityDetail, universityInfoForApplyId], - queryFn: () => universitiesApi.getUniversityDetail({ univApplyInfoId: universityInfoForApplyId }), - enabled: !!universityInfoForApplyId, - select: (data) => data as unknown as University, +const useGetUniversityDetail = (univApplyInfoId: string | number, params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.universities.universityDetail, univApplyInfoId, params], + queryFn: () => universitiesApi.getUniversityDetail({ univApplyInfoId, params }), + enabled: !!univApplyInfoId, }); }; -export default useGetUniversityDetail; +export default useGetUniversityDetail; \ No newline at end of file diff --git a/src/apis/universities/getWishList.ts b/src/apis/universities/getWishList.ts index 3bd08cf7..5c9f238e 100644 --- a/src/apis/universities/getWishList.ts +++ b/src/apis/universities/getWishList.ts @@ -1,21 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import type { ListUniversity } from "@/types/university"; +import { universitiesApi, WishListResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { universitiesApi, type WishListResponse } from "./api"; -/** - * @description 내 위시리스트 대학 목록 조회를 위한 useQuery 커스텀 훅 - * @param enabled - 쿼리 활성화 여부 - */ -const useGetWishList = (enabled: boolean = true) => { - return useQuery({ - queryKey: [QueryKeys.universities.wishList], - queryFn: () => universitiesApi.getWishList({}), - staleTime: 1000 * 60 * 5, - select: (data) => data as unknown as ListUniversity[], - enabled, +const useGetWishList = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.universities.wishList, params], + queryFn: () => universitiesApi.getWishList(params ? { params } : {}), }); }; -export default useGetWishList; +export default useGetWishList; \ No newline at end of file diff --git a/src/apis/universities/index.ts b/src/apis/universities/index.ts index 95a44032..24970ba9 100644 --- a/src/apis/universities/index.ts +++ b/src/apis/universities/index.ts @@ -1,10 +1,11 @@ -export { universitiesApi } from "./api"; -export { default as useDeleteWish } from "./deleteWish"; -export { default as useGetByRegionCountry } from "./getByRegionCountry"; -export { default as useGetIsWish } from "./getIsWish"; -export { default as useGetRecommendedUniversities } from "./getRecommendedUniversities"; -export { default as useGetUniversitySearchByFilter, type UniversitySearchFilterParams } from "./getSearchFilter"; -export { default as useUniversitySearch } from "./getSearchText"; -export { default as useGetUniversityDetail } from "./getUniversityDetail"; -export { default as useGetWishList } from "./getWishList"; -export { default as usePostAddWish } from "./postAddWish"; +export { universitiesApi } from './api'; +export { default as deleteWish } from './deleteWish'; +export { default as getByRegionCountry } from './getByRegionCountry'; +export { default as getIsWish } from './getIsWish'; +export { default as getRecommendedUniversities } from './getRecommendedUniversities'; +export { default as getSearchFilter } from './getSearchFilter'; +export { default as getSearchText } from './getSearchText'; +export { default as getUniversityDetail } from './getUniversityDetail'; +export { default as getWishList } from './getWishList'; +export { default as index } from './index'; +export { default as postAddWish } from './postAddWish'; diff --git a/src/apis/universities/legacy/deleteWish.CHANGES.md b/src/apis/universities/legacy/deleteWish.CHANGES.md new file mode 100644 index 00000000..8e5f3765 --- /dev/null +++ b/src/apis/universities/legacy/deleteWish.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: deleteWish.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/univ-apply-infos/{{univ-apply-info-id}}/like +- Method: DELETE +- Function: deleteWish + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.universities.wishList` +- 현재: `QueryKeys.universities.deleteWish, URL, params` + +## 권장 조치 + +1. `legacy/deleteWish.ts` 파일의 비즈니스 로직 확인 +2. 새 `deleteWish.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/deleteWish.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/universities/legacy/deleteWish.ts b/src/apis/universities/legacy/deleteWish.ts new file mode 100644 index 00000000..c76c58ec --- /dev/null +++ b/src/apis/universities/legacy/deleteWish.ts @@ -0,0 +1,20 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { universitiesApi, type WishResponse } from "./api"; + +/** + * @description 위시리스트에서 학교를 삭제하는 useMutation 커스텀 훅 + */ +const useDeleteWish = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (universityInfoForApplyId) => universitiesApi.deleteWish({ univApplyInfoId: universityInfoForApplyId }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: [QueryKeys.universities.wishList] }); + }, + }); +}; + +export default useDeleteWish; diff --git a/src/apis/universities/legacy/getByRegionCountry.CHANGES.md b/src/apis/universities/legacy/getByRegionCountry.CHANGES.md new file mode 100644 index 00000000..f3d742f8 --- /dev/null +++ b/src/apis/universities/legacy/getByRegionCountry.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getByRegionCountry.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/universities/search +- Method: GET +- Function: getByRegionCountry + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.universities.byRegionCountry, params` +- 현재: `QueryKeys.universities.getByRegionCountry, URL, params` + +## 권장 조치 + +1. `legacy/getByRegionCountry.ts` 파일의 비즈니스 로직 확인 +2. 새 `getByRegionCountry.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getByRegionCountry.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/universities/legacy/getByRegionCountry.ts b/src/apis/universities/legacy/getByRegionCountry.ts new file mode 100644 index 00000000..43e04cbf --- /dev/null +++ b/src/apis/universities/legacy/getByRegionCountry.ts @@ -0,0 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type ByRegionCountryResponse, universitiesApi } from "./api"; + +const useGetByRegionCountry = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.universities.byRegionCountry, params], + queryFn: () => universitiesApi.getByRegionCountry(params ? { params } : {}), + }); +}; + +export default useGetByRegionCountry; diff --git a/src/apis/universities/legacy/getIsWish.CHANGES.md b/src/apis/universities/legacy/getIsWish.CHANGES.md new file mode 100644 index 00000000..9f0e18e6 --- /dev/null +++ b/src/apis/universities/legacy/getIsWish.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getIsWish.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/univ-apply-infos/{{univ-apply-info-id}}/like +- Method: GET +- Function: getIsWish + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.universities.isWish, univApplyInfoId, params` +- 현재: `QueryKeys.universities.getIsWish, URL, params` + +## 권장 조치 + +1. `legacy/getIsWish.ts` 파일의 비즈니스 로직 확인 +2. 새 `getIsWish.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getIsWish.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/universities/legacy/getIsWish.ts b/src/apis/universities/legacy/getIsWish.ts new file mode 100644 index 00000000..a1d54a65 --- /dev/null +++ b/src/apis/universities/legacy/getIsWish.ts @@ -0,0 +1,14 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type IsWishResponse, universitiesApi } from "./api"; + +const useGetIsWish = (univApplyInfoId: string | number, params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.universities.isWish, univApplyInfoId, params], + queryFn: () => universitiesApi.getIsWish({ univApplyInfoId, params }), + enabled: !!univApplyInfoId, + }); +}; + +export default useGetIsWish; diff --git a/src/apis/universities/legacy/getRecommendedUniversities.CHANGES.md b/src/apis/universities/legacy/getRecommendedUniversities.CHANGES.md new file mode 100644 index 00000000..91daa940 --- /dev/null +++ b/src/apis/universities/legacy/getRecommendedUniversities.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getRecommendedUniversities.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/univ-apply-infos/recommend +- Method: GET +- Function: getRecommendedUniversities + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.universities.recommendedUniversities, isLogin` +- 현재: `QueryKeys.universities.getRecommendedUniversities, URL, params` + +## 권장 조치 + +1. `legacy/getRecommendedUniversities.ts` 파일의 비즈니스 로직 확인 +2. 새 `getRecommendedUniversities.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getRecommendedUniversities.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/universities/legacy/getRecommendedUniversities.ts b/src/apis/universities/legacy/getRecommendedUniversities.ts new file mode 100644 index 00000000..5d267ac3 --- /dev/null +++ b/src/apis/universities/legacy/getRecommendedUniversities.ts @@ -0,0 +1,24 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import type { ListUniversity } from "@/types/university"; +import { QueryKeys } from "../queryKeys"; +import { type RecommendedUniversitiesResponse, universitiesApi } from "./api"; + +type UseGetRecommendedUniversitiesParams = { + isLogin: boolean; +}; + +/** + * @description 추천 대학 목록 조회를 위한 useQuery 커스텀 훅 + * @param params.isLogin - 로그인 여부 (인스턴스 결정에 사용) + */ +const useGetRecommendedUniversities = ({ isLogin }: UseGetRecommendedUniversitiesParams) => { + return useQuery({ + queryKey: [QueryKeys.universities.recommendedUniversities, isLogin], + queryFn: () => universitiesApi.getRecommendedUniversities({ isLogin }), + staleTime: 1000 * 60 * 5, + select: (data) => data.recommendedUniversities as unknown as ListUniversity[], + }); +}; + +export default useGetRecommendedUniversities; diff --git a/src/apis/universities/legacy/getSearchText.CHANGES.md b/src/apis/universities/legacy/getSearchText.CHANGES.md new file mode 100644 index 00000000..d67e8cb9 --- /dev/null +++ b/src/apis/universities/legacy/getSearchText.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getSearchText.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/univ-apply-infos/search/text?value=일본 +- Method: GET +- Function: getSearchText + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.universities.searchText` +- 현재: `QueryKeys.universities.getSearchText, URL, params` + +## 권장 조치 + +1. `legacy/getSearchText.ts` 파일의 비즈니스 로직 확인 +2. 새 `getSearchText.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getSearchText.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/universities/legacy/getSearchText.ts b/src/apis/universities/legacy/getSearchText.ts new file mode 100644 index 00000000..ad2bab9d --- /dev/null +++ b/src/apis/universities/legacy/getSearchText.ts @@ -0,0 +1,53 @@ +import { useQuery } from "@tanstack/react-query"; + +import type { AxiosError } from "axios"; +import { useMemo } from "react"; +import type { ListUniversity } from "@/types/university"; +import { QueryKeys } from "../queryKeys"; +import { type SearchTextResponse, universitiesApi } from "./api"; + +/** + * @description 대학 검색을 위한 useQuery 커스텀 훅 + * 모든 대학 데이터를 한 번만 가져와 캐싱하고, 검색어에 따라 클라이언트에서 필터링합니다. + * @param searchValue - 검색어 + */ +const useUniversitySearch = (searchValue: string) => { + // 1. 모든 대학 데이터를 한 번만 가져와 'Infinity' 캐시로 저장합니다. + const { + data: allUniversities, + isLoading, + isError, + error, + } = useQuery({ + queryKey: [QueryKeys.universities.searchText], + queryFn: () => universitiesApi.getSearchText({ value: "" }), + staleTime: Infinity, + gcTime: Infinity, + select: (data) => data.univApplyInfoPreviews as unknown as ListUniversity[], + }); + + // 2. 검색어가 변경될 때만 캐시된 데이터를 필터링합니다. + const filteredUniversities = useMemo(() => { + const normalizedSearchValue = searchValue.trim().toLowerCase(); + + if (!normalizedSearchValue) { + return allUniversities; + } + + if (!allUniversities) { + return []; + } + + return allUniversities.filter((university) => university.koreanName.toLowerCase().includes(normalizedSearchValue)); + }, [allUniversities, searchValue]); + + return { + data: filteredUniversities, + isLoading, + isError, + error, + totalCount: allUniversities?.length || 0, + }; +}; + +export default useUniversitySearch; diff --git a/src/apis/universities/legacy/getUniversityDetail.CHANGES.md b/src/apis/universities/legacy/getUniversityDetail.CHANGES.md new file mode 100644 index 00000000..db9bcbe4 --- /dev/null +++ b/src/apis/universities/legacy/getUniversityDetail.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getUniversityDetail.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/univ-apply-infos/{{univ-apply-info-id}} +- Method: GET +- Function: getUniversityDetail + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.universities.universityDetail, universityInfoForApplyId` +- 현재: `QueryKeys.universities.getUniversityDetail, URL, params` + +## 권장 조치 + +1. `legacy/getUniversityDetail.ts` 파일의 비즈니스 로직 확인 +2. 새 `getUniversityDetail.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getUniversityDetail.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/universities/legacy/getUniversityDetail.ts b/src/apis/universities/legacy/getUniversityDetail.ts new file mode 100644 index 00000000..e5a3c6d1 --- /dev/null +++ b/src/apis/universities/legacy/getUniversityDetail.ts @@ -0,0 +1,20 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import type { University } from "@/types/university"; +import { QueryKeys } from "../queryKeys"; +import { type UniversityDetailResponse, universitiesApi } from "./api"; + +/** + * @description 대학 상세 조회를 위한 useQuery 커스텀 훅 + * @param universityInfoForApplyId - 대학 ID + */ +const useGetUniversityDetail = (universityInfoForApplyId: number) => { + return useQuery({ + queryKey: [QueryKeys.universities.universityDetail, universityInfoForApplyId], + queryFn: () => universitiesApi.getUniversityDetail({ univApplyInfoId: universityInfoForApplyId }), + enabled: !!universityInfoForApplyId, + select: (data) => data as unknown as University, + }); +}; + +export default useGetUniversityDetail; diff --git a/src/apis/universities/legacy/getWishList.CHANGES.md b/src/apis/universities/legacy/getWishList.CHANGES.md new file mode 100644 index 00000000..31820198 --- /dev/null +++ b/src/apis/universities/legacy/getWishList.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getWishList.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/univ-apply-infos/like +- Method: GET +- Function: getWishList + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.universities.wishList` +- 현재: `QueryKeys.universities.getWishList, URL, params` + +## 권장 조치 + +1. `legacy/getWishList.ts` 파일의 비즈니스 로직 확인 +2. 새 `getWishList.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getWishList.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/universities/legacy/getWishList.ts b/src/apis/universities/legacy/getWishList.ts new file mode 100644 index 00000000..3bd08cf7 --- /dev/null +++ b/src/apis/universities/legacy/getWishList.ts @@ -0,0 +1,21 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import type { ListUniversity } from "@/types/university"; +import { QueryKeys } from "../queryKeys"; +import { universitiesApi, type WishListResponse } from "./api"; + +/** + * @description 내 위시리스트 대학 목록 조회를 위한 useQuery 커스텀 훅 + * @param enabled - 쿼리 활성화 여부 + */ +const useGetWishList = (enabled: boolean = true) => { + return useQuery({ + queryKey: [QueryKeys.universities.wishList], + queryFn: () => universitiesApi.getWishList({}), + staleTime: 1000 * 60 * 5, + select: (data) => data as unknown as ListUniversity[], + enabled, + }); +}; + +export default useGetWishList; diff --git a/src/apis/universities/legacy/postAddWish.CHANGES.md b/src/apis/universities/legacy/postAddWish.CHANGES.md new file mode 100644 index 00000000..0e576ff7 --- /dev/null +++ b/src/apis/universities/legacy/postAddWish.CHANGES.md @@ -0,0 +1,32 @@ +# 변경사항: postAddWish.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/univ-apply-infos/{{univ-apply-info-id}}/like +- Method: POST +- Function: postAddWish + +## 변경 내용 + +### request-type + +**Request 타입 변경** + +- 이전: `number` +- 현재: `AddWishRequest` + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.universities.wishList` +- 현재: `QueryKeys.universities.postAddWish, URL, params` + +## 권장 조치 + +1. `legacy/postAddWish.ts` 파일의 비즈니스 로직 확인 +2. 새 `postAddWish.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postAddWish.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/universities/legacy/postAddWish.ts b/src/apis/universities/legacy/postAddWish.ts new file mode 100644 index 00000000..4f0eebce --- /dev/null +++ b/src/apis/universities/legacy/postAddWish.ts @@ -0,0 +1,23 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { createMutationErrorHandler } from "@/utils/errorHandler"; +import { QueryKeys } from "../queryKeys"; +import { type AddWishResponse, universitiesApi } from "./api"; + +/** + * @description 위시리스트에 학교를 추가하는 useMutation 커스텀 훅 + */ +const usePostAddWish = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (universityInfoForApplyId) => + universitiesApi.postAddWish({ univApplyInfoId: universityInfoForApplyId }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: [QueryKeys.universities.wishList] }); + }, + onError: createMutationErrorHandler("위시리스트 추가에 실패했습니다."), + }); +}; + +export default usePostAddWish; diff --git a/src/apis/universities/postAddWish.ts b/src/apis/universities/postAddWish.ts index 4f0eebce..92cf94e3 100644 --- a/src/apis/universities/postAddWish.ts +++ b/src/apis/universities/postAddWish.ts @@ -1,23 +1,11 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { createMutationErrorHandler } from "@/utils/errorHandler"; -import { QueryKeys } from "../queryKeys"; -import { type AddWishResponse, universitiesApi } from "./api"; +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { universitiesApi, AddWishResponse, AddWishRequest } from "./api"; -/** - * @description 위시리스트에 학교를 추가하는 useMutation 커스텀 훅 - */ const usePostAddWish = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: (universityInfoForApplyId) => - universitiesApi.postAddWish({ univApplyInfoId: universityInfoForApplyId }), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: [QueryKeys.universities.wishList] }); - }, - onError: createMutationErrorHandler("위시리스트 추가에 실패했습니다."), + return useMutation({ + mutationFn: (variables) => universitiesApi.postAddWish(variables), }); }; -export default usePostAddWish; +export default usePostAddWish; \ No newline at end of file diff --git a/src/apis/users/api.ts b/src/apis/users/api.ts index d91558fd..e9c4b789 100644 --- a/src/apis/users/api.ts +++ b/src/apis/users/api.ts @@ -4,13 +4,11 @@ export interface NicknameExistsResponse { exists: boolean; } -export type BlockUserResponse = undefined; +export type BlockUserResponse = void; export type BlockUserRequest = Record; -export type UnblockUserRequest = Record; - -export type UnblockUserResponse = undefined; +export type UnblockUserResponse = void; export interface BlockedUsersResponseContentItem { id: number; @@ -26,27 +24,31 @@ export interface BlockedUsersResponse { export const usersApi = { getNicknameExists: async (params: { params?: Record }): Promise => { - const res = await axiosInstance.get(`/users/exists?nickname=abc`, { - params: params?.params, - }); + const res = await axiosInstance.get( + `/users/exists?nickname=abc`, { params: params?.params } + ); return res.data; }, - postBlockUser: async (params: { - blockedId: string | number; - data?: BlockUserRequest; - }): Promise => { - const res = await axiosInstance.post(`/users/block/${params.blockedId}`, params?.data); + postBlockUser: async (params: { blockedId: string | number, data?: BlockUserRequest }): Promise => { + const res = await axiosInstance.post( + `/users/block/${params.blockedId}`, params?.data + ); return res.data; }, deleteUnblockUser: async (params: { blockedId: string | number }): Promise => { - const res = await axiosInstance.delete(`/users/block/${params.blockedId}`); + const res = await axiosInstance.delete( + `/users/block/${params.blockedId}` + ); return res.data; }, getBlockedUsers: async (params: { params?: Record }): Promise => { - const res = await axiosInstance.get(`/users/blocks`, { params: params?.params }); + const res = await axiosInstance.get( + `/users/blocks`, { params: params?.params } + ); return res.data; }, -}; + +}; \ No newline at end of file diff --git a/src/apis/users/deleteUnblockUser.ts b/src/apis/users/deleteUnblockUser.ts index b46b67db..385dd097 100644 --- a/src/apis/users/deleteUnblockUser.ts +++ b/src/apis/users/deleteUnblockUser.ts @@ -1,6 +1,6 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type UnblockUserRequest, type UnblockUserResponse, usersApi } from "./api"; +import { usersApi, UnblockUserResponse, UnblockUserRequest } from "./api"; const useDeleteUnblockUser = () => { return useMutation({ @@ -8,4 +8,4 @@ const useDeleteUnblockUser = () => { }); }; -export default useDeleteUnblockUser; +export default useDeleteUnblockUser; \ No newline at end of file diff --git a/src/apis/users/getBlockedUsers.ts b/src/apis/users/getBlockedUsers.ts index c244cb09..1681e5dd 100644 --- a/src/apis/users/getBlockedUsers.ts +++ b/src/apis/users/getBlockedUsers.ts @@ -1,7 +1,7 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { usersApi, BlockedUsersResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type BlockedUsersResponse, usersApi } from "./api"; const useGetBlockedUsers = (params?: Record) => { return useQuery({ @@ -10,4 +10,4 @@ const useGetBlockedUsers = (params?: Record) => { }); }; -export default useGetBlockedUsers; +export default useGetBlockedUsers; \ No newline at end of file diff --git a/src/apis/users/getNicknameExists.ts b/src/apis/users/getNicknameExists.ts index d86f151e..7793059c 100644 --- a/src/apis/users/getNicknameExists.ts +++ b/src/apis/users/getNicknameExists.ts @@ -1,7 +1,7 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; +import { usersApi, NicknameExistsResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type NicknameExistsResponse, usersApi } from "./api"; const useGetNicknameExists = (params?: Record) => { return useQuery({ @@ -10,4 +10,4 @@ const useGetNicknameExists = (params?: Record) => { }); }; -export default useGetNicknameExists; +export default useGetNicknameExists; \ No newline at end of file diff --git a/src/apis/users/index.ts b/src/apis/users/index.ts index ff51c891..926ade9f 100644 --- a/src/apis/users/index.ts +++ b/src/apis/users/index.ts @@ -1,5 +1,6 @@ -export { usersApi } from "./api"; -export { default as deleteUnblockUser } from "./deleteUnblockUser"; -export { default as getBlockedUsers } from "./getBlockedUsers"; -export { default as getNicknameExists } from "./getNicknameExists"; -export { default as postBlockUser } from "./postBlockUser"; +export { usersApi } from './api'; +export { default as deleteUnblockUser } from './deleteUnblockUser'; +export { default as getBlockedUsers } from './getBlockedUsers'; +export { default as getNicknameExists } from './getNicknameExists'; +export { default as index } from './index'; +export { default as postBlockUser } from './postBlockUser'; diff --git a/src/apis/users/legacy/deleteUnblockUser.ts b/src/apis/users/legacy/deleteUnblockUser.ts new file mode 100644 index 00000000..b46b67db --- /dev/null +++ b/src/apis/users/legacy/deleteUnblockUser.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type UnblockUserRequest, type UnblockUserResponse, usersApi } from "./api"; + +const useDeleteUnblockUser = () => { + return useMutation({ + mutationFn: (variables) => usersApi.deleteUnblockUser(variables), + }); +}; + +export default useDeleteUnblockUser; diff --git a/src/apis/users/legacy/getBlockedUsers.CHANGES.md b/src/apis/users/legacy/getBlockedUsers.CHANGES.md new file mode 100644 index 00000000..87858e8d --- /dev/null +++ b/src/apis/users/legacy/getBlockedUsers.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getBlockedUsers.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/users/blocks +- Method: GET +- Function: getBlockedUsers + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.users.blockedUsers, params` +- 현재: `QueryKeys.users.getBlockedUsers, URL, params` + +## 권장 조치 + +1. `legacy/getBlockedUsers.ts` 파일의 비즈니스 로직 확인 +2. 새 `getBlockedUsers.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getBlockedUsers.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/users/legacy/getBlockedUsers.ts b/src/apis/users/legacy/getBlockedUsers.ts new file mode 100644 index 00000000..c244cb09 --- /dev/null +++ b/src/apis/users/legacy/getBlockedUsers.ts @@ -0,0 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type BlockedUsersResponse, usersApi } from "./api"; + +const useGetBlockedUsers = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.users.blockedUsers, params], + queryFn: () => usersApi.getBlockedUsers(params ? { params } : {}), + }); +}; + +export default useGetBlockedUsers; diff --git a/src/apis/users/legacy/getNicknameExists.CHANGES.md b/src/apis/users/legacy/getNicknameExists.CHANGES.md new file mode 100644 index 00000000..f08f3fc3 --- /dev/null +++ b/src/apis/users/legacy/getNicknameExists.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: getNicknameExists.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/users/exists?nickname=abc +- Method: GET +- Function: getNicknameExists + +## 변경 내용 + +### query-key + +**QueryKey 변경** + +- 이전: `QueryKeys.users.nicknameExists, params` +- 현재: `QueryKeys.users.getNicknameExists, URL, params` + +## 권장 조치 + +1. `legacy/getNicknameExists.ts` 파일의 비즈니스 로직 확인 +2. 새 `getNicknameExists.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/getNicknameExists.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/users/legacy/getNicknameExists.ts b/src/apis/users/legacy/getNicknameExists.ts new file mode 100644 index 00000000..d86f151e --- /dev/null +++ b/src/apis/users/legacy/getNicknameExists.ts @@ -0,0 +1,13 @@ +import { useQuery } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { QueryKeys } from "../queryKeys"; +import { type NicknameExistsResponse, usersApi } from "./api"; + +const useGetNicknameExists = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.users.nicknameExists, params], + queryFn: () => usersApi.getNicknameExists(params ? { params } : {}), + }); +}; + +export default useGetNicknameExists; diff --git a/src/apis/users/legacy/postBlockUser.CHANGES.md b/src/apis/users/legacy/postBlockUser.CHANGES.md new file mode 100644 index 00000000..d4664abc --- /dev/null +++ b/src/apis/users/legacy/postBlockUser.CHANGES.md @@ -0,0 +1,25 @@ +# 변경사항: postBlockUser.ts + +## 변경 일시 +2026-01-25 + +## API 정보 +- URL: {{URL}}/users/block/{{blocked-id}} +- Method: POST +- Function: postBlockUser + +## 변경 내용 + +### request-type + +**Request 타입 변경** + +- 이전: `{ blockedId: string | number; data: BlockUserRequest }` +- 현재: `BlockUserRequest` + +## 권장 조치 + +1. `legacy/postBlockUser.ts` 파일의 비즈니스 로직 확인 +2. 새 `postBlockUser.ts` 파일과 비교 +3. 필요한 커스텀 로직을 새 파일에 수동 병합 +4. 병합 완료 후 `legacy/postBlockUser.ts` 파일 삭제 \ No newline at end of file diff --git a/src/apis/users/legacy/postBlockUser.ts b/src/apis/users/legacy/postBlockUser.ts new file mode 100644 index 00000000..1c6fde9d --- /dev/null +++ b/src/apis/users/legacy/postBlockUser.ts @@ -0,0 +1,11 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { type BlockUserRequest, type BlockUserResponse, usersApi } from "./api"; + +const usePostBlockUser = () => { + return useMutation({ + mutationFn: (variables) => usersApi.postBlockUser(variables), + }); +}; + +export default usePostBlockUser; diff --git a/src/apis/users/postBlockUser.ts b/src/apis/users/postBlockUser.ts index 1c6fde9d..11b44fe8 100644 --- a/src/apis/users/postBlockUser.ts +++ b/src/apis/users/postBlockUser.ts @@ -1,6 +1,6 @@ +import { AxiosError } from "axios"; import { useMutation } from "@tanstack/react-query"; -import type { AxiosError } from "axios"; -import { type BlockUserRequest, type BlockUserResponse, usersApi } from "./api"; +import { usersApi, BlockUserResponse, BlockUserRequest } from "./api"; const usePostBlockUser = () => { return useMutation({ @@ -8,4 +8,4 @@ const usePostBlockUser = () => { }); }; -export default usePostBlockUser; +export default usePostBlockUser; \ No newline at end of file