Feat: CRUD de areas no painel do admin#5
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
job-ready-developer | 700d572 | Commit Preview URL Branch Preview URL |
Apr 07 2026, 01:11 AM |
There was a problem hiding this comment.
Code Review
This pull request introduces functionality to add and remove competency areas within the admin component, including new modals, dropdowns, and associated styles. The review feedback highlights several issues, primarily the use of direct DOM manipulation instead of Angular's declarative patterns, which led to bugs like non-existent element references and potential memory leaks. Other suggestions include adding input validation, removing unused imports and dead code, fixing typos, and preventing runtime errors by disabling buttons when required data is missing.
| const dropbtn = document.getElementById("dropbtn"); | ||
| const botao_remover = document.getElementById("remover-id-admin"); | ||
| const modal_dropdown = document.getElementById("modal_dropdown_remove"); | ||
| botao_remover?.addEventListener("click", () => { | ||
| if (modal_dropdown !== null) { | ||
| modal_dropdown.style.display = "flex"; | ||
| } | ||
| }); | ||
|
|
||
| const modal = document.getElementById("modal_admin"); | ||
| const abrirModal = document.getElementById("abrir-modal-admin"); | ||
| const fecharModal = document.getElementById("salvar-modal-admin"); | ||
| const conteudo = document.getElementById("modal_content_admin"); | ||
|
|
||
| abrirModal?.addEventListener("click", () => { | ||
| if (modal !== null) { | ||
| modal.style.display = "flex"; | ||
| } | ||
| }); | ||
|
|
||
| modal?.addEventListener("click", (event) => { | ||
| modal.style.display = "none"; | ||
| }); | ||
|
|
||
| conteudo?.addEventListener("click", (event) => { | ||
| event.stopPropagation(); | ||
| }); | ||
|
|
||
| fecharModal?.addEventListener("click", () => { | ||
| if (modal !== null) { | ||
| modal?.classList.add("inactive"); | ||
| modal.style.display = "none"; | ||
| modal?.classList.remove("active"); | ||
| } | ||
| }); | ||
|
|
||
| const modalDropdown = document.getElementById("modal_dropdown_remove"); | ||
| const modalDropdownContent = document.getElementById( | ||
| "modal_content_dropdown_remove", | ||
| ); | ||
|
|
||
| modalDropdown?.addEventListener("click", (event) => { | ||
| if (event.target === modalDropdown) { | ||
| modalDropdown.style.display = "none"; | ||
| } | ||
| }); | ||
| modalDropdownContent?.addEventListener("click", (event) => { | ||
| event.stopPropagation(); | ||
| }); |
There was a problem hiding this comment.
A manipulação direta do DOM usando document.getElementById e addEventListener é um antipadrão em Angular. Isso ignora o ciclo de vida e a detecção de mudanças do Angular, pode levar a memory leaks (os event listeners não são removidos em ngOnDestroy), e torna o componente mais difícil de testar e manter.
Recomendo refatorar este código para usar uma abordagem declarativa do Angular. Por exemplo, você pode usar propriedades no componente para controlar a visibilidade dos modais e aplicar classes ou estilos condicionalmente no template.
Exemplo para o modal de adicionar área:
No componente (.ts):
isAddAreaModalVisible = false;
// ...
openAddAreaModal() {
this.isAddAreaModalVisible = true;
}
closeAddAreaModal() {
this.isAddAreaModalVisible = false;
}No template (.html):
<button (click)="openAddAreaModal()">+ Adicionar Área</button>
<!-- Modal -->
<div class="modal_admin" *ngIf="isAddAreaModalVisible">
<div class="modal_content_admin">
<!-- Conteúdo do modal -->
<button (click)="closeAddAreaModal()">Fechar</button>
</div>
</div>Essa abordagem é mais segura, mais limpa e alinhada com as boas práticas do framework.
| <button | ||
| class="btn-remove-area" | ||
| (click)="removeArea(selectedAreaToRemove()!)" | ||
| > | ||
| Remover Área | ||
| </button> |
There was a problem hiding this comment.
A chamada removeArea(selectedAreaToRemove()!) usa o operador de asserção não nula (!). Se o botão for clicado sem que uma área tenha sido selecionada para remoção, selectedAreaToRemove() será null e isso causará um erro em tempo de execução.
Para evitar isso, o botão de remover deve ser desabilitado quando nenhuma área estiver selecionada.
| <button | |
| class="btn-remove-area" | |
| (click)="removeArea(selectedAreaToRemove()!)" | |
| > | |
| Remover Área | |
| </button> | |
| <button | |
| class="btn-remove-area" | |
| (click)="removeArea(selectedAreaToRemove()!)" | |
| [disabled]="!selectedAreaToRemove()" | |
| > | |
| Remover Área | |
| </button> |
|
|
||
| const modal = document.getElementById("modal_admin"); | ||
| const abrirModal = document.getElementById("abrir-modal-admin"); | ||
| const fecharModal = document.getElementById("salvar-modal-admin"); |
There was a problem hiding this comment.
A variável fecharModal está tentando obter um elemento com o ID salvar-modal-admin, mas este ID não existe no template HTML. Como resultado, fecharModal será null e o addEventListener na linha 734 não terá efeito. A lógica para fechar o modal ao salvar uma nova área não está funcionando.
Este problema é um sintoma da manipulação direta do DOM. Ao refatorar para uma abordagem declarativa, como sugerido em outro comentário, este problema será resolvido naturalmente. O método addArea poderia, por exemplo, ser responsável por fechar o modal após a conclusão.
| import { CompetencyService } from "../../services/competency.service"; | ||
| import { Competency, Resource } from "../../models/competency.model"; | ||
| import { add_new_area } from "../../models/competency.model"; | ||
| import { doc } from "firebase/firestore"; |
| <input | ||
| id="area-desc" | ||
| type="text" | ||
| placeholder="Brevecd descrição da área" |
| dropdown_inactive() { | ||
| const myDropdown = document.getElementById("myDropdown"); | ||
| const modalDropdown = document.getElementsByClassName( | ||
| "remove-item-dropdown", | ||
| ); | ||
|
|
||
| modalDropdown[0].addEventListener("click", () => { | ||
| if (myDropdown !== null) { | ||
| myDropdown.classList.remove("show"); | ||
| } | ||
| }); | ||
| } |
There was a problem hiding this comment.
| addArea( | ||
| name: string, | ||
| description: string, | ||
| color: string, | ||
| icon: string, | ||
| ): void { | ||
| if (this.mapRef) { | ||
| add_new_area(name, description, color, icon, this.mapRef); | ||
| this.areas.set(this.mapRef.children ?? []); | ||
| } | ||
| } |
There was a problem hiding this comment.
O método addArea não valida os dados recebidos. Isso permite que um usuário adicione uma nova área com campos vazios, como o nome, o que pode levar a dados inconsistentes.
É uma boa prática validar os inputs antes de processá-los. Adicionalmente, após adicionar uma área com sucesso, os campos do formulário deveriam ser limpos e o modal fechado para melhorar a experiência do usuário.
addArea(
name: string,
description: string,
color: string,
icon: string,
): void {
if (!name?.trim()) {
// Idealmente, notificar o usuário sobre o erro.
return;
}
if (this.mapRef) {
add_new_area(name, description, color, icon, this.mapRef);
this.areas.set(this.mapRef.children ?? []);
// TODO: Limpar os campos do formulário e fechar o modal aqui.
}
}
Adicionei um Crud com botões para adicionar areas e remover areas, a aba de remover areas tem um botão de confirmação e ambas ações de deletar ou adicionar só salvam com o botão de "salvar alterações" no painel de admin.
Adicionado Crud de adicionar e remover segmentos de cada área.