From 0a29ba80de9e5bc57133b186af6d21ac3bbd73a2 Mon Sep 17 00:00:00 2001 From: Woosang <77317312+yws1502@users.noreply.github.com> Date: Mon, 6 Jan 2025 23:55:21 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A7=A4=EC=B9=AD=20=EC=84=A4=EB=AC=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20API=20=EC=97=B0=EB=8F=99=20(#272)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ #271 - 매칭 종료 후 매칭 설문 페이지 redirection 처리 및 매칭 이력 조회 API 연동 * 🐛 #271 - 매칭 중 상대방이 의도하지 않은 방법으로 통신을 종료하는 경우 이벤트 추가 * ✨ #271 - 피드백 생성 API 적용 * ✨ #271 - 매칭 후 블랙리스트 등록 API 연동 * 🩹 #271 - 매칭 피드백 완료 후 메인 이동 시 뒤로가기 못하도록 replace로 변경 * 🩹 #271 - 매칭 피드백 생성 axios 인스턴스 코드 포맷 통일 관련 작업 * ✏️ #271 - 블랙리스트 추가 관련 API 메소드 명 변경 * 🏷️ #271 - 매칭 히스토리 조회 응답 타입 수정 * fix: 구조분해 할당 데이터 위치 변경 #271 * fix: form 안에 있는 인터렉션 태그들 react hook form 하나로 관리 #271 --- src/api/blacklist.ts | 14 +++++ src/api/index.ts | 2 + src/api/matchingHistories.ts | 34 ++++++++++++ .../matching/FeedbackTypeCheckbox.tsx | 8 +-- .../matching/MatchingController.tsx | 5 +- src/constants/common/page.ts | 1 + src/constants/services/path.ts | 8 +++ src/constants/services/queryKeys.ts | 1 + src/hooks/services/mutations/useBlockUser.ts | 8 +++ .../mutations/useCreateMatchingFeedback.ts | 11 ++++ .../queries/useRecentMatchingHistory.ts | 13 +++++ src/pages/matching/survey.tsx | 54 ++++++++++++++----- src/types/matching.ts | 29 ++++++++-- src/utils/Matching.ts | 24 ++++++++- 14 files changed, 188 insertions(+), 24 deletions(-) create mode 100644 src/api/blacklist.ts create mode 100644 src/api/matchingHistories.ts create mode 100644 src/hooks/services/mutations/useBlockUser.ts create mode 100644 src/hooks/services/mutations/useCreateMatchingFeedback.ts create mode 100644 src/hooks/services/queries/useRecentMatchingHistory.ts diff --git a/src/api/blacklist.ts b/src/api/blacklist.ts new file mode 100644 index 00000000..d341d431 --- /dev/null +++ b/src/api/blacklist.ts @@ -0,0 +1,14 @@ +import type { OnlyMessageResponse, SuccessResponse } from 'types/response'; + +import { API_PATH } from 'constants/services'; +import axios from 'lib/axios'; + +export const addToBlackList = async (blockedUserId: string) => { + const { + data: { data }, + } = await axios.post>( + API_PATH.blacklist.addToBlackList(blockedUserId), + ); + + return data.message; +}; diff --git a/src/api/index.ts b/src/api/index.ts index 81d8a6dd..dd372bf8 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -8,3 +8,5 @@ export * from './bookmark'; export * from './profile'; export * from './activities'; export * from './badges'; +export * from './matchingHistories'; +export * from './blacklist'; diff --git a/src/api/matchingHistories.ts b/src/api/matchingHistories.ts new file mode 100644 index 00000000..b80d8a2a --- /dev/null +++ b/src/api/matchingHistories.ts @@ -0,0 +1,34 @@ +import type { + CreateMatchingFeedbackRequest, + CreateMatchingFeedbackResponse, + MatchingHistoryResponse, +} from 'types/matching'; +import type { SuccessResponse } from 'types/response'; + +import { API_PATH } from 'constants/services'; +import axios from 'lib/axios'; + +export const getRecentMatchingHistory = async () => { + const { + data: { data }, + } = await axios.get>( + API_PATH.matchingHistories.recent, + ); + + return data; +}; + +export const createMatchingFeedback = async ( + payload: CreateMatchingFeedbackRequest, +) => { + const { matchingHistoryId, ...feedbackForm } = payload; + + const { + data: { data }, + } = await axios.post>( + API_PATH.matchingHistories.feedback(matchingHistoryId), + feedbackForm, + ); + + return data; +}; diff --git a/src/components/matching/FeedbackTypeCheckbox.tsx b/src/components/matching/FeedbackTypeCheckbox.tsx index c35ec114..ce84b43d 100644 --- a/src/components/matching/FeedbackTypeCheckbox.tsx +++ b/src/components/matching/FeedbackTypeCheckbox.tsx @@ -16,25 +16,25 @@ const FeedbackTypeCheckbox = ({ register }: FeedbackTypeCheckboxProps) => { id: 'isNice', icon: , description: '친절해요', - hookFormProps: register('feedbackType.isNice'), + hookFormProps: register('isNice'), }, { id: 'isFluent', icon: , description: '영어를 잘해요', - hookFormProps: register('feedbackType.isFluent'), + hookFormProps: register('isFluent'), }, { id: 'isFun', icon: , description: '재밌어요', - hookFormProps: register('feedbackType.isFun'), + hookFormProps: register('isFun'), }, { id: 'isBad', icon: , description: '불쾌해요', - hookFormProps: register('feedbackType.isBad'), + hookFormProps: register('isBad'), }, ]); diff --git a/src/components/matching/MatchingController.tsx b/src/components/matching/MatchingController.tsx index 53409b86..38b46ba2 100644 --- a/src/components/matching/MatchingController.tsx +++ b/src/components/matching/MatchingController.tsx @@ -38,7 +38,7 @@ const MatchingController = () => { await matching.signaling(audioElement, { role: query.r as MatchingInformation['role'], socketId: query.ms as MatchingInformation['socketId'], - userId: query.mu as MatchingInformation['userId'], + userId: query.mu as MatchingInformation['userId'], // FIXME: username으로 변경 필요 }); } catch (error) { console.log(error); @@ -59,9 +59,8 @@ const MatchingController = () => { }, []); const handleEndMatching = () => { - // FIXME: 매칭 설문 페이지로 이동할 예정입니다. matching.disconnect(); - void router.replace(PAGE_PATH.main); + void router.replace(PAGE_PATH.matching.survey); }; const handleCloseAlert = () => { diff --git a/src/constants/common/page.ts b/src/constants/common/page.ts index ee61ef8b..e43e6955 100644 --- a/src/constants/common/page.ts +++ b/src/constants/common/page.ts @@ -5,6 +5,7 @@ export const PAGE_PATH = { index: '/matching', queue: '/matching/queue', matchUp: '/matching/match-up', + survey: '/matching/survey', }, diary: { diff --git a/src/constants/services/path.ts b/src/constants/services/path.ts index 2b3d3835..f0d0692a 100644 --- a/src/constants/services/path.ts +++ b/src/constants/services/path.ts @@ -25,4 +25,12 @@ export const API_PATH = { index: '/badges', users: '/badges/users', }, + matchingHistories: { + index: '/matching-histories', + recent: '/matching-histories/recent', + feedback: (id: string) => `/matching-histories/${id}/feedback`, + }, + blacklist: { + addToBlackList: (blockedUserId: string) => `/blacklist/${blockedUserId}`, + }, } as const; diff --git a/src/constants/services/queryKeys.ts b/src/constants/services/queryKeys.ts index 666163e8..78c2e4d6 100644 --- a/src/constants/services/queryKeys.ts +++ b/src/constants/services/queryKeys.ts @@ -1,4 +1,5 @@ export const queryKeys = { + recentMatchingHistory: 'recentMatchingHistory', badges: 'badges', bookmark: 'bookmark', comments: 'comments', diff --git a/src/hooks/services/mutations/useBlockUser.ts b/src/hooks/services/mutations/useBlockUser.ts new file mode 100644 index 00000000..5e56d39a --- /dev/null +++ b/src/hooks/services/mutations/useBlockUser.ts @@ -0,0 +1,8 @@ +import { useMutation } from '@tanstack/react-query'; +import * as api from 'api'; + +export const useAddToBlackList = () => { + return useMutation( + async (blockedUserId: string) => await api.addToBlackList(blockedUserId), + ); +}; diff --git a/src/hooks/services/mutations/useCreateMatchingFeedback.ts b/src/hooks/services/mutations/useCreateMatchingFeedback.ts new file mode 100644 index 00000000..ecb93da9 --- /dev/null +++ b/src/hooks/services/mutations/useCreateMatchingFeedback.ts @@ -0,0 +1,11 @@ +import { useMutation } from '@tanstack/react-query'; + +import type { CreateMatchingFeedbackRequest } from 'types/matching'; +import * as api from 'api'; + +export const useCreateMatchingFeedback = () => { + return useMutation( + async (payload: CreateMatchingFeedbackRequest) => + await api.createMatchingFeedback(payload), + ); +}; diff --git a/src/hooks/services/queries/useRecentMatchingHistory.ts b/src/hooks/services/queries/useRecentMatchingHistory.ts new file mode 100644 index 00000000..a9dcd949 --- /dev/null +++ b/src/hooks/services/queries/useRecentMatchingHistory.ts @@ -0,0 +1,13 @@ +import { useQuery } from '@tanstack/react-query'; +import * as api from 'api'; + +import { queryKeys } from 'constants/services'; + +export const useRecentMatchingHistory = () => { + const response = useQuery( + [queryKeys.recentMatchingHistory], + async () => await api.getRecentMatchingHistory(), + ); + + return response; +}; diff --git a/src/pages/matching/survey.tsx b/src/pages/matching/survey.tsx index cb41b844..e8fccdd4 100644 --- a/src/pages/matching/survey.tsx +++ b/src/pages/matching/survey.tsx @@ -1,6 +1,6 @@ import styled from '@emotion/styled'; import { useRouter } from 'next/router'; -import { useForm, useWatch } from 'react-hook-form'; +import { useForm } from 'react-hook-form'; import type { SubmitHandler } from 'react-hook-form'; import type { MatchingFeedbackForm } from 'types/matching'; @@ -9,23 +9,53 @@ import { CheckedOffIcon, CheckedOnIcon } from 'assets/icons'; import { Seo } from 'components/common'; import FeedbackTypeCheckbox from 'components/matching/FeedbackTypeCheckbox'; import { PAGE_PATH } from 'constants/common'; +import { useAddToBlackList } from 'hooks/services/mutations/useBlockUser'; +import { useCreateMatchingFeedback } from 'hooks/services/mutations/useCreateMatchingFeedback'; +import { useRecentMatchingHistory } from 'hooks/services/queries/useRecentMatchingHistory'; import { ScreenReaderOnly } from 'styles'; const MatchingSurvey = () => { const router = useRouter(); - const { control, register, handleSubmit } = useForm(); + const { register, handleSubmit, watch } = useForm(); - const onSubmit: SubmitHandler = async (data) => { - console.log(data); // FIXME: 실제 API 연동할 때 사용될 데이터 console.log 입니다. + const isBlockUser = watch('isBlockUser'); - await router.push(PAGE_PATH.main); + const { data: matchingHistory } = useRecentMatchingHistory(); + + const { mutate: createFeedbackMutate } = useCreateMatchingFeedback(); + + const { mutate: addToBlackListMutate } = useAddToBlackList(); + + const onRequestError = () => { + alert('의도하지 않은 에러가 발생하였습니다.'); + void router.push(PAGE_PATH.main); }; - const isBlockedMatching = useWatch({ - control, - name: 'isBlockedMatching', - }); + const onSubmit: SubmitHandler = (formData) => { + if (!matchingHistory) return; + + const { id, matchedUser } = matchingHistory; + const { isBlockUser, ...feedbackFormData } = formData; + + if (isBlockUser) { + addToBlackListMutate(matchedUser.id, { onError: onRequestError }); + } + + createFeedbackMutate( + { + ...feedbackFormData, + matchingHistoryId: id, + matchedUserId: matchedUser.id, + }, + { + onSuccess: () => { + void router.replace(PAGE_PATH.main); + }, + onError: onRequestError, + }, + ); + }; return ( <> @@ -45,11 +75,11 @@ const MatchingSurvey = () => {