Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature 022 : api 연동 #44

Merged
merged 15 commits into from
Feb 8, 2024
Merged
3 changes: 3 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import HomePage from '@/pages/HomePage';
// import GuestPage from './pages/GuestPage';
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 SignUpSuccessPage from '@/pages/SignUpSuccessPage';
Expand Down Expand Up @@ -51,7 +52,9 @@ const App = () => {
{userToken && (
<>
<Route path="/search" element={<SearchPage />} />
<Route path="/search/result" element={<SearchResult />} />
<Route path="/profile" element={<ProfilePage />} />

</>
)}

Expand Down
11 changes: 11 additions & 0 deletions src/apis/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { APIResponse } from '@/models/config/axios';
import axios from './config/instance';

const PREFIX = '/search';

export const searchAPI = (type : string, keyword : string) => {
const paramType = type === 'keyword' ? 'keywordName' : 'hashtagName';
return axios.get<APIResponse<any>>(PREFIX + `/${type}/`, {
params : {[paramType] : keyword}
});
}
3 changes: 1 addition & 2 deletions src/apis/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export const checkEmailAPI = (data: CheckEmailRequest) => {
data,
);
};

export const joinAPI = (data: JoinRequest) => {
return axios.post<APIResponse<JoinResponse>>(PREFIX + '/join', data);
};
};
8 changes: 8 additions & 0 deletions src/assets/icons/search-notfound.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions src/components/SearchPage/SearchNotFound.tsx
Original file line number Diff line number Diff line change
@@ -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<NotFoundprop> = ( {input} ) => {
return (
<styled.SearchNotFoundContainer>
<SearchNotFoundIcon width={156} height={156}/>
<div className='text'> <span className='user'>{input}</span>에 대한 검색 결과가 없어요</div>
<button>더 많은 영상 변환하기</button>
</styled.SearchNotFoundContainer>
);
}


export default SearchNotFound;
42 changes: 42 additions & 0 deletions src/components/SearchPage/SearchResultBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { IVideo } from '@/models/search';
import Styled from '@/styles/SearchResult';
import React, { ImgHTMLAttributes } from 'react';

Check failure on line 3 in src/components/SearchPage/SearchResultBox.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

'ImgHTMLAttributes' is declared but its value is never read.

interface SearchResultBoxProp {
video : IVideo
}
const SearchResultBox : React.FC<SearchResultBoxProp>= ({video}) => {
const date = video.created_at.toString().split('T')[0].split('-');
const handleImg = (event : React.SyntheticEvent<HTMLImageElement, Event>) => {
const target = event.target as HTMLImageElement;
target.style.display = 'none';
}
return (
<Styled.VideoCard style={{width : '910px', height : '254px'}}>
<div className="main" style={{width : '670px', height : '254px'}}>
<div className="user" style={{width : '114px', height : '20px'}}>
<span className="userName" style={{ height : '19px'}}>{video.user}</span>
<span className='contour' style={{width : '0px', height : '12px'}}></span>
<span className="userDate" style={{height :'19px'}}>
{`${date[0]}년 ${date[1]}월 ${date[2]}일`}
</span>
</div>
<div className="content" style={{width : '648px', height : '108px'}}>
<div className="title" style={{width : '648px', height : '26px'}} dangerouslySetInnerHTML={{__html : video.title}}></div>
<div className="subtitle" style={{width : '648px', height : '22px'}} dangerouslySetInnerHTML={{__html : video.description}}></div>
<div className="subcontent" style={{width : '648px' , height : '44px'}} dangerouslySetInnerHTML={{__html : video.content}}></div>
</div>
<div className='hashtag' style={{maxWidth : '648px',height : '31px'}}>
{video.tag.map((item, index) =>
<Styled.hashtagBox key = {index}>{item.name}</Styled.hashtagBox>
)}
</div>
</div>
<div className="imgBox" style={{width : '213px', height : '254px'}}>
<img src={video.image} style={{width : '213px', height : '254px'}} onError={(event) => handleImg(event)}></img>
</div>
</Styled.VideoCard>
);
}

export default SearchResultBox;
16 changes: 16 additions & 0 deletions src/models/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

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[];
}
159 changes: 60 additions & 99 deletions src/pages/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,112 +4,73 @@

import { useState } from 'react';
import TagInput from '@/components/SearchPage/SearchComponent';
import { useNavigate, createSearchParams } from 'react-router-dom';

