Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

finalizando-projeto #17

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
215 changes: 11 additions & 204 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,209 +1,16 @@
# Teste Frontend estágio V3

![Aiko](img/aiko.png)
Este projeto de teste é uma aplicação web que tem como objetivo exibir as coordenadas de cada equipamento em um mapa do Leaflet e criar um esquema de visualização do histórico de estado de cada equipamento. A aplicação foi construída utilizando HTML, CSS e JavaScript.

Neste teste serão avaliados seus conhecimentos em Javascript, HTML e CSS, a criatividade e metodologia aplicada no desenvolvimento, a usabilidade e design da aplicação final.
Funcionalidades
Exibir as posições de cada equipamento em um mapa do Leaflet
Criar um esquema de visualização do histórico de estado de cada equipamento
Visualização de informações detalhadas de cada equipamento

## O Desafio
Tecnologias utilizadas
HTML
CSS
JavaScript
Leaflet

Você é o desenvolvedor frontend de uma empresa que coleta dados de equipamentos utilizados em uma operação florestal. Dentre esses dados estão o histórico de posições e estados desses equipamentos. O estado de um equipamento é utilizado para saber o que o equipamento estava fazendo em um determinado momento, seja *Operando*, *Parado* ou em *Manutenção*. O estado é alterado de acordo com o uso do equipamento na operação, já a posição do equipamento é coletada através do GPS e é enviada e armazenada de tempo em tempo pela aplicação.

Seu objetivo é, de posse desses dados, desenvolver o frontend de aplicação web que trate e exibida essas informações para os gestores da operação.

## Requisitos

Esses requisitos são obrigatórios e devem ser desenvolvidos para a entrega do teste.

* **Posições dos equipamentos**: Exibir no mapa os equipamentos nas suas posições mais recentes.

* **Estado atual do equipamento**: Visualizar o estado mais recente dos equipamentos. Exemplo: mostrando no mapa, como um pop-up, mouse hover sobre o equipamento, etc.

* **Histórico de estados do equipamento**: Permitir a visualização do histórico de estados de um equipamento específico ao clicar sobre o equipamento.

## Dados

Todos os dados que precisa para desenvolver os requisitos estão na pasta `data/` no formato `json` e são detalhados a seguir.

```sh
data/
|- equipment.json
|- equipmentModel.json
|- equipmentPositionHistory.json
|- equipmentState.json
|- equipmentStateHistory.json
```

### equipment.json
Contém todos os equipamentos da aplicação.

```JSONC
[
{
// Identificador único do equipamento
"id": "a7c53eb1-4f5e-4eba-9764-ad205d0891f9",
// Chave estrangeira, utilizada para referenciar de qual modelo é esse equipamento
"equipmentModelId": "a3540227-2f0e-4362-9517-92f41dabbfdf",
// Nome do Equipamento
"name": "CA-0001"
},
// ...
]
```

### equipmentState.json
Contém todos os estados dos equipamentos.

```JSONC
[
{
// Identificador único do estado de equipamento
"id": "0808344c-454b-4c36-89e8-d7687e692d57",
// Nome do estado
"name": "Operando",
// Cor utilizada para representar o estado
"color": "#2ecc71"
},
// ...
]
```

### equipmentModel.json
Contém todos os modelos de equipamento e a informação de qual é o valor por hora do equipamento em cada um dos estados.

```JSONC
[
{
// Identificador único do modelo de equipamento
"id": "a3540227-2f0e-4362-9517-92f41dabbfdf",
// Nome do modelo de equipamento
"name": "Caminhão de carga",
// Valor gerado por hora para cada estado
"hourlyEarnings": [
{
// Chave estrangeira, utilizada para referenciar de qual valor é esse estado
"equipmentStateId": "0808344c-454b-4c36-89e8-d7687e692d57",
// Valor gerado por hora nesse estado
"value": 100
},
// ...
]
},
// ...
]
```

### equipmentStateHistory.json
O histórico de estados por equipamento.

```JSONC
[
{
// Chave estrangeira, utilizada para referenciar de qual equipamento são esses estados
"equipmentId": "a7c53eb1-4f5e-4eba-9764-ad205d0891f9",
// Histórico de estados do equipamento
"states": [
{
// Data em que o equipamento declarou estar nesse estado
"date": "2021-02-01T03:00:00.000Z",
// Chave estrangeira, utilizada para referenciar qual é o estado
// que o equipamento estava nesse momento
"equipmentStateId": "03b2d446-e3ba-4c82-8dc2-a5611fea6e1f"
},
// ...
]
},
// ...
]
```

