Add deleting bookmark groups
This commit is contained in:
parent
1b8460fd3e
commit
64b893b778
|
@ -18,7 +18,7 @@ This is a rewrite of my [New Tab Page project](https://github.com/NeilBrommer/Ne
|
||||||
- [x] Bookmarks
|
- [x] Bookmarks
|
||||||
- [ ] Manage bookmark containers
|
- [ ] Manage bookmark containers
|
||||||
- [x] Create
|
- [x] Create
|
||||||
- [ ] Delete
|
- [x] Delete
|
||||||
- [ ] Edit
|
- [ ] Edit
|
||||||
- [ ] Manage bookmark groups
|
- [ ] Manage bookmark groups
|
||||||
- [x] Create
|
- [x] Create
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
@using System.Drawing
|
@using System.Drawing
|
||||||
@using Fluxor
|
@using Fluxor
|
||||||
@using Start.Client.Store.State
|
@using Start.Client.Store.State
|
||||||
|
@using Start.Client.Store.Features.DeleteGroup
|
||||||
|
|
||||||
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
|
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
|
||||||
|
|
||||||
|
@ -12,6 +13,14 @@
|
||||||
<h2 class="card-title h6 d-inline-block @this.ForegroundTitleColorClass">
|
<h2 class="card-title h6 d-inline-block @this.ForegroundTitleColorClass">
|
||||||
@this.Group.Title
|
@this.Group.Title
|
||||||
</h2>
|
</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>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<ul class="bookmarks">
|
<ul class="bookmarks">
|
||||||
|
@ -72,6 +81,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void OnDeleteGroupClicked()
|
||||||
|
{
|
||||||
|
dispatch.Dispatch(new ShowDeleteGroupFormAction(
|
||||||
|
this.Group.BookmarkGroupId, this.Group.Title));
|
||||||
|
}
|
||||||
|
|
||||||
protected void OnCreateBookmarkClicked()
|
protected void OnCreateBookmarkClicked()
|
||||||
{
|
{
|
||||||
// Placeholder
|
// Placeholder
|
||||||
|
|
46
Start/Client/Components/DeleteGroup.razor
Normal file
46
Start/Client/Components/DeleteGroup.razor
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,6 +79,7 @@ else
|
||||||
<DeleteContainer />
|
<DeleteContainer />
|
||||||
|
|
||||||
<CreateGroup />
|
<CreateGroup />
|
||||||
|
<DeleteGroup />
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,9 @@
|
||||||
|
|
||||||
.card-title {
|
.card-title {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
// Keep the delete button from increasing the height of the header
|
||||||
|
line-height: 1.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-body {
|
.card-body {
|
||||||
|
|
|
@ -129,6 +129,7 @@
|
||||||
<None Remove="Store\Features\Sidebar\" />
|
<None Remove="Store\Features\Sidebar\" />
|
||||||
<None Remove="Sass\" />
|
<None Remove="Sass\" />
|
||||||
<None Remove="Sass\Spectre\" />
|
<None Remove="Sass\Spectre\" />
|
||||||
|
<None Remove="Store\Features\DeleteGroup\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Remove="wwwroot\css\Spectre\" />
|
<Content Remove="wwwroot\css\Spectre\" />
|
||||||
|
@ -145,5 +146,6 @@
|
||||||
<Folder Include="Store\Features\Sidebar\" />
|
<Folder Include="Store\Features\Sidebar\" />
|
||||||
<Folder Include="Sass\" />
|
<Folder Include="Sass\" />
|
||||||
<Folder Include="Sass\Spectre\" />
|
<Folder Include="Sass\Spectre\" />
|
||||||
|
<Folder Include="Store\Features\DeleteGroup\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -4,18 +4,14 @@ using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||||
using Start.Client.Store.Features.CurrentContainer;
|
using Start.Client.Store.Features.CurrentContainer;
|
||||||
using Start.Shared.Api;
|
using Start.Shared.Api;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Start.Client.Store.State;
|
|
||||||
using Start.Client.Store.Features.ContainersList;
|
using Start.Client.Store.Features.ContainersList;
|
||||||
|
|
||||||
namespace Start.Client.Store.Features.DeleteContainer {
|
namespace Start.Client.Store.Features.DeleteContainer {
|
||||||
public class DeleteContainerEffects {
|
public class DeleteContainerEffects {
|
||||||
public IBookmarkContainersApi BookmarkContainersApi { get; init; }
|
public IBookmarkContainersApi BookmarkContainersApi { get; init; }
|
||||||
public IState<RootState> RootState { get; set; }
|
|
||||||
|
|
||||||
public DeleteContainerEffects(IBookmarkContainersApi bookmarkContainersApi,
|
public DeleteContainerEffects(IBookmarkContainersApi bookmarkContainersApi) {
|
||||||
IState<RootState> rootState) {
|
|
||||||
this.BookmarkContainersApi = bookmarkContainersApi;
|
this.BookmarkContainersApi = bookmarkContainersApi;
|
||||||
this.RootState = rootState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[EffectMethod]
|
[EffectMethod]
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
Start/Client/Store/Features/DeleteGroup/DeleteGroupState.cs
Normal file
24
Start/Client/Store/Features/DeleteGroup/DeleteGroupState.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue