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

@@ -1,229 +0,0 @@
@using Management.Web.Shared.Components
@using Management.Web.Shared.Components.Forms
@using CanvasModel.Assignments
@inject CoursePlanner planner
@inject CanvasService canvas
@inject NavigationManager Navigation
@inject AssignmentEditorContext assignmentContext
@code {
protected override void OnInitialized()
{
assignmentContext.StateHasChanged += reload;
reload();
}
private void reload()
{
if (assignmentContext.Assignment != null)
{
name = assignmentContext.Assignment.Name;
}
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
assignmentContext.StateHasChanged -= reload;
}
private void OnHide()
{
assignmentContext.Assignment = null;
name = "";
}
private string name { get; set; } = String.Empty;
private bool addingAssignmentToCanvas = false;
private bool deletingAssignmentFromCanvas = false;
private bool showHelp = false;
private void toggleHelp() => showHelp = !showHelp;
private void submitHandler()
{
if (assignmentContext.Assignment != null)
{
var newAssignment = assignmentContext.Assignment with
{
Name = name,
};
assignmentContext.SaveAssignment(newAssignment);
}
assignmentContext.Assignment = null;
}
private async Task HandleDelete()
{
if (planner.LocalCourse != null && assignmentContext.Assignment != null)
{
var assignment = assignmentContext.Assignment;
var currentModule = planner
.LocalCourse
.Modules
.First(m =>
m.Assignments.Contains(assignment)
) ?? throw new Exception("handling assignment delete, could not find module");
var newModules = planner.LocalCourse.Modules.Select(m =>
m.Name == currentModule.Name
? m with
{
Assignments = m.Assignments.Where(a => a != assignment).ToArray()
}
: m
)
.ToArray();
planner.LocalCourse = planner.LocalCourse with
{
Modules = newModules
};
if (assignmentInCanvas != null && planner.LocalCourse.Settings.CanvasId != null)
{
ulong courseId = planner.LocalCourse.Settings.CanvasId ?? throw new Exception("cannot delete if no course id");
await canvas.Assignments.Delete(courseId, assignmentInCanvas.Id, assignment.Name);
}
Navigation.NavigateTo("/course/" + planner.LocalCourse?.Settings.Name);
}
}
private void handleNameChange(ChangeEventArgs e)
{
if (assignmentContext.Assignment != null)
{
var newAssignment = assignmentContext.Assignment with { Name = e.Value?.ToString() ?? "" };
assignmentContext.SaveAssignment(newAssignment);
}
}
private void setAssignmentGroup(LocalAssignmentGroup? group)
{
if (assignmentContext.Assignment == null)
return;
var newAssignment = assignmentContext.Assignment with
{
LocalAssignmentGroupName = group?.Name
};
assignmentContext.SaveAssignment(newAssignment);
}
private LocalAssignmentGroup? selectedAssignmentGroup =>
planner
.LocalCourse?
.Settings
.AssignmentGroups
.FirstOrDefault(g => g.Name == assignmentContext.Assignment?.LocalAssignmentGroupName);
private async Task addToCanvas()
{
addingAssignmentToCanvas = true;
await assignmentContext.AddAssignmentToCanvas();
await planner.LoadCanvasData();
addingAssignmentToCanvas = false;
}
private async Task updateInCanvas()
{
if(assignmentInCanvas != null)
{
addingAssignmentToCanvas = true;
await assignmentContext.UpdateInCanvas(assignmentInCanvas.Id);
await planner.LoadCanvasData();
addingAssignmentToCanvas = false;
}
}
private CanvasAssignment? assignmentInCanvas =>
planner.CanvasAssignments?.FirstOrDefault(a => a.Name == assignmentContext.Assignment?.Name);
private string canvasAssignmentUrl =>
$"https://snow.instructure.com/courses/{planner.LocalCourse?.Settings.CanvasId}/assignments/{assignmentInCanvas?.Id}";
private async Task deleteFromCanvas()
{
if (assignmentInCanvas == null
|| planner?.LocalCourse?.Settings.CanvasId == null
|| assignmentContext.Assignment == null
)
return;
deletingAssignmentFromCanvas = true;
await canvas.Assignments.Delete(
(ulong)planner.LocalCourse.Settings.CanvasId,
assignmentInCanvas.Id,
assignmentContext.Assignment.Name
);
await planner.LoadCanvasData();
deletingAssignmentFromCanvas = false;
StateHasChanged();
}
}
<div class="d-flex flex-column p-2 h-100 w-100" style="height: 100%;" >
<div>
@assignmentContext.Assignment?.Name
</div>
<section class="flex-grow-1 p-1 border rounded-4 bg-dark-subtle" style="min-height: 0;">
@if (assignmentContext.Assignment != null)
{
<AssignmentMarkdownEditor ShowHelp=@showHelp />
}
</section>
<div class="d-flex justify-content-end p-3">
@if (addingAssignmentToCanvas || deletingAssignmentFromCanvas)
{
<div>
<Spinner />
</div>
}
<button class="btn btn-outline-secondary mx-3" @onclick=toggleHelp>
Toggle Help
</button>
<ConfirmationModal Label="Delete" Class="btn btn-danger" OnConfirmAsync="HandleDelete" />
<button
class="btn btn-outline-secondary mx-3"
disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
@onclick="addToCanvas"
>
Add To Canvas
</button>
@if (assignmentInCanvas != null)
{
<a
class="btn btn-outline-secondary me-1"
href="@canvasAssignmentUrl"
target="_blank"
disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
>
View in Canvas
</a>
<button
class="btn btn-outline-secondary mx-3"
disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
@onclick="updateInCanvas"
>
Update In Canvas
</button>
<ConfirmationModal
Disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
Label="Delete from Canvas"
Class="btn btn-outline-danger mx-3"
OnConfirmAsync="deleteFromCanvas"
/>
}
<button class="btn btn-primary mx-2" @onclick="@(() => {
assignmentContext.Assignment = null;
Navigation.NavigateTo("/course/" + planner.LocalCourse?.Settings.Name);
})">
Done
</button>
</div>
</div>

