diff --git a/MoneyMap/Pages/Cards.cshtml b/MoneyMap/Pages/Cards.cshtml
new file mode 100644
index 0000000..1f8b42d
--- /dev/null
+++ b/MoneyMap/Pages/Cards.cshtml
@@ -0,0 +1,93 @@
+@page
+@model MoneyMap.Pages.CardsModel
+@{
+ ViewData["Title"] = "Manage Cards";
+}
+
+
+
+@if (!string.IsNullOrEmpty(Model.SuccessMessage))
+{
+
+ @Model.SuccessMessage
+
+
+}
+
+@if (!string.IsNullOrEmpty(Model.ErrorMessage))
+{
+
+ @Model.ErrorMessage
+
+
+}
+
+@if (Model.Cards.Any())
+{
+
+
+
+
+
+
+
+ | Owner |
+ Issuer |
+ Last 4 |
+ Transactions |
+ Actions |
+
+
+
+ @foreach (var item in Model.Cards)
+ {
+
+ | @item.Card.Owner |
+ @item.Card.Issuer |
+ •••• @item.Card.Last4 |
+ @item.TransactionCount |
+
+
+
+ Edit
+
+ @if (item.TransactionCount == 0)
+ {
+
+ }
+ else
+ {
+
+ }
+
+ |
+
+ }
+
+
+
+
+
+}
+else
+{
+
+
No cards found
+
Add your first card to start tracking transactions.
+
Add New Card
+
+}
\ No newline at end of file
diff --git a/MoneyMap/Pages/Cards.cshtml.cs b/MoneyMap/Pages/Cards.cshtml.cs
new file mode 100644
index 0000000..a75ddb0
--- /dev/null
+++ b/MoneyMap/Pages/Cards.cshtml.cs
@@ -0,0 +1,81 @@
+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 CardsModel : PageModel
+ {
+ private readonly MoneyMapContext _db;
+
+ public CardsModel(MoneyMapContext db)
+ {
+ _db = db;
+ }
+
+ public List Cards { get; set; } = new();
+
+ [TempData]
+ public string? SuccessMessage { get; set; }
+
+ [TempData]
+ public string? ErrorMessage { get; set; }
+
+ public async Task OnGetAsync()
+ {
+ var cards = await _db.Cards
+ .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;
+ }
+
+ public async Task OnPostDeleteAsync(int id)
+ {
+ var card = await _db.Cards.FindAsync(id);
+ if (card == null)
+ {
+ ErrorMessage = "Card not found.";
+ return RedirectToPage();
+ }
+
+ 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();
+ }
+
+ _db.Cards.Remove(card);
+ await _db.SaveChangesAsync();
+
+ SuccessMessage = "Card deleted successfully.";
+ return RedirectToPage();
+ }
+
+ public class CardWithStats
+ {
+ public Card Card { get; set; } = null!;
+ public int TransactionCount { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/MoneyMap/Pages/EditCard.cshtml b/MoneyMap/Pages/EditCard.cshtml
new file mode 100644
index 0000000..cc12bfe
--- /dev/null
+++ b/MoneyMap/Pages/EditCard.cshtml
@@ -0,0 +1,81 @@
+@page
+@model MoneyMap.Pages.EditCardModel
+@{
+ ViewData["Title"] = Model.IsNewCard ? "Add Card" : "Edit Card";
+}
+
+
+
@(Model.IsNewCard ? "Add Card" : "Edit Card")
+
Back to Cards
+
+
+
+
+
+
+
+
+
+
+ - Owner: Use the cardholder's name for easy identification
+ - Issuer: The bank or credit card company (e.g., Chase, Discover, Capital One)
+ - Last 4: These digits help match transactions to the correct card
+ - Cards with transactions cannot be deleted, only edited
+ - Auto-imported cards will have "Unknown" as the owner - update them here
+
+
+
+
+ @if (!Model.IsNewCard)
+ {
+
+ Note: Updating card details will not affect existing transactions, but will change how the card is displayed going forward.
+
+ }
+
+
+
+@section Scripts {
+
+}
\ No newline at end of file
diff --git a/MoneyMap/Pages/EditCard.cshtml.cs b/MoneyMap/Pages/EditCard.cshtml.cs
new file mode 100644
index 0000000..c17d3e0
--- /dev/null
+++ b/MoneyMap/Pages/EditCard.cshtml.cs
@@ -0,0 +1,111 @@
+using System.ComponentModel.DataAnnotations;
+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 EditCardModel : PageModel
+ {
+ private readonly MoneyMapContext _db;
+
+ public EditCardModel(MoneyMapContext db)
+ {
+ _db = db;
+ }
+
+ [BindProperty]
+ public CardEditModel Card { get; set; } = new();
+
+ public bool IsNewCard { get; set; }
+
+ [TempData]
+ public string? SuccessMessage { get; set; }
+
+ public async Task OnGetAsync(int? id)
+ {
+ if (id.HasValue)
+ {
+ var card = await _db.Cards.FindAsync(id.Value);
+ if (card == null)
+ return NotFound();
+
+ Card = new CardEditModel
+ {
+ Id = card.Id,
+ Owner = card.Owner,
+ Issuer = card.Issuer,
+ Last4 = card.Last4
+ };
+
+ IsNewCard = false;
+ }
+ else
+ {
+ IsNewCard = true;
+ }
+
+ return Page();
+ }
+
+ public async Task OnPostAsync()
+ {
+ if (!ModelState.IsValid)
+ {
+ IsNewCard = Card.Id == 0;
+ return Page();
+ }
+
+ if (Card.Id == 0)
+ {
+ // Create new card
+ var card = new Card
+ {
+ Owner = Card.Owner.Trim(),
+ Issuer = Card.Issuer.Trim(),
+ Last4 = Card.Last4.Trim()
+ };
+
+ _db.Cards.Add(card);
+ SuccessMessage = "Card added successfully!";
+ }
+ else
+ {
+ // Update existing card
+ var card = await _db.Cards.FindAsync(Card.Id);
+ if (card == null)
+ return NotFound();
+
+ card.Owner = Card.Owner.Trim();
+ card.Issuer = Card.Issuer.Trim();
+ card.Last4 = Card.Last4.Trim();
+
+ SuccessMessage = "Card updated successfully!";
+ }
+
+ await _db.SaveChangesAsync();
+ return RedirectToPage("/Cards");
+ }
+
+ public class CardEditModel
+ {
+ public int Id { get; set; }
+
+ [Required(ErrorMessage = "Owner is required")]
+ [StringLength(100)]
+ public string Owner { get; set; } = "";
+
+ [Required(ErrorMessage = "Issuer is required")]
+ [StringLength(100)]
+ public string Issuer { get; set; } = "";
+
+ [Required(ErrorMessage = "Last 4 digits are required")]
+ [StringLength(4, MinimumLength = 4, ErrorMessage = "Last 4 must be exactly 4 digits")]
+ [RegularExpression(@"^\d{4}$", ErrorMessage = "Last 4 must be 4 digits")]
+ public string Last4 { get; set; } = "";
+ }
+ }
+}
\ No newline at end of file
diff --git a/MoneyMap/Pages/Shared/_Layout.cshtml b/MoneyMap/Pages/Shared/_Layout.cshtml
index 5adcfdd..8764ecc 100644
--- a/MoneyMap/Pages/Shared/_Layout.cshtml
+++ b/MoneyMap/Pages/Shared/_Layout.cshtml
@@ -25,6 +25,9 @@
Transactions
+
+ Cards
+
Upload CSV