Passa al contenuto principale

Componenti UI — dominio edu

🎯 Cosa fa

Sotto TrainingHub.BackOffice/Components/CRUD/edu/ vivono i componenti Blazor CRUD auto-generati per le ~38 entità del dominio formazione. Il pattern di generazione è lo stesso di inv e reg (triade razor + razor.tt.cs + razor.cs + Forms/ + FormPopups/). Vedi componenti UI inv per i dettagli.

Questa pagina documenta le particolarità edu-specifiche.

🗺️ Entità core in scope

EntitàFileNote
CategoryCategory.razorAnagrafica semplice
CourseCourse.razorForm ricco con cascade variante normativa
TrainingSessionTrainingSession.razorSessione formativa (ciclo vita stati)
TrainingSessionsCourseTrainingSessionsCourse.razorM:N session ↔ corso (co-erogazione)
AppointmentAppointment.razor (grid CRUD) + Pages/AppointmentsCalendar/ (vista calendario page-level)Doppia vista griglia + calendario
AppointmentsCourseAppointmentsCourse.razorCella della matrice "programma" (appointment × corso)
AppointmentsCoursesArgumentAppointmentsCoursesArgument.razorArgomenti trattati per slot × corso
LocationLocation.razorAule con indirizzo inline + FK opzionale a reg.companies (gestore aula)
TeacherTeacher.razorAnagrafica docente
AppointmentsTeacherAppointmentsTeacher.razorM:N con hourlyAmount
TeacherCostTeacherCost.razorCosti per organizer
TeacherSkillTeacherSkill.razorCompetenze docente (skill matrix ↔ variant)

🧩 Pattern chiave edu-specifici

Vista calendario appuntamenti

Pages/AppointmentsCalendar/AppointmentsCalendar.razor (route /appointments-calendar) è la vista calendario principale degli appuntamenti, complementare alla griglia standard Appointment.razor. Scritta a mano (non CRUD-generata). Sub-componenti:

  • CalendarGrid.razor — rendering mese/settimana/giorno.
  • AppointmentDetailPanel.razor — pannello laterale con dettagli appuntamento + contesto sessione + azioni Edit/Duplica/Modifica sessione.

Caratteristiche principali (per dettaglio vedi panoramica edu — Vista calendario custom):

  • Filtri Corso/Sede/Docente/Sessione con cascade Corso → Sessione.
  • Colore appuntamento derivato da trainingTopics.color (primo topic alfabetico della session).
  • Click slot apre AppointmentFormPopup; pulsante "Nuova Sessione" apre SessionPlannerPopup.
  • Conflict detection via ISessionPlannerService.DetectConflictsAsync con toast warning post-save.
  • Query param ?teacherId=<guid> per landing dal teacher-calendar.

Wizard pianificazione sessione

Components/edu/SessionPlanner/SessionPlannerPopup.razor è un wizard 7-step per pianificare una sessione formativa end-to-end. Le partial class SessionPlannerPopup.razor.Step1Session.csSessionPlannerPopup.razor.Step6Review.cs (più SessionPlannerPopup.razor.Step4Program.cs) contengono la logica per-step.

Il backend è ISessionPlannerService (in Shared/Services/SessionPlanner/) con stato persistito su SessionPlannerState + SessionCoursePlan[].

Step:

  1. Sessione — data inizio + argomento opzionale (filtra corsi).
  2. Corsi — aggiunge uno o più corsi in co-erogazione con finestre orarie per-corso.
  3. Date e sedi — appuntamenti fisici e sede.
  4. Programma — matrice appuntamento × corso (TrainingSessionProgramMatrix): dichiara quali corsi sono erogati in ogni slot e popola gli argomenti per cella (slot × corso). Logica in SessionPlannerPopup.razor.Step4Program.cs.
  5. Docenti — assegnazione con "Suggerisci docenti per skill" (filtro su teacherSkills del corso). Logica in SessionPlannerPopup.razor.Step4Teachers.cs.
  6. Iscritti — aggiunta workers con scelta del corso di destinazione; integrazione con coda richieste e scadenziario.
  7. Riepilogo costi — stima Iscrizioni + Docenze + Aule prima del confirm finale.

Punti d'ingresso: lista corsi, lista sessioni, coda richieste, scadenziario, scheda lavoratore, calendario (pulsante "Nuova Sessione").

Vista dati aggregati

AppointmentsData.razor fornisce una vista di dati aggregati per analisi (totale ore per docente, saturazione aule, ecc.), distinta dal CRUD. Non è un CRUD: è una pagina di reportistica.

Cascade variante normativa in Course

Il form CourseForm.razor ha un combobox Variante normativa che, al cambio, pre-popola campi come durata minima e obblighi (logica nel .razor.cs). Pattern simile al cascade ATECO → riskLevel del form aziende.

Location con indirizzo inline e FK a reg.companies

Il form LocationForm.razor espone i campi indirizzo direttamente sull'aula (formattedAddress + geocoded country/province/city/zipCode/address/streetNumber/latitude/longitude) e un combobox opzionale companyId per il gestore aula (azienda proprietaria, NULL = aula 3SD). Cross-dominio: edu consuma reg per le aziende gestrici.

Suggerimento docenti per skill

Il filtro per competenza non vive più sul form AppointmentForm.razor (l'appuntamento non ha più una lezione associata): lo step "Docenti" del wizard SessionPlannerPopup.Step4Teachers usa il pulsante "Suggerisci docenti per skill" che incrocia edu.teacherSkills.trainingVariantId con le varianti dei corsi erogati nella sessione (trainingSessionsCourses → courses → trainingVariantId).

📁 File chiave

  • Components/CRUD/edu/Course.razor.cs — code-behind principale
  • Components/CRUD/edu/Forms/CourseForm.razor — form con cascade variante
  • Components/Pages/AppointmentsCalendar/ — vista calendario page-level (AppointmentsCalendar.razor, CalendarGrid.razor, AppointmentDetailPanel.razor)
  • Components/edu/SessionPlanner/ — wizard 7-step pianificazione sessione (SessionPlannerPopup.razor + Step1..Step6 + Step4Program partial; TrainingSessionProgramMatrix.razor per lo step Programma)
  • Components/CRUD/edu/AppointmentsData.razor — vista dati aggregati
  • Components/CRUD/edu/_conf/*.dxgrid.conf.json — configurazione

🔌 Estensione tipica

Segue il pattern generale (vedi componenti UI inv). Specificità edu:

  • Aggiungere un campo a Course. Rigenera + valuta se il cascade variante va aggiornato per precompilare anche il nuovo campo.
  • Nuova vista analitica cross-dominio. Aggiungi una nuova pagina Razor non-CRUD in CRUD/edu/ (es. MyAnalytics.razor), inject i service necessari. Non serve conf.json. Routing dichiarato con @page direttiva.
  • Estendere vista calendario. I file in Pages/AppointmentsCalendar/ sono scritti a mano — non CRUD generato. Modifiche dirette senza rigenerazione. Per aggiungere un filtro nuovo: aggiungi il combobox in AppointmentsCalendar.razor, il backing field nel code-behind, e passa il valore a IAppointmentsCalendarService.GetAppointmentsAsync.

⚠️ Debito tecnico

  • AppointmentsCalendar senza test UI. Componente complesso custom, non coperto da test automatici.
  • Filtro docenti per competenza. Coperto dallo step 4 del SessionPlannerPopup ("Suggerisci docenti per skill") che usa la skill matrix edu.teacherSkills.

🔗 Vedi anche