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:
soroush.asadi
2026-06-03 06:26:54 +03:30
parent 2fb86a435e
commit 563a40d1f4
30 changed files with 1761 additions and 27 deletions
@@ -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>