aufräumen
This commit is contained in:
@@ -13,6 +13,7 @@ public partial class DashboardViewModel : ObservableObject
|
||||
private static readonly CultureInfo De = new("de-DE");
|
||||
|
||||
private readonly IGroupRepository _groups;
|
||||
private readonly ISubjectRepository _subjects;
|
||||
private readonly ILessonRepository _lessons;
|
||||
private readonly IExamRepository _exams;
|
||||
private readonly IWorkTaskRepository _tasks;
|
||||
@@ -34,10 +35,10 @@ public partial class DashboardViewModel : ObservableObject
|
||||
// Navigation-Callback – wird von App.axaml.cs verdrahtet
|
||||
public Action<Guid>? OnNavigateToGroup { get; set; }
|
||||
|
||||
public DashboardViewModel(IGroupRepository groups, ILessonRepository lessons,
|
||||
public DashboardViewModel(IGroupRepository groups, ISubjectRepository subjects, ILessonRepository lessons,
|
||||
IExamRepository exams, IWorkTaskRepository tasks, SchoolYearService sy)
|
||||
{
|
||||
_groups = groups; _lessons = lessons; _exams = exams; _tasks = tasks; _sy = sy;
|
||||
_groups = groups; _subjects = subjects; _lessons = lessons; _exams = exams; _tasks = tasks; _sy = sy;
|
||||
Load();
|
||||
}
|
||||
|
||||
@@ -70,7 +71,12 @@ public partial class DashboardViewModel : ObservableObject
|
||||
|
||||
CurrentGroups.Clear();
|
||||
foreach (var g in groups.Values.OrderBy(g => g.Name))
|
||||
CurrentGroups.Add(new() { GroupId = g.Id, Name = g.Name, Subject = g.Subject ?? "" });
|
||||
CurrentGroups.Add(new()
|
||||
{
|
||||
GroupId = g.Id,
|
||||
Name = g.Name,
|
||||
Subject = g.SubjectId is Guid subjectId ? _subjects.GetById(subjectId)?.Name ?? "" : "",
|
||||
});
|
||||
|
||||
CalendarMonth = FirstOfMonth(now);
|
||||
LoadCalendar();
|
||||
|
||||
@@ -24,24 +24,24 @@ public partial class ExamGradingDialogViewModel : ObservableObject
|
||||
public ObservableCollection<ExamResultRow> Rows { get; } = [];
|
||||
|
||||
public ExamGradingDialogViewModel(IExamResultRepository results, IStudentRepository students,
|
||||
IEnrollmentRepository enrollments, GradingService grading, Exam exam, Guid groupId, string schoolYear)
|
||||
IGroupMembershipRepository memberships, GradingService grading, Exam exam, Guid groupId)
|
||||
{
|
||||
_results = results; _grading = grading; _exam = exam;
|
||||
Tasks = exam.Tasks.OrderBy(t => t.Nr).ToList();
|
||||
_examMaxPoints = Tasks.Sum(t => t.MaxPoints);
|
||||
|
||||
var enrolled = students.GetByGroup(groupId, schoolYear);
|
||||
var enrollmentList = enrollments.GetByGroupAndYear(groupId, schoolYear);
|
||||
var enrolled = students.GetByGroup(groupId);
|
||||
var membershipList = memberships.GetByGroup(groupId);
|
||||
var existing = results.GetByExam(exam.Id).ToDictionary(r => r.StudentId);
|
||||
|
||||
foreach (var s in enrolled.OrderBy(s => s.LastName).ThenBy(s => s.FirstName))
|
||||
{
|
||||
var enrollment = enrollmentList.FirstOrDefault(e => e.StudentId == s.Id);
|
||||
if (enrollment is not null && !IsEnrolledAtDate(enrollment, exam.Date)) continue;
|
||||
var membership = membershipList.FirstOrDefault(e => e.StudentId == s.Id);
|
||||
if (membership is not null && !IsMemberAtDate(membership, exam.Date)) continue;
|
||||
|
||||
// Niveau-Klausur: nur Schüler mit passendem Niveau zeigen. Klausuren ohne
|
||||
// Niveau-Zuordnung gelten weiterhin für die ganze Gruppe.
|
||||
if (exam.Niveau.HasValue && enrollment?.Niveau != exam.Niveau) continue;
|
||||
if (exam.Niveau.HasValue && membership?.Niveau != exam.Niveau) continue;
|
||||
|
||||
existing.TryGetValue(s.Id, out var result);
|
||||
var row = new ExamResultRow(s.Id, s.FullName, Tasks, result, _exam.GradingKey, _examMaxPoints, _grading);
|
||||
@@ -52,12 +52,12 @@ public partial class ExamGradingDialogViewModel : ObservableObject
|
||||
|
||||
private void SaveRow(ExamResultRow row) => _results.Save(row.ToModel(_exam.Id));
|
||||
|
||||
private static bool IsEnrolledAtDate(Enrollment e, DateOnly date) => e.Period switch
|
||||
private static bool IsMemberAtDate(GroupMembership membership, DateOnly date) => membership.Period switch
|
||||
{
|
||||
EnrollmentPeriod.H1Only => date.Month >= 8 || date.Month <= 1,
|
||||
EnrollmentPeriod.H2Only => date.Month >= 2 && date.Month <= 7,
|
||||
EnrollmentPeriod.Custom => (e.JoinedAt is null || date >= e.JoinedAt.Value)
|
||||
&& (e.LeftAt is null || date <= e.LeftAt.Value),
|
||||
MembershipPeriod.H1Only => date.Month >= 8 || date.Month <= 1,
|
||||
MembershipPeriod.H2Only => date.Month >= 2 && date.Month <= 7,
|
||||
MembershipPeriod.Custom => (membership.JoinedAt is null || date >= membership.JoinedAt.Value)
|
||||
&& (membership.LeftAt is null || date <= membership.LeftAt.Value),
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -289,7 +289,6 @@ public partial class ExamDialogViewModel : ObservableObject
|
||||
Result = _editingExam ?? new Exam { GroupId = _groupId };
|
||||
Result.Title = Title.Trim();
|
||||
Result.Date = date;
|
||||
Result.Subject = _subjectName.Trim();
|
||||
Result.ExamNumber = ExamNumber;
|
||||
Result.Notes = string.IsNullOrWhiteSpace(Notes) ? null : Notes.Trim();
|
||||
Result.ReturnedAt = returnedAt;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace LehrerApp.Desktop.ViewModels.Groups;
|
||||
public partial class GroupListViewModel : ObservableObject
|
||||
{
|
||||
private readonly IGroupRepository _groups;
|
||||
private readonly SchoolYearService _sy;
|
||||
private readonly ISubjectRepository _subjects;
|
||||
|
||||
public Action<Guid, int>? OnNavigateToDetail { get; set; }
|
||||
public Func<Task>? OnAddGroup { get; set; }
|
||||
@@ -37,9 +37,9 @@ public partial class GroupListViewModel : ObservableObject
|
||||
public ObservableCollection<string> SchoolYears { get; } = [];
|
||||
public ObservableCollection<GroupListItem> Groups { get; } = [];
|
||||
|
||||
public GroupListViewModel(IGroupRepository groups, SchoolYearService sy)
|
||||
public GroupListViewModel(IGroupRepository groups, ISubjectRepository subjects, SchoolYearService sy)
|
||||
{
|
||||
_groups = groups; _sy = sy;
|
||||
_groups = groups; _subjects = subjects;
|
||||
foreach (var y in sy.RecentSchoolYears()) SchoolYears.Add(y);
|
||||
SelectedSchoolYear = sy.CurrentSchoolYear();
|
||||
}
|
||||
@@ -63,11 +63,13 @@ public partial class GroupListViewModel : ObservableObject
|
||||
Groups.Clear();
|
||||
var all = _groups.GetBySchoolYear(SelectedSchoolYear, includeInactive: ShowArchived)
|
||||
.Where(g => g.IsActive != ShowArchived);
|
||||
var subjectNames = _subjects.GetAll().ToDictionary(s => s.Id, s => s.Name);
|
||||
var filtered = string.IsNullOrWhiteSpace(SearchText) ? all
|
||||
: all.Where(g => g.Name.Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|
||||
|| (g.Subject?.Contains(SearchText, StringComparison.OrdinalIgnoreCase) ?? false));
|
||||
|| (g.SubjectId is Guid id && subjectNames.GetValueOrDefault(id, "")
|
||||
.Contains(SearchText, StringComparison.OrdinalIgnoreCase)));
|
||||
foreach (var g in filtered.OrderBy(g => g.Name))
|
||||
Groups.Add(new GroupListItem(g));
|
||||
Groups.Add(new GroupListItem(g, g.SubjectId is Guid id ? subjectNames.GetValueOrDefault(id, "") : ""));
|
||||
SelectedGroup = Groups.FirstOrDefault(g => g.Id == selectedId);
|
||||
OnPropertyChanged(nameof(ListSummary));
|
||||
OnPropertyChanged(nameof(HasNoGroups));
|
||||
@@ -136,15 +138,15 @@ public class GroupListItem
|
||||
public bool IsActive { get; }
|
||||
public string ArchiveActionLabel => IsActive ? "Archivieren" : "Wieder aktivieren";
|
||||
|
||||
public GroupListItem(LearningGroup g)
|
||||
public GroupListItem(LearningGroup g, string subjectName)
|
||||
{
|
||||
Id = g.Id;
|
||||
IsActive = g.IsActive;
|
||||
Name = g.Name;
|
||||
Subject = g.Subject ?? "";
|
||||
Subject = subjectName;
|
||||
TypeLabel = g.Type == GroupType.Class ? "Klasse" : "Kurs";
|
||||
GradingLabel = g.GradingSystem == GradingSystem.Grades1To6 ? "1–6" : "0–15";
|
||||
DisplayName = string.IsNullOrEmpty(g.Subject) ? g.Name : $"{g.Name} · {g.Subject}";
|
||||
DisplayName = string.IsNullOrEmpty(subjectName) ? g.Name : $"{g.Name} · {subjectName}";
|
||||
Subtitle = $"{TypeLabel} · Stufe {g.GradeLevel} · Noten {GradingLabel} · {g.SchoolYear}";
|
||||
}
|
||||
}
|
||||
@@ -155,7 +157,8 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
{
|
||||
private readonly IGroupRepository _groups;
|
||||
private readonly IStudentRepository _students;
|
||||
private readonly IEnrollmentRepository _enrollments;
|
||||
private readonly IGroupMembershipRepository _memberships;
|
||||
private readonly ISubjectRepository _subjects;
|
||||
private readonly IExamRepository _exams;
|
||||
private readonly IGradeRepository _grades;
|
||||
|
||||
@@ -171,6 +174,7 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
// bevor LoadGroup() läuft (siehe MainWindowViewModel.NavigateToGroupDetail), Group ist dann
|
||||
// kurzzeitig null — ein verschachtelter Pfad würde dafür jedes Mal einen Binding-Fehler loggen.
|
||||
public bool IsDifferentiated => Group?.IsDifferentiated ?? false;
|
||||
public string SubjectName { get; private set; } = "";
|
||||
|
||||
partial void OnGroupChanged(LearningGroup? value) => OnPropertyChanged(nameof(IsDifferentiated));
|
||||
|
||||
@@ -187,10 +191,11 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
public Func<Exam, Task>? OnEvaluateExam { get; set; }
|
||||
|
||||
public GroupDetailViewModel(IGroupRepository groups, IStudentRepository students,
|
||||
IEnrollmentRepository enrollments, IExamRepository exams, IGradeRepository grades,
|
||||
IGroupMembershipRepository memberships, ISubjectRepository subjects,
|
||||
IExamRepository exams, IGradeRepository grades,
|
||||
ParticipationTabViewModel participationTab)
|
||||
{
|
||||
_groups = groups; _students = students; _enrollments = enrollments;
|
||||
_groups = groups; _students = students; _memberships = memberships; _subjects = subjects;
|
||||
_exams = exams; _grades = grades;
|
||||
ParticipationTab = participationTab;
|
||||
}
|
||||
@@ -199,6 +204,9 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
{
|
||||
Group = _groups.GetById(id);
|
||||
if (Group is null) return;
|
||||
SubjectName = Group.SubjectId is Guid subjectId
|
||||
? _subjects.GetById(subjectId)?.Name ?? ""
|
||||
: "";
|
||||
GroupTitle = Group.Name;
|
||||
GroupSubtitle = $"{Group.SchoolYear} · " +
|
||||
$"{(Group.Type == GroupType.Class ? "Klasse" : "Kurs")} · " +
|
||||
@@ -221,14 +229,13 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
{
|
||||
if (Group is null) return;
|
||||
Students.Clear();
|
||||
var enrolled = _students.GetByGroup(Group.Id, Group.SchoolYear);
|
||||
var enrollments = _enrollments.GetByGroupAndYear(Group.Id, Group.SchoolYear)
|
||||
.ToDictionary(e => e.StudentId);
|
||||
var enrolled = _students.GetByGroup(Group.Id);
|
||||
var memberships = _memberships.GetByGroup(Group.Id).ToDictionary(e => e.StudentId);
|
||||
StudentCount = enrolled.Count;
|
||||
foreach (var s in enrolled)
|
||||
{
|
||||
enrollments.TryGetValue(s.Id, out var enr);
|
||||
var summary = new StudentSummary(s, enr) { OnChanged = SaveStudentNiveau };
|
||||
memberships.TryGetValue(s.Id, out var membership);
|
||||
var summary = new StudentSummary(s, membership) { OnChanged = SaveStudentNiveau };
|
||||
Students.Add(summary);
|
||||
}
|
||||
}
|
||||
@@ -236,11 +243,10 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
private void SaveStudentNiveau(StudentSummary summary)
|
||||
{
|
||||
if (Group is null) return;
|
||||
var enrollment = _enrollments.GetByGroupAndYear(Group.Id, Group.SchoolYear)
|
||||
.FirstOrDefault(e => e.StudentId == summary.Id);
|
||||
if (enrollment is null) return;
|
||||
enrollment.Niveau = summary.Niveau;
|
||||
_enrollments.Save(enrollment);
|
||||
var membership = _memberships.GetByStudentAndGroup(summary.Id, Group.Id);
|
||||
if (membership is null) return;
|
||||
membership.Niveau = summary.Niveau;
|
||||
_memberships.Save(membership);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -259,10 +265,9 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
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);
|
||||
var membership = _memberships.GetByStudentAndGroup(SelectedStudent.Id, Group.Id);
|
||||
if (membership is null) return;
|
||||
_memberships.Delete(membership.Id);
|
||||
LoadStudents();
|
||||
SelectedStudent = null;
|
||||
ParticipationTab.RefreshCurrentGrid();
|
||||
@@ -422,18 +427,18 @@ public partial class StudentSummary : ObservableObject
|
||||
|
||||
public Action<StudentSummary>? OnChanged { get; set; }
|
||||
|
||||
public StudentSummary(Core.Models.Student s, Enrollment? e)
|
||||
public StudentSummary(Core.Models.Student s, GroupMembership? membership)
|
||||
{
|
||||
Id = s.Id;
|
||||
FullName = s.FullName;
|
||||
PeriodLabel = e?.Period switch
|
||||
PeriodLabel = membership?.Period switch
|
||||
{
|
||||
EnrollmentPeriod.H1Only => "H1",
|
||||
EnrollmentPeriod.H2Only => "H2",
|
||||
EnrollmentPeriod.Custom => BuildCustomLabel(e),
|
||||
MembershipPeriod.H1Only => "H1",
|
||||
MembershipPeriod.H2Only => "H2",
|
||||
MembershipPeriod.Custom => BuildCustomLabel(membership),
|
||||
_ => "",
|
||||
};
|
||||
_niveau = e?.Niveau;
|
||||
_niveau = membership?.Niveau;
|
||||
}
|
||||
|
||||
partial void OnNiveauChanged(Niveau? value)
|
||||
@@ -442,11 +447,11 @@ public partial class StudentSummary : ObservableObject
|
||||
OnChanged?.Invoke(this);
|
||||
}
|
||||
|
||||
private static string BuildCustomLabel(Enrollment e)
|
||||
private static string BuildCustomLabel(GroupMembership membership)
|
||||
{
|
||||
if (e.JoinedAt.HasValue && e.LeftAt.HasValue) return $"{e.JoinedAt:dd.MM.}–{e.LeftAt:dd.MM.}";
|
||||
if (e.JoinedAt.HasValue) return $"ab {e.JoinedAt:dd.MM.}";
|
||||
if (e.LeftAt.HasValue) return $"bis {e.LeftAt:dd.MM.}";
|
||||
if (membership.JoinedAt.HasValue && membership.LeftAt.HasValue) return $"{membership.JoinedAt:dd.MM.}–{membership.LeftAt:dd.MM.}";
|
||||
if (membership.JoinedAt.HasValue) return $"ab {membership.JoinedAt:dd.MM.}";
|
||||
if (membership.LeftAt.HasValue) return $"bis {membership.LeftAt:dd.MM.}";
|
||||
return "Datum";
|
||||
}
|
||||
}
|
||||
@@ -491,35 +496,34 @@ public class ExamSummary
|
||||
public partial class AddStudentToGroupDialogViewModel : ObservableObject
|
||||
{
|
||||
private readonly IStudentRepository _students;
|
||||
private readonly IEnrollmentRepository _enrollments;
|
||||
private readonly IGroupMembershipRepository _memberships;
|
||||
private readonly Guid _groupId;
|
||||
private readonly string _schoolYear;
|
||||
|
||||
[ObservableProperty] private string _searchText = "";
|
||||
[ObservableProperty] private StudentPickerItem? _selectedStudent;
|
||||
[ObservableProperty] private string _validationMessage = "";
|
||||
[ObservableProperty] private EnrollmentPeriod _period = EnrollmentPeriod.FullYear;
|
||||
[ObservableProperty] private MembershipPeriod _period = MembershipPeriod.FullYear;
|
||||
[ObservableProperty] private string _joinedAtText = "";
|
||||
[ObservableProperty] private string _leftAtText = "";
|
||||
|
||||
public bool IsFullYear { get => Period == EnrollmentPeriod.FullYear; set { if (value) Period = EnrollmentPeriod.FullYear; } }
|
||||
public bool IsH1Only { get => Period == EnrollmentPeriod.H1Only; set { if (value) Period = EnrollmentPeriod.H1Only; } }
|
||||
public bool IsH2Only { get => Period == EnrollmentPeriod.H2Only; set { if (value) Period = EnrollmentPeriod.H2Only; } }
|
||||
public bool IsCustom { get => Period == EnrollmentPeriod.Custom; set { if (value) Period = EnrollmentPeriod.Custom; } }
|
||||
public bool IsCustomPeriod => Period == EnrollmentPeriod.Custom;
|
||||
public bool IsFullYear { get => Period == MembershipPeriod.FullYear; set { if (value) Period = MembershipPeriod.FullYear; } }
|
||||
public bool IsH1Only { get => Period == MembershipPeriod.H1Only; set { if (value) Period = MembershipPeriod.H1Only; } }
|
||||
public bool IsH2Only { get => Period == MembershipPeriod.H2Only; set { if (value) Period = MembershipPeriod.H2Only; } }
|
||||
public bool IsCustom { get => Period == MembershipPeriod.Custom; set { if (value) Period = MembershipPeriod.Custom; } }
|
||||
public bool IsCustomPeriod => Period == MembershipPeriod.Custom;
|
||||
|
||||
public ObservableCollection<StudentPickerItem> AvailableStudents { get; } = [];
|
||||
public Enrollment? Result { get; private set; }
|
||||
public GroupMembership? Result { get; private set; }
|
||||
|
||||
public AddStudentToGroupDialogViewModel(IStudentRepository students,
|
||||
IEnrollmentRepository enrollments, Guid groupId, string schoolYear)
|
||||
IGroupMembershipRepository memberships, Guid groupId)
|
||||
{
|
||||
_students = students; _enrollments = enrollments;
|
||||
_groupId = groupId; _schoolYear = schoolYear;
|
||||
_students = students; _memberships = memberships;
|
||||
_groupId = groupId;
|
||||
LoadAvailableStudents();
|
||||
}
|
||||
|
||||
partial void OnPeriodChanged(EnrollmentPeriod value)
|
||||
partial void OnPeriodChanged(MembershipPeriod value)
|
||||
{
|
||||
OnPropertyChanged(nameof(IsFullYear));
|
||||
OnPropertyChanged(nameof(IsH1Only));
|
||||
@@ -532,11 +536,11 @@ public partial class AddStudentToGroupDialogViewModel : ObservableObject
|
||||
|
||||
private void LoadAvailableStudents()
|
||||
{
|
||||
var alreadyEnrolled = _enrollments.GetByGroupAndYear(_groupId, _schoolYear)
|
||||
var alreadyAssigned = _memberships.GetByGroup(_groupId)
|
||||
.Select(e => e.StudentId).ToHashSet();
|
||||
var all = _students.GetAll();
|
||||
var available = all
|
||||
.Where(s => !alreadyEnrolled.Contains(s.Id))
|
||||
.Where(s => !alreadyAssigned.Contains(s.Id))
|
||||
.Where(s => string.IsNullOrWhiteSpace(SearchText) ||
|
||||
s.FullName.Contains(SearchText, StringComparison.OrdinalIgnoreCase));
|
||||
AvailableStudents.Clear();
|
||||
@@ -549,7 +553,7 @@ public partial class AddStudentToGroupDialogViewModel : ObservableObject
|
||||
if (SelectedStudent is null) { ValidationMessage = "Bitte einen Schüler auswählen."; return; }
|
||||
|
||||
DateOnly? joinedAt = null, leftAt = null;
|
||||
if (Period == EnrollmentPeriod.Custom)
|
||||
if (Period == MembershipPeriod.Custom)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(JoinedAtText) &&
|
||||
DateOnly.TryParseExact(JoinedAtText, "dd.MM.yyyy",
|
||||
@@ -561,16 +565,15 @@ public partial class AddStudentToGroupDialogViewModel : ObservableObject
|
||||
leftAt = l;
|
||||
}
|
||||
|
||||
Result = new Enrollment
|
||||
Result = new GroupMembership
|
||||
{
|
||||
StudentId = SelectedStudent.Id,
|
||||
GroupId = _groupId,
|
||||
SchoolYear = _schoolYear,
|
||||
Period = Period,
|
||||
JoinedAt = joinedAt,
|
||||
LeftAt = leftAt,
|
||||
};
|
||||
_enrollments.Save(Result);
|
||||
_memberships.Save(Result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,11 +590,8 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
{
|
||||
private readonly IGroupRepository _groups;
|
||||
private readonly ISubjectRepository _subjects;
|
||||
private readonly SchoolYearService _sy;
|
||||
private readonly IEnrollmentRepository _enrollments;
|
||||
private List<Subject> _allSubjects = [];
|
||||
private LearningGroup? _editingGroup;
|
||||
private string? _originalSchoolYear;
|
||||
|
||||
public List<string> TypeOptions { get; } = ["Klasse", "Kurs"];
|
||||
[ObservableProperty] private string _selectedTypeName = "Kurs";
|
||||
@@ -625,9 +625,9 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
public string SaveButtonText => _editingGroup is null ? "Anlegen" : "Speichern";
|
||||
|
||||
public AddGroupDialogViewModel(IGroupRepository groups, ISubjectRepository subjects,
|
||||
SchoolYearService sy, IEnrollmentRepository enrollments)
|
||||
SchoolYearService sy)
|
||||
{
|
||||
_groups = groups; _subjects = subjects; _sy = sy; _enrollments = enrollments;
|
||||
_groups = groups; _subjects = subjects;
|
||||
_allSubjects = subjects.GetAll();
|
||||
KnownSubjectNames = _allSubjects.Select(s => s.Name).ToList();
|
||||
SchoolYears = sy.RecentSchoolYears(3);
|
||||
@@ -642,10 +642,9 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
public void LoadForEdit(LearningGroup group)
|
||||
{
|
||||
_editingGroup = group;
|
||||
_originalSchoolYear = group.SchoolYear;
|
||||
SelectedTypeName = group.Type == GroupType.Class ? "Klasse" : "Kurs";
|
||||
Name = group.Name;
|
||||
Subject = group.Subject ?? "";
|
||||
Subject = group.SubjectId is Guid subjectId ? _subjects.GetById(subjectId)?.Name ?? "" : "";
|
||||
GradeLevel = group.GradeLevel;
|
||||
SelectedGradingName = group.GradingSystem == GradingSystem.Grades1To6
|
||||
? "Noten 1–6" : "Punkte 0–15";
|
||||
@@ -684,7 +683,6 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
|
||||
Result = _editingGroup ?? new LearningGroup();
|
||||
Result.Name = Name.Trim();
|
||||
Result.Subject = subjectName;
|
||||
Result.SubjectId = subjectId;
|
||||
Result.Type = IsKurs ? GroupType.Course : GroupType.Class;
|
||||
Result.GradeLevel = GradeLevel;
|
||||
@@ -695,14 +693,5 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
Result.IsOwnClass = IsOwnClass;
|
||||
Result.IsDifferentiated = IsDifferentiated;
|
||||
_groups.Save(Result);
|
||||
|
||||
if (_editingGroup is not null && _originalSchoolYear != SelectedSchoolYear)
|
||||
{
|
||||
foreach (var enrollment in _enrollments.GetByGroup(Result.Id))
|
||||
{
|
||||
enrollment.SchoolYear = SelectedSchoolYear;
|
||||
_enrollments.Save(enrollment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public partial class ParticipationGradeDialogViewModel : ObservableObject
|
||||
private readonly IParticipationRepository _entries;
|
||||
private readonly IParticipationAspectRepository _aspects;
|
||||
private readonly IStudentRepository _students;
|
||||
private readonly IEnrollmentRepository _enrollments;
|
||||
private readonly IGroupMembershipRepository _memberships;
|
||||
private readonly IGradeRepository _grades;
|
||||
private readonly GradingService _grading;
|
||||
private readonly Guid _groupId;
|
||||
@@ -39,11 +39,11 @@ public partial class ParticipationGradeDialogViewModel : ObservableObject
|
||||
public ParticipationGradeDialogViewModel(
|
||||
IParticipationSessionRepository sessions, IParticipationRepository entries,
|
||||
IParticipationAspectRepository aspects, IStudentRepository students,
|
||||
IEnrollmentRepository enrollments, IGradeRepository grades, GradingService grading,
|
||||
IGroupMembershipRepository memberships, IGradeRepository grades, GradingService grading,
|
||||
Guid groupId, string schoolYear, GradingSystem gradingSystem)
|
||||
{
|
||||
_sessions = sessions; _entries = entries; _aspects = aspects;
|
||||
_students = students; _enrollments = enrollments; _grades = grades;
|
||||
_students = students; _memberships = memberships; _grades = grades;
|
||||
_grading = grading; _groupId = groupId; _schoolYear = schoolYear;
|
||||
_gradingSystem = gradingSystem;
|
||||
|
||||
@@ -83,14 +83,14 @@ public partial class ParticipationGradeDialogViewModel : ObservableObject
|
||||
.OrderBy(s => s.Date)
|
||||
.ToList();
|
||||
|
||||
var studentList = _students.GetByGroup(_groupId, _schoolYear);
|
||||
var enrollmentList = _enrollments.GetByGroupAndYear(_groupId, _schoolYear);
|
||||
var studentList = _students.GetByGroup(_groupId);
|
||||
var membershipList = _memberships.GetByGroup(_groupId);
|
||||
|
||||
foreach (var student in studentList.OrderBy(s => s.LastName).ThenBy(s => s.FirstName))
|
||||
{
|
||||
var enrollment = enrollmentList.FirstOrDefault(e => e.StudentId == student.Id);
|
||||
var membership = membershipList.FirstOrDefault(e => e.StudentId == student.Id);
|
||||
var relevantSessions = sessions
|
||||
.Where(s => enrollment is null || IsEnrolledAtDate(enrollment, s.Date))
|
||||
.Where(s => membership is null || IsMemberAtDate(membership, s.Date))
|
||||
.ToList();
|
||||
|
||||
var points = new List<(DateOnly Date, double Rating)>();
|
||||
@@ -132,7 +132,6 @@ public partial class ParticipationGradeDialogViewModel : ObservableObject
|
||||
{
|
||||
StudentId = row.StudentId,
|
||||
GroupId = _groupId,
|
||||
SchoolYear = _schoolYear,
|
||||
Category = GradeCategory.Participation,
|
||||
Note = noteTag,
|
||||
};
|
||||
@@ -153,12 +152,12 @@ public partial class ParticipationGradeDialogViewModel : ObservableObject
|
||||
_ => true,
|
||||
};
|
||||
|
||||
private static bool IsEnrolledAtDate(Enrollment e, DateOnly date) => e.Period switch
|
||||
private static bool IsMemberAtDate(GroupMembership membership, DateOnly date) => membership.Period switch
|
||||
{
|
||||
EnrollmentPeriod.H1Only => date.Month >= 8 || date.Month <= 1,
|
||||
EnrollmentPeriod.H2Only => date.Month >= 2 && date.Month <= 7,
|
||||
EnrollmentPeriod.Custom => (e.JoinedAt is null || date >= e.JoinedAt.Value)
|
||||
&& (e.LeftAt is null || date <= e.LeftAt.Value),
|
||||
MembershipPeriod.H1Only => date.Month >= 8 || date.Month <= 1,
|
||||
MembershipPeriod.H2Only => date.Month >= 2 && date.Month <= 7,
|
||||
MembershipPeriod.Custom => (membership.JoinedAt is null || date >= membership.JoinedAt.Value)
|
||||
&& (membership.LeftAt is null || date <= membership.LeftAt.Value),
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public partial class ParticipationTabViewModel : ObservableObject
|
||||
private readonly IParticipationRepository _entries;
|
||||
private readonly IParticipationAspectRepository _aspects;
|
||||
private readonly IStudentRepository _students;
|
||||
private readonly IEnrollmentRepository _enrollments;
|
||||
private readonly IGroupMembershipRepository _memberships;
|
||||
private readonly IGroupRepository _groups;
|
||||
private readonly ICompetencyDomainRepository _competencyDomains;
|
||||
|
||||
@@ -53,13 +53,13 @@ public partial class ParticipationTabViewModel : ObservableObject
|
||||
IParticipationRepository entries,
|
||||
IParticipationAspectRepository aspects,
|
||||
IStudentRepository students,
|
||||
IEnrollmentRepository enrollments,
|
||||
IGroupMembershipRepository memberships,
|
||||
IGroupRepository groups,
|
||||
ICompetencyDomainRepository competencyDomains)
|
||||
{
|
||||
_sessions = sessions; _entries = entries;
|
||||
_aspects = aspects; _students = students;
|
||||
_enrollments = enrollments; _groups = groups;
|
||||
_memberships = memberships; _groups = groups;
|
||||
_competencyDomains = competencyDomains;
|
||||
}
|
||||
|
||||
@@ -128,18 +128,18 @@ public partial class ParticipationTabViewModel : ObservableObject
|
||||
StudentRows.Clear();
|
||||
var session = _sessions.GetById(sessionId);
|
||||
var sessionDate = session?.Date ?? DateOnly.FromDateTime(DateTime.Today);
|
||||
var students = _students.GetByGroup(_groupId, _schoolYear);
|
||||
var enrollments = _enrollments.GetByGroupAndYear(_groupId, _schoolYear);
|
||||
var students = _students.GetByGroup(_groupId);
|
||||
var memberships = _memberships.GetByGroup(_groupId);
|
||||
var entries = _entries.GetBySession(sessionId);
|
||||
|
||||
foreach (var s in students)
|
||||
{
|
||||
var enrollment = enrollments.FirstOrDefault(e => e.StudentId == s.Id);
|
||||
if (enrollment is not null && !IsEnrolledAtDate(enrollment, sessionDate))
|
||||
var membership = memberships.FirstOrDefault(e => e.StudentId == s.Id);
|
||||
if (membership is not null && !IsMemberAtDate(membership, sessionDate))
|
||||
continue;
|
||||
|
||||
var entry = entries.FirstOrDefault(e => e.StudentId == s.Id)
|
||||
?? new ParticipationEntry { SessionId = sessionId, GroupId = _groupId, StudentId = s.Id };
|
||||
?? new ParticipationEntry { SessionId = sessionId, StudentId = s.Id };
|
||||
var row = new ParticipationStudentRow(s.Id, s.FullName, entry, Aspects.ToList(), ActiveCompetencyCodes);
|
||||
row.OnRatingChanged = (sid, key, val) => SaveRating(sessionId, sid, key, val);
|
||||
row.OnCompetencyRatingChanged = (sid, code, val) => SaveCompetencyRating(sessionId, sid, code, val);
|
||||
@@ -149,25 +149,22 @@ public partial class ParticipationTabViewModel : ObservableObject
|
||||
RebuildColumnsSignal++;
|
||||
}
|
||||
|
||||
private static bool IsEnrolledAtDate(Enrollment e, DateOnly date) => e.Period switch
|
||||
private static bool IsMemberAtDate(GroupMembership membership, DateOnly date) => membership.Period switch
|
||||
{
|
||||
EnrollmentPeriod.H1Only => date.Month >= 8 || date.Month <= 1,
|
||||
EnrollmentPeriod.H2Only => date.Month >= 2 && date.Month <= 7,
|
||||
EnrollmentPeriod.Custom => (e.JoinedAt is null || date >= e.JoinedAt.Value)
|
||||
&& (e.LeftAt is null || date <= e.LeftAt.Value),
|
||||
MembershipPeriod.H1Only => date.Month >= 8 || date.Month <= 1,
|
||||
MembershipPeriod.H2Only => date.Month >= 2 && date.Month <= 7,
|
||||
MembershipPeriod.Custom => (membership.JoinedAt is null || date >= membership.JoinedAt.Value)
|
||||
&& (membership.LeftAt is null || date <= membership.LeftAt.Value),
|
||||
_ => true,
|
||||
};
|
||||
|
||||
private void SaveRating(Guid sessionId, Guid studentId, string key, int? value)
|
||||
{
|
||||
var session = _sessions.GetById(sessionId);
|
||||
var entry = _entries.GetBySessionAndStudent(sessionId, studentId)
|
||||
var entry = _entries.GetBySessionAndStudent(sessionId, studentId)
|
||||
?? new ParticipationEntry
|
||||
{
|
||||
SessionId = sessionId,
|
||||
GroupId = _groupId,
|
||||
StudentId = studentId,
|
||||
Date = session?.Date ?? DateOnly.FromDateTime(DateTime.Today),
|
||||
};
|
||||
|
||||
var existing = entry.Ratings.FirstOrDefault(r => r.Key == key);
|
||||
@@ -280,14 +277,11 @@ public partial class ParticipationTabViewModel : ObservableObject
|
||||
|
||||
private void SaveCompetencyRating(Guid sessionId, Guid studentId, string code, int? value)
|
||||
{
|
||||
var session = _sessions.GetById(sessionId);
|
||||
var entry = _entries.GetBySessionAndStudent(sessionId, studentId)
|
||||
var entry = _entries.GetBySessionAndStudent(sessionId, studentId)
|
||||
?? new ParticipationEntry
|
||||
{
|
||||
SessionId = sessionId,
|
||||
GroupId = _groupId,
|
||||
StudentId = studentId,
|
||||
Date = session?.Date ?? DateOnly.FromDateTime(DateTime.Today),
|
||||
};
|
||||
var existing = entry.CompetencyRatings.FirstOrDefault(r => r.Code == code);
|
||||
if (value is null)
|
||||
|
||||
@@ -110,7 +110,15 @@ public partial class SettingsViewModel : ObservableObject
|
||||
private void AddSubject()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NewName)) { ValidationMessage = "Name erforderlich."; return; }
|
||||
_subjects.Save(new Subject { Name = NewName.Trim(), ShortName = NewShort.Trim() });
|
||||
try
|
||||
{
|
||||
_subjects.Save(new Subject { Name = NewName.Trim(), ShortName = NewShort.Trim() });
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
ValidationMessage = ex.Message;
|
||||
return;
|
||||
}
|
||||
NewName = ""; NewShort = ""; ValidationMessage = "";
|
||||
LoadSubjects();
|
||||
}
|
||||
@@ -119,7 +127,16 @@ public partial class SettingsViewModel : ObservableObject
|
||||
private void DeleteSubject(SubjectListItem? item)
|
||||
{
|
||||
if (item is null) return;
|
||||
_subjects.Delete(item.Id);
|
||||
try
|
||||
{
|
||||
_subjects.Delete(item.Id);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
ValidationMessage = ex.Message;
|
||||
return;
|
||||
}
|
||||
ValidationMessage = "";
|
||||
if (CatalogSubject?.Id == item.Id) CatalogSubject = null;
|
||||
LoadSubjects();
|
||||
}
|
||||
|
||||
@@ -68,8 +68,9 @@ public class StudentListItem
|
||||
public partial class StudentDetailViewModel : ObservableObject
|
||||
{
|
||||
private readonly IStudentRepository _students;
|
||||
private readonly IEnrollmentRepository _enrollments;
|
||||
private readonly IGroupMembershipRepository _memberships;
|
||||
private readonly IGroupRepository _groups;
|
||||
private readonly ISubjectRepository _subjects;
|
||||
private readonly IDocumentationRepository _docs;
|
||||
|
||||
[ObservableProperty] private Student? _student;
|
||||
@@ -79,7 +80,7 @@ public partial class StudentDetailViewModel : ObservableObject
|
||||
[ObservableProperty] private string _editLastName = "";
|
||||
[ObservableProperty] private ContactItem? _selectedContact;
|
||||
|
||||
public ObservableCollection<EnrollmentEntry> Enrollments { get; } = [];
|
||||
public ObservableCollection<GroupMembershipEntry> GroupMemberships { get; } = [];
|
||||
public ObservableCollection<DocEntry> Documentation { get; } = [];
|
||||
public ObservableCollection<ContactItem> Contacts { get; } = [];
|
||||
public bool HasNoContacts => Contacts.Count == 0;
|
||||
@@ -87,11 +88,11 @@ public partial class StudentDetailViewModel : ObservableObject
|
||||
public Action<ContactItem>? OnViewAddress { get; set; }
|
||||
|
||||
public StudentDetailViewModel(IStudentRepository students,
|
||||
IEnrollmentRepository enrollments, IGroupRepository groups,
|
||||
IGroupMembershipRepository memberships, IGroupRepository groups, ISubjectRepository subjects,
|
||||
IDocumentationRepository docs)
|
||||
{
|
||||
_students = students; _enrollments = enrollments;
|
||||
_groups = groups; _docs = docs;
|
||||
_students = students; _memberships = memberships;
|
||||
_groups = groups; _subjects = subjects; _docs = docs;
|
||||
}
|
||||
|
||||
public void LoadStudent(Guid id)
|
||||
@@ -102,12 +103,13 @@ public partial class StudentDetailViewModel : ObservableObject
|
||||
EditFirstName = Student.FirstName;
|
||||
EditLastName = Student.LastName;
|
||||
|
||||
Enrollments.Clear();
|
||||
foreach (var e in _enrollments.GetByStudent(Student.Id))
|
||||
GroupMemberships.Clear();
|
||||
foreach (var membership in _memberships.GetByStudent(Student.Id))
|
||||
{
|
||||
var g = _groups.GetById(e.GroupId);
|
||||
var g = _groups.GetById(membership.GroupId);
|
||||
if (g is null) continue;
|
||||
Enrollments.Add(new() { SchoolYear = e.SchoolYear, GroupName = g.Name, Subject = g.Subject ?? "" });
|
||||
var subject = g.SubjectId is Guid subjectId ? _subjects.GetById(subjectId)?.Name ?? "" : "";
|
||||
GroupMemberships.Add(new() { SchoolYear = g.SchoolYear, GroupName = g.Name, Subject = subject });
|
||||
}
|
||||
|
||||
LoadContacts();
|
||||
@@ -195,7 +197,7 @@ public partial class StudentDetailViewModel : ObservableObject
|
||||
private bool CanViewSelectedAddress() => SelectedContact?.HasAddress == true;
|
||||
}
|
||||
|
||||
public class EnrollmentEntry { public string SchoolYear { get; set; } = ""; public string GroupName { get; set; } = ""; public string Subject { get; set; } = ""; }
|
||||
public class GroupMembershipEntry { public string SchoolYear { get; set; } = ""; public string GroupName { get; set; } = ""; public string Subject { 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; } }
|
||||
|
||||
public class ContactItem
|
||||
|
||||
Reference in New Issue
Block a user