restructured components so that there are more components in the pages

This commit is contained in:
2024-01-11 17:28:14 -07:00
parent 4fb5d9a25d
commit 5666d3dc85
22 changed files with 110 additions and 85 deletions

View File

@@ -0,0 +1,142 @@
@using Management.Web.Shared.Components
@inject CanvasService canvas
@inject CoursePlanner planner
@code {
protected override void OnInitialized()
{
planner.StateHasChanged += reload;
}
private void reload()
{
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
planner.StateHasChanged -= reload;
}
private bool syncingAssignmentGroups { get; set; } = false;
private void AddAssignmentGroup()
{
if(planner.LocalCourse != null)
{
var newGroup = new LocalAssignmentGroup
{
Name = "",
Weight = 0,
Id = Guid.NewGuid().ToString()
};
var updatedGroups = planner.LocalCourse.Settings.AssignmentGroups.Append(newGroup);
planner.LocalCourse = planner.LocalCourse with
{
Settings = planner.LocalCourse.Settings with
{
AssignmentGroups = updatedGroups
}
};
}
}
private Action<ChangeEventArgs> saveGroupName(string groupId)
{
return (e) =>
{
if(planner.LocalCourse != null)
{
var newName = e.Value?.ToString() ?? "";
var newGroups = planner.LocalCourse.Settings.AssignmentGroups.Select(
g => g.Id == groupId
? g with { Name = newName }
: g
);
planner.LocalCourse = planner.LocalCourse with
{
Settings = planner.LocalCourse.Settings with
{
AssignmentGroups = newGroups
}
};
}
};
}
private Action<ChangeEventArgs> saveGroupWeight(string groupId)
{
return (e) =>
{
if(planner.LocalCourse != null)
{
var newWeight = double.Parse(e.Value?.ToString() ?? "0");
var newGroups = planner.LocalCourse.Settings.AssignmentGroups.Select(
g => g.Id == groupId
? g with { Weight = newWeight }
: g
);
planner.LocalCourse = planner.LocalCourse with
{
Settings = planner.LocalCourse.Settings with
{
AssignmentGroups = newGroups
}
};
}
};
}
private async Task SyncAssignmentGroupsWithCanvas()
{
syncingAssignmentGroups = true;
await planner.SyncAssignmentGroups();
syncingAssignmentGroups = false;
}
}
@if(planner.LocalCourse != null)
{
<h4 class="text-center">Assignment Groups</h4>
@foreach (var group in planner.LocalCourse.Settings.AssignmentGroups)
{
var groupName = group.Name;
var nameInputCallback = saveGroupName(group.Id);
var weight = group.Weight;
var weightInputCallback = saveGroupWeight(group.Id);
<div class="row">
<div class="col-auto">
<label class="form-label">Group Name</label>
<input
class="form-control"
@bind="groupName" @oninput="nameInputCallback">
</div>
<div class="col-auto">
<label class="form-label">Weight</label>
<input
class="form-control"
@bind="weight"
@oninput="weightInputCallback"
>
</div>
</div>
}
<div class="d-flex justify-content-end">
<button
class="btn btn-outline-primary"
@onclick="AddAssignmentGroup"
>
+ Assignment Group
</button>
</div>
<button
class="btn btn-outline-secondary"
@onclick="SyncAssignmentGroupsWithCanvas"
disabled="@syncingAssignmentGroups"
>
Sync Assignment Groups With Canvas
</button>
@if(syncingAssignmentGroups)
{
<Spinner />
}
}

View File