### equipmentPositionHistory.json
O histórico de posições dos equipamentos.

```JSONC
[
{
// Chave estrangeira, utilizada para referenciar de qual equipamento são esses estados
"equipmentId": "a7c53eb1-4f5e-4eba-9764-ad205d0891f9",
// Posições do equipamento
"positions": [
{
// Data em que a posição foi registrada
"date": "2021-02-01T03:00:00.000Z",
// Latitude WGS84
"lat": -19.126536,
// Longitude WGS84
"lon": -45.947756
},
// ...
]
},
// ...
]
```


## O que é permitido

* Vue, React e Angular.

* Typescript.

* Bibliotecas de componentes (Element-ui, Vuetify, Bootstrap, etc.)

* Bibliotecas e APIs de Mapas (Leaflet, Openlayers, Google Maps API, etc).

* Template engines (Pug, Ejs, etc).

* Gerenciamento de estado (Vuex, Redux, etc).

* Frameworks CSS (Tailwind, Bulma, Bootstrap, Materialize, etc).

* Pré-processadores CSS (SCSS, SASS, LESS, etc).

* Frameworks baseados em Vue (Nuxt.js, Quasar, etc).

* Qualquer tecnologia complementar as citadas anteriormente são permitidas desde que seu uso seja justificável.

## O que não é permitido

* Utilizar componentes ou códigos de terceiros que implementem algum dos requisitos.

## Recomendações

* **Linter**: Desenvolva o projeto utilizando algum padrão de formatação de código.

* **Leaflet**: Para a exibição de informações no mapa recomendamos o Leaflet por ser uma biblioteca de código aberto e de fácil uso.

## Extras

Aqui são listados algumas sugestões para você que quer ir além do desafio inicial. Lembrando que você não precisa se limitar a essas sugestões, se tiver pensado em outra funcionalidade que considera relevante ao escopo da aplicação fique à vontade para implementá-la.

* **Filtros**: Filtrar as visualizações por estado atual ou modelo de equipamento.

* **Pesquisa**: Ser possível pesquisar por dados de um equipamento especifico.

* **Percentual de Produtividade do equipamento**: Calcular a produtividade do equipamento, que consiste em uma relação das horas produtivas (em estado "Operando") em relação ao total de horas. Exemplo se um equipamento teve 18 horas operando no dia a formula deve ser `18 / 24 * 100 = 75% de produtividade`.

* **Ganho por equipamento**: Calcular o ganho do equipamento com base no valor recebido por hora informado no Modelo de Equipamento. Exemplo se um modelo de equipamento gera 100 por hora em operando e -20 em manutenção, então se esse equipamento ficou 10 horas em operação e 4 em manutenção ele gerou `10 * 100 + 4 * -20 = 920`.

* **Diferenciar os equipamentos**: Diferenciar visualmente os equipamentos por modelo de equipamento na visualização do mapa.

* **Histórico de posições**: Que seja possível visualizar o histórico de posições de um equipamento, mostrando o trajeto realizado por ele.

* **Testes**: Desenvolva testes que achar necessário para a aplicação, seja testes unitários, testes automatizados, testes de acessibilidade, etc.

* **Documentação**: Gerar uma documentação da aplicação. A documentação pode incluir detalhes sobre as decisões tomadas, especificação dos componentes desenvolvidos, instruções de uso dentre outras informações que achar relevantes.

## Entregas

Para realizar a entrega do teste você deve:

* Relizar o fork e clonar esse repositório para sua máquina.

* Criar uma branch com o nome de `teste/[NOME]`.
* `[NOME]`: Seu nome.
* Exemplos: `teste/fulano-da-silva`; `teste/beltrano-primeiro-gomes`.

* Faça um commit da sua branch com a implementação do teste.

* Realize o pull request da sua branch nesse repositório.
Obs: Me desculpem pela qualidade do trabalho, estava com alguns problemas pessoais e tive que fazer o trabalho todo em uma madrugada.
52 changes: 52 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="pt-br">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI=" crossorigin="" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"
integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM=" crossorigin=""></script>
<link rel="stylesheet" href="style.css">
<script src="index.js" defer></script>
</head>

<body>

