Skip to content

Commit 7a4cf0f

Browse files
committed
✨feat: implementa autenticação básica no SPA | Parte 04
- Configura a Barra de Navegação para Apresentar Elementos Gráficos de Autenticação - Refatora Script de Inicialização para Escutar Eventos de Autenticação (Login e Logout) - Implementa o "LoginView" e Configura nas Rotas - Implementa Página Segura "DashboardView" e Configura nas Rotas
1 parent 3f66da4 commit 7a4cf0f

File tree

7 files changed

+174
-0
lines changed

7 files changed

+174
-0
lines changed

index.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,20 @@
3939
</a>
4040
</li>
4141
</ul>
42+
43+
<ul class="navbar-nav ms-auto">
44+
<li class="nav-item">
45+
<a class="nav-link" href="/carrinho" data-link>
46+
<i class="bi bi-cart"></i> Carrinho
47+
<span class="badge bg-secondary">0</span> <!-- Esse número deve ser atualizado dinamicamente - Para testes está fixo -->
48+
</a>
49+
</li>
50+
<li class="nav-item ">
51+
<a class="nav-link" id="authLink" href="/login" data-link>
52+
<i id="iconAuthLink" class="bi bi-lock"></i> Login
53+
</a>
54+
</li>
55+
</ul>
4256
</div>
4357
</div>
4458
</nav>

index.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ function initListenerDOMContentLoaded(router) {
2626
});
2727
}
2828

