From 872e5c18182f07a59ffe8f589c81742aedd0e6a4 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Thu, 11 Jun 2026 00:23:22 +0330 Subject: [PATCH] fix(blog): repair pagination on public and admin interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Public /blog: the handler param was named `page`, which is a reserved route token in Razor Pages and never binds — so every page silently showed the same first 10 posts. Renamed the query param to `pg` ([FromQuery(Name="pg")]) and updated the pagination links to match. Admin: the posts table had no pagination and dumped all rows at once. Added client-side pagination (10/page) with a prev/next + numbered bar over the already-loaded posts array. Verified: public page1=10/page2=4 with zero overlap; admin shows ‹ 1 2 › with correct row counts and active state per page. Co-Authored-By: Claude Opus 4.8 --- DrSousan.Api/Pages/Blog/Index.cshtml | 6 ++-- DrSousan.Api/Pages/Blog/Index.cshtml.cs | 6 ++-- DrSousan.Api/wwwroot/admin/index.html | 44 ++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/DrSousan.Api/Pages/Blog/Index.cshtml b/DrSousan.Api/Pages/Blog/Index.cshtml index 78709f0..e8991cf 100644 --- a/DrSousan.Api/Pages/Blog/Index.cshtml +++ b/DrSousan.Api/Pages/Blog/Index.cshtml @@ -101,16 +101,16 @@ } diff --git a/DrSousan.Api/Pages/Blog/Index.cshtml.cs b/DrSousan.Api/Pages/Blog/Index.cshtml.cs index cf0cd0a..8f520e7 100644 --- a/DrSousan.Api/Pages/Blog/Index.cshtml.cs +++ b/DrSousan.Api/Pages/Blog/Index.cshtml.cs @@ -20,9 +20,11 @@ public class BlogIndexModel : PageModel public int TotalPosts { get; private set; } = 0; public string? ActiveCat { get; private set; } - public async Task OnGetAsync(int page = 1, string? category = null) + // NOTE: the query param is "pg", not "page" — "page" is a reserved route token in + // Razor Pages and never binds here, which silently pins every request to page 1. + public async Task OnGetAsync([FromQuery(Name = "pg")] int pg = 1, string? category = null) { - CurrentPage = page < 1 ? 1 : page; + CurrentPage = pg < 1 ? 1 : pg; ActiveCat = category; var q = _db.BlogPosts.Include(p => p.Category).Where(p => p.IsPublished); diff --git a/DrSousan.Api/wwwroot/admin/index.html b/DrSousan.Api/wwwroot/admin/index.html index 521ba72..22c8e23 100644 --- a/DrSousan.Api/wwwroot/admin/index.html +++ b/DrSousan.Api/wwwroot/admin/index.html @@ -189,6 +189,13 @@ tr:hover td{background:#FAFBFC} .page{display:none} .page.active{display:block} +/* ── Table pagination ── */ +.tbl-pagination{display:flex;gap:.4rem;justify-content:center;flex-wrap:wrap;padding:1rem 0 .25rem;margin-top:.5rem} +.tbl-page-btn{min-width:34px;height:34px;padding:0 .6rem;border-radius:8px;border:1.5px solid var(--border);background:#fff;font-family:'Vazirmatn',sans-serif;font-size:.85rem;color:var(--dark);cursor:pointer;transition:all .2s} +.tbl-page-btn:hover:not(:disabled){border-color:var(--gold);color:var(--gold)} +.tbl-page-btn.active{background:var(--gold);border-color:var(--gold);color:#fff} +.tbl-page-btn:disabled{opacity:.4;cursor:default} + /* ── Login ── */ .login-screen{position:fixed;inset:0;background:var(--dark);display:flex;align-items:center;justify-content:center;z-index:1000} .login-box{background:var(--white);border-radius:20px;padding:2.5rem;width:380px;text-align:center} @@ -496,6 +503,7 @@ tr:hover td{background:#FAFBFC}
عنواندستهکلیدواژهبازدیدوضعیتعملیات
+
@@ -2026,9 +2034,23 @@ async function deleteCat(id){if(!confirm('حذف؟'))return;await api(`/api/blog // ── Blog Posts ──────────────────────────────────────────────────────────────── let posts=[]; +const POSTS_PER_PAGE = 10; +let postsPage = 1; + async function loadPosts(){ posts=await api('/api/blog/posts/admin')||[]; - document.getElementById('postsTable').innerHTML=posts.map(p=>` + postsPage = 1; + renderPostsPage(); +} + +function renderPostsPage(){ + const totalPages = Math.max(1, Math.ceil(posts.length / POSTS_PER_PAGE)); + if (postsPage > totalPages) postsPage = totalPages; + if (postsPage < 1) postsPage = 1; + const start = (postsPage - 1) * POSTS_PER_PAGE; + const slice = posts.slice(start, start + POSTS_PER_PAGE); + + document.getElementById('postsTable').innerHTML = slice.map(p=>` ${p.title} ${p.category?.name||'—'} @@ -2041,6 +2063,26 @@ async function loadPosts(){ `).join(''); + + renderPostsPagination(totalPages); +} + +function renderPostsPagination(totalPages){ + const box = document.getElementById('postsPagination'); + if (!box) return; + if (totalPages <= 1) { box.innerHTML=''; return; } + let html = ''; + html += ``; + for (let p=1; p<=totalPages; p++){ + html += ``; + } + html += ``; + box.innerHTML = html; +} + +function gotoPostsPage(p){ + postsPage = p; + renderPostsPage(); } async function openPostEditor(){