3
respostas

Projeto de conclusão de curso

Como a Mônica deixou espaços para fazermos algumas mudanças, eu aproveitei para treinar e melhorar um pouco a questão dos erros, tanto no tratamento quanto na prevenção.

  • conecta-api.js

    As mudanças que fiz são relacionadas ao tratamento de erros. Aqui teve uma pegadinha pra mim porque não sabia que o Error() construia um objeto. Por conta disso, eu tentei armazenar nele o status e a mensagem, em forma de objeto mesmo.

throw new Error({
        status,
        mensagem,
    })

Só que, ao fazer iss, dá um erro. O certo é fazer como está no código.

async function listaVideos () {
    const conexao = await fetch("http://localhost:3000/videos");
    const conexaoConvertida = await conexao.json();

    if(!conexao.ok) {
        let erro = new Error;
        erro.status = conexao.status;
        erro.mensagem = conexao.statusText;         
        throw erro;
    };

    return conexaoConvertida;
};

async function criaVideo (titulo, descricao, url, imagem) {
    const conexao = await fetch('http://localhost:3000/videos', {
        method: 'POST',
        headers: {
            'Content-type': 'application/json'
        },
        body: JSON.stringify({
            titulo: titulo,
            descricao: `${descricao} mil visualizações`,
            url: url,
            imagem: imagem
        })
    });

    if(!conexao.ok) {
        let erro = new Error;
        erro.status = conexao.status;
        erro.mensagem = conexao.statusText;         
        throw erro;        
    };

    const conexaoConvertida = conexao.json();
    return conexaoConvertida;
}

async function buscaVideos (termoDeBusca) {
    const conexao = await fetch(`http://localhost:3000/videos?q=${termoDeBusca}`);
    const conexaoConvertida = conexao.json();

    return conexaoConvertida;
}

export const conectaApi = {
    listaVideos,
    criaVideo,
    buscaVideos
};
  • mostrar-videos.js

    Como meu conhecimento sobre lidar com os erros de promises é pouco, eu preferi somente mostrar qual é o erro e sua mensagem.

// ---------- Lógica ----------
import { conectaApi } from "./conecta-api.js";

const lista = document.querySelector('[data-lista]');

listaVideo();

// ---------- Funções ----------

export default function constroiCard (titulo, descricao, url, imagem) {
    const video = document.createElement('li');
    video.classList.add = 'videos__item';
    video.innerHTML = `
    <iframe width="100%" height="72%" src="${url}"
    title="YouTube video player" frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
    allowfullscreen></iframe>
    <div class="descricao-video">
        <img src="${imagem}" alt="logo canal alura">
        <h3>${titulo}</h3>
        <p>${descricao}</p>
    </div>
    `
    return video
};

async function listaVideo() {
    try {
        const listaApi = await conectaApi.listaVideos();
        listaApi.forEach(elemento => lista.appendChild(constroiCard(elemento.titulo, elemento.descricao, elemento.url, elemento.imagem)));
    } catch (erro) {
        lista.style.display = 'block';
        lista.innerHTML = `<h2 class="mensagem__titulo">Não foi possível carregar a lista de vídeos.</h2><br>
        <p>Tipo do erro: ${erro.status}</p>
        <p>Mensagem: ${erro.mensagem}</p>
        `
    };
};
3 respostas
  • criar.video.js

    Nesse código eu mudei e inseri mais coisas.

    1. Uma delas foi uma verificação da url, de modo que, se a url não for do youtube e clicar em enviar, aparece um aviso informando que é necessário que seja um link extraído do yotube, evitando que outros tipos de links apareçam na lista de vídeos;
    2. Outra foi a compatibilização da url, uma vez que é necessário que o link tenha um padrão (como ter o embed). Então, mesmo que o link inserido não siga o que está no placeholder, há uma função que faz o ajuste, evitando um erro na hora de exibir o vídeo na lista;
    3. Além dessas, no tratamento de erro de envio, fiz com que aparecesse o mesmo aviso de status e mensagem, além de ter um botão para tentar novamente.
    4. A última mudança surge quando clica em tentar novamente. Os inputs voltam e já são preenchidos com a url, título e imagem. Para que isso fosse possível, eu armazenei no localStorage essas informações no momento da tentativa de envio, e as usei quando clica novamente. Para evitar que houvesse algum conflito posteriormente, eu fiz com que o localStorage fosse apagado depois do preenchimento.

Para que não houvesse conflito ao clicar no botão de enviar/tentar novamente, fiz uma condicicional com o dataset.erro.

// ---------- Lógica ----------
import { conectaApi } from "./conecta-api.js";

const formulario = document.querySelector('[data-formulario]');
const inputUrl = document.querySelector('[data-url]');
const inputTitulo = document.querySelector('[data-titulo]');
const inputImagem = document.querySelector('[data-imagem]');

formulario.addEventListener('submit', evento => {
    evento.preventDefault();

    if(formulario.dataset.erro === 'nao') {
        const novoVideo = montaFichaVideo();

        let verificacao = verificaUrl(novoVideo);

        verificacao ? criaVideo(novoVideo) : mostraAviso();
    };

    if (formulario.dataset.erro === 'sim') {
        tentaNovamente(evento);
    };
});

// ---------- Funções ----------

