Initial commit — Hamkadr (همکادر) healthcare-staffing marketplace
ASP.NET Core 10 Razor Pages + PostgreSQL/EF Core. RTL Persian, Jalali dates, self-hosted Vazirmatn, teal/coral brand. Features: - Shift listings: browse/filter (city, district, role, type, pay), weekly Jalali calendar, detail + interest handoff, near-me distance sort - Hiring (استخدام) listings with employment type + salary range - Pattern-engine recommendations + anonymous interest tracking (visitor cookie) - Heuristic Persian listing-parser + admin queue (raw channel post → shift/job) - Phone-OTP cookie auth + visitor-history linking + profile Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
@page
|
||||
@model JobsMedical.Web.Pages.Preferences.IndexModel
|
||||
@{
|
||||
ViewData["Title"] = "علاقهمندیهای شما";
|
||||
}
|
||||
|
||||
<div class="page-head">
|
||||
<div class="container">
|
||||
<h1>علاقهمندیهای شما</h1>
|
||||
<p class="muted">بگو دنبال چه فرصتی هستی تا «همکادر» بهترین شیفتها و موقعیتها را برایت پیشنهاد دهد.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container section" style="max-width:560px;">
|
||||
<form method="post" class="card card-pad">
|
||||
<div class="filter-group">
|
||||
<label>نقش / رشته</label>
|
||||
<select name="RoleId">
|
||||
<option value="">مهم نیست</option>
|
||||
@foreach (var r in Model.Roles)
|
||||
{
|
||||
<option value="@r.Id" selected="@(Model.RoleId == r.Id)">@r.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label>شهر</label>
|
||||
<select name="CityId">
|
||||
<option value="">مهم نیست</option>
|
||||
@foreach (var c in Model.Cities)
|
||||
{
|
||||
<option value="@c.Id" selected="@(Model.CityId == c.Id)">@c.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label>نوع شیفت ترجیحی</label>
|
||||
<select name="PreferredShiftType">
|
||||
<option value="">مهم نیست</option>
|
||||
<option value="0" selected="@(Model.PreferredShiftType == ShiftType.Day)">صبح</option>
|
||||
<option value="1" selected="@(Model.PreferredShiftType == ShiftType.Evening)">عصر</option>
|
||||
<option value="2" selected="@(Model.PreferredShiftType == ShiftType.Night)">شب</option>
|
||||
<option value="3" selected="@(Model.PreferredShiftType == ShiftType.OnCall)">آنکال</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label>حداقل حقوق مورد انتظار (تومان)</label>
|
||||
<input type="number" name="MinPay" value="@Model.MinPay" placeholder="مثلاً ۲۰۰۰۰۰۰" dir="ltr" />
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-block btn-lg">ذخیره و دیدن پیشنهادها</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,57 @@
|
||||
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.Preferences;
|
||||
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
private readonly AppDbContext _db;
|
||||
private readonly InterestService _interest;
|
||||
|
||||
public IndexModel(AppDbContext db, InterestService interest)
|
||||
{
|
||||
_db = db;
|
||||
_interest = interest;
|
||||
}
|
||||
|
||||
public List<Role> Roles { get; private set; } = new();
|
||||
public List<City> Cities { get; private set; } = new();
|
||||
|
||||
[BindProperty] public int? RoleId { get; set; }
|
||||
[BindProperty] public int? CityId { get; set; }
|
||||
[BindProperty] public ShiftType? PreferredShiftType { get; set; }
|
||||
[BindProperty] public long? MinPay { get; set; }
|
||||
|
||||
public bool Saved { get; private set; }
|
||||
|
||||
public async Task OnGetAsync()
|
||||
{
|
||||
await LoadListsAsync();
|
||||
var prefs = await _interest.GetPreferencesAsync();
|
||||
if (prefs is not null)
|
||||
{
|
||||
RoleId = prefs.RoleId;
|
||||
CityId = prefs.CityId;
|
||||
PreferredShiftType = prefs.PreferredShiftType;
|
||||
MinPay = prefs.MinPay;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostAsync()
|
||||
{
|
||||
await _interest.SavePreferencesAsync(RoleId, CityId, PreferredShiftType, MinPay);
|
||||
// Back to home so the personalized feed is the immediate payoff.
|
||||
TempData["prefsSaved"] = true;
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
|
||||
private async Task LoadListsAsync()
|
||||
{
|
||||
Roles = await _db.Roles.Where(r => r.IsActive).OrderBy(r => r.SortOrder).ToListAsync();
|
||||
Cities = await _db.Cities.Where(c => c.IsActive).OrderBy(c => c.Name).ToListAsync();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user