Skip to content

Commit f5c458e

Browse files
authored
Merge pull request #250 from manNomi/refactor/applicant
Hot fix : applicant 페이지
2 parents e472d95 + c2ba9d3 commit f5c458e

30 files changed

+406
-381
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export enum QueryKeys {
2+
competitorsApplicationList = "competitorsApplicationList",
3+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { AxiosError, AxiosResponse } from "axios";
2+
3+
import { axiosInstance } from "@/utils/axiosInstance";
4+
5+
import { QueryKeys } from "./queryKeys";
6+
7+
import { ApplicationListResponse } from "@/types/application";
8+
9+
// UseQueryResult는 useQuery의 반환 타입을 명시할 때 유용합니다.
10+
import { UseQueryOptions, UseQueryResult, useQuery } from "@tanstack/react-query";
11+
12+
export const getCompetitorsApplicationList = (): Promise<AxiosResponse<ApplicationListResponse>> =>
13+
axiosInstance.get("/applications/competitors");
14+
15+
// 커스텀 훅의 props 타입 정의를 개선하여 queryKey와 queryFn을 제외시킵니다.
16+
type UseGetCompetitorsApplicationListOptions = Omit<
17+
UseQueryOptions<
18+
AxiosResponse<ApplicationListResponse>, // queryFn이 반환하는 원본 데이터 타입
19+
AxiosError<{ message: string }>, // 에러 타입
20+
ApplicationListResponse // select를 통해 최종적으로 반환될 데이터 타입
21+
>,
22+
"queryKey" | "queryFn" // 훅 내부에서 지정하므로 props에서는 제외
23+
>;
24+
25+
const useGetCompetitorsApplicationList = (
26+
props?: UseGetCompetitorsApplicationListOptions,
27+
): UseQueryResult<ApplicationListResponse, AxiosError<{ message: string }>> => {
28+
// 반환 타입 명시
29+
return useQuery({
30+
queryKey: [QueryKeys.competitorsApplicationList],
31+
queryFn: getCompetitorsApplicationList,
32+
staleTime: 1000 * 60 * 5,
33+
select: (response) => response.data,
34+
...props,
35+
});
36+
};
37+
38+
export default useGetCompetitorsApplicationList;

src/api/applications/client/usePostSubmitApplication.ts

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { useRouter } from "next/navigation";
22

3-
import { AxiosResponse } from "axios";
3+
import { AxiosError, AxiosResponse } from "axios";
44

55
import { axiosInstance } from "@/utils/axiosInstance";
66

77
import { useMutation } from "@tanstack/react-query";
8+
// 타입 경로
9+
import { UseMutationOptions, UseMutationResult } from "@tanstack/react-query";
810

911
// API 함수 경로
1012
export interface UseSubmitApplicationResponse {
@@ -25,32 +27,32 @@ export const postSubmitApplication = (
2527
request: UseSubmitApplicationRequest,
2628
): Promise<AxiosResponse<UseSubmitApplicationResponse>> => axiosInstance.post("/applications", request);
2729

28-
// 타입 경로
29-
30-
const usePostSubmitApplication = () => {
31-
const router = useRouter();
32-
33-
return useMutation({
30+
const usePostSubmitApplication = (
31+
props?: UseMutationOptions<
32+
AxiosResponse<UseSubmitApplicationResponse>, // TData
33+
AxiosError<{ message: string }>, // TError
34+
UseSubmitApplicationRequest, // TVariables
35+
unknown // TContext
36+
>,
37+
): UseMutationResult<
38+
AxiosResponse<UseSubmitApplicationResponse>,
39+
AxiosError<{ message: string }>,
40+
UseSubmitApplicationRequest,
41+
unknown
42+
> => {
43+
return useMutation<
44+
AxiosResponse<UseSubmitApplicationResponse>, // TData: 성공 시 반환 타입
45+
AxiosError<{ message: string }>, // TError: 에러 타입
46+
UseSubmitApplicationRequest // TVariables: 요청 body 타입
47+
>({
48+
...props,
3449
// mutationFn: API 요청을 수행할 비동기 함수를 지정합니다.
3550
mutationFn: (request: UseSubmitApplicationRequest) => postSubmitApplication(request),
3651

37-
// onSuccess: API 요청이 성공했을 때 실행할 콜백 함수입니다.
38-
onSuccess: (data) => {
39-
console.log("지원이 성공적으로 완료되었습니다.", data);
40-
alert("지원이 완료되었습니다.");
41-
42-
// 성공 후, 관련된 다른 데이터들을 최신 상태로 업데이트하고 싶을 때 사용합니다.
43-
// 예를 들어, '내 지원 목록' 데이터를 다시 불러옵니다.
44-
// queryClient.invalidateQueries({ queryKey: ['myApplications'] });
45-
46-
// 지원 완료 페이지로 이동합니다.
47-
router.push("/application/complete");
48-
},
49-
5052
// onError: API 요청이 실패했을 때 실행할 콜백 함수입니다.
5153
onError: (error) => {
52-
console.error("지원 중 오류가 발생했습니다.", error);
53-
alert("지원 중 오류가 발생했습니다. 다시 시도해주세요.");
54+
const errorMessage = error?.response?.data?.message;
55+
alert(errorMessage || "지원 중 오류가 발생했습니다. 다시 시도해주세요.");
5456
},
5557
});
5658
};
Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import { useMemo } from "react";
2+
13
import { AxiosResponse } from "axios";
24

35
import { publicAxiosInstance } from "@/utils/axiosInstance";
46

57
import { QueryKeys } from "./queryKey";
68

7-
// QueryKeys에 universitySearchText 추가 필요
89
import { ListUniversity } from "@/types/university";
910

10-
// ListUniversity 타입 경로
1111
import { useQuery } from "@tanstack/react-query";
1212

1313
// --- 타입 정의 ---
@@ -16,26 +16,54 @@ interface UniversitySearchTextResponse {
1616
}
1717

1818
// --- API 호출 함수 ---
19-
const getUniversitySearchByText = async (value: string): Promise<UniversitySearchTextResponse> => {
19+
const getAllUniversitiesApi = async (): Promise<UniversitySearchTextResponse> => {
2020
const response: AxiosResponse<UniversitySearchTextResponse> = await publicAxiosInstance.get(
2121
"/univ-apply-infos/search/text",
2222
{
23-
params: { value },
23+
params: { value: "" }, // 항상 빈 값으로 호출
2424
},
2525
);
2626
return response.data;
2727
};
2828

29-
// --- 커스텀 훅 ---
30-
const useGetUniversitySearchByText = (searchValue: string) => {
31-
const staleTime = searchValue === "" ? Infinity : 1000 * 60 * 5;
32-
33-
return useQuery<UniversitySearchTextResponse, Error, ListUniversity[]>({
34-
queryKey: [QueryKeys.universitySearchText, searchValue],
35-
queryFn: () => getUniversitySearchByText(searchValue),
36-
staleTime,
29+
const useUniversitySearch = (searchValue: string) => {
30+
// 1. 모든 대학 데이터를 한 번만 가져와 'Infinity' 캐시로 저장합니다.
31+
const {
32+
data: allUniversities, // 모든 대학 목록
33+
isLoading,
34+
isError,
35+
error,
36+
} = useQuery<UniversitySearchTextResponse, Error, ListUniversity[]>({
37+
queryKey: [QueryKeys.universitySearchText], // "모든 대학"을 위한 고유 키
38+
queryFn: getAllUniversitiesApi,
39+
staleTime: Infinity, // 한번 가져오면 절대 다시 요청하지 않음
40+
gcTime: Infinity, // 캐시가 절대 삭제되지 않음 (선택 사항)
3741
select: (data) => data.univApplyInfoPreviews,
3842
});
39-
};
4043

41-
export default useGetUniversitySearchByText;
44+
// 2. 검색어가 변경될 때만 캐시된 데이터를 필터링합니다.
45+
const filteredUniversities = useMemo(() => {
46+
const normalizedSearchValue = searchValue.trim().toLowerCase();
47+
48+
if (!normalizedSearchValue) {
49+
return allUniversities; // 검색어가 없으면 전체 목록 반환
50+
}
51+
52+
// allUniversities가 아직 로드되지 않았으면 빈 배열 반환
53+
if (!allUniversities) {
54+
return [];
55+
}
56+
57+
// 대학 이름(koreanName)에 검색어가 포함되어 있는지 확인하여 필터링
58+
return allUniversities.filter((university) => university.koreanName.toLowerCase().includes(normalizedSearchValue));
59+
}, [allUniversities, searchValue]); // allUniversities나 searchValue가 바뀔 때만 재계산
60+
61+
return {
62+
data: filteredUniversities, // 필터링된 결과
63+
isLoading, // 초기 데이터 로딩 상태
64+
isError,
65+
error,
66+
totalCount: allUniversities?.length || 0, // 전체 대학 수 (필요시 사용)
67+
};
68+
};
69+
export default useUniversitySearch;

src/app/(home)/page.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ const HomePage = async () => {
5757
</Link>
5858
</div>
5959
<div className="flex gap-2">
60-
<Link className="h-26 flex flex-1 flex-col gap-2 rounded-lg bg-[#FFF3E5] p-2.5" href="/application/apply">
60+
<Link
61+
className="h-26 flex flex-1 flex-col gap-2 rounded-lg bg-[#FFF3E5] p-2.5"
62+
href="/university/application/apply"
63+
>
6164
<div className="flex flex-col">
6265
<span className="text-sm font-bold text-[#FF7300]">학교 지원하기</span>
6366
<span className="text-xs font-medium leading-tight text-k-700">학교를 지원해주세요</span>
@@ -66,7 +69,10 @@ const HomePage = async () => {
6669
<IconMuseum />
6770
</div>
6871
</Link>
69-
<Link className="h-26 flex flex-1 flex-col gap-2 rounded-lg bg-[#E9F7EC] p-2.5" href="/application">
72+
<Link
73+
className="h-26 flex flex-1 flex-col gap-2 rounded-lg bg-[#E9F7EC] p-2.5"
74+
href="/university/application"
75+
>
7076
<div className="flex flex-col">
7177
<span className="text-sm font-bold text-[#15A861]">지원자 현황 확인</span>
7278
<span className="text-xs font-medium leading-tight text-k-700">경쟁률을 바로 분석해드려요</span>

src/app/application/ScorePageContent.tsx

Lines changed: 0 additions & 172 deletions
This file was deleted.

0 commit comments

Comments
 (0)