1. UI 구성
2. 코드분리
3. 키워드검색 ➡️ 카테고리 검색
퍼블리싱이 끝났고 해당 스타일을 가지고 리팩토링을 진행했다.
gif
에 나와있듯이 이전과는 다르게 깔끔하고 보기 좋은 디자인이다.
<SerchListWrap>
{/* 검색 및 필터 UI */}
<SerchTabWrap>
<SelectWrap>
<RegionSelector
selectedRegion={selectedRegion}
selectedCity={selectedCity}
setSelectedRegion={setSelectedRegion}
setSelectedCity={setSelectedCity}
onRegionChange={handleRegionChange}
/>
</SelectWrap>
<SearchTabUl>
<SearchTabLi
isActive={selectedCategory === 'CE7' ? 'true' : 'false'}
onClick={() => setSelectedCategory('CE7')} // 선택된 카테고리 업데이트
>
<i className="fa-solid fa-mug-saucer"></i>
<p>카페</p>
</SearchTabLi>
<SearchTabLi
isActive={selectedCategory === 'AD5' ? 'true' : 'false'}
onClick={() => setSelectedCategory('AD5')} // 선택된 카테고리 업데이트
>
<i className="fa-solid fa-hotel"></i>
<p>펜션</p>
</SearchTabLi>
</SearchTabUl>
</SerchTabWrap>
<SearchButton onClick={searchByCategory}>현 위치로 검색</SearchButton>
<ListWrap>
{places.map((place, index) => (
<ListItem
key={index}
onClick={() => {
const marker = markers[index];
if (marker) {
infowindow.setContent(createInfoWindowContent(place)); // 유틸리티 함수 사용
infowindow.open(map, marker);
map.panTo(marker.getPosition());
}
}}
>
<ListLine>
<div style={{ display: 'flex', alignItems: 'center' }}>
<i
className={`fa-solid ${
place.category_name?.includes('카페')
? 'fa-mug-saucer'
: 'fa-hotel'
}`}
style={{ color: '#ff6732', marginRight: '8px' }}
></i>
<TitleP isListTitle="true">{place.place_name}</TitleP>
</div>
<ListBookmark>
<HeartIcon className="fa-regular fa-heart" />
</ListBookmark>
</ListLine>
<AddressP isListTitle="true">
{place.road_address_name || place.address_name}
</AddressP>
<PhoneP isListTitle="true">{place.phone || '정보 없음'}</PhoneP>
</ListItem>
))}
</ListWrap>
</SerchListWrap>
<div style={{ flex: 1 }}>
<div id="map" style={{ width: '100%', height: '100%' }}></div>
</div>
<MapControls location={location} />
// 검색 결과 마커 표시
const displayPlaces = (places) => {
const bounds = new window.kakao.maps.LatLngBounds();
markers.forEach((marker) => marker.setMap(null));
setMarkers([]);
const newMarkers = places.map((place) => {
const position = new window.kakao.maps.LatLng(place.y, place.x);
const marker = new window.kakao.maps.Marker({ position });
marker.setMap(map);
bounds.extend(position);
window.kakao.maps.event.addListener(marker, 'click', () => {
infowindow.setContent(createInfoWindowContent(place));
infowindow.open(map, marker);
});
return marker;
});
setMarkers(newMarkers);
map.setBounds(bounds);
};
// 검색 결과 마커 표시
const displayPlaces = (places) => {
const bounds = new window.kakao.maps.LatLngBounds();
markers.forEach((marker) => marker.setMap(null));
setMarkers([]);
const newMarkers = places.map((place) => {
const position = new window.kakao.maps.LatLng(place.y, place.x);
const marker = new window.kakao.maps.Marker({ position });
marker.setMap(map);
bounds.extend(position);
window.kakao.maps.event.addListener(marker, 'click', () => {
infowindow.setContent(`
<div style="
padding: 10px;
font-size: 14px;
line-height: 1.6;
display: flex;
align-items: flex-start;
gap: 10px;
max-width: 250px;
width: auto;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
background-color: #fff;
color: #333;
">
<!-- 아이콘 -->
<div style="flex-shrink: 0; font-size: 20px;">
<i class="fa-solid ${iconClass}" style="color: #ff6732;"></i>
</div>
<!-- 텍스트 -->
<div>
<strong style="font-size: 16px; color: #4b74c6; font-weight:bold; display: block; margin-bottom: 5px;">
${place.place_name}
</strong>
<span style="font-size: 14px; color: #555; display: block; margin-bottom: 3px;">
${place.road_address_name || place.address_name}
</span>
<span style="font-size: 13px; color: #999;">
${place.phone || '전화번호 없음'}
</span>
</div>
</div>
`;
infowindow.open(map, marker);
});
return marker;
});
setMarkers(newMarkers);
map.setBounds(bounds);
};
//utils/infoWindowUitl.js
export const createInfoWindowContent = (place) => {
const iconClass = place.category_name?.includes('카페')
? 'fa-mug-saucer'
: 'fa-hotel';
return `
<div style="
padding: 10px;
font-size: 14px;
line-height: 1.6;
display: flex;
align-items: flex-start;
gap: 10px;
max-width: 250px;
width: auto;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
background-color: #fff;
color: #333;
">
<!-- 아이콘 -->
<div style="flex-shrink: 0; font-size: 20px;">
<i class="fa-solid ${iconClass}" style="color: #ff6732;"></i>
</div>
<!-- 텍스트 -->
<div>
<strong style="font-size: 16px; color: #4b74c6; font-weight:bold; display: block; margin-bottom: 5px;">
${place.place_name}
</strong>
<span style="font-size: 14px; color: #555; display: block; margin-bottom: 3px;">
${place.road_address_name || place.address_name}
</span>
<span style="font-size: 13px; color: #999;">
${place.phone || '전화번호 없음'}
</span>
</div>
</div>
`;
};
사실 이것은 가장 망설이던 부분인데 바꾸기로 결심하게된 포인트가 있다.
우리 프로젝트는 반려동물 동반 가능한 맛집 및 숙박업소 추천 서비스였기 때문에, 항상 그 조건이 만족을 해야만 한다.
그래서 공공데이터포털의 reponse
를 참고했는데, 결과를 보고는 조금 허탈했다.
대부분의 데이터가 카페아니면 펜션이었기 때문이다.
한가지 더 중요한것은, 높은확률로 가게 이름에 애견이라는 말이 붙는다는것...
🤔 근데 나중에 생각해보니 그럴만도 하겠다 싶었다.
그래서 결론이 뭐냐?
- 반려동물 동반 가능한 맛집은 높은확률로 애견카페다.
- 반려동물 동반 가능한 숙박업소는 애견펜션이다.
99%
이상을 얘기한다...뒤늦은 자기반성 :
API리서치를 하라고 했을때 조금 더 자세히 했어야됐다...
참 쉽지않다.
캠프에 호기롭게 도전하긴 했지만 이렇게 난이도가 급상승 할줄은 예상도 하지 못했기에 어려움이 많은것은 사실이다.
그렇지만 많은 과제들을 통해 스스로 어느정도인지 파악하고 또 학습해가면서 성장하는 그 시간들이 참 소중하다고 느낀다.
이제 발표까지 이틀남았으니까 조금 더 힘내서 완성도 높은 결과물을 보여주도록 하자!!! 화이팅!!!