async function criaVideo(novoVideo) {

    novoVideo.url = compatibilizaUrl(novoVideo.url);

    try {
        await conectaApi.criaVideo(novoVideo.titulo, novoVideo.descricao, novoVideo.url, novoVideo.imagem);

        window.location.href = '../pages/envio-concluido.html';
    } catch (erro) {
        localStorage.setItem('dadosVideo', JSON.stringify(novoVideo));
        formulario.dataset.erro = 'sim';
        formulario.innerHTML = `
        <h2 class="mensagem__titulo">Não foi possível enviar o vídeo.</h2><br>
        <p class="mensagem__texto">Tipo do erro: ${erro.status}.</p>
        <p class="mensagem__texto">Mensagem: ${erro.mensagem}.</p>
        <button class="formulario__botao">Tentar novamente</button>
        `
    };
};

function montaFichaVideo() {
    return {
        url: inputUrl.value,
        titulo: inputTitulo.value,
        imagem: inputImagem.value
    }
};

function verificaUrl(novoVideo) {

    if (novoVideo.url.includes('https://youtu.be') || novoVideo.url.includes('https://www.youtube.com')) {
        return true;
    };

    return false;
}

function compatibilizaUrl(urlTeste) {
    if (urlTeste.includes('youtu.be')) {
        return urlTeste.replace('https://youtu.be/', 'https://www.youtube.com/embed/');
    };
    if (urlTeste.includes('watch?v=')) {
        return urlTeste.replace('watch?v=', 'embed/');
    };

    return urlTeste;
};

function mostraAviso() {
    const avisoErro = document.createElement('p');
    avisoErro.innerHTML = 'O link precisa ser do youtube.';
    avisoErro.classList.add('mensagem__texto');
    inputUrl.parentNode.appendChild(avisoErro);
};

function tentaNovamente () {
    const listaLocalStorage = JSON.parse(localStorage.getItem('dadosVideo'));

    formulario.dataset.erro='nao';
    formulario.innerHTML = `
    <h2 class="formulario__titulo">Envie um vídeo!</h3>
    <div class="formulario__campo">
        <label class="campo__etiqueta" for="url">Link embed</label>
        <input name="url" class="campo__escrita" required
            placeholder="Por exemplo: https://www.youtube.com/embed/FAY1K2aUg5g" id='url' data-url  value="${listaLocalStorage.url}"/>
    </div>


    <div class="formulario__campo">
        <label class="campo__etiqueta" for="titulo">Titulo do vídeo</label>
        <input name="titulo" class="campo__escrita" required placeholder="Neste campo, dê o nome do vídeo" id='titulo' data-titulo ' value="${listaLocalStorage.titulo}"/>
    </div>

    <div class="formulario__campo">
        <label class="campo__etiqueta" for="imagem">Imagem de perfil</label>
        <input name="imagem" class="campo__escrita" required placeholder="Insira a url da imagem" id='imagem' data-imagem  value="${listaLocalStorage.imagem}"/>
    </div>

    <input class="formulario__botao" type="submit" />
    `

    localStorage.clear();
};
  • buscar-video.js

    Por fim, as mudanças que fiz nesse código são mais pra questão de organização e uma melhora na UX.

    1. Eu mantive em mente a ideia de que uma função faz somente uma coisa. Então, mantive dentro delas somente o que era necessário. Dentro da função buscarVideo() , coloquei uma condicional para prevenir que passasse pelo busca.forEach(). Não sei se era necessário, mas preferi fazê-lo.
    2. Adicionei um eventListener para que, quando apertar o enter, faça a pesquisa sem precisar clicar na lupa.
// ---------- Lógica ----------

import { conectaApi } from "./conecta-api.js";
import constroiCard from "./mostrar-videos.js";

const botaoPesquisa = document.querySelector('[data-botao-pesquisa]');
const dadosDePesquisa = document.querySelector('[data-pesquisa]');
const lista = document.querySelector('[data-lista]');

botaoPesquisa.addEventListener('click', evento => {
    evento.preventDefault();

    buscarVideo();
});

dadosDePesquisa.addEventListener('keypress', evento => {
    console.log(evento);

    if(evento.key === 'Enter') {
        evento.preventDefault();

        buscarVideo();
    }
})

// ---------- Funções ----------

async function buscarVideo () {
    const busca = await conectaApi.buscaVideos(dadosDePesquisa.value);

    if (busca.length > 0) {
        lista.innerHTML = '';

        busca.forEach(elemento => lista.appendChild(constroiCard(elemento.titulo, elemento.descricao, elemento.url, elemento.imagem)));
    } else {
        lista.innerHTML = `<h2 class="mensagem__titulo">Não existem vídeos com esse termo</h2>`
    };
};

Se quiserem ter acesso ao projeto pronto, segue aqui o link do github: https://github.com/alberto-palmeira/aluraplay-requisicoes

Oi José, tudo bem?

Nossa, você foi muito além mesmo! Parabéns por todo cuidado e tempo que você dedicou nesse projeto.

Ficaram incríveis todas as aplicações e mudanças que você fez e ainda explicou super bem os passos.

Acho que ficaria super massa se você fizer o deploy do projeto, sabe? (não sei se já tem, não achei no github pelo menos). Que aí outras pessoas poderão abrir e testar todas essas features. :D

E também indico que você poste nas suas redes sociais e marque a Alura, é uma ótima forma de mostrar ao mundo que você está fazendo.

Muito obrigada por compartilhar com a gente o seu projeto.

Um abraço e bons estudos.