From 60621911d988430242b1c9c9ab244ae9992bf63b Mon Sep 17 00:00:00 2001 From: Yamyam-code Date: Sat, 20 Jan 2024 03:06:52 +0900 Subject: [PATCH 1/6] Feat: create home recommend data --- .../RecommendedItemList.tsx | 279 ++++++- .../RecommendedLocationList.tsx | 68 +- .../TripSpaceItem/TripSpaceItem.tsx | 16 +- .../LocationFilter/LocationFilter.module.scss | 4 +- .../LocationFilter/LocationFilter.tsx | 34 +- .../LocationFliterPage.module.scss | 5 +- .../LocationFliterPage/LocationFliterPage.tsx | 34 +- .../PopularList/PopularList.module.scss | 10 +- .../PopularList/PopularList.tsx | 67 +- .../SelectLocation/SelectLocation.module.scss | 4 +- .../SelectLocation/SelectLocation.tsx | 43 +- .../SearchFromHome/SearchList/SearchList.tsx | 68 +- src/mocks/handlers/home.ts | 735 ++++++------------ src/pages/Home/Home.tsx | 58 +- .../SearchFromHome/SearchFromHome.module.scss | 4 +- 15 files changed, 665 insertions(+), 764 deletions(-) diff --git a/src/components/Home/RecommendedItemList/RecommendedItemList.tsx b/src/components/Home/RecommendedItemList/RecommendedItemList.tsx index cd484ad3..83e54a82 100644 --- a/src/components/Home/RecommendedItemList/RecommendedItemList.tsx +++ b/src/components/Home/RecommendedItemList/RecommendedItemList.tsx @@ -1,63 +1,268 @@ -import { useEffect, useState } from "react"; +import {useState} from 'react'; -import styles from "./RecommendedItemList.module.scss"; +import styles from './RecommendedItemList.module.scss'; -import useComponentSize from "@/hooks/useComponetSize"; +import useComponentSize from '@/hooks/useComponetSize'; -import SlideButton from "@/components/SlideButton/SlideButton"; +import SlideButton from '@/components/SlideButton/SlideButton'; -import { getData } from "@/mocks/handlers/home"; +import RecommendedItem from './RecommendedItem/RecommendedItem'; -import RecommendedItem from "./RecommendedItem/RecommendedItem"; - -import { RecommendedItemDataType } from "@/types/home"; +import {RecommendedItemDataType} from '@/types/home'; interface PropsType { apiNum: number; } -function RecommendedItemList(apiNum: PropsType) { +function RecommendedItemList({apiNum}: PropsType) { const [data, setData] = useState(); const [slideLocation, setSlideLocation] = useState(0); const [componentRef, size] = useComponentSize(); - useEffect(() => { - getData( - `home/recommendedItem/${apiNum.apiNum}`, - setData, - ); - }, [apiNum]); + const recommendedItem = [ + [ + { + id: 2046954, + contentTypeId: 1, + title: '롯데시티호텔 제주', + thumbnail: 'https://www.lottehotel.com/content/dam/lotte-hotel/lotte/jeju/main/4427-01-560-mai-LTJE.jpg', + areaCode: 39, + sigunguCode: 1, + category: '숙소', + rating: '4.5', + }, + { + id: 2804372, + contentTypeId: 1, + title: '하운드호텔 부산역점', + thumbnail: + 'https://q-xx.bstatic.com/xdata/images/hotel/max1024x768/297028773.jpg?k=9c276dfb0e6bf4096483b56901e98b6a843937e7afc62206edde1ab4421cf6a0&o=', + areaCode: 6, + sigunguCode: 5, + category: '숙소', + rating: '4.3', + }, + { + id: 142769, + contentTypeId: 1, + title: '그랜드 인터컨티넨탈 서울 파르나스', + thumbnail: + 'https://pix8.agoda.net/hotelImages/149130/0/5ed2d79f8bc36f329544bf7ddb205081.jpg?ca=7&ce=1&s=1024x768', + areaCode: 1, + sigunguCode: 1, + category: '숙소', + rating: '4.5', + }, + { + id: 2907277, + contentTypeId: 1, + title: '라마다속초호텔', + thumbnail: + 'https://pix8.agoda.net/hotelImages/1276680/-1/4a89954f3a1e111dab3a4d7e858ebab1.jpg?ca=0&ce=1&s=512x384', + areaCode: 32, + sigunguCode: 5, + category: '숙소', + rating: '4.1', + }, + { + id: 2819964, + contentTypeId: 1, + title: '그랜드 조선 제주', + thumbnail: 'https://pix8.agoda.net/hotelImages/18875336/-1/7215b8a9841ac0179c23301301c20a9c.jpg?ce=0&s=512x384', + areaCode: 39, + sigunguCode: 1, + category: '숙소', + rating: '4.5', + }, + { + id: 2706608, + contentTypeId: 1, + title: '경주 오릉한옥', + thumbnail: + 'https://mblogthumb-phinf.pstatic.net/MjAyMjA5MTJfMjk4/MDAxNjYyOTg4MjgzNTEw.Q9hG_pGCf_FZZxt3skTy-rRW2TIGUT1NkC4OzUIPtjMg.6bm7HjlLIeGec2RSQyLv38C9wzFuproRmna-inYz8Jcg.JPEG.sjfmf5588/1662988284079.jpg?type=w800', + areaCode: 35, + sigunguCode: 2, + category: '숙소', + rating: '4.2', + }, + { + id: 2570435, + contentTypeId: 1, + title: '더블힐링펜션', + thumbnail: 'https://ak-d.tripcdn.com/images/22041d000001eied8148C_R_600_400_R5_D.webp', + areaCode: 37, + sigunguCode: 6, + category: '숙소', + rating: '4.3', + }, + { + id: 3073495, + contentTypeId: 1, + title: '인스파이어 엔터테인먼트 리조트', + thumbnail: 'https://ak-d.tripcdn.com/images/1mc1d12000cuj8fhk9E0C_R_600_400_R5_D.webp', + areaCode: 2, + sigunguCode: 10, + category: '숙소', + rating: '4.2', + }, + { + id: 2756802, + contentTypeId: 1, + title: '블루원리조트 프라이빗콘도', + thumbnail: 'https://cd.blueone.com/img/01condo/private/s0201_img3.jpg', + areaCode: 35, + sigunguCode: 2, + category: '숙소', + rating: '4.5', + }, + { + id: 2783770, + contentTypeId: 1, + title: '더 메이 호텔', + thumbnail: + 'https://ak-d.tripcdn.com/images/0226p120009zufiaqAEF2_Z_960_660_R5_D.webp?proc=watermark/image_trip1,l_ne,x_16,y_16,w_67,h_16;digimark/t_image,logo_tripbinary;ignoredefaultwm,1A8F', + areaCode: 37, + sigunguCode: 12, + category: '숙소', + rating: '4.4', + }, + ], + [ + { + id: 3065360, + contentTypeId: 1, + title: '부산요트 투어 요트야', + thumbnail: 'https://d2ur7st6jjikze.cloudfront.net/offer_photos/119386/832573_large_1686709791.jpg?1686709791', + areaCode: 6, + sigunguCode: 16, + category: '레포츠', + rating: '5.0', + }, + { + id: 2774550, + contentTypeId: 1, + title: '알펜시아리조트 눈썰매장', + thumbnail: 'https://www.alpensia.com/images/ski/ski_sled_04.jpg', + areaCode: 32, + sigunguCode: 15, + category: '레포츠', + rating: '4.4', + }, + { + id: 131878, + contentTypeId: 1, + title: '오크밸리스키장', + thumbnail: + 'https://thumb.tidesquare.com/tour/public/product/PRV3000000012/PRD3000214495/origin/20230919054639313_xhnmy.jpg?type=thum', + areaCode: 32, + sigunguCode: 9, + category: '레포츠', + rating: '3.9', + }, + { + id: 131519, + contentTypeId: 1, + title: '그랜드하얏트 서울 아이스링크', + thumbnail: + 'https://t2.daumcdn.net/thumb/R720x0.fjpg/?fname=http://t1.daumcdn.net/brunch/service/user/56y8/image/rdK0l3jBvzz_-2v5_VN-P-JGvEA.jpg', + areaCode: 1, + sigunguCode: 21, + category: '레포츠', + rating: '4.5', + }, + { + id: 2648177, + contentTypeId: 1, + title: '아쿠아필드 하남', + thumbnail: 'https://m.starfield.co.kr/cdn/nstfd/images/tenant/hanam/TN201608091951332396/img_swiper_03_02.jpg', + areaCode: 31, + sigunguCode: 30, + category: '레포츠', + rating: '4.4', + }, + { + id: 702551, + contentTypeId: 1, + title: '스파랜드 센텀시티', + thumbnail: 'https://d2ur7st6jjikze.cloudfront.net/offer_photos/115727/884233_medium_1695113694.jpg?1695113694', + areaCode: 6, + sigunguCode: 16, + category: '레포츠', + rating: '4.5', + }, + { + id: 2714241, + contentTypeId: 1, + title: '아르떼뮤지엄 제주', + thumbnail: + 'https://image.kkday.com/v2/image/get/w_960%2Cc_fit%2Cq_55%2Ct_webp/s1.kkday.com/product_103871/20220617024719_dCb7Y/jpg', + areaCode: 39, + sigunguCode: 1, + category: '문화시설', + rating: '4.4', + }, + { + id: 126714, + contentTypeId: 1, + title: '한화리조트 설악워터피아', + thumbnail: + 'https://www.hanwha.co.kr/download.do?path=contents/reportDataImage&oriName=ec82aceca784365fec84a4ec958520ec9b8ced84b0ed94bcec958420ec95bceab2bd2e6a7067&svrName=157708391795997256.jpg&menu=reportDataImage&seq=5413', + areaCode: 32, + sigunguCode: 5, + category: '레포츠', + rating: '4.2', + }, + { + id: 131301, + contentTypeId: 1, + title: '비발디파크 스키장', + thumbnail: 'https://www.sonohotelsresorts.com/cimage/we/Resort/202301/images/DmWebA_1673944963349.jpg', + areaCode: 32, + sigunguCode: 16, + category: '레포츠', + rating: '4.4', + }, + { + id: 1045657, + contentTypeId: 1, + title: '반얀트리 클럽 앤 스파 서울', + thumbnail: 'https://image.goodchoice.kr/resize_490x348/affiliate/2017/06/14/5940944a3ebdd.jpg', + areaCode: 1, + sigunguCode: 24, + category: '레포츠', + rating: '4.5', + }, + ], + ]; return (
- {data && ( - - )} + +
- {data && - data.map((data, i) => ( - - ))} + {recommendedItem[apiNum].map((data, i) => ( + + ))}
); diff --git a/src/components/Home/RecommendedLocationList/RecommendedLocationList.tsx b/src/components/Home/RecommendedLocationList/RecommendedLocationList.tsx index 0a89fad3..bbe59669 100644 --- a/src/components/Home/RecommendedLocationList/RecommendedLocationList.tsx +++ b/src/components/Home/RecommendedLocationList/RecommendedLocationList.tsx @@ -1,53 +1,61 @@ -import { useEffect, useState } from "react"; +import {useState} from 'react'; -import styles from "./RecommendedLocationList.module.scss"; +import styles from './RecommendedLocationList.module.scss'; -import useComponentSize from "@/hooks/useComponetSize"; +import useComponentSize from '@/hooks/useComponetSize'; -import SlideButton from "@/components/SlideButton/SlideButton"; +import SlideButton from '@/components/SlideButton/SlideButton'; -import { getData } from "@/mocks/handlers/home"; +import RecommendedLocation from './RecommendedLocation/RecommendedLocation'; -import RecommendedLocation from "./RecommendedLocation/RecommendedLocation"; - -import { LocationDataType } from "@/types/home"; +import {LocationDataType} from '@/types/home'; function RecommendedLocationList() { const [data, setData] = useState(); const [slideLocation, setSlideLocation] = useState(0); const [componentRef, size] = useComponentSize(); - useEffect(() => { - getData( - `home/recommendedLocation`, - setData, - ); - }, []); + const recommendedLocation = [ + { + location: '제주', + imageURL: 'https://img-cf.kurly.com/shop/data/goodsview/20210218/gv30000159355_1.jpg', + }, + { + location: '부산', + imageURL: 'https://img-cf.kurly.com/shop/data/goodsview/20210218/gv30000159355_1.jpg', + }, + { + location: '강릉', + imageURL: 'https://img-cf.kurly.com/shop/data/goodsview/20210218/gv30000159355_1.jpg', + }, + { + location: '서울', + imageURL: 'https://img-cf.kurly.com/shop/data/goodsview/20210218/gv30000159355_1.jpg', + }, + ]; return (
- {data && ( - - )} + +
- {data && - data.map((data, i) => ( - - ))} + {recommendedLocation.map((data, i) => ( + + ))}
); diff --git a/src/components/Home/TripSpaceAtHome/TripSpaceItem/TripSpaceItem.tsx b/src/components/Home/TripSpaceAtHome/TripSpaceItem/TripSpaceItem.tsx index c8356c27..f8fd28d0 100644 --- a/src/components/Home/TripSpaceAtHome/TripSpaceItem/TripSpaceItem.tsx +++ b/src/components/Home/TripSpaceAtHome/TripSpaceItem/TripSpaceItem.tsx @@ -1,9 +1,9 @@ -import { MdArrowForwardIos } from "react-icons/md"; -import { Link } from "react-router-dom"; +import {MdArrowForwardIos} from 'react-icons/md'; +import {Link} from 'react-router-dom'; -import styles from "./TripSpaceItem.module.scss"; +import styles from './TripSpaceItem.module.scss'; -import { TripSpaceDataType } from "@/types/home"; +import {TripSpaceDataType} from '@/types/home'; interface PropsData { data: TripSpaceDataType; @@ -12,13 +12,9 @@ interface PropsData { function TripSpaceItem(data: PropsData) { const imageAlt = `${data.data.tripTitle}의 사진`; return ( - +
- {imageAlt} + {imageAlt} {data.data.dDay &&
} {data.data.dDay}
diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.module.scss b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.module.scss index 4112046d..aa23f46f 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.module.scss +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.module.scss @@ -1,7 +1,6 @@ -@use "@/sass" as *; +@use '@/sass' as *; .container { - width: 9.1rem; height: 3rem; display: flex; @@ -10,7 +9,6 @@ padding: 4px 4px 4px 10px; - border: 1px solid $neutral300; border-radius: 16px; @include typography(tabLabel); diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx index cab468ec..bba7d4a7 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx @@ -1,29 +1,49 @@ -import { useState } from "react"; -import { MdOutlineKeyboardArrowDown } from "react-icons/md"; +import {useEffect, useState} from 'react'; +import {MdOutlineKeyboardArrowDown} from 'react-icons/md'; -import styles from "./LocationFilter.module.scss"; +import styles from './LocationFilter.module.scss'; -import LocationFliterPage from "./LocationFliterPage/LocationFliterPage"; +import LocationFliterPage from './LocationFliterPage/LocationFliterPage'; interface PropsType { + searchLocation: string; setSearchLocation: React.Dispatch>; } -function LocationFilter({ setSearchLocation }: PropsType) { +function LocationFilter({searchLocation, setSearchLocation}: PropsType) { const [click, setClick] = useState(true); + const [buttonName, setButtonName] = useState('전체 지역'); function handleClick() { setClick((prev) => !prev); } + useEffect(() => { + const datas = searchLocation.split(' '); + if (datas[0] === '전국') { + setButtonName('전체 지역'); + } else { + setButtonName(datas[0]); + } + }, [searchLocation]); + return ( <> -
- 전체 지역 +
+ {buttonName}
diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.module.scss b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.module.scss index 7356bbeb..7534bec5 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.module.scss +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.module.scss @@ -1,9 +1,6 @@ -@use "@/sass" as *; +@use '@/sass' as *; .container { - position: absolute; - top: -88px; - width: 100%; background-color: $neutral0; diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx index 88e8b694..3b2ca98e 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx @@ -1,14 +1,15 @@ -import { useState } from "react"; +import {useState} from 'react'; -import styles from "./LocationFliterPage.module.scss"; +import styles from './LocationFliterPage.module.scss'; -import BackIcon from "@/assets/homeIcons/search/backInHome.svg?react"; +import BackIcon from '@/assets/homeIcons/search/backInHome.svg?react'; -import PopularList from "./PopularList/PopularList"; -import SelectLocation from "./SelectLocation/SelectLocation"; +import PopularList from './PopularList/PopularList'; +import SelectLocation from './SelectLocation/SelectLocation'; interface PropsType { click: boolean; + searchLocation: string; handleClick: () => void; setSearchLocation: React.Dispatch>; } @@ -18,14 +19,11 @@ interface AreaDataType { sigunguCode: number; } -function LocationFliterPage({ - click, - handleClick, - setSearchLocation, -}: PropsType) { - const [area, setArea] = useState("전국"); +function LocationFliterPage({click, handleClick, setSearchLocation}: PropsType) { + const [area, setArea] = useState('전국'); const [areaData, setAreaData] = useState(); - const [sigungu, setSigungu] = useState("전체 지역"); + const [sigungu, setSigungu] = useState('전체 지역'); + const [pick, setPick] = useState(''); const vh = window.innerHeight / 100; @@ -37,7 +35,12 @@ function LocationFliterPage({ return (
450 ? 'absolute' : 'fixed', + top: window.innerWidth > 450 ? '-88px' : 0, + right: click ? '-100%' : 0, + height: `${vh * 100}px`, + }} >
{!onboarding && } - {modal && ( - - )} + {modal && }
); } diff --git a/src/pages/SearchFromHome/SearchFromHome.module.scss b/src/pages/SearchFromHome/SearchFromHome.module.scss index f85f38d9..b5434c48 100644 --- a/src/pages/SearchFromHome/SearchFromHome.module.scss +++ b/src/pages/SearchFromHome/SearchFromHome.module.scss @@ -1,4 +1,4 @@ -@use "@/sass" as *; +@use '@/sass' as *; .container { width: 100%; @@ -6,7 +6,7 @@ display: flex; flex-direction: column; - font-family: "suit", sans-serif; + font-family: 'suit', sans-serif; color: $neutral900; From ba3652d14dd27c5bc2895a310fc0086aeeafc907 Mon Sep 17 00:00:00 2001 From: Yamyam-code Date: Sat, 20 Jan 2024 04:41:09 +0900 Subject: [PATCH 2/6] Feat: add location sort query --- .../SearchFromHome/MapHeader/MapHeader.tsx | 18 ++--- .../SearchFromHome/SearchBar/SearchBar.tsx | 47 +++++++------ .../SearchFromHome/SearchHome/SearchHome.tsx | 14 ++-- .../SearchKeyword/SearchKeyword.tsx | 30 ++++----- .../LocationFilter/LocationFilter.tsx | 11 ++- .../LocationFliterPage/LocationFliterPage.tsx | 12 +++- .../SearchFromHome/SearchList/SearchList.tsx | 52 +++++++++----- .../SearchList/Tabs/Tab/Tab.tsx | 23 ++++--- .../SearchFromHome/SearchList/Tabs/Tabs.tsx | 42 +++++------- src/pages/SearchFromHome/SearchFromHome.tsx | 67 +++++++++++++------ 10 files changed, 187 insertions(+), 129 deletions(-) diff --git a/src/components/SearchFromHome/MapHeader/MapHeader.tsx b/src/components/SearchFromHome/MapHeader/MapHeader.tsx index f1381cdb..5bf2c899 100644 --- a/src/components/SearchFromHome/MapHeader/MapHeader.tsx +++ b/src/components/SearchFromHome/MapHeader/MapHeader.tsx @@ -1,21 +1,23 @@ -import { useNavigate } from "react-router-dom"; +import {useNavigate} from 'react-router-dom'; -import styles from "./MapHeader.module.scss"; +import styles from './MapHeader.module.scss'; -import BackIcon from "@/assets/homeIcons/search/backInHome.svg?react"; +import BackIcon from '@/assets/homeIcons/search/backInHome.svg?react'; interface PropsType { - keyword: string | undefined; + keyword: string; category: string; - set: React.Dispatch>; + searchLocation: string; + sort: string; + setMoveMap: React.Dispatch>; } -function MapHeader({ keyword, set, category }: PropsType) { +function MapHeader({keyword, setMoveMap, category, searchLocation, sort}: PropsType) { const navigate = useNavigate(); function offMap() { - set("false"); - navigate(`/home/search?keyword=${keyword}&category=${category}`); + setMoveMap('false'); + navigate(`/home/search?keyword=${keyword}&category=${category}&map=false&location=${searchLocation}&sort=${sort}`); } return ( diff --git a/src/components/SearchFromHome/SearchBar/SearchBar.tsx b/src/components/SearchFromHome/SearchBar/SearchBar.tsx index 18866fe5..895e5062 100644 --- a/src/components/SearchFromHome/SearchBar/SearchBar.tsx +++ b/src/components/SearchFromHome/SearchBar/SearchBar.tsx @@ -1,29 +1,30 @@ -import { useEffect, useRef, useState } from "react"; -import { useNavigate } from "react-router-dom"; +import {useEffect, useRef, useState} from 'react'; +import {useNavigate} from 'react-router-dom'; -import styles from "./SearchBar.module.scss"; +import styles from './SearchBar.module.scss'; -import BackIcon from "@/assets/homeIcons/search/backInHome.svg?react"; -import SearchIcon from "@/assets/homeIcons/search/searchIcon.svg?react"; +import BackIcon from '@/assets/homeIcons/search/backInHome.svg?react'; +import SearchIcon from '@/assets/homeIcons/search/searchIcon.svg?react'; interface PropsType { - set: React.Dispatch>; - keyword: string | undefined; + keyword: string; + category: string; + searchLocation: string; + sort: string; + setKeyword: React.Dispatch>; } interface InputBarType extends HTMLInputElement { focus: () => void; } -function SearchBar({ set, keyword }: PropsType) { - const [inputValue, setInputValue] = useState(""); +function SearchBar({setKeyword, keyword, category, searchLocation, sort}: PropsType) { + const [inputValue, setInputValue] = useState(''); const navigate = useNavigate(); const inputBar = useRef(null); useEffect(() => { - if (keyword) { - setInputValue(keyword); - } + setInputValue(keyword); if (inputBar.current) { inputBar.current.focus(); } @@ -34,17 +35,19 @@ function SearchBar({ set, keyword }: PropsType) { } function search() { - set(inputValue); - navigate(`/home/search?keyword=${inputValue}&category=전체`); + setKeyword(inputValue); + navigate( + `/home/search?keyword=${inputValue}&category=${category}&map=false&location=${searchLocation}&sort=${sort}`, + ); } function removeValue() { - if (!keyword) { - navigate("/"); + if (keyword === '') { + navigate('/'); } else { - navigate("/home/search"); - setInputValue(""); - set(undefined); + navigate('/home/search'); + setInputValue(''); + setKeyword(''); } } @@ -53,13 +56,13 @@ function SearchBar({ set, keyword }: PropsType) {
{ - if (e.key === "Enter") { + if (e.key === 'Enter') { search(); } }} diff --git a/src/components/SearchFromHome/SearchHome/SearchHome.tsx b/src/components/SearchFromHome/SearchHome/SearchHome.tsx index b77108bc..45330897 100644 --- a/src/components/SearchFromHome/SearchHome/SearchHome.tsx +++ b/src/components/SearchFromHome/SearchHome/SearchHome.tsx @@ -1,13 +1,13 @@ -import styles from "./SearchHome.module.scss"; +import styles from './SearchHome.module.scss'; -import HotItems from "./HotItems/HotItems"; -import SearchKeyword from "./SearchKeyword/SearchKeyword"; +import HotItems from './HotItems/HotItems'; +import SearchKeyword from './SearchKeyword/SearchKeyword'; interface PropsType { - set: React.Dispatch>; + set: React.Dispatch>; } -function SearchHome({ set }: PropsType) { +function SearchHome({set}: PropsType) { return (
@@ -16,11 +16,11 @@ function SearchHome({ set }: PropsType) {

최근 30일간 인기 장소

- +

최근 30일간 인기 숙소

- +
); diff --git a/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx b/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx index 7f4a73da..ba80a087 100644 --- a/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx +++ b/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx @@ -1,19 +1,19 @@ -import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; +import {useEffect, useState} from 'react'; +import {useNavigate} from 'react-router-dom'; -import styles from "./SearchKeyword.module.scss"; +import styles from './SearchKeyword.module.scss'; -import useComponentSize from "@/hooks/useComponetSize"; +import useComponentSize from '@/hooks/useComponetSize'; -import SlideButton from "@/components/SlideButton/SlideButton"; +import SlideButton from '@/components/SlideButton/SlideButton'; -import { getData } from "@/mocks/handlers/home"; +import {getData} from '@/mocks/handlers/home'; interface PropsType { - set: React.Dispatch>; + set: React.Dispatch>; } -function SearchKeyword({ set }: PropsType) { +function SearchKeyword({set}: PropsType) { const [data, setData] = useState(); const [listWidth, setListWidth] = useState(0); const [slideLocation, setSlideLocation] = useState(0); @@ -21,19 +21,15 @@ function SearchKeyword({ set }: PropsType) { const navigate = useNavigate(); useEffect(() => { - getData("home/search/keyword", setData); + getData('home/search/keyword', setData); }, []); // 각 키워드의 너비를 모두 더한 값을 구함 useEffect(() => { // 정확한 이유를 찾지 못하였으나 setTimeout을 걸지 않으면 각 p태그의 width가 실제보다 다소 큰 수가 반영됨 setTimeout(() => { - if ( - data && - componentRef.current && - componentRef.current?.childNodes.length === data.length - ) { - const pTags = componentRef.current.querySelectorAll("p"); + if (data && componentRef.current && componentRef.current?.childNodes.length === data.length) { + const pTags = componentRef.current.querySelectorAll('p'); const widths = Array.from(pTags).map((pTag) => { const rect = pTag.getBoundingClientRect(); return rect.width; @@ -65,8 +61,8 @@ function SearchKeyword({ set }: PropsType) { className={styles.slide_box} ref={componentRef} style={{ - overflow: size.width < 449 ? "scroll" : "visible", - left: slideLocation + "px", + overflow: size.width < 449 ? 'scroll' : 'visible', + left: slideLocation + 'px', }} > {data ? ( diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx index bba7d4a7..9e4cfcfa 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx @@ -6,11 +6,15 @@ import styles from './LocationFilter.module.scss'; import LocationFliterPage from './LocationFliterPage/LocationFliterPage'; interface PropsType { + keyword: string; + category: string; + moveMap: string; searchLocation: string; + sort: string; setSearchLocation: React.Dispatch>; } -function LocationFilter({searchLocation, setSearchLocation}: PropsType) { +function LocationFilter({keyword, category, moveMap, searchLocation, sort, setSearchLocation}: PropsType) { const [click, setClick] = useState(true); const [buttonName, setButtonName] = useState('전체 지역'); @@ -43,7 +47,10 @@ function LocationFilter({searchLocation, setSearchLocation}: PropsType) {
diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx index 3b2ca98e..37660d7f 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx @@ -1,4 +1,5 @@ import {useState} from 'react'; +import {useNavigate} from 'react-router-dom'; import styles from './LocationFliterPage.module.scss'; @@ -9,7 +10,10 @@ import SelectLocation from './SelectLocation/SelectLocation'; interface PropsType { click: boolean; - searchLocation: string; + keyword: string; + category: string; + moveMap: string; + sort: string; handleClick: () => void; setSearchLocation: React.Dispatch>; } @@ -19,16 +23,20 @@ interface AreaDataType { sigunguCode: number; } -function LocationFliterPage({click, handleClick, setSearchLocation}: PropsType) { +function LocationFliterPage({click, keyword, category, moveMap, sort, handleClick, setSearchLocation}: PropsType) { const [area, setArea] = useState('전국'); const [areaData, setAreaData] = useState(); const [sigungu, setSigungu] = useState('전체 지역'); const [pick, setPick] = useState(''); + const navigate = useNavigate(); const vh = window.innerHeight / 100; function submit() { setSearchLocation(`${area} ${sigungu}`); + navigate( + `/home/search?keyword=${keyword}&category=${category}&map=${moveMap}&location=${area} ${sigungu}&sort=${sort}`, + ); handleClick(); } diff --git a/src/components/SearchFromHome/SearchList/SearchList.tsx b/src/components/SearchFromHome/SearchList/SearchList.tsx index 843985a2..f553de47 100644 --- a/src/components/SearchFromHome/SearchList/SearchList.tsx +++ b/src/components/SearchFromHome/SearchList/SearchList.tsx @@ -15,25 +15,34 @@ import Tabs from './Tabs/Tabs'; import {SearchItemType} from '@/types/home'; interface PropsType { - keyword: string | undefined; + keyword: string; category: string; moveMap: string; - set: React.Dispatch>; + searchLocation: string; + sort: string; + setMoveMap: React.Dispatch>; setCategory: React.Dispatch>; + setSearchLocation: React.Dispatch>; + setSort: React.Dispatch>; } -function SearchList({keyword, set, moveMap, category, setCategory}: PropsType) { +function SearchList({ + keyword, + moveMap, + category, + searchLocation, + sort, + setMoveMap, + setCategory, + setSearchLocation, + setSort, +}: PropsType) { const [data, setData] = useState(); const [filterData, setFilterData] = useState(); const [categoryChange, setCategoryChange] = useState(false); - const [searchLocation, setSearchLocation] = useState('전국'); const navigate = useNavigate(); const [searchParams] = useSearchParams(); - useEffect(() => { - console.log(searchLocation); - }, [searchLocation]); - useEffect(() => { getData('home/search/search', setData); @@ -60,23 +69,34 @@ function SearchList({keyword, set, moveMap, category, setCategory}: PropsType) { }, [data, category]); function onMap() { - set('true'); - if (category) { - navigate(`/home/search?keyword=${keyword}&category${category}&map=true`); - } else { - navigate(`/home/search?keyword=${keyword}&map=true`); - } + setMoveMap('true'); + navigate(`/home/search?keyword=${keyword}&category=${category}&map=true&location=${searchLocation}&sort=${sort}`); } return (
- + {moveMap === 'true' && filterData ? ( ) : ( <>
- +
    diff --git a/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx b/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx index 931c4400..669b58e3 100644 --- a/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx +++ b/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx @@ -1,13 +1,16 @@ -import { useNavigate, useSearchParams } from "react-router-dom"; +import {useNavigate} from 'react-router-dom'; -import styles from "./Tab.module.scss"; +import styles from './Tab.module.scss'; interface PropsType { setCategory: React.Dispatch>; setCategoryChange: React.Dispatch>; category: string; thisCategory: string; - keyword: string | undefined; + keyword: string; + moveMap: string; + searchLocation: string; + sort: string; } function Tab({ @@ -16,8 +19,10 @@ function Tab({ category, thisCategory, keyword, + moveMap, + sort, + searchLocation, }: PropsType) { - const [searchParams] = useSearchParams(); const navigate = useNavigate(); function handleCategory(key: string) { @@ -26,11 +31,7 @@ function Tab({ setCategoryChange(false); }, 150); setCategory(key); - if (searchParams.get("map")) { - navigate(`/home/search?keyword=${keyword}&category=${key}&map=true`); - } else { - navigate(`/home/search?keyword=${keyword}&category=${key}`); - } + navigate(`/home/search?keyword=${keyword}&category=${key}&map=${moveMap}&location=${searchLocation}&sort=${sort}`); } return ( @@ -38,8 +39,8 @@ function Tab({ className={styles.container} id={thisCategory} style={{ - color: category === thisCategory ? "#1d2433" : "#cdcfd0", - borderBottom: category === thisCategory ? "2px solid #1d2433" : "none", + color: category === thisCategory ? '#1d2433' : '#cdcfd0', + borderBottom: category === thisCategory ? '2px solid #1d2433' : 'none', }} onClick={() => { handleCategory(thisCategory); diff --git a/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx b/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx index b2c3f058..8340dd76 100644 --- a/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx +++ b/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx @@ -1,37 +1,28 @@ -import { useState } from "react"; +import {useState} from 'react'; -import styles from "./Tabs.module.scss"; +import styles from './Tabs.module.scss'; -import useComponentSize from "@/hooks/useComponetSize"; +import useComponentSize from '@/hooks/useComponetSize'; -import SlideButton from "@/components/SlideButton/SlideButton"; +import SlideButton from '@/components/SlideButton/SlideButton'; -import Tab from "./Tab/Tab"; +import Tab from './Tab/Tab'; interface PropsType { + keyword: string; + category: string; + moveMap: string; + searchLocation: string; + sort: string; + setCategory: React.Dispatch>; setCategoryChange: React.Dispatch>; - category: string; - keyword: string | undefined; } -function Tabs({ - setCategory, - setCategoryChange, - category, - keyword, -}: PropsType) { +function Tabs({setCategory, setCategoryChange, category, keyword, moveMap, searchLocation, sort}: PropsType) { const [slideLocation, setSlideLocation] = useState(0); const [componentRef, size] = useComponentSize(); - const thisCategory = [ - "전체", - "맛집", - "숙소", - "관광지", - "문화시설", - "레포츠", - "쇼핑", - ]; + const thisCategory = ['전체', '맛집', '숙소', '관광지', '문화시설', '레포츠', '쇼핑']; return (
    @@ -48,8 +39,8 @@ function Tabs({ className={styles.tabs} ref={componentRef} style={{ - overflow: size.width < 449 ? "scroll" : "visible", - left: slideLocation + "px", + overflow: size.width < 449 ? 'scroll' : 'visible', + left: slideLocation + 'px', }} > {thisCategory.map((thisCategory) => ( @@ -60,6 +51,9 @@ function Tabs({ thisCategory={thisCategory} key={thisCategory} keyword={keyword} + moveMap={moveMap} + searchLocation={searchLocation} + sort={sort} /> ))}
    diff --git a/src/pages/SearchFromHome/SearchFromHome.tsx b/src/pages/SearchFromHome/SearchFromHome.tsx index cc352fcb..ff0cd792 100644 --- a/src/pages/SearchFromHome/SearchFromHome.tsx +++ b/src/pages/SearchFromHome/SearchFromHome.tsx @@ -1,26 +1,31 @@ -import { useEffect, useState } from "react"; -import { useSearchParams } from "react-router-dom"; +import {useEffect, useState} from 'react'; +import {useSearchParams} from 'react-router-dom'; -import styles from "./SearchFromHome.module.scss"; +import styles from './SearchFromHome.module.scss'; -import MapHeader from "@/components/SearchFromHome/MapHeader/MapHeader"; -import SearchBar from "@/components/SearchFromHome/SearchBar/SearchBar"; -import SearchHome from "@/components/SearchFromHome/SearchHome/SearchHome"; -import SearchList from "@/components/SearchFromHome/SearchList/SearchList"; +import MapHeader from '@/components/SearchFromHome/MapHeader/MapHeader'; +import SearchBar from '@/components/SearchFromHome/SearchBar/SearchBar'; +import SearchHome from '@/components/SearchFromHome/SearchHome/SearchHome'; +import SearchList from '@/components/SearchFromHome/SearchList/SearchList'; function SearchFromHome() { - const [keyword, setKeyword] = useState(); - const [category, setCategory] = useState("전체"); - const [moveMap, setMoveMap] = useState("false"); + const [keyword, setKeyword] = useState(''); + const [category, setCategory] = useState('전체'); + const [moveMap, setMoveMap] = useState('false'); + const [searchLocation, setSearchLocation] = useState('전국'); + const [sort, setSort] = useState('등록순'); const [searchParams] = useSearchParams(); const vh = window.innerHeight; useEffect(() => { const querystring = { - keyword: searchParams.get("keyword"), - category: searchParams.get("category"), - map: searchParams.get("map"), + keyword: searchParams.get('keyword'), + category: searchParams.get('category'), + map: searchParams.get('map'), + location: searchParams.get('location'), + sort: searchParams.get('sort'), }; + if (querystring.keyword) { setKeyword(querystring.keyword); } @@ -30,6 +35,12 @@ function SearchFromHome() { if (querystring.map) { setMoveMap(querystring.map); } + if (querystring.location) { + setSearchLocation(querystring.location); + } + if (querystring.sort) { + setSort(querystring.sort); + } }, [searchParams]); return ( @@ -37,24 +48,40 @@ function SearchFromHome() { className={styles.container} style={{ height: `${vh}px`, - gap: moveMap === "true" ? "0" : "24px", - paddingTop: moveMap === "true" ? "0" : "16px", + gap: moveMap === 'true' ? '0' : '24px', + paddingTop: moveMap === 'true' ? '0' : '16px', }} > - {moveMap === "true" ? ( - + {moveMap === 'true' ? ( + ) : ( - + )} - {!keyword ? ( + {keyword === '' ? ( ) : ( )}
From 290f411c160283e6371b869a7fc9e6acef703334 Mon Sep 17 00:00:00 2001 From: Yamyam-code Date: Sat, 20 Jan 2024 18:10:25 +0900 Subject: [PATCH 3/6] Feat: translate query data --- .../RecommendedItem/RecommendedItem.tsx | 23 ++++------ .../RecommendedItemList.tsx | 3 -- .../SearchKeyword/SearchKeyword.tsx | 2 +- src/hooks/Search/useSearch.ts | 43 +++++++++++++++++++ src/pages/SearchFromHome/SearchFromHome.tsx | 11 +++++ src/utils/areas.json | 37 ++++++++-------- 6 files changed, 82 insertions(+), 37 deletions(-) create mode 100644 src/hooks/Search/useSearch.ts diff --git a/src/components/Home/RecommendedItemList/RecommendedItem/RecommendedItem.tsx b/src/components/Home/RecommendedItemList/RecommendedItem/RecommendedItem.tsx index 08f7ce95..c5830c0a 100644 --- a/src/components/Home/RecommendedItemList/RecommendedItem/RecommendedItem.tsx +++ b/src/components/Home/RecommendedItemList/RecommendedItem/RecommendedItem.tsx @@ -1,28 +1,21 @@ -import { FaStar } from "react-icons/fa"; -import { Link } from "react-router-dom"; +import {FaStar} from 'react-icons/fa'; +import {Link} from 'react-router-dom'; -import styles from "./RecommendedItem.module.scss"; +import styles from './RecommendedItem.module.scss'; -import areas from "@/utils/areas.json"; +import areas from '@/utils/areas.json'; -import { RecommendedItemDataType } from "@/types/home"; +import {RecommendedItemDataType} from '@/types/home'; interface PropsType { data: RecommendedItemDataType; } -function RecommendedItem({ data }: PropsType) { - const location = areas.filter((area) => area.areaCode === data.areaCode)[0] - .name; - console.log(data.thumbnail); - +function RecommendedItem({data}: PropsType) { + const location = areas.filter((area) => area.areaCode === data.areaCode)[0].name; return ( - {`${data.title}의 + {`${data.title}의
{data.title} {location} diff --git a/src/components/Home/RecommendedItemList/RecommendedItemList.tsx b/src/components/Home/RecommendedItemList/RecommendedItemList.tsx index 83e54a82..bf4d6690 100644 --- a/src/components/Home/RecommendedItemList/RecommendedItemList.tsx +++ b/src/components/Home/RecommendedItemList/RecommendedItemList.tsx @@ -8,14 +8,11 @@ import SlideButton from '@/components/SlideButton/SlideButton'; import RecommendedItem from './RecommendedItem/RecommendedItem'; -import {RecommendedItemDataType} from '@/types/home'; - interface PropsType { apiNum: number; } function RecommendedItemList({apiNum}: PropsType) { - const [data, setData] = useState(); const [slideLocation, setSlideLocation] = useState(0); const [componentRef, size] = useComponentSize(); diff --git a/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx b/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx index ba80a087..e836eaef 100644 --- a/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx +++ b/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx @@ -71,7 +71,7 @@ function SearchKeyword({set}: PropsType) { key={keyword + i} onClick={() => { searchKeyword(keyword); - navigate(`/home/search?keyword=${keyword}&category=전체`); + navigate(`/home/search?keyword=${keyword}&category=전체&map=false&location=전국&sort=등록순`); }} > {keyword} diff --git a/src/hooks/Search/useSearch.ts b/src/hooks/Search/useSearch.ts new file mode 100644 index 00000000..ff3521a9 --- /dev/null +++ b/src/hooks/Search/useSearch.ts @@ -0,0 +1,43 @@ +import areaData from '@/utils/areas.json'; + +function translateLocation(location: string) { + const searchLocation = location.split(' '); + let areaCode = 0; + let sigunguCode = 0; + if (searchLocation[0] === '전국') { + return {areaCode, sigunguCode}; + } + const area = areaData.filter((area) => area.name === searchLocation[0])[0]; + areaCode = area.areaCode; + sigunguCode = area.districts.filter((sigungu) => sigungu.name === searchLocation[1])[0].sigunguCode; + return {areaCode, sigunguCode}; +} + +function translateSort(sort: string) { + let sortCode; + switch (sort) { + case '등록순': + sortCode = 'R'; + break; + case '인기순': + sortCode = 'Q'; + break; + case '이름순': + sortCode = 'O'; + break; + + default: + sortCode = 'R'; + } + return sortCode; +} + +export function search(keyword: string, location: string, sort: string) { + const inputData = { + keyword: keyword, + location: translateLocation(location), + sort: translateSort(sort), + }; + + return inputData; +} diff --git a/src/pages/SearchFromHome/SearchFromHome.tsx b/src/pages/SearchFromHome/SearchFromHome.tsx index ff0cd792..adcbc086 100644 --- a/src/pages/SearchFromHome/SearchFromHome.tsx +++ b/src/pages/SearchFromHome/SearchFromHome.tsx @@ -3,6 +3,8 @@ import {useSearchParams} from 'react-router-dom'; import styles from './SearchFromHome.module.scss'; +import {search} from '@/hooks/Search/useSearch'; + import MapHeader from '@/components/SearchFromHome/MapHeader/MapHeader'; import SearchBar from '@/components/SearchFromHome/SearchBar/SearchBar'; import SearchHome from '@/components/SearchFromHome/SearchHome/SearchHome'; @@ -26,7 +28,12 @@ function SearchFromHome() { sort: searchParams.get('sort'), }; + let queryKeyword = ''; + let queryLocation = '전국'; + let querySort = '등록순'; + if (querystring.keyword) { + queryKeyword = querystring.keyword; setKeyword(querystring.keyword); } if (querystring.category) { @@ -36,11 +43,15 @@ function SearchFromHome() { setMoveMap(querystring.map); } if (querystring.location) { + queryLocation = querystring.location; setSearchLocation(querystring.location); } if (querystring.sort) { + querySort = querystring.sort; setSort(querystring.sort); } + + console.log(search(queryKeyword, queryLocation, querySort)); }, [searchParams]); return ( diff --git a/src/utils/areas.json b/src/utils/areas.json index f1ba607a..2b0b61f0 100644 --- a/src/utils/areas.json +++ b/src/utils/areas.json @@ -1,13 +1,14 @@ [ { "name": "전국", - "districts": [{ "name": "전체 지역", "sigunguCode": 1253153514 }] + "areaCode": 0, + "districts": [{"name": "전체 지역", "sigunguCode": 0}] }, { "name": "서울", "areaCode": 1, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "강남구", "sigunguCode": 1 @@ -114,7 +115,7 @@ "name": "인천", "areaCode": 2, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "강화군", "sigunguCode": 1 @@ -161,7 +162,7 @@ "name": "대전", "areaCode": 3, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "대덕구", "sigunguCode": 1 @@ -188,7 +189,7 @@ "name": "대구", "areaCode": 4, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "남구", "sigunguCode": 1 @@ -231,7 +232,7 @@ "name": "광주", "areaCode": 5, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "광산구", "sigunguCode": 1 @@ -258,7 +259,7 @@ "name": "부산", "areaCode": 6, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "강서구", "sigunguCode": 1 @@ -329,7 +330,7 @@ "name": "울산", "areaCode": 7, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "중구", "sigunguCode": 1 @@ -356,7 +357,7 @@ "name": "세종", "areaCode": 8, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "세종특별자치시", "sigunguCode": 1 @@ -367,7 +368,7 @@ "name": "경기", "areaCode": 31, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "가평군", "sigunguCode": 1 @@ -498,7 +499,7 @@ "name": "강원", "areaCode": 32, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "강릉시", "sigunguCode": 1 @@ -577,7 +578,7 @@ "name": "충북", "areaCode": 33, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "괴산군", "sigunguCode": 1 @@ -632,7 +633,7 @@ "name": "충남", "areaCode": 34, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "공주시", "sigunguCode": 1 @@ -699,7 +700,7 @@ "name": "경북", "areaCode": 35, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "경산시", "sigunguCode": 1 @@ -794,7 +795,7 @@ "name": "경남", "areaCode": 36, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "거제시", "sigunguCode": 1 @@ -881,7 +882,7 @@ "name": "전북", "areaCode": 37, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "고창군", "sigunguCode": 1 @@ -944,7 +945,7 @@ "name": "전남", "areaCode": 38, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "고흥군", "sigunguCode": 1 @@ -1039,7 +1040,7 @@ "name": "제주", "areaCode": 39, "districts": [ - { "name": "전체", "sigunguCode": 54314583 }, + {"name": "전체", "sigunguCode": 0}, { "name": "남제주군", "sigunguCode": 1 From 2cb0b1a8a9d92fc7986ac135dc3c2adfb150b7f2 Mon Sep 17 00:00:00 2001 From: Yamyam-code Date: Sun, 21 Jan 2024 21:51:25 +0900 Subject: [PATCH 4/6] Refactor: change search state --- .../SearchFromHome/MapHeader/MapHeader.tsx | 21 +++-- .../SearchFromHome/SearchBar/SearchBar.tsx | 29 +++---- .../SearchFromHome/SearchHome/SearchHome.tsx | 9 +- .../SearchKeyword/SearchKeyword.tsx | 11 ++- .../LocationFilter/LocationFilter.tsx | 26 ++---- .../LocationFliterPage/LocationFliterPage.tsx | 17 ++-- .../SearchFromHome/SearchList/SearchList.tsx | 70 +++++----------- .../SearchList/Tabs/Tab/Tab.tsx | 35 ++++---- .../SearchFromHome/SearchList/Tabs/Tabs.tsx | 21 ++--- src/pages/SearchFromHome/SearchFromHome.tsx | 82 ++++++------------- src/types/home.ts | 8 ++ 11 files changed, 133 insertions(+), 196 deletions(-) diff --git a/src/components/SearchFromHome/MapHeader/MapHeader.tsx b/src/components/SearchFromHome/MapHeader/MapHeader.tsx index 5bf2c899..6d859ab3 100644 --- a/src/components/SearchFromHome/MapHeader/MapHeader.tsx +++ b/src/components/SearchFromHome/MapHeader/MapHeader.tsx @@ -4,20 +4,23 @@ import styles from './MapHeader.module.scss'; import BackIcon from '@/assets/homeIcons/search/backInHome.svg?react'; +import {ForSearchType} from '@/types/home'; + interface PropsType { - keyword: string; - category: string; - searchLocation: string; - sort: string; - setMoveMap: React.Dispatch>; + forSearch: ForSearchType; + setForSearch: React.Dispatch>; } -function MapHeader({keyword, setMoveMap, category, searchLocation, sort}: PropsType) { +function MapHeader({forSearch, setForSearch}: PropsType) { const navigate = useNavigate(); function offMap() { - setMoveMap('false'); - navigate(`/home/search?keyword=${keyword}&category=${category}&map=false&location=${searchLocation}&sort=${sort}`); + const before = forSearch; + before.map = 'false'; + setForSearch(before); + navigate( + `/home/search?keyword=${forSearch.keyword}&category=${forSearch.category}&map=false&location=${forSearch.location}&sort=${forSearch.sort}`, + ); } return ( @@ -25,7 +28,7 @@ function MapHeader({keyword, setMoveMap, category, searchLocation, sort}: PropsT - {keyword} + {forSearch.keyword}
); } diff --git a/src/components/SearchFromHome/SearchBar/SearchBar.tsx b/src/components/SearchFromHome/SearchBar/SearchBar.tsx index 895e5062..a1b84ac8 100644 --- a/src/components/SearchFromHome/SearchBar/SearchBar.tsx +++ b/src/components/SearchFromHome/SearchBar/SearchBar.tsx @@ -6,48 +6,49 @@ import styles from './SearchBar.module.scss'; import BackIcon from '@/assets/homeIcons/search/backInHome.svg?react'; import SearchIcon from '@/assets/homeIcons/search/searchIcon.svg?react'; +import {ForSearchType} from '@/types/home'; + interface PropsType { - keyword: string; - category: string; - searchLocation: string; - sort: string; - setKeyword: React.Dispatch>; + forSearch: ForSearchType; + setForSearch: React.Dispatch>; } interface InputBarType extends HTMLInputElement { focus: () => void; } -function SearchBar({setKeyword, keyword, category, searchLocation, sort}: PropsType) { +function SearchBar({forSearch, setForSearch}: PropsType) { const [inputValue, setInputValue] = useState(''); const navigate = useNavigate(); const inputBar = useRef(null); useEffect(() => { - setInputValue(keyword); + setInputValue(forSearch.keyword); if (inputBar.current) { inputBar.current.focus(); } - }, [keyword]); + }, [forSearch.keyword]); function handleInputValue(e: React.ChangeEvent) { setInputValue(e.target.value); } function search() { - setKeyword(inputValue); - navigate( - `/home/search?keyword=${inputValue}&category=${category}&map=false&location=${searchLocation}&sort=${sort}`, - ); + const beforeData = forSearch; + beforeData.keyword = inputValue; + setForSearch(beforeData); + navigate(`/home/search?keyword=${inputValue}&category=전체&map=false&location=전국&sort=등록순`); } function removeValue() { - if (keyword === '') { + if (forSearch.keyword === '') { navigate('/'); } else { navigate('/home/search'); setInputValue(''); - setKeyword(''); + const beforeData = forSearch; + beforeData.keyword = ''; + setForSearch(beforeData); } } diff --git a/src/components/SearchFromHome/SearchHome/SearchHome.tsx b/src/components/SearchFromHome/SearchHome/SearchHome.tsx index 45330897..a8c5d1b8 100644 --- a/src/components/SearchFromHome/SearchHome/SearchHome.tsx +++ b/src/components/SearchFromHome/SearchHome/SearchHome.tsx @@ -3,16 +3,19 @@ import styles from './SearchHome.module.scss'; import HotItems from './HotItems/HotItems'; import SearchKeyword from './SearchKeyword/SearchKeyword'; +import {ForSearchType} from '@/types/home'; + interface PropsType { - set: React.Dispatch>; + forSearch: ForSearchType; + setForSearch: React.Dispatch>; } -function SearchHome({set}: PropsType) { +function SearchHome({forSearch, setForSearch}: PropsType) { return (

인기 검색 키워드

- +

최근 30일간 인기 장소

diff --git a/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx b/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx index e836eaef..52f822e0 100644 --- a/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx +++ b/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx @@ -9,11 +9,14 @@ import SlideButton from '@/components/SlideButton/SlideButton'; import {getData} from '@/mocks/handlers/home'; +import {ForSearchType} from '@/types/home'; + interface PropsType { - set: React.Dispatch>; + forSearch: ForSearchType; + setForSearch: React.Dispatch>; } -function SearchKeyword({set}: PropsType) { +function SearchKeyword({forSearch, setForSearch}: PropsType) { const [data, setData] = useState(); const [listWidth, setListWidth] = useState(0); const [slideLocation, setSlideLocation] = useState(0); @@ -41,7 +44,9 @@ function SearchKeyword({set}: PropsType) { }, [data, componentRef]); function searchKeyword(keyword: string) { - set(keyword); + const beforeData = forSearch; + beforeData.keyword = keyword; + setForSearch(beforeData); } return ( diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx index 9e4cfcfa..7a8565dd 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx @@ -5,16 +5,14 @@ import styles from './LocationFilter.module.scss'; import LocationFliterPage from './LocationFliterPage/LocationFliterPage'; +import {ForSearchType} from '@/types/home'; + interface PropsType { - keyword: string; - category: string; - moveMap: string; - searchLocation: string; - sort: string; - setSearchLocation: React.Dispatch>; + forSearch: ForSearchType; + setForSearch: React.Dispatch>; } -function LocationFilter({keyword, category, moveMap, searchLocation, sort, setSearchLocation}: PropsType) { +function LocationFilter({forSearch, setForSearch}: PropsType) { const [click, setClick] = useState(true); const [buttonName, setButtonName] = useState('전체 지역'); @@ -23,13 +21,13 @@ function LocationFilter({keyword, category, moveMap, searchLocation, sort, setSe } useEffect(() => { - const datas = searchLocation.split(' '); + const datas = forSearch.location.split(' '); if (datas[0] === '전국') { setButtonName('전체 지역'); } else { setButtonName(datas[0]); } - }, [searchLocation]); + }, [forSearch.location]); return ( <> @@ -45,15 +43,7 @@ function LocationFilter({keyword, category, moveMap, searchLocation, sort, setSe {buttonName}
- + ); } diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx index 37660d7f..b69b440c 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx @@ -8,14 +8,13 @@ import BackIcon from '@/assets/homeIcons/search/backInHome.svg?react'; import PopularList from './PopularList/PopularList'; import SelectLocation from './SelectLocation/SelectLocation'; +import {ForSearchType} from '@/types/home'; + interface PropsType { click: boolean; - keyword: string; - category: string; - moveMap: string; - sort: string; + forSearch: ForSearchType; + setForSearch: React.Dispatch>; handleClick: () => void; - setSearchLocation: React.Dispatch>; } interface AreaDataType { @@ -23,7 +22,7 @@ interface AreaDataType { sigunguCode: number; } -function LocationFliterPage({click, keyword, category, moveMap, sort, handleClick, setSearchLocation}: PropsType) { +function LocationFliterPage({forSearch, click, handleClick, setForSearch}: PropsType) { const [area, setArea] = useState('전국'); const [areaData, setAreaData] = useState(); const [sigungu, setSigungu] = useState('전체 지역'); @@ -33,9 +32,11 @@ function LocationFliterPage({click, keyword, category, moveMap, sort, handleClic const vh = window.innerHeight / 100; function submit() { - setSearchLocation(`${area} ${sigungu}`); + const beforeData = forSearch; + beforeData.location = `${area} ${sigungu}`; + setForSearch(beforeData); navigate( - `/home/search?keyword=${keyword}&category=${category}&map=${moveMap}&location=${area} ${sigungu}&sort=${sort}`, + `/home/search?keyword=${forSearch.keyword}&category=${forSearch.category}&map=${forSearch.map}&location=${area} ${sigungu}&sort=${forSearch.sort}`, ); handleClick(); } diff --git a/src/components/SearchFromHome/SearchList/SearchList.tsx b/src/components/SearchFromHome/SearchList/SearchList.tsx index f553de47..ec95735e 100644 --- a/src/components/SearchFromHome/SearchList/SearchList.tsx +++ b/src/components/SearchFromHome/SearchList/SearchList.tsx @@ -12,31 +12,14 @@ import MapButton from './MapButton/MapButton'; import SearchItem from './SearchItem/SearchItem'; import Tabs from './Tabs/Tabs'; -import {SearchItemType} from '@/types/home'; +import {ForSearchType, SearchItemType} from '@/types/home'; interface PropsType { - keyword: string; - category: string; - moveMap: string; - searchLocation: string; - sort: string; - setMoveMap: React.Dispatch>; - setCategory: React.Dispatch>; - setSearchLocation: React.Dispatch>; - setSort: React.Dispatch>; + forSearch: ForSearchType; + setForSearch: React.Dispatch>; } -function SearchList({ - keyword, - moveMap, - category, - searchLocation, - sort, - setMoveMap, - setCategory, - setSearchLocation, - setSort, -}: PropsType) { +function SearchList({forSearch, setForSearch}: PropsType) { const [data, setData] = useState(); const [filterData, setFilterData] = useState(); const [categoryChange, setCategoryChange] = useState(false); @@ -47,56 +30,47 @@ function SearchList({ getData('home/search/search', setData); const querystring = searchParams.get('category'); + const beforeData = forSearch; if (querystring) { - setCategory(querystring); + beforeData.category = querystring; + setForSearch(beforeData); } - }, [keyword, searchParams]); + }, [searchParams]); useEffect(() => { if (data) { - if (category !== '전체') { + if (forSearch.category !== '전체') { let filterData; - if (category === '맛집') { + if (forSearch.category === '맛집') { filterData = data.filter((data) => data.category === '음식점' || data.category === '카페'); } else { - filterData = data.filter((data) => data.category === category); + filterData = data.filter((data) => data.category === forSearch.category); } setFilterData(filterData); } else { setFilterData(data); } } - }, [data, category]); + }, [data, forSearch.category]); function onMap() { - setMoveMap('true'); - navigate(`/home/search?keyword=${keyword}&category=${category}&map=true&location=${searchLocation}&sort=${sort}`); + const beforeData = forSearch; + beforeData.map = 'true'; + setForSearch(beforeData); + navigate( + `/home/search?keyword=${forSearch.keyword}&category=${forSearch.category}&map=true&location=${forSearch.location}&sort=${forSearch.sort}`, + ); } return ( -
- - {moveMap === 'true' && filterData ? ( +
+ + {forSearch.map === 'true' && filterData ? ( ) : ( <>
- +
    diff --git a/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx b/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx index 669b58e3..78bc479a 100644 --- a/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx +++ b/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx @@ -2,27 +2,16 @@ import {useNavigate} from 'react-router-dom'; import styles from './Tab.module.scss'; +import {ForSearchType} from '@/types/home'; + interface PropsType { - setCategory: React.Dispatch>; - setCategoryChange: React.Dispatch>; - category: string; + forSearch: ForSearchType; thisCategory: string; - keyword: string; - moveMap: string; - searchLocation: string; - sort: string; + setCategoryChange: React.Dispatch>; + setForSearch: React.Dispatch>; } -function Tab({ - setCategory, - setCategoryChange, - category, - thisCategory, - keyword, - moveMap, - sort, - searchLocation, -}: PropsType) { +function Tab({forSearch, thisCategory, setForSearch, setCategoryChange}: PropsType) { const navigate = useNavigate(); function handleCategory(key: string) { @@ -30,8 +19,12 @@ function Tab({ setTimeout(() => { setCategoryChange(false); }, 150); - setCategory(key); - navigate(`/home/search?keyword=${keyword}&category=${key}&map=${moveMap}&location=${searchLocation}&sort=${sort}`); + const beforeData = forSearch; + beforeData.category = key; + setForSearch(beforeData); + navigate( + `/home/search?keyword=${forSearch.keyword}&category=${key}&map=${forSearch.map}&location=${forSearch.location}&sort=${forSearch.sort}`, + ); } return ( @@ -39,8 +32,8 @@ function Tab({ className={styles.container} id={thisCategory} style={{ - color: category === thisCategory ? '#1d2433' : '#cdcfd0', - borderBottom: category === thisCategory ? '2px solid #1d2433' : 'none', + color: forSearch.category === thisCategory ? '#1d2433' : '#cdcfd0', + borderBottom: forSearch.category === thisCategory ? '2px solid #1d2433' : 'none', }} onClick={() => { handleCategory(thisCategory); diff --git a/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx b/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx index 8340dd76..40a5bf70 100644 --- a/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx +++ b/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx @@ -8,18 +8,15 @@ import SlideButton from '@/components/SlideButton/SlideButton'; import Tab from './Tab/Tab'; -interface PropsType { - keyword: string; - category: string; - moveMap: string; - searchLocation: string; - sort: string; +import {ForSearchType} from '@/types/home'; - setCategory: React.Dispatch>; +interface PropsType { + forSearch: ForSearchType; + setForSearch: React.Dispatch>; setCategoryChange: React.Dispatch>; } -function Tabs({setCategory, setCategoryChange, category, keyword, moveMap, searchLocation, sort}: PropsType) { +function Tabs({forSearch, setForSearch, setCategoryChange}: PropsType) { const [slideLocation, setSlideLocation] = useState(0); const [componentRef, size] = useComponentSize(); const thisCategory = ['전체', '맛집', '숙소', '관광지', '문화시설', '레포츠', '쇼핑']; @@ -45,15 +42,11 @@ function Tabs({setCategory, setCategoryChange, category, keyword, moveMap, searc > {thisCategory.map((thisCategory) => ( ))}
diff --git a/src/pages/SearchFromHome/SearchFromHome.tsx b/src/pages/SearchFromHome/SearchFromHome.tsx index adcbc086..ceef949b 100644 --- a/src/pages/SearchFromHome/SearchFromHome.tsx +++ b/src/pages/SearchFromHome/SearchFromHome.tsx @@ -11,11 +11,13 @@ import SearchHome from '@/components/SearchFromHome/SearchHome/SearchHome'; import SearchList from '@/components/SearchFromHome/SearchList/SearchList'; function SearchFromHome() { - const [keyword, setKeyword] = useState(''); - const [category, setCategory] = useState('전체'); - const [moveMap, setMoveMap] = useState('false'); - const [searchLocation, setSearchLocation] = useState('전국'); - const [sort, setSort] = useState('등록순'); + const [forSearch, setForSearch] = useState({ + keyword: '', + category: '전체', + map: 'false', + location: '전국', + sort: '등록순', + }); const [searchParams] = useSearchParams(); const vh = window.innerHeight; @@ -28,30 +30,16 @@ function SearchFromHome() { sort: searchParams.get('sort'), }; - let queryKeyword = ''; - let queryLocation = '전국'; - let querySort = '등록순'; - - if (querystring.keyword) { - queryKeyword = querystring.keyword; - setKeyword(querystring.keyword); - } - if (querystring.category) { - setCategory(querystring.category); - } - if (querystring.map) { - setMoveMap(querystring.map); + if (querystring.keyword && querystring.category && querystring.location && querystring.map && querystring.sort) { + setForSearch({ + keyword: querystring.keyword, + category: querystring.category, + map: querystring.map, + location: querystring.location, + sort: querystring.sort, + }); + console.log(search(querystring.keyword, querystring.location, querystring.sort)); } - if (querystring.location) { - queryLocation = querystring.location; - setSearchLocation(querystring.location); - } - if (querystring.sort) { - querySort = querystring.sort; - setSort(querystring.sort); - } - - console.log(search(queryKeyword, queryLocation, querySort)); }, [searchParams]); return ( @@ -59,41 +47,19 @@ function SearchFromHome() { className={styles.container} style={{ height: `${vh}px`, - gap: moveMap === 'true' ? '0' : '24px', - paddingTop: moveMap === 'true' ? '0' : '16px', + gap: forSearch.map === 'true' ? '0' : '24px', + paddingTop: forSearch.map === 'true' ? '0' : '16px', }} > - {moveMap === 'true' ? ( - + {forSearch.map === 'true' ? ( + ) : ( - + )} - {keyword === '' ? ( - + {forSearch.keyword === '' ? ( + ) : ( - + )}
); diff --git a/src/types/home.ts b/src/types/home.ts index 0e14100c..8126bba2 100644 --- a/src/types/home.ts +++ b/src/types/home.ts @@ -79,3 +79,11 @@ export interface SearchItemType { location: SearchItemLocationType; category: string; } + +export interface ForSearchType { + keyword: string; + category: string; + map: string; + location: string; + sort: string; +} From 29245577aea2f78c7254ea5999252f80c04eac16 Mon Sep 17 00:00:00 2001 From: Yamyam-code Date: Mon, 22 Jan 2024 04:48:34 +0900 Subject: [PATCH 5/6] Feat: search connect api --- src/api/search.ts | 27 + .../RecommendedLocation.tsx | 43 +- .../RecommendedLocationList.tsx | 32 +- .../Home/TripSpaceAtHome/TripSpaceAtHome.tsx | 30 +- src/components/Home/VoteAtHome/VoteAtHome.tsx | 14 +- .../SearchFromHome/SearchBar/SearchBar.tsx | 2 +- .../SearchHome/HotItems/HotItems.tsx | 42 +- .../SearchFromHome/SearchHome/SearchHome.tsx | 15 +- .../SearchKeyword/SearchKeyword.tsx | 30 +- .../LocationFilter/LocationFilter.tsx | 5 +- .../LocationFliterPage/LocationFliterPage.tsx | 23 +- .../SearchFromHome/SearchList/Map/Map.tsx | 79 +-- .../SearchFromHome/SearchList/SearchList.tsx | 28 +- .../SearchList/Tabs/Tab/Tab.tsx | 16 +- .../SearchFromHome/SearchList/Tabs/Tabs.tsx | 4 +- src/hooks/Search/useSearch.ts | 78 ++- src/mocks/handlers/home.ts | 163 +---- src/pages/SearchFromHome/SearchFromHome.tsx | 9 +- src/types/home.ts | 2 +- src/utils/categories.json | 610 ++++++++++++++++++ src/utils/contentType.json | 30 + 21 files changed, 959 insertions(+), 323 deletions(-) create mode 100644 src/api/search.ts create mode 100644 src/utils/categories.json create mode 100644 src/utils/contentType.json diff --git a/src/api/search.ts b/src/api/search.ts new file mode 100644 index 00000000..5df432bc --- /dev/null +++ b/src/api/search.ts @@ -0,0 +1,27 @@ +import axios from 'axios'; + +import {SearchItemType} from '@/types/home'; + +export async function getSearchData( + page: number, + areaCode: number, + sigunguCode: number, + placeTypeId: number, + keyword: string, + sort: string, + categoryCode: string, +) { + const searchData: SearchItemType = await axios.get('/api/places/search', { + params: { + page: page, + size: 20, + areaCode: areaCode, + sigunguCode: sigunguCode, + placeTypeId: placeTypeId, + keyword: keyword, + sort: sort, + categoryCode: categoryCode, + }, + }); + return searchData; +} diff --git a/src/components/Home/RecommendedLocationList/RecommendedLocation/RecommendedLocation.tsx b/src/components/Home/RecommendedLocationList/RecommendedLocation/RecommendedLocation.tsx index 0b3a14b6..82aa2658 100644 --- a/src/components/Home/RecommendedLocationList/RecommendedLocation/RecommendedLocation.tsx +++ b/src/components/Home/RecommendedLocationList/RecommendedLocation/RecommendedLocation.tsx @@ -1,23 +1,48 @@ -import { Link } from "react-router-dom"; +import {Link} from 'react-router-dom'; -import styles from "./RecommendedLocation.module.scss"; +import styles from './RecommendedLocation.module.scss'; -import { LocationDataType } from "@/types/home"; +import {LocationDataType} from '@/types/home'; interface PropsType { data: LocationDataType; } -function RecommendedLocation(data: PropsType) { - const link = `/home/search`; - const imageAlt = `${data.data.location}의 사진`; +function RecommendedLocation({data}: PropsType) { + let location: string; + + switch (data.location) { + case '제주': + location = '제주 전체'; + break; + case '부산': + location = '부산 전체'; + break; + case '강릉': + location = '강원 강릉시'; + break; + case '속초': + location = '강원 속초시'; + break; + case '경주': + location = '경북 경주시'; + break; + case '여수': + location = '전남 여수시'; + break; + case '전주': + location = '전북 전주시'; + break; + default: + location = '전국'; + } return (
- - {imageAlt} + + {`${data.location}의
- {data.data.location} + {data.location}
); diff --git a/src/components/Home/RecommendedLocationList/RecommendedLocationList.tsx b/src/components/Home/RecommendedLocationList/RecommendedLocationList.tsx index bbe59669..03dfcc72 100644 --- a/src/components/Home/RecommendedLocationList/RecommendedLocationList.tsx +++ b/src/components/Home/RecommendedLocationList/RecommendedLocationList.tsx @@ -8,29 +8,45 @@ import SlideButton from '@/components/SlideButton/SlideButton'; import RecommendedLocation from './RecommendedLocation/RecommendedLocation'; -import {LocationDataType} from '@/types/home'; - function RecommendedLocationList() { - const [data, setData] = useState(); const [slideLocation, setSlideLocation] = useState(0); const [componentRef, size] = useComponentSize(); const recommendedLocation = [ { location: '제주', - imageURL: 'https://img-cf.kurly.com/shop/data/goodsview/20210218/gv30000159355_1.jpg', + imageURL: + 'https://images.unsplash.com/photo-1579169326371-ccb4e63f7889?q=80&w=1587&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', }, { location: '부산', - imageURL: 'https://img-cf.kurly.com/shop/data/goodsview/20210218/gv30000159355_1.jpg', + imageURL: + 'https://images.unsplash.com/photo-1578037571214-25e07ed4a487?q=80&w=2808&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', }, { location: '강릉', - imageURL: 'https://img-cf.kurly.com/shop/data/goodsview/20210218/gv30000159355_1.jpg', + imageURL: + 'https://images.unsplash.com/photo-1621044332832-717d5d986ab7?q=80&w=1740&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', + }, + { + location: '속초', + imageURL: + 'https://images.unsplash.com/photo-1663949405336-e142646d9fbd?q=80&w=2697&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', + }, + { + location: '경주', + imageURL: + 'https://images.unsplash.com/photo-1656980593245-b54c8c0828f0?q=80&w=1740&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', + }, + { + location: '여수', + imageURL: + 'https://images.unsplash.com/photo-1651375562199-65caae096ace?q=80&w=2670&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', }, { - location: '서울', - imageURL: 'https://img-cf.kurly.com/shop/data/goodsview/20210218/gv30000159355_1.jpg', + location: '전주', + imageURL: + 'https://images.unsplash.com/photo-1544827503-673e2a2c4c00?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8JUVDJUEwJTg0JUVDJUEzJUJDfGVufDB8fDB8fHww', }, ]; diff --git a/src/components/Home/TripSpaceAtHome/TripSpaceAtHome.tsx b/src/components/Home/TripSpaceAtHome/TripSpaceAtHome.tsx index aab13e8b..59d95c92 100644 --- a/src/components/Home/TripSpaceAtHome/TripSpaceAtHome.tsx +++ b/src/components/Home/TripSpaceAtHome/TripSpaceAtHome.tsx @@ -1,16 +1,16 @@ -import { useEffect, useState } from "react"; +import {useEffect, useState} from 'react'; -import styles from "./TripSpaceAtHome.module.scss"; +import styles from './TripSpaceAtHome.module.scss'; -import useComponentSize from "@/hooks/useComponetSize"; +import useComponentSize from '@/hooks/useComponetSize'; -import SlideButton from "@/components/SlideButton/SlideButton"; +import SlideButton from '@/components/SlideButton/SlideButton'; -import { getData } from "@/mocks/handlers/home"; +import {getData} from '@/mocks/handlers/home'; -import TripSpaceItem from "./TripSpaceItem/TripSpaceItem"; +import TripSpaceItem from './TripSpaceItem/TripSpaceItem'; -import { TripSpaceDataType } from "@/types/home"; +import {TripSpaceDataType} from '@/types/home'; function TripSpaceAtHome() { const [data, setData] = useState(); @@ -18,14 +18,14 @@ function TripSpaceAtHome() { const [componentRef, size] = useComponentSize(); const dataNull = { - tripTitle: "아직 여행 일정이 없어요", - tripDay: "새로운 여행 일정을 만들어보세요!", - tripImg: "/tripVoteLogoHome.png", + tripTitle: '아직 여행 일정이 없어요', + tripDay: '새로운 여행 일정을 만들어보세요!', + tripImg: '/tripVoteLogoHome.png', dDay: undefined, }; useEffect(() => { - getData(`home/tripSpace`, setData); + getData(`api/home/tripSpace`, setData); }, []); return ( @@ -44,14 +44,12 @@ function TripSpaceAtHome() { className={styles.slide_box} ref={componentRef} style={{ - overflow: size.width < 449 ? "scroll" : "visible", - left: slideLocation + "px", + overflow: size.width < 449 ? 'scroll' : 'visible', + left: slideLocation + 'px', }} > {data ? ( - data.map((data, i) => ( - - )) + data.map((data, i) => ) ) : ( )} diff --git a/src/components/Home/VoteAtHome/VoteAtHome.tsx b/src/components/Home/VoteAtHome/VoteAtHome.tsx index ed1613ed..a36928ad 100644 --- a/src/components/Home/VoteAtHome/VoteAtHome.tsx +++ b/src/components/Home/VoteAtHome/VoteAtHome.tsx @@ -1,19 +1,19 @@ -import { useEffect, useState } from "react"; +import {useEffect, useState} from 'react'; -import styles from "./VoteAtHome.module.scss"; +import styles from './VoteAtHome.module.scss'; -import { getData } from "@/mocks/handlers/home"; +import {getData} from '@/mocks/handlers/home'; -import CardHaveVote from "./VoteCard/CardHaveVote/CardHaveVote"; -import CardNull from "./VoteCard/CardNull/CardNull"; +import CardHaveVote from './VoteCard/CardHaveVote/CardHaveVote'; +import CardNull from './VoteCard/CardNull/CardNull'; -import { VoteDataType } from "@/types/home"; +import {VoteDataType} from '@/types/home'; function VoteAtHome() { const [data, setData] = useState(); useEffect(() => { - getData(`home/vote`, setData); + getData(`api/home/vote`, setData); }, []); return ( diff --git a/src/components/SearchFromHome/SearchBar/SearchBar.tsx b/src/components/SearchFromHome/SearchBar/SearchBar.tsx index a1b84ac8..2fd6207a 100644 --- a/src/components/SearchFromHome/SearchBar/SearchBar.tsx +++ b/src/components/SearchFromHome/SearchBar/SearchBar.tsx @@ -37,7 +37,7 @@ function SearchBar({forSearch, setForSearch}: PropsType) { const beforeData = forSearch; beforeData.keyword = inputValue; setForSearch(beforeData); - navigate(`/home/search?keyword=${inputValue}&category=전체&map=false&location=전국&sort=등록순`); + navigate(`/home/search?keyword=${inputValue}&category=0&map=false&location=${forSearch.location}&sort=등록순`); } function removeValue() { diff --git a/src/components/SearchFromHome/SearchHome/HotItems/HotItems.tsx b/src/components/SearchFromHome/SearchHome/HotItems/HotItems.tsx index d3936be4..db7421be 100644 --- a/src/components/SearchFromHome/SearchHome/HotItems/HotItems.tsx +++ b/src/components/SearchFromHome/SearchHome/HotItems/HotItems.tsx @@ -1,30 +1,41 @@ -import { useEffect, useState } from "react"; +import axios from 'axios'; +import {Dispatch, useEffect, useState} from 'react'; -import styles from "./HotItems.module.scss"; +import styles from './HotItems.module.scss'; -import useComponentSize from "@/hooks/useComponetSize"; +import useComponentSize from '@/hooks/useComponetSize'; -import SlideButton from "@/components/SlideButton/SlideButton"; +import SlideButton from '@/components/SlideButton/SlideButton'; -import { getData } from "@/mocks/handlers/home"; +import HotItem from './HotItem/HotItem'; -import HotItem from "./HotItem/HotItem"; - -import { SearchHotItemType } from "@/types/home"; +import {SearchHotItemType} from '@/types/home'; interface PropsType { - type: string; + type: number; } -function HotItems({ type }: PropsType) { +function HotItems({type}: PropsType) { const [data, setData] = useState(); const [slideLocation, setSlideLocation] = useState(0); const [componentRef, size] = useComponentSize(); useEffect(() => { - getData(`places/popular`, setData); + async function getData(apiURL: string, set: Dispatch>) { + try { + const fetchData = await axios.get(`${apiURL}`, { + params: { + size: 10, + placeTypeId: type, + }, + }); + set(fetchData.data); + } catch (error) { + console.log(error); + } + } + getData('api/places/popular', setData); }, [type]); - return (
{data && ( @@ -41,12 +52,11 @@ function HotItems({ type }: PropsType) { className={styles.slide_box} ref={componentRef} style={{ - overflow: size.width < 449 ? "scroll" : "visible", - left: slideLocation + "px", + overflow: size.width < 449 ? 'scroll' : 'visible', + left: slideLocation + 'px', }} > - {data && - data.map((data, i) => )} + {data && data.map((data, i) => )}
); diff --git a/src/components/SearchFromHome/SearchHome/SearchHome.tsx b/src/components/SearchFromHome/SearchHome/SearchHome.tsx index a8c5d1b8..0dcb6628 100644 --- a/src/components/SearchFromHome/SearchHome/SearchHome.tsx +++ b/src/components/SearchFromHome/SearchHome/SearchHome.tsx @@ -3,27 +3,24 @@ import styles from './SearchHome.module.scss'; import HotItems from './HotItems/HotItems'; import SearchKeyword from './SearchKeyword/SearchKeyword'; -import {ForSearchType} from '@/types/home'; - -interface PropsType { - forSearch: ForSearchType; - setForSearch: React.Dispatch>; +interface Propstype { + setKeywordClick: React.Dispatch>; } -function SearchHome({forSearch, setForSearch}: PropsType) { +function SearchHome({setKeywordClick}: Propstype) { return (

인기 검색 키워드

- +

최근 30일간 인기 장소

- +

최근 30일간 인기 숙소

- +
); diff --git a/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx b/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx index 52f822e0..9e28494c 100644 --- a/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx +++ b/src/components/SearchFromHome/SearchHome/SearchKeyword/SearchKeyword.tsx @@ -9,22 +9,19 @@ import SlideButton from '@/components/SlideButton/SlideButton'; import {getData} from '@/mocks/handlers/home'; -import {ForSearchType} from '@/types/home'; - -interface PropsType { - forSearch: ForSearchType; - setForSearch: React.Dispatch>; +interface Propstype { + setKeywordClick: React.Dispatch>; } -function SearchKeyword({forSearch, setForSearch}: PropsType) { - const [data, setData] = useState(); +function SearchKeyword({setKeywordClick}: Propstype) { + const [data, setData] = useState<{name: string; code: string}[] | undefined>(); const [listWidth, setListWidth] = useState(0); const [slideLocation, setSlideLocation] = useState(0); const [componentRef, size] = useComponentSize(); const navigate = useNavigate(); useEffect(() => { - getData('home/search/keyword', setData); + getData<{name: string; code: string}[] | undefined>('api/places/popular/keywords', setData); }, []); // 각 키워드의 너비를 모두 더한 값을 구함 @@ -43,12 +40,6 @@ function SearchKeyword({forSearch, setForSearch}: PropsType) { }, 100); }, [data, componentRef]); - function searchKeyword(keyword: string) { - const beforeData = forSearch; - beforeData.keyword = keyword; - setForSearch(beforeData); - } - return (
{data && ( @@ -73,13 +64,16 @@ function SearchKeyword({forSearch, setForSearch}: PropsType) { {data ? ( data.map((keyword, i) => (

{ - searchKeyword(keyword); - navigate(`/home/search?keyword=${keyword}&category=전체&map=false&location=전국&sort=등록순`); + setKeywordClick(true); + setTimeout(() => { + setKeywordClick(false); + }, 2000); + navigate(`/home/search?keyword=${keyword.name}&category=0&map=false&location=전국&sort=등록순`); }} > - {keyword} + {keyword.name}

)) ) : ( diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx index 7a8565dd..95e489ec 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFilter.tsx @@ -9,10 +9,9 @@ import {ForSearchType} from '@/types/home'; interface PropsType { forSearch: ForSearchType; - setForSearch: React.Dispatch>; } -function LocationFilter({forSearch, setForSearch}: PropsType) { +function LocationFilter({forSearch}: PropsType) { const [click, setClick] = useState(true); const [buttonName, setButtonName] = useState('전체 지역'); @@ -43,7 +42,7 @@ function LocationFilter({forSearch, setForSearch}: PropsType) { {buttonName}
- + ); } diff --git a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx index b69b440c..db343e43 100644 --- a/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx +++ b/src/components/SearchFromHome/SearchList/LocationFilter/LocationFliterPage/LocationFliterPage.tsx @@ -1,4 +1,4 @@ -import {useState} from 'react'; +import {useEffect, useState} from 'react'; import {useNavigate} from 'react-router-dom'; import styles from './LocationFliterPage.module.scss'; @@ -13,7 +13,6 @@ import {ForSearchType} from '@/types/home'; interface PropsType { click: boolean; forSearch: ForSearchType; - setForSearch: React.Dispatch>; handleClick: () => void; } @@ -22,7 +21,7 @@ interface AreaDataType { sigunguCode: number; } -function LocationFliterPage({forSearch, click, handleClick, setForSearch}: PropsType) { +function LocationFliterPage({forSearch, click, handleClick}: PropsType) { const [area, setArea] = useState('전국'); const [areaData, setAreaData] = useState(); const [sigungu, setSigungu] = useState('전체 지역'); @@ -31,10 +30,13 @@ function LocationFliterPage({forSearch, click, handleClick, setForSearch}: Props const vh = window.innerHeight / 100; + useEffect(() => { + const locationData = forSearch.location.split(' '); + setArea(locationData[0]); + setSigungu(locationData[1]); + }, [forSearch.location]); + function submit() { - const beforeData = forSearch; - beforeData.location = `${area} ${sigungu}`; - setForSearch(beforeData); navigate( `/home/search?keyword=${forSearch.keyword}&category=${forSearch.category}&map=${forSearch.map}&location=${area} ${sigungu}&sort=${forSearch.sort}`, ); @@ -52,7 +54,14 @@ function LocationFliterPage({forSearch, click, handleClick, setForSearch}: Props }} >
-
diff --git a/src/components/SearchFromHome/SearchList/Map/Map.tsx b/src/components/SearchFromHome/SearchList/Map/Map.tsx index 4d1c5ec3..10e974fd 100644 --- a/src/components/SearchFromHome/SearchList/Map/Map.tsx +++ b/src/components/SearchFromHome/SearchList/Map/Map.tsx @@ -1,26 +1,26 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { useEffect, useState } from "react"; +import {useEffect, useState} from 'react'; -import styles from "./Map.module.scss"; +import styles from './Map.module.scss'; -import flagMarker from "@/assets/homeIcons/map/flag.svg"; -import bigFlagMarker from "@/assets/homeIcons/map/flag_big.svg"; -import homeMarker from "@/assets/homeIcons/map/house.svg"; -import bigHomeMarker from "@/assets/homeIcons/map/house_big.svg"; -import forkMarker from "@/assets/homeIcons/map/restaurant.svg"; -import bigForkMarker from "@/assets/homeIcons/map/restaurant_big.svg"; +import flagMarker from '@/assets/homeIcons/map/flag.svg'; +import bigFlagMarker from '@/assets/homeIcons/map/flag_big.svg'; +import homeMarker from '@/assets/homeIcons/map/house.svg'; +import bigHomeMarker from '@/assets/homeIcons/map/house_big.svg'; +import forkMarker from '@/assets/homeIcons/map/restaurant.svg'; +import bigForkMarker from '@/assets/homeIcons/map/restaurant_big.svg'; -import MapItems from "./MapItems/MapItems"; +import MapItems from './MapItems/MapItems'; -import { SearchItemType } from "@/types/home"; +import {SearchItemType} from '@/types/home'; interface PropsType { data: SearchItemType[]; categoryChange: boolean; } -function Map({ data, categoryChange }: PropsType) { +function Map({data, categoryChange}: PropsType) { const [slideLocation, setSlideLocation] = useState(0); const [throttlePermission, setThrottlePermission] = useState(false); const [currentpin, setCurrentPin] = useState(); @@ -37,34 +37,22 @@ function Map({ data, categoryChange }: PropsType) { offSetHeight: number, data: SearchItemType, ) { - const image = - data.category === "숙소" - ? homeMarker - : data.category === "맛집" - ? forkMarker - : flagMarker; + const image = data.contentTypeId === 32 ? homeMarker : data.contentTypeId === 39 ? forkMarker : flagMarker; const imageSize = new window.kakao.maps.Size(sizeWidth, sizeHeight); const imageOption = { offset: new window.kakao.maps.Point(offSetWidth, offSetHeight), }; - const markerImage = new window.kakao.maps.MarkerImage( - image, - imageSize, - imageOption, - ); + const markerImage = new window.kakao.maps.MarkerImage(image, imageSize, imageOption); const marker = new window.kakao.maps.Marker({ - position: new window.kakao.maps.LatLng( - data.location.latitude, - data.location.longtitude, - ), + position: new window.kakao.maps.LatLng(data.location.latitude, data.location.longtitude), image: markerImage, }); return marker; } // 핀 클릭 이벤트 function clickMarker(marker: any, index: number) { - new window.kakao.maps.event.addListener(marker, "click", function () { + new window.kakao.maps.event.addListener(marker, 'click', function () { let timeOutId; if (window.innerWidth < 450) { if (timeOutId) { @@ -74,10 +62,10 @@ function Map({ data, categoryChange }: PropsType) { timeOutId = setTimeout(() => { setThrottlePermission(false); }, 2000); - const slide = document.querySelector("#map_slide"); + const slide = document.querySelector('#map_slide'); slide?.scrollTo({ left: 343 * index - 20, - behavior: "smooth", + behavior: 'smooth', }); } else { setSlideLocation(-343 * index + 20); @@ -90,16 +78,7 @@ function Map({ data, categoryChange }: PropsType) { const currentMarkers: any[] = []; data.map((data, i) => { - const marker = createPin( - homeMarker, - forkMarker, - flagMarker, - 32, - 32, - -6, - -8, - data, - ); + const marker = createPin(homeMarker, forkMarker, flagMarker, 32, 32, -6, -8, data); clickMarker(marker, i); marker.setMap(map); currentMarkers.push(marker); @@ -110,16 +89,7 @@ function Map({ data, categoryChange }: PropsType) { const currentMarkers: any[] = []; data.map((data) => { - const marker = createPin( - bigHomeMarker, - bigForkMarker, - bigFlagMarker, - 44, - 52, - 0, - 0, - data, - ); + const marker = createPin(bigHomeMarker, bigForkMarker, bigFlagMarker, 44, 52, 0, 0, data); marker.setZIndex(10); currentMarkers.push(marker); }); @@ -136,7 +106,7 @@ function Map({ data, categoryChange }: PropsType) { // 컴포넌트 마운트, 카테고리 전환 시 새로운 맵 생성 useEffect(() => { - const container = document.getElementById("map"); + const container = document.getElementById('map'); setPin([]); // React.StrictMode로 인해 map이 두 번 중첩되어 겹치는 현상 방지 @@ -160,12 +130,7 @@ function Map({ data, categoryChange }: PropsType) { setSmallPin(data); setBigPin(data); data.map((data) => { - bounds.extend( - new window.kakao.maps.LatLng( - data.location.latitude, - data.location.longtitude, - ), - ); + bounds.extend(new window.kakao.maps.LatLng(data.location.latitude, data.location.longtitude)); }); map.setBounds(bounds); } @@ -181,7 +146,7 @@ function Map({ data, categoryChange }: PropsType) { return (
-
+
>; + keywordClick: boolean; } -function SearchList({forSearch, setForSearch}: PropsType) { +function SearchList({forSearch, keywordClick}: PropsType) { const [data, setData] = useState(); const [filterData, setFilterData] = useState(); const [categoryChange, setCategoryChange] = useState(false); @@ -27,24 +27,17 @@ function SearchList({forSearch, setForSearch}: PropsType) { const [searchParams] = useSearchParams(); useEffect(() => { - getData('home/search/search', setData); - - const querystring = searchParams.get('category'); - const beforeData = forSearch; - if (querystring) { - beforeData.category = querystring; - setForSearch(beforeData); - } + getData('api/home/search/search', setData); }, [searchParams]); useEffect(() => { if (data) { - if (forSearch.category !== '전체') { + if (forSearch.category !== 0) { let filterData; - if (forSearch.category === '맛집') { - filterData = data.filter((data) => data.category === '음식점' || data.category === '카페'); + if (forSearch.category === 14) { + filterData = data.filter((data) => data.contentTypeId === 14 || data.contentTypeId === 15); } else { - filterData = data.filter((data) => data.category === forSearch.category); + filterData = data.filter((data) => data.contentTypeId === forSearch.category); } setFilterData(filterData); } else { @@ -54,9 +47,6 @@ function SearchList({forSearch, setForSearch}: PropsType) { }, [data, forSearch.category]); function onMap() { - const beforeData = forSearch; - beforeData.map = 'true'; - setForSearch(beforeData); navigate( `/home/search?keyword=${forSearch.keyword}&category=${forSearch.category}&map=true&location=${forSearch.location}&sort=${forSearch.sort}`, ); @@ -64,13 +54,13 @@ function SearchList({forSearch, setForSearch}: PropsType) { return (
- + {forSearch.map === 'true' && filterData ? ( ) : ( <>
- +
    diff --git a/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx b/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx index 78bc479a..f0fdbbdf 100644 --- a/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx +++ b/src/components/SearchFromHome/SearchList/Tabs/Tab/Tab.tsx @@ -2,26 +2,24 @@ import {useNavigate} from 'react-router-dom'; import styles from './Tab.module.scss'; +import {translateCategoryToNum, translateCategoryToStr} from '@/hooks/Search/useSearch'; + import {ForSearchType} from '@/types/home'; interface PropsType { forSearch: ForSearchType; thisCategory: string; setCategoryChange: React.Dispatch>; - setForSearch: React.Dispatch>; } -function Tab({forSearch, thisCategory, setForSearch, setCategoryChange}: PropsType) { +function Tab({forSearch, thisCategory, setCategoryChange}: PropsType) { const navigate = useNavigate(); - function handleCategory(key: string) { + function handleCategory(key: number) { setCategoryChange(true); setTimeout(() => { setCategoryChange(false); }, 150); - const beforeData = forSearch; - beforeData.category = key; - setForSearch(beforeData); navigate( `/home/search?keyword=${forSearch.keyword}&category=${key}&map=${forSearch.map}&location=${forSearch.location}&sort=${forSearch.sort}`, ); @@ -32,11 +30,11 @@ function Tab({forSearch, thisCategory, setForSearch, setCategoryChange}: PropsTy className={styles.container} id={thisCategory} style={{ - color: forSearch.category === thisCategory ? '#1d2433' : '#cdcfd0', - borderBottom: forSearch.category === thisCategory ? '2px solid #1d2433' : 'none', + color: translateCategoryToStr(forSearch.category) === thisCategory ? '#1d2433' : '#cdcfd0', + borderBottom: translateCategoryToStr(forSearch.category) === thisCategory ? '2px solid #1d2433' : 'none', }} onClick={() => { - handleCategory(thisCategory); + handleCategory(translateCategoryToNum(thisCategory)); }} > {thisCategory} diff --git a/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx b/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx index 40a5bf70..2fc5748c 100644 --- a/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx +++ b/src/components/SearchFromHome/SearchList/Tabs/Tabs.tsx @@ -12,11 +12,10 @@ import {ForSearchType} from '@/types/home'; interface PropsType { forSearch: ForSearchType; - setForSearch: React.Dispatch>; setCategoryChange: React.Dispatch>; } -function Tabs({forSearch, setForSearch, setCategoryChange}: PropsType) { +function Tabs({forSearch, setCategoryChange}: PropsType) { const [slideLocation, setSlideLocation] = useState(0); const [componentRef, size] = useComponentSize(); const thisCategory = ['전체', '맛집', '숙소', '관광지', '문화시설', '레포츠', '쇼핑']; @@ -43,7 +42,6 @@ function Tabs({forSearch, setForSearch, setCategoryChange}: PropsType) { {thisCategory.map((thisCategory) => ( { + http.get('api/home/vote', () => { return HttpResponse.json(userVoteData, { status: 200, }); }), - http.get('/api/home/tripSpace', () => { + http.get('api/home/tripSpace', () => { return HttpResponse.json(tripSpaceData, { status: 200, }); }), // 홈 검색 - http.get('/api/home/search/keyword', () => { + http.get('api/places/popular/keywords', () => { return HttpResponse.json(searchKeywordData, { status: 200, }); }), - http.get('/api/places/popular', () => { + http.get('api/places/popular', () => { return HttpResponse.json(hotPlaces, { status: 200, }); }), - http.get('/api/home/search/hothotel', () => { - return HttpResponse.json(hotHotels, { - status: 200, - }); - }), - http.get('/api/home/search/search', () => { + http.get('api/home/search/search', () => { return HttpResponse.json(searchItemData, { status: 200, }); @@ -608,7 +511,7 @@ export const home = [ // 추후 api폴더가 생기면 함수를 옮기겠습니다. export async function getData(apiURL: string, set: Dispatch>) { try { - const fetchData = await axios.get(`/api/${apiURL}`); + const fetchData = await axios.get(`${apiURL}`); set(fetchData.data); } catch (error) { console.log(error); diff --git a/src/pages/SearchFromHome/SearchFromHome.tsx b/src/pages/SearchFromHome/SearchFromHome.tsx index ceef949b..3c93a13b 100644 --- a/src/pages/SearchFromHome/SearchFromHome.tsx +++ b/src/pages/SearchFromHome/SearchFromHome.tsx @@ -13,12 +13,13 @@ import SearchList from '@/components/SearchFromHome/SearchList/SearchList'; function SearchFromHome() { const [forSearch, setForSearch] = useState({ keyword: '', - category: '전체', + category: 0, map: 'false', location: '전국', sort: '등록순', }); const [searchParams] = useSearchParams(); + const [kewordClick, setKeywordClick] = useState(false); const vh = window.innerHeight; useEffect(() => { @@ -33,7 +34,7 @@ function SearchFromHome() { if (querystring.keyword && querystring.category && querystring.location && querystring.map && querystring.sort) { setForSearch({ keyword: querystring.keyword, - category: querystring.category, + category: parseInt(querystring.category), map: querystring.map, location: querystring.location, sort: querystring.sort, @@ -57,9 +58,9 @@ function SearchFromHome() { )} {forSearch.keyword === '' ? ( - + ) : ( - + )}
); diff --git a/src/types/home.ts b/src/types/home.ts index 8126bba2..5fae2043 100644 --- a/src/types/home.ts +++ b/src/types/home.ts @@ -82,7 +82,7 @@ export interface SearchItemType { export interface ForSearchType { keyword: string; - category: string; + category: number; map: string; location: string; sort: string; diff --git a/src/utils/categories.json b/src/utils/categories.json new file mode 100644 index 00000000..5e42b55d --- /dev/null +++ b/src/utils/categories.json @@ -0,0 +1,610 @@ +[ + { + "code": "A01010100", + "name": "국립공원" + }, + { + "code": "A01010200", + "name": "도립공원" + }, + { + "code": "A01010300", + "name": "군립공원" + }, + { + "code": "A01010400", + "name": "산" + }, + { + "code": "A01010500", + "name": "자연생태관광지" + }, + { + "code": "A01010600", + "name": "자연휴양림" + }, + { + "code": "A01010700", + "name": "수목원" + }, + { + "code": "A01010800", + "name": "폭포" + }, + { + "code": "A01010900", + "name": "계곡" + }, + { + "code": "A01011000", + "name": "약수터" + }, + { + "code": "A01011100", + "name": "해안절경" + }, + { + "code": "A01011200", + "name": "해수욕장" + }, + { + "code": "A01011300", + "name": "섬" + }, + { + "code": "A01011400", + "name": "항구/포구" + }, + { + "code": "A01011600", + "name": "등대" + }, + { + "code": "A01011700", + "name": "호수" + }, + { + "code": "A01011800", + "name": "강" + }, + { + "code": "A01011900", + "name": "동굴" + }, + { + "code": "A01020100", + "name": "희귀동.식물" + }, + { + "code": "A01020200", + "name": "기암괴석" + }, + { + "code": "A02010100", + "name": "고궁" + }, + { + "code": "A02010200", + "name": "성" + }, + { + "code": "A02010300", + "name": "문" + }, + { + "code": "A02010400", + "name": "고택" + }, + { + "code": "A02010500", + "name": "생가" + }, + { + "code": "A02010600", + "name": "민속마을" + }, + { + "code": "A02010700", + "name": "유적지/사적지" + }, + { + "code": "A02010800", + "name": "사찰" + }, + { + "code": "A02010900", + "name": "종교성지" + }, + { + "code": "A02011000", + "name": "안보관광" + }, + { + "code": "A02020200", + "name": "관광단지" + }, + { + "code": "A02020300", + "name": "온천/욕장/스파" + }, + { + "code": "A02020400", + "name": "이색찜질방" + }, + { + "code": "A02020500", + "name": "헬스투어" + }, + { + "code": "A02020600", + "name": "테마공원" + }, + { + "code": "A02020700", + "name": "공원" + }, + { + "code": "A02020800", + "name": "유람선/잠수함관광" + }, + { + "code": "A02030100", + "name": "농.산.어촌 체험" + }, + { + "code": "A02030200", + "name": "전통체험" + }, + { + "code": "A02030300", + "name": "산사체험" + }, + { + "code": "A02030400", + "name": "이색체험" + }, + { + "code": "A02030600", + "name": "이색거리" + }, + { + "code": "A02040400", + "name": "발전소" + }, + { + "code": "A02040600", + "name": "식음료" + }, + { + "code": "A02040800", + "name": "기타" + }, + { + "code": "A02040900", + "name": "전자-반도체" + }, + { + "code": "A02041000", + "name": "자동차" + }, + { + "code": "A02050100", + "name": "다리/대교" + }, + { + "code": "A02050200", + "name": "기념탑/기념비/전망대" + }, + { + "code": "A02050300", + "name": "분수" + }, + { + "code": "A02050400", + "name": "동상" + }, + { + "code": "A02050500", + "name": "터널" + }, + { + "code": "A02050600", + "name": "유명건물" + }, + { + "code": "A02060100", + "name": "박물관" + }, + { + "code": "A02060200", + "name": "기념관" + }, + { + "code": "A02060300", + "name": "전시관" + }, + { + "code": "A02060400", + "name": "컨벤션센터" + }, + { + "code": "A02060500", + "name": "미술관/화랑" + }, + { + "code": "A02060600", + "name": "공연장" + }, + { + "code": "A02060700", + "name": "문화원" + }, + { + "code": "A02060800", + "name": "외국문화원" + }, + { + "code": "A02060900", + "name": "도서관" + }, + { + "code": "A02061000", + "name": "대형서점" + }, + { + "code": "A02061100", + "name": "문화전수시설" + }, + { + "code": "A02061200", + "name": "영화관" + }, + { + "code": "A02061300", + "name": "어학당" + }, + { + "code": "A02061400", + "name": "학교" + }, + { + "code": "A02070100", + "name": "문화관광축제" + }, + { + "code": "A02070200", + "name": "일반축제" + }, + { + "code": "A02080100", + "name": "전통공연" + }, + { + "code": "A02080200", + "name": "연극" + }, + { + "code": "A02080300", + "name": "뮤지컬" + }, + { + "code": "A02080400", + "name": "오페라" + }, + { + "code": "A02080500", + "name": "전시회" + }, + { + "code": "A02080600", + "name": "박람회" + }, + { + "code": "A02080800", + "name": "무용" + }, + { + "code": "A02080900", + "name": "클래식음악회" + }, + { + "code": "A02081000", + "name": "대중콘서트" + }, + { + "code": "A02081100", + "name": "영화" + }, + { + "code": "A02081200", + "name": "스포츠경기" + }, + { + "code": "A02081300", + "name": "기타행사" + }, + { + "code": "C01120001", + "name": "가족코스" + }, + { + "code": "C01130001", + "name": "나홀로코스" + }, + { + "code": "C01140001", + "name": "힐링코스" + }, + { + "code": "C01150001", + "name": "도보코스" + }, + { + "code": "C01160001", + "name": "캠핑코스" + }, + { + "code": "C01170001", + "name": "맛코스" + }, + { + "code": "A03010200", + "name": "수상레포츠" + }, + { + "code": "A03010300", + "name": "항공레포츠" + }, + { + "code": "A03020200", + "name": "수련시설" + }, + { + "code": "A03020300", + "name": "경기장" + }, + { + "code": "A03020400", + "name": "인라인(실내 인라인 포함)" + }, + { + "code": "A03020500", + "name": "자전거하이킹" + }, + { + "code": "A03020600", + "name": "카트" + }, + { + "code": "A03020700", + "name": "골프" + }, + { + "code": "A03020800", + "name": "경마" + }, + { + "code": "A03020900", + "name": "경륜" + }, + { + "code": "A03021000", + "name": "카지노" + }, + { + "code": "A03021100", + "name": "승마" + }, + { + "code": "A03021200", + "name": "스키/스노보드" + }, + { + "code": "A03021300", + "name": "스케이트" + }, + { + "code": "A03021400", + "name": "썰매장" + }, + { + "code": "A03021500", + "name": "수렵장" + }, + { + "code": "A03021600", + "name": "사격장" + }, + { + "code": "A03021700", + "name": "야영장,오토캠핑장" + }, + { + "code": "A03021800", + "name": "암벽등반" + }, + { + "code": "A03022000", + "name": "서바이벌게임" + }, + { + "code": "A03022100", + "name": "ATV" + }, + { + "code": "A03022200", + "name": "MTB" + }, + { + "code": "A03022300", + "name": "오프로드" + }, + { + "code": "A03022400", + "name": "번지점프" + }, + { + "code": "A03022600", + "name": "스키(보드) 렌탈샵" + }, + { + "code": "A03022700", + "name": "트래킹" + }, + { + "code": "A03030100", + "name": "윈드서핑/제트스키" + }, + { + "code": "A03030200", + "name": "카약/카누" + }, + { + "code": "A03030300", + "name": "요트" + }, + { + "code": "A03030400", + "name": "스노쿨링/스킨스쿠버다이빙" + }, + { + "code": "A03030500", + "name": "민물낚시" + }, + { + "code": "A03030600", + "name": "바다낚시" + }, + { + "code": "A03030700", + "name": "수영" + }, + { + "code": "A03030800", + "name": "래프팅" + }, + { + "code": "A03040100", + "name": "스카이다이빙" + }, + { + "code": "A03040200", + "name": "초경량비행" + }, + { + "code": "A03040300", + "name": "헹글라이딩/패러글라이딩" + }, + { + "code": "A03040400", + "name": "열기구" + }, + { + "code": "A03050100", + "name": "복합 레포츠" + }, + { + "code": "B02010100", + "name": "관광호텔" + }, + { + "code": "B02010500", + "name": "콘도미니엄" + }, + { + "code": "B02010600", + "name": "유스호스텔" + }, + { + "code": "B02010700", + "name": "펜션" + }, + { + "code": "B02010900", + "name": "모텔" + }, + { + "code": "B02011000", + "name": "민박" + }, + { + "code": "B02011100", + "name": "게스트하우스" + }, + { + "code": "B02011200", + "name": "홈스테이" + }, + { + "code": "B02011300", + "name": "서비스드레지던스" + }, + { + "code": "B02011600", + "name": "한옥" + }, + { + "code": "A04010100", + "name": "5일장" + }, + { + "code": "A04010200", + "name": "상설시장" + }, + { + "code": "A04010300", + "name": "백화점" + }, + { + "code": "A04010400", + "name": "면세점" + }, + { + "code": "A04010500", + "name": "대형마트" + }, + { + "code": "A04010600", + "name": "전문매장/상가" + }, + { + "code": "A04010700", + "name": "공예/공방" + }, + { + "code": "A04010900", + "name": "특산물판매점" + }, + { + "code": "A04011000", + "name": "사후면세점" + }, + { + "code": "A05020100", + "name": "한식" + }, + { + "code": "A05020200", + "name": "서양식" + }, + { + "code": "A05020300", + "name": "일식" + }, + { + "code": "A05020400", + "name": "중식" + }, + { + "code": "A05020700", + "name": "이색음식점" + }, + { + "code": "A05020900", + "name": "카페/전통찻집" + }, + { + "code": "A05021000", + "name": "클럽" + } +] \ No newline at end of file diff --git a/src/utils/contentType.json b/src/utils/contentType.json new file mode 100644 index 00000000..11fdae59 --- /dev/null +++ b/src/utils/contentType.json @@ -0,0 +1,30 @@ +[ + { + "name": "맛집", + "id": 39 + }, + { + "name": "관광지", + "id": 12 + }, + { + "name": "문화시설", + "id": 14 + }, + { + "name": "문화시설", + "id": 15 + }, + { + "name": "레포츠", + "id": 28 + }, + { + "name": "숙소", + "id": 32 + }, + { + "name": "쇼핑", + "id": 38 + } +] From 84ab68c8fa89d544ced88097f56f0e9e0bffb136 Mon Sep 17 00:00:00 2001 From: Yamyam-code Date: Mon, 22 Jan 2024 04:57:46 +0900 Subject: [PATCH 6/6] Fix: build error --- src/components/SearchFromHome/SearchList/SearchList.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/SearchFromHome/SearchList/SearchList.tsx b/src/components/SearchFromHome/SearchList/SearchList.tsx index 4e27cc8e..b27d2703 100644 --- a/src/components/SearchFromHome/SearchList/SearchList.tsx +++ b/src/components/SearchFromHome/SearchList/SearchList.tsx @@ -27,7 +27,11 @@ function SearchList({forSearch, keywordClick}: PropsType) { const [searchParams] = useSearchParams(); useEffect(() => { - getData('api/home/search/search', setData); + if (!keywordClick) { + getData('api/home/search/search', setData); + } else { + getData('api/home/search/search', setData); + } }, [searchParams]); useEffect(() => {