Criação da página de search (Elementos e estilo)

  1. Nós vamos começar pensando agora na renderização condicional. Nós vamos fazer a seguinte lógica: Se o resultado vier com o “.lenght” acima ou igual a 1, nós vamos retonar o map, se não, iremos retornar uma mensagem.

  2. Vamos fazer a verificação do lenght de cursos dentro da verificação.

    			<main>
            <HeaderAuth />
            {searchResult.lenght >= 1 ? (
              searchResult?.map((course) => (
                <div key={course.id}>
                  <p>{course.name}</p>
                </div>
              ))
            ) : (
              <p className={styles.noSearchText}>Nenhum resultado encontrado!</p>
            )}
          </main>
    
  3. Agora, nós iremos fazer uma verificação. Se o “res.data.courses” tiver um lenght igual a 0, nós iremos setar o “searchRender” como falso, para então aparecer a mensagem.

    const searchCourses = async () => {
        if (typeof searchName === "string") {
          const res = await courseService.getSearch(searchName);
    
          setSearchResult(res.data.courses);
    
          if (res.data.courses.length === 0) {
            setSearchRender(false);
          }
        }
      };
    
  4. Podemos então testar, veremos que quando não tem, ele retorna a mensagem certinha. Vamos fazer uma modificação visual simples, para que ele não fique tão pequeno e feio.

    1. Essa modificação vai ficar me “search.module.scss”
    .noSearchText {
      text-align: center;
      padding: 20px;
      font-size: 24px;
      font-weight: bold;
    }
    
  5. Nós iremos agora lá na pasta “components”, iremos lá criar uma pasta chamada “searchCard”, e dentro dela já colocar um “index.tsx” e um “styles.module.scss”

    import styles from "./styles.module.scss";
    
    const SearchCard = function () {
      return <></>;
    };
    
    export default SearchCard;
    
  6. Nós iremos criar uma props chamada “course”, faremos algo parecido com o que fizemos em “slideCard”

    interface props {
      course: CourseType;
    }
    
    const SearchCard = function ({ course }: props) {
      return <></>;
    };
    
  7. Agora, nós faremos um card que vai armazenar: Thumb, título, descrição e link para ir para o curso. Será muito similar ao que fizemos no slide, o que vai mudar de fato será o visual.

    		<>
          <Link href={`/courses/${course.id}`}>
            <div className={styles.searchCard}>
              <img src={`${process.env.NEXT_PUBLIC_BASEURL}/${course.thumbnailUrl}`} alt={course.name} className={styles.searchCardImg}/>
              <p className={styles.searchCardTitle}>{course.name}</p>
              <p className={styles.searchCardDescription}>{course.synopsis}</p>
            </div>
          </Link>
        </>
    
  8. Agora, nós iremos lá onde estamos fazendo o map para o search, e iremos colocar isso como retorno. Vamos também colocar o nosso map dentro de um container, onde mais para frente iremos colocar um display flex nele.

    			<main>
            <HeaderAuth />
            {searchResult.length >= 1 ? (
              <Container>
                {searchResult?.map((course) => (
                  <SearchCard key={course.id} course={course} />
                ))}
              </Container>
            ) : (
              <p className={styles.noSearchText}>Nenhum resultado encontrado!</p>
            )}
          </main>
    
  9. Podemos testar e ver que está funcionando, vemos que os cursos estão funcionando, só falta ajeitarmos esse visual para ficar 100%. Vamos começar com algo básico, para vermos melhor o retorno que estamos tendo.

    @import "../../../styles/colors.module.scss";
    .searchCard {
      width: 320px;
      height: 350px;
      border: 1px solid $darkGray;
      overflow: hidden;
      text-overflow: clip;
      cursor: pointer;
    }
    .searchCardImg {
      width: 100%;
      height: 190px;
    }
    
  10. Agora no navegador, já temos um belo retorno visual, nós vamos então fazer agora a manipulação dos textos e depois adicionar detalhe aos cards.

    .searchCardTitle {
      font-size: 20px;
      font-weight: bold;
      padding: 10px 20px;
    }
    .searchCardDescription {
      color: $lightGray;
      padding: 0px 20px;
      font-size: 18px;
    }
    
  11. Agora, nós iremos fazer um hover básico nos nossos cards, para que eles tenham um efeito da borda mudando de cor, também aumentando a altura do card, para vermos que tem uma decrição a mais do que vemos.

    .searchCard {
      width: 320px;
      height: 400px;
      border: 1px solid $darkGray;
      overflow: hidden;
      text-overflow: clip;
      cursor: pointer;
    
      transition: 0.4s;
      &:hover {
        border-color: $lightRed;
        height: 416px;
      }
    }
    .searchCardTitle {
      font-size: 20px;
      font-weight: bold;
      padding: 10px 20px;
      transition: 0.4s;
    }
    
  12. Nós podemos ver no navegador que está funcionando, mas está estranho. Nós iremos então fazer com que o container ganhe um display flex, para que fiquem lado a lado e não fique estranho como está agora.

    					<Container className="d-flex flex-wrap justify-content-center gap-5 py-4">
                {searchResult?.map((course) => (
                  <SearchCard key={course.id} course={course} />
                ))}
              </Container>
    
  13. Agora, nós precisamos apenas colocar o footer, e depois disso iremos colocar um background no footer e no header preto, que nem fizemos na página de dados.

    			<main>
            <div className={styles.header}>
              <HeaderAuth />
            </div>
            {searchResult.length >= 1 ? (
                <Container className="d-flex flex-wrap justify-content-center gap-5 py-4">
                  {searchResult?.map((course) => (
                    <SearchCard key={course.id} course={course} />
                  ))}
                </Container>
              ) : (
                <p className={styles.noSearchText}>Nenhum resultado encontrado!</p>
              )}
            <div className={styles.footer}>
              <Footer />
            </div>
          </main>
    
  14. Vamos então colocar os backgrounds.

    .header {
      background-color: black;
    }
    .footer {
      background-color: black;
    }
    
  15. Por último, nós iremos em “search.tsx” para colocarmos um nome dinâmico no nosso head. Nós iremos mudar o “title” para o que o usuário digitar

    			<Head>
            <title>Onebitflix - {searchName}</title>
            <link rel="shortcut icon" href="/favicon.svg" type="image/x-icon" />
          </Head>
    