29+
function initListenerEventLogin(router) {
30+
//Configurando a função ouvinte de evento customizado login para manipular navegação após feito o login
31+
window.addEventListener("eventLogin", async (e) => {
32+
var authLink = document.getElementById('authLink');
33+
34+
if (authLink) {
35+
authLink.innerHTML = ' <i id="iconAuthLink" class="bi bi-unlock"></i> Logout';
36+
authLink.href = '/logout';
37+
history.replaceState("", "", "/dashboard");
38+
router.navigateTo('/dashboard');
39+
}
40+
});
41+
}
42+
43+
function initListenerEventLogout(router) {
44+
//Configurando a função ouvinte de evento customizado login para manipular navegação após feito o login
45+
window.addEventListener("eventLogout", async (e) => {
46+
var authLink = document.getElementById('authLink');
47+
if (authLink) {
48+
authLink.innerHTML = ' <i id="iconAuthLink" class="bi bi-lock"></i> Login';
49+
authLink.href = '/login';
50+
history.replaceState("", "", "/");
51+
router.navigateTo('/');
52+
}
53+
});
54+
}
55+
2956
function bootstrap() {
3057

3158
console.log('Inicializando a Front End (SPA)');
@@ -38,6 +65,10 @@ function bootstrap() {
3865

3966
initListenerDOMContentLoaded(router);
4067

68+
initListenerEventLogin(router);
69+
70+
initListenerEventLogout(router);
71+
4172
}
4273

4374
bootstrap();

js/routes.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { HomeView } from "../views/home/home.js";
22
import { ContatoView } from "../views/contato/contato.js";
33
import { SobreView } from "../views/sobre/sobre.js";
44
import { NotFoundView } from "../views/not-found/not-found.js";
5+
import { LoginView } from "../views/autenticacao/login.js";
6+
import { DashboardView } from "../views/dashboard/dashboard.js";
57

68
//Recupera o elemento HTML que vai armazenar os templates das views
79
const containerView = document.getElementById('content-view');
@@ -11,6 +13,10 @@ const homeView = new HomeView(containerView);
1113
const contatoView = new ContatoView(containerView);
1214
const sobreView = new SobreView(containerView);
1315
const notFoundView = new NotFoundView(containerView);
16+
const loginView = new LoginView(containerView);
17+
18+
//Instancia as Views Seguras
19+
const dashboardView = new DashboardView(containerView);
1420

1521
//Define um objeto para relacionar as rotas (URL) as views
1622
const routes = {
@@ -19,6 +25,9 @@ const routes = {
1925
'/contato': contatoView,
2026
'/sobre': sobreView,
2127
'/not-found': notFoundView,
28+
'/login': loginView,
29+
'/logout': loginView,
30+
'/dashboard': dashboardView,
2231
};
2332

2433
export { routes }

views/autenticacao/login.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!--Login -->
2+
<section class="py-5">
3+
<div class="rounded-3 py-5 px-4 px-md-5 mb-5" style="background-color: #f7d3ad;">
4+
<div class="row gx-5 justify-content-center">
5+
<div class="col-md-6">
6+
<div class="card">
7+
<div class="card-body">
8+
<h5 class="card-title text-center mb-4 fw-bolder" style="color: #425862;">Autenticação | Login</h5>
9+
<form id="loginForm">
10+
<div class="mb-3">
11+
<label for="inputUsuario" class="form-label">Usuário</label>
12+
<input type="text" class="form-control" id="inputUsuario" name="usuario" required value="kminchelle"/>
13+
</div>
14+
<div class="mb-3">
15+
<label for="inputPassword" class="form-label">Senha</label>
16+
<input type="password" class="form-control" id="inputSenha" name="senha" required value="0lelplR"/>
17+
</div>
18+
<button type="submit" class="btn w-100" style="background-color: #7d7062; color: #f8e9d8">Enviar</button>
19+
</form>
20+
</div>
21+
</div>
22+
</div>
23+
</div>
24+
</div>
25+
</section>

views/autenticacao/login.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { View } from "../../js/view.js";
2+
3+
class LoginView extends View {
4+
5+
//////////////
6+
//Construtor//
7+
//////////////
8+
9+
constructor(contentView, templatePath = '/views/autenticacao/login.html') {
10+
super(contentView, templatePath);
11+
}
12+
13+
///////////////////////
14+
//Metodos Assincronos//
15+
///////////////////////
16+
17+
async manipularLoginForm(event) {
18+
event.preventDefault();
19+
const loginForm = new FormData(event.target);
20+
const inputUsuario = loginForm.get('usuario');
21+
const inputSenha = loginForm.get('senha');
22+
23+
const response = await fetch('https://dummyjson.com/auth/login', {
24+
method: 'POST',
25+
headers: { 'Content-Type': 'application/json' },
26+
body: JSON.stringify({
27+
username: inputUsuario,
28+
password: inputSenha
29+
// expiresInMins: 60, // optional
30+
})
31+
});
32+
33+
if (response.status === 200) {
34+
const data = await response.json();
35+
localStorage.setItem('usuarioLogado', JSON.stringify(data));
36+
localStorage.setItem('JWTToken', JSON.stringify(data.token));
37+
38+
const eventLogin = new Event('eventLogin', { bubbles: true, cancelable: false });
39+
window.dispatchEvent(eventLogin);
40+
}
41+
}
42+
43+
async init() {
44+
await this.show();
45+
const loginForm = document.getElementById('loginForm');
46+
if (loginForm) {
47+
loginForm.addEventListener('submit', this.manipularLoginForm);
48+
}
49+
}
50+
51+
}
52+
53+
export { LoginView }

views/dashboard/dashboard.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!-- Dashboard - Área Segura -->
2+
<section class="py-5">
3+
<div class="rounded-3 py-5 px-4 px-md-5 mb-5" style="background-color: #f7d3ad;">
4+
<div class="row gx-5 justify-content-center">
5+
<!-- Main Content -->
6+
<div class="col-md-9">
7+
<div class="container mt-4">
8+
<h2>Dashboard</h2>
9+
<a class="nav-link page" href="/gerenciar-categorias" data-link>
10+
<i class="bi bi-tag">Gerenciar Categorias</i>
11+
</a>
12+
<a class="nav-link page" href="/gerenciar-produtos" data-link>
13+
<i class="bi bi-tag">Gerenciar Produtos</i>
14+
</a>
15+
</div>
16+
</div>
17+
</div>
18+
</div>
19+
</section>

views/dashboard/dashboard.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { View } from "../../js/view.js";
2+
3+
class DashboardView extends View {
4+
5+
//////////////
6+
//Construtor//
7+
//////////////
8+
9+
constructor(contentView, templatePath = '/views/dashboard/dashboard.html') {
10+
super(contentView, templatePath);
11+
this._safe = true;
12+
}
13+
14+
/////////////////////
15+
//Metodo Assincrono//
16+
////////////////////
17+
18+
async init() {
19+
await this.show();
20+
}
21+
}
22+
23+
export { DashboardView }

0 commit comments

Comments
 (0)