[Profile] Show applicant avatar + resume to employers; profile-completeness nudge
Employer Listings: each applicant row now shows their avatar (or initials) and a «مشاهده رزومه» link when they uploaded one (served via /resume/{id}, already access-controlled to the receiving employer). Applicant projection avoids loading avatar/resume blobs. Me panel: a nudge banner prompts users to complete their profile (name/photo/resume) when any is missing, linking to /Me/Profile.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,8 @@ public class ListingsModel : PageModel
|
||||
_notify = notify;
|
||||
}
|
||||
|
||||
public record Applicant(string? Name, string Phone, DateTime When, long EventId, int UserId, ApplicationStatus Status);
|
||||
public record Applicant(string? Name, string Phone, DateTime When, long EventId, int UserId,
|
||||
ApplicationStatus Status, bool HasAvatar, bool HasResume);
|
||||
public record ShiftRow(Shift Shift, List<Applicant> Applicants, int Guests);
|
||||
public record JobRow(JobOpening Job, List<Applicant> Applicants, int Guests);
|
||||
|
||||
@@ -124,7 +125,9 @@ public class ListingsModel : PageModel
|
||||
var visitorUser = await _db.Visitors.Where(v => visitorIds.Contains(v.Id))
|
||||
.ToDictionaryAsync(v => v.Id, v => v.UserId);
|
||||
var userIds = visitorUser.Values.Where(u => u != null).Select(u => u!.Value).Distinct().ToList();
|
||||
var users = await _db.Users.Where(u => userIds.Contains(u.Id)).ToDictionaryAsync(u => u.Id);
|
||||
var users = await _db.Users.Where(u => userIds.Contains(u.Id))
|
||||
.Select(u => new { u.Id, u.FullName, u.Phone, HasAvatar = u.Avatar != null, HasResume = u.Resume != null })
|
||||
.ToDictionaryAsync(u => u.Id);
|
||||
|
||||
(List<Applicant> applicants, int guests) Resolve(IEnumerable<InterestEvent> evs)
|
||||
{
|
||||
@@ -136,7 +139,7 @@ public class ListingsModel : PageModel
|
||||
var uid = visitorUser.GetValueOrDefault(e.VisitorId);
|
||||
if (uid is int id && users.TryGetValue(id, out var u))
|
||||
{
|
||||
if (seen.Add(id)) applicants.Add(new Applicant(u.FullName, u.Phone, e.CreatedAt, e.Id, id, e.Status));
|
||||
if (seen.Add(id)) applicants.Add(new Applicant(u.FullName, u.Phone, e.CreatedAt, e.Id, id, e.Status, u.HasAvatar, u.HasResume));
|
||||
}
|
||||
else guests++;
|
||||
}
|
||||
|
||||
@@ -1,26 +1,44 @@
|
||||
@model JobsMedical.Web.Pages.Employer.ListingsModel.Applicant
|
||||
@{
|
||||
var s = Model.Status;
|
||||
var nm = (Model.Name ?? Model.Phone).Trim();
|
||||
var initial = nm.Length > 0 ? nm.Substring(0, 1) : "؟";
|
||||
}
|
||||
<li style="margin-bottom:8px;">
|
||||
<span>@(Model.Name ?? "کاربر") — <span dir="ltr">@JalaliDate.ToPersianDigits(Model.Phone)</span></span>
|
||||
@if (s == JobsMedical.Web.Models.ApplicationStatus.Accepted)
|
||||
{
|
||||
<span class="badge badge-verified">✓ پذیرفته شد</span>
|
||||
}
|
||||
else if (s == JobsMedical.Web.Models.ApplicationStatus.Rejected)
|
||||
{
|
||||
<span class="badge badge-gender">رد شد</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span style="display:inline-flex; gap:6px; margin-inline-start:8px; vertical-align:middle;">
|
||||
<li class="applicant-row">
|
||||
<span class="avatar-sm">
|
||||
@if (Model.HasAvatar)
|
||||
{
|
||||
<img src="/avatar/@Model.UserId" alt="" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="avatar-fallback">@initial</span>
|
||||
}
|
||||
</span>
|
||||
<span class="applicant-info">
|
||||
<span>@(Model.Name ?? "کاربر") — <span dir="ltr">@JalaliDate.ToPersianDigits(Model.Phone)</span></span>
|
||||
@if (Model.HasResume)
|
||||
{
|
||||
<a href="/resume/@Model.UserId" target="_blank" class="resume-link">📎 مشاهده رزومه</a>
|
||||
}
|
||||
</span>
|
||||
<span class="applicant-actions">
|
||||
@if (s == JobsMedical.Web.Models.ApplicationStatus.Accepted)
|
||||
{
|
||||
<span class="badge badge-verified">✓ پذیرفته شد</span>
|
||||
}
|
||||
else if (s == JobsMedical.Web.Models.ApplicationStatus.Rejected)
|
||||
{
|
||||
<span class="badge badge-gender">رد شد</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post" asp-page-handler="Accept" asp-route-eventId="@Model.EventId" style="display:inline;">
|
||||
<button type="submit" class="btn btn-accent" style="padding:3px 12px; font-size:12px;">پذیرفتن</button>
|
||||
</form>
|
||||
<form method="post" asp-page-handler="Reject" asp-route-eventId="@Model.EventId" style="display:inline;">
|
||||
<button type="submit" class="btn btn-outline" style="padding:3px 12px; font-size:12px; color:var(--danger); border-color:var(--danger);">رد</button>
|
||||
</form>
|
||||
</span>
|
||||
}
|
||||
}
|
||||
</span>
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user