-
Notifications
You must be signed in to change notification settings - Fork 1
[Refactor] 아바타 생성/선택 및 퀴즈 타입 리팩토링 #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,36 +1,32 @@ | ||
| import { AnswerQuizResponse } from "@/types/realQuiz/answerQuiz"; | ||
| import { ApiResponse, GlobalResponse } from "@/types/common/apiResponse.type"; | ||
| import { | ||
| AnswerQuizRequest, | ||
| AnswerQuizResponse, | ||
| } from "@/types/realQuiz/answerQuiz"; | ||
| import { getQuizRequest, getQuizResponse } from "@/types/realQuiz/getQuiz"; | ||
|
|
||
| import axios from "@/apis/instance"; | ||
|
|
||
| export const getQuizApi = async ( | ||
| params: getQuizRequest | ||
| ): Promise<getQuizResponse> => { | ||
| try { | ||
| const response = await axios.get("/api/v1/realQuiz", { params }); | ||
|
|
||
| return response.data; | ||
| } catch (error) { | ||
| console.error("Error get MissionPanel:", error); | ||
| throw error; | ||
| } | ||
| ): ApiResponse<getQuizResponse> => { | ||
| return axios.get("/api/v1/realQuiz", { params }).then(res => res.data); | ||
| }; | ||
|
|
||
| export const postAnswerQuizApi = async ({ | ||
| selectedOptionOrder, | ||
| quizId, | ||
| }: { | ||
| selectedOptionOrder: number; | ||
| quizId: number; | ||
| }): Promise<AnswerQuizResponse> => { | ||
| }: AnswerQuizRequest & { quizId: number }): Promise< | ||
| GlobalResponse<AnswerQuizResponse> | ||
| > => { | ||
| try { | ||
| const response = await axios.post<AnswerQuizResponse>( | ||
| const response = await axios.post<GlobalResponse<AnswerQuizResponse>>( | ||
| `/api/v1/realQuiz/${quizId}/answer`, | ||
| { selectedOptionOrder } | ||
| ); | ||
| return response.data; | ||
| } catch (error) { | ||
| console.error("Error post Answer Quiz:", error); | ||
| console.error("퀴즈 답안 제출 실패:", error); | ||
| throw error; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,3 +1,4 @@ | ||||||
| import { ApiResponse } from "@/types/common/apiResponse.type"; | ||||||
| import { | ||||||
| writeDiaryImageUploadResponse, | ||||||
| writeDiarySubmitRequest, | ||||||
|
|
@@ -7,26 +8,15 @@ import { | |||||
| import axios from "@/apis/instance"; | ||||||
|
|
||||||
| // 이미지 전송 API | ||||||
| export const takePhotoUploadApi = async ( | ||||||
|
|
||||||
| export const takePhotoUploadApi = ( | ||||||
| formData: FormData | ||||||
| ): Promise<writeDiaryImageUploadResponse> => { | ||||||
| try { | ||||||
| const response = await axios.post("/api/v1/diaries/images", formData); | ||||||
| return response.data; | ||||||
| } catch (error) { | ||||||
| console.error("Error post TakePhotoUpload:", error); | ||||||
| throw error; | ||||||
| } | ||||||
| ): ApiResponse<writeDiaryImageUploadResponse> => { | ||||||
| return axios.post("/api/v1/diaries/images", formData).then(res => res.data); | ||||||
| }; | ||||||
|
|
||||||
| export const writeDiarySubmitApi = async ( | ||||||
| params: writeDiarySubmitRequest | ||||||
| ): Promise<writeDiarySubmitResponse> => { | ||||||
| try { | ||||||
| const response = await axios.post("/api/v1/diaries", params); | ||||||
| return response.data; | ||||||
| } catch (error) { | ||||||
| console.error("Error post WriteDiarySubmit:", error); | ||||||
| throw error; | ||||||
| } | ||||||
| ): ApiResponse<writeDiarySubmitResponse> => { | ||||||
| return axios.post("api/v1/diaries", params).then(res => res.data); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chain경로 버그: 선행 슬래시 누락으로 베이스 경로 오조합 위험
- return axios.post("api/v1/diaries", params).then(res => res.data);
+ return axios.post("/api/v1/diaries", params).then(res => res.data);레포 전역에서 동일한 패턴이 있는지 점검해 주세요. 🏁 Script executed: #!/bin/bash
rg -nP '"api/v1/[^"]+"' -g '!**/node_modules/**' -C2Length of output: 358 경로 앞에 슬래시 추가 필요 - return axios.post("api/v1/diaries", params).then(res => res.data);
+ return axios.post("/api/v1/diaries", params).then(res => res.data);레포 전역 검색 결과 해당 패턴은 이 파일 한 곳에서만 확인되었습니다. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| }; | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,25 +1,28 @@ | ||
| import { useMutation } from "@tanstack/react-query"; | ||
| import { AxiosError } from "axios"; | ||
|
|
||
| import { | ||
| FinalChoiceAvatarRequest, | ||
| FinalChoiceAvatarResponse, | ||
| } from "@/types/avatars/masters"; | ||
| import { ErrorResponse, GlobalResponse } from "@/types/common/apiResponse.type"; | ||
|
|
||
| import { finalChoiceAvatarApi } from "@/apis/avatars/avatarApi"; | ||
|
|
||
| export const useFinalChoiceAvatar = () => { | ||
| return useMutation< | ||
| FinalChoiceAvatarResponse, | ||
| Error, | ||
| GlobalResponse<FinalChoiceAvatarResponse>, | ||
| AxiosError<ErrorResponse>, | ||
| FinalChoiceAvatarRequest | ||
| >({ | ||
| mutationFn: data => finalChoiceAvatarApi(data), | ||
| onSuccess: data => { | ||
| console.log("아바타 최종 선택 성공:", data); | ||
| console.log("아바타 최종 선택 성공:", data.result); | ||
| }, | ||
| onError: error => { | ||
| alert("아바타 최종 선택에 실패했습니다."); | ||
| console.error(error); | ||
| console.error(error.response?.data || error.message); | ||
| }, | ||
| retry: 1, | ||
| }); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,23 @@ | ||
| import { useQuery } from "@tanstack/react-query"; | ||
| import { AxiosError } from "axios"; | ||
|
|
||
| import { SelectAvatarResponse } from "@/types/avatars/masters"; | ||
| import { AvatarType } from "@/types/avatars/masters"; | ||
| import { ErrorResponse, GlobalResponse } from "@/types/common/apiResponse.type"; | ||
|
|
||
| import { getSelectionAvatarApi } from "@/apis/avatars/avatarApi"; | ||
|
|
||
| export const useGetSelectAvatar = () => { | ||
| return useQuery<SelectAvatarResponse, Error>({ | ||
| return useQuery< | ||
| GlobalResponse<AvatarType[]>, | ||
| AxiosError<ErrorResponse>, | ||
| AvatarType[] | ||
| >({ | ||
| queryKey: ["selectionAvatar"], | ||
| queryFn: getSelectionAvatarApi, | ||
| select: data => data.result, | ||
|
Comment on lines
+10
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainAPI 반환 타입과 훅 제네릭 일치 여부 확인 필요 훅은 GlobalResponse<AvatarType[]>를 가정하고 select로 배열을 언래핑합니다. 관련 API(getSelectionAvatarApi)가 ApiResponse<AvatarType[]>를 반환하는지 확인해 주세요. 단수형이면 컴파일/런타임 불일치가 발생합니다. 다음 스크립트로 선언을 확인하세요: 🏁 Script executed: #!/bin/bash
# getSelectionAvatarApi 시그니처와 반환 제네릭 확인
rg -nP -C2 'export\s+const\s+getSelectionAvatarApi\s*=\s*async' src | sed -n '1,120p'
rg -nP 'getSelectionAvatarApi.*ApiResponse<\s*AvatarType(\[\])?\s*>' -C1 srcLength of output: 760 API 반환 타입과 훅 제네릭 일치시키기 🤖 Prompt for AI Agents |
||
| staleTime: 1000 * 60 * 120, | ||
| gcTime: 1000 * 60 * 5, | ||
| retry: 1, | ||
| refetchOnWindowFocus: true, | ||
| }); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,13 +1,21 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useQuery } from "@tanstack/react-query"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { AxiosError } from "axios"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ApiResponse, ErrorResponse } from "@/types/common/apiResponse.type"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getQuizRequest, getQuizResponse } from "@/types/realQuiz/getQuiz"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getQuizApi } from "@/apis/missions/QuizApi"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const useGetQuiz = (params: getQuizRequest) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return useQuery<getQuizResponse>({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return useQuery< | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ApiResponse<getQuizResponse>, // 서버 전체 응답 타입 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AxiosError<ErrorResponse>, // Axios 확장 에러 타입 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getQuizResponse // select로 실제 사용할 데이터 타입 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| >({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+10
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. useQuery 제네릭 오용 및 select 누락으로 인한 타입/런타임 불일치
아래처럼 수정 제안합니다. -import { ApiResponse, ErrorResponse } from "@/types/common/apiResponse.type";
+import { GlobalResponse, ErrorResponse } from "@/types/common/apiResponse.type";
…
- return useQuery<
- ApiResponse<getQuizResponse>, // 서버 전체 응답 타입
- AxiosError<ErrorResponse>, // Axios 확장 에러 타입
- getQuizResponse // select로 실제 사용할 데이터 타입
- >({
+ return useQuery<
+ GlobalResponse<getQuizResponse>, // 서버 전체 응답 타입(해결된 데이터)
+ AxiosError<ErrorResponse>,
+ getQuizResponse // select로 실제 사용할 데이터 타입
+ >({
queryKey: ["quiz", params],
queryFn: () => getQuizApi(params),
+ select: (data) => data.result,
staleTime: 1000 * 60 * 5, // 5분 동안 stale 처리 안함
retry: 1, // 실패 시 1번 재시도
refetchOnWindowFocus: false, // 창 포커스 시 재요청 X
});또는 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queryKey: ["quiz", params], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| queryFn: () => getQuizApi(params), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| staleTime: 1000 * 60 * 5, // 5분 동안 stale 처리 안함 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| retry: 1, // 실패 시 1번 재시도 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| refetchOnWindowFocus: false, // 창 포커스 시 재요청 X | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
타입 불일치: 배열 반환으로 수정 + 제네릭 지정 누락
해당 엔드포인트는 선택 가능한 아바타 목록을 반환하므로 배열 타입이 맞습니다. 또한
axios.get에GlobalResponse제네릭을 지정해 타입 안전성을 확보해 주세요.관련 훅(
src/hooks/avatars/useGetSelectAvatarApi.ts)과 페이지가AvatarType[]을 기대하는지 최종 확인 부탁드립니다.🏁 Script executed:
Length of output: 2763
아래 스크립트로 API 함수 정의와
ApiResponse·GlobalResponse타입을 확인해 주세요.🏁 Script executed:
Length of output: 2240
getSelectionAvatarApi 반환 타입 및 제네릭 수정 필요
getSelectionAvatarApi시그니처를ApiResponse<AvatarType[]>로 변경axios.get호출에<GlobalResponse<AvatarType[]>>제네릭 지정useGetSelectAvatar)의AvatarType[]기대값과 일치하도록 반영해주세요.🤖 Prompt for AI Agents