feat: catalogo dinamico de tipificaciones de hitos, matriz RBAC y desacoplamiento en modal de eventos
This commit is contained in:
+4
-13
@@ -16,19 +16,10 @@
|
||||
<ion-list lines="inset" class="compact-list">
|
||||
<ion-item class="input-item">
|
||||
<ion-label position="stacked">Tipo e Hito</ion-label>
|
||||
<ion-select [(ngModel)]="tipo" interface="popover">
|
||||
<ion-select-option value="Parcial 1">Parcial 1</ion-select-option>
|
||||
<ion-select-option value="Parcial 2">Parcial 2</ion-select-option>
|
||||
<ion-select-option value="TP 1">Trabajo Práctico 1</ion-select-option>
|
||||
<ion-select-option value="TP 2">Trabajo Práctico 2</ion-select-option>
|
||||
<ion-select-option value="TP 3">Trabajo Práctico 3</ion-select-option>
|
||||
<ion-select-option value="Recu. P1">Recuperatorio Parcial 1</ion-select-option>
|
||||
<ion-select-option value="Recu. P2">Recuperatorio Parcial 2</ion-select-option>
|
||||
<ion-select-option value="Recu. TP 1">Recuperatorio TP 1</ion-select-option>
|
||||
<ion-select-option value="Recu. TP 2">Recuperatorio TP 2</ion-select-option>
|
||||
<ion-select-option value="Recu. TP 3">Recuperatorio TP 3</ion-select-option>
|
||||
<ion-select-option value="Final">Final</ion-select-option>
|
||||
<ion-select-option value="Otro">Otro</ion-select-option>
|
||||
<ion-select [(ngModel)]="tipo" interface="popover" placeholder="Seleccionar tipo de hito">
|
||||
<ion-select-option *ngFor="let opt of milestoneTypes" [value]="opt.name">
|
||||
{{ opt.name }}
|
||||
</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
|
||||
+49
-2
@@ -7,6 +7,36 @@ import { EventosService } from '../../services/eventos.service';
|
||||
import { CapacitorCalendar } from '@ebarooni/capacitor-calendar';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-evento-modal',
|
||||
templateUrl: './evento-modal.component.html',
|
||||
styleUrls: ['./evento-modal.component.scss'],
|
||||
standalone: true,
|
||||
imports: [CommonModule, IonicModule, FormsModule]
|
||||
})
|
||||
export interface MilestoneTypeOption {
|
||||
id?: number;
|
||||
name: string;
|
||||
code?: string;
|
||||
color?: string;
|
||||
is_active?: boolean;
|
||||
}
|
||||
|
||||
export const DEFAULT_MILESTONE_TYPES: MilestoneTypeOption[] = [
|
||||
{ name: 'Parcial 1', code: 'parcial_1', color: '#0d6efd' },
|
||||
{ name: 'Parcial 2', code: 'parcial_2', color: '#0b5ed7' },
|
||||
{ name: 'Trabajo Práctico 1', code: 'tp_1', color: '#198754' },
|
||||
{ name: 'Trabajo Práctico 2', code: 'tp_2', color: '#157347' },
|
||||
{ name: 'Trabajo Práctico 3', code: 'tp_3', color: '#0f5132' },
|
||||
{ name: 'Recuperatorio Parcial 1', code: 'recu_p1', color: '#fd7e14' },
|
||||
{ name: 'Recuperatorio Parcial 2', code: 'recu_p2', color: '#e76b08' },
|
||||
{ name: 'Recuperatorio TP 1', code: 'recu_tp1', color: '#ffc107' },
|
||||
{ name: 'Recuperatorio TP 2', code: 'recu_tp2', color: '#e0a800' },
|
||||
{ name: 'Recuperatorio TP 3', code: 'recu_tp3', color: '#c69500' },
|
||||
{ name: 'Final', code: 'final', color: '#dc3545' },
|
||||
{ name: 'Otro', code: 'otro', color: '#6c757d' }
|
||||
];
|
||||
|
||||
@Component({
|
||||
selector: 'app-evento-modal',
|
||||
templateUrl: './evento-modal.component.html',
|
||||
@@ -19,7 +49,8 @@ export class EventoModalComponent implements OnInit {
|
||||
@Input() materiaNombre!: string;
|
||||
@Input() eventoExistente?: EventoAcademico;
|
||||
|
||||
tipo: 'Parcial' | 'TP' | 'Final' | 'Otro' = 'Parcial';
|
||||
tipo: string = 'Parcial 1';
|
||||
milestoneTypes: MilestoneTypeOption[] = DEFAULT_MILESTONE_TYPES;
|
||||
fecha: string = new Date().toISOString();
|
||||
aula: string = '';
|
||||
link: string = '';
|
||||
@@ -34,7 +65,9 @@ export class EventoModalComponent implements OnInit {
|
||||
private toastCtrl: ToastController
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
async ngOnInit() {
|
||||
await this.cargarTipificaciones();
|
||||
|
||||
if (this.eventoExistente) {
|
||||
this.isEdit = true;
|
||||
this.tipo = this.eventoExistente.tipo;
|
||||
@@ -45,6 +78,20 @@ export class EventoModalComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
async cargarTipificaciones() {
|
||||
try {
|
||||
const response = await fetch('/api/milestone-types');
|
||||
if (response.ok) {
|
||||
const data: MilestoneTypeOption[] = await response.json();
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
this.milestoneTypes = data.filter(d => d.is_active !== false);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Mantiene catálogo predeterminado si no hay conexión al backend
|
||||
}
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.modalCtrl.dismiss();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export interface ClaseHorario {
|
||||
export interface EventoAcademico {
|
||||
id: string;
|
||||
materiaCodigo: string;
|
||||
tipo: 'Parcial' | 'TP' | 'Final' | 'Otro';
|
||||
tipo: string; // Dinámico según catálogo MilestoneType
|
||||
fecha: string; // ISO string
|
||||
aula?: string;
|
||||
link?: string;
|
||||
|
||||
Reference in New Issue
Block a user