<header class="header">
<img src="img/aiko.png" alt="aiko-icon" width="110px" height="70px">
<h1>Aiko Soluções</h1>
<a href="">
<p>Contato</p>
</a>
<a href="">
<p>Suporte</p>
</a>
</header>
<div class="main">
<div id="buttons" class="left-side">
<button id="a7c53eb1-4f5e-4eba-9764-ad205d0891f9" class="equipment-button">Equipamento 1</button>
<button id="1c7e9615-cc1c-4d72-8496-190fe5791c8b" class="equipment-button">Equipamento 2</button>
<button id="2b5796cb-21c1-480e-8886-4498ea593a65" class="equipment-button">Equipamento 3</button>
<button id="1d222cdc-01dd-4caa-8934-5351d3995cfb" class="equipment-button">Equipamento 4</button>
<button id="491b983b-950c-4a88-942d-487e99b92540" class="equipment-button">Equipamento 5</button>
<button id="39317fcb-79e7-4e7e-83dc-723a9b63633c" class="equipment-button">Equipamento 6</button>
<button id="c79ef1de-92f3-4edd-bd55-553056640449" class="equipment-button">Equipamento 7</button>
<button id="b7aaba00-13f7-44a0-8bf1-bc163afcf9d8" class="equipment-button">Equipamento 8</button>
<button id="fe2a2e11-bfa6-46b6-990b-fd8175946b7e" class="equipment-button">Equipamento 9</button>
</div>
<div id="equipment-history-container" class="history-container">
</div>
<div id="map" class="right-side">
<ul>

</ul>
</div>
</div>

</body>

</html>
92 changes: 92 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// URL da API que retorna a posição dos equipamentos
const positionHistory = '/data/equipmentPositionHistory.json';
const stateHistory = '/data/equipmentStateHistory.json'

// Criar o mapa
const map = L.map('map').setView([-19.134644, -46.087206], 9);


L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data &copy; OpenStreetMap contributors'
}).addTo(map);




const markers = {};

// Requisitar a posição dos equipamentos para a API
fetch(positionHistory)
.then(response => response.json())
.then(positionHistory => {
positionHistory.forEach(position => {
const equipmentId = position.equipmentId;
const lastPosition = position.positions[position.positions.length - 1];
const lat = lastPosition.lat;
const lon = lastPosition.lon;

let lastEquipmentState = 'Desconhecido';
fetch(stateHistory)
.then(response => response.json())
.then(stateHistory => {
stateHistory.forEach(state => {
if (state.equipmentId === equipmentId) {
const lastState = state.states[state.states.length - 1];
const equipmentStateId = lastState.equipmentStateId;
if (equipmentStateId === '0808344c-454b-4c36-89e8-d7687e692d57') {
lastEquipmentState = 'Operando';
} else if (equipmentStateId === 'baff9783-84e8-4e01-874b-6fd743b875ad') {
lastEquipmentState = 'Parado';
} else if (equipmentStateId === '03b2d446-e3ba-4c82-8dc2-a5611fea6e1f') {
lastEquipmentState = 'Manutenção';
}
}
});

const buttons = document.querySelectorAll('.equipment-button');
buttons.forEach(button => {
button.addEventListener('click', () => {
const equipmentId = button.id;
const stateHistoryUrl = '/data/equipmentStateHistory.json';

// Obter o histórico de estado do equipamento da API
fetch(stateHistoryUrl)
.then(response => response.json())
.then(stateHistory => {
// Filtrar o histórico para o equipamento selecionado
const equipmentStateHistory = stateHistory.find(state => state.equipmentId === equipmentId);

// Criar uma tabela HTML para exibir o histórico de estado
const table = document.createElement('table');
const headerRow = table.insertRow();
headerRow.insertCell().textContent = 'Data';
headerRow.insertCell().textContent = 'Estado';

equipmentStateHistory.states.forEach(state => {
const row = table.insertRow();
row.insertCell().textContent = state.date;

let stateText = '';
if (state.equipmentStateId === '0808344c-454b-4c36-89e8-d7687e692d57') {
stateText = 'Operando';
} else if (state.equipmentStateId === 'baff9783-84e8-4e01-874b-6fd743b875ad') {
stateText = 'Parado';
} else if (state.equipmentStateId === '03b2d446-e3ba-4c82-8dc2-a5611fea6e1f') {
stateText = 'Manutenção';
}
row.insertCell().textContent = stateText;
});

const tableContainer = document.getElementById('equipment-history-container');
tableContainer.innerHTML = '';
tableContainer.appendChild(table);
});
});
});

const marker = L.marker([lat, lon]).bindPopup(`Estado atual do equipamento: ${lastEquipmentState}`);
markers[equipmentId] = marker;
marker.addTo(map);
});
});
});
Loading