Add deleting bookmark groups

This commit is contained in:
Neil Brommer 2021-12-11 13:56:35 -08:00
parent 1b8460fd3e
commit 64b893b778
12 changed files with 235 additions and 6 deletions

View file

@ -18,7 +18,7 @@ This is a rewrite of my [New Tab Page project](https://github.com/NeilBrommer/Ne
- [x] Bookmarks
- [ ] Manage bookmark containers
- [x] Create
- [ ] Delete
- [x] Delete
- [ ] Edit
- [ ] Manage bookmark groups
- [x] Create

View file

@ -1,6 +1,7 @@
@using System.Drawing
@using Fluxor
@using Start.Client.Store.State
@using Start.Client.Store.Features.DeleteGroup
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@ -12,6 +13,14 @@
<h2 class="card-title h6 d-inline-block @this.ForegroundTitleColorClass">
@this.Group.Title
</h2>
@if (this.state.Value.EditMode)
{
<button class="btn btn-error tooltip tooltip-left float-right"
data-tooltip="Delete Group" @onclick="this.OnDeleteGroupClicked">
<i class="icon icon-delete"></i>
</button>
}
</div>
<div class="card-body">
<ul class="bookmarks">
@ -72,6 +81,12 @@
}
}
protected void OnDeleteGroupClicked()
{
dispatch.Dispatch(new ShowDeleteGroupFormAction(
this.Group.BookmarkGroupId, this.Group.Title));
}
protected void OnCreateBookmarkClicked()
{
// Placeholder

View file

@ -0,0 +1,46 @@
@using Start.Client.Store.Features.DeleteGroup
@using Fluxor
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@inject IDispatcher dispatch
@inject IState<DeleteGroupState> state
@{ string title = $"Delete Group \"{this.state.Value.BookmarkGroupTitleToDelete}\""; }
<Dialog Title="@title" Active="this.state.Value.ShowDeleteGroupForm" OnClose="this.OnDialogClose">
@if (this.state.Value.DeleteGroupErrorMessage != null)
{
<Alert Type="Alert.AlertType.Error">
@this.state.Value.DeleteGroupErrorMessage
</Alert>
}
<p>
Are you sure you want to delete the bookmark container
"@this.state.Value.BookmarkGroupTitleToDelete"?
</p>
<div class="text-right">
@if (!this.state.Value.IsLoadingDeleteGroup)
{
<button type="button" class="btn" @onclick="this.OnDialogClose">Cancel</button>
<button type="submit" class="btn btn-error" @onclick="this.OnConfirmDelete">Delete</button>
}
else
{
<button type="button" disabled class="btn" @onclick="this.OnDialogClose">Cancel</button>
<button type="submit" disabled class="btn btn-error loading" @onclick="this.OnConfirmDelete">Delete</button>
}
</div>
</Dialog>
@code {
public void OnDialogClose() {
this.dispatch.Dispatch(new HideDeleteGroupFormAction());
}
public void OnConfirmDelete() {
this.dispatch.Dispatch(new SubmitDeleteGroupFormAction(
this.state.Value.BookmarkGroupIdToDelete));
}
}

View file

@ -79,6 +79,7 @@ else
<DeleteContainer />
<CreateGroup />
<DeleteGroup />
</Sidebar>
}

View file