View File

@@ -1,124 +0,0 @@
@using Markdig
@using Shared.Components.AssignmentForm
@inject CoursePlanner planner
@inject AssignmentEditorContext assignmentContext
@code
{
[Parameter, EditorRequired]
public bool ShowHelp { get; set; } = false;
protected override void OnInitialized()
{
assignmentContext.StateHasChanged += reload;
reload();
}
private void reload()
{
if (assignmentContext.Assignment != null)
{
if(rawText == string.Empty)
{
rawText = assignmentContext.Assignment.ToMarkdown();
this.InvokeAsync(this.StateHasChanged);
}
}
}
public void Dispose()
{
assignmentContext.StateHasChanged -= reload;
}
private string rawText { get; set; } = string.Empty;
private string? error = null;
public bool? UseTemplate { get; set; } = null;
public string? TemplateId { get; set; }
private void handleChange(string newRawAssignment)
{
rawText = newRawAssignment;
if (newRawAssignment != string.Empty)
{
try
{
var parsed = LocalAssignment.ParseMarkdown(newRawAssignment);
error = null;
assignmentContext.SaveAssignment(parsed);
}
catch(AssignmentMarkdownParseException e)
{
error = e.Message;
}
catch(RubricMarkdownParseException e)
{
error = e.Message;
}
finally
{
StateHasChanged();
}
}
StateHasChanged();
}
private MarkupString preview { get => (MarkupString)Markdown.ToHtml(assignmentContext?.Assignment?.Description ?? ""); }
private string HelpText()
{
var groupNames = string.Join("\n- " , planner.LocalCourse?.Settings.AssignmentGroups.Select(g => g.Name) ?? []);
return $@"
SubmissionTypes:
- {AssignmentSubmissionType.ONLINE_TEXT_ENTRY}
- {AssignmentSubmissionType.ONLINE_UPLOAD}
- {AssignmentSubmissionType.DISCUSSION_TOPIC}
Assignment Group Names:
- {groupNames}
";
}
}
<div class="d-flex w-100 h-100 flex-row">
@if(ShowHelp)
{
<div class=" rounded rounded-3 bg-black" >
<pre class=" me-3 pe-5 ps-3 rounded rounded-3">
@HelpText()
</pre>
</div>
}
@if(assignmentContext.Assignment != null && planner.LocalCourse != null)
{
<div class="row h-100 w-100">
<div class="col-6">
<MonacoTextArea Value=@rawText OnChange=@handleChange />
</div>
<div class="col-6 overflow-y-auto h-100" >
@if (error != null)
{
<p class="text-danger text-truncate">Error: @error</p>
}
<div>Due At: @assignmentContext.Assignment.DueAt</div>
<div>Lock At: @assignmentContext.Assignment.LockAt</div>
<div>Assignment Group Name @assignmentContext.Assignment.LocalAssignmentGroupName</div>
<div>Submission Types</div>
<ul>
@foreach(var t in assignmentContext.Assignment.SubmissionTypes)
{
<li>@t</li>
}
</ul>
<hr>
<div>
@(preview)
</div>
<hr>
<RubricDisplay />
</div>
</div>
}
</div>

