From e0dabdc46df612aec7847c9e0af97a8df2d119ba Mon Sep 17 00:00:00 2001 From: AJ Date: Sat, 11 Oct 2025 22:30:05 -0400 Subject: [PATCH] Add account details page with card management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a new AccountDetails page that shows account information and all linked cards. This replaces the standalone Cards page and nests card management under accounts, as cards are always linked to accounts. Features: - View account details (institution, type, owner, etc.) - List all cards linked to the account - Add new cards directly from the account page - Edit and delete cards within the account context - Click-through navigation from Accounts list 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- MoneyMap/Pages/AccountDetails.cshtml | 136 ++++++++++++++++++++++++ MoneyMap/Pages/AccountDetails.cshtml.cs | 96 +++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 MoneyMap/Pages/AccountDetails.cshtml create mode 100644 MoneyMap/Pages/AccountDetails.cshtml.cs diff --git a/MoneyMap/Pages/AccountDetails.cshtml b/MoneyMap/Pages/AccountDetails.cshtml new file mode 100644 index 0000000..5979047 --- /dev/null +++ b/MoneyMap/Pages/AccountDetails.cshtml @@ -0,0 +1,136 @@ +@page "{id:int}" +@model MoneyMap.Pages.AccountDetailsModel +@{ + ViewData["Title"] = $"Account - {Model.Account.DisplayLabel}"; +} + +
+

@Model.Account.DisplayLabel

+
+ Edit Account + Back to Accounts +
+
+ +@if (!string.IsNullOrEmpty(Model.SuccessMessage)) +{ + +} + +@if (!string.IsNullOrEmpty(Model.ErrorMessage)) +{ + +} + + +
+
+ Account Details +
+
+
+
+
+
Institution:
+
@Model.Account.Institution
+ +
Account Type:
+
@Model.Account.AccountType
+ +
Last 4:
+
@Model.Account.Last4
+
+
+
+
+
Owner:
+
@Model.Account.Owner
+ +
Nickname:
+
@(string.IsNullOrEmpty(Model.Account.Nickname) ? "-" : Model.Account.Nickname)
+ +
Transactions:
+
@Model.TransactionCount
+
+
+
+
+
+ + +
+
+ Linked Cards (@Model.Cards.Count) + + Add Card +
+
+ @if (Model.Cards.Any()) + { +
+ + + + + + + + + + + @foreach (var item in Model.Cards) + { + + + + + + + } + +
CardOwnerTransactionsActions
+
+ @item.Card.Issuer •••• @item.Card.Last4 + @if (!string.IsNullOrEmpty(item.Card.Nickname)) + { +
+ @item.Card.Nickname + } +
+
@item.Card.Owner@item.TransactionCount +
+ + Edit + + @if (item.TransactionCount == 0) + { +
+ +
+ } + else + { + + } +
+
+
+ } + else + { +
+

No cards linked to this account yet.

+ Add First Card +
+ } +
+
diff --git a/MoneyMap/Pages/AccountDetails.cshtml.cs b/MoneyMap/Pages/AccountDetails.cshtml.cs new file mode 100644 index 0000000..b4ec6c0 --- /dev/null +++ b/MoneyMap/Pages/AccountDetails.cshtml.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.EntityFrameworkCore; +using MoneyMap.Data; +using MoneyMap.Models; + +namespace MoneyMap.Pages +{ + public class AccountDetailsModel : PageModel + { + private readonly MoneyMapContext _db; + + public AccountDetailsModel(MoneyMapContext db) + { + _db = db; + } + + public Account Account { get; set; } = null!; + public List Cards { get; set; } = new(); + public int TransactionCount { get; set; } + + [TempData] + public string? SuccessMessage { get; set; } + + [TempData] + public string? ErrorMessage { get; set; } + + public async Task OnGetAsync(int id) + { + var account = await _db.Accounts.FindAsync(id); + if (account == null) + return NotFound(); + + Account = account; + + // Get cards linked to this account + var cards = await _db.Cards + .Where(c => c.AccountId == id) + .OrderBy(c => c.Owner) + .ThenBy(c => c.Last4) + .ToListAsync(); + + var cardStats = new List(); + foreach (var card in cards) + { + var transactionCount = await _db.Transactions.CountAsync(t => t.CardId == card.Id); + cardStats.Add(new CardWithStats + { + Card = card, + TransactionCount = transactionCount + }); + } + + Cards = cardStats; + + // Get transaction count for this account + TransactionCount = await _db.Transactions.CountAsync(t => t.AccountId == id); + + return Page(); + } + + public async Task OnPostDeleteCardAsync(int cardId) + { + var card = await _db.Cards.FindAsync(cardId); + if (card == null) + { + ErrorMessage = "Card not found."; + return RedirectToPage(new { id = card?.AccountId }); + } + + var accountId = card.AccountId; + + var transactionCount = await _db.Transactions.CountAsync(t => t.CardId == card.Id); + if (transactionCount > 0) + { + ErrorMessage = $"Cannot delete card. It has {transactionCount} transaction(s) associated with it."; + return RedirectToPage(new { id = accountId }); + } + + _db.Cards.Remove(card); + await _db.SaveChangesAsync(); + + SuccessMessage = "Card deleted successfully."; + return RedirectToPage(new { id = accountId }); + } + + public class CardWithStats + { + public Card Card { get; set; } = null!; + public int TransactionCount { get; set; } + } + } +}