diff --git a/src/app/components/admin/admin.component.ts b/src/app/components/admin/admin.component.ts
index d03a08a..e52d87f 100644
--- a/src/app/components/admin/admin.component.ts
+++ b/src/app/components/admin/admin.component.ts
@@ -1,13 +1,21 @@
-import { Component, OnInit, OnDestroy, inject, signal, ChangeDetectionStrategy } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { FormsModule } from '@angular/forms';
-import { RouterLink } from '@angular/router';
-import { Subscription } from 'rxjs';
-import { CompetencyService } from '../../services/competency.service';
-import { Competency, Resource } from '../../models/competency.model';
+import {
+ Component,
+ OnInit,
+ OnDestroy,
+ inject,
+ signal,
+ ChangeDetectionStrategy,
+} from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { FormsModule } from "@angular/forms";
+import { RouterLink } from "@angular/router";
+import { Subscription } from "rxjs";
+import { CompetencyService } from "../../services/competency.service";
+import { Competency, Resource } from "../../models/competency.model";
+import { add_new_area } from "../../models/competency.model";
@Component({
- selector: 'app-admin',
+ selector: "app-admin",
standalone: true,
imports: [CommonModule, FormsModule, RouterLink],
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -20,14 +28,16 @@ import { Competency, Resource } from '../../models/competency.model';
@if (saved()) {
- ✅ Mapa salvo com sucesso! Todos os alunos já verão as mudanças.
+
+ ✅ Mapa salvo com sucesso! Todos os alunos já verão as mudanças.
+
}
@@ -36,271 +46,766 @@ import { Competency, Resource } from '../../models/competency.model';
@if (selectedArea()) {
-
-
{{ selectedArea()!.icon }} {{ selectedArea()!.name }}
-
-
- @for (node of getNodesForArea(selectedArea()!); track node.id) {
-
-
- {{ node.icon }} {{ node.name }}
- {{ node.resources.length }} recursos
-
+
+
{{ selectedArea()!.icon }} {{ selectedArea()!.name }}
-
{{ node.description }}
-
-
-
- @for (res of node.resources; track $index; let i = $index) {
-
-
-
-
-
-
-
- }
+
+ @for (node of getNodesForArea(selectedArea()!); track node.id) {
+
+
+ {{ node.icon }} {{ node.name }}
+ {{ node.resources.length }} recursos
+
-
-
+
{{ node.description }}
+
+
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+
Adicionar Novo Segmento
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Deletar segmento
+
Selecione um segmento da área "{{ selectedArea()?.name }}" para remover:
+
+
+
+ @for (node of getNodesForArea(selectedArea()!); track node) {
+ @if (node.id !== selectedArea()?.id) {
+
+ }
+ }
+
- }
+
+
+
} @else {
-
-
👈
-
Selecione uma área para editar seus recursos
-
+
+
👈
+
Selecione uma área para editar seus recursos
+
}
`,
- styles: [`
- .admin {
- max-width: 1200px;
- margin: 0 auto;
- padding: 2rem;
- }
+ styles: [
+ `
+ .admin {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 2rem;
+ }
- .admin-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 1.5rem;
- flex-wrap: wrap;
- gap: 1rem;
- }
+ .admin-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin-bottom: 1.5rem;
+ flex-wrap: wrap;
+ gap: 1rem;
+ }
- h1 { font-size: 1.8rem; font-weight: 800; margin: 0 0 0.25rem; color: var(--text-primary); }
- .admin-header > div > p { color: var(--text-secondary); margin: 0; }
-
- .header-actions { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; }
-
- .btn-save {
- padding: 0.6rem 1.25rem;
- background: var(--gradient);
- color: white;
- border: none;
- border-radius: 8px;
- font-weight: 600;
- cursor: pointer;
- transition: opacity 0.2s;
- &:disabled { opacity: 0.6; cursor: not-allowed; }
- }
+ h1 {
+ font-size: 1.8rem;
+ font-weight: 800;
+ margin: 0 0 0.25rem;
+ color: var(--text-primary);
+ }
+ .admin-header > div > p {
+ color: var(--text-secondary);
+ margin: 0;
+ }
- .btn-secondary {
- padding: 0.6rem 1rem;
- border: 1px solid var(--border);
- border-radius: 8px;
- color: var(--text-secondary);
- text-decoration: none;
- font-size: 0.875rem;
- transition: all 0.2s;
- &:hover { border-color: var(--text-primary); color: var(--text-primary); }
- }
+ .header-actions {
+ display: flex;
+ gap: 0.75rem;
+ align-items: center;
+ flex-wrap: wrap;
+ }
- .toast {
- padding: 1rem 1.25rem;
- border-radius: 10px;
- margin-bottom: 1.5rem;
- font-weight: 500;
- &.success { background: rgba(16, 185, 129, 0.1); border: 1px solid rgba(16, 185, 129, 0.3); color: #10b981; }
- }
+ .btn-save {
+ padding: 0.6rem 1.25rem;
+ background: var(--gradient);
+ color: white;
+ border: none;
+ border-radius: 8px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: opacity 0.2s;
+ &:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+ }
+ }
- .tree-layout {
- display: grid;
- grid-template-columns: 220px 1fr;
- gap: 1.5rem;
- min-height: 600px;
- }
+ .btn-secondary {
+ padding: 0.6rem 1rem;
+ border: 1px solid var(--border);
+ border-radius: 8px;
+ color: var(--text-secondary);
+ text-decoration: none;
+ font-size: 0.875rem;
+ transition: all 0.2s;
+ &:hover {
+ border-color: var(--text-primary);
+ color: var(--text-primary);
+ }
+ }
- @media (max-width: 640px) {
- .tree-layout { grid-template-columns: 1fr; }
- }
+ .toast {
+ padding: 1rem 1.25rem;
+ border-radius: 10px;
+ margin-bottom: 1.5rem;
+ font-weight: 500;
+ &.success {
+ background: rgba(16, 185, 129, 0.1);
+ border: 1px solid rgba(16, 185, 129, 0.3);
+ color: #10b981;
+ }
+ }
- .tree-nav {
- background: var(--panel-bg);
- border: 1px solid var(--border);
- border-radius: 14px;
- padding: 1rem;
- height: fit-content;
- position: sticky;
- top: 80px;
- }
+ .tree-layout {
+ display: grid;
+ grid-template-columns: 220px 1fr;
+ gap: 1.5rem;
+ min-height: 600px;
+ }
- .nav-title { font-size: 0.7rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.75rem; padding: 0 0.5rem; }
-
- .nav-item {
- display: block;
- width: 100%;
- text-align: left;
- padding: 0.6rem 0.75rem;
- background: transparent;
- border: none;
- border-left: 3px solid transparent;
- border-radius: 0 8px 8px 0;
- color: var(--text-secondary);
- font-size: 0.875rem;
- cursor: pointer;
- transition: all 0.15s;
- margin-bottom: 0.25rem;
- &:hover { background: var(--card-bg); color: var(--text-primary); }
- &.active { background: var(--card-bg); color: var(--text-primary); font-weight: 600; }
- }
+ @media (max-width: 640px) {
+ .tree-layout {
+ grid-template-columns: 1fr;
+ }
+ }
- .editor-panel {
- background: var(--panel-bg);
- border: 1px solid var(--border);
- border-radius: 14px;
- padding: 1.5rem;
- }
+ .tree-nav {
+ background: var(--panel-bg);
+ border: 1px solid var(--border);
+ border-radius: 14px;
+ padding: 1rem;
+ height: fit-content;
+ position: sticky;
+ top: 80px;
+ }
- h2 { font-size: 1.3rem; font-weight: 700; margin: 0 0 1.5rem; color: var(--text-primary); }
+ .nav-title {
+ font-size: 0.7rem;
+ font-weight: 700;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+ margin-bottom: 0.75rem;
+ padding: 0 0.5rem;
+ }
- .node-section {
- background: var(--card-bg);
- border: 1px solid var(--border);
- border-radius: 10px;
- padding: 1.25rem;
- margin-bottom: 1rem;
- }
+ .nav-item {
+ display: block;
+ width: 100%;
+ text-align: left;
+ padding: 0.6rem 0.75rem;
+ background: transparent;
+ border: none;
+ border-left: 3px solid transparent;
+ border-radius: 0 8px 8px 0;
+ color: var(--text-secondary);
+ font-size: 0.875rem;
+ cursor: pointer;
+ transition: all 0.15s;
+ margin-bottom: 0.25rem;
+ &:hover {
+ background: var(--card-bg);
+ color: var(--text-primary);
+ }
+ &.active {
+ background: var(--card-bg);
+ color: var(--text-primary);
+ font-weight: 600;
+ }
+ }
- .node-title {
- display: flex;
- justify-content: space-between;
- align-items: center;
- font-weight: 700;
- font-size: 1rem;
- color: var(--text-primary);
- margin-bottom: 0.5rem;
- }
+ .editor-panel {
+ background: var(--panel-bg);
+ border: 1px solid var(--border);
+ border-radius: 14px;
+ padding: 1.5rem;
+ }
- .node-badge {
- font-size: 0.7rem;
- font-weight: 600;
- color: var(--text-muted);
- background: var(--panel-bg);
- padding: 0.2rem 0.5rem;
- border-radius: 4px;
- border: 1px solid var(--border);
- }
+ h2 {
+ font-size: 1.3rem;
+ font-weight: 700;
+ margin: 0 0 1.5rem;
+ color: var(--text-primary);
+ }
- .node-desc { font-size: 0.8rem; color: var(--text-muted); margin: 0 0 1rem; }
+ .node-section {
+ background: var(--card-bg);
+ border: 1px solid var(--border);
+ border-radius: 10px;
+ padding: 1.25rem;
+ margin-bottom: 1rem;
+ }
- .res-row {
- display: grid;
- grid-template-columns: 110px 60px 1fr 1.5fr 32px;
- gap: 0.5rem;
- align-items: center;
- margin-bottom: 0.5rem;
- }
+ .node-title {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-weight: 700;
+ font-size: 1rem;
+ color: var(--text-primary);
+ margin-bottom: 0.5rem;
+ }
- @media (max-width: 900px) {
- .res-row { grid-template-columns: 1fr 1fr; }
- .url-input { grid-column: span 2; }
- }
+ .node-badge {
+ font-size: 0.7rem;
+ font-weight: 600;
+ color: var(--text-muted);
+ background: var(--panel-bg);
+ padding: 0.2rem 0.5rem;
+ border-radius: 4px;
+ border: 1px solid var(--border);
+ }
- input, select {
- padding: 0.45rem 0.6rem;
- background: var(--panel-bg);
- border: 1px solid var(--border);
- border-radius: 6px;
- color: var(--text-primary);
- font-size: 0.8rem;
- transition: border-color 0.2s;
- &:focus { outline: none; border-color: var(--accent); }
- }
+ .node-desc {
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ margin: 0 0 1rem;
+ }
- .btn-remove {
- width: 32px;
- height: 32px;
- background: transparent;
- border: 1px solid var(--border);
- border-radius: 6px;
- color: var(--text-muted);
- cursor: pointer;
- font-size: 0.9rem;
- transition: all 0.15s;
- display: flex;
- align-items: center;
- justify-content: center;
- &:hover { border-color: #ef4444; color: #ef4444; }
- }
+ .res-row {
+ display: grid;
+ grid-template-columns: 110px 60px 1fr 1.5fr 32px;
+ gap: 0.5rem;
+ align-items: center;
+ margin-bottom: 0.5rem;
+ }
- .btn-add-resource {
- margin-top: 0.5rem;
- padding: 0.45rem 1rem;
- background: transparent;
- border: 1px dashed var(--border);
- border-radius: 6px;
- color: var(--text-muted);
- font-size: 0.8rem;
- cursor: pointer;
- transition: all 0.2s;
- &:hover { border-color: var(--accent); color: var(--accent); }
- }
+ @media (max-width: 900px) {
+ .res-row {
+ grid-template-columns: 1fr 1fr;
+ }
+ .url-input {
+ grid-column: span 2;
+ }
+ }
- .editor-placeholder {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- background: var(--panel-bg);
- border: 1px solid var(--border);
- border-radius: 14px;
- gap: 1rem;
- color: var(--text-muted);
- font-size: 0.95rem;
- span { font-size: 3rem; }
- }
- `]
+ input,
+ select {
+ padding: 0.45rem 0.6rem;
+ background: var(--panel-bg);
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ color: var(--text-primary);
+ font-size: 0.8rem;
+ transition: border-color 0.2s;
+ &:focus {
+ outline: none;
+ border-color: var(--accent);
+ }
+ }
+
+ .btn-remove {
+ width: 32px;
+ height: 32px;
+ background: transparent;
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ color: var(--text-muted);
+ cursor: pointer;
+ font-size: 0.9rem;
+ transition: all 0.15s;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ &:hover {
+ border-color: #ef4444;
+ color: #ef4444;
+ }
+ }
+
+ .btn-add-resource {
+ margin-top: 0.5rem;
+ padding: 0.45rem 1rem;
+ background: transparent;
+ border: 1px dashed var(--border);
+ border-radius: 6px;
+ color: var(--text-muted);
+ font-size: 0.8rem;
+ cursor: pointer;
+ transition: all 0.2s;
+ &:hover {
+ border-color: var(--accent);
+ color: var(--accent);
+ }
+ }
+
+ .editor-placeholder {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ background: var(--panel-bg);
+ border: 1px solid var(--border);
+ border-radius: 14px;
+ gap: 1rem;
+ color: var(--text-muted);
+ font-size: 0.95rem;
+ span {
+ font-size: 3rem;
+ }
+ }
+
+ .add-item {
+ margin-top: 0.5rem;
+ padding: 0.45rem 1rem;
+ background: transparent;
+ border: 1px dashed var(--border);
+ border-radius: 6px;
+ color: var(--text-secondary);
+ font-size: 0.8rem;
+ cursor: pointer;
+ transition: all 0.2s;
+ &:hover {
+ border-color: var(--accent);
+ color: var(--accent);
+ }
+ }
+
+ .modal_admin {
+ display: flex;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+
+ background-color: rgba(20, 20, 20, 0.55);
+ justify-content: center;
+ align-items: center;
+ }
+
+ #modal_content_admin,
+ #modal_content_segment {
+ display: flex;
+ width: 500px;
+ gap: 15px;
+ flex-direction: column;
+ background-color: #0f172a;
+ padding: 20px;
+ border-radius: 10px;
+ }
+
+ .campo {
+ background-color: #0f172a;
+ display: flex;
+ flex-direction: column;
+ padding: 10px;
+ border-radius: 8px;
+ }
+
+ .dropbtn {
+ background-color: transparent;
+ color: white;
+ padding: 16px;
+ font-size: 16px;
+ cursor: pointer;
+ width: 150px;
+
+ border-radius: 10%;
+ text-align: center;
+ font-size: 14px;
+ border-color: #a6b3c5;
+ }
+
+ .dropbtn:hover,
+ .dropbtn:focus {
+ background-color: #297fb93a;
+ }
+
+ .dropdown {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+
+ .dropdown-content {
+ display: none;
+ position: absolute;
+ background-color: #203147;
+ min-width: 150px;
+ border-radius: 10%;
+ box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
+ z-index: 1;
+ }
+
+ .dropdown-content button {
+ color: var(--text-primary);
+ padding: 0.6rem 1rem;
+ text-decoration: none;
+ display: block;
+ background: transparent;
+ border: none;
+ width: 100%;
+ text-align: left;
+ cursor: pointer;
+ font-size: 0.875rem;
+ transition: background 0.15s ease;
+ &:hover {
+ background: var(--panel-bg);
+ }
+ &.active {
+ background: var(--accent);
+ color: white;
+ font-weight: 600;
+ }
+ }
+
+ .dropdown-content button:hover {
+ background-color: #4b4343;
+ }
+
+ .show {
+ display: block;
+ }
+
+ .modal_dropdown {
+ display: flex;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ background: rgba(20, 20, 20, 0.55);
+ justify-content: center;
+ align-items: center;
+ z-index: 2000;
+ }
+
+ .modal_dropdown h3 {
+ color: white;
+ }
+
+ .modal_content_dropdown h3 {
+ color: var(--text-primary);
+ font-size: 1.2rem;
+ font-weight: 700;
+ margin: 0 0 0.5rem 0;
+ letter-spacing: 0.01em;
+ text-align: left;
+ }
+
+ .modal_content_dropdown {
+ background: var(--panel-bg);
+ border: 1.5px solid var(--border);
+ border-radius: 14px;
+ box-shadow: 0 8px 32px 0 rgba(16, 23, 42, 0.45);
+ padding: 2rem 2.5rem 1.5rem 2.5rem;
+ min-width: 320px;
+ min-height: 180px;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 1.5rem;
+ }
+
+ .btn-remove-area {
+ padding: 0.75rem 1.25rem;
+ background: var(--danger);
+ border: none;
+ border-radius: 8px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ margin-top: 0.5rem;
+ &:hover {
+ background: #dc2626;
+ transform: translateY(-1px);
+ }
+ &:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+ transform: none;
+ }
+ }
+ `,
+ ],
})
export class AdminComponent implements OnInit, OnDestroy {
private competencyService = inject(CompetencyService);
+ areaName = "";
+ areaDescription = "";
+ areaColor = "#123456";
+ areaIcon = "";
+
areas = signal
([]);
selectedArea = signal(null);
saving = signal(false);
@@ -311,19 +816,212 @@ export class AdminComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.sub.add(
- this.competencyService.map$.subscribe(map => {
+ this.competencyService.map$.subscribe((map) => {
this.mapRef = map;
this.areas.set(map.children ?? []);
// Refresh selected area reference
if (this.selectedArea()) {
- const updated = (map.children ?? []).find(a => a.id === this.selectedArea()!.id);
+ const updated = (map.children ?? []).find(
+ (a) => a.id === this.selectedArea()!.id
+ );
if (updated) this.selectedArea.set(updated);
}
})
);
}
- ngOnDestroy(): void { this.sub.unsubscribe(); }
+ isAddAreaModalVisible = false;
+ isRemoveAreaModalVisible = false;
+ isDropdownOpen = false;
+
+ openAddAreaModal() {
+ this.isAddAreaModalVisible = true;
+ }
+ closeAddAreaModal() {
+ this.isAddAreaModalVisible = false;
+ }
+
+ openRemoveAreaModal() {
+ this.isRemoveAreaModalVisible = true;
+ }
+ closeRemoveAreaModal() {
+ this.isRemoveAreaModalVisible = false;
+ }
+
+ isAddSegmentModalVisible = false;
+ isRemoveSegmentModalVisible = false;
+ isSegmentDropdownOpen = false;
+ segmentName = "";
+ segmentDescription = "";
+ segmentIcon = "";
+ selectedNodeForSegment: Competency | null = null;
+ selectedSegmentToRemove = signal(null);
+
+ openAddSegmentModal(node: Competency) {
+ this.selectedNodeForSegment = node;
+ this.segmentIcon = node.icon;
+ this.isAddSegmentModalVisible = true;
+ }
+
+ closeAddSegmentModal() {
+ this.isAddSegmentModalVisible = false;
+ this.selectedNodeForSegment = null;
+ this.segmentName = "";
+ this.segmentDescription = "";
+ this.segmentIcon = "";
+ }
+
+ openRemoveSegmentModal() {
+ this.isRemoveSegmentModalVisible = true;
+ this.selectedSegmentToRemove.set(null);
+ this.isSegmentDropdownOpen = false;
+ }
+
+ closeRemoveSegmentModal() {
+ this.isRemoveSegmentModalVisible = false;
+ this.selectedSegmentToRemove.set(null);
+ this.isSegmentDropdownOpen = false;
+ }
+
+ toggleSegmentDropdown() {
+ this.isSegmentDropdownOpen = !this.isSegmentDropdownOpen;
+ }
+
+ selectSegmentToRemove(segment: Competency) {
+ this.selectedSegmentToRemove.set(segment);
+ this.isSegmentDropdownOpen = false;
+ }
+
+ removeSegment(segment: Competency) {
+ if (!this.mapRef || !segment) return;
+
+ // Alerta: Não permitimos remover o root ou a área selecionada por este botão
+ if (segment.id === 'root' || (this.selectedArea() && segment.id === this.selectedArea()?.id)) {
+ this.closeRemoveSegmentModal();
+ return;
+ }
+
+ // Função recursiva para encontrar o pai e remover o filho usando splice
+ const removeRecursive = (root: Competency, target: Competency): boolean => {
+ if (!root.children) return false;
+
+ const index = root.children.findIndex(c =>
+ c === target || (target.id && c.id === target.id)
+ );
+
+ if (index !== -1) {
+ root.children.splice(index, 1);
+ return true;
+ }
+
+ for (const child of root.children) {
+ if (removeRecursive(child, target)) return true;
+ }
+ return false;
+ };
+
+ if (removeRecursive(this.mapRef, segment)) {
+ this.areas.set([...(this.mapRef.children ?? [])]);
+
+ if (this.selectedArea()) {
+ const updatedArea = this.findNodeInMap(this.mapRef, this.selectedArea()!.id);
+ if (updatedArea) {
+ this.selectedArea.set({ ...updatedArea });
+ } else {
+ this.selectedArea.set(null);
+ }
+ }
+ }
+
+ this.closeRemoveSegmentModal();
+ }
+
+ private findNodeInMap(root: Competency, id: string): Competency | null {
+ if (root.id === id) return root;
+ if (root.children) {
+ for (const child of root.children) {
+ const found = this.findNodeInMap(child, id);
+ if (found) return found;
+ }
+ }
+ return null;
+ }
+
+ addSegment(): void {
+ const areaRef = this.selectedArea();
+ if (!this.segmentName?.trim() || !this.mapRef || !areaRef) {
+ return;
+ }
+
+ const targetNode = this.findNodeInMap(this.mapRef, areaRef.id);
+ if (targetNode) {
+ if (!targetNode.children) targetNode.children = [];
+
+ targetNode.children.push({
+ id: "seg_" + Date.now(),
+ name: this.segmentName,
+ description: this.segmentDescription,
+ color: targetNode.color,
+ icon: this.segmentIcon || targetNode.icon,
+ resources: [],
+ children: [],
+ });
+
+ this.selectedArea.set({ ...targetNode });
+ this.areas.set([...(this.mapRef.children ?? [])]);
+ }
+
+ this.closeAddSegmentModal();
+ }
+
+ dropdown_active() {
+ this.isDropdownOpen = !this.isDropdownOpen;
+ }
+
+ closeDropdown() {
+ this.isDropdownOpen = false;
+ }
+
+ addArea(
+ name: string,
+ description: string,
+ color: string,
+ icon: string
+ ): void {
+ if (!name?.trim()) {
+ return;
+ }
+ if (this.mapRef) {
+ add_new_area(name, description, color, icon, this.mapRef);
+ this.areas.set(this.mapRef.children ?? []);
+ this.areaName = "";
+ this.areaDescription = "";
+ this.areaColor = "#123456";
+ this.areaIcon = "";
+ this.closeAddAreaModal();
+ }
+
+ }
+
+ selectedAreaToRemove = signal(null);
+
+ removeArea(area: Competency): void {
+ if (!this.mapRef) return;
+ this.mapRef.children = (this.mapRef.children ?? []).filter(
+ (a) => a.id !== area.id
+ );
+ this.areas.set(this.mapRef.children);
+ this.closeRemoveAreaModal();
+ }
+
+ selectAreaToRemove(area: Competency): void {
+ this.selectedAreaToRemove.set(area);
+ this.closeDropdown();
+ }
+
+ ngOnDestroy(): void {
+ this.sub.unsubscribe();
+ }
selectArea(area: Competency): void {
this.selectedArea.set(area);
@@ -334,9 +1032,15 @@ export class AdminComponent implements OnInit, OnDestroy {
}
addResource(node: Competency): void {
- node.resources = [...node.resources, {
- title: '', url: '', type: 'video', language: 'pt'
- }];
+ node.resources = [
+ ...node.resources,
+ {
+ title: "",
+ url: "",
+ type: "video",
+ language: "pt",
+ },
+ ];
}
removeResource(node: Competency, index: number): void {
diff --git a/src/app/models/competency.model.ts b/src/app/models/competency.model.ts
index d2b93f8..d5a6749 100644
--- a/src/app/models/competency.model.ts
+++ b/src/app/models/competency.model.ts
@@ -209,3 +209,58 @@ export const DEFAULT_COMPETENCY_MAP: Competency = {
}
]
};
+
+export function add_new_area(
+ name: string,
+ description: string,
+ color: string,
+ icon: string,
+ node: Competency
+): void {
+ if (!node.children) node.children = [];
+ const newCompetency: Competency = {
+ id: 'area_' + Date.now(),
+ name,
+ description,
+ color,
+ icon,
+ resources: [],
+ children: []
+ };
+ node.children.push(newCompetency);
+}
+
+export function remove_area(competencyId: string, node: Competency): boolean {
+ if (!node.children) return false;
+ const index = node.children.findIndex(c => c.id === competencyId);
+ if (index !== -1) {
+ node.children.splice(index, 1);
+ return true;
+ }
+ else{
+ return false;
+ }
+}
+
+export function add_new_Resource(
+ title: string,
+ url: string,
+ type: 'video' | 'article' | 'course' | 'docs',
+ language: 'pt' | 'en',
+ node: Competency
+): void {
+ if (!node.resources) node.resources = [];
+ const newResource: Resource = {
+ title,
+ url,
+ type,
+ language
+ };
+ node.resources.push(newResource);
+}
+
+export function remove_resource(resourceId: string, nodeId: string): void {
+ if (!DEFAULT_COMPETENCY_MAP.children) return ;
+ const node = DEFAULT_COMPETENCY_MAP.children.find(child => child.id === nodeId);
+ node?.children?.filter(child => child.id === nodeId);
+}