11"use client" ;
22
33import { useRouter } from "next/navigation" ;
4- import { useMemo , useRef , useState } from "react" ;
4+ import { useEffect , useMemo , useRef , useState } from "react" ;
55
66import ConfirmCancelModal from "@/components/modal/ConfirmCancelModal" ;
77import ButtonTab from "@/components/ui/ButtonTab" ;
@@ -20,8 +20,6 @@ import useGetApplicationsList from "@/api/applications/client/useGetApplications
2020
2121const PREFERENCE_CHOICE : ( "1순위" | "2순위" | "3순위" ) [ ] = [ "1순위" , "2순위" , "3순위" ] ;
2222
23- // API 응답 데이터의 타입을 명확하게 정의합니다.
24- // 실제 ApplicationListResponse 타입을 사용하시는 것이 더 좋습니다.
2523interface ScoreData {
2624 firstChoice : ScoreSheetType [ ] ;
2725 secondChoice : ScoreSheetType [ ] ;
@@ -38,38 +36,47 @@ const ScorePageContent = () => {
3836 const [ searchValue , setSearchValue ] = useState ( "" ) ;
3937 const [ showNeedApply , setShowNeedApply ] = useState ( false ) ;
4038
41- // ✨ 1. 초기 데이터를 API 응답 구조와 동일하게 설정합니다.
4239 const initialData : ScoreData = {
4340 firstChoice : [ ] ,
4441 secondChoice : [ ] ,
4542 thirdChoice : [ ] ,
4643 } ;
4744
48- // ✨ 2. `data`의 기본값을 위에서 정의한 initialData로 변경합니다.
49- const { data : scoreResponseData = initialData , isLoading } = useGetApplicationsList ( ) ;
45+ const {
46+ data : scoreResponseData = initialData ,
47+ isError,
48+ isLoading,
49+ } = useGetApplicationsList ( {
50+ retry : false ,
51+ } ) ;
5052
5153 const filteredAndSortedData = useMemo ( ( ) => {
52- // 데이터가 없는 경우를 대비한 방어 코드
53- const firstChoice = scoreResponseData ?. firstChoice || [ ] ;
54- const secondChoice = scoreResponseData ?. secondChoice || [ ] ;
55- const thirdChoice = scoreResponseData ?. thirdChoice || [ ] ;
54+ // ✨ 1. 대학 이름(koreanName)을 기준으로 중복을 제거하는 헬퍼 함수
55+ const uniqueByKoreanName = ( data : ScoreSheetType [ ] ) => {
56+ // Map을 사용해 koreanName을 키로 하여 중복을 효율적으로 제거합니다.
57+ const universityMap = new Map ( data . map ( ( sheet ) => [ sheet . koreanName , sheet ] ) ) ;
58+ // Map의 값들만 다시 배열로 변환하여 반환합니다.
59+ return Array . from ( universityMap . values ( ) ) ;
60+ } ;
61+
62+ // ✨ 2. API 응답 데이터를 받자마자 중복부터 제거합니다.
63+ const firstChoice = uniqueByKoreanName ( scoreResponseData ?. firstChoice || [ ] ) ;
64+ const secondChoice = uniqueByKoreanName ( scoreResponseData ?. secondChoice || [ ] ) ;
65+ const thirdChoice = uniqueByKoreanName ( scoreResponseData ?. thirdChoice || [ ] ) ;
5666
57- // 원본 데이터를 훼손하지 않기 위해 복사본을 만들어 정렬합니다.
67+ // 3. 중복이 제거된 데이터를 정렬합니다.
5868 const sortedData = {
59- // ✨ 3. `[...scoreResponseData]`가 아니라 `[...firstChoice]`로 수정합니다.
6069 firstChoice : [ ...firstChoice ] . sort ( ( a , b ) => b . applicants . length - a . applicants . length ) ,
6170 secondChoice : [ ...secondChoice ] . sort ( ( a , b ) => b . applicants . length - a . applicants . length ) ,
6271 thirdChoice : [ ...thirdChoice ] . sort ( ( a , b ) => b . applicants . length - a . applicants . length ) ,
6372 } ;
6473
65- // 필터링 로직
74+ // 4. 기존 필터링 로직을 적용합니다.
6675 const applyFilters = ( data : ScoreSheetType [ ] ) => {
6776 let result = data ;
68- // 지역 필터
6977 if ( regionFilter ) {
7078 result = result . filter ( ( sheet ) => sheet . region === regionFilter ) ;
7179 }
72- // 검색어 필터
7380 if ( searchValue ) {
7481 result = result . filter ( ( sheet ) => sheet . koreanName . toLowerCase ( ) . includes ( searchValue . toLowerCase ( ) ) ) ;
7582 }
@@ -116,6 +123,14 @@ const ScorePageContent = () => {
116123 } ;
117124 const scoreSheets = getScoreSheet ( ) ;
118125
126+ useEffect ( ( ) => {
127+ if ( isLoading ) return ;
128+ if ( isError ) {
129+ alert ( "지원 현황을 불러오는 중에 오류가 발생했습니다. 지원 절차를 진행해주세요." ) ;
130+ router . replace ( "/university/application/apply" ) ;
131+ }
132+ } , [ isError , isLoading , router ] ) ;
133+
119134 if ( isLoading ) {
120135 return < CloudSpinnerPage /> ;
121136 }
@@ -145,7 +160,7 @@ const ScorePageContent = () => {
145160 style = { { padding : "10px 0 10px 18px" } }
146161 />
147162
148- < div className = "mx-5 mt-2.5 flex w-[calc(100%-44px)] flex-col gap-3 overflow-x-auto" >
163+ < div className = "mx-auto mt-2.5 flex w-full flex-col gap-3 overflow-x-auto" >
149164 { scoreSheets . map ( ( choice ) => (
150165 < ScoreSheet key = { choice . koreanName } scoreSheet = { choice } />
151166 ) ) }
0 commit comments