88 toggleFavorite as toggleFavoriteAPI ,
99 fetchFavoriteEtfCodes ,
1010} from "@/services/etfFavoriteService" ;
11- import { useRouter } from "next/navigation" ;
11+ import { useRouter , useSearchParams } from "next/navigation" ;
1212
1313import FilterTabs from "@/components/blocks/ETFFind/FilterTabs" ;
1414import FilterButtons from "@/components/blocks/ETFFind/FilterButtons" ;
@@ -18,10 +18,14 @@ import HoldingTable from "@/components/blocks/ETFFind/HoldingTable";
1818import CompareModal from "@/components/blocks/ETFCompare/ETFComapreModal" ;
1919
2020export default function FindPage ( ) {
21+ const router = useRouter ( ) ;
22+ const searchParams = useSearchParams ( ) ;
23+ const initialQuery = searchParams . get ( "query" ) ?? "" ;
24+
2125 const [ selectedTab , setSelectedTab ] = useState ( "유형별" ) ;
2226 const [ selectedType , setSelectedType ] = useState ( "전체" ) ;
2327 const [ selectedTheme , setSelectedTheme ] = useState ( "전체" ) ;
24- const [ searchQuery , setSearchQuery ] = useState ( "" ) ;
28+ const [ searchQuery , setSearchQuery ] = useState ( initialQuery ) ;
2529
2630 const [ etfData , setEtfData ] = useState < ETFView [ ] > ( [ ] ) ;
2731 const [ holdingsData , setHoldingsData ] = useState < HoldingView [ ] > ( [ ] ) ;
@@ -32,7 +36,8 @@ export default function FindPage() {
3236 const [ modalVisible , setModalVisible ] = useState ( false ) ;
3337 const [ modalData , setModalData ] = useState < any [ ] > ( [ ] ) ;
3438 const [ showPlaceholder , setShowPlaceholder ] = useState ( true ) ;
35- const router = useRouter ( ) ;
39+ const [ hasInitialized , setHasInitialized ] = useState ( false ) ;
40+
3641 const tabList = [ "유형별" , "테마별" , "관심별" ] ;
3742 const assetFilters = [
3843 "전체" ,
@@ -117,9 +122,134 @@ export default function FindPage() {
117122 }
118123 } ;
119124
125+ // 검색 실행 함수 (URL 파라미터용)
126+ const executeSearchWithQuery = async ( query : string ) => {
127+ setIsLoading ( true ) ;
128+
129+ const params : any = {
130+ query : query ,
131+ sort : viewMode === "ETF로 보기" ? "etf_code" : "weight_pct" ,
132+ } ;
133+
134+ if ( selectedTab === "관심별" ) {
135+ params . isFavorite = true ;
136+ } else {
137+ if ( selectedType !== "전체" ) params . assetClass = selectedType ;
138+ if ( selectedTheme !== "전체" ) params . theme = selectedTheme ;
139+ }
140+
141+ try {
142+ if ( viewMode === "ETF로 보기" ) {
143+ const data : any [ ] = await fetchEtfData ( params ) ;
144+ const formatted = ( data as any [ ] ) . map ( ( etf ) => ( {
145+ name : etf . etf_name ,
146+ etfCode : etf . etf_code ,
147+ nav : etf . latest_price ,
148+ week1 : etf . week1 ?? "-" ,
149+ month1 : etf . month1 ?? "-" ,
150+ month3 : etf . month3 ?? "-" ,
151+ month6 : etf . month6 ?? "-" ,
152+ year1 : etf . year1 ?? "-" ,
153+ year3 : etf . year3 ?? "-" ,
154+ inception : etf . inception ?? "-" ,
155+ } ) ) ;
156+ setEtfData ( formatted ) ;
157+
158+ // 관심 ETF 세팅
159+ try {
160+ const favoriteCodes = await fetchFavoriteEtfCodes ( ) ;
161+ setFavoriteEtfCodes ( favoriteCodes ) ;
162+ } catch ( err : any ) {
163+ console . warn (
164+ "💥 관심 ETF 목록 가져오기 실패 (비로그인일 수 있음)" ,
165+ err
166+ ) ;
167+ }
168+ } else {
169+ const data : any [ ] = await fetchHoldingsData ( params ) ;
170+ const formatted = ( data as any [ ] ) . map ( ( holding ) => ( {
171+ etfName : holding . etf_name ,
172+ etfCode : holding . etf_code ,
173+ holdingName : holding . holding_name ,
174+ weight : holding . weight_pct ,
175+ } ) ) ;
176+ setHoldingsData ( formatted ) ;
177+ }
178+ } catch ( err ) {
179+ console . error ( "데이터 불러오기 실패:" , err ) ;
180+ if ( viewMode === "ETF로 보기" ) setEtfData ( [ ] ) ;
181+ else setHoldingsData ( [ ] ) ;
182+ } finally {
183+ setIsLoading ( false ) ;
184+ }
185+ } ;
186+
187+ // 검색 실행 함수
188+ const executeSearch = async ( ) => {
189+ setIsLoading ( true ) ;
190+
191+ const params : any = {
192+ query : searchQuery ,
193+ sort : viewMode === "ETF로 보기" ? "etf_code" : "weight_pct" ,
194+ } ;
195+
196+ if ( selectedTab === "관심별" ) {
197+ params . isFavorite = true ;
198+ } else {
199+ if ( selectedType !== "전체" ) params . assetClass = selectedType ;
200+ if ( selectedTheme !== "전체" ) params . theme = selectedTheme ;
201+ }
202+
203+ try {
204+ if ( viewMode === "ETF로 보기" ) {
205+ const data : any [ ] = await fetchEtfData ( params ) ;
206+ const formatted = ( data as any [ ] ) . map ( ( etf ) => ( {
207+ name : etf . etf_name ,
208+ etfCode : etf . etf_code ,
209+ nav : etf . latest_price ,
210+ week1 : etf . week1 ?? "-" ,
211+ month1 : etf . month1 ?? "-" ,
212+ month3 : etf . month3 ?? "-" ,
213+ month6 : etf . month6 ?? "-" ,
214+ year1 : etf . year1 ?? "-" ,
215+ year3 : etf . year3 ?? "-" ,
216+ inception : etf . inception ?? "-" ,
217+ } ) ) ;
218+ setEtfData ( formatted ) ;
219+
220+ // 관심 ETF 세팅
221+ try {
222+ const favoriteCodes = await fetchFavoriteEtfCodes ( ) ;
223+ setFavoriteEtfCodes ( favoriteCodes ) ;
224+ } catch ( err : any ) {
225+ console . warn (
226+ "💥 관심 ETF 목록 가져오기 실패 (비로그인일 수 있음)" ,
227+ err
228+ ) ;
229+ }
230+ } else {
231+ const data : any [ ] = await fetchHoldingsData ( params ) ;
232+ const formatted = ( data as any [ ] ) . map ( ( holding ) => ( {
233+ etfName : holding . etf_name ,
234+ etfCode : holding . etf_code ,
235+ holdingName : holding . holding_name ,
236+ weight : holding . weight_pct ,
237+ } ) ) ;
238+ setHoldingsData ( formatted ) ;
239+ }
240+ } catch ( err ) {
241+ console . error ( "데이터 불러오기 실패:" , err ) ;
242+ if ( viewMode === "ETF로 보기" ) setEtfData ( [ ] ) ;
243+ else setHoldingsData ( [ ] ) ;
244+ } finally {
245+ setIsLoading ( false ) ;
246+ }
247+ } ;
248+
120249 const handleSearch = ( ) => {
121250 if ( searchQuery . trim ( ) ) {
122- router . push ( `/find?query=${ encodeURIComponent ( searchQuery ) } ` ) ;
251+ // 현재 페이지에서 검색할 때는 URL을 업데이트하지 않고 바로 검색 실행
252+ executeSearch ( ) ;
123253 }
124254 } ;
125255
@@ -139,71 +269,38 @@ export default function FindPage() {
139269 }
140270 } ;
141271
142- // 🔥 API 요청 트리거
272+ // URL 파라미터에서 검색어 가져오기 및 초기 검색 실행
143273 useEffect ( ( ) => {
144- const fetchData = async ( ) => {
145- setIsLoading ( true ) ;
274+ if ( hasInitialized ) return ; // 이미 초기화된 경우 중복 실행 방지
146275
147- const params : any = {
148- query : searchQuery ,
149- sort : viewMode === "ETF로 보기" ? "etf_code" : "weight_pct" ,
150- } ;
276+ const query = searchParams . get ( "query" ) ;
277+ if ( query ) {
278+ setSearchQuery ( query ) ;
279+ setShowPlaceholder ( false ) ;
151280
152- if ( selectedTab === "관심별" ) {
153- params . isFavorite = true ;
154- } else {
155- if ( selectedType !== "전체" ) params . assetClass = selectedType ;
156- if ( selectedTheme !== "전체" ) params . theme = selectedTheme ;
157- }
281+ // URL 파라미터에서 검색어가 있으면 자동으로 검색 실행
282+ setTimeout ( ( ) => {
283+ executeSearchWithQuery ( query ) ;
158284
159- try {
160- if ( viewMode === "ETF로 보기" ) {
161- const data : any [ ] = await fetchEtfData ( params ) ;
162- const formatted = ( data as any [ ] ) . map ( ( etf ) => ( {
163- name : etf . etf_name ,
164- etfCode : etf . etf_code ,
165- nav : etf . latest_price ,
166- week1 : etf . week1 ?? "-" ,
167- month1 : etf . month1 ?? "-" ,
168- month3 : etf . month3 ?? "-" ,
169- month6 : etf . month6 ?? "-" ,
170- year1 : etf . year1 ?? "-" ,
171- year3 : etf . year3 ?? "-" ,
172- inception : etf . inception ?? "-" ,
173- } ) ) ;
174- setEtfData ( formatted ) ;
175-
176- // 관심 ETF 세팅
177- try {
178- const favoriteCodes = await fetchFavoriteEtfCodes ( ) ;
179- setFavoriteEtfCodes ( favoriteCodes ) ;
180- } catch ( err : any ) {
181- console . warn (
182- "💥 관심 ETF 목록 가져오기 실패 (비로그인일 수 있음)" ,
183- err
184- ) ;
185- }
186- } else {
187- const data : any [ ] = await fetchHoldingsData ( params ) ;
188- const formatted = ( data as any [ ] ) . map ( ( holding ) => ( {
189- etfName : holding . etf_name ,
190- etfCode : holding . etf_code ,
191- holdingName : holding . holding_name ,
192- weight : holding . weight_pct ,
193- } ) ) ;
194- setHoldingsData ( formatted ) ;
195- }
196- } catch ( err ) {
197- console . error ( "데이터 불러오기 실패:" , err ) ;
198- if ( viewMode === "ETF로 보기" ) setEtfData ( [ ] ) ;
199- else setHoldingsData ( [ ] ) ;
200- } finally {
201- setIsLoading ( false ) ;
202- }
203- } ;
285+ const newUrl = window . location . pathname ;
286+ window . history . replaceState ( { } , "" , newUrl ) ;
287+ } , 100 ) ; // 약간의 지연을 주어 searchQuery가 설정된 후 실행
288+ } else {
289+ // 검색어가 없으면 모든 ETF 목록을 가져오기
290+ setTimeout ( ( ) => {
291+ executeSearchWithQuery ( "" ) ;
292+ } , 100 ) ;
293+ }
294+ setHasInitialized ( true ) ;
295+ } , [ searchParams ] ) ;
204296
205- fetchData ( ) ;
206- } , [ searchQuery , selectedType , selectedTheme , viewMode , selectedTab ] ) ;
297+ // 🔥 API 요청 트리거 (필터 변경 시에만 실행)
298+ useEffect ( ( ) => {
299+ // 초기 로드 시에는 실행하지 않음 (URL 파라미터 처리에서 실행됨)
300+ if ( searchQuery ) {
301+ executeSearch ( ) ;
302+ }
303+ } , [ selectedType , selectedTheme , viewMode , selectedTab ] ) ;
207304
208305 // 비교하기 버튼 클릭 핸들러
209306 const handleCompareClick = async ( ) => {
@@ -273,7 +370,7 @@ export default function FindPage() {
273370 style = { { caretColor : "white" } }
274371 placeholder = {
275372 showPlaceholder
276- ? "상품명 혹은 종목명으로 원하는 ETF를 검색해보세요"
373+ ? "상품명 혹은 증권코드로 원하는 ETF를 검색해보세요"
277374 : ""
278375 }
279376 value = { searchQuery }
@@ -334,7 +431,7 @@ export default function FindPage() {
334431 count = {
335432 viewMode === "ETF로 보기" ? etfData . length : holdingsData . length
336433 }
337- selectedTab = { selectedTab }
434+ selectedTab = { "" }
338435 />
339436
340437 { isLoading ? (
0 commit comments