Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy-eks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Frontend → ArgoCD Deploy

on:
push:
branches: ["main"]
branches: ["feature/ats2"]
workflow_dispatch:

env:
Expand Down
8 changes: 8 additions & 0 deletions src/pages/auth/LoginPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,17 @@ function LoginPage() {
return (
<div className="login-page">
<div className="login-container">

{/* 제목 */}
<h1 className="login-title">
로그인
</h1>

{/* 설명 문구 추가 */}
<p className="login-description">
사번과 비밀번호를 입력해주세요.
</p>

<form
className="login-form"
onSubmit={handleLogin}
Expand Down Expand Up @@ -79,6 +86,7 @@ function LoginPage() {
로그인
</button>
</form>

</div>
</div>
);
Expand Down
41 changes: 33 additions & 8 deletions src/pages/resume/ResumePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ function parseAnalysisResultJson(resultJson) {
}
}

/** 종합 점수 막대 색 (구간별) */
function scoreBarTierClass(score) {
if (score < 50) return 'resume-ai__score-fill--tier-bad';
if (score < 70) return 'resume-ai__score-fill--tier-fair';
if (score < 85) return 'resume-ai__score-fill--tier-good';
return 'resume-ai__score-fill--tier-great';
}

function mergeAnalyzeIntoRow(row, analyzeResult) {
const a = analyzeResult?.analysis;
if (!a) return row;
Expand Down Expand Up @@ -153,14 +161,14 @@ export default function ResumePage() {
useEffect(() => {
if (!analyzeModalRow) return;
const onKey = (e) => {
if (e.key === 'Escape') {
if (e.key === 'Escape' && analyzeBusyId !== analyzeModalRow.applicantId) {
setAnalyzeModalRow(null);
setAnalyzeJd('');
}
};
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, [analyzeModalRow]);
}, [analyzeModalRow, analyzeBusyId]);

const kpis = useMemo(() => {
const total = rows.length;
Expand Down Expand Up @@ -573,11 +581,19 @@ export default function ResumePage() {
<td>
<button
type="button"
className="resume-ai__btn-accent"
className="resume-ai__btn-accent resume-ai__btn-accent--with-spinner"
disabled={!row.resumeAttached || busy}
onClick={() => openAnalyzeModal(row)}
aria-busy={busy}
>
{busy ? '분석중…' : '분석'}
{busy ? (
<span
className="resume-ai__spinner-donut resume-ai__spinner-donut--sm"
aria-hidden="true"
/>
) : (
'분석'
)}
</button>
</td>
</tr>
Expand Down Expand Up @@ -754,7 +770,7 @@ export default function ResumePage() {
aria-valuemax={100}
>
<div
className="resume-ai__score-fill"
className={`resume-ai__score-fill ${scoreBarTierClass(sc)}`}
style={{ width: `${sc}%` }}
/>
</div>
Expand Down Expand Up @@ -851,6 +867,7 @@ export default function ResumePage() {
className="resume-ai__modal-backdrop"
role="presentation"
onClick={(e) => {
if (analyzeBusyId === analyzeModalRow?.applicantId) return;
if (e.target === e.currentTarget) closeAnalyzeModal();
}}
>
Expand Down Expand Up @@ -895,11 +912,19 @@ export default function ResumePage() {
onClick={confirmAnalyze}
disabled={analyzeBusyId === analyzeModalRow.applicantId}
>
{analyzeBusyId === analyzeModalRow.applicantId
? '분석 중…'
: '분석 실행'}
분석 실행
</button>
</div>
{analyzeBusyId === analyzeModalRow.applicantId ? (
<div
className="resume-ai__modal-busy"
role="status"
aria-live="polite"
>
<span className="resume-ai__spinner-donut" aria-hidden="true" />
<span className="resume-ai__sr-only">Resume analysis in progress</span>
</div>
) : null}
</div>
</div>
) : null}
Expand Down
111 changes: 92 additions & 19 deletions src/pages/resume/resumeAi.css
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,15 @@
box-shadow: none;
}

.resume-ai__btn-accent--with-spinner {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 56px;
min-height: 36px;
vertical-align: middle;
}

/* ----- 패널(목록·상세): 전체 폭 카드 ----- */

.resume-ai .panel {
Expand Down Expand Up @@ -523,6 +532,7 @@
}

.resume-ai__modal {
position: relative;
width: 100%;
max-width: 520px;
max-height: min(90vh, 640px);
Expand All @@ -534,6 +544,51 @@
padding: 26px 28px 24px;
}

.resume-ai__modal-busy {
position: absolute;
inset: 0;
z-index: 3;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 14px;
border-radius: inherit;
background: rgba(255, 255, 255, 0.88);
backdrop-filter: blur(3px);
}

.resume-ai__spinner-donut {
box-sizing: border-box;
width: 52px;
height: 52px;
flex-shrink: 0;
border-radius: 50%;
border: 4px solid #e8edf3;
border-top-color: var(--resume-ai-accent);
border-right-color: #fb923c;
animation: resume-ai-spin 0.72s linear infinite;
}

.resume-ai__spinner-donut--sm {
width: 20px;
height: 20px;
border-width: 2px;
animation-duration: 0.65s;
}

.resume-ai__sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}

.resume-ai__modal h3 {
margin: 0 0 6px;
font-size: 20px;
Expand Down Expand Up @@ -809,7 +864,7 @@

.resume-ai__section-title {
margin: 0 0 12px;
font-size: 13px;
font-size: 15px;
font-weight: 800;
color: var(--resume-ai-text);
letter-spacing: -0.02em;
Expand Down Expand Up @@ -946,20 +1001,20 @@ button.resume-ai__icon-btn--link {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 8px;
font-size: 13px;
margin-bottom: 10px;
font-size: 15px;
font-weight: 600;
color: var(--resume-ai-muted);
}

.resume-ai__score-head strong {
font-size: 18px;
font-size: 22px;
font-weight: 800;
color: var(--resume-ai-text);
}

.resume-ai__score-track {
height: 10px;
height: 12px;
border-radius: 999px;
background: #e2e8f0;
overflow: hidden;
Expand All @@ -969,15 +1024,33 @@ button.resume-ai__icon-btn--link {
height: 100%;
border-radius: inherit;
background: linear-gradient(90deg, #fb923c, #ea580c);
transition: width 0.35s ease;
transition:
width 0.35s ease,
background 0.25s ease;
}

.resume-ai__score-fill--tier-bad {
background: linear-gradient(90deg, #fca5a5, #dc2626);
}

.resume-ai__score-fill--tier-fair {
background: linear-gradient(90deg, #fdba74, #ea580c);
}

.resume-ai__score-fill--tier-good {
background: linear-gradient(90deg, #bef264, #65a30d);
}

.resume-ai__score-fill--tier-great {
background: linear-gradient(90deg, #4ade80, #15803d);
}

.resume-ai__summary-box {
padding: 14px 16px;
font-size: 14px;
line-height: 1.65;
padding: 18px 20px;
font-size: 16px;
line-height: 1.72;
font-weight: 500;
color: #334155;
color: #1e293b;
background: #fafaf9;
border: 1px solid var(--resume-ai-border);
border-radius: 12px;
Expand All @@ -991,30 +1064,30 @@ button.resume-ai__icon-btn--link {
}

.resume-ai__analysis-block {
margin-top: 18px;
margin-top: 22px;
}

.resume-ai__analysis-block-title {
margin: 0 0 10px;
padding-bottom: 8px;
margin: 0 0 12px;
padding-bottom: 10px;
border-bottom: 2px solid var(--resume-ai-accent-border);
font-size: 14px;
font-size: 18px;
font-weight: 800;
color: var(--resume-ai-text);
letter-spacing: -0.02em;
}

.resume-ai__bullet-list {
margin: 0;
padding-left: 1.2rem;
font-size: 14px;
line-height: 1.65;
padding-left: 1.35rem;
font-size: 16px;
line-height: 1.72;
font-weight: 500;
color: #334155;
color: #1e293b;
}

.resume-ai__bullet-list li {
margin-bottom: 8px;
margin-bottom: 12px;
}

.resume-ai__bullet-list li:last-child {
Expand Down
Loading
Loading