@ -170,6 +170,9 @@
.card-title {
margin-top: 0.5em;
font-weight: bold;
// Keep the delete button from increasing the height of the header
line-height: 1.25;
}
.card-body {

View file

@ -129,6 +129,7 @@
<None Remove="Store\Features\Sidebar\" />
<None Remove="Sass\" />
<None Remove="Sass\Spectre\" />
<None Remove="Store\Features\DeleteGroup\" />
</ItemGroup>
<ItemGroup>
<Content Remove="wwwroot\css\Spectre\" />
@ -145,5 +146,6 @@
<Folder Include="Store\Features\Sidebar\" />
<Folder Include="Sass\" />
<Folder Include="Sass\Spectre\" />
<Folder Include="Store\Features\DeleteGroup\" />
</ItemGroup>
</Project>

View file

@ -4,18 +4,14 @@ using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Start.Client.Store.Features.CurrentContainer;
using Start.Shared.Api;
using System.Net;
using Start.Client.Store.State;
using Start.Client.Store.Features.ContainersList;
namespace Start.Client.Store.Features.DeleteContainer {
public class DeleteContainerEffects {
public IBookmarkContainersApi BookmarkContainersApi { get; init; }
public IState<RootState> RootState { get; set; }
public DeleteContainerEffects(IBookmarkContainersApi bookmarkContainersApi,
IState<RootState> rootState) {
public DeleteContainerEffects(IBookmarkContainersApi bookmarkContainersApi) {
this.BookmarkContainersApi = bookmarkContainersApi;
this.RootState = rootState;
}
[EffectMethod]

View file

@ -0,0 +1,33 @@
namespace Start.Client.Store.Features.DeleteGroup {
public class ShowDeleteGroupFormAction {
public int GroupIdToDelete { get; init; }
public string GroupTitleToDelete { get; init; }
public ShowDeleteGroupFormAction(int groupIdToDelete, string groupTitleToDelete) {
this.GroupIdToDelete = groupIdToDelete;
this.GroupTitleToDelete = groupTitleToDelete;
}
}
public class HideDeleteGroupFormAction { }
public class FetchDeleteGroupFormAction { }
public class SubmitDeleteGroupFormAction {
public int GroupIdToDelete { get; init; }
public SubmitDeleteGroupFormAction(int groupIdToDelete) {
this.GroupIdToDelete = groupIdToDelete;
}
}
public class ReceivedDeleteGroupAction { }
public class ErrorFetchingDeleteGroupAction {
public string ErrorMessage { get; init; }
public ErrorFetchingDeleteGroupAction(string errorMessage) {
this.ErrorMessage = errorMessage;
}
}
}

View file

@ -0,0 +1,49 @@
using System.Threading.Tasks;
using Fluxor;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Start.Shared.Api;
using Start.Client.Store.Features.CurrentContainer;
namespace Start.Client.Store.Features.DeleteGroup {
public class DeleteGroupEffects {
public IBookmarkGroupsApi BookmarkGroupsApi { get; init; }
public DeleteGroupEffects(IBookmarkGroupsApi bookmarkGroupsApi) {
this.BookmarkGroupsApi = bookmarkGroupsApi;
}
[EffectMethod]
public async Task SubmitDeleteGroupForm(SubmitDeleteGroupFormAction action,
IDispatcher dispatch) {
dispatch.Dispatch(new FetchDeleteGroupFormAction());
try {
System.Net.Http.HttpResponseMessage? apiResonse = await this.BookmarkGroupsApi
.DeleteBookmarkGroup(action.GroupIdToDelete);
if (apiResonse == null) {
dispatch.Dispatch(new ErrorFetchingDeleteGroupAction(
"Failed to submit request"));
return;
}
if (apiResonse.StatusCode == System.Net.HttpStatusCode.NotFound) {
dispatch.Dispatch(new ErrorFetchingDeleteGroupAction(
"The bookmark group to delete doesn't exist"));
return;
}
if (!apiResonse.IsSuccessStatusCode) {
dispatch.Dispatch(new ErrorFetchingDeleteGroupAction(
"There was an error deleting the bookmark group"));
return;
}
dispatch.Dispatch(new RemoveBookmarkGroupAction(action.GroupIdToDelete));
dispatch.Dispatch(new ReceivedDeleteGroupAction());
} catch (AccessTokenNotAvailableException e) {
e.Redirect();
}
}
}
}

View file

@ -0,0 +1,11 @@
using Fluxor;
namespace Start.Client.Store.Features.DeleteGroup {
public class DeleteGroupFeature : Feature<DeleteGroupState> {
public override string GetName() => "Delete Group";
protected override DeleteGroupState GetInitialState() {
return new DeleteGroupState();
}
}
}

View file

@ -0,0 +1,49 @@
using Fluxor;
namespace Start.Client.Store.Features.DeleteGroup {
public static class DeleteGroupReducers {
[ReducerMethod]
public static DeleteGroupState ShowDeleteGroupForm(DeleteGroupState state,
ShowDeleteGroupFormAction action) {
return state with {
ShowDeleteGroupForm = true,
BookmarkGroupIdToDelete = action.GroupIdToDelete,
BookmarkGroupTitleToDelete = action.GroupTitleToDelete,
IsLoadingDeleteGroup = false,
DeleteGroupErrorMessage = null
};
}
[ReducerMethod(typeof(HideDeleteGroupFormAction))]
public static DeleteGroupState HideDeleteGroupForm(DeleteGroupState state) {
return state with {
ShowDeleteGroupForm = false
};
}
[ReducerMethod(typeof(FetchDeleteGroupFormAction))]
public static DeleteGroupState FetchDeleteGroup(DeleteGroupState state) {
return state with {
IsLoadingDeleteGroup = true,
DeleteGroupErrorMessage = null
};
}
[ReducerMethod(typeof(ReceivedDeleteGroupAction))]
public static DeleteGroupState ReceivedDeleteGroup(DeleteGroupState state) {
return state with {
IsLoadingDeleteGroup = false,
ShowDeleteGroupForm = false
};
}
[ReducerMethod]
public static DeleteGroupState ErrorFetchingDeleteGroup(DeleteGroupState state,
ErrorFetchingDeleteGroupAction action) {
return state with {
IsLoadingDeleteGroup = false,
DeleteGroupErrorMessage = action.ErrorMessage
};
}
}
}

View file

@ -0,0 +1,24 @@
using System;
namespace Start.Client.Store.Features.DeleteGroup {
public record DeleteGroupState {
public bool ShowDeleteGroupForm { get; init; }
public int BookmarkGroupIdToDelete { get; init; }
public string BookmarkGroupTitleToDelete { get; init; }
public bool IsLoadingDeleteGroup { get; init; }
public string? DeleteGroupErrorMessage { get; init; }
public DeleteGroupState() {
this.BookmarkGroupTitleToDelete = "";
}
public DeleteGroupState(bool showDeleteGroupForm, int bookmarkGroupIdToDelete,
string bookmarkTitleToDelete, bool isLoadingDeleteGroup,
string? deleteGroupErrorMessage) {
this.ShowDeleteGroupForm = showDeleteGroupForm;
this.BookmarkGroupIdToDelete = bookmarkGroupIdToDelete;
this.BookmarkGroupTitleToDelete = bookmarkTitleToDelete;
this.IsLoadingDeleteGroup = isLoadingDeleteGroup;
this.DeleteGroupErrorMessage = deleteGroupErrorMessage;
}
}
}