This commit is contained in:
2026-03-29 23:47:31 +02:00
commit 216d5d2280
75 changed files with 5702 additions and 0 deletions

View File

@@ -0,0 +1,223 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LehrerApp.Core.Interfaces;
using LehrerApp.Core.Models;
using System.Collections.ObjectModel;
namespace LehrerApp.Desktop.ViewModels.Students;
// ── Schülerliste ──────────────────────────────────────────────────────────────
public partial class StudentListViewModel : ObservableObject
{
private readonly IStudentRepository _students;
[ObservableProperty] private string _searchText = "";
[ObservableProperty] private bool _showInactive;
[ObservableProperty] private StudentListItem? _selectedStudent;
public ObservableCollection<StudentListItem> Students { get; } = [];
public StudentListViewModel(IStudentRepository students)
{
_students = students;
LoadStudents();
}
partial void OnSearchTextChanged(string value) => LoadStudents();
partial void OnShowInactiveChanged(bool value) => LoadStudents();
private void LoadStudents()
{
Students.Clear();
var all = _students.GetAll(includeInactive: ShowInactive);
var filtered = string.IsNullOrWhiteSpace(SearchText)
? all
: all.Where(s =>
s.LastName.Contains(SearchText, StringComparison.OrdinalIgnoreCase) ||
s.FirstName.Contains(SearchText, StringComparison.OrdinalIgnoreCase));
foreach (var s in filtered)
Students.Add(new StudentListItem(s));
}
[RelayCommand]
private void AddStudent()
{
// TODO: Neuer-Schüler-Dialog
}
[RelayCommand]
private void Refresh() => LoadStudents();
}
public class StudentListItem
{
public Guid Id { get; }
public string FullName { get; }
public string DateOfBirth { get; }
public bool IsActive { get; }
public StudentListItem(Student s)
{
Id = s.Id;
FullName = s.FullName;
DateOfBirth = s.DateOfBirth?.ToString("dd.MM.yyyy") ?? "";
IsActive = s.IsActive;
}
}
// ── Schülerdetail ─────────────────────────────────────────────────────────────
public partial class StudentDetailViewModel : ObservableObject
{
private readonly IStudentRepository _students;
private readonly IEnrollmentRepository _enrollments;
private readonly IGroupRepository _groups;
private readonly IGradeRepository _grades;
private readonly IDocumentationRepository _docs;
[ObservableProperty] private Student? _student;
[ObservableProperty] private string _studentTitle = "";
[ObservableProperty] private StudentTab _activeTab = StudentTab.Overview;
[ObservableProperty] private bool _isEditing;
// Bearbeitbare Felder
[ObservableProperty] private string _editFirstName = "";
[ObservableProperty] private string _editLastName = "";
[ObservableProperty] private string _editNotes = "";
public ObservableCollection<EnrollmentEntry> Enrollments { get; } = [];
public ObservableCollection<GradeEntry> Grades { get; } = [];
public ObservableCollection<DocEntry> Documentation { get; } = [];
public StudentDetailViewModel(
IStudentRepository students,
IEnrollmentRepository enrollments,
IGroupRepository groups,
IGradeRepository grades,
IDocumentationRepository docs)
{
_students = students;
_enrollments = enrollments;
_groups = groups;
_grades = grades;
_docs = docs;
}
public void LoadStudent(Guid studentId)
{
Student = _students.GetById(studentId);
if (Student is null) return;
StudentTitle = Student.FullName;
EditFirstName = Student.FirstName;
EditLastName = Student.LastName;
EditNotes = Student.Notes ?? "";
LoadEnrollments();
LoadDocs();
}
[RelayCommand]
private void SwitchTab(StudentTab tab) => ActiveTab = tab;
[RelayCommand]
private void StartEdit() => IsEditing = true;
[RelayCommand]
private void CancelEdit()
{
if (Student is null) return;
EditFirstName = Student.FirstName;
EditLastName = Student.LastName;
EditNotes = Student.Notes ?? "";
IsEditing = false;
}
[RelayCommand]
private void SaveEdit()
{
if (Student is null) return;
Student.FirstName = EditFirstName;
Student.LastName = EditLastName;
Student.Notes = string.IsNullOrWhiteSpace(EditNotes) ? null : EditNotes;
_students.Save(Student);
StudentTitle = Student.FullName;
IsEditing = false;
}
private void LoadEnrollments()
{
if (Student is null) return;
Enrollments.Clear();
var enrollments = _enrollments.GetByStudent(Student.Id);
var groupIds = enrollments.Select(e => e.GroupId).Distinct();
var groupMap = groupIds
.Select(id => _groups.GetById(id))
.Where(g => g is not null)
.ToDictionary(g => g!.Id);
foreach (var e in enrollments.OrderByDescending(e => e.SchoolYear))
{
if (!groupMap.TryGetValue(e.GroupId, out var group)) continue;
Enrollments.Add(new EnrollmentEntry
{
SchoolYear = e.SchoolYear,
GroupName = group.Name,
Subject = group.Subject ?? "",
});
}
}
private void LoadDocs()
{
if (Student is null) return;
Documentation.Clear();
foreach (var doc in _docs.GetByStudent(Student.Id))
{
Documentation.Add(new DocEntry
{
Date = doc.Date.ToString("dd.MM.yyyy"),
Title = doc.Title,
TypeLabel = doc.Type switch
{
DocumentationType.Conversation => "Gespräch",
DocumentationType.Incident => "Vorkommnis",
DocumentationType.SupportPlan => "Förderplan",
DocumentationType.Absence => "Fehlzeit",
_ => "",
},
IsConfidential = doc.IsConfidential,
});
}
}
}
public enum StudentTab { Overview, Grades, Documentation }
public class EnrollmentEntry
{
public string SchoolYear { get; set; } = "";
public string GroupName { get; set; } = "";
public string Subject { get; set; } = "";
}
public class GradeEntry
{
public string Date { get; set; } = "";
public string Value { get; set; } = "";
public string Category { get; set; } = "";
public string GroupName { get; set; } = "";
}
public class DocEntry
{
public string Date { get; set; } = "";
public string Title { get; set; } = "";
public string TypeLabel { get; set; } = "";
public bool IsConfidential { get; set; }
}