Skip to content
Open
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
14 changes: 14 additions & 0 deletions Coronado.Web/BlazorApp/BlazorApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>BlazorApp</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.0" />
<PackageReference Include="MudBlazor" Version="8.5.0" />
</ItemGroup>

</Project>
63 changes: 63 additions & 0 deletions Coronado.Web/BlazorApp/Pages/AccountPage.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
@page "/account"
@using Coronado.Web.Controllers.Api
@using Coronado.Web.Controllers.Dtos
@inject HttpClient Http
@inject NavigationManager Navigation
@inject ISnackbar Snackbar

<MudContainer MaxWidth="MaxWidth.Medium" Class="mt-4">
<MudPaper Class="pa-4">
<MudText Typo="Typo.h4">Accounts</MudText>
<MudTable Items="_accounts" Hover="true" Bordered="true" Striped="true">
<HeaderContent>
<MudTh>Account Name</MudTh>
<MudTh>Current Balance</MudTh>
<MudTh>Currency</MudTh>
<MudTh>Actions</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Account Name">@context.Name</MudTd>
<MudTd DataLabel="Current Balance">@context.CurrentBalance</MudTd>
<MudTd DataLabel="Currency">@context.Currency</MudTd>
<MudTd DataLabel="Actions">
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="() => EditAccount(context)">Edit</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Error" OnClick="() => DeleteAccount(context.AccountId)">Delete</MudButton>
</MudTd>
</RowTemplate>
</MudTable>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="AddAccount">Add Account</MudButton>
</MudPaper>
</MudContainer>

@code {
private List<AccountWithBalance> _accounts = new List<AccountWithBalance>();

protected override async Task OnInitializedAsync()
{
_accounts = await Http.GetFromJsonAsync<List<AccountWithBalance>>("api/accounts");
}

private void AddAccount()
{
Navigation.NavigateTo("/add-account");
}

private void EditAccount(AccountWithBalance account)
{
Navigation.NavigateTo($"/edit-account/{account.AccountId}");
}

private async Task DeleteAccount(Guid accountId)
{
var response = await Http.DeleteAsync($"api/accounts/{accountId}");
if (response.IsSuccessStatusCode)
{
Snackbar.Add("Account deleted successfully", Severity.Success);
_accounts = await Http.GetFromJsonAsync<List<AccountWithBalance>>("api/accounts");
}
else
{
Snackbar.Add("Failed to delete account", Severity.Error);
}
}
}
110 changes: 110 additions & 0 deletions Coronado.Web/BlazorApp/Pages/CategoryPage.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
@page "/categories"
@using Coronado.Web.Controllers.Api
@inject HttpClient Http
@inject NavigationManager Navigation
@implements IDisposable

<PageTitle>Categories</PageTitle>

<MudText Typo="Typo.h4">Categories</MudText>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="AddCategory">Add Category</MudButton>

<MudTable Items="_categories" Hover="true" Bordered="true" Striped="true">
<HeaderContent>
<MudTh>Name</MudTh>
<MudTh>Type</MudTh>
<MudTh>Parent</MudTh>
<MudTh>Actions</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Name">@context.Name</MudTd>
<MudTd DataLabel="Type">@context.Type</MudTd>
<MudTd DataLabel="Parent">@GetParentCategoryName(context.ParentCategoryId)</MudTd>
<MudTd DataLabel="Actions">
<MudButton Variant="Variant.Outlined" Color="Color.Primary" OnClick="@(async () => await EditCategory(context))">Edit</MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Error" OnClick="@(async () => await DeleteCategory(context.CategoryId))">Delete</MudButton>
</MudTd>
</RowTemplate>
</MudTable>

<MudDialog @ref="_dialog" MaxWidth="MaxWidth.Small">
<DialogContent>
<MudText Typo="Typo.h6">@(_isNewCategory ? "Add Category" : "Edit Category")</MudText>
<MudTextField @bind-Value="_category.Name" Label="Name" Required="true" />
<MudTextField @bind-Value="_category.Type" Label="Type" Required="true" />
<MudSelect T="Guid?" @bind-Value="_category.ParentCategoryId" Label="Parent Category">
<MudSelectItem T="Guid?" Value="null">None</MudSelectItem>
@foreach (var parentCategory in _categories)
{
<MudSelectItem T="Guid?" Value="parentCategory.CategoryId">@parentCategory.Name</MudSelectItem>
}
</MudSelect>
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="SaveCategory">Save</MudButton>
<MudButton Variant="Variant.Outlined" OnClick="Cancel">Cancel</MudButton>
</DialogActions>
</MudDialog>

@code {
private List<Category> _categories;
private Category _category = new Category();
private bool _isNewCategory;
private MudDialogInstance _dialog;

protected override async Task OnInitializedAsync()
{
_categories = await Http.GetFromJsonAsync<List<Category>>("api/categories");
}

private void AddCategory()
{
_category = new Category();
_isNewCategory = true;
_dialog.Show();
}

private async Task EditCategory(Category category)
{
_category = category;
_isNewCategory = false;
_dialog.Show();
}

private async Task SaveCategory()
{
if (_isNewCategory)
{
await Http.PostAsJsonAsync("api/categories", _category);
}
else
{
await Http.PutAsJsonAsync($"api/categories/{_category.CategoryId}", _category);
}
_categories = await Http.GetFromJsonAsync<List<Category>>("api/categories");
_dialog.Hide();
}

private async Task DeleteCategory(Guid categoryId)
{
await Http.DeleteAsync($"api/categories/{categoryId}");
_categories = await Http.GetFromJsonAsync<List<Category>>("api/categories");
}

private void Cancel()
{
_dialog.Hide();
}

private string GetParentCategoryName(Guid? parentCategoryId)
{
if (parentCategoryId == null) return "None";
var parentCategory = _categories.FirstOrDefault(c => c.CategoryId == parentCategoryId);
return parentCategory?.Name ?? "None";
}

public void Dispose()
{
_dialog?.Dispose();
}
}
69 changes: 69 additions & 0 deletions Coronado.Web/BlazorApp/Pages/TransactionPage.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
@page "/transactions"
@using Coronado.Web.Controllers.Api
@using Coronado.Web.Controllers.Dtos
@inject HttpClient Http
@inject NavigationManager Navigation
@inject ISnackbar Snackbar

<MudContainer MaxWidth="MaxWidth.Medium" Class="mt-4">
<MudPaper Class="pa-4">
<MudText Typo="Typo.h4">Transactions</MudText>
<MudTable Items="_transactions" Hover="true" Bordered="true" Striped="true">
<HeaderContent>
<MudTh>Date</MudTh>
<MudTh>Vendor</MudTh>
<MudTh>Category</MudTh>
<MudTh>Description</MudTh>
<MudTh>Debit</MudTh>
<MudTh>Credit</MudTh>
<MudTh>Actions</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Date">@context.TransactionDate.ToShortDateString()</MudTd>
<MudTd DataLabel="Vendor">@context.Vendor</MudTd>
<MudTd DataLabel="Category">@context.CategoryDisplay</MudTd>
<MudTd DataLabel="Description">@context.Description</MudTd>
<MudTd DataLabel="Debit">@context.Debit</MudTd>
<MudTd DataLabel="Credit">@context.Credit</MudTd>
<MudTd DataLabel="Actions">
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="() => EditTransaction(context)">Edit</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Error" OnClick="() => DeleteTransaction(context.TransactionId)">Delete</MudButton>
</MudTd>
</RowTemplate>
</MudTable>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="AddTransaction">Add Transaction</MudButton>
</MudPaper>
</MudContainer>

@code {
private List<TransactionForDisplay> _transactions = new List<TransactionForDisplay>();

protected override async Task OnInitializedAsync()
{
_transactions = await Http.GetFromJsonAsync<List<TransactionForDisplay>>("api/transactions");
}

private void AddTransaction()
{
Navigation.NavigateTo("/add-transaction");
}

private void EditTransaction(TransactionForDisplay transaction)
{
Navigation.NavigateTo($"/edit-transaction/{transaction.TransactionId}");
}

private async Task DeleteTransaction(Guid transactionId)
{
var response = await Http.DeleteAsync($"api/transactions/{transactionId}");
if (response.IsSuccessStatusCode)
{
Snackbar.Add("Transaction deleted successfully", Severity.Success);
_transactions = await Http.GetFromJsonAsync<List<TransactionForDisplay>>("api/transactions");
}
else
{
Snackbar.Add("Failed to delete transaction", Severity.Error);
}
}
}
13 changes: 13 additions & 0 deletions Coronado.Web/BlazorApp/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using MudBlazor.Services;
using BlazorApp;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddMudServices();

await builder.Build().RunAsync();
20 changes: 20 additions & 0 deletions Coronado.Web/BlazorApp/Shared/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@inherits LayoutComponentBase

<MudLayout>
<MudAppBar Color="Color.Primary" Elevation="4">
<MudText Typo="Typo.h6">Coronado</MudText>
</MudAppBar>

<MudDrawer Open="true" ClipMode="DrawerClipMode.Always">
<MudNavMenu>
<MudNavLink Href="/" Match="NavLinkMatch.All">Home</MudNavLink>
<MudNavLink Href="/account">Accounts</MudNavLink>
<MudNavLink Href="/categories">Categories</MudNavLink>
<MudNavLink Href="/transactions">Transactions</MudNavLink>
</MudNavMenu>
</MudDrawer>

<MudMainContent>
@Body
</MudMainContent>
</MudLayout>
50 changes: 50 additions & 0 deletions Coronado.Web/BlazorApp/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MudBlazor.Services;

namespace BlazorApp
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddMudServices();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}
5 changes: 5 additions & 0 deletions Coronado.Web/Coronado.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
<PackageReference Include="SendGrid" Version="9.28.1" />
<PackageReference Include="System.Text.Json" Version="7.0.3" />
<PackageReference Include="MudBlazor" Version="5.1.5" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BlazorApp\BlazorApp.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
7 changes: 7 additions & 0 deletions Coronado.Web/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Coronado.Web.Controllers.Api;
using MudBlazor.Services;

namespace Coronado.Web
{
Expand Down Expand Up @@ -86,6 +87,10 @@ public void ConfigureServices(IServiceCollection services) {
services.AddMvc().AddNewtonsoftJson(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

services.AddRazorPages();
services.AddServerSideBlazor();
services.AddMudServices();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
Expand Down Expand Up @@ -116,6 +121,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
endpoints.MapControllerRoute(
name:"admin",
pattern: "/admin/{controller=Home}/{action=Index}/{id?}");
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
app.UseSpa(spa => {
spa.Options.SourcePath = "ClientApp";
Expand Down