@@ -0,0 +1,74 @@
@page "/course/{CourseName}"
@using CanvasModel.EnrollmentTerms
@using CanvasModel.Courses
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@using LocalModels
@using Management.Web.Shared.Module.Assignment
@using Management.Web.Shared.Components
@inject FileStorageManager fileStorageManager
@inject CanvasService canvas
@inject CoursePlanner planner
@inject NavigationManager navigtion
@inject IConfiguration config
@code {
[Parameter]
public string? CourseName { get; set; }
private bool loading = true;
protected override async Task OnInitializedAsync()
{
if (planner.LocalCourse == null)
{
var courses = await fileStorageManager.LoadSavedCourses();
planner.LocalCourse = courses.First(c => c.Settings.Name == CourseName);
}
base.OnInitialized();
loading = false;
}
private void selectNewCourse()
{
planner.Clear();
navigtion.NavigateTo("/");
}
}
<PageTitle>@CourseName</PageTitle>
<div style="height: 100vh;">
@if (loading)
{
<Spinner />
}
@if (planner.LocalCourse != null)
{
<div class="pb-3 d-flex justify-content-between" style="height: 4em;">
<div class="my-auto">
<button @onclick="selectNewCourse" class="btn btn-primary">
Select New Course
</button>
<CourseSettings />
<a class="btn btn-outline-secondary" target="_blank"
href="@($"{config["CANVAS_URL"]}/courses/{planner.LocalCourse.Settings.CanvasId}")">
View In Canvas
</a>
<div class="my-auto ms-2 d-inline">
@planner.LocalCourse.Settings.Name
</div>
</div>
@if (planner.LoadingCanvasData)
{
<Spinner />
}
</div>
<CourseDetails />
}
</div>

View File

@@ -0,0 +1,53 @@
@using Management.Web.Shared.Module.Assignment
@inject DragContainer dragContainer
@inject NavigationManager Navigation
@inject AssignmentEditorContext assignmentContext
@inject MyLogger<AssignmentInDay> logger
@inherits DroppableAssignment
@code {
protected override void OnInitialized()
{
planner.StateHasChanged += reload;
}
private void reload()
{
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
planner.StateHasChanged -= reload;
}
private void HandleDragStart()
{
dragContainer.DropCallback = DropCallback;
}
private void HandleDragEnd()
{
dragContainer.DropCallback = null;
}
private void OnClick()
{
if(planner.LocalCourse != null)
{
assignmentContext.Assignment = Assignment;
Navigation.NavigateTo("/course/" + planner.LocalCourse.Settings.Name + "/assignment/" + Assignment.Name);
logger.Log("navigating to assignment page");
}
}
}
<li
draggable="true"
@ondragstart="HandleDragStart"
@ondragend="HandleDragEnd"
@onclick="OnClick"
role="button"
>
@Assignment.Name
</li>

View File

@@ -0,0 +1,130 @@
@inject DragContainer dragContainer
@inject CoursePlanner configurationManagement
@inject CoursePlanner planner
@code
{
[Parameter, EditorRequired]
public DateTime? date { get; set; } =
default!;
private bool isWeekDay {
get => date?.DayOfWeek != null;
}
private bool dragging {get; set;} = false;
protected override void OnInitialized()
{
planner.StateHasChanged += reload;
}
private void reload()
{
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
planner.StateHasChanged -= reload;
}
private IEnumerable<LocalAssignment> TodaysAssignments
{
get
{
if(planner.LocalCourse == null || date == null)
return Enumerable.Empty<LocalAssignment>();
else
return planner.LocalCourse.Modules
.SelectMany(m => m.Assignments)
.Where(a => a.DueAt.Date == date?.Date);
}
}
private IEnumerable<LocalQuiz> todaysQuizzes
{
get
{
if(planner.LocalCourse == null || date == null)
return Enumerable.Empty<LocalQuiz>();
else
return planner.LocalCourse.Modules
.SelectMany(m => m.Quizzes)
.Where(q => q.DueAt.Date == date?.Date);
}
}
private string calculatedClass
{
get
{
var baseClasses = "col border rounded rounded-3 p-2 pb-4 m-1 ";
if(dragging)
return baseClasses + " bg-secondary text-light ";
if(date?.Date == DateTime.Today)
baseClasses += " border-1 border-primary-subtle ";
if (isWeekDay)
{
DayOfWeek? weekDay = date?.DayOfWeek;
DayOfWeek notNullDay = weekDay ?? default;
var isClassDay = planner.LocalCourse?.Settings.DaysOfWeek.Contains(notNullDay) ?? false;
var dayInSemester =
isClassDay
&& date <= planner.LocalCourse?.Settings.EndDate
&& date >= planner.LocalCourse?.Settings.StartDate;
var totalClasses = dayInSemester
? "bg-light-subtle text-light " + baseClasses
: " " + baseClasses;
return totalClasses;
}
else
{
return baseClasses;
}
}
}
void OnDragEnter() {
dragging = true;
}
void OnDragLeave() {
dragging = false;
}
void OnDrop()
{
dragging = false;
if(dragContainer.DropCallback == null){
System.Console.WriteLine("no drop callback set");
return;
}
if(date != null)
{
DateTime d = date ?? throw new Exception("should not get here, error converting date from nullable");
dragContainer.DropCallback?.Invoke(d, null);
}
}
}
<div
class="@calculatedClass"
@ondrop="@(() => OnDrop())"
@ondragenter="OnDragEnter"
@ondragleave="OnDragLeave"
ondragover="event.preventDefault();"
>
@(isWeekDay ? date?.Day : "")
<ul class="m-0 ps-3">
@foreach (var assignment in TodaysAssignments)
{
@* Console.WriteLine($"assignment: {assignment.Name}"); *@
<AssignmentInDay Assignment="assignment" @key="@assignment" />
}
@foreach(var quiz in todaysQuizzes)
{
<QuizInDay Quiz="quiz" @key="@quiz" />
}
</ul>
</div>

