using JobsMedical.Web.Data; using JobsMedical.Web.Models; using JobsMedical.Web.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.EntityFrameworkCore; namespace JobsMedical.Web.Pages.Shifts; 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 int? FacilityId { get; set; } [BindProperty(SupportsGet = true)] public ShiftType? ShiftType { get; set; } [BindProperty(SupportsGet = true)] public bool PaidOnly { get; set; } [BindProperty(SupportsGet = true)] public bool ShareOnly { get; set; } // فقط شیفت‌های سهم درآمد [BindProperty(SupportsGet = true)] public Gender? GenderFilter { get; set; } // "Near me": the browser sends the visitor's coordinates and we sort by distance. [BindProperty(SupportsGet = true)] public double? Lat { get; set; } [BindProperty(SupportsGet = true)] public double? Lng { get; set; } public bool NearMeActive => Lat is not null && Lng is not null; public List Results { get; private set; } = new(); public List Cities { get; private set; } = new(); public List Districts { get; private set; } = new(); public List Roles { get; private set; } = new(); public List Facilities { get; private set; } = new(); public async Task OnGetAsync() { var today = DateOnly.FromDateTime(DateTime.UtcNow); 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(); Facilities = await _db.Facilities .Where(f => CityId == null || f.CityId == CityId) .OrderBy(f => f.Name).ToListAsync(); var q = _db.Shifts .Include(s => s.Facility).ThenInclude(f => f.City) .Include(s => s.Facility).ThenInclude(f => f.District) .Include(s => s.Role) .Where(s => s.Status == ShiftStatus.Open && s.Date >= today); if (CityId is not null) q = q.Where(s => s.Facility.CityId == CityId); if (DistrictId is not null) q = q.Where(s => s.Facility.DistrictId == DistrictId); if (RoleId is not null) q = q.Where(s => s.RoleId == RoleId); if (FacilityId is not null) q = q.Where(s => s.FacilityId == FacilityId); if (ShiftType is not null) q = q.Where(s => s.ShiftType == ShiftType); if (PaidOnly) q = q.Where(s => s.PayAmount != null); if (ShareOnly) q = q.Where(s => s.SharePercent != null); // A given gender sees listings open to them (their gender or "فرقی نمی‌کند"). if (GenderFilter is Gender g && g != Gender.Any) q = q.Where(s => s.GenderRequirement == Gender.Any || s.GenderRequirement == g); var results = await q.ToListAsync(); if (NearMeActive) { // Compute distance to each facility, then nearest-first (shifts without coords last). foreach (var s in results) { if (s.Facility.Lat is double flat && s.Facility.Lng is double flng) s.DistanceKm = Geo.DistanceKm(Lat!.Value, Lng!.Value, flat, flng); } Results = results .OrderBy(s => s.DistanceKm ?? double.MaxValue) .ThenBy(s => s.Date).ThenBy(s => s.StartTime) .ToList(); } else { Results = results.OrderBy(s => s.Date).ThenBy(s => s.StartTime).ToList(); } } }