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
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
65 changes: 40 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
# 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. Crie um repositório no GitHub.
2. Use esse repositório para desenvolver a aplicação.
3. 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)
4. Fazer a funcionalidade de busca funcionar.
5. 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.
6. Ao finalizar a avaliação crie um README na raiz do repositório 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!
7. Ao finalizar a sua avaliação enviar um e-mail para [email protected] com o assunto "Avaliação Junior", informando que finalizou a avaliação e colocando o link do seu repositório GitHub com o código feito.

## 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.
# Projeto Front-end JR

Projeto deseonvolvido com React para front-end e lib json-server para simular um backend;

## Pré-requisitos para rodar o projeto

Para rodar o projeto você precisa ter instalado o GIT e Nodejs;

## Hora de rodar o projeto

Abra o terminal e clone o repositório
$ git clone https://github.com/gabrielluiz01/frontendjr.git

# Entre na pasta do projeto

$ cd frontendjr

Instale todas as dependências
$ yarn install ou npm install

Agora iremos executar o json-server para que nossa "API" rode
$ npx json-server -p 8000 db.json

E agora sim rodamos o front-end da aplicação
$ yarn dev ou npm run dev

A aplicação estará rodando na porta 3000 - http://localhost:3000/

OBS: Para que toda a aplicação esteja funcionando perfeitamente lembre-se de deixar o json-server rodando junto com o front

# Tecnologias

Para criação dessa aplicação usei seguintes tecnologias:

- ReactJS
- Axios
- Styled-components
- json-server

Feito por Gabriel Luiz
34 changes: 34 additions & 0 deletions db.json

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
Binary file removed layout.png
Binary file not shown.
24 changes: 24 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "impar-teste",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^0.27.2",
"json-server": "^0.17.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"styled-components": "^5.3.5",
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@vitejs/plugin-react": "^1.3.0",
"vite": "^2.9.9"
}
}
147 changes: 147 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import Header from "./components/header";
import Search from "./components/search";
import styled from "styled-components";
import Button from "./components/button";
import Card from "./components/card";
import ModalCreate from "./components/modalCreate";

import { useState, useEffect } from "react";
import ModalDelete from "./components/modalDelete";
import {
createCourse,
deleteCourse,
editCourse,
getCourses,
} from "./services/api";

const Content = styled.section`
max-width: 1050px;
align-self: center;
margin: 40px auto 0 auto;

@media (max-width: 1000px) {
max-width: 95% !important;
}

span {
display: flex;
justify-content: space-between;
align-items: center;
}

h1 {
font-size: 25px;
color: #5f1478;
font-weight: normal;
}
`;

const ContainerCards = styled.div`
width: 100%;
display: flex;
flex-wrap: wrap;
gap: 37px;
margin: 36px 0;

@media (max-width: 1000px) {
justify-content: center;
}
`;

const BoxError = styled.div`
width: 100%;
height: 30vh;
display: flex;
justify-content: center;
align-items: center;

h2 {
font-size: 32px;
color: #4d4b4b;
width: 50%;
text-align: center;
}
`;

