From ff6cfffdcd348ed8726546b89fecd1edc3bf2aba Mon Sep 17 00:00:00 2001 From: "bruno-sync-app[bot]" Date: Mon, 26 Jan 2026 10:23:59 +0000 Subject: [PATCH] chore: sync API from Bruno --- apps/web/src/apis/.bruno-cache/hashes.json | 688 ++++++++++++++++++ apps/web/src/apis/Admin/api.ts | 52 +- apps/web/src/apis/Admin/getGpaList.ts | 6 +- .../web/src/apis/Admin/getLanguageTestList.ts | 6 +- apps/web/src/apis/Admin/index.ts | 12 +- ...0\353\217\231 \355\225\264\354\240\234.ts" | 11 + ...0\354\240\200 \354\260\250\353\213\250.ts" | 11 + apps/web/src/apis/Admin/putVerifyGpa.ts | 6 +- .../src/apis/Admin/putVerifyLanguageTest.ts | 12 +- apps/web/src/apis/Auth/api.ts | 121 ++- apps/web/src/apis/Auth/deleteAccount.ts | 38 +- apps/web/src/apis/Auth/index.ts | 34 +- apps/web/src/apis/Auth/postAppleAuth.ts | 40 +- apps/web/src/apis/Auth/postEmailLogin.ts | 36 +- .../src/apis/Auth/postEmailVerification.ts | 21 +- apps/web/src/apis/Auth/postKakaoAuth.ts | 41 +- apps/web/src/apis/Auth/postRefreshToken.ts | 10 +- apps/web/src/apis/Auth/postSignOut.ts | 29 +- apps/web/src/apis/Auth/postSignUp.ts | 17 +- apps/web/src/apis/MyPage/api.ts | 84 +-- apps/web/src/apis/MyPage/getProfile.ts | 40 +- apps/web/src/apis/MyPage/index.ts | 18 +- .../MyPage/patchInterestedRegionCountry.ts | 8 +- apps/web/src/apis/MyPage/patchPassword.ts | 34 +- apps/web/src/apis/MyPage/patchProfile.ts | 31 +- apps/web/src/apis/Scores/api.ts | 115 ++- apps/web/src/apis/Scores/getGpaList.ts | 20 +- .../src/apis/Scores/getLanguageTestList.ts | 20 +- apps/web/src/apis/Scores/index.ts | 17 +- apps/web/src/apis/Scores/postCreateGpa.ts | 30 +- .../src/apis/Scores/postCreateLanguageTest.ts | 30 +- apps/web/src/apis/applications/api.ts | 171 +++-- .../src/apis/applications/getApplicants.ts | 34 +- .../src/apis/applications/getCompetitors.ts | 6 +- apps/web/src/apis/applications/index.ts | 9 +- .../applications/postSubmitApplication.ts | 40 +- apps/web/src/apis/chat/api.ts | 80 +- apps/web/src/apis/chat/getChatMessages.ts | 46 +- apps/web/src/apis/chat/getChatPartner.ts | 19 +- apps/web/src/apis/chat/getChatRooms.ts | 20 +- apps/web/src/apis/chat/index.ts | 11 +- apps/web/src/apis/chat/putReadChatRoom.ts | 26 +- apps/web/src/apis/community/api.ts | 251 ++++--- apps/web/src/apis/community/deleteComment.ts | 33 +- apps/web/src/apis/community/deleteLikePost.ts | 29 +- apps/web/src/apis/community/deletePost.ts | 36 +- apps/web/src/apis/community/getBoard.ts | 8 +- apps/web/src/apis/community/getBoardList.ts | 6 +- apps/web/src/apis/community/getPostDetail.ts | 19 +- apps/web/src/apis/community/index.ts | 40 +- .../src/apis/community/patchUpdateComment.ts | 10 +- .../web/src/apis/community/patchUpdatePost.ts | 36 +- .../src/apis/community/postCreateComment.ts | 30 +- apps/web/src/apis/community/postCreatePost.ts | 63 +- apps/web/src/apis/community/postLikePost.ts | 29 +- apps/web/src/apis/environments/api.ts | 4 + apps/web/src/apis/environments/index.ts | 1 + apps/web/src/apis/image-upload/api.ts | 84 +-- apps/web/src/apis/image-upload/index.ts | 14 +- .../image-upload/postSlackNotification.ts | 6 +- .../apis/image-upload/postUploadGpaReport.ts | 10 +- .../postUploadLanguageTestReport.ts | 10 +- .../image-upload/postUploadProfileImage.ts | 10 +- .../postUploadProfileImageBeforeSignup.ts | 21 +- apps/web/src/apis/kakao-api/api.ts | 21 +- apps/web/src/apis/kakao-api/getKakaoInfo.ts | 8 +- .../web/src/apis/kakao-api/getKakaoUserIds.ts | 8 +- apps/web/src/apis/kakao-api/index.ts | 8 +- .../web/src/apis/kakao-api/postKakaoUnlink.ts | 6 +- apps/web/src/apis/mentor/api.ts | 280 +++---- .../src/apis/mentor/getAppliedMentorings.ts | 49 +- apps/web/src/apis/mentor/getMatchedMentors.ts | 12 +- apps/web/src/apis/mentor/getMentorDetail.ts | 21 +- apps/web/src/apis/mentor/getMentorList.ts | 47 +- apps/web/src/apis/mentor/getMyMentorPage.ts | 19 +- .../src/apis/mentor/getReceivedMentorings.ts | 29 +- .../mentor/getUnconfirmedMentoringCount.ts | 22 +- apps/web/src/apis/mentor/index.ts | 40 +- .../src/apis/mentor/patchConfirmMentoring.ts | 25 +- .../src/apis/mentor/patchMentoringStatus.ts | 66 +- .../web/src/apis/mentor/postApplyMentoring.ts | 25 +- .../src/apis/mentor/putUpdateMyMentorPage.ts | 25 +- apps/web/src/apis/news/api.ts | 139 ++-- apps/web/src/apis/news/deleteLikeNews.ts | 54 +- apps/web/src/apis/news/deleteNews.ts | 53 +- apps/web/src/apis/news/getNewsList.ts | 28 +- apps/web/src/apis/news/index.ts | 22 +- apps/web/src/apis/news/postCreateNews.ts | 60 +- apps/web/src/apis/news/postLikeNews.ts | 55 +- apps/web/src/apis/news/putUpdateNews.ts | 62 +- apps/web/src/apis/queryKeys.ts | 195 +++-- apps/web/src/apis/reports/api.ts | 26 +- apps/web/src/apis/reports/index.ts | 5 +- apps/web/src/apis/reports/postReport.ts | 27 +- apps/web/src/apis/universities/api.ts | 100 +-- apps/web/src/apis/universities/deleteWish.ts | 21 +- .../apis/universities/getByRegionCountry.ts | 6 +- apps/web/src/apis/universities/getIsWish.ts | 6 +- .../getRecommendedUniversities.ts | 25 +- .../src/apis/universities/getSearchText.ts | 68 +- .../apis/universities/getUniversityDetail.ts | 22 +- apps/web/src/apis/universities/getWishList.ts | 22 +- apps/web/src/apis/universities/index.ts | 20 +- apps/web/src/apis/universities/postAddWish.ts | 24 +- apps/web/src/apis/users/api.ts | 32 +- apps/web/src/apis/users/deleteUnblockUser.ts | 6 +- apps/web/src/apis/users/getBlockedUsers.ts | 6 +- apps/web/src/apis/users/getNicknameExists.ts | 6 +- apps/web/src/apis/users/index.ts | 10 +- apps/web/src/apis/users/postBlockUser.ts | 6 +- 110 files changed, 2188 insertions(+), 2479 deletions(-) create mode 100644 apps/web/src/apis/.bruno-cache/hashes.json create mode 100644 "apps/web/src/apis/Admin/patch\354\234\240\354\240\200 \354\260\250\353\213\250 \354\210\230\353\217\231 \355\225\264\354\240\234.ts" create mode 100644 "apps/web/src/apis/Admin/post\354\234\240\354\240\200 \354\260\250\353\213\250.ts" create mode 100644 apps/web/src/apis/environments/api.ts create mode 100644 apps/web/src/apis/environments/index.ts diff --git a/apps/web/src/apis/.bruno-cache/hashes.json b/apps/web/src/apis/.bruno-cache/hashes.json new file mode 100644 index 00000000..c3ef70c4 --- /dev/null +++ b/apps/web/src/apis/.bruno-cache/hashes.json @@ -0,0 +1,688 @@ +{ + "version": "1.0", + "hashes": { + "/tmp/bruno/Solid Connection/1) 인증 [Auth]/folder.bru": { + "hash": "8e91265cf125a3cf72adbb5f1d5da9060a4d91e482d7f2deb494c8e49b5edee5", + "lastGenerated": "2026-01-26T10:23:58.849Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/1) 인증 [Auth]/로그아웃 [sign-out].bru": { + "hash": "25517b361f9c899eb841e477f7490a86f14dca603bcb5ebe3ae0a672cdf2a261", + "lastGenerated": "2026-01-26T10:23:58.850Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Auth/postSignOut.ts" + ] + }, + "/tmp/bruno/Solid Connection/1) 인증 [Auth]/애플 인증 [apple-auth].bru": { + "hash": "0c465126248a544c43d2e31aa2bcb6509b76404dc19d05f63762b8b98e46658e", + "lastGenerated": "2026-01-26T10:23:58.850Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Auth/postAppleAuth.ts" + ] + }, + "/tmp/bruno/Solid Connection/1) 인증 [Auth]/엑세스 토큰 재발급 [refresh-token].bru": { + "hash": "fa5f5b0551470c64fa4c46973d9a0e142ee83fea519ec402c2241075f7b926ac", + "lastGenerated": "2026-01-26T10:23:58.851Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Auth/postRefreshToken.ts" + ] + }, + "/tmp/bruno/Solid Connection/1) 인증 [Auth]/이메일 로그인 [email-login].bru": { + "hash": "14841bd2bb8fe0ea0df09bb3f78b46f1cc27b0afcc73d78e0a94dea7ddd6dd1a", + "lastGenerated": "2026-01-26T10:23:58.851Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Auth/postEmailLogin.ts" + ] + }, + "/tmp/bruno/Solid Connection/1) 인증 [Auth]/이메일 인증 [email-verification].bru": { + "hash": "eb2bf7b06ad35c038fb0bcb8c50260c567ba437eb5f426706dc10a7d82c79def", + "lastGenerated": "2026-01-26T10:23:58.851Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Auth/postEmailVerification.ts" + ] + }, + "/tmp/bruno/Solid Connection/1) 인증 [Auth]/카카오 인증 [kakao-auth].bru": { + "hash": "10f82cf1ecb3d77a697c63b5532be860f29d00adb960678eafed7c66ec91ee15", + "lastGenerated": "2026-01-26T10:23:58.851Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Auth/postKakaoAuth.ts" + ] + }, + "/tmp/bruno/Solid Connection/1) 인증 [Auth]/회원 탈퇴 [account].bru": { + "hash": "131b2d3c540f7ce07a82d2691920c0da11431f8f4dc7bd4401b6a8d7c402230b", + "lastGenerated": "2026-01-26T10:23:58.852Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Auth/deleteAccount.ts" + ] + }, + "/tmp/bruno/Solid Connection/1) 인증 [Auth]/회원가입 [sign-up].bru": { + "hash": "5e62a63352a4ee87784d767c63a51134fd5c3986a8af9c0cb1204db313a3ae55", + "lastGenerated": "2026-01-26T10:23:58.852Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Auth/postSignUp.ts" + ] + }, + "/tmp/bruno/Solid Connection/10) 소식지 [news]/folder.bru": { + "hash": "77d250ab9a6916aa139953f7ecf63ead0fe28f4ca59c6adf6a2578c03f0a97ae", + "lastGenerated": "2026-01-26T10:23:58.852Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/10) 소식지 [news]/소식지 목록 [news-list].bru": { + "hash": "94aa9bcbac824d0a939ab6ea2599b4ae0eab3c80b7befd4cd2da0e9e9f99e080", + "lastGenerated": "2026-01-26T10:23:58.853Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/news/getNewsList.ts" + ] + }, + "/tmp/bruno/Solid Connection/10) 소식지 [news]/소식지 삭제 [news].bru": { + "hash": "8f20e5a662c4f08fb4d870c304f54fd3996f7a37cac7d5854a3d32a6edf88c6a", + "lastGenerated": "2026-01-26T10:23:58.853Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/news/deleteNews.ts" + ] + }, + "/tmp/bruno/Solid Connection/10) 소식지 [news]/소식지 수정 [update-news].bru": { + "hash": "9f3f4b0266d0f24938f828f1edd56f65b0720adfbae4b7bc25c26da7f2593b45", + "lastGenerated": "2026-01-26T10:23:58.854Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/news/putUpdateNews.ts" + ] + }, + "/tmp/bruno/Solid Connection/10) 소식지 [news]/소식지 좋아요 [like-news].bru": { + "hash": "e68b301ce17e142128b8be86fcc6fde3ce160bfea415e41941a5a6e29c2c25be", + "lastGenerated": "2026-01-26T10:23:58.854Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/news/postLikeNews.ts" + ] + }, + "/tmp/bruno/Solid Connection/10) 소식지 [news]/소식지 좋아요 취소 [like-news].bru": { + "hash": "da6a6301da82e9fa986f6452a47007e9f4c4fd11b4aad21512f1fab5bbcd6fa9", + "lastGenerated": "2026-01-26T10:23:58.854Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/news/deleteLikeNews.ts" + ] + }, + "/tmp/bruno/Solid Connection/10) 소식지 [news]/소식지 추가 [create-news].bru": { + "hash": "a7cd6c83cefeb515bceaa886db980975b8ba39453348b8939e667b025a827638", + "lastGenerated": "2026-01-26T10:23:58.855Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/news/postCreateNews.ts" + ] + }, + "/tmp/bruno/Solid Connection/11) 신고 [reports]/folder.bru": { + "hash": "e74c3068cfeb9a71ea1175258c3ae0030b5dbd10a0e34aa89f92d23e65c3df2d", + "lastGenerated": "2026-01-26T10:23:58.855Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/11) 신고 [reports]/신고하기 [report].bru": { + "hash": "75e57efa5746b4593d00f47bf99e39f27b286ee40175b37f18aefbf35fa13461", + "lastGenerated": "2026-01-26T10:23:58.855Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/reports/postReport.ts" + ] + }, + "/tmp/bruno/Solid Connection/11) 채팅 [chat]/folder.bru": { + "hash": "0dff2d5c0f3e2990704653e992ef17f8d7396bc5b67b1777c183fd5b41dcda73", + "lastGenerated": "2026-01-26T10:23:58.855Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/11) 채팅 [chat]/채팅 내역 [chat-messages].bru": { + "hash": "55ddf51cbcf809898d575c9b912678ce62a3bf04f241aa223c550652bcf16628", + "lastGenerated": "2026-01-26T10:23:58.855Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/chat/getChatMessages.ts" + ] + }, + "/tmp/bruno/Solid Connection/11) 채팅 [chat]/채팅방 목록 [chat-rooms].bru": { + "hash": "042d1632b86576a277c1369a91bb04231d568c3dacfab932fa9b4d3ea42aabe0", + "lastGenerated": "2026-01-26T10:23:58.856Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/chat/getChatRooms.ts" + ] + }, + "/tmp/bruno/Solid Connection/11) 채팅 [chat]/채팅방 읽음 [read-chat-room].bru": { + "hash": "87036c469e658bf48b7ddc6226caa6aa43dffed86fcaabac659ebb29dd7e604e", + "lastGenerated": "2026-01-26T10:23:58.856Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/chat/putReadChatRoom.ts" + ] + }, + "/tmp/bruno/Solid Connection/11) 채팅 [chat]/채팅방 파트너 [chat-partner].bru": { + "hash": "6fb7336c127afd330a806d3deb03b3ecadcb341185f9c9e0f4c2afc036d772ad", + "lastGenerated": "2026-01-26T10:23:58.856Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/chat/getChatPartner.ts" + ] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/folder.bru": { + "hash": "b2ecc044eba5b951c1e0bf3d204f45996bed91ddcf86cf55efd717aae98590ff", + "lastGenerated": "2026-01-26T10:23:58.856Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/univ-apply-infos/folder.bru": { + "hash": "419e88968bddd7d83ae2bf4e43d5ba08ba586f855219d7adfd9b438e1e6055ff", + "lastGenerated": "2026-01-26T10:23:58.857Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/univ-apply-infos/맞춤 대학 추천 [recommended-universities].bru": { + "hash": "5e655440fe597146c451bf42b712a78b00653437854bc794e0f6dfd175d7de8e", + "lastGenerated": "2026-01-26T10:23:58.857Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/universities/getRecommendedUniversities.ts" + ] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/univ-apply-infos/위시 학교 목록 [wish-list].bru": { + "hash": "1974840ffbfbe742fcdbe4ca74ed928986848a20acb22e6a04b4e9ffff03bfed", + "lastGenerated": "2026-01-26T10:23:58.857Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/universities/getWishList.ts" + ] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/univ-apply-infos/위시 학교 삭제 [wish].bru": { + "hash": "85e1414b164549bebdb4998de2c3e99c544891bb7c0afd89f5f8d924c2ff7925", + "lastGenerated": "2026-01-26T10:23:58.857Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/universities/deleteWish.ts" + ] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/univ-apply-infos/위시 학교 추가 [add-wish].bru": { + "hash": "764146688e833c0cdc4fc735972c97ed88d4872e243eea88a507495f82ac1163", + "lastGenerated": "2026-01-26T10:23:58.858Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/universities/postAddWish.ts" + ] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/univ-apply-infos/위시 학교 확인 [is-wish].bru": { + "hash": "a9791d3d2ee69ec8e2e99ce7885450e24e668df29800e5c013c1468eda87a8d1", + "lastGenerated": "2026-01-26T10:23:58.858Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/universities/getIsWish.ts" + ] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/univ-apply-infos/학교 상세 정보 [university-detail].bru": { + "hash": "c642309fe0143efefb56f309fb11c4f4df0003e8101c639d484ada49ae2a48d5", + "lastGenerated": "2026-01-26T10:23:58.858Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/universities/getUniversityDetail.ts" + ] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/univ-apply-infos/학교 텍스트 검색 [search-text].bru": { + "hash": "26de3e34862e6211e55542b5a5573318fb4d7d317a5038121704f881d448abd7", + "lastGenerated": "2026-01-26T10:23:58.858Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/universities/getSearchText.ts" + ] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/universities/folder.bru": { + "hash": "df66fcd336e7d2961d8177eda63e497d085a07056bce3f45711532046b00190f", + "lastGenerated": "2026-01-26T10:23:58.858Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/2) 대학교 [universities]/universities/권역-국가별 대학 [by-region-country].bru": { + "hash": "9a960d71ef2c7fd6d5d4e8fb0379c5aeb32501e957f08bcd3c129b2483704b24", + "lastGenerated": "2026-01-26T10:23:58.859Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/universities/getByRegionCountry.ts" + ] + }, + "/tmp/bruno/Solid Connection/3) 마이페이지 [MyPage]/folder.bru": { + "hash": "ee40d5ac24c6faf84a2948a74ea3ea21015cf35e39b2a3d94bf03c1e40bd726d", + "lastGenerated": "2026-01-26T10:23:58.859Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/3) 마이페이지 [MyPage]/관심 권역-국가 변경 [interested-region-country].bru": { + "hash": "24d5ef7f09224a0d63efe24b6e28dbe3fb7a3e8962e7027c40685de9226797ec", + "lastGenerated": "2026-01-26T10:23:58.859Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/MyPage/patchInterestedRegionCountry.ts" + ] + }, + "/tmp/bruno/Solid Connection/3) 마이페이지 [MyPage]/내 정보 수정 [profile].bru": { + "hash": "c9d0813e061a3d930093acdf7424fea70e203e7f237798076b0b4cdf79daed9b", + "lastGenerated": "2026-01-26T10:23:58.859Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/MyPage/patchProfile.ts" + ] + }, + "/tmp/bruno/Solid Connection/3) 마이페이지 [MyPage]/내 정보 조회 [profile].bru": { + "hash": "f6fa9594c4553623229c4ba76e3c6c89fcb0c218894a8e34b2730780320ad0be", + "lastGenerated": "2026-01-26T10:23:58.860Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/MyPage/getProfile.ts" + ] + }, + "/tmp/bruno/Solid Connection/3) 마이페이지 [MyPage]/비밀번호 변경 [password].bru": { + "hash": "290e59dd88d636fcfb883e4d581e5d1a726c5d34ce1e2488a228f14df108715d", + "lastGenerated": "2026-01-26T10:23:58.860Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/MyPage/patchPassword.ts" + ] + }, + "/tmp/bruno/Solid Connection/4) 지원정보 [applications]/folder.bru": { + "hash": "0c6da4142e7d342d09544c4e3d5e11e8942c099256ed844baccdce08e472f08b", + "lastGenerated": "2026-01-26T10:23:58.860Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/4) 지원정보 [applications]/경쟁자 현황 [competitors].bru": { + "hash": "04b9c5905d7efe479a42a4dda65dc4606a9a95566cea674f388b36a4615d17ed", + "lastGenerated": "2026-01-26T10:23:58.860Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/applications/getCompetitors.ts" + ] + }, + "/tmp/bruno/Solid Connection/4) 지원정보 [applications]/지원서 제출 [submit-application].bru": { + "hash": "b2d23f77f434c6b461db69923826e798aa17bc1e0e47b9717f6bef21c48e2bd1", + "lastGenerated": "2026-01-26T10:23:58.860Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/applications/postSubmitApplication.ts" + ] + }, + "/tmp/bruno/Solid Connection/4) 지원정보 [applications]/지원자 현황 [applicants].bru": { + "hash": "36a2c14b7a5b985de9854c1c3ba7e2d1ca453e3428defa158f7d12e5afec3279", + "lastGenerated": "2026-01-26T10:23:58.861Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/applications/getApplicants.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/boards/folder.bru": { + "hash": "a6b155502eef19cb047e473f8de89a30279aa539ad87f5639ffe5e993d1c3dc4", + "lastGenerated": "2026-01-26T10:23:58.861Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/boards/게시판 목록 [board-list].bru": { + "hash": "394d5d4736e5e47c74cdb0a26d2b51af7391012d724fb6e14534365c017ce471", + "lastGenerated": "2026-01-26T10:23:58.861Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/getBoardList.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/boards/게시판 조회 [board].bru": { + "hash": "07a90ceb0610dd4d59f202f94a13b3257e8d441e8eb390ed1c91320ca69f9e82", + "lastGenerated": "2026-01-26T10:23:58.861Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/getBoard.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/comments/folder.bru": { + "hash": "ba47363fc0ca5bf12c050c78cd9730fc630cc2fd88ba51dba22a1fa1e39413b8", + "lastGenerated": "2026-01-26T10:23:58.861Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/comments/댓글 삭제 [comment].bru": { + "hash": "cc52f32359e90a5628c989572bcfd0c12733eba0ffbe808196592f2643750c7e", + "lastGenerated": "2026-01-26T10:23:58.862Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/deleteComment.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/comments/댓글 수정 [update-comment].bru": { + "hash": "51091a654511add0b4e2e272d107d265fe6a9f9bf272fd14582aa8d57a3276d1", + "lastGenerated": "2026-01-26T10:23:58.862Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/patchUpdateComment.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/comments/댓글 작성 [create-comment].bru": { + "hash": "610d59af217778cf3ccf941ffbce53f88743a5e4d3ec6ff63e9ad60bb5ab7ca3", + "lastGenerated": "2026-01-26T10:23:58.862Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/postCreateComment.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/folder.bru": { + "hash": "0a5ff57df866db18f569df2b1c433653249752d3088cd10eced762f39009ea4a", + "lastGenerated": "2026-01-26T10:23:58.862Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/posts/folder.bru": { + "hash": "12ad1ad8f64c94eb8503b32864ca8603787f6fba742c826cb42902f2d2611618", + "lastGenerated": "2026-01-26T10:23:58.862Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/posts/게시글 삭제 [post].bru": { + "hash": "b08c636fb60c50c90ef92ceaa3859cf90d08f62665feff3716487c36988c69c3", + "lastGenerated": "2026-01-26T10:23:58.862Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/deletePost.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/posts/게시글 수정 [update-post].bru": { + "hash": "c8a74d3734252099a9b3c1469b3e69778350f0036458297c199cd4a555f4daa7", + "lastGenerated": "2026-01-26T10:23:58.863Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/patchUpdatePost.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/posts/게시글 작성 [create-post].bru": { + "hash": "677ea297c854b23f0a81e5e462dff6b3c76e36e16f01a2436ad2b749ffc010b6", + "lastGenerated": "2026-01-26T10:23:58.863Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/postCreatePost.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/posts/게시글 조회 [post-detail].bru": { + "hash": "716a48fb6a7da3d65c847e0ed69eaa009412deb3dfdbcd1743cd7ce01a35074e", + "lastGenerated": "2026-01-26T10:23:58.863Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/getPostDetail.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/posts/게시글 좋아요 [like-post].bru": { + "hash": "225951fdd4400a052b6448cc213499bd17f496cae39cf004558ee480342b465f", + "lastGenerated": "2026-01-26T10:23:58.863Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/postLikePost.ts" + ] + }, + "/tmp/bruno/Solid Connection/5) 커뮤니티 [community]/posts/게시글 좋아요 취소 [like-post].bru": { + "hash": "89a4567c80d225badd7f2279d55fc83b2ef88c2420c2c02474fbdb0b023c04c5", + "lastGenerated": "2026-01-26T10:23:58.864Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/community/deleteLikePost.ts" + ] + }, + "/tmp/bruno/Solid Connection/6) 성적 [Scores]/folder.bru": { + "hash": "f0f1e22e55cbf59434a31261c5e6a7bc31e5756190354e67f18dac224f1386d6", + "lastGenerated": "2026-01-26T10:23:58.864Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/6) 성적 [Scores]/어학 성적 등록 [create-language-test].bru": { + "hash": "0ba4e708ae523dacf5923652107b417ea7dd48126241a4a9d0efa7e104dd1f60", + "lastGenerated": "2026-01-26T10:23:58.864Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Scores/postCreateLanguageTest.ts" + ] + }, + "/tmp/bruno/Solid Connection/6) 성적 [Scores]/어학 성적 조회 [language-test-list].bru": { + "hash": "a4920b60fd5d7b32100f521ce9674d6c90d95f8d599377d0f2b1e5b19dc0a35a", + "lastGenerated": "2026-01-26T10:23:58.864Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Scores/getLanguageTestList.ts" + ] + }, + "/tmp/bruno/Solid Connection/6) 성적 [Scores]/학점 등록 [create-gpa].bru": { + "hash": "2cda7a34a3fbac0fd1d6a17249c7c7599da720ac931aceab90dd258001a9707a", + "lastGenerated": "2026-01-26T10:23:58.864Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Scores/postCreateGpa.ts" + ] + }, + "/tmp/bruno/Solid Connection/6) 성적 [Scores]/학점 조회 [gpa-list].bru": { + "hash": "e51910e94eb0332399c59ea1bfe467c006832097f58cf300b183a398106257b6", + "lastGenerated": "2026-01-26T10:23:58.865Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Scores/getGpaList.ts" + ] + }, + "/tmp/bruno/Solid Connection/7) 어드민 [Admin]/folder.bru": { + "hash": "c12f1c3d068a98a389f58739bb2248ad7ca46bee451767fe8cb3604ab2086db4", + "lastGenerated": "2026-01-26T10:23:58.865Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/7) 어드민 [Admin]/어학 검증 및 수정 [verify-language-test].bru": { + "hash": "a55691b7bf4cb2126ff0089f50d79ad05e398d1447027ebb08269731e5f93e5b", + "lastGenerated": "2026-01-26T10:23:58.865Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Admin/putVerifyLanguageTest.ts" + ] + }, + "/tmp/bruno/Solid Connection/7) 어드민 [Admin]/어학 조회 [language-test-list].bru": { + "hash": "db4631654f94d11523075cbc2672a67c840d815051bde42d03dfc34f0e1f9984", + "lastGenerated": "2026-01-26T10:23:58.865Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Admin/getLanguageTestList.ts" + ] + }, + "/tmp/bruno/Solid Connection/7) 어드민 [Admin]/차단 기능/folder.bru": { + "hash": "7ad1af973b6acde346796fb5b68f6830ac696320f5dadb8e14bac1601e7e01e2", + "lastGenerated": "2026-01-26T10:23:58.865Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/7) 어드민 [Admin]/차단 기능/유저 차단 수동 해제.bru": { + "hash": "a8faef6d454e48fba31e6558d474f310755b0e3a69fd15476d6e53a606566a7e", + "lastGenerated": "2026-01-26T10:23:58.865Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Admin/patch유저 차단 수동 해제.ts" + ] + }, + "/tmp/bruno/Solid Connection/7) 어드민 [Admin]/차단 기능/유저 차단.bru": { + "hash": "ce79c214831c32c4c31a1a6e01f833814650df3de019c67d0e2245eee4d8dc56", + "lastGenerated": "2026-01-26T10:23:58.866Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Admin/post유저 차단.ts" + ] + }, + "/tmp/bruno/Solid Connection/7) 어드민 [Admin]/학점 검증 및 수정 [verify-gpa].bru": { + "hash": "0febe94c78c2f1993141efed3ef5e46d6d94a040c7eccba24964000a8640443b", + "lastGenerated": "2026-01-26T10:23:58.866Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Admin/putVerifyGpa.ts" + ] + }, + "/tmp/bruno/Solid Connection/7) 어드민 [Admin]/학점 조회 [gpa-list].bru": { + "hash": "c95e237f06b63bacd5a129fcb24b8525878cc3b298e3a50032bd3fc938a43c27", + "lastGenerated": "2026-01-26T10:23:58.866Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/Admin/getGpaList.ts" + ] + }, + "/tmp/bruno/Solid Connection/8) 사용자 [users]/folder.bru": { + "hash": "6e63f3ece2b1f9780a444178433aad1216ef07a2f420f2e4c93eee99fc5d697e", + "lastGenerated": "2026-01-26T10:23:58.866Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/8) 사용자 [users]/닉네임 중복 검증 [nickname-exists].bru": { + "hash": "95558c2dd0a7049f4b24ff7dcf58346ea80519f2d8d70d6428c6daefb35fd8ed", + "lastGenerated": "2026-01-26T10:23:58.866Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/users/getNicknameExists.ts" + ] + }, + "/tmp/bruno/Solid Connection/8) 사용자 [users]/유저 차단 [block-user].bru": { + "hash": "fa0aca42761f35fc4fc9ce1bd57ea100076e450ab7874f88f9cc7e27e1375a5a", + "lastGenerated": "2026-01-26T10:23:58.867Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/users/postBlockUser.ts" + ] + }, + "/tmp/bruno/Solid Connection/8) 사용자 [users]/유저 차단 취소 [unblock-user].bru": { + "hash": "faea682b3e75c55710ec4b92c30112aa8e811f4e50aa5d05925fcfc30b228e58", + "lastGenerated": "2026-01-26T10:23:58.867Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/users/deleteUnblockUser.ts" + ] + }, + "/tmp/bruno/Solid Connection/8) 사용자 [users]/차단한 유저 목록 [blocked-users].bru": { + "hash": "b71235470d88d230dc0f78be82fe88f83b5d27be5374c722423994d96e86223c", + "lastGenerated": "2026-01-26T10:23:58.867Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/users/getBlockedUsers.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/folder.bru": { + "hash": "0991756e4421a2e651828883b9bd3d77ee1a0122557ee7d86b99f4f7fc8fbb02", + "lastGenerated": "2026-01-26T10:23:58.867Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentee-only/folder.bru": { + "hash": "3763a8a195748562e91d4cb01b9bea9b50a378572f6ede24e6e6a4f3051e0108", + "lastGenerated": "2026-01-26T10:23:58.867Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentee-only/매칭된 멘토 목록 [matched-mentors].bru": { + "hash": "0af0fdc81eb2cafff9bf91f634a6caab39ec8674a3e5961e5b422aa90ac447a1", + "lastGenerated": "2026-01-26T10:23:58.868Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/getMatchedMentors.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentee-only/멘토링 신청 [apply-mentoring].bru": { + "hash": "f01db17b66f4860bea554e711f8adf45d2f6aaf0224e916fe3ad30d15b1b2b38", + "lastGenerated": "2026-01-26T10:23:58.868Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/postApplyMentoring.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentee-only/멘토링 확인 [confirm-mentoring].bru": { + "hash": "1cae59951d931b2817e779087d71a3f082622681b9a9a5467aa656eceae620bc", + "lastGenerated": "2026-01-26T10:23:58.868Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/patchConfirmMentoring.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentee-only/신청한 멘토링 목록 [applied-mentorings].bru": { + "hash": "58ffa494789c972151bee9d3d1fd5f1d59dccd47b9ecb55f626a3fba870fea24", + "lastGenerated": "2026-01-26T10:23:58.868Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/getAppliedMentorings.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor/folder.bru": { + "hash": "0309228eefe216ce5d99274be87b1672f7f60dafbf64560ba6f82326029a53f6", + "lastGenerated": "2026-01-26T10:23:58.869Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor/멘토 목록 [mentor-list].bru": { + "hash": "817be70c53925e39d7503d737c1cc3bdb99e5a4fb043f4e266493befa4576cd6", + "lastGenerated": "2026-01-26T10:23:58.869Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/getMentorList.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor/멘토 상세 [mentor-detail].bru": { + "hash": "830a8a800e3aade7678b40cd5ddcdfb45e58b5e9393afbf030baa1aa8b014ea0", + "lastGenerated": "2026-01-26T10:23:58.869Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/getMentorDetail.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor-only/folder.bru": { + "hash": "3176b71042e68048761678dc33e46ea34a24b11cbaa4fb3373662c287ecf8140", + "lastGenerated": "2026-01-26T10:23:58.869Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor-only/나의 멘토 페이지 [my-mentor-page].bru": { + "hash": "af32af4f06e745b9328b761b112ecd44f9dbfb9918a131a7abd9c72488a508fe", + "lastGenerated": "2026-01-26T10:23:58.869Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/getMyMentorPage.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor-only/나의 멘토 페이지 수정 [update-my-mentor-page].bru": { + "hash": "26ed6a8dc111253f4b34a93cd3df4d6f730f758a2b8a77c6af50af018395560d", + "lastGenerated": "2026-01-26T10:23:58.870Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/putUpdateMyMentorPage.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor-only/멘토링 수락-거절 [mentoring-status].bru": { + "hash": "9869b8f41bd4337e47b941a47887d55c465f94d530a7a688f742ba29859bfcc5", + "lastGenerated": "2026-01-26T10:23:58.870Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/patchMentoringStatus.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor-only/멘토링 확인 [confirm-mentoring].bru": { + "hash": "4d6dd27804baa1abfbf2c830f4a4909479c8b66bbb8d375e81b94686f66d9360", + "lastGenerated": "2026-01-26T10:23:58.870Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/patchConfirmMentoring.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor-only/신청받은 멘토링 목록 [received-mentorings].bru": { + "hash": "f193dd8236f296c9f7a1a019a2373f37f9c1ae11ed811f62ad4ba7bc85b2c642", + "lastGenerated": "2026-01-26T10:23:58.870Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/getReceivedMentorings.ts" + ] + }, + "/tmp/bruno/Solid Connection/9) 멘토 [mentor]/mentor-only/확인하지 않은 멘토링 수 [unconfirmed-mentoring-count].bru": { + "hash": "3015bf13815f41cf207cce046ab98a6a5e08e8fa2071af5e3aaf3f4e48253a84", + "lastGenerated": "2026-01-26T10:23:58.871Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/mentor/getUnconfirmedMentoringCount.ts" + ] + }, + "/tmp/bruno/Solid Connection/99) 카카오 API [kakao-api]/folder.bru": { + "hash": "beda2c003d02394e0afa2775dd617e700412635638dd0f67009cebe4fb45c289", + "lastGenerated": "2026-01-26T10:23:58.871Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/99) 카카오 API [kakao-api]/카카오 사용자 ID 목록 [kakao-user-ids].bru": { + "hash": "43efbd034ff7451fbb0e26d885d5439ee7d70c4fe5df6321d9d0712f137b7ae1", + "lastGenerated": "2026-01-26T10:23:58.871Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/kakao-api/getKakaoUserIds.ts" + ] + }, + "/tmp/bruno/Solid Connection/99) 카카오 API [kakao-api]/카카오 연결 끊기 [kakao-unlink].bru": { + "hash": "d0c47c341f87a46e15799ee8ed244a8cf5e2371693379101a57701ba4c86dd46", + "lastGenerated": "2026-01-26T10:23:58.871Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/kakao-api/postKakaoUnlink.ts" + ] + }, + "/tmp/bruno/Solid Connection/99) 카카오 API [kakao-api]/카카오 정보 조회 [kakao-info].bru": { + "hash": "8ed6efdb7133151694d33c3378dc0b8691d8f7e865616c8fff16182078430c24", + "lastGenerated": "2026-01-26T10:23:58.871Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/kakao-api/getKakaoInfo.ts" + ] + }, + "/tmp/bruno/Solid Connection/environments/dev.bru": { + "hash": "859dbdba0f24522be318a5e07a706330527ae5adfd036eba073ff1f12e5a4bc0", + "lastGenerated": "2026-01-26T10:23:58.872Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/environments/local.bru": { + "hash": "608fe37e11d05512f91884e62b55b0c23d3075d0cde747d61e990577d1f22114", + "lastGenerated": "2026-01-26T10:23:58.872Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/environments/prod.bru": { + "hash": "5cbd9c94dcd58e9bf3f745bd2fe2394e8a99dfe3ec83ef568667a70a8e9d2812", + "lastGenerated": "2026-01-26T10:23:58.872Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/이미지 업로드 [image-upload]/folder.bru": { + "hash": "f294e3f7b8f7b16fdc0d091949fcb0b0654db6c53195e7def953c1d1a2ca80e6", + "lastGenerated": "2026-01-26T10:23:58.872Z", + "outputFiles": [] + }, + "/tmp/bruno/Solid Connection/이미지 업로드 [image-upload]/슬랙 알림 [slack-notification].bru": { + "hash": "c8ad069d7a05fc8e15783e0f4d2d08f8f84f6af5edc3ae3f1ebffe94435eec34", + "lastGenerated": "2026-01-26T10:23:58.872Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/image-upload/postSlackNotification.ts" + ] + }, + "/tmp/bruno/Solid Connection/이미지 업로드 [image-upload]/어학 성적표 업로드 [upload-language-test-report].bru": { + "hash": "0a1b2191be71cef5b605bd645df0d43f084db5da1db44bf465c3a40754fd0f4f", + "lastGenerated": "2026-01-26T10:23:58.872Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/image-upload/postUploadLanguageTestReport.ts" + ] + }, + "/tmp/bruno/Solid Connection/이미지 업로드 [image-upload]/프로필 사진 업로드 [upload-profile-image].bru": { + "hash": "37a4dac04578a030de4fc83574b52c0c0c5968fb7ca00fdfcdf40ae243d28ff8", + "lastGenerated": "2026-01-26T10:23:58.872Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/image-upload/postUploadProfileImage.ts" + ] + }, + "/tmp/bruno/Solid Connection/이미지 업로드 [image-upload]/프로필 사진 업로드 가입전 [upload-profile-image-before-signup].bru": { + "hash": "134ab99c4221821407a41d1471b5a73ce04b7c3c1055bb6168ea269fbce66e0b", + "lastGenerated": "2026-01-26T10:23:58.873Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/image-upload/postUploadProfileImageBeforeSignup.ts" + ] + }, + "/tmp/bruno/Solid Connection/이미지 업로드 [image-upload]/학적 성적표 업로드 [upload-gpa-report].bru": { + "hash": "a65ca1a81af6b2cf74ba6594589928581b0a816368adaeee25c0da5c6eb088da", + "lastGenerated": "2026-01-26T10:23:58.873Z", + "outputFiles": [ + "/home/runner/work/solid-connect-web/solid-connect-web/apps/web/src/apis/image-upload/postUploadGpaReport.ts" + ] + } + } +} \ No newline at end of file diff --git a/apps/web/src/apis/Admin/api.ts b/apps/web/src/apis/Admin/api.ts index 74b67368..5b6cffa8 100644 --- a/apps/web/src/apis/Admin/api.ts +++ b/apps/web/src/apis/Admin/api.ts @@ -71,6 +71,14 @@ export interface LanguageTestListResponse { empty: boolean; } +export type 유저 차단 수동 해제Response = Record; + +export type 유저 차단 수동 해제Request = Record; + +export type 유저 차단Response = Record; + +export type 유저 차단Request = Record; + export interface VerifyGpaResponse { id: number; gpa: number; @@ -143,34 +151,46 @@ 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; + }, + + patch유저 차단 수동 해제: async (params: { userId: string | number, data?: 유저 차단 수동 해제Request }): Promise<유저 차단 수동 해제Response> => { + const res = await axiosInstance.patch<유저 차단 수동 해제Response>( + `/admin/users/${params.userId}/unban`, params?.data + ); + return res.data; + }, + + post유저 차단: async (params: { userId: string | number, data?: 유저 차단Request }): Promise<유저 차단Response> => { + const res = await axiosInstance.post<유저 차단Response>( + `/admin/users/${params.userId}/ban`, params?.data + ); 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/apps/web/src/apis/Admin/getGpaList.ts b/apps/web/src/apis/Admin/getGpaList.ts index bb3448f8..d3ae89e6 100644 --- a/apps/web/src/apis/Admin/getGpaList.ts +++ b/apps/web/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/apps/web/src/apis/Admin/getLanguageTestList.ts b/apps/web/src/apis/Admin/getLanguageTestList.ts index 3192c406..6d9325d8 100644 --- a/apps/web/src/apis/Admin/getLanguageTestList.ts +++ b/apps/web/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/apps/web/src/apis/Admin/index.ts b/apps/web/src/apis/Admin/index.ts index f7d22c2a..89d2da92 100644 --- a/apps/web/src/apis/Admin/index.ts +++ b/apps/web/src/apis/Admin/index.ts @@ -1,5 +1,7 @@ -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 patch유저 차단 수동 해제 } from './patch유저 차단 수동 해제'; +export { default as post유저 차단 } from './post유저 차단'; +export { default as putVerifyGpa } from './putVerifyGpa'; +export { default as putVerifyLanguageTest } from './putVerifyLanguageTest'; diff --git "a/apps/web/src/apis/Admin/patch\354\234\240\354\240\200 \354\260\250\353\213\250 \354\210\230\353\217\231 \355\225\264\354\240\234.ts" "b/apps/web/src/apis/Admin/patch\354\234\240\354\240\200 \354\260\250\353\213\250 \354\210\230\353\217\231 \355\225\264\354\240\234.ts" new file mode 100644 index 00000000..2fec3dad --- /dev/null +++ "b/apps/web/src/apis/Admin/patch\354\234\240\354\240\200 \354\260\250\353\213\250 \354\210\230\353\217\231 \355\225\264\354\240\234.ts" @@ -0,0 +1,11 @@ +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { adminApi, 유저 차단 수동 해제Response, 유저 차단 수동 해제Request } from "./api"; + +const usePatch유저 차단 수동 해제 = () => { + return useMutation<유저 차단 수동 해제Response, AxiosError, { userId: string | number; data: 유저 차단 수동 해제Request }>({ + mutationFn: (variables) => adminApi.patch유저 차단 수동 해제(variables), + }); +}; + +export default usePatch유저 차단 수동 해제; \ No newline at end of file diff --git "a/apps/web/src/apis/Admin/post\354\234\240\354\240\200 \354\260\250\353\213\250.ts" "b/apps/web/src/apis/Admin/post\354\234\240\354\240\200 \354\260\250\353\213\250.ts" new file mode 100644 index 00000000..78e06a44 --- /dev/null +++ "b/apps/web/src/apis/Admin/post\354\234\240\354\240\200 \354\260\250\353\213\250.ts" @@ -0,0 +1,11 @@ +import { AxiosError } from "axios"; +import { useMutation } from "@tanstack/react-query"; +import { adminApi, 유저 차단Response, 유저 차단Request } from "./api"; + +const usePost유저 차단 = () => { + return useMutation<유저 차단Response, AxiosError, { userId: string | number; data: 유저 차단Request }>({ + mutationFn: (variables) => adminApi.post유저 차단(variables), + }); +}; + +export default usePost유저 차단; \ No newline at end of file diff --git a/apps/web/src/apis/Admin/putVerifyGpa.ts b/apps/web/src/apis/Admin/putVerifyGpa.ts index 9d834b2f..8073d81a 100644 --- a/apps/web/src/apis/Admin/putVerifyGpa.ts +++ b/apps/web/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/apps/web/src/apis/Admin/putVerifyLanguageTest.ts b/apps/web/src/apis/Admin/putVerifyLanguageTest.ts index 0e04811c..fa37c5e4 100644 --- a/apps/web/src/apis/Admin/putVerifyLanguageTest.ts +++ b/apps/web/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/apps/web/src/apis/Auth/api.ts b/apps/web/src/apis/Auth/api.ts index 3f04e115..7d6ac3be 100644 --- a/apps/web/src/apis/Auth/api.ts +++ b/apps/web/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/apps/web/src/apis/Auth/deleteAccount.ts b/apps/web/src/apis/Auth/deleteAccount.ts index 546282a4..00038562 100644 --- a/apps/web/src/apis/Auth/deleteAccount.ts +++ b/apps/web/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/apps/web/src/apis/Auth/index.ts b/apps/web/src/apis/Auth/index.ts index cd56347d..844947a4 100644 --- a/apps/web/src/apis/Auth/index.ts +++ b/apps/web/src/apis/Auth/index.ts @@ -1,25 +1,9 @@ -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 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/apps/web/src/apis/Auth/postAppleAuth.ts b/apps/web/src/apis/Auth/postAppleAuth.ts index c62cfdd9..cb30b87b 100644 --- a/apps/web/src/apis/Auth/postAppleAuth.ts +++ b/apps/web/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/apps/web/src/apis/Auth/postEmailLogin.ts b/apps/web/src/apis/Auth/postEmailLogin.ts index 1597a15c..d8ef06df 100644 --- a/apps/web/src/apis/Auth/postEmailLogin.ts +++ b/apps/web/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/apps/web/src/apis/Auth/postEmailVerification.ts b/apps/web/src/apis/Auth/postEmailVerification.ts index e9fe17f6..99aefafe 100644 --- a/apps/web/src/apis/Auth/postEmailVerification.ts +++ b/apps/web/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/apps/web/src/apis/Auth/postKakaoAuth.ts b/apps/web/src/apis/Auth/postKakaoAuth.ts index ee5e22b6..2aaebd97 100644 --- a/apps/web/src/apis/Auth/postKakaoAuth.ts +++ b/apps/web/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/apps/web/src/apis/Auth/postRefreshToken.ts b/apps/web/src/apis/Auth/postRefreshToken.ts index 68fbf570..ae86a780 100644 --- a/apps/web/src/apis/Auth/postRefreshToken.ts +++ b/apps/web/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/apps/web/src/apis/Auth/postSignOut.ts b/apps/web/src/apis/Auth/postSignOut.ts index a983f61a..8d31dc93 100644 --- a/apps/web/src/apis/Auth/postSignOut.ts +++ b/apps/web/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/apps/web/src/apis/Auth/postSignUp.ts b/apps/web/src/apis/Auth/postSignUp.ts index c5068006..eadc9cb8 100644 --- a/apps/web/src/apis/Auth/postSignUp.ts +++ b/apps/web/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/apps/web/src/apis/MyPage/api.ts b/apps/web/src/apis/MyPage/api.ts index 8586b26d..d6f5f956 100644 --- a/apps/web/src/apis/MyPage/api.ts +++ b/apps/web/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/apps/web/src/apis/MyPage/getProfile.ts b/apps/web/src/apis/MyPage/getProfile.ts index 3ca32d82..042c0767 100644 --- a/apps/web/src/apis/MyPage/getProfile.ts +++ b/apps/web/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/apps/web/src/apis/MyPage/index.ts b/apps/web/src/apis/MyPage/index.ts index f431945c..31a7cccf 100644 --- a/apps/web/src/apis/MyPage/index.ts +++ b/apps/web/src/apis/MyPage/index.ts @@ -1,13 +1,5 @@ -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 patchInterestedRegionCountry } from './patchInterestedRegionCountry'; +export { default as patchPassword } from './patchPassword'; +export { default as patchProfile } from './patchProfile'; diff --git a/apps/web/src/apis/MyPage/patchInterestedRegionCountry.ts b/apps/web/src/apis/MyPage/patchInterestedRegionCountry.ts index 0b15e70f..0ea8b18f 100644 --- a/apps/web/src/apis/MyPage/patchInterestedRegionCountry.ts +++ b/apps/web/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/apps/web/src/apis/MyPage/patchPassword.ts b/apps/web/src/apis/MyPage/patchPassword.ts index ac8096f8..8592b77e 100644 --- a/apps/web/src/apis/MyPage/patchPassword.ts +++ b/apps/web/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/apps/web/src/apis/MyPage/patchProfile.ts b/apps/web/src/apis/MyPage/patchProfile.ts index ce26560c..20204ad8 100644 --- a/apps/web/src/apis/MyPage/patchProfile.ts +++ b/apps/web/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/apps/web/src/apis/Scores/api.ts b/apps/web/src/apis/Scores/api.ts index e1961939..5b45182c 100644 --- a/apps/web/src/apis/Scores/api.ts +++ b/apps/web/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/apps/web/src/apis/Scores/getGpaList.ts b/apps/web/src/apis/Scores/getGpaList.ts index 00437ae8..b402a643 100644 --- a/apps/web/src/apis/Scores/getGpaList.ts +++ b/apps/web/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/apps/web/src/apis/Scores/getLanguageTestList.ts b/apps/web/src/apis/Scores/getLanguageTestList.ts index 22a42549..ace30a13 100644 --- a/apps/web/src/apis/Scores/getLanguageTestList.ts +++ b/apps/web/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/apps/web/src/apis/Scores/index.ts b/apps/web/src/apis/Scores/index.ts index 529612eb..73669f35 100644 --- a/apps/web/src/apis/Scores/index.ts +++ b/apps/web/src/apis/Scores/index.ts @@ -1,12 +1,5 @@ -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 postCreateGpa } from './postCreateGpa'; +export { default as postCreateLanguageTest } from './postCreateLanguageTest'; diff --git a/apps/web/src/apis/Scores/postCreateGpa.ts b/apps/web/src/apis/Scores/postCreateGpa.ts index 7cf6174a..6255a5d0 100644 --- a/apps/web/src/apis/Scores/postCreateGpa.ts +++ b/apps/web/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/apps/web/src/apis/Scores/postCreateLanguageTest.ts b/apps/web/src/apis/Scores/postCreateLanguageTest.ts index d4ebbc42..b6201433 100644 --- a/apps/web/src/apis/Scores/postCreateLanguageTest.ts +++ b/apps/web/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/apps/web/src/apis/applications/api.ts b/apps/web/src/apis/applications/api.ts index 5837a038..f4879dd1 100644 --- a/apps/web/src/apis/applications/api.ts +++ b/apps/web/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/apps/web/src/apis/applications/getApplicants.ts b/apps/web/src/apis/applications/getApplicants.ts index f7da9024..2a266ec3 100644 --- a/apps/web/src/apis/applications/getApplicants.ts +++ b/apps/web/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/apps/web/src/apis/applications/getCompetitors.ts b/apps/web/src/apis/applications/getCompetitors.ts index e137b9bd..4d3ccbc9 100644 --- a/apps/web/src/apis/applications/getCompetitors.ts +++ b/apps/web/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/apps/web/src/apis/applications/index.ts b/apps/web/src/apis/applications/index.ts index f0b0f16b..3169f9b1 100644 --- a/apps/web/src/apis/applications/index.ts +++ b/apps/web/src/apis/applications/index.ts @@ -1,5 +1,4 @@ -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 postSubmitApplication } from './postSubmitApplication'; diff --git a/apps/web/src/apis/applications/postSubmitApplication.ts b/apps/web/src/apis/applications/postSubmitApplication.ts index 4c8d374a..5434d6ee 100644 --- a/apps/web/src/apis/applications/postSubmitApplication.ts +++ b/apps/web/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/apps/web/src/apis/chat/api.ts b/apps/web/src/apis/chat/api.ts index 1fa093d0..11da37af 100644 --- a/apps/web/src/apis/chat/api.ts +++ b/apps/web/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/apps/web/src/apis/chat/getChatMessages.ts b/apps/web/src/apis/chat/getChatMessages.ts index 1b01ab23..2cf05b68 100644 --- a/apps/web/src/apis/chat/getChatMessages.ts +++ b/apps/web/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/apps/web/src/apis/chat/getChatPartner.ts b/apps/web/src/apis/chat/getChatPartner.ts index 56be7d48..ab3ab0c0 100644 --- a/apps/web/src/apis/chat/getChatPartner.ts +++ b/apps/web/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/apps/web/src/apis/chat/getChatRooms.ts b/apps/web/src/apis/chat/getChatRooms.ts index b96a43d2..b2c6c0c4 100644 --- a/apps/web/src/apis/chat/getChatRooms.ts +++ b/apps/web/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/apps/web/src/apis/chat/index.ts b/apps/web/src/apis/chat/index.ts index e1a190a4..c6566109 100644 --- a/apps/web/src/apis/chat/index.ts +++ b/apps/web/src/apis/chat/index.ts @@ -1,6 +1,5 @@ -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 putReadChatRoom } from './putReadChatRoom'; diff --git a/apps/web/src/apis/chat/putReadChatRoom.ts b/apps/web/src/apis/chat/putReadChatRoom.ts index 3aea8922..02af78df 100644 --- a/apps/web/src/apis/chat/putReadChatRoom.ts +++ b/apps/web/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/apps/web/src/apis/community/api.ts b/apps/web/src/apis/community/api.ts index 0ffc27fb..52eaec57 100644 --- a/apps/web/src/apis/community/api.ts +++ b/apps/web/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/apps/web/src/apis/community/deleteComment.ts b/apps/web/src/apis/community/deleteComment.ts index 77ca58ca..6bea8c7e 100644 --- a/apps/web/src/apis/community/deleteComment.ts +++ b/apps/web/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/apps/web/src/apis/community/deleteLikePost.ts b/apps/web/src/apis/community/deleteLikePost.ts index 0c6a81b6..63036f50 100644 --- a/apps/web/src/apis/community/deleteLikePost.ts +++ b/apps/web/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/apps/web/src/apis/community/deletePost.ts b/apps/web/src/apis/community/deletePost.ts index a3307b17..1b194b65 100644 --- a/apps/web/src/apis/community/deletePost.ts +++ b/apps/web/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/apps/web/src/apis/community/getBoard.ts b/apps/web/src/apis/community/getBoard.ts index 7e3174e5..1ea2869d 100644 --- a/apps/web/src/apis/community/getBoard.ts +++ b/apps/web/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/apps/web/src/apis/community/getBoardList.ts b/apps/web/src/apis/community/getBoardList.ts index e1455822..bcb0d65b 100644 --- a/apps/web/src/apis/community/getBoardList.ts +++ b/apps/web/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/apps/web/src/apis/community/getPostDetail.ts b/apps/web/src/apis/community/getPostDetail.ts index fcc71ef7..ba5cc61a 100644 --- a/apps/web/src/apis/community/getPostDetail.ts +++ b/apps/web/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/apps/web/src/apis/community/index.ts b/apps/web/src/apis/community/index.ts index d396a31d..18902ac8 100644 --- a/apps/web/src/apis/community/index.ts +++ b/apps/web/src/apis/community/index.ts @@ -1,26 +1,14 @@ -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 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/apps/web/src/apis/community/patchUpdateComment.ts b/apps/web/src/apis/community/patchUpdateComment.ts index 8b235b55..3a0fbfe6 100644 --- a/apps/web/src/apis/community/patchUpdateComment.ts +++ b/apps/web/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/apps/web/src/apis/community/patchUpdatePost.ts b/apps/web/src/apis/community/patchUpdatePost.ts index ba2be8a0..acbdf578 100644 --- a/apps/web/src/apis/community/patchUpdatePost.ts +++ b/apps/web/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/apps/web/src/apis/community/postCreateComment.ts b/apps/web/src/apis/community/postCreateComment.ts index 2004f1a1..215cd41e 100644 --- a/apps/web/src/apis/community/postCreateComment.ts +++ b/apps/web/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/apps/web/src/apis/community/postCreatePost.ts b/apps/web/src/apis/community/postCreatePost.ts index 8a8d29ab..e83b02c4 100644 --- a/apps/web/src/apis/community/postCreatePost.ts +++ b/apps/web/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/apps/web/src/apis/community/postLikePost.ts b/apps/web/src/apis/community/postLikePost.ts index a723c7dd..f88f4c4c 100644 --- a/apps/web/src/apis/community/postLikePost.ts +++ b/apps/web/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/apps/web/src/apis/environments/api.ts b/apps/web/src/apis/environments/api.ts new file mode 100644 index 00000000..df9d1b7d --- /dev/null +++ b/apps/web/src/apis/environments/api.ts @@ -0,0 +1,4 @@ +import { axiosInstance } from "@/utils/axiosInstance"; + +export const environmentsApi = { +}; \ No newline at end of file diff --git a/apps/web/src/apis/environments/index.ts b/apps/web/src/apis/environments/index.ts new file mode 100644 index 00000000..86a6a74e --- /dev/null +++ b/apps/web/src/apis/environments/index.ts @@ -0,0 +1 @@ +export { environmentsApi } from './api'; diff --git a/apps/web/src/apis/image-upload/api.ts b/apps/web/src/apis/image-upload/api.ts index 932d1a69..a2024dda 100644 --- a/apps/web/src/apis/image-upload/api.ts +++ b/apps/web/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/apps/web/src/apis/image-upload/index.ts b/apps/web/src/apis/image-upload/index.ts index d6ee6647..95f3e6f9 100644 --- a/apps/web/src/apis/image-upload/index.ts +++ b/apps/web/src/apis/image-upload/index.ts @@ -1,8 +1,6 @@ -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 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/apps/web/src/apis/image-upload/postSlackNotification.ts b/apps/web/src/apis/image-upload/postSlackNotification.ts index f4b397a8..c973ec12 100644 --- a/apps/web/src/apis/image-upload/postSlackNotification.ts +++ b/apps/web/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/apps/web/src/apis/image-upload/postUploadGpaReport.ts b/apps/web/src/apis/image-upload/postUploadGpaReport.ts index f8ef7529..06ed6ece 100644 --- a/apps/web/src/apis/image-upload/postUploadGpaReport.ts +++ b/apps/web/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/apps/web/src/apis/image-upload/postUploadLanguageTestReport.ts b/apps/web/src/apis/image-upload/postUploadLanguageTestReport.ts index 6a939941..7b36f675 100644 --- a/apps/web/src/apis/image-upload/postUploadLanguageTestReport.ts +++ b/apps/web/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/apps/web/src/apis/image-upload/postUploadProfileImage.ts b/apps/web/src/apis/image-upload/postUploadProfileImage.ts index 0b8e35a9..72db4ae2 100644 --- a/apps/web/src/apis/image-upload/postUploadProfileImage.ts +++ b/apps/web/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/apps/web/src/apis/image-upload/postUploadProfileImageBeforeSignup.ts b/apps/web/src/apis/image-upload/postUploadProfileImageBeforeSignup.ts index 88eb117d..edf2b95c 100644 --- a/apps/web/src/apis/image-upload/postUploadProfileImageBeforeSignup.ts +++ b/apps/web/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/apps/web/src/apis/kakao-api/api.ts b/apps/web/src/apis/kakao-api/api.ts index 935a1bc6..51eda46d 100644 --- a/apps/web/src/apis/kakao-api/api.ts +++ b/apps/web/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/apps/web/src/apis/kakao-api/getKakaoInfo.ts b/apps/web/src/apis/kakao-api/getKakaoInfo.ts index 2c5482dc..92c82449 100644 --- a/apps/web/src/apis/kakao-api/getKakaoInfo.ts +++ b/apps/web/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/apps/web/src/apis/kakao-api/getKakaoUserIds.ts b/apps/web/src/apis/kakao-api/getKakaoUserIds.ts index 89159426..dc85cac5 100644 --- a/apps/web/src/apis/kakao-api/getKakaoUserIds.ts +++ b/apps/web/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/apps/web/src/apis/kakao-api/index.ts b/apps/web/src/apis/kakao-api/index.ts index 0acb2db7..bd6c3ae8 100644 --- a/apps/web/src/apis/kakao-api/index.ts +++ b/apps/web/src/apis/kakao-api/index.ts @@ -1,4 +1,4 @@ -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 postKakaoUnlink } from './postKakaoUnlink'; diff --git a/apps/web/src/apis/kakao-api/postKakaoUnlink.ts b/apps/web/src/apis/kakao-api/postKakaoUnlink.ts index 35714879..c20d19d0 100644 --- a/apps/web/src/apis/kakao-api/postKakaoUnlink.ts +++ b/apps/web/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/apps/web/src/apis/mentor/api.ts b/apps/web/src/apis/mentor/api.ts index d4069700..1a11d710 100644 --- a/apps/web/src/apis/mentor/api.ts +++ b/apps/web/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/apps/web/src/apis/mentor/getAppliedMentorings.ts b/apps/web/src/apis/mentor/getAppliedMentorings.ts index 17ee3b3f..54a9d70b 100644 --- a/apps/web/src/apis/mentor/getAppliedMentorings.ts +++ b/apps/web/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/apps/web/src/apis/mentor/getMatchedMentors.ts b/apps/web/src/apis/mentor/getMatchedMentors.ts index c89239f1..40ff31b9 100644 --- a/apps/web/src/apis/mentor/getMatchedMentors.ts +++ b/apps/web/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/apps/web/src/apis/mentor/getMentorDetail.ts b/apps/web/src/apis/mentor/getMentorDetail.ts index 75cbc778..88f22b9e 100644 --- a/apps/web/src/apis/mentor/getMentorDetail.ts +++ b/apps/web/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/apps/web/src/apis/mentor/getMentorList.ts b/apps/web/src/apis/mentor/getMentorList.ts index 8e41e741..465458c0 100644 --- a/apps/web/src/apis/mentor/getMentorList.ts +++ b/apps/web/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/apps/web/src/apis/mentor/getMyMentorPage.ts b/apps/web/src/apis/mentor/getMyMentorPage.ts index 7f0a7448..db6d1b42 100644 --- a/apps/web/src/apis/mentor/getMyMentorPage.ts +++ b/apps/web/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/apps/web/src/apis/mentor/getReceivedMentorings.ts b/apps/web/src/apis/mentor/getReceivedMentorings.ts index 7355a7a1..81d875cf 100644 --- a/apps/web/src/apis/mentor/getReceivedMentorings.ts +++ b/apps/web/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/apps/web/src/apis/mentor/getUnconfirmedMentoringCount.ts b/apps/web/src/apis/mentor/getUnconfirmedMentoringCount.ts index 5d55d649..7c3b9c1b 100644 --- a/apps/web/src/apis/mentor/getUnconfirmedMentoringCount.ts +++ b/apps/web/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/apps/web/src/apis/mentor/index.ts b/apps/web/src/apis/mentor/index.ts index 7986dd51..5e89fb8e 100644 --- a/apps/web/src/apis/mentor/index.ts +++ b/apps/web/src/apis/mentor/index.ts @@ -1,26 +1,14 @@ -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 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/apps/web/src/apis/mentor/patchConfirmMentoring.ts b/apps/web/src/apis/mentor/patchConfirmMentoring.ts index a423e814..43e07f3f 100644 --- a/apps/web/src/apis/mentor/patchConfirmMentoring.ts +++ b/apps/web/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/apps/web/src/apis/mentor/patchMentoringStatus.ts b/apps/web/src/apis/mentor/patchMentoringStatus.ts index 76fb6cd9..eec04d74 100644 --- a/apps/web/src/apis/mentor/patchMentoringStatus.ts +++ b/apps/web/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/apps/web/src/apis/mentor/postApplyMentoring.ts b/apps/web/src/apis/mentor/postApplyMentoring.ts index 6be451f4..f5a54e52 100644 --- a/apps/web/src/apis/mentor/postApplyMentoring.ts +++ b/apps/web/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/apps/web/src/apis/mentor/putUpdateMyMentorPage.ts b/apps/web/src/apis/mentor/putUpdateMyMentorPage.ts index 69a59090..a3cd5a31 100644 --- a/apps/web/src/apis/mentor/putUpdateMyMentorPage.ts +++ b/apps/web/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/apps/web/src/apis/news/api.ts b/apps/web/src/apis/news/api.ts index dccf7dc5..13a68b0b 100644 --- a/apps/web/src/apis/news/api.ts +++ b/apps/web/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/apps/web/src/apis/news/deleteLikeNews.ts b/apps/web/src/apis/news/deleteLikeNews.ts index 67898dba..9e0ad49c 100644 --- a/apps/web/src/apis/news/deleteLikeNews.ts +++ b/apps/web/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/apps/web/src/apis/news/deleteNews.ts b/apps/web/src/apis/news/deleteNews.ts index ba0542de..854b6392 100644 --- a/apps/web/src/apis/news/deleteNews.ts +++ b/apps/web/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/apps/web/src/apis/news/getNewsList.ts b/apps/web/src/apis/news/getNewsList.ts index fcbc7832..bd2f587d 100644 --- a/apps/web/src/apis/news/getNewsList.ts +++ b/apps/web/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/apps/web/src/apis/news/index.ts b/apps/web/src/apis/news/index.ts index 000e3daa..dc313953 100644 --- a/apps/web/src/apis/news/index.ts +++ b/apps/web/src/apis/news/index.ts @@ -1,15 +1,7 @@ -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 postCreateNews } from './postCreateNews'; +export { default as postLikeNews } from './postLikeNews'; +export { default as putUpdateNews } from './putUpdateNews'; diff --git a/apps/web/src/apis/news/postCreateNews.ts b/apps/web/src/apis/news/postCreateNews.ts index 95621848..075351f2 100644 --- a/apps/web/src/apis/news/postCreateNews.ts +++ b/apps/web/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/apps/web/src/apis/news/postLikeNews.ts b/apps/web/src/apis/news/postLikeNews.ts index 86adc752..9aaf4c53 100644 --- a/apps/web/src/apis/news/postLikeNews.ts +++ b/apps/web/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/apps/web/src/apis/news/putUpdateNews.ts b/apps/web/src/apis/news/putUpdateNews.ts index 614bc5d6..d7fedea7 100644 --- a/apps/web/src/apis/news/putUpdateNews.ts +++ b/apps/web/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/apps/web/src/apis/queryKeys.ts b/apps/web/src/apis/queryKeys.ts index 3963ad5a..e8088405 100644 --- a/apps/web/src/apis/queryKeys.ts +++ b/apps/web/src/apis/queryKeys.ts @@ -5,128 +5,127 @@ 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, + 유저 차단 수동 해제: 'Admin.유저 차단 수동 해제' as const, + 유저 차단: 'Admin.유저 차단' 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, }, 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/apps/web/src/apis/reports/api.ts b/apps/web/src/apis/reports/api.ts index c1417589..39bd649c 100644 --- a/apps/web/src/apis/reports/api.ts +++ b/apps/web/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/apps/web/src/apis/reports/index.ts b/apps/web/src/apis/reports/index.ts index 25277463..c8d54d63 100644 --- a/apps/web/src/apis/reports/index.ts +++ b/apps/web/src/apis/reports/index.ts @@ -1,3 +1,2 @@ -export type { UsePostReportsRequest } from "./api"; -export { reportsApi } from "./api"; -export { default as usePostReports } from "./postReport"; +export { reportsApi } from './api'; +export { default as postReport } from './postReport'; diff --git a/apps/web/src/apis/reports/postReport.ts b/apps/web/src/apis/reports/postReport.ts index acb3f013..76fd804f 100644 --- a/apps/web/src/apis/reports/postReport.ts +++ b/apps/web/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/apps/web/src/apis/universities/api.ts b/apps/web/src/apis/universities/api.ts index 56b2bb19..35419bc6 100644 --- a/apps/web/src/apis/universities/api.ts +++ b/apps/web/src/apis/universities/api.ts @@ -1,5 +1,4 @@ -import type { HomeUniversityName } from "@/types/university"; -import { axiosInstance, publicAxiosInstance } from "@/utils/axiosInstance"; +import { axiosInstance } from "@/utils/axiosInstance"; export interface RecommendedUniversitiesResponseRecommendedUniversitiesItem { id: number; @@ -40,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; @@ -90,13 +89,13 @@ export interface SearchTextResponseUnivApplyInfoPreviewsItem { id: number; term: string; koreanName: string; + homeUniversityName: string; region: string; country: string; logoImageUrl: string; backgroundImageUrl: string; studentCapacity: number; languageRequirements: SearchTextResponseUnivApplyInfoPreviewsItemLanguageRequirementsItem[]; - homeUniversityName?: HomeUniversityName; } export interface SearchTextResponseUnivApplyInfoPreviewsItemLanguageRequirementsItem { @@ -108,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/apps/web/src/apis/universities/deleteWish.ts b/apps/web/src/apis/universities/deleteWish.ts index c76c58ec..e4c88b1f 100644 --- a/apps/web/src/apis/universities/deleteWish.ts +++ b/apps/web/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/apps/web/src/apis/universities/getByRegionCountry.ts b/apps/web/src/apis/universities/getByRegionCountry.ts index 43e04cbf..baa84596 100644 --- a/apps/web/src/apis/universities/getByRegionCountry.ts +++ b/apps/web/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/apps/web/src/apis/universities/getIsWish.ts b/apps/web/src/apis/universities/getIsWish.ts index a1d54a65..567a0887 100644 --- a/apps/web/src/apis/universities/getIsWish.ts +++ b/apps/web/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/apps/web/src/apis/universities/getSearchText.ts b/apps/web/src/apis/universities/getSearchText.ts index 1ca20e45..30967c5e 100644 --- a/apps/web/src/apis/universities/getSearchText.ts +++ b/apps/web/src/apis/universities/getSearchText.ts @@ -1,67 +1,13 @@ +import { AxiosError } from "axios"; import { useQuery } from "@tanstack/react-query"; - -import type { AxiosError } from "axios"; -import { useMemo } from "react"; -import type { HomeUniversityName, ListUniversity } from "@/types/university"; +import { universitiesApi, SearchTextResponse } from "./api"; import { QueryKeys } from "../queryKeys"; -import { type SearchTextResponse, universitiesApi } from "./api"; - -// API 응답에 homeUniversityName이 포함된 타입 -interface ListUniversityWithHome extends ListUniversity { - homeUniversityName?: HomeUniversityName; -} -/** - * @description 대학 검색을 위한 useQuery 커스텀 훅 - * 모든 대학 데이터를 한 번만 가져와 캐싱하고, 검색어에 따라 클라이언트에서 필터링합니다. - * @param searchValue - 검색어 - * @param homeUniversityName - 홈 대학교 이름 (선택적 필터) - */ -const useUniversitySearch = (searchValue: string, homeUniversityName?: HomeUniversityName) => { - // 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 ListUniversityWithHome[], +const useGetSearchText = (params?: Record) => { + return useQuery({ + queryKey: [QueryKeys.universities.searchText, params], + queryFn: () => universitiesApi.getSearchText(params ? { params } : {}), }); - - // 2. 검색어와 homeUniversityName에 따라 필터링합니다. - const filteredUniversities = useMemo(() => { - const normalizedSearchValue = searchValue.trim().toLowerCase(); - - if (!allUniversities) { - return []; - } - - let filtered = allUniversities; - - // homeUniversityName 필터링 - if (homeUniversityName) { - filtered = filtered.filter((university) => university.homeUniversityName === homeUniversityName); - } - - // 검색어 필터링 - if (normalizedSearchValue) { - filtered = filtered.filter((university) => university.koreanName.toLowerCase().includes(normalizedSearchValue)); - } - - return filtered; - }, [allUniversities, searchValue, homeUniversityName]); - - 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/apps/web/src/apis/universities/getUniversityDetail.ts b/apps/web/src/apis/universities/getUniversityDetail.ts index e5a3c6d1..f5601ea6 100644 --- a/apps/web/src/apis/universities/getUniversityDetail.ts +++ b/apps/web/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/apps/web/src/apis/universities/getWishList.ts b/apps/web/src/apis/universities/getWishList.ts index 3bd08cf7..5c9f238e 100644 --- a/apps/web/src/apis/universities/getWishList.ts +++ b/apps/web/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/apps/web/src/apis/universities/index.ts b/apps/web/src/apis/universities/index.ts index 95a44032..d7ddf2bb 100644 --- a/apps/web/src/apis/universities/index.ts +++ b/apps/web/src/apis/universities/index.ts @@ -1,10 +1,10 @@ -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 postAddWish } from './postAddWish'; diff --git a/apps/web/src/apis/universities/postAddWish.ts b/apps/web/src/apis/universities/postAddWish.ts index 4f0eebce..92cf94e3 100644 --- a/apps/web/src/apis/universities/postAddWish.ts +++ b/apps/web/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/apps/web/src/apis/users/api.ts b/apps/web/src/apis/users/api.ts index d91558fd..e9c4b789 100644 --- a/apps/web/src/apis/users/api.ts +++ b/apps/web/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/apps/web/src/apis/users/deleteUnblockUser.ts b/apps/web/src/apis/users/deleteUnblockUser.ts index b46b67db..385dd097 100644 --- a/apps/web/src/apis/users/deleteUnblockUser.ts +++ b/apps/web/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/apps/web/src/apis/users/getBlockedUsers.ts b/apps/web/src/apis/users/getBlockedUsers.ts index c244cb09..1681e5dd 100644 --- a/apps/web/src/apis/users/getBlockedUsers.ts +++ b/apps/web/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/apps/web/src/apis/users/getNicknameExists.ts b/apps/web/src/apis/users/getNicknameExists.ts index d86f151e..7793059c 100644 --- a/apps/web/src/apis/users/getNicknameExists.ts +++ b/apps/web/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/apps/web/src/apis/users/index.ts b/apps/web/src/apis/users/index.ts index ff51c891..6b491bd6 100644 --- a/apps/web/src/apis/users/index.ts +++ b/apps/web/src/apis/users/index.ts @@ -1,5 +1,5 @@ -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 postBlockUser } from './postBlockUser'; diff --git a/apps/web/src/apis/users/postBlockUser.ts b/apps/web/src/apis/users/postBlockUser.ts index 1c6fde9d..11b44fe8 100644 --- a/apps/web/src/apis/users/postBlockUser.ts +++ b/apps/web/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