Criação do visual da página de curso (Elementos e estilo)

  1. Nós iremos agora fazer a manipulação da página de curso. Nós iremos começar retornando as informações do curso, depois iremos partir para episódios.

  2. Iremos começar então criando uma seção exclusiva para a imagem do curso. Dentro dessa div nós iremos colocar o nosso header.

    <div style={{}}>
    	<HeaderAuth />
    </div>
    
  3. Nós iremos agora colocar um background e também uma altura mínima nessa nossa div, onde teremos a imagem, parecido com o que temos na “homeAuth”

    <main>
    	<div
      style={{
    	  backgroundImage: `linear-gradient(to bottom, #6666661a, #151515),
    	  url(${process.env.NEXT_PUBLIC_BASEURL}/${course?.thumbnailUrl})`,
        backgroundSize: "cover",
        backgroundPosition: "center",
    	  minHeight: "450px",
      }}
      >
    	  <HeaderAuth />
      </div>
    </main>
    
  4. Agora, nós faremos um container onde vai ficar todas as informações do curso.

    <Container className={styles.courseInfo}>
    	<p className={styles.courseTitle}>{course?.name}</p>
      <p className={styles.courseDescription}>{course?.synopsis}</p>
      <Button outline className={styles.courseBtn}>
    	  ASSISTIR AGORA!
        <img
        src="/buttonPlay.svg"
        alt="buttonImg"
        className={styles.buttonImg}
        />
      </Button>
    </Container>
    
  5. Nós vamos também colocar os ícones de like e de favorito abaixo do botão.

    <Container className={styles.courseInfo}>
    	<p className={styles.courseTitle}>{course?.name}</p>
      <p className={styles.courseDescription}>{course?.synopsis}</p>
      <Button outline className={styles.courseBtn}>
    	  ASSISTIR AGORA!
        <img
        src="/buttonPlay.svg"
        alt="buttonImg"
        className={styles.buttonImg}
        />
      </Button>
    	<div className={styles.interactions}>
    		<img
        src="/course/iconLike.svg"
        alt="likeImage"
        className={styles.interactionImages}
        onClick={handleLikeCourse}
        />
        <img
        onClick={handleFavCourse}
        src="/course/iconAddFav.svg"
        alt="addFav"
        className={styles.interactionImages}
        />
    	</div>
    </Container>
    
  6. Podemos ver que temos retorno visual na tela, vamos então começar a manipular ele. Nós iremos colocar um pequeno margintop negativo para os nossos textos ficarem em cima da transição do degradê.

    @import "../styles/colors.module.scss";
    .courseInfo {
      margin-top: -120px;
    }
    
  7. Agora, podemos manipular os textos e os botões de interação.

    .courseTitle {
      font-size: 40px;
      font-weight: bold;
      padding-bottom: 25px;
      width: 700px;
    }
    .courseDescription {
      color: $lightGray;
      width: 650px;
      padding-bottom: 25px;
    }
    .courseBtn {
      display: flex;
      align-items: center;
      gap: 15px;
      font-weight: bold;
      font-size: 14px;
      padding: 10px 35px;
      color: white;
      border-color: $lightRed;
      &:hover {
        border-color: $darkRed;
        color: $lightGray;
        background-color: transparent;
      }
    }
    .buttonImg {
      width: 10px;
      margin: 0;
      padding: 0;
    }
    .interactions {
      display: flex;
      gap: 20px;
      margin: 26px 0px;
    }
    .interactionImages {
      width: 36px;
      cursor: pointer;
    }	
    
  8. Vamos agora criar dois states que vão começar como falso. Vamos criar um para like e outro para favorito.

    const [liked, setLiked] = useState(false);
    const [favorited, setFavorited] = useState(false);
    
  9. E nós vamos colocar dentro de “getCouse” os sets para esses states. Nós temos duas coisas dentro do objeto do curso, que é o “liked” e “favorited”, sendo boleanos. Ou seja, vamos saber se o usuário já deu like ou favoritou esse curso.

    const getCourse = async function () {
    	if (typeof id !== "string") return;
    
      const res = await courseService.getEpisodes(id);
      if (res.status === 200) {
    	  setCourse(res.data);
        setLiked(res.data.liked);
        setFavorited(res.data.favorited);
      }
    };
    
  10. Agora, quando a página de curso for carregada, nós vmaos conseguir verificar se o curso está com like e favoritado. Com isso, nós vamos fazer uma renderização condicional para o nosso curso. Começando pelo like, vamos verificar se o like está como falso, se estiver, vamos mostrar a imagem do coração vazio, se não estiver, o coração cheio.

    {liked === false ? (
    	<img
    	  src="/course/iconLike.svg"
        alt="likeImage"
        className={styles.interactionImages}
        onClick={handleLikeCourse}
      />
    ) : (
    	<img
    	  src="/course/iconLiked.svg"
        alt="likedImage"
        className={styles.interactionImages}
        onClick={handleLikeCourse}
      />
    )}
    
  11. Nós vamos então fazer a mesma coisa com favoritos. Se for falso, iremos renderizar a normal.

    {favorited === false ? (
    	<img
    	  onClick={handleFavCourse}
        src="/course/iconAddFav.svg"
        alt="addFav"
        className={styles.interactionImages}
      />
    ) : (
    	<img
    	  onClick={handleFavCourse}
        src="/course/iconFavorited.svg"
        alt="favorited"
        className={styles.interactionImages}
    	/>
    )}
    
  12. Agora nós temos temos as imagens prontas. Precisamos apenas criar os handles para transformar o like e o favorito do curso. Nós vamos primeiro criar o handle de like. Vamos fazer uma função assíncrona, que vai ter uma verificação. Se o esado estiver como like, vamos remover o like e dar um set para ele de falso. Vamos então botar um else fazendo o inverso.

    const handleLikeCourse = async () => {
    	if (liked === true) {
    	  await courseService.removeLike(id);
        setLiked(false);
      } else {
    	  await courseService.like(id);
        setLiked(true);
      }
    };
    
  13. Podemos até testar e ver que está funcionando. Vamos fazer a mesma coisa com favorito. Do mesmo estilo.

    const handleFavCourse = async () => {
    	if (favorited === true) {
    	  await courseService.removeFav(id);
        setFavorited(false);
      } else {
    	  await courseService.addToFav(id);
        setFavorited(true);
    	}
    };
    
  14. Nós vamos poder testar os dois agora. Até mesmo sair do curso, ir no local dos slides de favortos e vermos que estamos tendo retorno dos cursos.

  15. Agora, nós iremos começar colocando a quantidade de episódios existentes nesse curso. Nós estaremos colocar quando episódios e o lenght desses episódios são opcionais, por que um curso pode não ter episódios, então ambos serão opcionais.

    <Container className={styles.episodeInfo}>
    	<p className={styles.episodeDivision}>EPISÓDIOS</p>
      <p className={styles.episodeLength}>
    	  {course?.episodes?.length} episódios
      </p>
    </Container>
    
  16. Conseguimos ver que ele trouxe um retorno da quantidade de episódios no curso. Agora, nós faremos um map para retornar o título do episódio por enquanto, faremos ser opcional também.

    <Container className={styles.episodeInfo}>
    	<p className={styles.episodeDivision}>EPISÓDIOS</p>
      <p className={styles.episodeLength}>
    	  {course?.episodes?length} episódios
      </p>
      {course?.episodes?.map((episode) => (
    	  <>
    	    <p>{episode.name}</p>
        </>
      ))}
    </Container>
    
  17. Nós vamos fazer então um component para conter a lista de episódios. Podemos então ir na pasta “components” criar um arquivo chamado “episodesList” e criar dentro dele index e scss.

    import styles from "./styles.module.scss";
    
    const EpisodeList = function () {
      return <></>;
    };
    
    export default EpisodeList;
    
  18. Nós vamos agora fazer algo muito parecido com o que fizemos so searchCard, nós iremos fazer aqui uma interface props para colocarmos o episódio que vai vir do map.

    import styles from "./styles.module.scss";
    import { EpisodeType } from "../../services/courseService";
    
    interface props {
      episode: EpisodeType;
    }
    
    const EpisodeList = function ({ episode }: props) {
      return <></>;
    };
    
    export default EpisodeList;
    
  19. Nós iremos agora colocar 2 divisões, uma ficará com o número do episódio e com o tempo dele e outro vai ficar com título e descrição

    <>
    	<div className={styles.episodeCard}>
    	  <div className={styles.episodeOrderTime}>
    	    <p className={styles.episodeOrder}>Episódio Nº {episode.order}</p>
          <p className={styles.episodeTime}>{episode.secondsLong}</p>
        </div>
        <div className={styles.episodeTitleDescription}>
    	    <p className={styles.episodeTitle}>{episode.name}</p>
          <p className={styles.episodeDescription}>{episode.synopsis}</p>
        </div>
      </div>
    </>