Files
hamkadr/src/JobsMedical.Web/Pages/Talent/Index.cshtml.cs
T
soroush.asadi 5fcdb8599f
CI/CD / CI · dotnet build (push) Successful in 2m50s
CI/CD / Deploy · hamkadr (push) Successful in 5m42s
Add pagination to the Jobs / Shifts / Talent list pages
The list pages loaded EVERY matching listing into one page (/Jobs was a ~2.6MB page with 1000+
cards) — no pagination at all. Add server-side paging (24/page, DB Skip/Take; near-me still sorts
all by distance then paginates in memory). The header count now shows the true total, and a shared
_Pager partial renders prev/next + a windowed page list that preserves all active filters in the URL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 19:27:41 +03:30

85 lines
4.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using JobsMedical.Web.Data;
using JobsMedical.Web.Models;
using JobsMedical.Web.Services.Scraping;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
namespace JobsMedical.Web.Pages.Talent;
public class IndexModel : PageModel
{
private readonly AppDbContext _db;
public IndexModel(AppDbContext db) => _db = db;
[BindProperty(SupportsGet = true)] public int? CityId { get; set; }
[BindProperty(SupportsGet = true)] public int? DistrictId { get; set; }
[BindProperty(SupportsGet = true)] public int? RoleId { get; set; }
[BindProperty(SupportsGet = true)] public Gender? GenderFilter { get; set; }
[BindProperty(SupportsGet = true)] public string? Q { get; set; } // deep search
[BindProperty(SupportsGet = true)] public int Page { get; set; } = 1;
private const int PageSize = 24;
public int TotalCount { get; private set; }
public int TotalPages { get; private set; }
public int CurrentPage { get; private set; }
public List<TalentListing> Results { get; private set; } = new();
public List<City> Cities { get; private set; } = new();
public List<District> Districts { get; private set; } = new();
public List<Role> Roles { get; private set; } = new();
/// <summary>Dynamic page heading/H1 + title, set from the active role/city for SEO.</summary>
public string PageHeading { get; private set; } = "کادر درمان آماده به کار";
public async Task OnGetAsync()
{
Cities = await _db.Cities.Where(c => c.IsActive).OrderBy(c => c.Name).ToListAsync();
Roles = await _db.Roles.Where(r => r.IsActive).OrderBy(r => r.SortOrder).ToListAsync();
Districts = await _db.Districts
.Where(d => d.IsActive && (CityId == null || d.CityId == CityId))
.OrderBy(d => d.Name).ToListAsync();
var q = _db.TalentListings
.Include(t => t.City)
.Include(t => t.District)
.Include(t => t.Role)
.Where(t => t.Status == ShiftStatus.Open && t.CreatedAt >= ListingPolicy.TalentCutoffUtc);
if (CityId is not null) q = q.Where(t => t.CityId == CityId);
if (DistrictId is not null) q = q.Where(t => t.DistrictId == DistrictId);
if (RoleId is not null) q = q.Where(t => t.RoleId == RoleId);
if (GenderFilter is Gender g && g != Gender.Any)
q = q.Where(t => t.Gender == Gender.Any || t.Gender == g);
// Deep search: every term must match somewhere (tags, role, city, person, area, description).
if (!string.IsNullOrWhiteSpace(Q))
foreach (var term in Q.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
var like = $"%{term}%";
q = q.Where(t =>
EF.Functions.ILike(t.Tags ?? "", like) ||
EF.Functions.ILike(t.Description ?? "", like) ||
EF.Functions.ILike(t.PersonName ?? "", like) ||
EF.Functions.ILike(t.AreaNote ?? "", like) ||
EF.Functions.ILike(t.Role.Name, like) ||
EF.Functions.ILike(t.City.Name, like));
}
TotalCount = await q.CountAsync();
TotalPages = Math.Max(1, (int)Math.Ceiling(TotalCount / (double)PageSize));
CurrentPage = Math.Clamp(Page, 1, TotalPages);
Results = await q.OrderByDescending(t => t.CreatedAt)
.Skip((CurrentPage - 1) * PageSize).Take(PageSize).ToListAsync();
var role = Roles.FirstOrDefault(r => r.Id == RoleId)?.Name;
var city = Cities.FirstOrDefault(c => c.Id == CityId)?.Name;
PageHeading =
role is not null && city is not null ? $"{role} آماده به کار در {city}"
: role is not null ? $"{role} آماده به کار"
: city is not null ? $"کادر درمان آماده به کار در {city}"
: "کادر درمان آماده به کار";
ViewData["Title"] = PageHeading;
ViewData["Description"] = $"فهرست «آماده به کار» {(role ?? "کادر درمان")}{(city is not null ? " در " + city : "")} — همکادر؛ مشاهده و تماس مستقیم.";
}
}