diff --git a/src/components/SearchPage/SearchComponent.tsx b/src/components/SearchPage/SearchComponent.tsx index c4f37cc..86d8a54 100644 --- a/src/components/SearchPage/SearchComponent.tsx +++ b/src/components/SearchPage/SearchComponent.tsx @@ -3,6 +3,9 @@ import Container from '@/styles/SearchComponent'; import useBoolean from '@/hooks/useBoolean'; import useIndex from '@/hooks/useIndex'; import CloseIcon from '@/assets/icons/close-btn.svg?react' +import SearchIcon from '@/assets/icons/search.svg?react'; +import { createSearchParams, useNavigate } from 'react-router-dom'; + const placeholder = '검색하고 싶은 키워드를 입력해주세요' interface BaseTagInputProps { @@ -27,7 +30,7 @@ const SearchComponent : React.FC = ({tags, input, searchType, sel const [hoverdIndex, setHoveredIndex, setLeaveIndex] = useIndex(null); const [hoverBtnIndex, setHoverBtnIndex, setLeaveBtnIndex] = useIndex(null); const [tagIndex, setRemovingTagIndex, setNullTagIndex] = useIndex(null); - + const searchNav = useNavigate(); useEffect(() => { if (tags.length > 3) { const lastValue = tags[3] @@ -45,8 +48,12 @@ const SearchComponent : React.FC = ({tags, input, searchType, sel }, [tags, setTags]); const handleKeyDown = (event: KeyboardEvent) => { + if (event.code === 'Enter'){ + handleSearch(); + } if(!searchType){ - if (event.key === 'Enter' && !isComposing) { + + if ((event.code === 'Comma' || event.code === 'Space') && !isComposing) { event.preventDefault(); if (input) { tags.length > 0 && !input.startsWith('#') ? setTags([...tags, '#' + input]) : setTags([...tags, input]) @@ -54,7 +61,7 @@ const SearchComponent : React.FC = ({tags, input, searchType, sel input.startsWith('#') ? setSelectedHashtags([...selectedHashtags, input.substring(1)]) : setSelectedHashtags([...selectedHashtags, input]) setInput(''); } - } else if (event.key === 'Backspace' && !input) { + } else if ((event.key === 'Backspace' || event.code === 'Backspace') && !input) { if(tags.length > 0){ const lastValue = tags[tags.length - 1] if(selectedHashtags && setSelectedHashtags && selectedHashtags.includes(lastValue.substring(1))) @@ -90,8 +97,23 @@ const SearchComponent : React.FC = ({tags, input, searchType, sel }, 500) } - + const handleSearch = () => { + const params = { + type : searchType === true ? 'keyword' : 'hashtag', + value: searchType ? input : tags.join('&') + }; + + searchNav({ + pathname : '/search/result', + search : `?${createSearchParams(params)}` + }) + window.scrollTo(0, 0); +} + return ( +
+
+ {tags.map((tag : string, index : number) => ( = 3 || index === tagIndex) ? 'exceed' : ''}`} key={index} onMouseEnter={() => setHoverBtnIndex(index)} onMouseLeave={setLeaveBtnIndex}> @@ -110,6 +132,9 @@ const SearchComponent : React.FC = ({tags, input, searchType, sel onChange={(e) => handleOnchage(e)} /> +
+ +
); }; diff --git a/src/components/SearchPage/SearchNotFound.tsx b/src/components/SearchPage/SearchNotFound.tsx index 79f9b2d..ed74404 100644 --- a/src/components/SearchPage/SearchNotFound.tsx +++ b/src/components/SearchPage/SearchNotFound.tsx @@ -1,16 +1,22 @@ import SearchNotFoundIcon from '@/assets/icons/search-notfound.svg?react'; import styled from '@/styles/SearchResult'; +import { useNavigate } from 'react-router-dom'; type NotFoundprop = { input : string } const SearchNotFound : React.FC = ( {input} ) => { + const navigate = useNavigate(); + + const handleBtn = () => { + navigate('/'); + } return (
{input}에 대한 검색 결과가 없어요
- +
); } diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx index 710bad1..4819ecf 100644 --- a/src/pages/SearchPage.tsx +++ b/src/pages/SearchPage.tsx @@ -1,18 +1,31 @@ import { Container, HashtagBox } from '@/styles/SearchPage'; -import TooltipImg from '@/assets/icons/tooltip.svg?react'; -import SearchIcon from '@/assets/icons/search.svg?react'; - -import { useState } from 'react'; +import { Tooltip } from '@/components/common'; +import { useEffect, useState } from 'react'; import TagInput from '@/components/SearchPage/SearchComponent'; -import { useNavigate, createSearchParams } from 'react-router-dom'; +import { tagAPI } from '@/apis/search'; const SearchPage = () => { const [tags, setTags] = useState([]); const [input, setInput] = useState(''); const [searchType, setSearchType] = useState(true); // True : keyword | False : hashTag - const userHashTag = ["기획", "광고", "마케팅", "트렌드", "기업", "광고", "마케팅", "트렌드", "기업", "광고"]; // 사용자의 해시태그 데이터 10개 <임의 데이터> + const [userHashTag, setUserHashTag] = useState([]); const [selectedHashtags, setSelectedHashtags] = useState([]); - const searchNav = useNavigate(); + + useEffect(() => { + const handleTagAPI = async () => { + try { + const {data} = (await tagAPI()); + const extraData = data.result.map((item) => { + return item.name; + }); + const shuffleData = sortShuffle(extraData).slice(0, 10); + setUserHashTag(shuffleData); + } catch(e) { + setUserHashTag(['A','B','C','D','E','F','G','H','I','J']); + } + } + handleTagAPI(); + }, []); const handleHashtagBox = (value : string) => { const isSelected = selectedHashtags.includes(value); @@ -23,17 +36,9 @@ const SearchPage = () => { setSearchType(false); // 박스를 클릭했을 때도 type 변경 } - const handleSearch = () => { - const params = { - type : searchType === true ? 'keyword' : 'hashtag', - value: searchType ? input : tags.join('&') - }; - - searchNav({ - pathname : '/search/result', - search : `?${createSearchParams(params)}` - }) - } + const sortShuffle = (arr : string[]) => { + return arr.sort(() => Math.random() - 0.5); + } return ( @@ -48,16 +53,24 @@ const SearchPage = () => {
-
-
- {(input.length === 0 && tags.length === 0)? : ''} + {(input.length === 0 && tags.length === 0) ? ( + + <> + 1. 키워드 검색 : 키워드를 검색하면 해당 키워드가 언급 된 영상들을 찾아드려요! +
+ 2. 해시태그 검색 : #을 함께 검색하면 해당 해시태그가 있는 영상들을 찾아드려요! + +
+ ) + : '' + }
diff --git a/src/pages/SearchResultPage.tsx b/src/pages/SearchResultPage.tsx index 2593df1..fdfa78c 100644 --- a/src/pages/SearchResultPage.tsx +++ b/src/pages/SearchResultPage.tsx @@ -1,13 +1,12 @@ import { escapeHTML } from "@/utils/string"; import { useState, useEffect} from "react"; -import { createSearchParams, useLocation } from "react-router-dom"; +import { useLocation } from "react-router-dom"; import Styled from "@/styles/SearchResult"; import TagInput from "@/components/SearchPage/SearchComponent"; import SearchNotFound from "@/components/SearchPage/SearchNotFound"; import SearchIcon from '@/assets/icons/search.svg?react'; import { IVideo } from "@/models/search"; import { searchAPI } from "@/apis/search"; -import { useNavigate } from "react-router-dom"; import SearchResultBox from "@/components/SearchPage/SearchResultBox"; @@ -19,8 +18,6 @@ const SearchResult = () => { const [errormsg, setErrormsg] = useState(''); const [data, setData] = useState([]); const location = useLocation(); - const searchNav = useNavigate(); - useEffect(() => { const searchParams = new URLSearchParams(location.search); @@ -41,13 +38,13 @@ const SearchResult = () => { break; case 'hashtag': const tagValues = searchParams.get('value') as string; - const tagtype = searchParams.get('type') as string - - setTags(tagValues.split('&')) + const tagtype = searchParams.get('type') as string; + setTags(tagValues.replace(/\ /g, '').split('&')) setSearchType(false); handleSearchAPI(tagValues, tagtype, '&'); if(data.length === 0){ - setErrormsg(tagValues.replace('&', ' ')) + const changeSpace = tagValues.replace(/\&/g, ' '); + setErrormsg(changeSpace) } break; @@ -109,18 +106,7 @@ const SearchResult = () => { }); mappingData; } - const handleReSearch = () => { - const params = { - type : searchType === true ? 'keyword' : 'hashtag', - value: searchType ? input : tags.join('&') - }; - - searchNav({ - pathname : '/search/result', - search : `?${createSearchParams(params)}` - }) - window.location.reload(); - } + if(loading){ return ( @@ -140,7 +126,6 @@ const SearchResult = () => {
- diff --git a/src/styles/SearchPage.ts b/src/styles/SearchPage.ts index f08c845..764273c 100644 --- a/src/styles/SearchPage.ts +++ b/src/styles/SearchPage.ts @@ -1,4 +1,5 @@ import styled from "styled-components"; +import theme from "./theme"; const Container = styled.div` display : flex; @@ -98,6 +99,10 @@ const Container = styled.div` border-radius: 8px; order : 1; border : 0; + &:hover { + background-color : ${theme.color.green500}; + color : ${theme.color.gray500}; + } } & button:disabled { diff --git a/src/styles/SearchResult.ts b/src/styles/SearchResult.ts index e10f5a2..5592d6f 100644 --- a/src/styles/SearchResult.ts +++ b/src/styles/SearchResult.ts @@ -1,4 +1,5 @@ import styled from "styled-components"; +import theme from "./theme"; const Container = styled.div` display : flex; @@ -45,7 +46,7 @@ const Container = styled.div` & div.input { display : flex; - gap : 20px; + gap : 10px; } & input::placeholder { @@ -66,6 +67,10 @@ const Container = styled.div` border-radius: 8px; order : 1; border : 0; + &:hover { + background-color : ${theme.color.green500}; + color : ${theme.color.gray500}; + } } & button:disabled { @@ -273,9 +278,14 @@ const SearchNotFoundContainer = styled.div` & div.text { ${(props) => props.theme.typography.Header3}; + display : flex; + flex-direction : column; + justify-content: center; + align-items: center; } & span.user { color : ${(props) => props.theme.color.gray300}; + text-align : center; } & button {