Mitarbeit bewerten begonnen, Schülerdaten, Gruppen

This commit is contained in:
2026-06-23 10:12:52 +02:00
parent fdbaa9ef4d
commit b2211270b4
32 changed files with 1968 additions and 49 deletions
@@ -21,6 +21,9 @@ public partial class GroupListViewModel : ObservableObject
[ObservableProperty] private string _searchText = "";
[ObservableProperty] private GroupListItem? _selectedGroup;
public string SelectedGroupDisplayName => SelectedGroup?.DisplayName ?? "";
public string SelectedGroupSubtitle => SelectedGroup?.Subtitle ?? "";
public ObservableCollection<string> SchoolYears { get; } = [];
public ObservableCollection<GroupListItem> Groups { get; } = [];
@@ -33,8 +36,12 @@ public partial class GroupListViewModel : ObservableObject
partial void OnSelectedSchoolYearChanged(string value) => LoadGroups();
partial void OnSearchTextChanged(string value) => LoadGroups();
partial void OnSelectedGroupChanged(GroupListItem? value) =>
partial void OnSelectedGroupChanged(GroupListItem? value)
{
OnPropertyChanged(nameof(SelectedGroupDisplayName));
OnPropertyChanged(nameof(SelectedGroupSubtitle));
NavigateToSectionCommand.NotifyCanExecuteChanged();
}
public void LoadGroups()
{
@@ -88,6 +95,7 @@ public partial class GroupDetailViewModel : ObservableObject
{
private readonly IGroupRepository _groups;
private readonly IStudentRepository _students;
private readonly IEnrollmentRepository _enrollments;
private readonly IExamRepository _exams;
private readonly IGradeRepository _grades;
@@ -96,14 +104,21 @@ public partial class GroupDetailViewModel : ObservableObject
[ObservableProperty] private string _groupSubtitle = "";
[ObservableProperty] private int _studentCount;
[ObservableProperty] private int _activeTabIndex = 0;
[ObservableProperty] private StudentSummary? _selectedStudent;
public ObservableCollection<StudentSummary> Students { get; } = [];
public ObservableCollection<ExamSummary> Exams { get; } = [];
public ParticipationTabViewModel ParticipationTab { get; }
public Func<Task<bool>>? OnAddStudent { get; set; }
public GroupDetailViewModel(IGroupRepository groups, IStudentRepository students,
IExamRepository exams, IGradeRepository grades)
IEnrollmentRepository enrollments, IExamRepository exams, IGradeRepository grades,
ParticipationTabViewModel participationTab)
{
_groups = groups; _students = students; _exams = exams; _grades = grades;
_groups = groups; _students = students; _enrollments = enrollments;
_exams = exams; _grades = grades;
ParticipationTab = participationTab;
}
public void LoadGroup(Guid id)
@@ -114,19 +129,48 @@ public partial class GroupDetailViewModel : ObservableObject
GroupSubtitle = $"{Group.SchoolYear} · " +
$"{(Group.Type == GroupType.Class ? "Klasse" : "Kurs")} · " +
$"Stufe {Group.GradeLevel} · Noten {(Group.GradingSystem == GradingSystem.Grades1To6 ? "16" : "015")}";
LoadStudents();
Exams.Clear();
foreach (var e in _exams.GetByGroup(Group.Id)) Exams.Add(new ExamSummary(e));
ParticipationTab.Initialize(Group.Id, Group.SchoolYear);
}
public void LoadStudents()
{
if (Group is null) return;
Students.Clear();
var enrolled = _students.GetByGroup(Group.Id, Group.SchoolYear);
StudentCount = enrolled.Count;
foreach (var s in enrolled) Students.Add(new StudentSummary(s));
Exams.Clear();
foreach (var e in _exams.GetByGroup(Group.Id)) Exams.Add(new ExamSummary(e));
}
[RelayCommand] private void AddStudent() { /* TODO */ }
[RelayCommand] private void AddExam() { /* TODO */ }
[RelayCommand] private void Refresh() { if (Group is not null) LoadGroup(Group.Id); }
[RelayCommand]
private async Task AddStudent()
{
if (OnAddStudent is null) return;
var confirmed = await OnAddStudent();
if (confirmed) LoadStudents();
}
[RelayCommand(CanExecute = nameof(HasSelectedStudent))]
private void RemoveStudent()
{
if (Group is null || SelectedStudent is null) return;
var enrollment = _enrollments.GetByGroupAndYear(Group.Id, Group.SchoolYear)
.FirstOrDefault(e => e.StudentId == SelectedStudent.Id);
if (enrollment is null) return;
_enrollments.Delete(enrollment.Id);
LoadStudents();
SelectedStudent = null;
}
partial void OnSelectedStudentChanged(StudentSummary? value) =>
RemoveStudentCommand.NotifyCanExecuteChanged();
private bool HasSelectedStudent() => SelectedStudent is not null;
[RelayCommand] private void AddExam() { /* TODO */ }
[RelayCommand] private void Refresh() { if (Group is not null) LoadGroup(Group.Id); }
}
public class StudentSummary
@@ -156,6 +200,66 @@ public class ExamSummary
}
}
// ── Dialog: Schüler zur Gruppe hinzufügen ─────────────────────────────────────
public partial class AddStudentToGroupDialogViewModel : ObservableObject
{
private readonly IStudentRepository _students;
private readonly IEnrollmentRepository _enrollments;
private readonly Guid _groupId;
private readonly string _schoolYear;
[ObservableProperty] private string _searchText = "";
[ObservableProperty] private StudentPickerItem? _selectedStudent;
[ObservableProperty] private string _validationMessage = "";
public ObservableCollection<StudentPickerItem> AvailableStudents { get; } = [];
public Enrollment? Result { get; private set; }
public AddStudentToGroupDialogViewModel(IStudentRepository students,
IEnrollmentRepository enrollments, Guid groupId, string schoolYear)
{
_students = students; _enrollments = enrollments;
_groupId = groupId; _schoolYear = schoolYear;
LoadAvailableStudents();
}
partial void OnSearchTextChanged(string value) => LoadAvailableStudents();
private void LoadAvailableStudents()
{
var alreadyEnrolled = _enrollments.GetByGroupAndYear(_groupId, _schoolYear)
.Select(e => e.StudentId).ToHashSet();
var all = _students.GetAll();
var available = all
.Where(s => !alreadyEnrolled.Contains(s.Id))
.Where(s => string.IsNullOrWhiteSpace(SearchText) ||
s.FullName.Contains(SearchText, StringComparison.OrdinalIgnoreCase));
AvailableStudents.Clear();
foreach (var s in available) AvailableStudents.Add(new StudentPickerItem(s));
}
[RelayCommand]
private void Save()
{
if (SelectedStudent is null) { ValidationMessage = "Bitte einen Schüler auswählen."; return; }
Result = new Enrollment
{
StudentId = SelectedStudent.Id,
GroupId = _groupId,
SchoolYear = _schoolYear,
};
_enrollments.Save(Result);
}
}
public class StudentPickerItem
{
public Guid Id { get; }
public string FullName { get; }
public StudentPickerItem(Student s) { Id = s.Id; FullName = s.FullName; }
}
// ── Dialog: Neue Lerngruppe anlegen ──────────────────────────────────────────
public partial class AddGroupDialogViewModel : ObservableObject