From 86809190e702e1431928438a837686bfe9d206e4 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Thu, 4 Jun 2026 18:57:49 +0330 Subject: [PATCH] [Map] Render real Neshan map on shift/job detail pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The detail pages showed a 'map coming later' placeholder. Add a read-only Neshan web map (Leaflet SDK) showing the facility marker when NeshanMapKey is set, plus a 'مسیریابی در نشان' directions link; falls back to coordinates when no key. New _NeshanMap shared partial loads the SDK and inits #facmap. Shift/Job Details models now expose MapKey via SettingsService. Coordinates are emitted with InvariantCulture so the decimal point/digits don't break JS. The facility registration picker already used Neshan; this reuses the same key. Co-Authored-By: Claude Opus 4.8 --- src/JobsMedical.Web/Pages/Jobs/Details.cshtml | 26 +++++++++++++++++++ .../Pages/Jobs/Details.cshtml.cs | 7 ++++- .../Pages/Shared/_NeshanMap.cshtml | 21 +++++++++++++++ .../Pages/Shifts/Details.cshtml | 24 +++++++++++++---- .../Pages/Shifts/Details.cshtml.cs | 7 ++++- 5 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 src/JobsMedical.Web/Pages/Shared/_NeshanMap.cshtml diff --git a/src/JobsMedical.Web/Pages/Jobs/Details.cshtml b/src/JobsMedical.Web/Pages/Jobs/Details.cshtml index 43ad587..6dadbcc 100644 --- a/src/JobsMedical.Web/Pages/Jobs/Details.cshtml +++ b/src/JobsMedical.Web/Pages/Jobs/Details.cshtml @@ -122,6 +122,32 @@ } } + + @if (j.Facility?.Lat is not null && j.Facility?.Lng is not null) + { + var latS = j.Facility.Lat.Value.ToString(System.Globalization.CultureInfo.InvariantCulture); + var lngS = j.Facility.Lng.Value.ToString(System.Globalization.CultureInfo.InvariantCulture); +
+

موقعیت مکانی

+ @if (!string.IsNullOrEmpty(Model.MapKey)) + { +
+ } + else + { +
+ 🗺️
@latS، @lngS +
+ } + مسیریابی در نشان +
+ } + +@if (!string.IsNullOrEmpty(Model.MapKey) && Model.Job?.Facility?.Lat is not null) +{ + +} diff --git a/src/JobsMedical.Web/Pages/Jobs/Details.cshtml.cs b/src/JobsMedical.Web/Pages/Jobs/Details.cshtml.cs index 6922f77..583b857 100644 --- a/src/JobsMedical.Web/Pages/Jobs/Details.cshtml.cs +++ b/src/JobsMedical.Web/Pages/Jobs/Details.cshtml.cs @@ -11,14 +11,18 @@ public class DetailsModel : PageModel { private readonly AppDbContext _db; private readonly InterestService _interest; + private readonly JobsMedical.Web.Services.Scraping.SettingsService _settings; - public DetailsModel(AppDbContext db, InterestService interest) + public DetailsModel(AppDbContext db, InterestService interest, + JobsMedical.Web.Services.Scraping.SettingsService settings) { _db = db; _interest = interest; + _settings = settings; } public JobOpening? Job { get; private set; } + public string? MapKey { get; private set; } public bool ShowContact { get; private set; } public bool Saved { get; private set; } public bool Reported { get; private set; } @@ -27,6 +31,7 @@ public class DetailsModel : PageModel { await LoadAsync(id); if (Job is null) return NotFound(); + MapKey = (await _settings.GetAsync()).NeshanMapKey; Reported = Request.Query["reported"] == "1"; await _interest.LogJobAsync(InterestEventType.View, id); return Page(); diff --git a/src/JobsMedical.Web/Pages/Shared/_NeshanMap.cshtml b/src/JobsMedical.Web/Pages/Shared/_NeshanMap.cshtml new file mode 100644 index 0000000..8cb4eb4 --- /dev/null +++ b/src/JobsMedical.Web/Pages/Shared/_NeshanMap.cshtml @@ -0,0 +1,21 @@ +@model string +@* + Read-only Neshan map. Render once per page AFTER an element
exists. Pass the Neshan web key as the model. + The SDK is a synchronous script, so the init below runs once L is defined. +*@ + + + diff --git a/src/JobsMedical.Web/Pages/Shifts/Details.cshtml b/src/JobsMedical.Web/Pages/Shifts/Details.cshtml index e1354e2..e81efc0 100644 --- a/src/JobsMedical.Web/Pages/Shifts/Details.cshtml +++ b/src/JobsMedical.Web/Pages/Shifts/Details.cshtml @@ -143,11 +143,20 @@

موقعیت مکانی

@if (f.Lat is not null && f.Lng is not null) { -
- 🗺️
نقشه نشان/بلد
- @f.Lat، @f.Lng -
-

نقشه تعاملی در فاز بعد اضافه می‌شود (Neshan/Balad).

+ var latS = f.Lat.Value.ToString(System.Globalization.CultureInfo.InvariantCulture); + var lngS = f.Lng.Value.ToString(System.Globalization.CultureInfo.InvariantCulture); + @if (!string.IsNullOrEmpty(Model.MapKey)) + { +
+ } + else + { +
+ 🗺️
@latS، @lngS +
+ } + مسیریابی در نشان } else { @@ -157,3 +166,8 @@
+ +@if (!string.IsNullOrEmpty(Model.MapKey) && Model.Shift?.Facility?.Lat is not null) +{ + +} diff --git a/src/JobsMedical.Web/Pages/Shifts/Details.cshtml.cs b/src/JobsMedical.Web/Pages/Shifts/Details.cshtml.cs index e5bf3be..f05bffc 100644 --- a/src/JobsMedical.Web/Pages/Shifts/Details.cshtml.cs +++ b/src/JobsMedical.Web/Pages/Shifts/Details.cshtml.cs @@ -11,15 +11,19 @@ public class DetailsModel : PageModel { private readonly AppDbContext _db; private readonly InterestService _interest; + private readonly JobsMedical.Web.Services.Scraping.SettingsService _settings; - public DetailsModel(AppDbContext db, InterestService interest) + public DetailsModel(AppDbContext db, InterestService interest, + JobsMedical.Web.Services.Scraping.SettingsService settings) { _db = db; _interest = interest; + _settings = settings; } public Shift? Shift { get; private set; } public List MoreAtFacility { get; private set; } = new(); + public string? MapKey { get; private set; } // Set after the visitor taps "interested" — reveals the facility contact (handoff model). public bool ShowContact { get; private set; } @@ -30,6 +34,7 @@ public class DetailsModel : PageModel { await LoadAsync(id); if (Shift is null) return NotFound(); + MapKey = (await _settings.GetAsync()).NeshanMapKey; Reported = Request.Query["reported"] == "1"; await _interest.LogAsync(InterestEventType.View, id); // behavioral signal for recommendations return Page();