const SearchPage = () => {
const [tags, setTags] = useState<string[]>([]);
const [input, setInput] = useState<string>('');
const [searchType, setSearchType] = useState(true); // True : keyword | False : hashTag
const [userHashTag] = useState<string[]>([
'기획',
'광고',
'마케팅',
'트렌드',
'기업',
'광고',
'마케팅',
'트렌드',
'기업',
'광고',
]); // 사용자의 해시태그 데이터 10개 <임의 데이터>
const [selectedHashtags, setSelectedHashtags] = useState<string[]>([]);
const [tags, setTags] = useState<string[]>([]);
const [input, setInput] = useState<string>('');
const [searchType, setSearchType] = useState(true); // True : keyword | False : hashTag
const [userHashTag, SetUserHashTag] = useState<string[]>(["기획", "광고", "마케팅", "트렌드", "기업", "광고", "마케팅", "트렌드", "기업", "광고"]); // 사용자의 해시태그 데이터 10개 <임의 데이터>

Check failure on line 13 in src/pages/SearchPage.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

'SetUserHashTag' is declared but its value is never read.
const [selectedHashtags, setSelectedHashtags] = useState<string[]>([]);
const searchNav = useNavigate();

const handleHashtagBox = (value: string) => {
const isSelected = selectedHashtags.includes(value);
setSelectedHashtags((prev) =>
isSelected ? prev.filter((idx) => idx !== value) : [...prev, value],
);
isSelected
? setTags(tags.filter((prev) => prev !== '#' + value))
: setTags([...tags, `#${value}`]);
setSearchType(false); // 박스를 클릭했을 때도 type 변경
};
const handleHashtagBox = (value : string) => {
const isSelected = selectedHashtags.includes(value);
setSelectedHashtags(prev =>
isSelected ? prev.filter(idx => idx !== value) : [...prev, value]
);
isSelected ? setTags(tags.filter((prev) => prev !== '#'+value)) : setTags([...tags, `#${value}`]);
setSearchType(false); // 박스를 클릭했을 때도 type 변경
}

return (
<Container style={{ width: '100vw', height: '100vh' }}>
<div className="wrap" style={{ width: '908px', height: '450px' }}>
<div className="search" style={{ width: '908px', height: '288px' }}>
<div
className="search-inner"
style={{ width: '908px', height: '204px' }}
>
<div className="header" style={{ width: '508px', height: '92px' }}>
<span
className="header3"
style={{ width: '508px', height: '58px' }}
>
찾고 싶은 키워드가 있나요?
</span>
<span
className="header5"
style={{ width: '508px', height: '26px' }}
>
찾고자 하는 키워드를 검색하면 관련 영상을 찾아드릴게요
</span>
</div>
const handleSearch = () => {
const params = {
type : searchType === true ? 'keyword' : 'hashtag',
value: searchType ? input : tags.join('&')
};

searchNav({
pathname : '/search/result',
search : `?${createSearchParams(params)}`
})
}

return (
<Container style={{width : '100vw', height : '100vh'}}>
<div className='wrap' style={{width : '908px', height : '450px'}}>
<div className="search" style={{width : '908px', height : '288px'}}>
<div className="search-inner" style={{width : '908px', height : '204px'}}>
<div className='header' style={{width : '508px', height : '92px'}}>
<span className='header3' style={{width: '508px', height: '58px'}}>찾고 싶은 키워드가 있나요?</span>
<span className='header5' style={{width: '508px', height: '26px'}}>찾고자 하는 키워드를 검색하면 관련 영상을 찾아드릴게요</span>
</div>

<div
className="inputwrap"
style={{ width: '908px', height: '72px' }}
>
<div
className="input-inner"
style={{ width: '861px', height: '36px' }}
>
<div
className="input"
style={{ width: '770px', height: '36px' }}
>
<SearchIcon width={36} height={36} />
<TagInput
tags={tags}
input={input}
searchType={searchType}
selectedHashtags={selectedHashtags}
setTags={setTags}
setInput={setInput}
setSearchType={setSearchType}
setSelectedHashtags={setSelectedHashtags}
/>
<div className='inputwrap' style={{width : '908px', height : '72px'}}>
<div className='input-inner' style={{width : '861px', height : '36px'}}>
<div className='input' style={{width : '770px', height : '36px'}}>
<SearchIcon width={36} height={36}/>
<TagInput tags={tags} input={input} searchType={searchType} selectedHashtags={selectedHashtags}
setTags={setTags} setInput={setInput} setSearchType={setSearchType} setSelectedHashtags={setSelectedHashtags}/>
</div>
<button className='search-btn' onClick={handleSearch} disabled={(input.length === 0 && tags.length === 0)} style={{width : '90px', height : '36px'}}>Search</button>
</div>
</div>

</div>
{(input.length === 0 && tags.length === 0)? <TooltipImg/> : ''}
</div>
<button
className="search-btn"
disabled={input.length === 0 && tags.length === 0}
style={{ width: '90px', height: '36px' }}
>
Search
</button>
</div>
</div>
</div>
{input.length === 0 && tags.length === 0 ? <TooltipImg /> : ''}
</div>

<div className="hashtag" style={{ width: '572px', height: '102px' }}>
{userHashTag.map((value: string, idx: number) => {
return (
<HashtagBox
key={idx}
onClick={() => handleHashtagBox(value)}
className={selectedHashtags.includes(value) ? 'toggle' : ''}
>
{'#' + value}
</HashtagBox>
);
})}
</div>
</div>
</Container>
);
<div className="hashtag" style={{width : '572px', height : '102px'}}>
{
userHashTag.map((value : string, idx : number) => {
return(<HashtagBox key={idx} onClick={() => handleHashtagBox(value)}
className={selectedHashtags.includes(value) ? 'toggle' : ''}>{'#' + value}</HashtagBox>)
})
}
</div>
</div>
</Container>
);
};

export default SearchPage;
Loading
Loading