From c867528daa2f0e7f2ac620bfc759d5c59bcf1852 Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Wed, 31 Jan 2024 11:26:35 +0900 Subject: [PATCH 01/13] =?UTF-8?q?useNavigate=20=EC=B6=94=EA=B0=80,=20searc?= =?UTF-8?q?hResult=20Page=20=EC=B6=94=EA=B0=80,=20flex=201=201=20auto?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/SearchPage.tsx | 70 ++++++++++++++++++++-------------- src/pages/SearchResultPage.tsx | 67 ++++++++++++++++++++++---------- src/styles/SearchPage.ts | 2 +- 3 files changed, 90 insertions(+), 49 deletions(-) diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx index 9e9adce..53db40f 100644 --- a/src/pages/SearchPage.tsx +++ b/src/pages/SearchPage.tsx @@ -4,6 +4,7 @@ import SearchIcon from '@/assets/icons/search.svg?react'; import { useState } from 'react'; import TagInput from '@/components/SearchPage/SearchComponent'; +import { useNavigate, createSearchParams } from 'react-router-dom'; const SearchPage = () => { const [tags, setTags] = useState([]); @@ -11,6 +12,7 @@ const SearchPage = () => { const [searchType, setSearchType] = useState(true); // True : keyword | False : hashTag const [userHashTag, SetUserHashTag] = useState(["기획", "광고", "마케팅", "트렌드", "기업", "광고", "마케팅", "트렌드", "기업", "광고"]); // 사용자의 해시태그 데이터 10개 <임의 데이터> const [selectedHashtags, setSelectedHashtags] = useState([]); + const searchNav = useNavigate(); const handleHashtagBox = (value : string) => { const isSelected = selectedHashtags.includes(value); @@ -21,42 +23,54 @@ 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)}` + }) + } + return ( - -
-
-
-
- 찾고 싶은 키워드가 있나요? - 찾고자 하는 키워드를 검색하면 관련 영상을 찾아드릴게요 -
+ +
+
+
+
+ 찾고 싶은 키워드가 있나요? + 찾고자 하는 키워드를 검색하면 관련 영상을 찾아드릴게요 +
-
-
-
- - -
- +
+
+
+ +
+
-
- {(input.length === 0 && tags.length === 0)? : ''} +
+ {(input.length === 0 && tags.length === 0)? : ''} +
-
- { - userHashTag.map((value : string, idx : number) => { - return( handleHashtagBox(value)} - className={selectedHashtags.includes(value) ? 'toggle' : ''}>{'#' + value}) - }) - } -
+
+ { + userHashTag.map((value : string, idx : number) => { + return( handleHashtagBox(value)} + className={selectedHashtags.includes(value) ? 'toggle' : ''}>{'#' + value}) + }) + }
- - ); +
+ +); }; export default SearchPage; diff --git a/src/pages/SearchResultPage.tsx b/src/pages/SearchResultPage.tsx index 40a93a1..02a8443 100644 --- a/src/pages/SearchResultPage.tsx +++ b/src/pages/SearchResultPage.tsx @@ -1,44 +1,71 @@ -import TagInput from "@/components/SearchPage/SearchComponent"; -import { useState } from "react"; + +import { useState, useEffect } from "react"; import SearchIcon from '@/assets/icons/search.svg?react' -import FilterIcon from '@/assets/icons/filter.svg?react' + +import useBoolean from "@/hooks/useBoolean"; +import { useLocation } from "react-router-dom"; +import Styled from "@/styles/SearchResult"; + +import TagInput from "@/components/SearchPage/SearchComponent"; +import SearchNotFound from "@/components/SearchPage/SearchNotFound"; +import SearchResultBox from "@/components/SearchPage/SearchResultBox"; const SearchResult = () => { const [tags, setTags] = useState([]); const [input, setInput] = useState(''); const [searchType, setSearchType] = useState(true); // True : keyword | False : hashTag + const [isScrolling, ,startScrolling,,] = useBoolean(false); + const location = useLocation(); + + useEffect(() => { + const fetchData = () => { + try { + const searchParams = new URLSearchParams(location.search); + const type = searchParams.get('type'); + const data = searchParams.get('value'); + if (type === 'keyword' && data) { + setInput(data); + setSearchType(true); + } else if (type === 'hashtag' && data) { + const initialTagList = data.split('&'); + setTags(initialTagList) + setSearchType(false); + } + } catch (error) { + console.error('Error:', error); + } + }; + fetchData(); + }, [location]) return ( -
-
-
-
-
+ +
+
+
+
- +
-
-
-
+
+
총 0개의 영상이 발견되었어요! -
- - -
- +
-
+ ); }; diff --git a/src/styles/SearchPage.ts b/src/styles/SearchPage.ts index 0ce9f51..f08c845 100644 --- a/src/styles/SearchPage.ts +++ b/src/styles/SearchPage.ts @@ -5,7 +5,7 @@ const Container = styled.div` flex-direction : row; justify-content: center; align-items: center; - flex: none; + flex: 1 1 auto; order: 0; flex-grow: 0; From d3935e1e9ffbc30a6fec32a462a77f58ea607ea8 Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Wed, 31 Jan 2024 11:27:04 +0900 Subject: [PATCH 02/13] =?UTF-8?q?searchnotfound=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/search-notfound.svg | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/assets/icons/search-notfound.svg diff --git a/src/assets/icons/search-notfound.svg b/src/assets/icons/search-notfound.svg new file mode 100644 index 0000000..f253848 --- /dev/null +++ b/src/assets/icons/search-notfound.svg @@ -0,0 +1,8 @@ + + + + + + + + From a64389e4117c39b41ef10ce1092a3787dcbd1a00 Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Wed, 31 Jan 2024 11:28:17 +0900 Subject: [PATCH 03/13] =?UTF-8?q?searchresult=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchPage/SearchNotFound.tsx | 19 +++++++++++++ src/components/SearchPage/SearchResultBox.tsx | 28 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/components/SearchPage/SearchNotFound.tsx create mode 100644 src/components/SearchPage/SearchResultBox.tsx diff --git a/src/components/SearchPage/SearchNotFound.tsx b/src/components/SearchPage/SearchNotFound.tsx new file mode 100644 index 0000000..79f9b2d --- /dev/null +++ b/src/components/SearchPage/SearchNotFound.tsx @@ -0,0 +1,19 @@ +import SearchNotFoundIcon from '@/assets/icons/search-notfound.svg?react'; +import styled from '@/styles/SearchResult'; + +type NotFoundprop = { + input : string +} + +const SearchNotFound : React.FC = ( {input} ) => { + return ( + + +
{input}에 대한 검색 결과가 없어요
+ +
+ ); +} + + +export default SearchNotFound; \ No newline at end of file diff --git a/src/components/SearchPage/SearchResultBox.tsx b/src/components/SearchPage/SearchResultBox.tsx new file mode 100644 index 0000000..fa2bea5 --- /dev/null +++ b/src/components/SearchPage/SearchResultBox.tsx @@ -0,0 +1,28 @@ +import Styled from '@/styles/SearchResult'; + +const SearchResultBox = () => { + return ( + +
+
+ 여울 + + 2024년 1월 1일 +
+
+
메조미디어가 본 내년 미디어 트렌드는…생성AI·광고없는 구독
+
2024 광고 시장의 현황
+
올해 마크색 테스트IT업계의 가장 큰 화제는 단연코 생성형 AI라고 할 수 있겠습니다. 2022년 11월, OpenAI가 출시한 ChatGPT는 멀게만 느껴졌던 AI 기술을 우리의 실생활에 밀접한 서비스로 바꾸었죠. 그리고 이제는 디지털 광고 영역도dsad 우리모두화이팅
+
+
+ #마케팅팅팅 + #트렌드 + #기획 +
+
+
+
+ ); +} + +export default SearchResultBox; \ No newline at end of file From 14c5f86a2cb9d319e85f0bb4d793af5dd6622fc4 Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Wed, 31 Jan 2024 11:28:38 +0900 Subject: [PATCH 04/13] =?UTF-8?q?searchResult=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/SearchResult.ts | 291 +++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 src/styles/SearchResult.ts diff --git a/src/styles/SearchResult.ts b/src/styles/SearchResult.ts new file mode 100644 index 0000000..5a4afb8 --- /dev/null +++ b/src/styles/SearchResult.ts @@ -0,0 +1,291 @@ +import styled from "styled-components"; + +const Container = styled.div` + display : flex; + flex-direction : column; + + & mark { + color : ${(props) => props.theme.color.green600} !important; + background : transparent; + } + + & div.inputContainer { + display: flex; + flex-direction: column; + align-items: center; + padding: 40px 0px 40px; + gap: 40px; + + background: ${(props) => props.theme.color.white}; + } + & div.inputwrap { + display : flex; + flex-direction : column; + justify-content: center; + align-items: center; + padding: 0px; + gap: 20px; + + background: ${(props) => props.theme.color.gray100}; + border-radius: 12px; + white-space: nowrap; + overflow: hidden; + } + + & div.inputwrap:hover { + box-shadow: 1px 1px 20px ${(props) => props.theme.color.gray100}; + } + + & div.input-inner { + display : flex; + justify-content : space-between; + white-space: nowrap; + } + + & div.input { + display : flex; + gap : 20px; + } + + & input::placeholder { + ${(props) => props.theme.typography.Subheader2}; + + color: ${(props) => props.theme.color.gray300}; + } + + & button.search-btn { + + ${(props) => props.theme.typography.Body1}; + + color: ${(props) => props.theme.color.white}; + + + background : ${(props) => props.theme.color.gray500}; + + border-radius: 8px; + order : 1; + border : 0; + } + + & button:disabled { + background: ${(props) => props.theme.color.gray300}; + } + + & div.result { + display: flex; + overflow : scroll; + align-items : center; + flex-direction: column; + gap : 10px; + } + + & div.filter { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + padding: 0px; + gap: 12px; + & span { + ${(props) => props.theme.typography.Body3}; + color : ${(props) => props.theme.color.gray300}; + } + } + & div.content { + display : flex; + flex-direction : column; + gap : 20px; + } +`; + +const VideoCard = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-start; + padding: 0px; + + background : ${(props) => props.theme.color.white} + flex: none; + order: 1; + flex-grow: 0; + + box-shadow: 0px 4px 40px rgba(0, 0, 0, 0.05); + border-radius: 16px; + + & div.main { + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 24px; + gap: 24px; + + background : transparent; + + flex: none; + order: 0; + flex-grow: 1; + } + + & div.user { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 0px; + gap: 8px; + + flex: none; + order: 0; + flex-grow: 0; + } + + & span.userName { + + ${(props) => props.theme.typography.Caption1}; + color: ${(props) => props.theme.color.gray300}; + flex: none; + order: 0; + flex-grow: 0; + } + + & span.contour { + border: 1px solid ${(props) => props.theme.color.gray300}; + + flex: none; + order: 1; + flex-grow: 0; + } + + & span.userDate { + ${(props) => props.theme.typography.Caption1}; + + color: ${(props) => props.theme.color.gray300}; + + flex: none; + order: 2; + flex-grow: 0; + } + + & div.content { + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 0px; + gap: 8px; + + flex: none; + order: 1; + align-self: stretch; + flex-grow: 0; + } + + & div.title { + ${(props) => props.theme.typography.Subheader3}; + + color: ${(props) => props.theme.color.gray500}; + + flex: none; + order: 0; + align-self: stretch; + flex-grow: 0; + } + + & div.subtitle { + ${(props) => props.theme.typography.Body3}; + + color: ${(props) => props.theme.color.gray400}; + + flex: none; + order: 1; + align-self: stretch; + flex-grow: 0; + } + + & div.subcontent { + ${(props) => props.theme.typography.Body3}; + + color: ${(props) => props.theme.color.gray300}; + overflow : hidden; + text-overflow : ellipsis; + flex: none; + order: 2; + align-self: stretch; + flex-grow: 0; + } + + & div.hashtag { + display: flex; + flex-direction: row; + align-items: flex-start; + padding: 0px; + gap: 8px; + order : 2; + } + + & div.imgBox { + display: flex; + flex-direction: column; + align-items: center; + padding: 0; + gap: 9px; + + flex: none; + order: 1; + align-self: stretch; + flex-grow: 0; + } +` +const hashtagBox = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 6px 10px; + gap: 10px; + + height: 31px; + + background: ${(props) => props.theme.color.gray100}; + color : ${(props) => props.theme.color.gray400}; + border-radius: 8px; + + flex: none; + order: 2; + flex-grow: 0; + + ${(props) => props.theme.typography.Caption1}; + ` + +const SearchNotFoundContainer = styled.div` + width : 500px; + height : 337px; + display : flex; + flex-direction : column; + justify-content: center; + align-items: center; + gap : 40px; + + & div.text { + ${(props) => props.theme.typography.Header3}; + } + & span.user { + color : ${(props) => props.theme.color.gray300}; + } + + & button { + width : 235px; + height : 56px; + background : ${(props) => props.theme.color.gray500}; + color : ${(props) => props.theme.color.white}; + border : none; + border-radius : 100px; + padding: 12px 32px; + gap: 10px; + ${(props) => props.theme.typography.Subheader2}; + } + ` +export default {Container, VideoCard, hashtagBox, SearchNotFoundContainer}; + + + From 92ccab8ef3f43abdfb2c3f2e64ec2e9d66395875 Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Wed, 31 Jan 2024 11:29:26 +0900 Subject: [PATCH 05/13] =?UTF-8?q?search=20result=20page=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20token=20=EC=9E=84=EC=8B=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 5342b8b..b1db12d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import FindPasswordPage from '@/pages/FindPasswordPage'; import HomePage from '@/pages/HomePage'; import ProfilePage from '@/pages/ProfilePage'; import SearchPage from '@/pages/SearchPage'; +import SearchResult from './pages/SearchResultPage'; import SignInPage from '@/pages/SignInPage'; import SignUpPage from '@/pages/SignUpPage'; import SummaryPage from '@/pages/SummaryPage'; @@ -45,10 +46,12 @@ const App = () => { )} }> - {userToken && ( + {!userToken && ( <> } /> + } /> } /> + )} From e8f5914c541e6ab96cbe5a8a84dd3c9792f617e2 Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Thu, 1 Feb 2024 15:10:26 +0900 Subject: [PATCH 06/13] =?UTF-8?q?api=20=ED=98=B8=EC=B6=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 +- src/pages/SearchPage.tsx | 1 + src/pages/SearchResultPage.tsx | 47 +++++++++++++++++++--------------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index b1db12d..30d5633 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -46,7 +46,7 @@ const App = () => { )} }> - {!userToken && ( + {userToken && ( <> } /> } /> diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx index 53db40f..d9ede2f 100644 --- a/src/pages/SearchPage.tsx +++ b/src/pages/SearchPage.tsx @@ -5,6 +5,7 @@ import SearchIcon from '@/assets/icons/search.svg?react'; import { useState } from 'react'; import TagInput from '@/components/SearchPage/SearchComponent'; import { useNavigate, createSearchParams } from 'react-router-dom'; +const baseURL = 'https://backend.vi-no.site'; const SearchPage = () => { const [tags, setTags] = useState([]); diff --git a/src/pages/SearchResultPage.tsx b/src/pages/SearchResultPage.tsx index 02a8443..5e8f2e5 100644 --- a/src/pages/SearchResultPage.tsx +++ b/src/pages/SearchResultPage.tsx @@ -1,43 +1,48 @@ import { useState, useEffect } from "react"; import SearchIcon from '@/assets/icons/search.svg?react' - import useBoolean from "@/hooks/useBoolean"; import { useLocation } from "react-router-dom"; import Styled from "@/styles/SearchResult"; - import TagInput from "@/components/SearchPage/SearchComponent"; import SearchNotFound from "@/components/SearchPage/SearchNotFound"; -import SearchResultBox from "@/components/SearchPage/SearchResultBox"; +import { axiosInstance } from "@/apis/config/instance"; const SearchResult = () => { const [tags, setTags] = useState([]); const [input, setInput] = useState(''); const [searchType, setSearchType] = useState(true); // True : keyword | False : hashTag const [isScrolling, ,startScrolling,,] = useBoolean(false); + const [loading, setLoading] = useState(Boolean); + const location = useLocation(); useEffect(() => { - const fetchData = () => { + const fetchApiData = async () => { try { - const searchParams = new URLSearchParams(location.search); - const type = searchParams.get('type'); - const data = searchParams.get('value'); - - if (type === 'keyword' && data) { - setInput(data); - setSearchType(true); - } else if (type === 'hashtag' && data) { - const initialTagList = data.split('&'); - setTags(initialTagList) - setSearchType(false); - } - } catch (error) { - console.error('Error:', error); + setLoading(true); + const response = await axiosInstance.get('/search/keyword', { + data : { + "keywords" : ['dasdas'] + } + }) + setLoading(false); + return response.data; + } catch (notFound) { + setLoading(false); + return notFound; } - }; - fetchData(); - }, [location]) + } + fetchApiData().then((data) => { + console.log(data); + }); + }, []) + + if(loading){ + return ( +
스켈레톤 페이지
+ ) + } return (
Date: Tue, 6 Feb 2024 10:10:06 +0900 Subject: [PATCH 07/13] =?UTF-8?q?api=20=EC=98=88=EC=8B=9C=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 +- src/pages/SearchResultPage.tsx | 89 +++++++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 30d5633..b1db12d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -46,7 +46,7 @@ const App = () => { )} }> - {userToken && ( + {!userToken && ( <> } /> } /> diff --git a/src/pages/SearchResultPage.tsx b/src/pages/SearchResultPage.tsx index 5e8f2e5..730f21e 100644 --- a/src/pages/SearchResultPage.tsx +++ b/src/pages/SearchResultPage.tsx @@ -1,5 +1,5 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useMemo } from "react"; import SearchIcon from '@/assets/icons/search.svg?react' import useBoolean from "@/hooks/useBoolean"; import { useLocation } from "react-router-dom"; @@ -7,24 +7,94 @@ import Styled from "@/styles/SearchResult"; import TagInput from "@/components/SearchPage/SearchComponent"; import SearchNotFound from "@/components/SearchPage/SearchNotFound"; import { axiosInstance } from "@/apis/config/instance"; +import { escapeHTML } from "@/utils/string"; + +const apiSample = { + isSuccess : true, + code : 200, + message : "success!", + result : { + videos : [ + { + videoid : 9, + title : "", + image : "link", + created_at : new Date, + name : "", + content : "", + user : "", + tag : [ + { + "name": "부동산" + }, + { + "name": "재건축" + }, + { + "name": "경제" + }, + { + "name": "정부정책" + } + ] + } + ] + } +} const SearchResult = () => { const [tags, setTags] = useState([]); const [input, setInput] = useState(''); const [searchType, setSearchType] = useState(true); // True : keyword | False : hashTag const [isScrolling, ,startScrolling,,] = useBoolean(false); const [loading, setLoading] = useState(Boolean); - + const [data, setData] = useState([]); const location = useLocation(); + const formattedScriptList = useMemo(() => { + return apiSample.result.videos.map(({ content, ...others }) => { + if (input.trim() !== '') { + content = content + .split(input) + .map((s) => escapeHTML(s)) + .join(`${escapeHTML(input)}`); + } else { + content = escapeHTML(content); + } + content = content.replace(/\n/g, '
'); + return { + content, + ...others, + }; + }); + }, []); + useEffect(() => { + const crollLoc = () => { + try { + const searchParams = new URLSearchParams(location.search); + const type = searchParams.get('type'); + const data = searchParams.get('value'); + if (type === 'keyword' && data) { + setInput(data); + setSearchType(true); + } else if (type === 'hashtag' && data) { + const initialTagList = data.split('&'); + setTags(initialTagList) + setSearchType(false); + } + } catch (error) { + console.error('Error:', error); + // 사용자에게 오류를 알리는 로직을 추가할 수 있습니다. + } + } const fetchApiData = async () => { try { setLoading(true); - const response = await axiosInstance.get('/search/keyword', { - data : { + const response = await axiosInstance.get('/dummies/dummyProgressFail', { + /*data : { "keywords" : ['dasdas'] - } + }*/ }) setLoading(false); return response.data; @@ -33,10 +103,15 @@ const SearchResult = () => { return notFound; } } + + crollLoc(); fetchApiData().then((data) => { - console.log(data); + if(apiSample.isSuccess){ + + } }); - }, []) + }, [location]) + if(loading){ return ( From ef30939eb7bf64d4c41b05ad9dd61b01a84dbe95 Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Tue, 6 Feb 2024 11:09:56 +0900 Subject: [PATCH 08/13] =?UTF-8?q?=EB=B8=8C=EB=9E=9C=EC=B9=98=20=EC=B5=9C?= =?UTF-8?q?=EC=8B=A0=ED=99=94,=20search=20interface=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/search.ts | 9 +++++ src/apis/user.ts | 9 ++--- src/models/search.ts | 27 ++++++++++++++ src/pages/SearchResultPage.tsx | 64 ++-------------------------------- 4 files changed, 43 insertions(+), 66 deletions(-) create mode 100644 src/apis/search.ts create mode 100644 src/models/search.ts diff --git a/src/apis/search.ts b/src/apis/search.ts new file mode 100644 index 0000000..8ad96a8 --- /dev/null +++ b/src/apis/search.ts @@ -0,0 +1,9 @@ +import { APIResponse } from '@/models/config/axios'; +import axios from './config/instance'; +import { SearchKeywordRequest, SearchResponse } from '@/models/search'; + +const PREFIX = '/search'; + +export const searchKeyowrdAPI = (data: SearchKeywordRequest) => { + return axios.post>(PREFIX + '/keyword', data); + }; \ No newline at end of file diff --git a/src/apis/user.ts b/src/apis/user.ts index ba600b8..3e78358 100644 --- a/src/apis/user.ts +++ b/src/apis/user.ts @@ -1,5 +1,5 @@ import { APIResponse } from '@/models/config/axios'; -import { LoginRequest, LoginResponse } from '@/models/user'; +import { LoginRequest, LoginResponse, CheckEmailRequest, CheckEmailResponse, } from '@/models/user'; import { AlarmResponse } from '@/models/alarm'; import axios from './config/instance'; @@ -13,17 +13,18 @@ export const loginAPI = (data: LoginRequest) => { export const getAlarm = () => { return axios.get>(PREFIX + '/alarm'); }; -/* + export const checkEmailAPI = (data: CheckEmailRequest) => { return axios.post>( PREFIX + '/checkemail', data, ); }; - +/* export const joinAPI = (data: JoinRequest) => { return axios.post>( PREFIX + '/join', data, ); -};*/ +}; +*/ // joinRequest, joinResponse가 없음 \ No newline at end of file diff --git a/src/models/search.ts b/src/models/search.ts new file mode 100644 index 0000000..61797d2 --- /dev/null +++ b/src/models/search.ts @@ -0,0 +1,27 @@ +export interface SearchKeywordRequest { + keyword : string +}; + +export interface SearchHashtagRequest { + hashtag : string[] +}; + +export interface IName { + name : string; +} + +export interface IVideo { + video_id: number; + title: string; + description : string; + image: string; + created_at : Date; + name : string; + content : string; + user : string; + tag : IName[]; +} + +export interface SearchResponse { + videos : IVideo[]; + } \ No newline at end of file diff --git a/src/pages/SearchResultPage.tsx b/src/pages/SearchResultPage.tsx index 3a4201a..cdc504f 100644 --- a/src/pages/SearchResultPage.tsx +++ b/src/pages/SearchResultPage.tsx @@ -8,39 +8,6 @@ import TagInput from "@/components/SearchPage/SearchComponent"; import SearchNotFound from "@/components/SearchPage/SearchNotFound"; import { escapeHTML } from "@/utils/string"; - -const apiSample = { - isSuccess : true, - code : 200, - message : "success!", - result : { - videos : [ - { - videoid : 9, - title : "", - image : "link", - created_at : new Date, - name : "", - content : "", - user : "", - tag : [ - { - "name": "부동산" - }, - { - "name": "재건축" - }, - { - "name": "경제" - }, - { - "name": "정부정책" - } - ] - } - ] - } -} const SearchResult = () => { const [tags, setTags] = useState([]); const [input, setInput] = useState(''); @@ -50,23 +17,6 @@ const SearchResult = () => { const [data, setData] = useState([]); const location = useLocation(); - const formattedScriptList = useMemo(() => { - return apiSample.result.videos.map(({ content, ...others }) => { - if (input.trim() !== '') { - content = content - .split(input) - .map((s) => escapeHTML(s)) - .join(`${escapeHTML(input)}`); - } else { - content = escapeHTML(content); - } - content = content.replace(/\n/g, '
'); - return { - content, - ...others, - }; - }); - }, []); useEffect(() => { const crollLoc = () => { @@ -84,19 +34,14 @@ const SearchResult = () => { } } catch (error) { console.error('Error:', error); - // 사용자에게 오류를 알리는 로직을 추가할 수 있습니다. } } const fetchApiData = async () => { try { setLoading(true); - const response = await axiosInstance.get('/dummies/dummyProgressFail', { - /*data : { - "keywords" : ['dasdas'] - }*/ - }) + setLoading(false); - return response.data; + return undefined; } catch (notFound) { setLoading(false); return notFound; @@ -104,11 +49,6 @@ const SearchResult = () => { } crollLoc(); - fetchApiData().then((data) => { - if(apiSample.isSuccess){ - - } - }); }, [location]) From 502588e46505b8fd370bdbf47bb3483a3d671b76 Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Tue, 6 Feb 2024 22:57:43 +0900 Subject: [PATCH 09/13] =?UTF-8?q?keyword=20api=20=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99=20=EC=83=89=EC=83=81=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?x?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/search.ts | 12 +- src/components/SearchPage/SearchResultBox.tsx | 30 +++-- src/pages/SearchResultPage.tsx | 105 +++++++++++------- 3 files changed, 96 insertions(+), 51 deletions(-) diff --git a/src/apis/search.ts b/src/apis/search.ts index 8ad96a8..875f428 100644 --- a/src/apis/search.ts +++ b/src/apis/search.ts @@ -4,6 +4,12 @@ import { SearchKeywordRequest, SearchResponse } from '@/models/search'; const PREFIX = '/search'; -export const searchKeyowrdAPI = (data: SearchKeywordRequest) => { - return axios.post>(PREFIX + '/keyword', data); - }; \ No newline at end of file +export const searchKeyowrdAPI = (keyword : string) => { + return axios.get>(PREFIX + '/keyword/', { + params : {keyName : keyword} + }); +}; + +export const searchHashtagAPI = () => { + return axios.get>(PREFIX + '/hashtag'); +} diff --git a/src/components/SearchPage/SearchResultBox.tsx b/src/components/SearchPage/SearchResultBox.tsx index fa2bea5..59ae143 100644 --- a/src/components/SearchPage/SearchResultBox.tsx +++ b/src/components/SearchPage/SearchResultBox.tsx @@ -1,26 +1,36 @@ +import { IVideo } from '@/models/search'; import Styled from '@/styles/SearchResult'; +import React from 'react'; -const SearchResultBox = () => { +interface SearchResultBoxProp { + video : IVideo +} +const SearchResultBox : React.FC= ({video}) => { + const date = video.created_at.toString().split('T')[0].split('-'); return (
- 여울 + {video.user} - 2024년 1월 1일 + + {`${date[0]}년 ${date[1]}월 ${date[2]}일`} +
-
메조미디어가 본 내년 미디어 트렌드는…생성AI·광고없는 구독
-
2024 광고 시장의 현황
-
올해 마크색 테스트IT업계의 가장 큰 화제는 단연코 생성형 AI라고 할 수 있겠습니다. 2022년 11월, OpenAI가 출시한 ChatGPT는 멀게만 느껴졌던 AI 기술을 우리의 실생활에 밀접한 서비스로 바꾸었죠. 그리고 이제는 디지털 광고 영역도dsad 우리모두화이팅
+
{video.title}
+
{video.description}
+
{video.content}
- #마케팅팅팅 - #트렌드 - #기획 + {video.tag.map((item, index) => + {item.name} + )}
-
+
+ +
); } diff --git a/src/pages/SearchResultPage.tsx b/src/pages/SearchResultPage.tsx index cdc504f..2665fc6 100644 --- a/src/pages/SearchResultPage.tsx +++ b/src/pages/SearchResultPage.tsx @@ -6,50 +6,76 @@ import { useLocation } from "react-router-dom"; import Styled from "@/styles/SearchResult"; import TagInput from "@/components/SearchPage/SearchComponent"; import SearchNotFound from "@/components/SearchPage/SearchNotFound"; -import { escapeHTML } from "@/utils/string"; +import axios, { AxiosError } from "axios"; +import { IVideo } from "@/models/search"; + +import SearchResultBox from "@/components/SearchPage/SearchResultBox"; const SearchResult = () => { const [tags, setTags] = useState([]); const [input, setInput] = useState(''); const [searchType, setSearchType] = useState(true); // True : keyword | False : hashTag - const [isScrolling, ,startScrolling,,] = useBoolean(false); - const [loading, setLoading] = useState(Boolean); - const [data, setData] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(false); + const [data, setData] = useState([]); + const [count, setCount] = useState(0); const location = useLocation(); - + const dataDuplicateHandler = (videos : IVideo[]) => { + const newData = videos.filter((value) => { + return !data.some((item) => item.video_id === value.video_id); + }); + + setData(data.concat(newData)); + } useEffect(() => { - const crollLoc = () => { - try { - const searchParams = new URLSearchParams(location.search); - const type = searchParams.get('type'); - const data = searchParams.get('value'); - if (type === 'keyword' && data) { - setInput(data); + const searchParams = new URLSearchParams(location.search); + setLoading(true); + switch(searchParams.get('type')) { + case 'keyword': setSearchType(true); - } else if (type === 'hashtag' && data) { - const initialTagList = data.split('&'); - setTags(initialTagList) + const inputValues = searchParams.get('value') as string; + setInput(inputValues); + + const handleSearchAPI = async () => { + try { + const storage = JSON.parse(localStorage.vino); + const keywords = inputValues.split('+'); + + const requests = keywords.map((value) => { + return axios.get('https://backend.vi-no.site/search/keyword/', { + params: { + keywordName: value + }, + headers: { + Authorization: `Bearer ${storage['user-token']}` + } + }); + }); + const responses = await Promise.all(requests); + responses.forEach((response) => { + dataDuplicateHandler(response.data.result.videos) + setCount((prev) => prev + 1); + }) + } catch (error) { + if (error instanceof AxiosError) { + setCount(0); + setError(true); + } + } + }; + handleSearchAPI(); + setLoading(false); + break; + case 'hashtag': + const tagValues = searchParams.get('value') as string; + setTags(tagValues.split('&')) setSearchType(false); - } - } catch (error) { - console.error('Error:', error); + break; + default: + // 기타 에러 } - } - const fetchApiData = async () => { - try { - setLoading(true); - - setLoading(false); - return undefined; - } catch (notFound) { - setLoading(false); - return notFound; - } - } - - crollLoc(); - }, [location]) + }, []) if(loading){ @@ -61,8 +87,7 @@ const SearchResult = () => {
@@ -76,12 +101,16 @@ const SearchResult = () => {
-
+
- 총 0개의 영상이 발견되었어요! + {(count !== 0) ? 총 {count}개의 영상이 발견되었어요! : ''}
- + {error ? + : + data.map((item, index) => + ) + }
From 5de2d0ba6aac0c901285cbe88ca50cdba9920d91 Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Thu, 8 Feb 2024 21:54:22 +0900 Subject: [PATCH 10/13] =?UTF-8?q?api=20=EC=97=B0=EA=B2=B0,=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EB=B6=84=EB=A6=ACx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SearchPage/SearchResultBox.tsx | 16 ++- src/pages/SearchPage.tsx | 1 - src/pages/SearchResultPage.tsx | 131 +++++++++++++----- src/styles/SearchComponent.ts | 1 - src/styles/SearchResult.ts | 9 +- 5 files changed, 117 insertions(+), 41 deletions(-) diff --git a/src/components/SearchPage/SearchResultBox.tsx b/src/components/SearchPage/SearchResultBox.tsx index 59ae143..21c7731 100644 --- a/src/components/SearchPage/SearchResultBox.tsx +++ b/src/components/SearchPage/SearchResultBox.tsx @@ -1,26 +1,30 @@ import { IVideo } from '@/models/search'; import Styled from '@/styles/SearchResult'; -import React from 'react'; +import React, { ImgHTMLAttributes } from 'react'; interface SearchResultBoxProp { video : IVideo } const SearchResultBox : React.FC= ({video}) => { const date = video.created_at.toString().split('T')[0].split('-'); + const handleImg = (event : React.SyntheticEvent) => { + const target = event.target as HTMLImageElement; + target.style.display = 'none'; + } return (
- {video.user} + {video.user} {`${date[0]}년 ${date[1]}월 ${date[2]}일`}
-
{video.title}
-
{video.description}
-
{video.content}
+
+
+
{video.tag.map((item, index) => @@ -29,7 +33,7 @@ const SearchResultBox : React.FC= ({video}) => {
- + handleImg(event)}>
); diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx index d9ede2f..53db40f 100644 --- a/src/pages/SearchPage.tsx +++ b/src/pages/SearchPage.tsx @@ -5,7 +5,6 @@ import SearchIcon from '@/assets/icons/search.svg?react'; import { useState } from 'react'; import TagInput from '@/components/SearchPage/SearchComponent'; import { useNavigate, createSearchParams } from 'react-router-dom'; -const baseURL = 'https://backend.vi-no.site'; const SearchPage = () => { const [tags, setTags] = useState([]); diff --git a/src/pages/SearchResultPage.tsx b/src/pages/SearchResultPage.tsx index 2665fc6..d83c006 100644 --- a/src/pages/SearchResultPage.tsx +++ b/src/pages/SearchResultPage.tsx @@ -1,13 +1,13 @@ - -import { useState, useEffect, useMemo } from "react"; +import { escapeHTML } from "@/utils/string"; +import { useState, useEffect} from "react"; import SearchIcon from '@/assets/icons/search.svg?react' -import useBoolean from "@/hooks/useBoolean"; -import { useLocation } from "react-router-dom"; +import { createSearchParams, useLocation } from "react-router-dom"; import Styled from "@/styles/SearchResult"; import TagInput from "@/components/SearchPage/SearchComponent"; import SearchNotFound from "@/components/SearchPage/SearchNotFound"; import axios, { AxiosError } from "axios"; import { IVideo } from "@/models/search"; +import { useNavigate } from "react-router-dom"; import SearchResultBox from "@/components/SearchPage/SearchResultBox"; @@ -16,20 +16,15 @@ const SearchResult = () => { const [input, setInput] = useState(''); const [searchType, setSearchType] = useState(true); // True : keyword | False : hashTag const [loading, setLoading] = useState(false); - const [error, setError] = useState(false); + const [errormsg, setErrormsg] = useState(''); const [data, setData] = useState([]); - const [count, setCount] = useState(0); const location = useLocation(); + const searchNav = useNavigate(); + - const dataDuplicateHandler = (videos : IVideo[]) => { - const newData = videos.filter((value) => { - return !data.some((item) => item.video_id === value.video_id); - }); - - setData(data.concat(newData)); - } useEffect(() => { const searchParams = new URLSearchParams(location.search); + const storage = JSON.parse(localStorage.vino); setLoading(true); switch(searchParams.get('type')) { case 'keyword': @@ -37,11 +32,9 @@ const SearchResult = () => { const inputValues = searchParams.get('value') as string; setInput(inputValues); - const handleSearchAPI = async () => { + const handleSearchKeyAPI = async () => { try { - const storage = JSON.parse(localStorage.vino); - const keywords = inputValues.split('+'); - + const keywords = inputValues.split(' '); const requests = keywords.map((value) => { return axios.get('https://backend.vi-no.site/search/keyword/', { params: { @@ -54,33 +47,109 @@ const SearchResult = () => { }); const responses = await Promise.all(requests); responses.forEach((response) => { - dataDuplicateHandler(response.data.result.videos) - setCount((prev) => prev + 1); + dataDuplicateHandler(response.data.result.videos, inputValues) }) + } catch (error) { - if (error instanceof AxiosError) { - setCount(0); - setError(true); - } + + } finally { + setLoading(false); } }; - handleSearchAPI(); - setLoading(false); + handleSearchKeyAPI(); + if(data.length === 0){ + setErrormsg(inputValues) + } break; case 'hashtag': const tagValues = searchParams.get('value') as string; setTags(tagValues.split('&')) setSearchType(false); + + const handleSearchTagAPI = async () => { + try { + const requests = tagValues.split('&').map((value) => { + return axios.get('https://backend.vi-no.site/search/hashtag/', { + params: { + hashtagName : value.replace('#','') + }, + headers: { + Authorization: `Bearer ${storage['user-token']}` + } + }); + }); + + const responses = await Promise.all(requests); + responses.forEach((response) => { + dataDuplicateHandler(response.data.result.videos, tagValues.replace('#', '')) + }) + + } catch (error) { + + } finally { + setLoading(false); + } + } + handleSearchTagAPI(); + if(data.length === 0){ + setErrormsg(tagValues.replace('&', ' ')) + } break; + default: // 기타 에러 } - }, []) + }, [location.search]) + + const formatContent = (content : string, keyword : string) => { + if (keyword.trim() !== '') { + content = content + .split(keyword) + .map((s) => escapeHTML(s)) + .join(`${escapeHTML(keyword)}`); + } else { + content = escapeHTML(content); + } + + content = content.replace(/\n/g, '
'); + + return content; + }; + + const dataDuplicateHandler = (videos : IVideo[], check : string) => { + const newData = videos.filter((value) => { + return !data.some((item) => item.video_id === value.video_id); + }).map((video) => { + // video의 content 부분을 formatContent 함수를 이용해 변형 + const formattedContent = formatContent(video.content, check); + const formattedTitle = formatContent(video.title, check); + const formattedDescription = formatContent(video.description, check) + + return { + ...video, + title: formattedTitle, + description : formattedDescription, + content: formattedContent + }; + }); + setData(data.concat(newData)); + } + 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 ( -
스켈레톤 페이지
+
스켈레톤 페이지
) } return ( @@ -96,18 +165,18 @@ const SearchResult = () => {
- +
- {(count !== 0) ? 총 {count}개의 영상이 발견되었어요! : ''} + {(data.length !== 0) ? 총 {data.length}개의 영상이 발견되었어요! : ''}
- {error ? - : + {data.length === 0 ? + : data.map((item, index) => ) } diff --git a/src/styles/SearchComponent.ts b/src/styles/SearchComponent.ts index 9562365..75936fb 100644 --- a/src/styles/SearchComponent.ts +++ b/src/styles/SearchComponent.ts @@ -32,7 +32,6 @@ const Container = styled.div` gap: 13px; max-width: calc(100% - 10px); position: relative; - z-index: 1; outline: 0; background : ${(props) => props.theme.color.white}; ${(props) => props.theme.typography.Body3}; diff --git a/src/styles/SearchResult.ts b/src/styles/SearchResult.ts index 5a4afb8..e10f5a2 100644 --- a/src/styles/SearchResult.ts +++ b/src/styles/SearchResult.ts @@ -2,6 +2,7 @@ import styled from "styled-components"; const Container = styled.div` display : flex; + flex : 1 1 auto; flex-direction : column; & mark { @@ -132,7 +133,7 @@ const VideoCard = styled.div` flex-direction: row; justify-content: center; align-items: center; - padding: 0px; + padding: 0px 0px 0px 24px; gap: 8px; flex: none; @@ -141,7 +142,7 @@ const VideoCard = styled.div` } & span.userName { - + ${(props) => props.theme.typography.Caption1}; color: ${(props) => props.theme.color.gray300}; flex: none; @@ -235,6 +236,10 @@ const VideoCard = styled.div` align-self: stretch; flex-grow: 0; } + & img { + border : none; + border-radius : 0px 16px 16px 0px; + } ` const hashtagBox = styled.div` display: flex; From 1dee84e7e72c53377e06386cffefc366388bc8ad Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Thu, 8 Feb 2024 23:22:49 +0900 Subject: [PATCH 11/13] search api --- src/apis/search.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/apis/search.ts b/src/apis/search.ts index 875f428..73074cb 100644 --- a/src/apis/search.ts +++ b/src/apis/search.ts @@ -1,15 +1,11 @@ import { APIResponse } from '@/models/config/axios'; import axios from './config/instance'; -import { SearchKeywordRequest, SearchResponse } from '@/models/search'; const PREFIX = '/search'; -export const searchKeyowrdAPI = (keyword : string) => { - return axios.get>(PREFIX + '/keyword/', { - params : {keyName : keyword} +export const searchAPI = (type : string, keyword : string) => { + const paramType = type === 'keyword' ? 'keywordName' : 'hashtagName'; + return axios.get>(PREFIX + `/${type}/`, { + params : {[paramType] : keyword} }); -}; - -export const searchHashtagAPI = () => { - return axios.get>(PREFIX + '/hashtag'); -} +} \ No newline at end of file From 464509fac62d3885a441d82f3a598870340dfa6f Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Thu, 8 Feb 2024 23:23:11 +0900 Subject: [PATCH 12/13] search api interface --- src/models/search.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/models/search.ts b/src/models/search.ts index 61797d2..a57b4ea 100644 --- a/src/models/search.ts +++ b/src/models/search.ts @@ -1,10 +1,3 @@ -export interface SearchKeywordRequest { - keyword : string -}; - -export interface SearchHashtagRequest { - hashtag : string[] -}; export interface IName { name : string; @@ -21,7 +14,3 @@ export interface IVideo { user : string; tag : IName[]; } - -export interface SearchResponse { - videos : IVideo[]; - } \ No newline at end of file From f053d9dd7706386cc2d2533af99de7e72d1b6c1d Mon Sep 17 00:00:00 2001 From: KimSehyeoun Date: Thu, 8 Feb 2024 23:23:54 +0900 Subject: [PATCH 13/13] =?UTF-8?q?search=20api=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/SearchResultPage.tsx | 91 +++++++++++++--------------------- 1 file changed, 34 insertions(+), 57 deletions(-) diff --git a/src/pages/SearchResultPage.tsx b/src/pages/SearchResultPage.tsx index d83c006..d148f7d 100644 --- a/src/pages/SearchResultPage.tsx +++ b/src/pages/SearchResultPage.tsx @@ -1,12 +1,12 @@ import { escapeHTML } from "@/utils/string"; import { useState, useEffect} from "react"; -import SearchIcon from '@/assets/icons/search.svg?react' import { createSearchParams, useLocation } from "react-router-dom"; import Styled from "@/styles/SearchResult"; import TagInput from "@/components/SearchPage/SearchComponent"; import SearchNotFound from "@/components/SearchPage/SearchNotFound"; -import axios, { AxiosError } from "axios"; +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"; @@ -24,73 +24,28 @@ const SearchResult = () => { useEffect(() => { const searchParams = new URLSearchParams(location.search); - const storage = JSON.parse(localStorage.vino); + setLoading(true); + switch(searchParams.get('type')) { case 'keyword': setSearchType(true); const inputValues = searchParams.get('value') as string; + const keywordtype = searchParams.get('type') as string + setInput(inputValues); - - const handleSearchKeyAPI = async () => { - try { - const keywords = inputValues.split(' '); - const requests = keywords.map((value) => { - return axios.get('https://backend.vi-no.site/search/keyword/', { - params: { - keywordName: value - }, - headers: { - Authorization: `Bearer ${storage['user-token']}` - } - }); - }); - const responses = await Promise.all(requests); - responses.forEach((response) => { - dataDuplicateHandler(response.data.result.videos, inputValues) - }) - - } catch (error) { - - } finally { - setLoading(false); - } - }; - handleSearchKeyAPI(); + handleSearchAPI(inputValues, keywordtype, ' '); if(data.length === 0){ setErrormsg(inputValues) } break; case 'hashtag': const tagValues = searchParams.get('value') as string; + const tagtype = searchParams.get('type') as string + setTags(tagValues.split('&')) setSearchType(false); - - const handleSearchTagAPI = async () => { - try { - const requests = tagValues.split('&').map((value) => { - return axios.get('https://backend.vi-no.site/search/hashtag/', { - params: { - hashtagName : value.replace('#','') - }, - headers: { - Authorization: `Bearer ${storage['user-token']}` - } - }); - }); - - const responses = await Promise.all(requests); - responses.forEach((response) => { - dataDuplicateHandler(response.data.result.videos, tagValues.replace('#', '')) - }) - - } catch (error) { - - } finally { - setLoading(false); - } - } - handleSearchTagAPI(); + handleSearchAPI(tagValues, tagtype, '&'); if(data.length === 0){ setErrormsg(tagValues.replace('&', ' ')) } @@ -101,6 +56,29 @@ const SearchResult = () => { } }, [location.search]) + const handleSearchAPI = async (inputValues : string, type : string, splittype : string) => { + try { + const keywords = inputValues.split(splittype); + + const requests = keywords.map((value) => { + if (type === 'hashtag') { + value = value.replace('#', ''); + } + const searchData = (searchAPI(type, value)); + return searchData.then(value => value.data.result); + }) + const responses = await Promise.all(requests); + responses.forEach((response) => { + const ivideos = response.videos as IVideo[]; + dataDuplicateHandler(ivideos, inputValues); + }) + } catch (error) { + + } finally { + setLoading(false); + } + } + const formatContent = (content : string, keyword : string) => { if (keyword.trim() !== '') { content = content @@ -120,7 +98,6 @@ const SearchResult = () => { const newData = videos.filter((value) => { return !data.some((item) => item.video_id === value.video_id); }).map((video) => { - // video의 content 부분을 formatContent 함수를 이용해 변형 const formattedContent = formatContent(video.content, check); const formattedTitle = formatContent(video.title, check); const formattedDescription = formatContent(video.description, check) @@ -149,7 +126,7 @@ const SearchResult = () => { if(loading){ return ( -
스켈레톤 페이지
+
스켈레톤 페이지
) } return (