frotnedn and bnackend crashing check #31

Merged
ahmed.mujtaba merged 4 commits from RELIMIt into main 2026-08-28 13:23:38 +00:00
3 changed files with 18 additions and 27 deletions

View File

@ -42,7 +42,7 @@ import { companies, fmtDate, moneyK, pick } from '../data/seed'
/* Workflow order: learn (Overview, Resume, Documents) interview (Interview,
Forms, Feedback) track (Notes, Activity) audit (Timeline, History). */
const TABS = ['Overview', 'Resume', 'Documents', 'Interview', 'Forms', 'Feedback', 'Notes', 'Activity', 'Timeline', 'History']
const TABS = ['Overview', 'Resume', 'Interview', 'Forms', 'Feedback', 'Notes', 'Activity', 'Timeline', 'History']
// Forward progression for the live Advance button. Rejected has no next stage.
const KANBAN_ORDER = ['Shortlist', 'Screening', 'Assessment', 'Interview', 'Offer', 'Hired']
const LABEL = { fontSize: 12, color: 'var(--text-3)', fontWeight: 600, textTransform: 'uppercase', marginBottom: 8 }
@ -673,20 +673,13 @@ export default function CandidateProfile({
function ResumeTab({ live }) {
const source = live.documents?.[0]?.name
const resumeKey = s3Api.resumeKeyFrom(live)
if (!live.resume_text) {
if (!s3Api.canOpen(resumeKey)) {
return (
<>
{s3Api.canOpen(resumeKey) && (
<div className="flex gap-8" style={{ flexWrap: 'wrap', marginBottom: 14 }}>
<OpenResumeButton filePath={resumeKey} />
</div>
)}
<EmptyState icon="file" title="No résumé text">
{source
? `${source} is attached but has not been parsed yet — run the match to extract it.`
: 'This candidate applied without an attachment we could read.'}
</EmptyState>
</>
<EmptyState icon="file" title="No résumé on file">
{source
? `${source} is attached but is not stored in S3, so it cannot be opened here.`
: 'This candidate applied without an attachment we could open.'}
</EmptyState>
)
}
return (
@ -694,15 +687,11 @@ function ResumeTab({ live }) {
<div className="card-body">
<h3 style={{ marginBottom: 4 }}>{live.name}</h3>
<p className="text-muted">
{source ? `Extracted from ${source}` : 'Extracted from the application email'}
{source ? `Original CV — ${source}` : 'Original CV from the application'}
</p>
{s3Api.canOpen(resumeKey) && (
<div className="flex gap-8" style={{ flexWrap: 'wrap', margin: '10px 0 4px' }}>
<OpenResumeButton filePath={resumeKey} />
</div>
)}
<div className="divider" />
<div className="text-sm" style={{ whiteSpace: 'pre-wrap', lineHeight: 1.6 }}>{live.resume_text}</div>
<div className="flex gap-8" style={{ flexWrap: 'wrap', margin: '10px 0 0' }}>
<OpenResumeButton filePath={resumeKey} />
</div>
</div>
</div>
)

View File

@ -672,10 +672,12 @@ function MatchingWorkspace({
</div>
)}
<div className="fw-600" style={{ marginBottom: 6 }}>Resume text</div>
<pre className="resume-thumb is-full">
{resumeText || 'Resume text not extracted yet.'}
</pre>
<div className="fw-600" style={{ marginBottom: 6 }}>CV</div>
{s3Api.canOpen(resumeKey) ? (
<OpenResumeButton filePath={resumeKey} />
) : (
<p className="text-muted text-sm">No CV file stored in S3 for this application.</p>
)}
</div>
<div role="radiogroup" aria-label="Suggested roles" style={{ flex: '0 1 360px', minWidth: 260 }}>

View File

@ -270,7 +270,7 @@ export default function TalentPool() {
{c.aiScore != null && <ScoreChip score={c.aiScore} />}
</div>
<div className="k-tags" style={{ marginBottom: 12 }}>
{c.skills.slice(0, 4).map((s) => <span className="tag" key={s}>{s}</span>)}
{(c.skills ?? []).slice(0, 4).map((s) => <span className="tag" key={s}>{s}</span>)}
</div>
<div className="divider" style={{ margin: '12px 0' }} />
<div className="flex items-center" style={{ justifyContent: 'space-between' }}>