View File

@@ -1,61 +0,0 @@
@using Management.Web.Shared.Components
@inject CoursePlanner planner
@inject AssignmentEditorContext assignmentContext
@code
{
private string? error { get; set; } = null;
protected override void OnInitialized()
{
assignmentContext.StateHasChanged += reload;
reload();
}
private void reload()
{
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
assignmentContext.StateHasChanged -= reload;
}
private int requiredPoints => assignmentContext?.Assignment?.Rubric.Where(r => !r.IsExtraCredit).Select(r => r.Points).Sum() ?? 0;
private int extraCreditPoints => assignmentContext?.Assignment?.Rubric.Where(r => r.IsExtraCredit).Select(r => r.Points).Sum() ?? 0;
}
@if(assignmentContext != null)
{
<div class="row">
<h4 class="text-center">Rubric</h4>
</div>
@if (error != null)
{
<p class="text-danger text-truncate">Error: @error</p>
}
<div class="row border-bottom">
<div class="col-6 text-end">Label</div>
<div class="col-3 text-center">Points</div>
<div class="col-3 text-center">Extra Credit</div>
</div>
@foreach (var item in assignmentContext?.Assignment?.Rubric ?? [])
{
<div class="row border-bottom">
<div class="col-6 text-end">@item.Label</div>
<div class="col-3 text-center">@item.Points</div>
<div class="col-3 text-center">@item.IsExtraCredit</div>
</div>
}
<div class="text-end">
<div>
Required Points: @requiredPoints
</div>
<div>
Extra Credit Points @extraCreditPoints
</div>
</div>
}

View File

@@ -1,85 +0,0 @@
@using System.Reflection
@inject AssignmentEditorContext assignmentContext
@code
{
protected override void OnInitialized()
{
assignmentContext.StateHasChanged += reload;
reload();
}
private void reload()
{
if (assignmentContext.Assignment != null)
{
types = assignmentContext.Assignment.SubmissionTypes;
}
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
assignmentContext.StateHasChanged -= reload;
}
private IEnumerable<string> types { get; set; } = Enumerable.Empty<string>();
private string getLabel(string type)
{
return type.ToString().Replace("_", "") + "switch";
}
private bool discussionIsSelected
{
get => types.FirstOrDefault(
t => t == AssignmentSubmissionType.DISCUSSION_TOPIC
) != null;
}
private void saveTypes(IEnumerable<string> newTypes)
{
if(assignmentContext.Assignment != null)
{
types = newTypes;
assignmentContext.SaveAssignment(assignmentContext.Assignment with
{
SubmissionTypes = types
});
}
}
}
<h5>Submission Types</h5>
<div class="row" @key="types">
@foreach (var submissionType in AssignmentSubmissionType.AllTypes)
{
var isDiscussion = submissionType == AssignmentSubmissionType.DISCUSSION_TOPIC;
var allowedToBeChecked = !discussionIsSelected || isDiscussion;
<div class="col-3">
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="@getLabel(submissionType)"
checked="@(types.Contains(submissionType) && allowedToBeChecked)"
@onchange="(e) => {
var isChecked = (bool)(e.Value ?? false);
if(isChecked)
saveTypes(types.Append(submissionType));
else
saveTypes(types.Where(t => t != submissionType));
}"
disabled="@(discussionIsSelected && !isDiscussion)"
>
<label
class="form-check-label"
for="@getLabel(submissionType)"
>
@submissionType
</label>
</div>
</div>
}
</div>

View File

@@ -1,82 +0,0 @@
@using Markdig
@code {
[Parameter, EditorRequired]
public LocalQuizQuestion Question { get; set; } = default!;
}
<div class="row justify-content-between text-secondary">
<div class="col">
points: @Question.Points
</div>
<div class="col-auto">
@Question.QuestionType
</div>
</div>
@((MarkupString)Question.HtmlText)
@if(Question.QuestionType == QuestionType.MATCHING)
{
@foreach(var answer in Question.Answers)
{
<div class="mx-3 mb-1 bg-dark px-2 rounded rounded-2 border row">
<div
class="col text-end my-auto p-1"
>
@answer.Text
</div>
<div
class="col my-auto"
>
@answer.MatchedText
</div>
</div>
}
}
else
{
@foreach(var answer in Question.Answers)
{
string answerPreview = answer.HtmlText.StartsWith("<p>")
? answer.HtmlText.Replace("<p>", "<p class='m-0'>")
: answer.HtmlText;
<div class="mx-3 mb-1 bg-dark px-2 rounded rounded-2 d-flex flex-row border">
@if(answer.Correct)
{
<svg
style="width: 1em;"
class="me-1 my-auto"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M4 12.6111L8.92308 17.5L20 6.5"
stroke="var(--bs-success)"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
}
else
{
<div
class="me-1 my-auto"
style="width: 1em;"
>
@if(Question.QuestionType == QuestionType.MULTIPLE_ANSWERS)
{
<span>[ ]</span>
}
</div>
}
<div class="markdownQuizAnswerPreview p-1">
@((MarkupString)answerPreview)
</div>
</div>
}
}

View File

@@ -1,79 +0,0 @@
@using Management.Web.Shared.Components
@inject QuizEditorContext quizContext
@code {
private Modal? modal { get; set; }
private LocalQuiz? testQuiz;
private string? error { get; set; } = null;
private string _quizMarkdownInput { get; set; } = "";
private string quizMarkdownInput
{
get => _quizMarkdownInput;
set
{
_quizMarkdownInput = value;
try
{
var newQuiz = LocalQuiz.ParseMarkdown(_quizMarkdownInput);
error = null;
testQuiz = newQuiz;
quizContext.SaveQuiz(newQuiz);
}
catch (QuizMarkdownParseException e)
{
error = e.Message;
StateHasChanged();
}
}
}
protected override void OnInitialized()
{
reload();
quizContext.StateHasChanged += reload;
}
private void reload()
{
if (quizContext.Quiz != null)
{
if (quizMarkdownInput == "")
{
quizMarkdownInput = quizContext.Quiz.ToMarkdown();
}
this.InvokeAsync(this.StateHasChanged);
}
}
public void Dispose()
{
quizContext.StateHasChanged -= reload;
}
}
<div class="d-flex flex-column h-100">
<div class="d-flex flex-row h-100 p-2">
<div class="row flex-grow-1">
<div class="col-6">
<MonacoTextArea
Value="@quizMarkdownInput"
OnChange="@((v) => quizMarkdownInput = v)"
/>
</div>
<div class="col-6 h-100 overflow-y-auto">
@if (error != null)
{
<p class="text-danger text-truncate">Error: @error</p>
}
@if(testQuiz != null)
{
<QuizPreview Quiz="testQuiz" />
}
</div>
</div>
</div>
</div>

View File

