Add Blazor WebApp and rework data handling to utilize Entity Framework
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
@page "/students/create"
|
||||
@inject AppDbContext Context
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<PageTitle>Create Student - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">Create</MudText>
|
||||
<MudText Typo="Typo.h4">Student</MudText>
|
||||
<MudDivider />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<EditForm method="post" Model="Student" OnValidSubmit="AddStudent" FormName="create" Enhance>
|
||||
<DataAnnotationsValidator />
|
||||
<ValidationSummary class="text-danger" role="alert"/>
|
||||
<div class="mb-3">
|
||||
<label for="firstname" class="form-label">First Name:</label>
|
||||
<InputText id="firstname" @bind-Value="Student.FirstName" class="form-control" />
|
||||
<ValidationMessage For="() => Student.FirstName" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="lastname" class="form-label">Last Name:</label>
|
||||
<InputText id="lastname" @bind-Value="Student.LastName" class="form-control" />
|
||||
<ValidationMessage For="() => Student.LastName" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="grade" class="form-label">Grade:</label>
|
||||
<InputNumber id="grade" @bind-Value="Student.Grade" class="form-control" />
|
||||
<ValidationMessage For="() => Student.Grade" class="text-danger" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="tsayear" class="form-label">TSA Year:</label>
|
||||
<InputNumber id="tsayear" @bind-Value="Student.TsaYear" class="form-control" />
|
||||
<ValidationMessage For="() => Student.TsaYear" class="text-danger" />
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Create</button>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="/students">Back to List</a>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[SupplyParameterFromForm]
|
||||
private Student Student { get; set; } = new() { TsaYear = 1 };
|
||||
|
||||
private async Task AddStudent()
|
||||
{
|
||||
|
||||
Context.Students.Add(Student);
|
||||
await Context.SaveChangesAsync();
|
||||
NavigationManager.NavigateTo("/students");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
@page "/students/delete"
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@inject AppDbContext context
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<PageTitle>Delete Student - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<h1>Delete</h1>
|
||||
|
||||
<p>Are you sure you want to delete this?</p>
|
||||
<div>
|
||||
<h2>Student</h2>
|
||||
<hr />
|
||||
@if (student is null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else {
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">FirstName</dt>
|
||||
<dd class="col-sm-10">@student.FirstName</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">LastName</dt>
|
||||
<dd class="col-sm-10">@student.LastName</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">Grade</dt>
|
||||
<dd class="col-sm-10">@student.Grade</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">StateId</dt>
|
||||
<dd class="col-sm-10">@student.StateId</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">RegionalId</dt>
|
||||
<dd class="col-sm-10">@student.RegionalId</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">NationalId</dt>
|
||||
<dd class="col-sm-10">@student.NationalId</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">TsaYear</dt>
|
||||
<dd class="col-sm-10">@student.TsaYear</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">OfficerRole</dt>
|
||||
<dd class="col-sm-10">@student.OfficerRole</dd>
|
||||
</dl>
|
||||
<EditForm method="post" Model="student" OnValidSubmit="DeleteStudent" FormName="delete" Enhance>
|
||||
<button type="submit" class="btn btn-danger" disabled="@(student is null)">Delete</button> |
|
||||
<a href="/students">Back to List</a>
|
||||
</EditForm>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private Student? student;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private int Id { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
student = await context.Students.FirstOrDefaultAsync(m => m.Id == Id);
|
||||
|
||||
if (student is null)
|
||||
{
|
||||
NavigationManager.NavigateTo("notfound");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteStudent()
|
||||
{
|
||||
context.Students.Remove(student!);
|
||||
await context.SaveChangesAsync();
|
||||
NavigationManager.NavigateTo("/students");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
@page "/students/details"
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using Core.Entities
|
||||
@using Data
|
||||
@inject AppDbContext context
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<PageTitle>Student Details - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<h1>Details</h1>
|
||||
|
||||
<div>
|
||||
<h2>Student</h2>
|
||||
<hr />
|
||||
@if (student is null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else {
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">FirstName</dt>
|
||||
<dd class="col-sm-10">@student.FirstName</dd>
|
||||
<dt class="col-sm-2">LastName</dt>
|
||||
<dd class="col-sm-10">@student.LastName</dd>
|
||||
<dt class="col-sm-2">Grade</dt>
|
||||
<dd class="col-sm-10">@student.Grade</dd>
|
||||
<dt class="col-sm-2">Email</dt>
|
||||
<dd class="col-sm-10">@student.Email</dd>
|
||||
<dt class="col-sm-2">PhoneNumber</dt>
|
||||
<dd class="col-sm-10">@student.PhoneNumber</dd>
|
||||
<dt class="col-sm-2">TsaYear</dt>
|
||||
<dd class="col-sm-10">@student.TsaYear</dd>
|
||||
<dt class="col-sm-2">StateId</dt>
|
||||
<dd class="col-sm-10">@student.StateId</dd>
|
||||
<dt class="col-sm-2">RegionalId</dt>
|
||||
<dd class="col-sm-10">@student.RegionalId</dd>
|
||||
<dt class="col-sm-2">NationalId</dt>
|
||||
<dd class="col-sm-10">@student.NationalId</dd>
|
||||
<dt class="col-sm-2">OfficerRole</dt>
|
||||
<dd class="col-sm-10">@student.OfficerRole</dd>
|
||||
</dl>
|
||||
<div>
|
||||
<a href="@($"/students/edit?id={student.Id}")">Edit</a> |
|
||||
<a href="@($"/students")">Back to List</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private Student? student;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private int Id { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
student = await context.Students.FirstOrDefaultAsync(m => m.Id == Id);
|
||||
|
||||
if (student is null)
|
||||
{
|
||||
NavigationManager.NavigateTo("notfound");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
@page "/students/edit"
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@inject AppDbContext Context
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<PageTitle>Edit Student - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">Edit</MudText>
|
||||
<MudText Typo="Typo.h4">Student@(@Student == null ? "" : $" ({Student.Name})")</MudText>
|
||||
|
||||
|
||||
|
||||
@if (Student is null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
/* https://www.mudblazor.com/components/form */
|
||||
/* https://medium.com/@husainalbar/applying-mudblazor-for-crud-operations-in-our-blazor-project-a343037a52ef */
|
||||
<EditForm method="post" Model="Student" OnValidSubmit="UpdateStudent" FormName="edit" Enhance>
|
||||
<DataAnnotationsValidator/>
|
||||
<MudGrid>
|
||||
<MudItem xs="12" sm="7">
|
||||
<MudPaper Class="pa-4">
|
||||
<MudTextField T="string" Label="First Name" @bind-Value="Student.FirstName" For="@(() => Student.FirstName)"></MudTextField>
|
||||
<MudTextField T="string" Label="Last Name" @bind-Value="Student.LastName" For="@(() => Student.LastName)"></MudTextField>
|
||||
<MudTextField T="string" Label="Email Adress" @bind-Value="Student.Email" For="@(() => Student.Email)"></MudTextField>
|
||||
<MudTextField T="string" Label="Phone Number" @bind-Value="Student.PhoneNumber" For="@(() => Student.PhoneNumber)"></MudTextField>
|
||||
<MudTextField T="int" Label="Grade" @bind-Value="Student.Grade" For="@(() => Student.Grade)"></MudTextField>
|
||||
<MudTextField T="int" Label="TSA Year" @bind-Value="Student.TsaYear" For="@(() => Student.TsaYear)"></MudTextField>
|
||||
<MudTextField T="string" Label="Regional Id" @bind-Value="Student.RegionalId" For="@(() => Student.RegionalId)"></MudTextField>
|
||||
<MudTextField T="string" Label="State Id" @bind-Value="Student.StateId" For="@(() => Student.StateId)"></MudTextField>
|
||||
<MudTextField T="string" Label="National Id" @bind-Value="Student.NationalId" For="@(() => Student.NationalId)"></MudTextField>
|
||||
<MudSelect T="OfficerRole?" @bind-Value="@Student.OfficerRole" Label="Officer Role">
|
||||
|
||||
<MudSelectItem T="OfficerRole?" Value="@null">-not an officer-</MudSelectItem>
|
||||
@foreach (var officerRole in Enum.GetValues(typeof(OfficerRole)).Cast<OfficerRole>())
|
||||
{
|
||||
<MudSelectItem T="OfficerRole?" Value="@(officerRole)"></MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.ArrowBack" Href="students">Back</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Save" OnClick="UpdateStudent">Save</MudButton>
|
||||
</EditForm>
|
||||
}
|
||||
|
||||
@code {
|
||||
[SupplyParameterFromQuery]
|
||||
private int Id { get; set; }
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private Student? Student { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
Student ??= await Context.Students.FirstOrDefaultAsync(m => m.Id == Id);
|
||||
|
||||
if (Student is null)
|
||||
{
|
||||
NavigationManager.NavigateTo("notfound");
|
||||
}
|
||||
}
|
||||
|
||||
// To protect from overposting attacks, enable the specific properties you want to bind to.
|
||||
// For more information, see https://learn.microsoft.com/aspnet/core/blazor/forms/#mitigate-overposting-attacks.
|
||||
private async Task UpdateStudent()
|
||||
{
|
||||
if (Student.OfficerRole == 0)
|
||||
Student.OfficerRole = null;
|
||||
|
||||
Context.Attach(Student!).State = EntityState.Modified;
|
||||
|
||||
try
|
||||
{
|
||||
await Context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (!StudentExists(Student!.Id))
|
||||
{
|
||||
NavigationManager.NavigateTo("notfound");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
NavigationManager.NavigateTo("/students");
|
||||
}
|
||||
|
||||
private bool StudentExists(int id)
|
||||
{
|
||||
return Context.Students.Any(e => e.Id == id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@page "/students/event-ranking"
|
||||
@inject AppDbContext Context
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Student Event Ranks - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
@if (_students == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTable Items="_students" Hover="true" Breakpoint="Breakpoint.Sm" LoadingProgressColor="Color.Info">
|
||||
<HeaderContent>
|
||||
|
||||
<MudTh>Name</MudTh>
|
||||
<MudTh>Grade</MudTh>
|
||||
<MudTh>TSA Year</MudTh>
|
||||
<MudTh>1st</MudTh>
|
||||
<MudTh>2nd</MudTh>
|
||||
<MudTh>3rd</MudTh>
|
||||
<MudTh>4th</MudTh>
|
||||
<MudTh>5th</MudTh>
|
||||
<MudTh>6th</MudTh>
|
||||
<MudTh></MudTh>
|
||||
<MudTh>Warnings</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
|
||||
<MudTd>@context.FirstName</MudTd>
|
||||
<MudTh>@context.Grade</MudTh>
|
||||
<MudTh>@context.TsaYear</MudTh>
|
||||
|
||||
@for (var i = 1; i <= 6; i++)
|
||||
{
|
||||
var st = context.EventRankings.FirstOrDefault(e => e.Rank == i);
|
||||
<MudTd Class="@($"event-rank-{i})")">
|
||||
@if (st != null)
|
||||
{
|
||||
<span>@st.EventDefinition.ShortName
|
||||
@if(st.EventDefinition.EventFormat == EventFormat.Individual) { <span>ⓘ</span>}
|
||||
@if(st.EventDefinition.RegionalEvent) { <span>ⓡ</span>}
|
||||
@if(st.EventDefinition.OnSiteActivity) { <span>ⓐ</span>}
|
||||
</span>
|
||||
}
|
||||
</MudTd>
|
||||
}
|
||||
<MudTd><MudButton StartIcon="@Icons.Material.Filled.TableChart" Href="@($"students/event-ranking-edit/{context.Id}")">Edit</MudButton></MudTd>
|
||||
<MudTd>
|
||||
@if (!context.RankedEvents.Any(re => re.OnSiteActivity))
|
||||
{
|
||||
<MudTooltip Text="No On-Site Activity">
|
||||
<MudIcon Color="Color.Warning" Icon="@Icons.Material.Filled.LocalActivity"></MudIcon>
|
||||
</MudTooltip>
|
||||
}
|
||||
@if (!context.RankedEvents.Any(re => re.RegionalEvent))
|
||||
{
|
||||
<MudTooltip Text="No Regional Event">
|
||||
<MudIcon Color="Color.Warning" Icon="@Icons.Material.Filled.PinDrop"></MudIcon>
|
||||
</MudTooltip>
|
||||
}
|
||||
|
||||
@if (context.RankedEvents.All(re => re.EventFormat != EventFormat.Individual))
|
||||
{
|
||||
<MudTooltip Text="No Individual Event">
|
||||
<MudIcon Color="Color.Warning" Icon="@Icons.Material.Filled.Person"></MudIcon>
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
<MudTable Items="_eventStudentRankings" Hover="true" Breakpoint="Breakpoint.Sm" LoadingProgressColor="Color.Info">
|
||||
<HeaderContent>
|
||||
<MudTh>Event</MudTh>
|
||||
<MudTh>Level of Effort</MudTh>
|
||||
<MudTh>Individual</MudTh>
|
||||
<MudTh>Regional</MudTh>
|
||||
<MudTh>On-site Activity</MudTh>
|
||||
<MudTh>Team Size</MudTh>
|
||||
@for (var i = 0; i < _maxEventStudentRankings; i++)
|
||||
{
|
||||
var i1 = i + 1;
|
||||
<MudTh>@i1</MudTh>
|
||||
}
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Event.Name</MudTd>
|
||||
<MudTd>@context.Event.LevelOfEffort</MudTd>
|
||||
<MudTd>@if (context.Event.EventFormat == EventFormat.Individual) { <span>ⓘ</span> }</MudTd >
|
||||
<MudTd>@if (context.Event.RegionalEvent) { <span>ⓡ</span> }</MudTd >
|
||||
<MudTd>@if (context.Event.OnSiteActivity) { <span>ⓐ</span> }</MudTd >
|
||||
<MudTd>[@context.Event.MinTeamSize-@context.Event.MaxTeamSize]</MudTd >
|
||||
@for (var j = 0; j < _maxEventStudentRankings; j++)
|
||||
{
|
||||
var student = j < context.StudentRanking.Length ? context.StudentRanking[j] : null;
|
||||
var eventClass = student != null ? $"event-rank-{student.Item2}" : "";
|
||||
<MudTd Class="@eventClass">
|
||||
@if (student != null)
|
||||
{
|
||||
@student.Item1.FirstName
|
||||
}
|
||||
</MudTd>
|
||||
}
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
}
|
||||
@code {
|
||||
private Student[]? _students;
|
||||
|
||||
private class EventStudentRankings {
|
||||
public EventDefinition Event {get; set; }
|
||||
public Tuple<Student,int> [] StudentRanking { get; set; }
|
||||
}
|
||||
|
||||
private EventStudentRankings[] _eventStudentRankings;
|
||||
private int _maxEventStudentRankings;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_students =
|
||||
await Context.Students
|
||||
.Include(e => e.EventRankings)
|
||||
.ThenInclude(e => e.EventDefinition)
|
||||
.OrderBy(e => e.FirstName).ToArrayAsync();
|
||||
|
||||
_eventStudentRankings =
|
||||
_students.SelectMany(s =>
|
||||
s.EventRankings,
|
||||
(student, ranking) => new { e = ranking.EventDefinition, a = Tuple.Create(student, ranking.Rank) }
|
||||
)
|
||||
.GroupBy(e => e.e)
|
||||
.Select(e =>
|
||||
new EventStudentRankings
|
||||
{
|
||||
Event = e.Key,
|
||||
StudentRanking = e.Select(er => er.a).OrderBy(ser => ser.Item2).ThenByDescending(ser => ser.Item1.Grade + ser.Item1.TsaYear).ToArray()
|
||||
})
|
||||
.OrderBy(e => e.Event.Name)
|
||||
.ToArray();
|
||||
|
||||
var events = await Context.Events.ToArrayAsync();
|
||||
var remainingEvents =
|
||||
events
|
||||
.Where(e => _eventStudentRankings.All(est => est.Event.Id != e.Id))
|
||||
.Select(e => new EventStudentRankings { Event = e, StudentRanking = Array.Empty<Tuple<Student, int>>() })
|
||||
.OrderBy(e => e.Event.Name)
|
||||
.ToArray();
|
||||
|
||||
_eventStudentRankings = _eventStudentRankings.Concat(remainingEvents).ToArray();
|
||||
|
||||
_maxEventStudentRankings = _eventStudentRankings.Max(esr => esr.StudentRanking.Length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using BlazorSortableList
|
||||
@using WebApp.Models
|
||||
@page "/students/event-ranking-edit/{StudentId:int}"
|
||||
@inject AppDbContext Context
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<PageTitle>Student Event Ranks - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">Student Event Ranks</MudText>
|
||||
|
||||
<div>
|
||||
@if (_student == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.h4">@_student.Name</MudText>
|
||||
<MudText Color="Color.Warning">Warning: drag and drop is currently a bit squirrely - double check!</MudText>
|
||||
|
||||
<MudButton StartIcon="@Icons.Material.Filled.ArrowBack" Href="students/event-ranking">Back</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Save" OnClick="Save">Save</MudButton>
|
||||
|
||||
/* https://github.com/AlexNek/BlazorSortableList */
|
||||
<MudGrid>
|
||||
<MudItem xs="6" md="4" xl="3" Class="ranked-event-column">
|
||||
<SortableList
|
||||
Group="GroupId" Id="ListId1" Context="item"
|
||||
Items="_rankedEvents" OnRemove="RankedEventsRemove" OnUpdate="Update">
|
||||
<SortableItemTemplate>
|
||||
<MudCard Outlined="true">
|
||||
<MudCardContent>@item.Name</MudCardContent>
|
||||
</MudCard>
|
||||
</SortableItemTemplate>
|
||||
</SortableList>
|
||||
</MudItem>
|
||||
<MudItem xs="6" md="4" xl="3">
|
||||
<SortableList
|
||||
Group="GroupId" Id="ListId2" Context="item"
|
||||
Items="_availableEvents" OnRemove="AvailableEventsRemove" Sort="false">
|
||||
<SortableItemTemplate>
|
||||
<MudCard Outlined="true">
|
||||
<MudCardContent>@item.Name</MudCardContent>
|
||||
</MudCard>
|
||||
</SortableItemTemplate>
|
||||
|
||||
</SortableList>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
private const string ListId1 = "SharedListId1";
|
||||
private const string ListId2 = "SharedListId2";
|
||||
private const string GroupId = "CommonGroup";
|
||||
|
||||
[Parameter] public int? StudentId { get; set; }
|
||||
|
||||
private Student? _student;
|
||||
private List<EventDefinition>? _events;
|
||||
|
||||
public List<EventDefinition> _rankedEvents = [];
|
||||
public List<EventDefinition> _availableEvents = [];
|
||||
|
||||
SharedSortableListGroup _group;
|
||||
|
||||
private void RankedEventsRemove((int oldIndex, int newIndex) indices)
|
||||
{
|
||||
// get the item at the old index in list 1
|
||||
var item = _rankedEvents[indices.oldIndex];
|
||||
|
||||
// add it to the new index in list 2
|
||||
_availableEvents.Insert(indices.newIndex, item);
|
||||
|
||||
// remove the item from the old index in list 1
|
||||
_rankedEvents.Remove(_rankedEvents[indices.oldIndex]);
|
||||
}
|
||||
|
||||
private void AvailableEventsRemove((int oldIndex, int newIndex) indices)
|
||||
{
|
||||
// get the item at the old index in list 2
|
||||
var item = _availableEvents[indices.oldIndex];
|
||||
|
||||
// add it to the new index in list 1
|
||||
_rankedEvents.Insert(indices.newIndex, item);
|
||||
|
||||
// remove the item from the old index in list 2
|
||||
_availableEvents.Remove(_availableEvents[indices.oldIndex]);
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_student =
|
||||
await Context.Students
|
||||
.Include(e => e.EventRankings)
|
||||
.Where(e => e.Id == StudentId).FirstAsync();
|
||||
_events =
|
||||
await Context.Events
|
||||
.OrderBy(e => e.Name)
|
||||
.ToListAsync();
|
||||
|
||||
_rankedEvents = _student.EventRankings.OrderBy(e => e.Rank).Select(e => e.EventDefinition).ToList();
|
||||
_availableEvents = _events.Where(e => !_rankedEvents.Contains(e)).ToList();
|
||||
|
||||
_group = new SharedSortableListGroup(StateHasChanged);
|
||||
_group.AddModel(ListId1, new SortableListModel<EventDefinition>(_rankedEvents) { Group = GroupId });
|
||||
_group.AddModel(ListId2, new SortableListModel<EventDefinition>(_availableEvents) { Group = GroupId });
|
||||
}
|
||||
|
||||
private void Update((int oldIndex, int newIndex) indices)
|
||||
{
|
||||
var (oldIndex, newIndex) = indices;
|
||||
|
||||
var items = _rankedEvents;
|
||||
var itemToMove = items[oldIndex];
|
||||
items.RemoveAt(oldIndex);
|
||||
|
||||
if (newIndex < items.Count)
|
||||
{
|
||||
items.Insert(newIndex, itemToMove);
|
||||
}
|
||||
else
|
||||
{
|
||||
items.Add(itemToMove);
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
async Task Save()
|
||||
{
|
||||
if (_student == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_student.EventRankings.Clear();
|
||||
for (var index = 0; index < _rankedEvents.Count; index++)
|
||||
{
|
||||
var evt = _rankedEvents[index];
|
||||
_student.EventRankings.Add(new StudentEventRanking
|
||||
{
|
||||
EventDefinition = evt,
|
||||
Student = _student,
|
||||
Rank = index + 1
|
||||
});
|
||||
}
|
||||
|
||||
Context.Students.Update(_student);
|
||||
|
||||
await Context.SaveChangesAsync();
|
||||
|
||||
NavigationManager.NavigateTo("/students/event-ranking");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
@page "/students"
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using WebApp.Models
|
||||
@inject AppDbContext Context
|
||||
|
||||
<PageTitle>Students - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">Students</MudText>
|
||||
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Create" Href="students/create">Create New</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.AddChart" Href="students/event-ranking">Event Rankings</MudButton>
|
||||
|
||||
<MudDataGrid T="Student" ServerData="ServerReload" @ref="_dataGrid" Filterable="true" RowsPerPage="25">
|
||||
<Columns>
|
||||
@* <PropertyColumn Property="@(e => e.Name)" Title="First Name" SortBy="e => e.FirstName" /> *@
|
||||
<TemplateColumn Title="Name" SortBy="e => e.FirstName" Sortable="true">
|
||||
<CellTemplate>
|
||||
@context.Item.Name
|
||||
@if (context.Item.OfficerRole != null)
|
||||
{
|
||||
<MudChip T="string" Icon="@(AppIcons.OfficerRoleIcon(context.Item.OfficerRole.Value))">@context.Item.OfficerRole</MudChip>
|
||||
}
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="Grade (TSA Year)" SortBy="e => e.Grade" Sortable="true">
|
||||
<CellTemplate>
|
||||
@context.Item.Grade (@context.Item.TsaYear)
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn>
|
||||
<CellTemplate>
|
||||
<MudStack Row>
|
||||
<MudButtonGroup Size="Size.Small">
|
||||
<MudTooltip Text="Details">
|
||||
<MudIconButton Href="@($"/students/details?id={context.Item.Id}")" Icon="@Icons.Material.Filled.Description">Details</MudIconButton>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="Edit">
|
||||
<MudIconButton Href="@($"/students/edit?id={context.Item.Id}")" Icon="@Icons.Material.Filled.Edit">Edit</MudIconButton>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="Delete">
|
||||
<MudIconButton Href="@($"/students/delete?id={context.Item.Id}")" Icon="@Icons.Material.Filled.Delete" Color="@Color.Warning">Delete</MudIconButton>
|
||||
</MudTooltip>
|
||||
</MudButtonGroup>
|
||||
</MudStack>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="Student"></MudDataGridPager>
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
|
||||
@code {
|
||||
MudDataGrid<Student> _dataGrid = null!;
|
||||
|
||||
private async Task<GridData<Student>> ServerReload(GridState<Student> state)
|
||||
{
|
||||
|
||||
var query = Context.Students.Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
||||
|
||||
var totalItems = await query.CountAsync();
|
||||
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync();
|
||||
|
||||
return new GridData<Student>
|
||||
{
|
||||
TotalItems = totalItems,
|
||||
Items = pagedData
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user