Inbox: redesign the form applicant detail pane #58
|
|
@ -1492,12 +1492,6 @@ function FormApplicantDetail({
|
|||
{loading && <span className="cell-sub">Loading details…</span>}
|
||||
</div>
|
||||
</div>
|
||||
{i.rowNumber != null && (
|
||||
<div style={{ textAlign: 'right' }}>
|
||||
<div className="cell-sub">Sheet row</div>
|
||||
<div className="fw-600">{i.rowNumber}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{(resumeHref || profileHref) && (
|
||||
|
|
@ -1570,19 +1564,11 @@ function FormApplicantDetail({
|
|||
marginBottom: 20,
|
||||
}}
|
||||
>
|
||||
<div style={{ flex: '1 1 320px', minWidth: 0 }}>
|
||||
<div className="email-head" style={{ borderRadius: '10px 10px 0 0' }}>Contact & application</div>
|
||||
<div
|
||||
className="info-grid"
|
||||
style={{
|
||||
marginBottom: 20,
|
||||
border: '1px solid var(--border)',
|
||||
borderTop: 'none',
|
||||
borderRadius: '0 0 10px 10px',
|
||||
padding: '14px 16px',
|
||||
background: 'var(--bg-elev)',
|
||||
}}
|
||||
>
|
||||
<div style={{ flex: '1 1 320px', minWidth: 0, display: 'flex', flexDirection: 'column', gap: 18 }}>
|
||||
<div className="card" style={{ boxShadow: 'none' }}>
|
||||
<div className="card-head"><h3>Contact & application</h3></div>
|
||||
<div className="card-body">
|
||||
<div className="info-grid">
|
||||
<div className="info-item"><div className="il">Email</div><div className="iv">{orDash(i.email)}</div></div>
|
||||
<div className="info-item"><div className="il">Phone</div><div className="iv">{orDash(i.phone)}</div></div>
|
||||
<div className="info-item"><div className="il">Applied</div><div className="iv">{i.received ? fmtDate(i.received) : '—'}</div></div>
|
||||
|
|
@ -1590,19 +1576,13 @@ function FormApplicantDetail({
|
|||
<div className="info-item"><div className="il">Screened by</div><div className="iv">{orDash(i.screenedBy)}</div></div>
|
||||
<div className="info-item"><div className="il">Notice period</div><div className="iv">{orDash(i.noticePeriod)}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="email-head" style={{ borderRadius: '10px 10px 0 0' }}>Profile</div>
|
||||
<div
|
||||
className="info-grid"
|
||||
style={{
|
||||
marginBottom: 20,
|
||||
border: '1px solid var(--border)',
|
||||
borderTop: 'none',
|
||||
borderRadius: '0 0 10px 10px',
|
||||
padding: '14px 16px',
|
||||
background: 'var(--bg-elev)',
|
||||
}}
|
||||
>
|
||||
<div className="card" style={{ boxShadow: 'none' }}>
|
||||
<div className="card-head"><h3>Profile</h3></div>
|
||||
<div className="card-body">
|
||||
<div className="info-grid">
|
||||
<div className="info-item"><div className="il">Gender</div><div className="iv">{orDash(i.gender)}</div></div>
|
||||
<div className="info-item"><div className="il">Date of birth</div><div className="iv">{i.dateOfBirth ? fmtDate(i.dateOfBirth) : '—'}</div></div>
|
||||
<div className="info-item"><div className="il">CNIC</div><div className="iv">{orDash(i.cnic)}</div></div>
|
||||
|
|
@ -1614,44 +1594,39 @@ function FormApplicantDetail({
|
|||
<div className="info-item"><div className="il">Current salary</div><div className="iv">{orDash(i.currentSalary)}</div></div>
|
||||
<div className="info-item"><div className="il">Expected salary</div><div className="iv">{orDash(i.expectedSalary)}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{i.hrComments && (
|
||||
<div className="card" style={{ boxShadow: 'none', background: 'var(--bg-sunken)', marginBottom: 8 }}>
|
||||
<div className="card" style={{ boxShadow: 'none', background: 'var(--bg-sunken)' }}>
|
||||
<div className="card-body">
|
||||
<div className="fw-600" style={{ marginBottom: 6 }}>HR comment</div>
|
||||
<p style={{ margin: 0 }}>{i.hrComments}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{i.sheet && (
|
||||
<div className="cell-sub" style={{ marginTop: 12 }}>
|
||||
Imported from {i.sheet}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div role="radiogroup" aria-label="Matching roles" style={{ flex: '0 1 360px', minWidth: 260 }}>
|
||||
<div className="fw-600" style={{ marginBottom: 8 }}>Matching roles</div>
|
||||
<div className="cell-sub" style={{ marginBottom: 10 }}>
|
||||
Matched by position applied for: {orDash(i.position)}
|
||||
</div>
|
||||
{matchCards.length === 0 && !manualPost ? (
|
||||
<EmptyState icon="alert" title="No matching roles">
|
||||
<p>No job post title matches this position. Choose a role manually.</p>
|
||||
<div style={{ display: 'flex', gap: 8, justifyContent: 'center', flexWrap: 'wrap', marginTop: 10 }}>
|
||||
<button
|
||||
className="btn btn-primary btn-sm"
|
||||
disabled={!canEdit}
|
||||
title={!canEdit ? 'Requires inbox.edit' : undefined}
|
||||
onClick={() => setShowPicker(true)}
|
||||
<div
|
||||
role="radiogroup"
|
||||
aria-label="Matching roles"
|
||||
className="card"
|
||||
style={{ flex: '1 1 300px', minWidth: 260, boxShadow: 'none', alignSelf: 'start' }}
|
||||
>
|
||||
Choose a role
|
||||
</button>
|
||||
<div className="card-head">
|
||||
<div>
|
||||
<h3>Matching roles</h3>
|
||||
<span className="ch-sub">Matched by position: {orDash(i.position)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
{matchCards.length === 0 && !manualPost ? (
|
||||
<EmptyState icon="target" title="No matching roles">
|
||||
<p>No job post title matches this position — pick one manually.</p>
|
||||
</EmptyState>
|
||||
) : (
|
||||
matchCards.map(({ rank, post }) => (
|
||||
<>
|
||||
{matchCards.map(({ rank, post }) => (
|
||||
<JobCard
|
||||
key={post.id}
|
||||
post={post}
|
||||
|
|
@ -1660,8 +1635,7 @@ function FormApplicantDetail({
|
|||
selected={String(selection) === String(post.id)}
|
||||
onSelect={(id) => setSelection(String(id))}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
))}
|
||||
{manualPost && (
|
||||
<JobCard
|
||||
post={manualPost}
|
||||
|
|
@ -1671,18 +1645,24 @@ function FormApplicantDetail({
|
|||
onSelect={(id) => setSelection(String(id))}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<div className="flex gap-8" style={{ flexWrap: 'wrap', marginTop: 12 }}>
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
style={{ width: '100%', marginTop: 8 }}
|
||||
className={`btn ${matchCards.length === 0 && !manualPost ? 'btn-primary' : 'btn-secondary'}`}
|
||||
style={{ flex: '1 1 auto' }}
|
||||
disabled={!canEdit}
|
||||
title={!canEdit ? 'Requires inbox.edit' : undefined}
|
||||
onClick={() => setShowPicker(true)}
|
||||
>
|
||||
Choose a different role…
|
||||
<Icon name="search" /> Browse roles…
|
||||
</button>
|
||||
{/* Assign only renders once there is a selection to act on —
|
||||
a permanently disabled primary button read as broken UI. */}
|
||||
{selection && selection !== i.assignedId && (
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
style={{ width: '100%', marginTop: 8 }}
|
||||
style={{ flex: '1 1 auto' }}
|
||||
disabled={!canAssign}
|
||||
title={!canEdit ? 'Requires inbox.edit' : undefined}
|
||||
onClick={() => {
|
||||
|
|
@ -1690,12 +1670,21 @@ function FormApplicantDetail({
|
|||
assignMutation.mutate({ recordId: i.id, jobPostId: selection })
|
||||
}}
|
||||
>
|
||||
Assign
|
||||
<Icon name="check" /> Assign{selectedPost?.title ? ` — ${selectedPost.title}` : ''}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-8" style={{ flexWrap: 'wrap' }}>
|
||||
{i.sheet && (
|
||||
<div className="cell-sub" style={{ marginBottom: 14 }}>
|
||||
Imported from {i.sheet}{i.rowNumber != null ? ` · row ${i.rowNumber}` : ''}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-8" style={{ flexWrap: 'wrap', borderTop: '1px solid var(--border)', paddingTop: 16 }}>
|
||||
<button className="btn btn-primary" onClick={onImport} disabled={panelBusy || i.processing === 'Imported'}>
|
||||
<Icon name="user-plus" /> {i.processing === 'Imported' ? 'Imported' : 'Import Candidate'}
|
||||
</button>
|
||||
|
|
@ -2081,7 +2070,7 @@ function ApplicationDetail({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-8" style={{ flexWrap: 'wrap' }}>
|
||||
<div className="flex gap-8" style={{ flexWrap: 'wrap', borderTop: '1px solid var(--border)', paddingTop: 16 }}>
|
||||
<button className="btn btn-primary" onClick={onImport} disabled={panelBusy || i.processing === 'Imported'}>
|
||||
<Icon name="user-plus" /> {i.processing === 'Imported' ? 'Imported' : 'Import Candidate'}
|
||||
</button>
|
||||
|
|
|
|||
Loading…
Reference in New Issue