diff --git a/src/JobsMedical.Web/Pages/Admin/Review.cshtml b/src/JobsMedical.Web/Pages/Admin/Review.cshtml index b1f06e2..6ae6115 100644 --- a/src/JobsMedical.Web/Pages/Admin/Review.cshtml +++ b/src/JobsMedical.Web/Pages/Admin/Review.cshtml @@ -10,6 +10,10 @@
+ @if (Model.Error is not null) + { +
⚠ @Model.Error
+ }
@@ -47,11 +51,14 @@
+ +

اگر مرکز در فهرست نیست، نامش را اینجا بنویس تا به‌صورت «تأییدنشده» ساخته شود.

diff --git a/src/JobsMedical.Web/Pages/Admin/Review.cshtml.cs b/src/JobsMedical.Web/Pages/Admin/Review.cshtml.cs index b2d8145..1832c05 100644 --- a/src/JobsMedical.Web/Pages/Admin/Review.cshtml.cs +++ b/src/JobsMedical.Web/Pages/Admin/Review.cshtml.cs @@ -27,9 +27,12 @@ public class ReviewModel : PageModel public List Facilities { get; private set; } = new(); public List Roles { get; private set; } = new(); + [TempData] public string? Error { get; set; } + // The editable form (prefilled from the parser, admin can override everything). [BindProperty] public ListingKind Kind { get; set; } [BindProperty] public int FacilityId { get; set; } + [BindProperty] public string? NewFacilityName { get; set; } // create a facility on the fly if none picked [BindProperty] public int RoleId { get; set; } [BindProperty] public string? Description { get; set; } // Shift fields @@ -77,6 +80,21 @@ public class ReviewModel : PageModel Raw = await _db.RawListings.FirstOrDefaultAsync(r => r.Id == id); if (Raw is null) return NotFound(); + // Resolve the facility: prefer the picked one; otherwise create from the typed name. + // This prevents FK_Shifts_Facilities_FacilityId violations when no facility is selected + // (e.g. the dropdown is empty because no facilities exist yet). + var facilityId = await ResolveFacilityIdAsync(); + if (facilityId is null) + { + Error = "یک مرکز درمانی معتبر انتخاب کن، یا در کادر «نام مرکز جدید» نام مرکز را وارد کن تا ساخته شود."; + return RedirectToPage(new { id }); + } + if (!await _db.Roles.AnyAsync(r => r.Id == RoleId)) + { + Error = "یک نقش معتبر انتخاب کن."; + return RedirectToPage(new { id }); + } + Shift? createdShift = null; JobOpening? createdJob = null; if (Kind == ListingKind.Shift) @@ -84,7 +102,7 @@ public class ReviewModel : PageModel var role = await _db.Roles.FindAsync(RoleId); var shift = new Shift { - FacilityId = FacilityId, + FacilityId = facilityId.Value, RoleId = RoleId, Date = ShiftDate, StartTime = StartTime, @@ -111,7 +129,7 @@ public class ReviewModel : PageModel { var job = new JobOpening { - FacilityId = FacilityId, + FacilityId = facilityId.Value, RoleId = RoleId, Title = string.IsNullOrWhiteSpace(Title) ? "موقعیت استخدامی" : Title.Trim(), EmploymentType = EmploymentType, @@ -150,6 +168,41 @@ public class ReviewModel : PageModel _ => (new TimeOnly(8, 0), new TimeOnly(8, 0)), }; + /// + /// Returns a valid existing FacilityId, creating a new unverified facility from + /// when nothing valid is selected. Returns null when + /// neither a valid facility is picked nor a name is provided. + /// + private async Task ResolveFacilityIdAsync() + { + if (FacilityId > 0 && await _db.Facilities.AnyAsync(f => f.Id == FacilityId)) + return FacilityId; + + if (string.IsNullOrWhiteSpace(NewFacilityName)) + return null; + + // Reuse a same-named facility if one already exists, else create it. + var name = NewFacilityName.Trim(); + var existing = await _db.Facilities.FirstOrDefaultAsync(f => f.Name == name); + if (existing is not null) return existing.Id; + + var cityId = await _db.Cities.OrderByDescending(c => c.IsActive) + .Select(c => (int?)c.Id).FirstOrDefaultAsync(); + if (cityId is null) return null; // no cities seeded — cannot create a facility + + var facility = new Facility + { + Name = name, + CityId = cityId.Value, + Type = FacilityType.Hospital, + Verification = VerificationStatus.Unverified, + IsVerified = false, + }; + _db.Facilities.Add(facility); + await _db.SaveChangesAsync(); + return facility.Id; + } + private async Task LoadListsAsync() { Facilities = await _db.Facilities.Include(f => f.City).OrderBy(f => f.Name).ToListAsync(); diff --git a/src/JobsMedical.Web/wwwroot/css/site.css b/src/JobsMedical.Web/wwwroot/css/site.css index d6f0f64..fa3a96c 100644 --- a/src/JobsMedical.Web/wwwroot/css/site.css +++ b/src/JobsMedical.Web/wwwroot/css/site.css @@ -399,6 +399,7 @@ label { font-size: 13px; } .legal li { margin-bottom: 6px; } .alert { padding: 12px 16px; border-radius: 10px; margin-bottom: 16px; font-weight: 600; } .alert-success { background: var(--primary-soft); color: var(--primary-dark); } +.alert-error { background: #fdecea; color: #b3261e; border: 1px solid #f5c2c0; } /* notification bell badge */ .bell-badge { position:absolute; top:-6px; inset-inline-start:-8px; background:var(--accent); color:#fff;