@@ -1,72 +0,0 @@
@using Management.Web.Shared.Components
@inject QuizEditorContext quizContext
@code {
[Parameter, EditorRequired]
public LocalQuiz Quiz { get; set; } = default!;
protected override void OnInitialized()
{
quizContext.StateHasChanged += reload;
}
private void reload()
{
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
quizContext.StateHasChanged -= reload;
}
}
@if(Quiz != null)
{
<div class="row justify-content-start">
<div class="col-auto" style="min-width: 35em;">
<div class="row">
<div class="col-6 text-end">Name: </div>
<div class="col-6">@Quiz.Name</div>
</div>
<div class="row">
<div class="col-6 text-end">Due At: </div>
<div class="col-6">@Quiz.DueAt</div>
</div>
<div class="row">
<div class="col-6 text-end">Lock At: </div>
<div class="col-6">@Quiz.LockAt</div>
</div>
<div class="row">
<div class="col-6 text-end">Shuffle Answers: </div>
<div class="col-6">@Quiz.ShuffleAnswers</div>
</div>
<div class="row">
<div class="col-6 text-end">Allowed Attempts: </div>
<div class="col-6">@Quiz.AllowedAttempts</div>
</div>
<div class="row">
<div class="col-6 text-end">One question at a time: </div>
<div class="col-6">@Quiz.OneQuestionAtATime</div>
</div>
<div class="row">
<div class="col-6 text-end">Assignment Group: </div>
<div class="col-6">@Quiz.LocalAssignmentGroupName</div>
</div>
</div>
</div>
<div class="p-3" style="white-space: pre-wrap;">@Quiz.Description</div>
@foreach(var question in Quiz.Questions)
{
<div class="bg-dark-subtle mt-1 p-1 ps-2 rounded rounded-2">
<MarkdownQuestionPreview
Question="question"
@key="question"
/>
</div>
}
}

View File

@@ -1,142 +0,0 @@
@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

@@ -1,60 +0,0 @@
@using CanvasModel.EnrollmentTerms
@using Management.Web.Shared.Module
@using Management.Web.Shared.Semester
@using Management.Web.Shared.Components.AssignmentForm
@using Management.Web.Shared.Components.Quiz
@using Management.Web.Shared.Components.Quiz.Markdown
@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

@@ -1,166 +0,0 @@
@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>

View File

@@ -1,6 +1,5 @@
@using CanvasModel.EnrollmentTerms
@using Management.Web.Shared.Components
@using Management.Web.Shared.Semester
@using CanvasModel.Courses
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@using LocalModels
@@ -110,9 +109,9 @@
<div class="row justify-content-center">
<div class="col-auto">
<label for="termselect">Select Term:</label>
<select
id="termselect"
class="form-select"
<select
id="termselect"
class="form-select"
@bind="selectedTermId"
>
@foreach (var term in terms)
@@ -148,9 +147,9 @@
<div class="row justify-content-center m-3">
<div class="col-auto">
<label for="directorySelect">Select Storage Directory:</label>
<select
id="directorySelect"
class="form-select"
<select
id="directorySelect"
class="form-select"
@bind="selectedStorageDirectory"
>
<option></option>
@@ -168,12 +167,12 @@
@foreach (DayOfWeek day in (DayOfWeek[])Enum.GetValues(typeof(DayOfWeek)))
{
<div class="col">
<button
<button
class="@(
days.Contains(day)
? "btn btn-secondary"
days.Contains(day)
? "btn btn-secondary"
: "btn btn-outline-secondary"
)"
)"
@onclick="() => {
if(days.Contains(day))
days.Remove(day);

View File

