Use Fluxor for state management
This commit is contained in:
parent
437e90039f
commit
560c25b4e8
|
@ -1,3 +1,5 @@
|
|||
<Fluxor.Blazor.Web.StoreInitializer />
|
||||
|
||||
<CascadingAuthenticationState>
|
||||
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
|
||||
<Found Context="routeData">
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
@using Start.Shared
|
||||
|
||||
<div class="activeBookmarkContainer">
|
||||
<div class="activeBookmarkContainer">
|
||||
@if (this.Container == null)
|
||||
{
|
||||
<div class="empty">
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
@using Start.Shared
|
||||
|
||||
<h2 class="bookmarkGroupTitle" style="background-color: #@this.Group.Color">
|
||||
<h2 class="bookmarkGroupTitle" style="background-color: #@this.Group.Color">
|
||||
@this.Group.Title
|
||||
</h2>
|
||||
<ul class="bookmarkGroupList">
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
@using Start.Shared
|
||||
@using Start.Shared.Api
|
||||
@using Refit
|
||||
@using Start.Client.Store.Features.CreateContainer
|
||||
@using Fluxor
|
||||
|
||||
@inject IBookmarkContainersApi bookmarkContainersApi
|
||||
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
|
||||
|
||||
<Dialog Title="Create Container" Active="this.IsOpen" OnClose="this.OnDialogClose">
|
||||
<EditForm Model="this.model" OnValidSubmit="this.OnSubmit">
|
||||
@if (displayError)
|
||||
@inject IDispatcher dispatch
|
||||
@inject IState<CreateContainerState> state
|
||||
|
||||
<Dialog Title="Create Container" Active="this.state.Value.ShowCreateContainerForm" OnClose="this.OnDialogClose">
|
||||
<EditForm Model="this.Model" OnValidSubmit="this.OnSubmit">
|
||||
@if (this.state.Value.CreateContainerErrorMessage != null)
|
||||
{
|
||||
<Alert Type="Alert.AlertType.Error">
|
||||
There was an error creating the container
|
||||
@this.state.Value.CreateContainerErrorMessage
|
||||
</Alert>
|
||||
}
|
||||
<div class="form-group">
|
||||
|
@ -19,7 +21,7 @@
|
|||
<div>
|
||||
<label for="createBookmarkContainerTitle" class="form-label">Title</label>
|
||||
<InputText id="createBookmarkContainerTitle" name="createBookmarkContainerTitle"
|
||||
class="form-input" @bind-Value="this.model.Title" />
|
||||
class="form-input" @bind-Value="this.Model.Title" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -28,9 +30,18 @@
|
|||
<div class="columns">
|
||||
<div class="column col-12 text-right">
|
||||
<div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="icon icon-plus"></i> Create
|
||||
</button>
|
||||
@if (this.state.Value.IsLoadingCreateContainer)
|
||||
{
|
||||
<button type="submit" disabled class="btn btn-primary loading">
|
||||
<i class="icon icon-plus"></i> Create
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="icon icon-plus"></i> Create
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -42,34 +53,16 @@
|
|||
@code {
|
||||
[Parameter]
|
||||
public EventCallback<BookmarkContainerDto> OnCreated { get; set; }
|
||||
[Parameter]
|
||||
public bool IsOpen { get; set; }
|
||||
[Parameter]
|
||||
public EventCallback OnClose { get; set; }
|
||||
|
||||
private BookmarkContainerDto model = new("");
|
||||
private bool displayError = false;
|
||||
private BookmarkContainerDto Model { get; set; } = new BookmarkContainerDto("");
|
||||
|
||||
protected async void OnSubmit()
|
||||
protected void OnSubmit()
|
||||
{
|
||||
ApiResponse<BookmarkContainerDto?> apiResponse = await bookmarkContainersApi
|
||||
.CreateBookmarkContainer(model.Title);
|
||||
|
||||
BookmarkContainerDto? container = apiResponse.Content;
|
||||
|
||||
if (container == null)
|
||||
{
|
||||
this.displayError = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await this.OnCreated.InvokeAsync(container);
|
||||
}
|
||||
dispatch.Dispatch(new SubmitCreateContainerAction(this.Model));
|
||||
}
|
||||
|
||||
protected async void OnDialogClose()
|
||||
protected void OnDialogClose()
|
||||
{
|
||||
this.IsOpen = false;
|
||||
await this.OnClose.InvokeAsync();
|
||||
dispatch.Dispatch(new HideCreateContainerFormAction());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,66 +1,48 @@
|
|||
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
|
||||
@using Start.Shared.Api
|
||||
@using Start.Client.Store.Features.DeleteContainer
|
||||
@using Fluxor
|
||||
|
||||
@inject HttpClient Http
|
||||
@inject IBookmarkContainersApi bookmarkContainersApi
|
||||
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
|
||||
|
||||
@{ string title = $"Delete Container \"{this.ContainerTitle}\""; }
|
||||
@inject IDispatcher dispatch
|
||||
@inject IState<DeleteContainerState> state
|
||||
|
||||
<Dialog Title="@title" Active="this.Active">
|
||||
@if (this.ShowAlert)
|
||||
@{ string title = $"Delete Container \"{this.state.Value.BookmarkContainerTitleToDelete}\""; }
|
||||
|
||||
<Dialog Title="@title" Active="this.state.Value.ShowDeleteContainerForm" OnClose="this.OnDialogClose">
|
||||
@if (this.state.Value.DeleteContainerErrorMessage != null)
|
||||
{
|
||||
<div class="toast toast-error">
|
||||
There was an error deleting the bookmark container
|
||||
</div>
|
||||
<Alert Type="Alert.AlertType.Error">
|
||||
@this.state.Value.DeleteContainerErrorMessage
|
||||
</Alert>
|
||||
}
|
||||
<p>Are you sure you want to delete the bookmark container "@this.ContainerTitle"?</p>
|
||||
|
||||
<p>
|
||||
Are you sure you want to delete the bookmark container
|
||||
"@this.state.Value.BookmarkContainerTitleToDelete"?
|
||||
</p>
|
||||
<div class="text-right">
|
||||
<button class="btn" @onclick="this.OnDialogClose">Cancel</button>
|
||||
<button class="btn btn-error" @onclick="this.OnConfirmDelete">Delete</button>
|
||||
@if (!this.state.Value.IsLoadingDeleteContainer)
|
||||
{
|
||||
<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 {
|
||||
[Parameter]
|
||||
public int BookmarkContainerId { get; set; }
|
||||
[Parameter]
|
||||
public string ContainerTitle { get; set; } = null!;
|
||||
[Parameter]
|
||||
public bool Active { get; set; }
|
||||
[Parameter]
|
||||
public EventCallback<int> OnDeleted { get; set; }
|
||||
[Parameter]
|
||||
public EventCallback OnClose { get; set; }
|
||||
|
||||
public bool ShowAlert { get; set; } = false;
|
||||
|
||||
public async Task OnDialogClose()
|
||||
public void OnDialogClose()
|
||||
{
|
||||
this.Active = false;
|
||||
await this.OnClose.InvokeAsync();
|
||||
this.dispatch.Dispatch(new HideDeleteContainerFormAction());
|
||||
}
|
||||
|
||||
public async Task OnConfirmDelete()
|
||||
public void OnConfirmDelete()
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpResponseMessage result = await bookmarkContainersApi
|
||||
.DeleteBookmarkContainer(this.BookmarkContainerId);
|
||||
|
||||
if (result.StatusCode == System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
await this.OnDeleted.InvokeAsync(BookmarkContainerId);
|
||||
this.ShowAlert = false;
|
||||
this.Active = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ShowAlert = true;
|
||||
}
|
||||
}
|
||||
catch (AccessTokenNotAvailableException e)
|
||||
{
|
||||
e.Redirect();
|
||||
}
|
||||
this.dispatch.Dispatch(new SubmitDeleteContainerAction(
|
||||
this.state.Value.BookmarkContainerIdToDelete));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,30 @@
|
|||
@page "/"
|
||||
@using System.Collections.Generic
|
||||
|
||||
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
|
||||
|
||||
@using System.Linq
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
|
||||
@using Start.Client.Components
|
||||
@using Start.Shared
|
||||
@using Start.Shared.Api
|
||||
@using Refit
|
||||
@using Start.Client.Store.State
|
||||
@using Start.Client.Store.Features.ContainersList
|
||||
@using Start.Client.Store.Features.CurrentContainer
|
||||
@using Start.Client.Store.Features.CreateContainer
|
||||
@using Start.Client.Store.Features.DeleteContainer
|
||||
@using Fluxor
|
||||
|
||||
@* Distinguish from Refit.Authorize *@
|
||||
@attribute [Microsoft.AspNetCore.Authorization.Authorize]
|
||||
@inject Blazored.LocalStorage.ILocalStorageService localStorage
|
||||
@inject IBookmarkContainersApi bookmarkContainersApi
|
||||
|
||||
@if (bookmarkContainers == null)
|
||||
@inject Blazored.LocalStorage.ILocalStorageService localStorage
|
||||
@inject IState<RootState> state
|
||||
@inject IDispatcher dispatch
|
||||
|
||||
@if (this.state.Value.ContainerListState.ErrorMessage != null) {
|
||||
<Alert Type="Alert.AlertType.Error">
|
||||
<b>Error</b> @this.state.Value.ContainerListState.ErrorMessage
|
||||
</Alert>
|
||||
}
|
||||
|
||||
@if (this.state.Value.ContainerListState.IsLoadingContainersList)
|
||||
{
|
||||
<div class="empty">
|
||||
<div class="empty-icon">
|
||||
|
@ -24,10 +36,10 @@
|
|||
else
|
||||
{
|
||||
<ul class="containerList tab">
|
||||
@foreach (BookmarkContainerDto container in this.bookmarkContainers)
|
||||
@foreach (BookmarkContainerDto container in this.state.Value.ContainerListState.Containers)
|
||||
{
|
||||
string itemClasses = "tab-item";
|
||||
if (container.BookmarkContainerId == this.selectedBookmarkContainer?.BookmarkContainerId)
|
||||
if (container.BookmarkContainerId == this.state.Value.CurrentContainerState.Container?.BookmarkContainerId)
|
||||
itemClasses += " active";
|
||||
|
||||
<li class="@itemClasses">
|
||||
|
@ -47,132 +59,41 @@ else
|
|||
</li>
|
||||
</ul>
|
||||
|
||||
<BookmarkContainer Container="this.selectedBookmarkContainer" />
|
||||
<BookmarkContainer Container="this.state.Value.CurrentContainerState.Container" />
|
||||
|
||||
<CreateContainer IsOpen="showCreateContainerForm" OnClose="this.OnCloseCreateContainer"
|
||||
OnCreated="this.OnContainerCreated" />
|
||||
<DeleteContainer Active="this.showDeleteContainerForm" OnClose="this.OnCloseDeleteContainer"
|
||||
BookmarkContainerId="this.bookmarkContainerToDelete?.BookmarkContainerId ?? 0"
|
||||
ContainerTitle="@(this.bookmarkContainerToDelete?.Title ?? "")"
|
||||
OnDeleted="this.OnContainerDeleted" />
|
||||
<CreateContainer />
|
||||
<DeleteContainer />
|
||||
}
|
||||
|
||||
@code
|
||||
{
|
||||
private IList<BookmarkContainerDto>? bookmarkContainers;
|
||||
private BookmarkContainerDto? selectedBookmarkContainer;
|
||||
|
||||
private bool showCreateContainerForm = false;
|
||||
|
||||
private bool showDeleteContainerForm = false;
|
||||
private BookmarkContainerDto? bookmarkContainerToDelete;
|
||||
|
||||
private bool showCreateGroupForm = false;
|
||||
private bool showCreateBookmarkForm = false;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadContainers();
|
||||
this.dispatch.Dispatch(new LoadContainerListAction());
|
||||
this.dispatch.Dispatch(new LoadCurrentContainerAction(await this.GetSelectedContainerId()));
|
||||
}
|
||||
|
||||
protected async Task LoadContainers()
|
||||
protected void OnContainerSelected(int bookmarkContainerId)
|
||||
{
|
||||
try
|
||||
{
|
||||
ApiResponse<IEnumerable<BookmarkContainerDto>> response = await bookmarkContainersApi
|
||||
.GetAllBookmarkContainers();
|
||||
|
||||
this.bookmarkContainers = response.Content?.ToList();
|
||||
|
||||
if (this.bookmarkContainers == null || !this.bookmarkContainers.Any())
|
||||
{
|
||||
await this.CreateDefaultContainer();
|
||||
}
|
||||
|
||||
await this.OnContainerSelected(await this.GetSelectedContainerId());
|
||||
}
|
||||
catch (AccessTokenNotAvailableException e)
|
||||
{
|
||||
e.Redirect();
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task CreateDefaultContainer()
|
||||
{
|
||||
ApiResponse<BookmarkContainerDto?> response = await bookmarkContainersApi
|
||||
.CreateBookmarkContainer("Default");
|
||||
|
||||
BookmarkContainerDto? container = response.Content;
|
||||
|
||||
if (container != null)
|
||||
await this.OnContainerSelected(container.BookmarkContainerId);
|
||||
}
|
||||
|
||||
protected async Task OnContainerSelected(int bookmarkContainerId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.bookmarkContainers?.Any(bc => bc.BookmarkContainerId == bookmarkContainerId) ?? false)
|
||||
bookmarkContainerId = this.bookmarkContainers?.First().BookmarkContainerId ?? bookmarkContainerId;
|
||||
|
||||
ApiResponse<BookmarkContainerDto?> response = await bookmarkContainersApi
|
||||
.GetBookmarkContainer(bookmarkContainerId);
|
||||
|
||||
BookmarkContainerDto? container = response.Content;
|
||||
|
||||
await this.SetSelectedContainer(bookmarkContainerId);
|
||||
this.selectedBookmarkContainer = container;
|
||||
}
|
||||
catch (AccessTokenNotAvailableException e)
|
||||
{
|
||||
e.Redirect();
|
||||
}
|
||||
dispatch.Dispatch(new LoadCurrentContainerAction(bookmarkContainerId));
|
||||
}
|
||||
|
||||
protected void OnDeleteContainerClicked(int bookmarkContainerId)
|
||||
{
|
||||
this.bookmarkContainerToDelete = this.bookmarkContainers
|
||||
?.First(bc => bc.BookmarkContainerId == bookmarkContainerId);
|
||||
this.showDeleteContainerForm = true;
|
||||
BookmarkContainerDto? bookmarkContainerToDelete = this.state.Value.ContainerListState
|
||||
.Containers
|
||||
?.FirstOrDefault(bc => bc.BookmarkContainerId == bookmarkContainerId);
|
||||
|
||||
if (bookmarkContainerToDelete == null)
|
||||
return;
|
||||
|
||||
this.dispatch.Dispatch(new ShowDeleteContainerFormAction(
|
||||
bookmarkContainerToDelete.BookmarkContainerId, bookmarkContainerToDelete.Title));
|
||||
}
|
||||
|
||||
protected void OnCreateContainerClicked()
|
||||
{
|
||||
this.showCreateContainerForm = true;
|
||||
}
|
||||
|
||||
protected void OnCloseCreateContainer()
|
||||
{
|
||||
this.showCreateContainerForm = false;
|
||||
}
|
||||
|
||||
protected async Task OnContainerCreated(BookmarkContainerDto newContainer)
|
||||
{
|
||||
if (this.bookmarkContainers == null)
|
||||
return;
|
||||
|
||||
this.bookmarkContainers.Add(newContainer);
|
||||
this.showCreateContainerForm = false;
|
||||
await OnContainerSelected(newContainer.BookmarkContainerId);
|
||||
}
|
||||
|
||||
protected void OnCloseDeleteContainer()
|
||||
{
|
||||
this.showDeleteContainerForm = false;
|
||||
}
|
||||
|
||||
protected async Task OnContainerDeleted(int bookmarkContainerId)
|
||||
{
|
||||
if (!this.bookmarkContainers?.Any(bc => bc.BookmarkContainerId != bookmarkContainerId) ?? false)
|
||||
await this.CreateDefaultContainer();
|
||||
|
||||
if (await this.GetSelectedContainerId() == bookmarkContainerId)
|
||||
await this.OnContainerSelected(
|
||||
this.bookmarkContainers?.First().BookmarkContainerId ?? bookmarkContainerId);
|
||||
|
||||
this.bookmarkContainers = this.bookmarkContainers
|
||||
?.Where(bc => bc.BookmarkContainerId != bookmarkContainerId)
|
||||
.ToList();
|
||||
dispatch.Dispatch(new ShowCreateContainerFormAction());
|
||||
}
|
||||
|
||||
// Save the currently selected container in LocalStorage so that the same container remains
|
||||
|
@ -186,7 +107,8 @@ else
|
|||
return await localStorage.GetItemAsync<int>("SelectedContainer");
|
||||
|
||||
// Default to the first container
|
||||
int firstContainer = this.bookmarkContainers!.First().BookmarkContainerId;
|
||||
int firstContainer = this.state.Value.ContainerListState.Containers
|
||||
.First().BookmarkContainerId;
|
||||
await this.SetSelectedContainer(firstContainer);
|
||||
return firstContainer;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
using Blazored.LocalStorage;
|
||||
using Refit;
|
||||
using Start.Shared.Api;
|
||||
using Fluxor;
|
||||
|
||||
namespace Start.Client {
|
||||
public class Program {
|
||||
|
@ -40,6 +41,13 @@ namespace Start.Client {
|
|||
builder.Services.AddApiAuthorization();
|
||||
builder.Services.AddBlazoredLocalStorage();
|
||||
|
||||
builder.Services.AddFluxor(opt => {
|
||||
opt.ScanAssemblies(typeof(Program).Assembly);
|
||||
#if DEBUG
|
||||
opt.UseReduxDevTools();
|
||||
#endif
|
||||
});
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
<PackageReference Include="Blazored.LocalStorage" Version="4.1.5" />
|
||||
<PackageReference Include="Refit" Version="6.1.15" />
|
||||
<PackageReference Include="Refit.HttpClientFactory" Version="6.1.15" />
|
||||
<PackageReference Include="Fluxor" Version="4.2.1" />
|
||||
<PackageReference Include="Fluxor.Blazor.Web" Version="4.2.1" />
|
||||
<PackageReference Include="Fluxor.Blazor.Web.ReduxDevTools" Version="4.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -33,8 +36,27 @@
|
|||
<None Remove="Blazored.LocalStorage" />
|
||||
<None Remove="Refit" />
|
||||
<None Remove="Refit.HttpClientFactory" />
|
||||
<None Remove="Fluxor" />
|
||||
<None Remove="Fluxor.Blazor.Web" />
|
||||
<None Remove="Fluxor.Blazor.Web.ReduxDevTools" />
|
||||
<None Remove="Store\" />
|
||||
<None Remove="Store\Features\" />
|
||||
<None Remove="Store\State\" />
|
||||
<None Remove="Store\Features\CreateContainer\" />
|
||||
<None Remove="Store\Features\DeleteContainer\" />
|
||||
<None Remove="Store\Features\ContainersList\" />
|
||||
<None Remove="Store\Features\CurrentContainer\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="wwwroot\css\Spectre\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Store\" />
|
||||
<Folder Include="Store\Features\" />
|
||||
<Folder Include="Store\State\" />
|
||||
<Folder Include="Store\Features\CreateContainer\" />
|
||||
<Folder Include="Store\Features\DeleteContainer\" />
|
||||
<Folder Include="Store\Features\ContainersList\" />
|
||||
<Folder Include="Store\Features\CurrentContainer\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
using System.Collections.Generic;
|
||||
using Start.Shared;
|
||||
|
||||
namespace Start.Client.Store.Features.ContainersList {
|
||||
/// <summary>Dispatch before sending an API request</summary>
|
||||
public class FetchContainerListAction { }
|
||||
|
||||
/// <summary>Dispatch after recieving the container list from an API request</summary>
|
||||
public class RecievedContainerListAction {
|
||||
public IList<BookmarkContainerDto> Containers { get; set; }
|
||||
|
||||
public RecievedContainerListAction(IList<BookmarkContainerDto> containers) {
|
||||
this.Containers = containers;
|
||||
}
|
||||
}
|
||||
|
||||
public class ErrorFetchingContainerListAction {
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public ErrorFetchingContainerListAction(string errorMessage) {
|
||||
this.ErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public class LoadContainerListAction { }
|
||||
|
||||
public class RemoveContainerFromListAction {
|
||||
public int ContainerIdToRemove { get; set; }
|
||||
|
||||
public RemoveContainerFromListAction(int containerIdToRemove) {
|
||||
this.ContainerIdToRemove = containerIdToRemove;
|
||||
}
|
||||
}
|
||||
|
||||
public class AddContainerToListAction {
|
||||
public BookmarkContainerDto NewContainer { get; set; }
|
||||
|
||||
public AddContainerToListAction(BookmarkContainerDto newContainer) {
|
||||
this.NewContainer = newContainer;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Fluxor;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
using Refit;
|
||||
using Start.Shared;
|
||||
using Start.Shared.Api;
|
||||
|
||||
namespace Start.Client.Store.Features.ContainersList {
|
||||
public class ContainerListEffects {
|
||||
public IBookmarkContainersApi BookmarkContainersApi { get; init; }
|
||||
|
||||
public ContainerListEffects(IBookmarkContainersApi bookmarkContainersApi) {
|
||||
this.BookmarkContainersApi = bookmarkContainersApi;
|
||||
}
|
||||
|
||||
[EffectMethod(typeof(LoadContainerListAction))]
|
||||
public async Task LoadContainerList(IDispatcher dispatch) {
|
||||
dispatch.Dispatch(new FetchContainerListAction());
|
||||
|
||||
try {
|
||||
ApiResponse<IEnumerable<BookmarkContainerDto>> response = await this
|
||||
.BookmarkContainersApi
|
||||
.GetAllBookmarkContainers();
|
||||
|
||||
List<BookmarkContainerDto>? bookmarkContainers = response.Content?.ToList();
|
||||
|
||||
if (bookmarkContainers == null) {
|
||||
dispatch.Dispatch(new ErrorFetchingContainerListAction(
|
||||
"Failed to fetch containers list"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bookmarkContainers.Any())
|
||||
throw new NotImplementedException("Create bookmark effect has not been created");
|
||||
|
||||
dispatch.Dispatch(new RecievedContainerListAction(bookmarkContainers));
|
||||
}
|
||||
catch (AccessTokenNotAvailableException e) {
|
||||
e.Redirect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Fluxor;
|
||||
using Start.Client.Store.State;
|
||||
using Start.Shared;
|
||||
|
||||
namespace Start.Client.Store.Features.ContainersList {
|
||||
public static class ContainerListReducers {
|
||||
[ReducerMethod(typeof(FetchContainerListAction))]
|
||||
public static RootState OnFetchContainerList(RootState state) {
|
||||
return state with {
|
||||
ContainerListState = state.ContainerListState with {
|
||||
Containers = ImmutableList<BookmarkContainerDto>.Empty,
|
||||
IsLoadingContainersList = true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod]
|
||||
public static RootState OnRecievedContainerList(RootState state,
|
||||
RecievedContainerListAction action) {
|
||||
return state with {
|
||||
ContainerListState = state.ContainerListState with {
|
||||
Containers = action.Containers.ToImmutableList(),
|
||||
IsLoadingContainersList = false,
|
||||
ErrorMessage = null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod]
|
||||
public static RootState OnErrorFetchingContainerList(RootState state,
|
||||
ErrorFetchingContainerListAction action) {
|
||||
return state with {
|
||||
ContainerListState = state.ContainerListState with {
|
||||
ErrorMessage = action.ErrorMessage
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod]
|
||||
public static RootState AddContainerToList(RootState state,
|
||||
AddContainerToListAction action) {
|
||||
return state with {
|
||||
ContainerListState = state.ContainerListState with {
|
||||
Containers = state.ContainerListState.Containers.Add(action.NewContainer)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod]
|
||||
public static RootState RemoveContainerFromList(RootState state,
|
||||
RemoveContainerFromListAction action) {
|
||||
return state with {
|
||||
ContainerListState = state.ContainerListState with {
|
||||
Containers = state.ContainerListState.Containers
|
||||
.Where(c => c.BookmarkContainerId != action.ContainerIdToRemove)
|
||||
.ToImmutableList()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using Start.Shared;
|
||||
|
||||
namespace Start.Client.Store.Features.CreateContainer {
|
||||
public class ShowCreateContainerFormAction { }
|
||||
|
||||
public class HideCreateContainerFormAction { }
|
||||
|
||||
public class FetchCreateContainerAction { }
|
||||
|
||||
public class ReceivedCreateContainerAction { }
|
||||
|
||||
public class ErrorFetchingCreateContainerAction {
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public ErrorFetchingCreateContainerAction(string errorMessage) {
|
||||
this.ErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public class SubmitCreateContainerAction {
|
||||
public BookmarkContainerDto NewContainer { get; set; }
|
||||
|
||||
public SubmitCreateContainerAction(BookmarkContainerDto container) {
|
||||
this.NewContainer = container;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System.Threading.Tasks;
|
||||
using Fluxor;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
using Refit;
|
||||
using Start.Shared;
|
||||
using Start.Shared.Api;
|
||||
using Start.Client.Store.Features.CurrentContainer;
|
||||
using Start.Client.Store.Features.ContainersList;
|
||||
|
||||
namespace Start.Client.Store.Features.CreateContainer {
|
||||
public class CreateContainerEffects {
|
||||
public IBookmarkContainersApi BookmarkContainersApi { get; set; }
|
||||
|
||||
public CreateContainerEffects(IBookmarkContainersApi bookmarkContainersApi) {
|
||||
this.BookmarkContainersApi = bookmarkContainersApi;
|
||||
}
|
||||
|
||||
[EffectMethod]
|
||||
public async Task SubmitCreateContainer(SubmitCreateContainerAction action,
|
||||
IDispatcher dispatch) {
|
||||
dispatch.Dispatch(new FetchCreateContainerAction());
|
||||
|
||||
try {
|
||||
ApiResponse<BookmarkContainerDto?> apiResponse = await this.BookmarkContainersApi
|
||||
.CreateBookmarkContainer(action.NewContainer.Title);
|
||||
|
||||
BookmarkContainerDto? container = apiResponse.Content;
|
||||
|
||||
if (container == null)
|
||||
dispatch.Dispatch(new ErrorFetchingCreateContainerAction(
|
||||
"Failed to create container"));
|
||||
else {
|
||||
dispatch.Dispatch(new AddContainerToListAction(container));
|
||||
dispatch.Dispatch(new ReceivedCreateContainerAction());
|
||||
dispatch.Dispatch(new LoadCurrentContainerAction(
|
||||
container.BookmarkContainerId));
|
||||
}
|
||||
} catch (AccessTokenNotAvailableException e) {
|
||||
e.Redirect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using Fluxor;
|
||||
using Start.Client.Store.State;
|
||||
|
||||
namespace Start.Client.Store.Features.CreateContainer {
|
||||
public class CreateContainerFeature : Feature<CreateContainerState> {
|
||||
public override string GetName() => "Create Container";
|
||||
|
||||
protected override CreateContainerState GetInitialState() {
|
||||
return new CreateContainerState();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using Fluxor;
|
||||
|
||||
namespace Start.Client.Store.Features.CreateContainer {
|
||||
public static class CreateContainerReducers {
|
||||
[ReducerMethod(typeof(ShowCreateContainerFormAction))]
|
||||
public static CreateContainerState ShowCreateContainerForm(CreateContainerState state) {
|
||||
return state with {
|
||||
ShowCreateContainerForm = true
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod(typeof(HideCreateContainerFormAction))]
|
||||
public static CreateContainerState HideCreateContainerForm(CreateContainerState state) {
|
||||
return state with {
|
||||
ShowCreateContainerForm = false
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod(typeof(FetchCreateContainerAction))]
|
||||
public static CreateContainerState FetchCreateContainer(CreateContainerState state) {
|
||||
return state with {
|
||||
IsLoadingCreateContainer = true
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod(typeof(ReceivedCreateContainerAction))]
|
||||
public static CreateContainerState ReceivedCreateContainer(CreateContainerState state) {
|
||||
return state with {
|
||||
IsLoadingCreateContainer = false,
|
||||
CreateContainerErrorMessage = null,
|
||||
ShowCreateContainerForm = false
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod]
|
||||
public static CreateContainerState ErrorFetchingCreateContainer(CreateContainerState state,
|
||||
ErrorFetchingCreateContainerAction action) {
|
||||
return state with {
|
||||
IsLoadingCreateContainer = false,
|
||||
CreateContainerErrorMessage = action.ErrorMessage
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using Start.Client.Store.State;
|
||||
|
||||
namespace Start.Client.Store.Features.CreateContainer {
|
||||
public record CreateContainerState : RootState {
|
||||
public bool ShowCreateContainerForm { get; init; }
|
||||
public bool IsLoadingCreateContainer { get; init; }
|
||||
public string? CreateContainerErrorMessage { get; init; }
|
||||
|
||||
public CreateContainerState() { }
|
||||
|
||||
public CreateContainerState(ContainerListState containerList,
|
||||
CurrentContainerState currentContainer, bool showCreateContainer, bool isLoading,
|
||||
string? errorMessage)
|
||||
: base(containerList, currentContainer) {
|
||||
this.ShowCreateContainerForm = showCreateContainer;
|
||||
this.IsLoadingCreateContainer = isLoading;
|
||||
this.CreateContainerErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using Start.Shared;
|
||||
|
||||
namespace Start.Client.Store.Features.CurrentContainer {
|
||||
public class FetchCurrentContainerAction { }
|
||||
|
||||
public class ReceivedCurrentContainerAction {
|
||||
public BookmarkContainerDto BookmarkContainer { get; init; }
|
||||
|
||||
public ReceivedCurrentContainerAction(BookmarkContainerDto bookmarkContainer) {
|
||||
this.BookmarkContainer = bookmarkContainer;
|
||||
}
|
||||
}
|
||||
|
||||
public class ErrorFetchingCurrentContainerAction {
|
||||
public string ErrorMessage { get; init; }
|
||||
|
||||
public ErrorFetchingCurrentContainerAction(string errorMessage) {
|
||||
this.ErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public class LoadCurrentContainerAction {
|
||||
public int BookmarkContainerId { get; init; }
|
||||
|
||||
public LoadCurrentContainerAction(int bookmarkContainerId) {
|
||||
this.BookmarkContainerId = bookmarkContainerId;
|
||||
}
|
||||
}
|
||||
|
||||
public class FixCurrentContainerAction { }
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Blazored.LocalStorage;
|
||||
using Fluxor;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
using Refit;
|
||||
using Start.Client.Store.State;
|
||||
using Start.Client.Store.Features.CreateContainer;
|
||||
using Start.Shared;
|
||||
using Start.Shared.Api;
|
||||
|
||||
namespace Start.Client.Store.Features.CurrentContainer {
|
||||
public class CurrentContainerEffects {
|
||||
public IBookmarkContainersApi BookmarkContainersApi { get; set; }
|
||||
public ILocalStorageService LocalStorage { get; set; }
|
||||
public IState<RootState> RootState { get; set; }
|
||||
|
||||
public CurrentContainerEffects(IBookmarkContainersApi bookmarkContainersApi,
|
||||
ILocalStorageService localStorage, IState<RootState> rootState) {
|
||||
this.BookmarkContainersApi = bookmarkContainersApi;
|
||||
this.LocalStorage = localStorage;
|
||||
this.RootState = rootState;
|
||||
}
|
||||
|
||||
[EffectMethod]
|
||||
public async Task LoadCurrentContainer(LoadCurrentContainerAction action,
|
||||
IDispatcher dispatch) {
|
||||
dispatch.Dispatch(new FetchCurrentContainerAction());
|
||||
|
||||
try {
|
||||
ApiResponse<BookmarkContainerDto?> response = await this.BookmarkContainersApi
|
||||
.GetBookmarkContainer(action.BookmarkContainerId);
|
||||
|
||||
BookmarkContainerDto? container = response.Content;
|
||||
|
||||
if (container == null) {
|
||||
dispatch.Dispatch(new ErrorFetchingCurrentContainerAction(
|
||||
"Failed to get current bookmark container"));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch.Dispatch(new ReceivedCurrentContainerAction(container));
|
||||
|
||||
await this.LocalStorage
|
||||
.SetItemAsync("SelectedContainer", action.BookmarkContainerId);
|
||||
} catch (AccessTokenNotAvailableException e) {
|
||||
e.Redirect();
|
||||
}
|
||||
}
|
||||
|
||||
[EffectMethod(typeof(FixCurrentContainerAction))]
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
public async Task FixCurrentContainer(IDispatcher dispatch) {
|
||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
if (!this.RootState.Value.ContainerListState.Containers.Any()) {
|
||||
dispatch.Dispatch(new SubmitCreateContainerAction(
|
||||
new BookmarkContainerDto("Default")));
|
||||
return;
|
||||
}
|
||||
|
||||
IEnumerable<int?> containerIds = this.RootState.Value.ContainerListState.Containers
|
||||
.Select(c => (int?)c.BookmarkContainerId);
|
||||
int? currentContainerId = this.RootState.Value.CurrentContainerState.Container
|
||||
?.BookmarkContainerId;
|
||||
|
||||
if (containerIds.Contains(currentContainerId))
|
||||
return;
|
||||
|
||||
int firstContainerId = this.RootState.Value.ContainerListState.Containers
|
||||
.First().BookmarkContainerId;
|
||||
|
||||
dispatch.Dispatch(new LoadCurrentContainerAction(firstContainerId));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using Fluxor;
|
||||
using Start.Client.Store.State;
|
||||
|
||||
namespace Start.Client.Store.Features.CurrentContainer {
|
||||
public static class CurrentContainerReducers {
|
||||
[ReducerMethod(typeof(FetchCurrentContainerAction))]
|
||||
public static RootState FetchCurrentContainer(RootState state) {
|
||||
return state with {
|
||||
CurrentContainerState = state.CurrentContainerState with {
|
||||
Container = null,
|
||||
IsLoadingCurrentContainer = true,
|
||||
ErrorMessage = null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod]
|
||||
public static RootState ReceivedCurrentContainer(RootState state,
|
||||
ReceivedCurrentContainerAction action) {
|
||||
return state with {
|
||||
CurrentContainerState = state.CurrentContainerState with {
|
||||
Container = action.BookmarkContainer,
|
||||
IsLoadingCurrentContainer = false,
|
||||
ErrorMessage = null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod]
|
||||
public static RootState ErrorFetchingCurrentContainer(RootState state,
|
||||
ErrorFetchingCurrentContainerAction action) {
|
||||
return state with {
|
||||
CurrentContainerState = state.CurrentContainerState with {
|
||||
Container = null,
|
||||
IsLoadingCurrentContainer = false,
|
||||
ErrorMessage = action.ErrorMessage
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
namespace Start.Client.Store.Features.DeleteContainer {
|
||||
public class ShowDeleteContainerFormAction {
|
||||
public int ContainerIdToDelete { get; init; }
|
||||
public string ContainerTitleToDelete { get; init; }
|
||||
|
||||
public ShowDeleteContainerFormAction(int containerIdToDelete,
|
||||
string containerTitleToDelete) {
|
||||
this.ContainerIdToDelete = containerIdToDelete;
|
||||
this.ContainerTitleToDelete = containerTitleToDelete;
|
||||
}
|
||||
}
|
||||
|
||||
public class HideDeleteContainerFormAction { }
|
||||
|
||||
public class FetchDeleteContainerFormAction { }
|
||||
|
||||
public class SubmitDeleteContainerAction {
|
||||
public int ContainerIdToDelete { get; init; }
|
||||
|
||||
public SubmitDeleteContainerAction(int containerIdToDelete) {
|
||||
this.ContainerIdToDelete = containerIdToDelete;
|
||||
}
|
||||
}
|
||||
|
||||
public class RecievedDeleteContainerAction { }
|
||||
|
||||
public class ErrorFetchingDeleteContainerAction {
|
||||
public string ErrorMessage { get; init; }
|
||||
|
||||
public ErrorFetchingDeleteContainerAction(string errorMessage) {
|
||||
this.ErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System.Threading.Tasks;
|
||||
using Fluxor;
|
||||
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) {
|
||||
this.BookmarkContainersApi = bookmarkContainersApi;
|
||||
this.RootState = rootState;
|
||||
}
|
||||
|
||||
[EffectMethod]
|
||||
public async Task SubmitDeleteContainer(SubmitDeleteContainerAction action,
|
||||
IDispatcher dispatch) {
|
||||
dispatch.Dispatch(new FetchDeleteContainerFormAction());
|
||||
|
||||
try {
|
||||
System.Net.Http.HttpResponseMessage? apiResponse = await this.BookmarkContainersApi
|
||||
.DeleteBookmarkContainer(action.ContainerIdToDelete);
|
||||
|
||||
if (apiResponse == null) {
|
||||
dispatch.Dispatch(
|
||||
new ErrorFetchingDeleteContainerAction("Failed to submit request"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (apiResponse.StatusCode == HttpStatusCode.NotFound) {
|
||||
dispatch.Dispatch(new ErrorFetchingDeleteContainerAction(
|
||||
"The bookmark container to delete doesn't exist"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!apiResponse.IsSuccessStatusCode) {
|
||||
dispatch.Dispatch(new ErrorFetchingDeleteContainerAction(
|
||||
"There was an error deleting the bookmark container"));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch.Dispatch(new RemoveContainerFromListAction(action.ContainerIdToDelete));
|
||||
dispatch.Dispatch(new FixCurrentContainerAction());
|
||||
dispatch.Dispatch(new RecievedDeleteContainerAction());
|
||||
} catch (AccessTokenNotAvailableException e) {
|
||||
e.Redirect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using Fluxor;
|
||||
|
||||
namespace Start.Client.Store.Features.DeleteContainer {
|
||||
public class DeleteContainerFeature : Feature<DeleteContainerState> {
|
||||
public override string GetName() => "Delete Container";
|
||||
|
||||
protected override DeleteContainerState GetInitialState() {
|
||||
return new DeleteContainerState();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using Fluxor;
|
||||
|
||||
namespace Start.Client.Store.Features.DeleteContainer {
|
||||
public static class DeleteContainerReducers {
|
||||
[ReducerMethod]
|
||||
public static DeleteContainerState ShowDeleteContainerForm(DeleteContainerState state,
|
||||
ShowDeleteContainerFormAction action) {
|
||||
return state with {
|
||||
ShowDeleteContainerForm = true,
|
||||
BookmarkContainerIdToDelete = action.ContainerIdToDelete,
|
||||
BookmarkContainerTitleToDelete = action.ContainerTitleToDelete,
|
||||
DeleteContainerErrorMessage = null
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod(typeof(HideDeleteContainerFormAction))]
|
||||
public static DeleteContainerState HideDeleteContainerForm(DeleteContainerState state) {
|
||||
return state with {
|
||||
ShowDeleteContainerForm = false,
|
||||
DeleteContainerErrorMessage = null
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod(typeof(FetchDeleteContainerFormAction))]
|
||||
public static DeleteContainerState FetchDeleteContainerForm(DeleteContainerState state) {
|
||||
return state with {
|
||||
IsLoadingDeleteContainer = true,
|
||||
DeleteContainerErrorMessage = null
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod(typeof(RecievedDeleteContainerAction))]
|
||||
public static DeleteContainerState ReceivedDeleteContainer(DeleteContainerState state) {
|
||||
return state with {
|
||||
IsLoadingDeleteContainer = false,
|
||||
DeleteContainerErrorMessage = null,
|
||||
ShowDeleteContainerForm = false
|
||||
};
|
||||
}
|
||||
|
||||
[ReducerMethod]
|
||||
public static DeleteContainerState ErrorFetchingDeleteContainer(DeleteContainerState state,
|
||||
ErrorFetchingDeleteContainerAction action) {
|
||||
return state with {
|
||||
DeleteContainerErrorMessage = action.ErrorMessage,
|
||||
IsLoadingDeleteContainer = false
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using Start.Client.Store.State;
|
||||
|
||||
namespace Start.Client.Store.Features.DeleteContainer {
|
||||
public record DeleteContainerState : RootState {
|
||||
public bool ShowDeleteContainerForm { get; set; }
|
||||
public int BookmarkContainerIdToDelete { get; set; }
|
||||
public string BookmarkContainerTitleToDelete { get; set; }
|
||||
public bool IsLoadingDeleteContainer { get; set; }
|
||||
public string? DeleteContainerErrorMessage { get; set; }
|
||||
|
||||
public DeleteContainerState() {
|
||||
this.BookmarkContainerIdToDelete = 0;
|
||||
this.BookmarkContainerTitleToDelete = "";
|
||||
}
|
||||
|
||||
public DeleteContainerState(ContainerListState containerList,
|
||||
CurrentContainerState currentContainer, bool showDeleteContainerForm,
|
||||
int containerIdToDelete, string containerTitleToDelete, bool isLoadingDeleteContainer,
|
||||
string? errorMessage)
|
||||
: base(containerList, currentContainer) {
|
||||
this.ShowDeleteContainerForm = showDeleteContainerForm;
|
||||
this.BookmarkContainerIdToDelete = containerIdToDelete;
|
||||
this.BookmarkContainerTitleToDelete = containerTitleToDelete;
|
||||
this.IsLoadingDeleteContainer = isLoadingDeleteContainer;
|
||||
this.DeleteContainerErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
}
|
59
Start/Client/Store/State/RootState.cs
Normal file
59
Start/Client/Store/State/RootState.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System.Collections.Immutable;
|
||||
using Fluxor;
|
||||
using Start.Shared;
|
||||
|
||||
namespace Start.Client.Store.State {
|
||||
[FeatureState]
|
||||
public record RootState {
|
||||
public ContainerListState ContainerListState { get; init; }
|
||||
public CurrentContainerState CurrentContainerState { get; init; }
|
||||
|
||||
public RootState() {
|
||||
this.ContainerListState = new ContainerListState();
|
||||
this.CurrentContainerState = new CurrentContainerState();
|
||||
}
|
||||
|
||||
public RootState(ContainerListState containerList, CurrentContainerState currentContainer) {
|
||||
this.ContainerListState = containerList;
|
||||
this.CurrentContainerState = currentContainer;
|
||||
}
|
||||
}
|
||||
|
||||
public record ContainerListState {
|
||||
public ImmutableList<BookmarkContainerDto> Containers { get; init; }
|
||||
public bool IsLoadingContainersList { get; init; }
|
||||
public string? ErrorMessage { get; init; }
|
||||
|
||||
public ContainerListState() {
|
||||
this.Containers = ImmutableList<BookmarkContainerDto>.Empty;
|
||||
this.IsLoadingContainersList = false;
|
||||
this.ErrorMessage = null;
|
||||
}
|
||||
|
||||
public ContainerListState(ImmutableList<BookmarkContainerDto> containers,
|
||||
bool isLoadingContainersList, string? errorMessage) {
|
||||
this.Containers = containers;
|
||||
this.IsLoadingContainersList = isLoadingContainersList;
|
||||
this.ErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public record CurrentContainerState {
|
||||
public BookmarkContainerDto? Container { get; init; }
|
||||
public bool IsLoadingCurrentContainer { get; init; }
|
||||
public string? ErrorMessage { get; init; }
|
||||
|
||||
public CurrentContainerState() {
|
||||
this.Container = null;
|
||||
this.IsLoadingCurrentContainer = false;
|
||||
this.ErrorMessage = null;
|
||||
}
|
||||
|
||||
public CurrentContainerState(BookmarkContainerDto? currentContainer,
|
||||
bool isLoadingCurrentContainer, string? errorMessage) {
|
||||
this.Container = currentContainer;
|
||||
this.IsLoadingCurrentContainer = isLoadingCurrentContainer;
|
||||
this.ErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,3 +9,4 @@
|
|||
@using Microsoft.JSInterop
|
||||
@using Start.Client
|
||||
@using Start.Client.Shared
|
||||
@using Start.Shared;
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>Start</title>
|
||||
<base href="/" />
|
||||
|
||||
<script src="_content/Fluxor.Blazor.Web/scripts/index.js"></script>
|
||||
|
||||
<!--<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />-->
|
||||
<link href="css/spectre/spectre.min.css" rel="stylesheet" />
|
||||
<link href="css/spectre/spectre-icons.css" rel="stylesheet" />
|
||||
<link href="css/app.css" rel="stylesheet" />
|
||||
<link href="Start.Client.styles.css" rel="stylesheet" />
|
||||
|
||||
<link href="manifest.json" rel="manifest" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" />
|
||||
</head>
|
||||
|
|
Loading…
Reference in a new issue