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"; +} + +
+

Manage Cards

+
+ Add New Card + Back to Dashboard +
+
+ +@if (!string.IsNullOrEmpty(Model.SuccessMessage)) +{ + +} + +@if (!string.IsNullOrEmpty(Model.ErrorMessage)) +{ + +} + +@if (Model.Cards.Any()) +{ +
+
+ Your Cards (@Model.Cards.Count) +
+
+
+ + + + + + + + + + + + @foreach (var item in Model.Cards) + { + + + + + + + + } + +
OwnerIssuerLast 4TransactionsActions
@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 +
+ +
+
+
+
+ Card Details +
+
+
+ + +
+ + + +
Who owns this card?
+
+ +
+ + + +
Which bank or institution issued the card?
+
+ +
+ + + +
The last 4 digits of the card number
+
+ +
+ + Cancel +
+
+
+
+
+ +
+
+
+ Tips +
+
+
    +
  • 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 @@ +