@@ -1,5 +1,4 @@
@using Management.Web.Shared.Components
@using Management.Web.Shared.Components.AssignmentForm
@using CanvasModel.Assignments;
@inject DragContainer dragContainer
@@ -26,7 +25,7 @@
}
private bool showAll { get; set; } = false;
private void HandleDragStart()
{
dragContainer.DropCallback = DropCallback;
@@ -43,9 +42,9 @@
a => a.Name == Assignment.Name
);
private bool existsInCanvas =>
private bool existsInCanvas =>
assignmentInCanvas != null;
private void OnClick()
private void OnClick()
{
assignmentContext.Assignment = Assignment;
Navigation.NavigateTo("/course/" + planner.LocalCourse?.Settings.Name + "/assignment/" + Assignment.Name);
@@ -54,15 +53,15 @@
private bool NeedsToBeUpdatedInCanvas => planner.LocalCourse != null
&& planner.LocalCourse.Settings.CanvasId != null
&& planner.CanvasAssignments != null
&& planner.CanvasModules != null
&& planner.CanvasModules != null
&& assignmentInCanvas != null
&& Assignment.NeedsUpdates(
(CanvasAssignment)assignmentInCanvas,
(CanvasAssignment)assignmentInCanvas,
Assignment.GetCanvasAssignmentGroupId(planner.LocalCourse.Settings.AssignmentGroups)
);
}
<div
<div
draggable="true"
@ondragstart="HandleDragStart"
@ondragend="HandleDragEnd"
@@ -99,15 +98,15 @@
</div>
@if(
planner.LocalCourse != null
&& existsInCanvas
&& NeedsToBeUpdatedInCanvas
planner.LocalCourse != null
&& existsInCanvas
&& NeedsToBeUpdatedInCanvas
&& assignmentInCanvas != null
)
{
<div class="mx-3 text-body-tertiary">
@Assignment.GetUpdateReason(
(CanvasAssignment)assignmentInCanvas,
(CanvasAssignment)assignmentInCanvas,
Assignment.GetCanvasAssignmentGroupId(planner.LocalCourse.Settings.AssignmentGroups))
</div>
}
@@ -149,25 +148,25 @@
</section>
</div>
}
@if(!showAll)
{
<div
class="text-center fs-3 fw-bold lh-1 text-primary"
role="button"
@onclick:preventDefault="true"
<div
class="text-center fs-3 fw-bold lh-1 text-primary"
role="button"
@onclick:preventDefault="true"
@onclick:stopPropagation="true"
@onclick="() => showAll = true"
>
<svg
width="30"
height="30"
viewBox="0 0 20 20"
<svg
width="30"
height="30"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 10a2 2 0 11-4.001-.001A2 2 0 016 10zm6 0a2 2 0 11-4.001-.001A2 2 0 0112 10zm6 0a2 2 0 11-4.001-.001A2 2 0 0118 10z"
<path
d="M6 10a2 2 0 11-4.001-.001A2 2 0 016 10zm6 0a2 2 0 11-4.001-.001A2 2 0 0112 10zm6 0a2 2 0 11-4.001-.001A2 2 0 0118 10z"
fill="var(--bs-primary)"
/>
</svg>
@@ -175,21 +174,21 @@
}
else
{
<div
class="text-center fs-3 fw-bold lh-1 text-primary"
role="button"
@onclick:preventDefault="true"
<div
class="text-center fs-3 fw-bold lh-1 text-primary"
role="button"
@onclick:preventDefault="true"
@onclick:stopPropagation="true"
@onclick="() => showAll = false"
>
<svg
width="30"
height="30"
viewBox="0 0 20 20"
<svg
width="30"
height="30"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 10a2 2 0 11-4.001-.001A2 2 0 016 10zm6 0a2 2 0 11-4.001-.001A2 2 0 0112 10zm6 0a2 2 0 11-4.001-.001A2 2 0 0118 10z"
<path
d="M6 10a2 2 0 11-4.001-.001A2 2 0 016 10zm6 0a2 2 0 11-4.001-.001A2 2 0 0112 10zm6 0a2 2 0 11-4.001-.001A2 2 0 0118 10z"
fill="var(--bs-primary)"
/>
</svg>

View File

@@ -1,53 +0,0 @@
@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

@@ -1,130 +0,0 @@
@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

@@ -1,34 +0,0 @@
@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

@@ -1,55 +0,0 @@
@using System.Linq
@using Management.Web.Shared.Semester.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>