diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 77e7aa4..c72243a 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -4,7 +4,8 @@ "Bash(dotnet build)", "Bash(dotnet run:*)", "Bash(powershell:*)", - "Bash(dotnet script:*)" + "Bash(dotnet script:*)", + "Bash(taskkill:*)" ], "deny": [], "ask": [] diff --git a/Media.JoshHeaps.Net/Pages/Index.cshtml b/Media.JoshHeaps.Net/Pages/Index.cshtml index ab81d29..72128d8 100644 --- a/Media.JoshHeaps.Net/Pages/Index.cshtml +++ b/Media.JoshHeaps.Net/Pages/Index.cshtml @@ -1,4 +1,4 @@ -@page +@page "{handler?}" @model Media.JoshHeaps.Net.Pages.IndexModel @{ ViewData["Title"] = "Dashboard"; @@ -47,7 +47,7 @@ - + @@ -64,10 +64,10 @@ } diff --git a/Media.JoshHeaps.Net/Pages/Index.cshtml.cs b/Media.JoshHeaps.Net/Pages/Index.cshtml.cs index ea74fb8..ee3ad29 100644 --- a/Media.JoshHeaps.Net/Pages/Index.cshtml.cs +++ b/Media.JoshHeaps.Net/Pages/Index.cshtml.cs @@ -17,6 +17,9 @@ namespace Media.JoshHeaps.Net.Pages [BindProperty] public string? Description { get; set; } + [BindProperty] + public long? MediaId { get; set; } + public string? UploadMessage { get; set; } public bool UploadSuccess { get; set; } @@ -39,6 +42,17 @@ namespace Media.JoshHeaps.Net.Pages RequireAuthentication(); LoadUserSession(); + Dashboard = await userService.GetUserDashboardAsync(UserId); + MediaItems = await _mediaService.GetUserMediaAsync(UserId, 0, 20); + + return Page(); + } + + public async Task OnPostAddAsync() + { + RequireAuthentication(); + LoadUserSession(); + if (UploadedFile == null || UploadedFile.Length == 0) { UploadMessage = "Please select a file to upload."; @@ -69,19 +83,19 @@ namespace Media.JoshHeaps.Net.Pages } } - // Reload data - Dashboard = await userService.GetUserDashboardAsync(UserId); - MediaItems = await _mediaService.GetUserMediaAsync(UserId, 0, 20); - - return Page(); + // Redirect to prevent form resubmission on refresh + return RedirectToPage(); } - public async Task OnPostDeleteAsync(long mediaId) + public async Task OnPostDeleteAsync() { RequireAuthentication(); LoadUserSession(); - var success = await _mediaService.DeleteMediaAsync(mediaId, UserId); + if (MediaId.HasValue) + { + var success = await _mediaService.DeleteMediaAsync(MediaId.Value, UserId); + } return RedirectToPage(); } diff --git a/Media.JoshHeaps.Net/Pages/_ViewImports.cshtml b/Media.JoshHeaps.Net/Pages/_ViewImports.cshtml new file mode 100644 index 0000000..ac7c365 --- /dev/null +++ b/Media.JoshHeaps.Net/Pages/_ViewImports.cshtml @@ -0,0 +1,4 @@ +@using Media.JoshHeaps.Net +@using Media.JoshHeaps.Net.Pages +@namespace Media.JoshHeaps.Net.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/Media.JoshHeaps.Net/wwwroot/js/gallery.js b/Media.JoshHeaps.Net/wwwroot/js/gallery.js index fddbe4c..cd07c27 100644 --- a/Media.JoshHeaps.Net/wwwroot/js/gallery.js +++ b/Media.JoshHeaps.Net/wwwroot/js/gallery.js @@ -89,7 +89,7 @@ function createGalleryItem(media) { const form = document.createElement('form'); form.method = 'post'; - form.action = '/?handler=Delete'; + form.action = '?handler=Delete'; // Relative to current page form.style.display = 'inline'; // Add anti-forgery token @@ -101,7 +101,7 @@ function createGalleryItem(media) { const hiddenInput = document.createElement('input'); hiddenInput.type = 'hidden'; - hiddenInput.name = 'mediaId'; + hiddenInput.name = 'MediaId'; // Match C# property name exactly hiddenInput.value = media.id; form.appendChild(hiddenInput); @@ -110,7 +110,10 @@ function createGalleryItem(media) { deleteBtn.className = 'btn-delete'; deleteBtn.textContent = 'Delete'; deleteBtn.onclick = function(e) { - return confirm('Are you sure you want to delete this image?'); + if (!confirm('Are you sure you want to delete this image?')) { + e.preventDefault(); + return false; + } }; form.appendChild(deleteBtn);