Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dashboard Campaign Deletion Modal #48

Merged
merged 6 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions ChatRPG/App.razor
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
<CascadingBlazoredModal>
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingBlazoredModal>
</CascadingAuthenticationState>
1 change: 1 addition & 0 deletions ChatRPG/ChatRPG.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Blazored.Modal" Version="7.1.0" />
<PackageReference Include="MailKit" Version="4.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.12" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.12" />
Expand Down
58 changes: 58 additions & 0 deletions ChatRPG/Pages/ConfirmModal.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
@using ChatRPG.Services
@using ChatRPG.Data.Models

<div class="modal fade show d-block" tabindex="-1" role="dialog">
<div class="modal-backdrop fade show" @onclick="Cancel"></div>
<div class="modal-dialog" style="z-index: 1050">
<!-- Pop it above the backdrop -->
<div class="modal-content custom-gray-bg text-white">
<div class="modal-header">
<h5 class="modal-title">Delete Campaign?</h5>
<button type="button" class="close" aria-label="Close" @onclick="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Do you really want to delete the campaign?</p>
<p>
<b>Campaign title:</b> @CampaignToDelete!.Title
</p>
<p>
<b>Character name:</b> @CampaignToDelete!.Player.Name
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @onclick="Close" id="modal-close">Close</button>
<button type="button" class="btn alert-danger" @onclick="Confirm" id="modal-confirm">Confirm</button>
</div>
</div>
</div>
</div>

@code {

[CascadingParameter]
BlazoredModalInstance Modal { get; set; } = default!;

[Parameter]
[EditorRequired]
public Campaign? CampaignToDelete { get; set; }

[Inject]
private IPersisterService? PersistService { get; set; }

private async Task Confirm()
{
if (CampaignToDelete is null)
{
await Modal.CancelAsync();
}

await PersistService!.DeleteAsync(CampaignToDelete!);
await Modal.CloseAsync(ModalResult.Ok(true));
}

private async Task Close() => await Modal.CloseAsync(ModalResult.Ok(false));
private async Task Cancel() => await Modal.CancelAsync();

}
5 changes: 4 additions & 1 deletion ChatRPG/Pages/UserCampaignOverview.razor
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
<div class="vstack overflow-auto form-text-black mb-1 scrollbar" style="max-height: 500px;" id="your-campaigns">
@foreach (CampaignModel campaign in Campaigns)
{
<button class="card card-dim mb-2" @onclick='() => LaunchCampaign(campaign.Id)'>
<button class="campaign-button card card-dim mb-2" @onclick='() => LaunchCampaign(campaign.Id)'>
<div class="card-body col-12">
<h5 class="card-title">@campaign.Title</h5>
<h6 class="card-subtitle mb-2 text-muted" style="font-size: 14px;">@campaign.Player.Name</h6>
<hr/>
<p class="card-text line-clamp text-start">@(campaign.StartScenario ?? "No scenario")</p>
<p class="card-text" style="font-size: 14px;">Started @campaign.StartedOn.ToShortDateString() @campaign.StartedOn.ToShortTimeString()</p>
</div>
<button class="delete-campaign-button rounded" @onclick='() => ShowCampaignDeleteModal(campaign)' @onclick:stopPropagation>
<i class="bi bi-trash3 text-danger"></i>
</button>
</button>
}
</div>
Expand Down
23 changes: 23 additions & 0 deletions ChatRPG/Pages/UserCampaignOverview.razor.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.Security.Authentication;
using Blazored.Modal;
using Blazored.Modal.Services;
using ChatRPG.Data.Models;
using ChatRPG.Services;
using Microsoft.AspNetCore.Components;
Expand Down Expand Up @@ -32,6 +34,8 @@ public partial class UserCampaignOverview : ComponentBase
[Inject] private ICampaignMediatorService? CampaignMediatorService { get; set; }
[Inject] private NavigationManager? NavMan { get; set; }

[CascadingParameter] public IModalService? ConfirmDeleteModal { get; set; }

protected override async Task OnInitializedAsync()
{
AuthenticationState authState = await AuthProvider!.GetAuthenticationStateAsync();
Expand Down Expand Up @@ -79,6 +83,25 @@ private void ApplyStartingScenario(string title, string scenario)
StateHasChanged();
}

