refactor: remove Requirements page — superseded by Batches

This commit is contained in:
root
2026-07-25 09:54:36 +00:00
parent 0c64a4679f
commit 1dac6df6e4
2 changed files with 1 additions and 200 deletions

View File

@@ -17,7 +17,6 @@ document.querySelectorAll('.nav-link').forEach(link => {
if (page === 'dashboard') loadDashboard();
if (page === 'candidates') loadCandidates();
if (page === 'templates') loadCarboneTemplates();
if (page === 'requirements') loadRequirements();
if (page === 'generated') loadGeneratedCVs();
if (page === 'batches') loadBatches();
});
@@ -343,194 +342,6 @@ async function deleteTemplate(id) {
loadTemplates();
}
// ============================================================
// REQUIREMENTS
// ============================================================
async function loadRequirements() {
const data = await api('/api/requirements');
const list = document.getElementById('requirements-list');
if (!data.requirements.length) {
list.innerHTML = '<p class="text-muted">No requirements yet. Create one to start matching candidates.</p>';
return;
}
list.innerHTML = data.requirements.map(r => `
<div class="card">
<div class="flex-between">
<div>
<strong>${r.title}</strong>
${r.customer_name ? '<span class="text-muted"> · ' + r.customer_name + '</span>' : ''}
<div class="text-muted text-sm mt-8">${r.description || ''}</div>
<div class="text-sm mt-8">${(r.requirements || []).length} position(s) requested</div>
</div>
<div class="flex gap-8">
<button class="btn btn-sm" onclick="viewRequirement('${r.id}')">View</button>
<button class="btn btn-sm btn-outline" onclick="matchRequirement('${r.id}')">Match</button>
<button class="btn btn-sm btn-green" onclick="generateForRequirement('${r.id}')">Generate CVs</button>
<button class="btn btn-sm btn-danger" onclick="deleteRequirement('${r.id}')">Delete</button>
</div>
</div>
</div>
`).join('');
}
function showRequirementModal() {
const body = `
<div class="form-group">
<label>Request Title</label>
<input type="text" id="req-title" placeholder="e.g. Q3 2026 Staff Augmentation">
</div>
<div class="form-group">
<label>Customer Name</label>
<input type="text" id="req-customer" placeholder="Client name">
</div>
<div class="form-group">
<label>Description</label>
<textarea id="req-desc" placeholder="Overall description of the requirement"></textarea>
</div>
<div class="form-group">
<label>Positions Required (JSON)</label>
<p class="text-muted text-sm mb-16">Define each position with required skills and years of experience.</p>
<textarea id="req-positions" style="min-height:300px;font-family:monospace;font-size:13px" placeholder='[
{
"position_title": "Senior .NET Developer",
"quantity": 2,
"experience_years": 5,
"skills": [
{"name": "C#", "min_years": 4, "required": true},
{"name": ".NET Core", "min_years": 3, "required": true},
{"name": "Azure", "min_years": 2, "required": false}
],
"education": "Bachelor degree in Computer Science or related",
"description": "Backend developer with cloud experience"
},
{
"position_title": "Frontend Developer",
"quantity": 1,
"experience_years": 3,
"skills": [
{"name": "React", "min_years": 2, "required": true},
{"name": "TypeScript", "min_years": 2, "required": true}
]
}
]'></textarea>
</div>
<button class="btn" onclick="createRequirement()">Create Requirement</button>
`;
showModal(body, 'Create Requirement Request');
}
async function createRequirement() {
const positions = JSON.parse(document.getElementById('req-positions').value || '[]');
await api('/api/requirements', 'POST', {
title: document.getElementById('req-title').value,
customer_name: document.getElementById('req-customer').value,
description: document.getElementById('req-desc').value,
requirements: positions
});
closeModal();
toast('Requirement created');
loadRequirements();
}
async function viewRequirement(id) {
const data = await api('/api/requirements/' + id);
const positions = data.requirements || [];
const body = `
<h2>${data.title}</h2>
${data.customer_name ? '<p class="text-muted">Customer: ' + data.customer_name + '</p>' : ''}
${data.description ? '<p class="mt-8">' + data.description + '</p>' : ''}
<h3 style="margin-top:20px">Positions (${positions.length})</h3>
${positions.map((p, i) => `
<div class="req-position mt-16">
<strong>${p.position_title || 'Position ' + (i+1)}</strong>
${p.quantity ? '<span class="badge badge-blue">Qty: ' + p.quantity + '</span>' : ''}
${p.experience_years ? '<span class="badge badge-orange">Min ' + p.experience_years + ' yrs</span>' : ''}
${p.description ? '<p class="text-sm mt-8">' + p.description + '</p>' : ''}
${(p.skills || []).map(s => `
<div class="text-sm" style="margin:4px 0">
${s.required ? '🔒' : '⚪'} ${s.name} ${s.min_years ? '(min ' + s.min_years + ' yrs)' : ''}
</div>
`).join('')}
</div>
`).join('')}
${data.generated_cvs && data.generated_cvs.length ? `
<h3 style="margin-top:20px">Generated CVs (${data.generated_cvs.length})</h3>
${data.generated_cvs.map(g => `
<div class="skill-row">
<span>${g.position_title || 'N/A'}${g.first_name || ''} ${g.last_name || ''}</span>
<span class="badge badge-${g.status === 'approved' ? 'green' : g.status === 'draft' ? 'orange' : 'red'}">${g.status}</span>
</div>
`).join('')}
` : ''}
`;
showModal(body, 'Requirement Details');
}
async function matchRequirement(id) {
const list = document.getElementById('requirements-list');
// Show loading
const oldHTML = list.innerHTML;
list.innerHTML = '<div class="loading"><span class="spinner"></span> Matching candidates with AI... this may take a while</div>';
try {
const data = await api('/api/requirements/' + id + '/match', 'POST', {});
const results = data.matches.filter(m => !m.error);
results.sort((a, b) => (b.match_score || 0) - (a.match_score || 0));
const body = `
<h2>Match Results</h2>
<p class="text-muted">${results.length} candidates matched</p>
<div style="margin-top:16px">
${results.map(m => `
<div class="match-item">
<div>
<strong>${m.candidate_name || 'Unknown'}</strong>
<div class="text-sm text-muted">${m.position_title || ''}</div>
<div class="text-sm">
Match: ${m.matching_skills?.join(', ') || 'none'} |
Missing: ${m.missing_skills?.join(', ') || 'none'}
</div>
<div class="text-sm text-muted mt-8">${m.reasoning || ''}</div>
</div>
<div class="match-score" style="color: ${m.match_score >= 70 ? 'var(--green)' : m.match_score >= 40 ? 'var(--orange)' : 'var(--red)'}">${m.match_score || 0}%</div>
</div>
`).join('')}
</div>
`;
showModal(body, 'Match Results');
list.innerHTML = oldHTML;
} catch(e) {
list.innerHTML = oldHTML;
toast('Match failed: ' + e.message, 'error');
}
}
async function generateForRequirement(id) {
if (!confirm('Generate tailored CVs for all parsed candidates? This may take several minutes.')) return;
const list = document.getElementById('requirements-list');
const oldHTML = list.innerHTML;
list.innerHTML = '<div class="loading"><span class="spinner"></span> Generating CVs with AI... this may take several minutes</div>';
try {
const data = await api('/api/requirements/' + id + '/generate', 'POST', {});
closeModal();
list.innerHTML = oldHTML;
toast(`Generated ${data.generated.length} CVs`);
loadGeneratedCVs();
document.querySelector('[data-page="generated"]').click();
} catch(e) {
list.innerHTML = oldHTML;
toast('Generation failed: ' + e.message, 'error');
}
}
async function deleteRequirement(id) {
if (!confirm('Delete this requirement and all generated CVs?')) return;
await api('/api/requirements/' + id, 'DELETE');
toast('Requirement deleted');
loadRequirements();
}
// ============================================================
// GENERATED CVs
// ============================================================