Skip to content

Commit

Permalink
Merge pull request #270 from boostcampwm-2024/feature/fe/search
Browse files Browse the repository at this point in the history
Feature/fe/search
  • Loading branch information
leedongyull authored Nov 26, 2024
2 parents d2f952d + 035d7f9 commit 20f96e6
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import startmarker from '@/assets/startmarker.png';
import endmarker from '@/assets/endmarker.png';
import { CurrentUserContext } from '@/context/CurrentUserContext';
import { ToolDescription } from '@/component/tooldescription/ToolDescription';
import { SearchBox } from '@/component/searchbox/SearchBox';

export const MapCanvasForDraw = ({
width,
Expand Down Expand Up @@ -216,9 +217,27 @@ export const MapCanvasForDraw = ({
if (!clickedPoint) return;
switch (toolType) {
case ButtonState.START_MARKER:
setCurrentUser(prevUser => ({
...prevUser,
start_location: {
...prevUser.start_location,
title: '', // title을 빈 문자열로 초기화 -> 검색창에 보이게 하려고
lat: clickedPoint.lat,
lng: clickedPoint.lng,
},
}));
setStartMarker(clickedPoint);
break;
case ButtonState.DESTINATION_MARKER:
setCurrentUser(prevUser => ({
...prevUser,
end_location: {
...prevUser.end_location,
title: '', // title을 빈 문자열로 초기화 -> 검색창에 보이게 하려고
lat: clickedPoint.lat,
lng: clickedPoint.lng,
},
}));
setEndMarker(clickedPoint);
break;
case ButtonState.LINE_DRAWING:
Expand Down Expand Up @@ -384,6 +403,33 @@ export const MapCanvasForDraw = ({
}
};

const handleCreateMarker = (point: IPoint) => {
if (toolType === ButtonState.START_MARKER) {
setStartMarker(point);
setCurrentUser(prevUser => ({
...prevUser,
start_location: {
...prevUser.start_location,
title: '',
},
}));
} else {
setEndMarker(point);
setCurrentUser(prevUser => ({
...prevUser,
end_location: {
...prevUser.end_location,
title: '',
},
}));
}
};

const handleDeleteMarker = () => {
if (toolType === ButtonState.START_MARKER) setStartMarker(null);
else setEndMarker(null);
};

useEffect(() => {
if (isDragging) {
if (canvasRef.current) {
Expand Down Expand Up @@ -415,6 +461,16 @@ export const MapCanvasForDraw = ({
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
>
{(toolType === ButtonState.START_MARKER || toolType === ButtonState.DESTINATION_MARKER) && (
<div className="relative">
<SearchBox
setMarker={handleCreateMarker}
deleteMarker={handleDeleteMarker}
startMarker={startMarker}
endMarker={endMarker}
/>
</div>
)}
<div ref={mapRef} style={{ width: '100%', height: '100%' }} />
{toolType === ButtonState.LINE_DRAWING ? (
<div className="z-1000 absolute left-1/2 top-[10px] flex -translate-x-1/2 transform gap-2">
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/component/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const Header = (props: IHeaderProps) => {
return (
<header
className={classNames(
'absolute flex w-full flex-col gap-2.5 bg-transparent p-4',
'absolute flex w-full flex-col gap-2.5 bg-transparent px-4 pb-2 pt-4',
props.className,
)}
>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/component/routebutton/RouteResultButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ export const RouteResultButton = (props: IRouteResultButtonProps) => {
props.user.id > 1 ? '' : 'mr-8',
)}
>
<div className="h-full w-24 overflow-hidden text-ellipsis whitespace-nowrap rounded border-2 px-2 py-4 text-start text-xs font-normal">
{props.user.start_location.title}
<div className="h-full w-24 overflow-hidden text-ellipsis whitespace-nowrap rounded border-2 px-2 py-[16px] text-start text-xs font-normal">
{props.user.end_location.title}
</div>
<GoArrowRight className="mx-2 h-8 w-8" />
<div className="h-full w-24 overflow-hidden text-ellipsis whitespace-nowrap rounded border-2 px-2 py-4 text-start text-xs font-normal">
<div className="h-full w-24 overflow-hidden text-ellipsis whitespace-nowrap rounded border-2 px-2 py-[16px] text-start text-xs font-normal">
{props.user.end_location.title}
</div>
</div>
Expand Down
92 changes: 67 additions & 25 deletions frontend/src/component/searchbox/SearchBox.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import { ToolTypeContext } from '@/context/ToolTypeContext';
import React, { useContext, useEffect, useState } from 'react';
import { IoMdClose, IoMdSearch } from 'react-icons/io';
import { IoMdClose } from 'react-icons/io';
import { CurrentUserContext } from '@/context/CurrentUserContext';
import { IPoint } from '@/lib/types/canvasInterface';
import { getAddressFromCoordinates } from '@/utils/map/getAddress';
import { ButtonState } from '../common/enums';

interface ISearchResultItem {
title: string;
address: string;
link: string;
roadAddress: string;
lat: number;
lng: number;
}

export const SearchBox = () => {
const [inputValue, setInputValue] = useState(''); // 검색 입력값 상태
interface ISearchBoxProps {
startMarker?: IPoint | null;
endMarker?: IPoint | null;
setMarker: (point: IPoint) => void;
deleteMarker: () => void;
}
export const SearchBox = (props: ISearchBoxProps) => {
const [inputValue, setInputValue] = useState<string>(''); // 검색 입력값 상태
const [searchResults, setSearchResults] = useState<ISearchResultItem[]>([]); // 검색 결과 상태
const [loading, setLoading] = useState(false); // 로딩 상태
const [error, setError] = useState<string | null>(null); // 에러 상태
Expand Down Expand Up @@ -68,8 +76,8 @@ export const SearchBox = () => {
title: item.title.replace(/<\/?[^>]+(>|$)/g, ''), // HTML 태그 제거
address: item.address || item.roadAddress || '주소 정보 없음',
link: item.link || '#',
lat: parseFloat(item.mapy) / 1e7, // 위도 값 변환
lng: parseFloat(item.mapx) / 1e7, // 경도 값 변환
lat: parseFloat(item.mapy) / 1e7,
lng: parseFloat(item.mapx) / 1e7,
}));
console.log(data);
setSearchResults(formattedResults); // 검색 결과 상태 업데이트
Expand All @@ -83,45 +91,79 @@ export const SearchBox = () => {
/* TODO: 자동검색 로직 수정 필요 */

useEffect(() => {
const delayDebounceFn = setTimeout(() => {
if (inputValue.trim()) {
handleSearch();
const getAddress = async () => {
if (toolType === ButtonState.START_MARKER && props.startMarker) {
if (currentUser.start_location?.title) {
// title이 비어있을 때 === 부산역 같은 title이 없을때
return;
}
const value = await getAddressFromCoordinates(props.startMarker.lat, props.startMarker.lng);
setInputValue(value);
} else if (toolType === ButtonState.DESTINATION_MARKER && props.endMarker) {
if (currentUser.end_location?.title) {
return;
}
const value = await getAddressFromCoordinates(props.endMarker.lat, props.endMarker.lng);
setInputValue(value);
}
}, 300);
};

return () => clearTimeout(delayDebounceFn);
}, [inputValue]);
getAddress();
}, [toolType, props.startMarker, props.endMarker]);

const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value); // 상태 업데이트
};

useEffect(() => {
// 마커가 이미 존재하는 경우 더 이상 검색하지 않도록 방지
if (toolType === ButtonState.START_MARKER && props.startMarker) {
return;
}

if (toolType === ButtonState.DESTINATION_MARKER && props.endMarker) {
return;
}

if (inputValue.trim()) {
const delayDebounceFn = setTimeout(() => {
handleSearch();
}, 300);

// Todo : 요부분 반환값 lint 오류 때문에 해결이 안돼요...
// eslint-disable-next-line consistent-return
return () => {
clearTimeout(delayDebounceFn);
};
}
}, [inputValue, props.startMarker, props.endMarker, toolType]);

const handleSelectResult = (result: ISearchResultItem) => {
setInputValue(result.title); // 선택한 결과로 inputValue를 업데이트
setSearchResults([]); // 결과 리스트를 닫음
setInputValue(result.title);
setSearchResults([]);
props.setMarker({ lat: result.lat, lng: result.lng });
updateUser(result.title, result.lat, result.lng);
console.log(`위도: ${result.lat}, 경도: ${result.lng}`);
};

const handleClear = () => {
setInputValue(''); // 입력값 초기화
setSearchResults([]); // 검색 결과 초기화
setInputValue('');
setSearchResults([]);
props.deleteMarker();
};

return (
<div className="relative">
<div className="absolute top-2 z-[6000] w-full px-2">
{/* 검색 입력 */}
<div className="border-grayscale-75 text-grayscale-400 flex h-11 w-full rounded border px-3">
<div className="border-grayscale-75 text-grayscale-400 flex h-11 w-full rounded border bg-white px-3">
<input
type="text"
value={inputValue}
onChange={handleInputChange}
placeholder="검색어를 입력하세요"
className="placeholder:text-grayscale-50 text-grayscale-400 h-11 w-full px-3 text-xs focus:outline-none"
placeholder={
toolType === ButtonState.START_MARKER ? '출발지를 입력하세요' : '도착지를 입력하세요'
}
className="placeholder:text-grayscale-50 text-grayscale-400 h-full w-full px-3 text-xs focus:outline-none"
/>
<button className="flex h-full w-8 items-center" onClick={handleSearch}>
<IoMdSearch className="h-6 w-6" />
</button>
<button className="jusify-center flex h-full w-8 items-center" onClick={handleClear}>
<IoMdClose className="h-6 w-6" />
</button>
Expand All @@ -135,7 +177,7 @@ export const SearchBox = () => {
{searchResults.map(result => (
<button
type="button"
key={result.link}
key={result.roadAddress}
onClick={() => handleSelectResult(result)}
className="flex flex-col items-start gap-2 p-2"
>
Expand Down
18 changes: 4 additions & 14 deletions frontend/src/pages/DrawRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { useContext, useEffect } from 'react';
import { FooterContext } from '@/component/layout/footer/LayoutFooterProvider';
import { useNavigate, useParams } from 'react-router-dom';
import { IUser, UserContext } from '@/context/UserContext';
import { SearchBox } from '@/component/searchbox/SearchBox';
import { ToolTypeProvider } from '@/context/ToolTypeContext';
import { buttonActiveType } from '@/component/layout/enumTypes';
import { MapProviderForDraw } from '@/component/canvasWithMap/canvasWithMapforDraw/MapProviderForDraw.tsx';
Expand Down Expand Up @@ -84,11 +83,7 @@ export const DrawRoute = () => {
const updatedUser = { ...currentUser }; // currentUser 복사

// start_location.title이 비어 있으면 주소를 업데이트
if (
!updatedUser.start_location.title &&
updatedUser.start_location.lat &&
updatedUser.start_location.lng
) {
if (!updatedUser.start_location.title) {
try {
const startAddress = await getAddressFromCoordinates(
updatedUser.start_location.lat,
Expand All @@ -101,11 +96,7 @@ export const DrawRoute = () => {
}

// end_location.title이 비어 있으면 주소를 업데이트
if (
!updatedUser.end_location.title &&
updatedUser.end_location.lat &&
updatedUser.end_location.lng
) {
if (!updatedUser.end_location.title) {
try {
const endAddress = await getAddressFromCoordinates(
updatedUser.end_location.lat,
Expand Down Expand Up @@ -137,10 +128,9 @@ export const DrawRoute = () => {

return (
<ToolTypeProvider>
<div className="flex h-full w-full flex-col py-20">
<SearchBox />
<div className="flex h-full w-full flex-col py-[75px]">
<div style={{ position: 'relative', padding: '1rem' }}>
<MapProviderForDraw width={window.innerWidth - 32} height={window.innerHeight - 210} />
<MapProviderForDraw width={window.innerWidth - 32} height={window.innerHeight - 180} />
</div>
</div>
</ToolTypeProvider>
Expand Down

0 comments on commit 20f96e6

Please sign in to comment.