diff --git a/addons_extensions/hr_recruitment_web_app/controllers/web_recruitment.py b/addons_extensions/hr_recruitment_web_app/controllers/web_recruitment.py index a62a8e26a..e79cbb60b 100644 --- a/addons_extensions/hr_recruitment_web_app/controllers/web_recruitment.py +++ b/addons_extensions/hr_recruitment_web_app/controllers/web_recruitment.py @@ -23,7 +23,7 @@ class ATSController(http.Controller): @http.route('/myATS/page/', type='http', auth='user', website=True) def render_partial_content(self, page, **kwargs): - if page == "job_requests": + if page in ["job_requests","jobs"]: jobs = request.env['hr.job.recruitment'].search([], order='create_date desc') return request.render('hr_recruitment_web_app.job_list_partial_page', {'jobs': jobs}) elif page == "applicants": @@ -56,6 +56,17 @@ class ATSController(http.Controller): } ) + @http.route('/myATS/applicant/update_stage', type='json', auth='user') + def update_applicant_stage(self, applicant_id, stage_id, **kwargs): + try: + applicant = request.env['hr.applicant'].browse(int(applicant_id)) + if applicant.exists(): + applicant.write({'stage_id': int(stage_id)}) + return {'success': True} + return {'success': False, 'error': 'Applicant not found'} + except Exception as e: + return {'success': False, 'error': str(e)} + @http.route('/myATS/job/create', type='http', auth='user', methods=['POST'], csrf=False) def create_job_request(self, **post): try: diff --git a/addons_extensions/hr_recruitment_web_app/static/src/css/applicants.css b/addons_extensions/hr_recruitment_web_app/static/src/css/applicants.css index 9416f2c65..ac367b083 100644 --- a/addons_extensions/hr_recruitment_web_app/static/src/css/applicants.css +++ b/addons_extensions/hr_recruitment_web_app/static/src/css/applicants.css @@ -493,6 +493,71 @@ border: 1px solid var(--border-color) !important; box-shadow: 0 2px 5px var(--shadow-color) !important; } +/* Base button styling */ +.btn-stage { + position: relative; + min-width: 100px; + padding: 0.5rem 1rem; + margin: 0 2px; + border-radius: 4px; + font-size: 0.85rem; + font-weight: 500; + text-align: center; + transition: all 0.25s ease; + cursor: pointer; + border: 1px solid #ddd; + outline: none; +} +/* Current stage styling */ +.btn-stage-current { + background-color: #0d6efd; /* Primary blue */ + color: white; + border-color: #0d6efd; + box-shadow: 0 2px 5px rgba(13, 110, 253, 0.3); + font-weight: 600; +} +/* Other stage options */ +.btn-stage-option { + background-color: white; + color: #555; + border-color: #ddd; +} +/* Hover effects */ +.btn-stage-option:hover { + background-color: #f0f7ff; /* Very light blue */ + border-color: #0d6efd; + color: #0d6efd; +} + +.btn-stage-current:hover { + background-color: #0b5ed7; /* Slightly darker blue */ +} + +/* Active state */ +.btn-stage:active { + transform: translateY(1px); +} + +/* Focus state */ +.btn-stage:focus { + box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.25); +} + +/* Disabled state during loading */ +.btn-stage.processing { + opacity: 0.7; + pointer-events: none; +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + .btn-stage { + min-width: 80px; + padding: 0.4rem 0.6rem; + font-size: 0.8rem; + margin: 2px; + } +} \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/static/src/js/applicants.js b/addons_extensions/hr_recruitment_web_app/static/src/js/applicants.js index 65e995538..9a35041e5 100644 --- a/addons_extensions/hr_recruitment_web_app/static/src/js/applicants.js +++ b/addons_extensions/hr_recruitment_web_app/static/src/js/applicants.js @@ -248,20 +248,20 @@ function initApplicantsPage() { }); } // Close modal when clicking outside of it - applicantModal.addEventListener('click', function(e) { - if (e.target === applicantModal) { - applicantModal.classList.remove('show'); - setTimeout(() => { - applicantModal.style.display = 'none'; - }, 300); - document.body.style.overflow = ''; - } - }); +// applicantModal.addEventListener('click', function(e) { +// if (e.target === applicantModal) { +// applicantModal.classList.remove('show'); +// setTimeout(() => { +// applicantModal.style.display = 'none'; +// }, 300); +// document.body.style.overflow = ''; +// } +// }); // File Upload Handling const resumeUpload = document.getElementById('resume-upload'); const resumeDropzone = document.getElementById('resume-dropzone'); const resumePreview = document.getElementById('resume-preview'); - const resumePlaceholder = resumePreview.querySelector('.resume-preview-placeholder'); + const resumePlaceholder = document.querySelector('.resume-preview-placeholder'); const resumeIframe = document.getElementById('resume-iframe'); const resumeImage = document.getElementById('resume-image'); const unsupportedFormat = document.getElementById('unsupported-format'); diff --git a/addons_extensions/hr_recruitment_web_app/static/src/js/ats.js b/addons_extensions/hr_recruitment_web_app/static/src/js/ats.js index 77cb1b3e6..aca1abdd0 100644 --- a/addons_extensions/hr_recruitment_web_app/static/src/js/ats.js +++ b/addons_extensions/hr_recruitment_web_app/static/src/js/ats.js @@ -5,7 +5,6 @@ document.addEventListener("DOMContentLoaded", function () { initNavigation(); // Load default page based on URL hash or default to jobs - loadPage(window.location.hash || "#jobs"); }); /** @@ -47,6 +46,61 @@ function initTheme() { applyTheme(currentTheme === 'dark' ? 'light' : 'dark'); }); } + + document.querySelectorAll('.btn-stage').forEach(button => { + button.addEventListener('click', function() { + const container = this.closest('.stage-selector'); + const buttons = container.querySelectorAll('.btn-stage'); + const applicantId = container.dataset.applicantId; + const newStageId = this.dataset.stageId; + + // Visual feedback + buttons.forEach(btn => { + btn.classList.remove('btn-stage-current'); + btn.classList.add('btn-stage-option'); + }); + + this.classList.remove('btn-stage-option'); + this.classList.add('btn-stage-current', 'processing'); + + // AJAX call to update stage + fetch('/update_stage', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': getCSRFToken() + }, + body: JSON.stringify({ + applicant_id: applicantId, + stage_id: newStageId + }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + showNotification('Stage updated successfully!', 'success'); + } else { + throw new Error(data.error || 'Update failed'); + } + }) + .catch(error => { + console.error("Error:", error); + showNotification('Failed to update stage', 'danger'); + // Revert visual state if needed + }) + .finally(() => { + this.classList.remove('processing'); + }); + }); + }); + + function getCSRFToken() { + return document.querySelector('meta[name="csrf-token"]').content; + } + + function showNotification(message, type) { + // Your notification implementation + } // Watch for system theme changes window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { @@ -171,4 +225,5 @@ function initNavigation() { // Initial highlight highlightActiveMenu(); -} \ No newline at end of file +} + diff --git a/addons_extensions/hr_recruitment_web_app/static/src/js/candidates.js b/addons_extensions/hr_recruitment_web_app/static/src/js/candidates.js index 51b89010f..8ee5fe945 100644 --- a/addons_extensions/hr_recruitment_web_app/static/src/js/candidates.js +++ b/addons_extensions/hr_recruitment_web_app/static/src/js/candidates.js @@ -118,7 +118,7 @@ function initCandidatesPage() { const resumeUpload = document.getElementById('resume-upload'); const resumeDropzone = document.getElementById('resume-dropzone'); const resumePreview = document.getElementById('resume-preview'); - const resumePlaceholder = resumePreview.querySelector('.resume-preview-placeholder'); + const resumePlaceholder = document.querySelector('.resume-preview-placeholder'); const resumeIframe = document.getElementById('resume-iframe'); const resumeImage = document.getElementById('resume-image'); const unsupportedFormat = document.getElementById('unsupported-format'); @@ -161,15 +161,15 @@ function initCandidatesPage() { }); } - candidateModal.addEventListener('click', function(e) { - if (e.target === candidateModal) { - candidateModal.classList.remove('show'); - setTimeout(() => { - candidateModal.style.display = 'none'; - }, 300); - document.body.style.overflow = ''; - } - }); +// candidateModal.addEventListener('click', function(e) { +// if (e.target === candidateModal) { +// candidateModal.classList.remove('show'); +// setTimeout(() => { +// candidateModal.style.display = 'none'; +// }, 300); +// document.body.style.overflow = ''; +// } +// }); function formatUserOption(user) { if (!user.id) return user.text; diff --git a/addons_extensions/hr_recruitment_web_app/static/src/js/job_requests.js b/addons_extensions/hr_recruitment_web_app/static/src/js/job_requests.js index 0be23f0a6..a886cb8f6 100644 --- a/addons_extensions/hr_recruitment_web_app/static/src/js/job_requests.js +++ b/addons_extensions/hr_recruitment_web_app/static/src/js/job_requests.js @@ -1,5 +1,3 @@ -/** @odoo-module */ - // Define all your page initialization functions first function initJobListPage() { console.log("Job List Page JS Loaded"); diff --git a/addons_extensions/hr_recruitment_web_app/static/src/js/select2.main.js b/addons_extensions/hr_recruitment_web_app/static/src/js/select2.min.js similarity index 100% rename from addons_extensions/hr_recruitment_web_app/static/src/js/select2.main.js rename to addons_extensions/hr_recruitment_web_app/static/src/js/select2.min.js diff --git a/addons_extensions/hr_recruitment_web_app/views/applicants.xml b/addons_extensions/hr_recruitment_web_app/views/applicants.xml index 75fb4f418..b698500d4 100644 --- a/addons_extensions/hr_recruitment_web_app/views/applicants.xml +++ b/addons_extensions/hr_recruitment_web_app/views/applicants.xml @@ -243,6 +243,16 @@ +
+ +
diff --git a/addons_extensions/hr_recruitment_web_app/views/main.xml b/addons_extensions/hr_recruitment_web_app/views/main.xml index 706e827d7..811232f5e 100644 --- a/addons_extensions/hr_recruitment_web_app/views/main.xml +++ b/addons_extensions/hr_recruitment_web_app/views/main.xml @@ -28,13 +28,10 @@ - + - -