function App() {
const [isModalCreate, setIsModalCreate] = useState(false);
const [isModalDelete, setIsModalDelete] = useState(false);
const [isEdit, setIsEdit] = useState(false);
const [coursesData, setCoursesData] = useState(undefined);
const [cardSelected, setCardSelected] = useState([]);
const [searchText, setSearchText] = useState("");
const [filteredCard, setFilteredCard] = useState([]);

useEffect(() => {
fetchingCourses();
}, [isModalCreate, isModalDelete, isEdit]);

useEffect(() => {
const filteredList = coursesData?.filter((item) =>
handleFiltered(item.title)
);
setFilteredCard(filteredList);
}, [searchText]);

const handleFiltered = (title) => {
const regex = new RegExp(searchText, "i");
return regex.test(title);
};

const fetchingCourses = async () => {
try {
const { data } = await getCourses("course");
setCoursesData(data);
} catch (err) {
console.log("err", err);
}
};

return (
<div className="App">
<Header />
<Search searchText={searchText} setSearchText={setSearchText} />
<Content>
<span>
<h1>{searchText ? "Resultado da busca" : "Cursos"}</h1>
<Button handleClick={() => setIsModalCreate(true)}>Novo card</Button>
</span>
<ContainerCards>
{coursesData ? (
<Card
setIsModalDelete={setIsModalDelete}
setIsEdit={setIsEdit}
coursesData={coursesData}
setCardSelected={setCardSelected}
filteredCard={filteredCard}
/>
) : (
searchText &&
!filteredCard.length && (
<BoxError>
<h2>Não encontramos nenhum resultado para {searchText}</h2>
</BoxError>
)
)}
</ContainerCards>
</Content>
{(isModalCreate || isEdit) && (
<ModalCreate
setIsModalCreate={setIsModalCreate}
isEdit={isEdit}
setIsEdit={setIsEdit}
cardSelected={cardSelected}
coursesData={coursesData}
/>
)}
{isModalDelete && (
<ModalDelete
setIsModalDelete={setIsModalDelete}
cardSelected={cardSelected}
/>
)}
</div>
);
}

export default App;
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.
Binary file added src/assets/[email protected]
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/check-icon.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/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/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.
1 change: 1 addition & 0 deletions src/assets/logo-teste.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/lupa.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions src/components/button/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ButtonBox } from "./style";

export default function Button({
children,
buttonBackground,
buttonBorder,
buttonColor,
handleClick,
buttonMarginDesk,
buttonMarginMobile,
}) {
return (
<>
<ButtonBox
buttonBackground={buttonBackground}
buttonBorder={buttonBorder}
buttonColor={buttonColor}
onClick={handleClick}
buttonMarginDesk={buttonMarginDesk}
buttonMarginMobile={buttonMarginMobile}
>
{children}
</ButtonBox>
</>
);
}

Button.defaultProps = {
buttonBackground: "#E76316",
buttonBorder: "none",
buttonColor: "#FFF",
buttonMarginDesk: 0,
buttonMarginMobile: 0,
};
24 changes: 24 additions & 0 deletions src/components/button/style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import styled from 'styled-components';

export const ButtonBox = styled.button`
width: 173px;
height: 48px;
background: ${({ buttonBackground }) => buttonBackground};
box-shadow: 0 3px 6px #92207242;
border-radius: 8px;
font-size: 16px;
color: ${({ buttonColor }) => buttonColor};
font-weight: bold;
border: ${({ buttonBorder }) => buttonBorder};
cursor: pointer;
transition: 0.5s all;
margin: ${({ buttonMarginDesk }) => buttonMarginDesk};

@media (max-width: 425px){
margin: ${({ buttonMarginMobile }) => buttonMarginMobile}
}

:hover{
filter: brightness(90%);
}
`;
43 changes: 43 additions & 0 deletions src/components/card/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { CardBox, OptionsBox, Title } from "./style";

import deleteIcon from "../../assets/icon-trash.png";
import editIcon from "../../assets/icon-edit.png";

export default function Card({
setIsModalDelete,
setIsEdit,
coursesData,
setCardSelected,
filteredCard,
}) {
const handleDelete = (item) => {
setIsModalDelete(true);
setCardSelected(item);
};

const handleEdit = (item) => {
setIsEdit(true);
setCardSelected(item);
};

const validate = filteredCard?.length ? filteredCard : coursesData;

return validate?.map((item, index) => (
<CardBox>
<span>
<img src={item.image} alt={item.name} />
</span>
<Title>{item.title}</Title>
<OptionsBox>
<button onClick={() => handleDelete(item)}>
<img src={deleteIcon} alt="deletar card" />
<p>Excluir</p>
</button>
<button onClick={() => handleEdit(item)}>
<img src={editIcon} alt="editar card" />
<p>Editar</p>
</button>
</OptionsBox>
</CardBox>
));
}
Loading