Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
98 changes: 75 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,76 @@
# Avaliação Junior
Olá desenvolvedor!\
Tudo bem?! 😊\
\
Seja bem-vindo, o intuito do teste não é reprovar e sim conhecer seu melhor estilo de programar e resolver problemas.

## O que fazer
1. Fazer um fork desse repositório e trabalhar no seu ambiente.
2. Replicar o layout do link abaixo, pode usar dados de um JSON local:\
[Link para o layout](https://xd.adobe.com/view/c715f110-fbd4-4323-be0c-0e453c1450db-9246)
2. Fazer a funcionalidade de busca funcionar.
3. Os cliques nos botões de editar/excluir/criar card podem exibir uma mensagem pro usuário de que a funcionalidade não foi implementada.
4. Ao finalizar a avaliação modifique esse README com as instruções de como podemos fazer o seu código rodar na nossa máquina. Ou seja, passo a passo do que instalar e de quais comandos rodar para podermos visualizar o seu trabalho!
5. Realizar um Pull Request para o nosso repositório e mandar um e-mail para [email protected] com o assunto "Avaliação Junior", informando que finalizou a avaliação e colocando o link do Pull Request.

## Dicas
* Não foi definido limite de linhas e colunas, portanto fique à vontade para tal escolha.
* Gostamos de interfaces limpas e elegantes.

## Quais tecnologias usar
* Deixaremos a seu critério qual tecnologia utilizar no entanto você terá mais pontos conosco se utilizar React para criação da interface e também o uso de pré-processadores/styled-components para o CSS.

## Desafios se você se sentir confiante
* Usar alguma API na internet, tipo https://pokeapi.co/, para trazer os dados que vão aparecer nos cards da tela.
Olá Avaliador Ímpar!\
Tudo ótimo e você ?! 😊


Abaixo estarão listados o modo de execução de código, sobre como preparar o ambiente para a execução do mesmo, e a proposta de solução do projeto teste para a vaga de Desenvolvedor Front-End na Ímpar!

## Proposta e Implementação do Projeto

A proposta do teste é utilizar um cenário onde recebemos o mock do projeto feito alguma ferramenta de mockup, que nesse foi Adobe XD.

[Link para o layout utilizado](https://xd.adobe.com/view/c715f110-fbd4-4323-be0c-0e453c1450db-9246)

Para implementação foi utilizado o layout proposto como base para orientação onde teríamos além de replicar a interface, implementar a função de busca de dados através do input de pesquisa e como dica para consumo de dados foi indicado a API de busca de Pokémons, a [Poke Api](https://pokeapi.co/).

### Ferramentas para implementação foram utilizadas:

- [React JS](https://pt-br.reactjs.org/)
- [Styled Components](https://styled-components.com/)
- [Axios](https://axios-http.com/docs/intro)
- [React-Modal](https://reactcommunity.org/react-modal/)
- [React-Toastify](https://fkhadra.github.io/react-toastify/introduction)

Interface gráfica contruída com React.
Biblioteca Axios para requisições http.
Styled Component para estilização da aplicação.
React-Modal para funcionalidade de exibição da tela de exclusão de cards.
React-Toastify para exibição de mensagem de "Função não implementada".

### Funcionalidades

- Função do input de pesquisa retornando o pokemon procurado ou uma mensagem caso não seja encontrado.
- Implementada a exibição da tela de adição e da tela de exclusão de card.
- Implementada responsividade

### Rodando localmente

Clone o projeto

```bash
git clone https://github.com/cristianolimaribeiro/frontendjr.git
```

Entre no diretório do projeto

```bash
cd frontendjr
```

Instale as dependências

```bash
npm install ou yarn install
```

Inicie o servidor

```bash
npm start ou yarn start
```

Executando todos os passos corretamente você poderá ver o projeto rodando no seu navegador

```bash
Local: http://localhost:3000
Na sua rede: http://XX.XX.XXX.XXX:3000
```
## Agradecimentos

Quero agradecer a todos desde agora pela oportunidade de participar deste processo seletivo, a todos os responsáveis pelo processo e por todas as instruções de como executar esse projeto e pela avaliação de vocês.
Espero tão logo por estar junto de você.

:wave: Até Logo.



45 changes: 45 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "impar-teste",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.26.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-modal": "^3.14.4",
"react-scripts": "5.0.0",
"react-toastify": "^8.2.0",
"styled-components": "^5.3.5",
"web-vitals": "^2.1.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.0.0",
"@testing-library/user-event": "^13.2.1",
"@types/styled-components": "^5.1.24"
}
}
Binary file added public/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.png" type="image/png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://use.typekit.net/vdt0wap.css">
<title>Teste - Impar</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
116 changes: 116 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { useEffect, useState } from "react";
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { Banner } from "./components/Banner";
import { DeleteModal } from "./components/DeleteModal";
import { Header } from "./components/Header";
import { MainContainer } from "./components/MainContainer";
import { getPokemon, getPokemonData, searchPokemon } from "./services/api";
import { GlobalStyle } from "./styles/global";

export function App() {
const [pokemons, setPokemons] = useState([])
const [loading, setLoading] = useState(false)
const [notFound, setNotFound] = useState(false)
const [showCard, setShowCard] = useState(false)
const [isNewDeleteModalIsOpen, setIsNewDeleteModalIsOpen] = useState(false)


const fetchPokemons = async () => {
try {
setLoading(true)
const data = await getPokemon()
const promises = data.results.map(async (pokemon) => {
return await getPokemonData(pokemon.url)
})
const result = await Promise.all(promises)
setPokemons(result)
setLoading(false)
} catch (error) {
console.log(error);
}
}

const onSearchHandler = async (pokemon) => {
if (!pokemon) {
return fetchPokemons()
}
setLoading(true)
setNotFound(false)
const result = await searchPokemon(pokemon)

if (!result) {
setNotFound(true)
} else {
setPokemons([result])
}
setLoading(false)
}

const showInsertCard = () => {
setShowCard(true)
}
const CloseInsertCard = () => {
if (showCard) {
setShowCard(false)
}
}
function handleOpenNewDeleteModal() {
setIsNewDeleteModalIsOpen(true)
}

function handleCloseNewDeleteModal() {
setIsNewDeleteModalIsOpen(false)
}
const notify = () => toast.warn('Função não implementada', {
position: "top-right",
autoClose: 5000,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});


useEffect(() => {
fetchPokemons()
}, [])

return (
<div>
<GlobalStyle />
<Header />
<DeleteModal
isOpen={isNewDeleteModalIsOpen}
onRequestClose={handleCloseNewDeleteModal}
notify={notify}
/>
<Banner onSearch={onSearchHandler} />
<ToastContainer
position="top-right"
autoClose={5000}
hideProgressBar
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss={false}
draggable
pauseOnHover
/>
{notFound ? (<div className="search-error">Não encontramos este Pokemon, Refaça a pesquisa ou Recarregue a página.</div>)
: (<MainContainer
pokemons={pokemons}
loading={loading}
showCard={showCard}
showInsertCard={showInsertCard}
CloseInsertCard={CloseInsertCard}
handleOpenNewDeleteModal={handleOpenNewDeleteModal}
notify={notify}
/>
)}
</div>
);
}


Binary file added src/assets/Icon-edit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/Icon-trash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/close_fff.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/fundo-busca.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icon_trash_64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icone_criar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/logo-teste.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/lupa.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions src/components/Banner/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Container, Content } from "./styles";
import imgMagnifyingGlass from '../../assets/lupa.png'
import { useState } from "react";


export function Banner(props) {
const [search, setSearch] = useState('')
const { onSearch } = props


const onChangeSearch = (e) => {
setSearch(e.target.value.toLowerCase())
if (e.target.value === '') {
onSearch(undefined)
}
}

const buttonSearch = async () => {
onSearch(search)
}

return (
<Container>
<Content>
<input
type="text"
placeholder="Digite aqui sua busca..."
onChange={onChangeSearch}
/>
<button
onClick={buttonSearch}
>
<img src={imgMagnifyingGlass} alt="Botão de Pesquisar" />
</button>

</Content>
</Container>
)
}
47 changes: 47 additions & 0 deletions src/components/Banner/styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import styled from "styled-components"
import imgBanner from '../../assets/fundo-busca.png'

export const Container = styled.main`
background: transparent url(${imgBanner}) 0% 0% no-repeat padding-box;
width: 100%;
height: 16rem;
padding: 1rem;
display: flex;
align-items: center;
justify-content: center;

`
export const Content = styled.div`
display: flex;
align-items: center;
position: relative;
width: min(100%, 65rem);
margin-top: 6rem;
height: 5rem;

input{
width: 100%;
height: 100%;
padding: 1.4375rem 1.75rem ;
outline: none;
border: none;
border-radius: 0.5rem;
font-size: 1.5rem;
font-weight: 300;

&::-webkit-input-placeholder{
color: var(--light-text-color);
transition: all .2s ease-in-out;
}
&:hover::-webkit-input-placeholder{
color: var(--dark-text-color);
}
}
button{
position: absolute;
right: 1rem;
background: transparent;
outline: none;
border: none;
}
`
Loading