티스토리 뷰

검색 쪽에서는 이제 디테일한 것만 남은 것 같다!!

 

그래도 내가 검색 파트는 처음부터 끝까지 해본다는 게 혹은 해보려고 한다는게 좋은 것 같다.

 

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;

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함