private async Task ShowCampaignDeleteModal(Campaign campaign)
{
IModalReference modal = ConfirmDeleteModal!.Show<ConfirmModal>("Delete Campaign",
new ModalParameters().Add(nameof(ConfirmModal.CampaignToDelete), campaign));

ModalResult shouldDelete = await modal.Result;
if (shouldDelete.Confirmed)
{
await ModalClosed();
}
}

private async Task ModalClosed()
{
Campaigns = await PersisterService!.GetCampaignsForUser(User!);
Campaigns.Reverse(); // Reverse to display latest campaign first
StateHasChanged();
}

private bool FieldIsEmpty()
{
if (string.IsNullOrWhiteSpace(CampaignTitle) && string.IsNullOrWhiteSpace(CharacterName))
Expand Down
1 change: 1 addition & 0 deletions ChatRPG/Pages/_Host.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<link href="css/site.css" rel="stylesheet" />
<link href="ChatRPG.styles.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png"/>
Expand Down
2 changes: 2 additions & 0 deletions ChatRPG/Program.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Blazored.Modal;
using ChatRPG.API;
using ChatRPG.Areas.Identity;
using ChatRPG.Data;
Expand All @@ -22,6 +23,7 @@
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddBlazoredModal();

HttpMessageHandlerFactory httpMessageHandlerFactory = new HttpMessageHandlerFactory(configuration);
builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<User>>()
Expand Down
26 changes: 26 additions & 0 deletions ChatRPG/Services/EfPersisterService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,32 @@ public async Task SaveAsync(Campaign campaign)
}
}

/// <inheritdoc />
public async Task DeleteAsync(Campaign campaign)
{
if (!(await _dbContext.Campaigns.ContainsAsync(campaign)))
{
return;
}

await using IDbContextTransaction transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
int campaignId = campaign.Id;
_dbContext.Campaigns.Remove(campaign);

await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
_logger.LogInformation("Deleted campaign with id {Id} successfully", campaignId);
}
catch (Exception e)
{
_logger.LogError(e, "An error occurred while deleting");
await transaction.RollbackAsync();
throw;
}
}

/// <inheritdoc />
public async Task<Campaign> LoadFromCampaignIdAsync(int campaignId)
{
Expand Down
6 changes: 6 additions & 0 deletions ChatRPG/Services/IPersisterService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ public interface IPersisterService
/// <returns>A task representing the asynchronous operation.</returns>
Task SaveAsync(Campaign campaign);
/// <summary>
/// Deletes the given <paramref name="campaign"/> and all its related entities.
/// </summary>
/// <param name="campaign">The campaign to delete.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task DeleteAsync(Campaign campaign);
/// <summary>
/// Loads the campaign with the given <paramref name="campaignId"/> with all its related entities.
/// </summary>
/// <param name="campaignId">Id of the campaign to load.</param>
Expand Down
2 changes: 2 additions & 0 deletions ChatRPG/_Imports.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Blazored.Modal
@using Blazored.Modal.Services
@using ChatRPG
@using ChatRPG.Shared
31 changes: 27 additions & 4 deletions ChatRPG/wwwroot/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
height: 100%;
}

h1:focus {
Expand All @@ -12,6 +13,10 @@ a, .btn-link {
color: #0071c1;
}

.page {
min-height: 100vh;
}

.btn-primary {
background-color: #4eb758;
color: black;
Expand Down Expand Up @@ -180,7 +185,7 @@ a, .btn-link {
.dashboard-wrapper {
display: flex;
flex-direction: column;
height: 100vh;
height: 100%;
}

.dashboard-container {
Expand All @@ -189,8 +194,7 @@ a, .btn-link {
flex-direction: column;
align-items: center;
justify-content: center;
overflow-y: auto;
margin-top: -120px;
margin-top: -50px;
}

.title-front {
Expand Down Expand Up @@ -226,7 +230,6 @@ a, .btn-link {
}

.card-dim {
width: 18rem;
background: #dcdcdc;
}

Expand Down Expand Up @@ -354,3 +357,23 @@ a, .btn-link {
.dashboard-title-container {
padding-bottom: 60px;
}

.campaign-button {
position: relative;
}

.delete-campaign-button {
position: absolute;
bottom: 0;
right: 0;
margin-right: 5px;
margin-bottom: 5px;
background: none;
overflow: hidden;
outline:none;
border:solid 1px black;
}

.delete-campaign-button:hover {
background: #eaeaea;
}
Loading