Add hiring, AI parser+admin, OTP auth, employer dashboard, profit-share pay
- Hiring (استخدام) listings: JobOpening + /Jobs browse/detail + home section - Heuristic Persian listing-parser + admin queue (/Admin) → publish shift/job - Phone-OTP cookie auth + visitor-history linking + profile; Admin role gate - Employer side: self-serve facility registration, dashboard, post/manage shifts & jobs, applicants list with contact - Compensation models: fixed / hourly / profit-share (درصدی) / negotiable / choice (به انتخاب شما); SharePercent + JalaliDate.PayLabel; parser + filter Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -49,7 +49,7 @@
|
||||
<div class="info-row"><span class="k">ساعت</span><span class="v">@JalaliDate.Time(s.StartTime) تا @JalaliDate.Time(s.EndTime)</span></div>
|
||||
<div class="info-row"><span class="k">مدت</span><span class="v">@JalaliDate.ToPersianDigits(s.DurationHours.ToString("0.#")) ساعت</span></div>
|
||||
<div class="info-row"><span class="k">نقش مورد نیاز</span><span class="v">@(s.Role?.Name ?? s.SpecialtyRequired)</span></div>
|
||||
<div class="info-row"><span class="k">حقوق</span><span class="v" style="color:var(--primary-dark)">@JalaliDate.Toman(s.PayAmount)</span></div>
|
||||
<div class="info-row"><span class="k">پرداخت</span><span class="v" style="color:var(--primary-dark)">@JalaliDate.PayLabel(s.PayType, s.PayAmount, s.SharePercent)</span></div>
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrEmpty(s.Description))
|
||||
@@ -74,10 +74,13 @@
|
||||
|
||||
<aside>
|
||||
<div class="card card-pad">
|
||||
<div class="pay" style="font-size:20px; margin-bottom:6px; color:var(--primary-dark); font-weight:800;">
|
||||
@JalaliDate.Toman(s.PayAmount)
|
||||
<div class="pay" style="font-size:19px; margin-bottom:6px; color:var(--primary-dark); font-weight:800;">
|
||||
@JalaliDate.PayLabel(s.PayType, s.PayAmount, s.SharePercent)
|
||||
</div>
|
||||
<p class="muted" style="font-size:13px; margin-top:0;">@(s.PayType == PayType.Negotiable ? "توافقی با مرکز درمانی" : "برای هر شیفت")</p>
|
||||
@if (s.PayAmount is not null && s.SharePercent is not null)
|
||||
{
|
||||
<p class="muted" style="font-size:13px; margin-top:0;">میتوانی هنگام هماهنگی، یکی از دو حالت را با مرکز انتخاب کنی.</p>
|
||||
}
|
||||
@if (Model.Saved)
|
||||
{
|
||||
<div class="alert alert-success" style="margin-bottom:12px;">✓ این فرصت ذخیره شد و در پیشنهادهای شما لحاظ میشود.</div>
|
||||
|
||||
@@ -95,6 +95,13 @@
|
||||
فقط شیفتهای با حقوق مشخص
|
||||
</label>
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<label style="display:flex; align-items:center; gap:8px; font-weight:600;">
|
||||
<input type="checkbox" name="ShareOnly" value="true" style="width:auto;"
|
||||
onchange="this.form.submit()" checked="@Model.ShareOnly" />
|
||||
فقط شیفتهای سهم درآمد (درصدی)
|
||||
</label>
|
||||
</div>
|
||||
<a asp-page="/Shifts/Index" class="btn btn-outline btn-block">حذف فیلترها</a>
|
||||
</form>
|
||||
</aside>
|
||||
|
||||
@@ -18,6 +18,7 @@ public class IndexModel : PageModel
|
||||
[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; } // فقط شیفتهای سهم درآمد
|
||||
|
||||
// "Near me": the browser sends the visitor's coordinates and we sort by distance.
|
||||
[BindProperty(SupportsGet = true)] public double? Lat { get; set; }
|
||||
@@ -56,6 +57,7 @@ public class IndexModel : PageModel
|
||||
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);
|
||||
|
||||
var results = await q.ToListAsync();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user