Responsividade da seção

  1. Nossa responsividade será bem básica aqui, nós podemos ver que todos os cards vão se adaptando de acordo com a tela, pois temos o display flex. Mas a partir de “334px”, o nosso texto dentro de card fica estranho, vamos alterar ele.

    @media (max-width: 334px) {
      .searchCardTitle {
        font-size: 16px;
      }
      .searchCardDescription {
        font-size: 14px;
      }
    }
    
  2. Agora, uma coisa relacionada a página em si, é que, caso a nossa página retorne o parágrafo informando erro no conteúdo, o footer vai ter um bug e ficar próximo a ele. Nós iremos manipular isso, iremos primeiro colocar um “className” no “main” e também iremos envolver o nosso map com um section, para podermos utilizar o flex para deixarmos o footer sempre colado na parte baixa da nossa página.

    			<main className={styles.main}>
            <div className={styles.header}>
              <HeaderAuth />
            </div>
            <section className={styles.mainContent}>
              {searchResult.length >= 1 ? (
                <Container className="d-flex flex-wrap justify-content-center gap-5 py-4">
                  {searchResult?.map((course) => (
                    <SearchCard key={course.id} course={course} />
                  ))}
                </Container>
              ) : (
                <p className={styles.noSearchText}>Nenhum resultado encontrado!</p>
              )}
            </section>
            <div className={styles.footer}>
              <Footer />
            </div>
          </main>