View File

@@ -0,0 +1,34 @@
@using Management.Web.Shared.Components.Quiz
@inject DragContainer dragContainer
@inject QuizEditorContext quizContext
@inject NavigationManager Navigation
@inherits DroppableQuiz
@code {
private void HandleDragStart()
{
dragContainer.DropCallback = dropCallback;
}
private void HandleDragEnd()
{
dragContainer.DropCallback = null;
}
private void OnClick()
{
quizContext.Quiz = Quiz;
Navigation.NavigateTo("/course/" + planner.LocalCourse?.Settings.Name + "/quiz/" + Quiz.Name);
}
}
<li
draggable="true"
@ondragstart="HandleDragStart"
@ondragend="HandleDragEnd"
@onclick="OnClick"
role="button"
>
@Quiz.Name
</li>

View File

@@ -0,0 +1,55 @@
@using System.Linq
@using Management.Web.Pages.Course.CourseCalendar.Day
@inject CoursePlanner planner
@code
{
[Parameter, EditorRequired]
public CalendarMonth Month { get; set; } = default!;
public DayOfWeek[] WeekDaysList { get => (DayOfWeek[])Enum.GetValues(typeof(DayOfWeek)); }
public string MonthName { get => Month?.DaysByWeek.First().FirstOrDefault(d => d != null)?.ToString("MMMM") ?? ""; }
private string htmlLabel => "collapse"+MonthName;
private bool isInPast =>
new DateTime(Month.Year, Month.Month, 1) < new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
private string collapseClass => " collapse " + (isInPast ? "hide" : "show");
}
<h3 class="text-center">
<a
role="button"
data-bs-toggle="collapse"
data-bs-target="@("#" + htmlLabel)"
aria-expanded="@( isInPast ? "false" : "true")"
aria-controls="@htmlLabel"
>
@MonthName
</a>
</h3>
<div class="@collapseClass" id="@htmlLabel">
<div class="row text-center fw-bold">
@foreach (DayOfWeek day in WeekDaysList)
{
<div class="@(
planner.LocalCourse?.Settings.DaysOfWeek.Contains(day) ?? false
? "col"
: "col text-secondary"
)">
@day
</div>
}
</div>
@foreach (var week in Month.DaysByWeek)
{
<div class="row m-3">
@foreach (var day in week)
{
<Day date="day"></Day>
}
</div>
}
</div>

View File

@@ -0,0 +1,57 @@
@using CanvasModel.EnrollmentTerms
@using Management.Web.Shared.Module
@using Management.Web.Pages.Course.CourseCalendar
@inject CanvasService canvas
@inject CoursePlanner planner
@code
{
protected override void OnInitialized()
{
planner.StateHasChanged += reload;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender)
{
if(
planner.CanvasAssignments == null
&& planner.LocalCourse != null
&& planner.LocalCourse.Settings.CanvasId != null
)
{
await planner.LoadCanvasData();
}
}
}
private void reload()
{
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
planner.StateHasChanged -= reload;
}
}
<div class="row">
<div class="col overflow-y-auto border rounded " style="max-height: 95vh;">
@if (planner.LocalCourse != null)
{
<div class="py-2">
@foreach (var month in SemesterPlanner.GetMonthsBetweenDates(planner.LocalCourse.Settings.StartDate, planner.LocalCourse.Settings.EndDate))
{
<MonthDetail Month="month" />
<hr />
}
</div>
}
</div>
<div class="col-4 overflow-y-auto" style="max-height: 95vh;">
<Modules />
</div>
</div>

