티스토리 뷰
검색 쪽에서는 이제 디테일한 것만 남은 것 같다!!
그래도 내가 검색 파트는 처음부터 끝까지 해본다는 게 혹은 해보려고 한다는게 좋은 것 같다.
1. 검색페이지에서 데이터베이스에 해당하는 값이 없으면 값이 없다는 것을 보여줘야한다.
2. 검색페이지에서 빈 값 검색을 하면 다시 검색 페이지로 오는 것
3. 메인페이지에서 검색창 부분 수정 & 키워드 검색 페이지로 넘기는 것
4. nav bar에 검색 탭을 만드는 것
5. 정말 시간되면 페이징까지 하는 것 (페이지 나누기? 무한 스크롤?)
우선 4번의 nav bar에 검색 탭 이름을 강의라고 하고 클릭 시 검색 페이지로 넘어가게 했다.
또한, 리로드까지 구현했다. 생각보다 나는 시간이 좀 걸렸다...
리로드하는 걸 해보니 2번의 빈 값을 검색했을 때 리로드 하는 건 금방 해결했다.
1번도 해결했고 1번 같은 경우 글씨를 작성하면 위 아래로 여백이 크게 생겨서 풋터가 위로 올라와서
풋터 밑에는 하얗게 보여서 위 아래로 여백을 좀 늘렸다.
import React, { ReactNode, useEffect, useState } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import { Box, Container, Flex, SimpleGrid, Input, Button, IconButton, useColorModeValue, background } from "@chakra-ui/react";
import { SearchIcon } from "@chakra-ui/icons"
import { Text } from "@chakra-ui/react";
import axios from "axios";
import ClassCard from "../../components/ClassCard";
import SectionTitle from "../../components/SectionTitle";
import ContentArea from "../../components/ContentArea";
import { API } from "../../../config"
// 강의 정보에 대한 타입 정의
type CourseInfo = {
title: string;
description: string;
classId: number;
thumbnailPath: string;
};
// 검색 정보에 대한 타입 정의
type CourseSearchInfo = {
title: string;
description: string;
courseId: number;
thumbnailPath: string;
tags: string;
userName: string;
}
const ClassCardList = ({ children }: { children: ReactNode }) => (
<SimpleGrid
columns={{ base: 1, sm: 2, md: 3 }}
spacing={5}
gridAutoRows={"1fr"}
borderColor={"none"}
>
{children}
</SimpleGrid>
);
function SearchPage() {
const location = useLocation();
const navigate = useNavigate();
// 최고의 결과를 저장할 상태
const [bestResults, setBestResults] = useState<CourseInfo[]>([]);
// 최신의 결과를 저장할 상태
const [newResults, setNewResults] = useState<CourseInfo[]>([]);
// 검색 결과를 저장할 상태
const [keyword, setKeyword] = useState<string>("");
const [searchResults, setSearchResults] = useState<CourseSearchInfo[]>([]);
// 검색 버튼 클릭 여부를 저장할 상태
const [isSearchButtonClick, setIsSearchButtonClick] = useState<boolean>(false);
// 페이지 로드 시 최고의 결과와 최신의 결과를 가져오는 useEffect
useEffect(() => {
handleBest();
handleNew();
}, []); // 페이지가 로드될 때 한 번만 실행
// 서버에서 최고의 결과를 가져오는 함수
const handleBest = () => {
axios.get(API.COURSE_LIST_BY_BEST)
.then((response) => {
setBestResults(response.data.data); // 최고의 결과를 state에 저장
})
.catch((error) => {
console.error('Error fetching best results', error);
});
};
// 서버에서 최신의 결과를 가져오는 함수
const handleNew = () => {
axios.get(API.COURSE_LIST_BY_NEW)
.then((response) => {
setNewResults(response.data.data); // 최신의 결과를 state에 저장
})
.catch((error) => {
console.error('Error fetching new results', error);
});
};
/* ******************** 검색 부분 ***************************/
// handleSearch 함수에서 검색어가 비어있는 경우 처리를 추가합니다.
const handleSearch = () => {
if (!keyword.trim()) { // 검색어가 비어있는 경우 처리
console.log("검색어를 입력하세요.");
// 빈 검색어일 경우 현재 페이지를 리로드하여 `/search`로 이동
window.location.reload();
return; // 빈 검색어일 경우 함수를 빠르게 종료
}
navigate(`/search?keyword=${keyword}`);
axios.get(API.COURSE_LIST_BY_SEARCH, {
params: {
keyword: keyword
},
})
.then((response) => {
setSearchResults(response.data.data); // response.data -> response.data.data 로 하니까 나온다....
console.log('Search results:', response.data); // 검색 결과를 콘솔에 출력
setIsSearchButtonClick(true); // 검색 버튼 클릭을 true로 설정
// 검색 결과가 나오면 bestResults와 newResults를 비워줍니다.
setBestResults([]);
setNewResults([]);
})
.catch((error) => {
console.error('Error fetching search results', error);
});
};
return (
<>
<ContentArea>
<Flex
flexDirection={"column"}
className={"content-wrapper"}
p={4}
width={"100%"}
gap={4}
>
<Box mx="auto" width="50%">
<Flex align="center" justify="center">
<input
type="text"
placeholder="검색어를 입력하세요"
value={keyword}
onChange={(event) => setKeyword(event.target.value)}
onKeyPress={(event) => {
if (event.key === "Enter") {
handleSearch();
}
}}
style={{ padding: "8px", fontSize: "16px", borderRadius: "999px", width: "100%", paddingLeft: "20px" }}
/>
<Button
onClick={handleSearch}
borderRadius="full"
bgColor={useColorModeValue("gray.200", "gray.700")}
_hover={{ bgColor: useColorModeValue("gray.300", "gray.600")}}
ml={2}
>
<SearchIcon />
</Button>
</Flex>
</Box>
{/* 검색 결과를 보여줄지 여부를 조건부 렌더링으로 설정 */}
{isSearchButtonClick && (
<>
{/* 실제 검색 결과가 있는 경우에만 표시 */}
{searchResults.length > 0 && (
<Box>
<SectionTitle title={"검색 결과"} />
<ClassCardList>
{searchResults.map((item, idx) => (
<ClassCard
key={idx}
title={item.title}
desc={item.description}
onClick={() => navigate(`/class/${item.courseId}`)}
imgSrc={item.thumbnailPath}
/>
))}
</ClassCardList>
</Box>
)}
{/* 검색 결과가 없을 때 메시지 표시 */}
{searchResults.length === 0 && (
<Box textAlign="center" my={100}>
<Text fontSize="3xl" fontWeight="bold" color="white">검색 결과가 없습니다.</Text>
<Box mt={250} />
</Box>
)}
</>
)}
{/* 최고의 결과 표시 */}
{bestResults.length > 0 && (
<Box>
<SectionTitle title={"BEST"} />
<ClassCardList>
{bestResults.map((item, idx) => (
<ClassCard
key={idx}
title={item.title}
desc={item.description}
onClick={() => navigate(`/class/${item.classId}`)}
imgSrc={item.thumbnailPath}
/>
))}
</ClassCardList>
</Box>
)}
{/* 최신의 결과 표시 */}
{newResults.length > 0 && (
<Box>
<SectionTitle title={"New"} />
<ClassCardList>
{newResults.map((item, idx) => (
<ClassCard
key={idx}
title={item.title}
desc={item.description}
onClick={() => navigate(`/class/${item.classId}`)}
imgSrc={item.thumbnailPath}
/>
))}
</ClassCardList>
</Box>
)}
</Flex>
</ContentArea>
</>
);
}
export default SearchPage;
'SeSAC_도봉캠퍼스 > 새싹_도봉캠퍼스_프로젝트 4' 카테고리의 다른 글
2024.04.21_프로젝트 4 (20 일차) (1) | 2024.04.22 |
---|---|
2024.04.20_프로젝트 4 (19 일차) (0) | 2024.04.20 |
2024.04.18_프로젝트 4 (17 일차) (0) | 2024.04.18 |
2024.04.17_프로젝트 4 (16 일차) (0) | 2024.04.18 |
2024.04.16_프로젝트 4 (15 일차) (0) | 2024.04.17 |