Enhance school creation and staffing management with native language support
ci / server (push) Failing after 3m44s
ci / client (push) Successful in 14s

- Updated protocol documentation to include `nativeLanguages` in `nameSets` and added `nativeLanguage` to school creation options.
- Enhanced the UI for school creation to allow selection of native languages, improving user experience.
- Revised API interfaces to accommodate new native language features, ensuring proper data handling.
- Improved localization strings to support new native language functionalities in both English and Russian.
- Updated tests to validate the new native language features and ensure robust functionality in staffing scenarios.
This commit is contained in:
Leonid Pershin
2026-08-19 22:22:31 +03:00
parent 21d79cb49b
commit 5a00ad7746
48 changed files with 2064 additions and 312 deletions
@@ -29,14 +29,23 @@ public class StaffingApiTests(AppHostFixture fixture)
Assert.Equal(100_000f, staffing.Allocated);
Assert.Equal(0f, staffing.Payroll);
Assert.Equal(100_000f, staffing.Remaining);
Assert.Equal(12, staffing.Applicants.Count);
Assert.Equal(32, staffing.Applicants.Count);
Assert.Empty(staffing.Staff);
Assert.Contains(staffing.Uncovered, subject => subject.DefName == "Mathematics");
Assert.Contains(staffing.Uncovered, subject => subject.DefName == "PrimarySchool");
Assert.NotEmpty(staffing.Positions);
Assert.Contains(staffing.Positions, position => position.DefName == "Teacher");
Assert.Contains(staffing.Subjects, subject => subject.DefName == "Mathematics");
Assert.All(staffing.Applicants, applicant => Assert.NotEmpty(applicant.Skills));
Assert.All(
staffing.Applicants,
applicant =>
{
Assert.Contains(applicant.Skills, skill => skill.Id == "Communication");
Assert.Contains(
applicant.Skills,
skill => skill.Id is "RussianLanguage" or "BelarusianLanguage" or "UkrainianLanguage");
Assert.All(applicant.Skills, skill => Assert.False(string.IsNullOrWhiteSpace(skill.Value)));
});
}
[Fact]
@@ -135,6 +144,12 @@ public class StaffingApiTests(AppHostFixture fixture)
$"/api/schools/{school.Id}/staff/hire",
new { personId = applicant.Id, position = "Teacher" },
TestContext.Current.CancellationToken);
if (response.StatusCode == HttpStatusCode.Conflict)
{
Assert.Equal("payroll-exceeded", await ProblemCodeAsync(response));
break;
}
response.EnsureSuccessStatusCode();
staffing = await response.Content.ReadFromJsonAsync<StaffingResponse>(TestContext.Current.CancellationToken);
Assert.NotNull(staffing);
@@ -143,7 +158,7 @@ public class StaffingApiTests(AppHostFixture fixture)
Assert.Equal(100_000f, staffing.Allocated);
Assert.True(staffing.Payroll > 0f);
Assert.True(staffing.Payroll <= staffing.Allocated);
Assert.Equal(12, staffing.Staff.Count);
Assert.NotEmpty(staffing.Staff);
}
[Fact]
@@ -224,9 +239,23 @@ public class StaffingApiTests(AppHostFixture fixture)
var staffing = await GetStaffingAsync(client, school.Id);
while (staffing.Applicants.Count > 0)
{
staffing = await HireAsync(client, school.Id, staffing.Applicants[0].Id, "Teacher");
var applicant = staffing.Applicants[0];
using var response = await client.PostAsJsonAsync(
$"/api/schools/{school.Id}/staff/hire",
new { personId = applicant.Id, position = "Teacher" },
TestContext.Current.CancellationToken);
if (response.StatusCode == HttpStatusCode.Conflict)
{
break;
}
response.EnsureSuccessStatusCode();
staffing = await response.Content.ReadFromJsonAsync<StaffingResponse>(TestContext.Current.CancellationToken);
Assert.NotNull(staffing);
}
Assert.NotEmpty(staffing.Staff);
var subjects = staffing.Subjects.Select(subject => subject.DefName).ToArray();
Assert.NotEmpty(subjects);
@@ -327,7 +356,8 @@ public class StaffingApiTests(AppHostFixture fixture)
bool IsParent,
float HourlyWageAsk,
float MonthlyBase,
IReadOnlyList<LabeledStatResponse> Skills);
IReadOnlyList<LabeledStatResponse> Skills,
IReadOnlyList<DefLabelResponse> Traits);
private sealed record LabeledStatResponse(string Id, string Label, string Value);