View File

@@ -0,0 +1,166 @@
@using Management.Web.Shared.Components
@inject CanvasService canvas
@inject CoursePlanner planner
@code
{
private Modal modal { get; set; } = default!;
protected override void OnInitialized()
{
planner.StateHasChanged += reload;
}
private void reload()
{
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
planner.StateHasChanged -= reload;
}
private IEnumerable<EnrollmentTermModel>? terms { get; set; } = null;
private ulong? _selectedTermId {get; set;}
private ulong? selectedTermId {
get => _selectedTermId;
set
{
_selectedTermId = value;
if(selectedTerm != null && planner.LocalCourse != null)
{
planner.LocalCourse = planner.LocalCourse with
{
Settings = planner.LocalCourse.Settings with
{
StartDate=selectedTerm.StartAt ?? new DateTime(),
EndDate=selectedTerm.EndAt ?? new DateTime(),
}
};
}
}
}
private EnrollmentTermModel? selectedTerm
{
get => terms?.FirstOrDefault(t => t.Id == selectedTermId);
}
private bool loading = false;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if(planner.LocalCourse != null && planner.LocalCourse.Settings.CanvasId != null)
{
loading = true;
ulong id = planner.LocalCourse?.Settings.CanvasId ?? throw new Exception("wtf how did i get here");
var canvasCourse = await canvas.GetCourse(id);
terms = await canvas.GetCurrentTermsFor(canvasCourse.StartAt);
loading = false;
}
}
}
}
<button
class="btn btn-outline-secondary"
@onclick="@(() => modal.Show())"
>
Edit Course Settings
</button>
<Modal @ref="modal">
<Title>
<h1>Course Settings</h1>
</Title>
<Body>
<h5 class="text-center">Select Days Of Week</h5>
<div class="row m-3">
@foreach (DayOfWeek day in (DayOfWeek[])Enum.GetValues(typeof(DayOfWeek)))
{
<div class="col">
<button
class="@(
planner.LocalCourse?.Settings.DaysOfWeek.Contains(day) ?? false
? "btn btn-secondary"
: "btn btn-outline-secondary"
)"
@onclick="() =>
{
if(planner.LocalCourse?.Settings.DaysOfWeek.Contains(day) ?? false)
{
planner.LocalCourse = planner.LocalCourse with
{
Settings = planner.LocalCourse.Settings with
{
DaysOfWeek = planner.LocalCourse.Settings.DaysOfWeek.Where((d) => d != day)
}
};
}
else
{
if (planner.LocalCourse != null)
{
planner.LocalCourse = planner.LocalCourse with
{
Settings = planner.LocalCourse.Settings with
{
DaysOfWeek = planner.LocalCourse.Settings.DaysOfWeek.Append(day)
}
};
}
}
}"
>
@day
</button>
</div>
}
</div>
@if(loading)
{
<Spinner />
}
@if (terms != null)
{
<div class="row justify-content-center">
<div class="col-auto">
<form @onsubmit:preventDefault="true">
<label for="termselect">Select Term for Start and End Date:</label>
<select id="termselect" class="form-select" @bind="selectedTermId">
@foreach (var term in terms)
{
<option value="@term.Id">@term.Name</option>
}
</select>
</form>
</div>
</div>
}
@if(planner.LocalCourse != null)
{
<div class="row justify-content-center m-3 text-center">
<div class="col-auto">
<div>Default Assignment Due Time</div>
<TimePicker Time="planner.LocalCourse.Settings.DefaultDueTime" UpdateTime="@((newTime) =>
planner.LocalCourse =
planner.LocalCourse with
{ Settings = planner.LocalCourse.Settings with { DefaultDueTime=newTime } }
)"
/>
</div>
</div>
}
<AssignmentGroups />
</Body>
<Footer>
<button
class="btn btn-outline-secondary"
@onclick="@(() => modal.Hide())"
>
Done Editing Course Settings
</button>
</Footer>
</Modal>