1
+ // LocationInput.tsx
2
+
1
3
import React , { useState } from "react" ;
2
4
import Image from "next/image" ;
3
5
import SearchResults from "./SearchResults" ;
4
6
5
7
interface LocationInputProps {
6
8
className ?: string ;
7
- onSelect : ( location : string ) => void ;
9
+ onSelect : ( place : { name : string ; address : string } ) => void ; // 타입 수정
8
10
}
9
11
10
12
function LocationInput ( { className, onSelect } : LocationInputProps ) {
11
- const [ location , setLocation ] = useState ( "" ) ;
13
+ const [ location , setLocation ] = useState < string > ( "" ) ;
12
14
const [ results , setResults ] = useState < { name : string ; address : string } [ ] > (
13
15
[ ]
14
16
) ;
15
-
16
- const fetchPlaces = async ( latitude : string , longitude : string ) => {
17
- try {
18
- const response = await fetch (
19
- `${ process . env . NEXT_PUBLIC_API_BASE_URL } /places?lat=${ latitude } &lon=${ longitude } ` ,
20
- {
21
- headers : { accept : "*/*" } ,
22
- }
23
- ) ;
24
-
25
- if ( ! response . ok ) {
26
- throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
27
- }
28
-
29
- const data = await response . json ( ) ;
30
-
31
- if ( data . places && data . places . length > 0 ) {
32
- setResults ( data . places ) ; // 결과 저장
33
- } else {
34
- alert ( "현재 위치에 대한 장소를 찾을 수 없습니다." ) ;
35
- }
36
- } catch ( error ) {
37
- const err = error as Error ;
38
- alert ( `위치 정보를 가져오는 중 오류가 발생했습니다: ${ err . message } ` ) ;
39
- }
40
- } ;
17
+ const [ isFetching , setIsFetching ] = useState ( false ) ; // 중복 요청 방지 상태
41
18
42
19
const fetchPlacesBySearch = async ( query : string ) => {
20
+ if ( isFetching ) return ;
21
+ setIsFetching ( true ) ;
22
+
43
23
try {
44
24
const response = await fetch (
45
- `${ process . env . NEXT_PUBLIC_API_BASE_URL } /places/search/ ${ encodeURIComponent ( query ) } ` ,
25
+ `${ process . env . NEXT_PUBLIC_API_BASE_URL } /places/search?keyword= ${ encodeURIComponent ( query ) } ` ,
46
26
{
47
27
headers : { accept : "*/*" } ,
48
28
}
49
29
) ;
50
30
51
31
if ( ! response . ok ) {
32
+ const errorText = await response . text ( ) ;
33
+ console . error ( "Error fetching search results:" , errorText ) ;
52
34
throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
53
35
}
54
36
55
37
const data = await response . json ( ) ;
56
38
if ( data . code === 200 ) {
57
- setResults ( data . data ) ; // 검색 결과 저장
39
+ setResults ( data . data ) ;
58
40
} else {
59
41
setResults ( [ ] ) ;
60
42
alert ( `장소 검색에 실패했습니다: ${ data . message } ` ) ;
61
43
}
62
44
} catch ( error ) {
63
- const err = error as Error ;
64
- alert ( `API 요청 중 오류가 발생했습니다: ${ err . message } ` ) ;
45
+ if ( error instanceof Error ) {
46
+ alert ( `API 요청 중 오류가 발생했습니다: ${ error . message } ` ) ;
47
+ } else {
48
+ alert ( "API 요청 중 알 수 없는 오류가 발생했습니다." ) ;
49
+ }
50
+ } finally {
51
+ setIsFetching ( false ) ;
65
52
}
66
53
} ;
67
54
@@ -70,31 +57,67 @@ function LocationInput({ className, onSelect }: LocationInputProps) {
70
57
setLocation ( value ) ;
71
58
72
59
if ( value . length > 0 ) {
73
- fetchPlacesBySearch ( value ) ; // 검색 실행
60
+ fetchPlacesBySearch ( value ) ;
74
61
} else {
75
- setResults ( [ ] ) ; // 입력이 없으면 결과 초기화
62
+ setResults ( [ ] ) ;
76
63
}
77
64
} ;
78
65
79
- const handleSelectPlace = ( { name } : { name : string } ) => {
80
- setLocation ( name ) ;
66
+ const handleSelectPlace = ( place : { name : string ; address : string } ) => {
67
+ // 매개변수 타입 수정
68
+ setLocation ( place . name ) ; // 입력 필드를 선택된 장소의 이름으로 업데이트
81
69
setResults ( [ ] ) ;
82
- onSelect ( name ) ; // 부모 컴포넌트에 선택된 장소 전달
70
+ onSelect ( place ) ; // place 객체 전달
83
71
} ;
84
72
85
73
const handleCurrentLocation = async ( ) => {
74
+ if ( isFetching ) return ;
75
+ setIsFetching ( true ) ;
76
+
86
77
if ( ! navigator . geolocation ) {
87
78
alert ( "현재 위치를 지원하지 않는 브라우저입니다." ) ;
79
+ setIsFetching ( false ) ;
88
80
return ;
89
81
}
90
82
91
83
navigator . geolocation . getCurrentPosition (
92
84
async ( { coords } ) => {
93
- const { latitude, longitude } = coords ;
94
- await fetchPlaces ( latitude . toString ( ) , longitude . toString ( ) ) ; // 현재 위치를 이용해 장소 검색
85
+ const { latitude : py , longitude : px } = coords ;
86
+
87
+ try {
88
+ const response = await fetch (
89
+ `${ process . env . NEXT_PUBLIC_API_BASE_URL } /places/geocode?py=${ py } &px=${ px } ` ,
90
+ {
91
+ headers : { accept : "*/*" } ,
92
+ }
93
+ ) ;
94
+
95
+ if ( ! response . ok ) {
96
+ const errorText = await response . text ( ) ;
97
+ console . error ( "Error fetching places:" , errorText ) ;
98
+ throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
99
+ }
100
+
101
+ const data = await response . json ( ) ;
102
+
103
+ if ( data . data && data . data . length > 0 ) {
104
+ const selectedPlace = data . data [ 0 ] ;
105
+ setResults ( data . data ) ;
106
+ setLocation ( selectedPlace . name ) ;
107
+ handleSelectPlace ( selectedPlace ) ; // 선택된 장소를 전달
108
+ } else {
109
+ alert ( "현재 위치에 대한 장소를 찾을 수 없습니다." ) ;
110
+ }
111
+ } catch ( error ) {
112
+ console . error ( "Error fetching places:" , error ) ;
113
+ alert ( "위치 정보를 가져오는 중 오류가 발생했습니다." ) ;
114
+ } finally {
115
+ setIsFetching ( false ) ;
116
+ }
95
117
} ,
96
118
( ) => {
97
119
alert ( "위치 정보를 가져오는 중 오류가 발생했습니다." ) ;
120
+ setIsFetching ( false ) ;
98
121
}
99
122
) ;
100
123
} ;
@@ -104,7 +127,6 @@ function LocationInput({ className, onSelect }: LocationInputProps) {
104
127
< div className = "text-text-default text-xl font-semibold leading-loose mb-[12px]" >
105
128
어떤 공간을 찾고 계신가요?
106
129
</ div >
107
-
108
130
< div className = "relative w-[328px] h-14 p-4 bg-background-light rounded-lg flex justify-between items-center" >
109
131
< div className = "flex items-center gap-3" >
110
132
< Image
@@ -121,8 +143,6 @@ function LocationInput({ className, onSelect }: LocationInputProps) {
121
143
className = "bg-transparent border-none grow shrink basis-0 text-text-default text-base font-medium font-['Pretendard'] leading-normal outline-none flex-1 placeholder-mediumGray"
122
144
/>
123
145
</ div >
124
-
125
- { /* 현재 위치 찾기 버튼 복원 */ }
126
146
< div
127
147
role = "button"
128
148
tabIndex = { 0 }
@@ -140,12 +160,11 @@ function LocationInput({ className, onSelect }: LocationInputProps) {
140
160
/>
141
161
</ div >
142
162
</ div >
143
-
144
163
{ results . length > 0 && (
145
164
< SearchResults
146
165
results = { results }
147
166
searchTerm = { location }
148
- onSelect = { handleSelectPlace }
167
+ onSelect = { handleSelectPlace } // 수정된 handleSelectPlace 함수 전달
149
168
/>
150
169
) }
151
170
</ div >
0 commit comments