183 lines
5.9 KiB
Plaintext
183 lines
5.9 KiB
Plaintext
@page "/my-decks"
|
|
@rendermode InteractiveServer
|
|
@using Cloud.Models
|
|
@using Microsoft.EntityFrameworkCore
|
|
@inject AppDbContext Db
|
|
@inject NavigationManager Nav
|
|
|
|
<PageTitle>My Decks - Chrono CCG</PageTitle>
|
|
|
|
<div class="my-decks-container">
|
|
<div class="my-decks-header">
|
|
<div>
|
|
<h1>My Decks</h1>
|
|
<p class="text-secondary">@decks.Count deck@(decks.Count != 1 ? "s" : "") saved</p>
|
|
</div>
|
|
<a href="/deck-builder" class="btn btn-primary">
|
|
<i class="bi bi-plus-lg me-1"></i> New Deck
|
|
</a>
|
|
</div>
|
|
|
|
@if (loading)
|
|
{
|
|
<div class="decks-loading">
|
|
<span class="spinner-border spinner-border-sm me-2"></span> Loading decks...
|
|
</div>
|
|
}
|
|
else if (decks.Count == 0)
|
|
{
|
|
<div class="decks-empty">
|
|
<i class="bi bi-journal-x"></i>
|
|
<p>No decks yet. Create your first deck!</p>
|
|
<a href="/deck-builder" class="btn btn-outline-primary">
|
|
<i class="bi bi-plus-lg me-1"></i> Build a Deck
|
|
</a>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="decks-grid">
|
|
@foreach (var deck in decks)
|
|
{
|
|
var cardCount = deck.Cards.Count;
|
|
var uniqueCount = deck.Cards.Distinct().Count();
|
|
var isValid = cardCount == 40 && deck.Divers.Count == 2;
|
|
<div class="deck-card" @onclick="() => EditDeck(deck.Id)">
|
|
<div class="deck-card-header">
|
|
<div class="deck-name">@(string.IsNullOrEmpty(deck.Name) ? "Untitled Deck" : deck.Name)</div>
|
|
<span class="deck-valid-badge @(isValid ? "valid" : "invalid")">
|
|
<i class="bi @(isValid ? "bi-check-circle-fill" : "bi-exclamation-circle-fill")"></i>
|
|
@(isValid ? "Valid" : $"{cardCount}/40")
|
|
</span>
|
|
</div>
|
|
|
|
@if (!string.IsNullOrEmpty(deck.Season))
|
|
{
|
|
<div class="deck-season">
|
|
<i class="bi bi-calendar3"></i> @deck.Season
|
|
</div>
|
|
}
|
|
|
|
<div class="deck-meta">
|
|
<span><i class="bi bi-stack"></i> @cardCount cards</span>
|
|
<span><i class="bi bi-files"></i> @uniqueCount unique</span>
|
|
<span><i class="bi bi-person-arms-up"></i> @deck.Divers.Count/2 divers</span>
|
|
</div>
|
|
|
|
@if (deck.Divers.Count > 0)
|
|
{
|
|
<div class="deck-divers">
|
|
@foreach (var diver in deck.Divers)
|
|
{
|
|
<span class="diver-chip"><i class="bi bi-person-arms-up"></i> @diver</span>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
@if (!string.IsNullOrEmpty(deck.Notes))
|
|
{
|
|
<div class="deck-notes-preview">@deck.Notes</div>
|
|
}
|
|
|
|
<div class="deck-footer">
|
|
<span class="deck-updated">
|
|
<i class="bi bi-clock"></i> @deck.UpdatedAt.ToLocalTime().ToString("MMM d, yyyy h:mm tt")
|
|
</span>
|
|
<button class="btn btn-sm btn-outline-danger deck-delete"
|
|
@onclick:stopPropagation="true"
|
|
@onclick="() => ConfirmDelete(deck)">
|
|
<i class="bi bi-trash3"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
@if (deckToDelete != null)
|
|
{
|
|
<div class="modal-backdrop" @onclick="CancelDelete"></div>
|
|
<div class="confirm-modal">
|
|
<h5>Delete Deck</h5>
|
|
<p>Delete <strong>@(string.IsNullOrEmpty(deckToDelete.Name) ? "Untitled Deck" : deckToDelete.Name)</strong>? This cannot be undone.</p>
|
|
<div class="d-flex gap-2 justify-content-end">
|
|
<button class="btn btn-outline-secondary" @onclick="CancelDelete">Cancel</button>
|
|
<button class="btn btn-danger" @onclick="DeleteDeck" disabled="@deleting">
|
|
@if (deleting) { <span class="spinner-border spinner-border-sm me-1"></span> }
|
|
Delete
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@code {
|
|
private List<UserDeck> decks = [];
|
|
private bool loading = true;
|
|
private UserDeck? deckToDelete;
|
|
private bool deleting;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await LoadDecks();
|
|
}
|
|
|
|
private async Task LoadDecks()
|
|
{
|
|
loading = true;
|
|
try
|
|
{
|
|
decks = await Db.UserDecks.OrderByDescending(d => d.UpdatedAt).ToListAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[WARNING] Could not load decks: {ex.Message}");
|
|
decks = [];
|
|
}
|
|
finally
|
|
{
|
|
loading = false;
|
|
}
|
|
}
|
|
|
|
private void EditDeck(Guid id)
|
|
{
|
|
Nav.NavigateTo($"/deck-builder/{id}");
|
|
}
|
|
|
|
private void ConfirmDelete(UserDeck deck)
|
|
{
|
|
deckToDelete = deck;
|
|
}
|
|
|
|
private void CancelDelete()
|
|
{
|
|
deckToDelete = null;
|
|
}
|
|
|
|
private async Task DeleteDeck()
|
|
{
|
|
if (deckToDelete == null) return;
|
|
deleting = true;
|
|
try
|
|
{
|
|
var deck = await Db.UserDecks.FindAsync(deckToDelete.Id);
|
|
if (deck != null)
|
|
{
|
|
Db.UserDecks.Remove(deck);
|
|
await Db.SaveChangesAsync();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[WARNING] Could not delete deck: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
deleting = false;
|
|
deckToDelete = null;
|
|
await LoadDecks();
|
|
}
|
|
}
|
|
}
|