From e88f7da488587fb1ef33c4cb40148c75414db9ce Mon Sep 17 00:00:00 2001 From: Pranay Date: Thu, 7 Aug 2025 12:43:43 +0530 Subject: [PATCH] recruitment web first commit --- .../hr_recruitment_web_app/__init__.py | 2 + .../hr_recruitment_web_app/__manifest__.py | 50 + .../controllers/__init__.py | 1 + .../controllers/web_recruitment.py | 1294 ++ .../hr_recruitment_web_app/models/__init__.py | 2 + .../models/recruitment_doc_upload_wizard.py | 216 + .../models/res_config_settings.py | 7 + .../security/ir.model.access.csv | 2 + .../static/description/banner.png | Bin 0 -> 76312 bytes .../static/description/banner_copy.png | Bin 0 -> 58167 bytes .../static/src/css/applicants.css | 498 + .../static/src/css/ats.css | 217 + .../static/src/css/candidate.css | 667 + .../static/src/css/colors.css | 66 + .../static/src/css/content.css | 1055 ++ .../static/src/css/jd.css | 1122 ++ .../static/src/css/list.css | 708 + .../static/src/css/select2.min.css | 1 + .../static/src/img/logo.jpeg | Bin 0 -> 121212 bytes .../static/src/js/applicants.js | 850 ++ .../static/src/js/ats.js | 46 + .../static/src/js/candidates.js | 608 + .../static/src/js/job_requests.js | 1631 +++ .../static/src/js/jquery.js | 10993 ++++++++++++++++ .../static/src/js/select2.main.js | 5 + .../static/src/js/sortable.min.js | 2 + .../src/libs/ckeditor/build/ckeditor.js | 7 + .../views/applicants.xml | 1121 ++ .../views/candidate.xml | 597 + .../views/hr_candidate.xml | 13 + .../hr_recruitment_web_app/views/jd.xml | 864 ++ .../hr_recruitment_web_app/views/main.xml | 64 + .../views/recruitment.xml | 19 + .../views/recruitmnet_doc_upload_wizard.xml | 50 + .../views/res_config_view.xml | 24 + 35 files changed, 22802 insertions(+) create mode 100644 addons_extensions/hr_recruitment_web_app/__init__.py create mode 100644 addons_extensions/hr_recruitment_web_app/__manifest__.py create mode 100644 addons_extensions/hr_recruitment_web_app/controllers/__init__.py create mode 100644 addons_extensions/hr_recruitment_web_app/controllers/web_recruitment.py create mode 100644 addons_extensions/hr_recruitment_web_app/models/__init__.py create mode 100644 addons_extensions/hr_recruitment_web_app/models/recruitment_doc_upload_wizard.py create mode 100644 addons_extensions/hr_recruitment_web_app/models/res_config_settings.py create mode 100644 addons_extensions/hr_recruitment_web_app/security/ir.model.access.csv create mode 100644 addons_extensions/hr_recruitment_web_app/static/description/banner.png create mode 100644 addons_extensions/hr_recruitment_web_app/static/description/banner_copy.png create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/css/applicants.css create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/css/ats.css create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/css/candidate.css create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/css/colors.css create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/css/content.css create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/css/jd.css create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/css/list.css create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/css/select2.min.css create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/img/logo.jpeg create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/js/applicants.js create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/js/ats.js create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/js/candidates.js create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/js/job_requests.js create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/js/jquery.js create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/js/select2.main.js create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/js/sortable.min.js create mode 100644 addons_extensions/hr_recruitment_web_app/static/src/libs/ckeditor/build/ckeditor.js create mode 100644 addons_extensions/hr_recruitment_web_app/views/applicants.xml create mode 100644 addons_extensions/hr_recruitment_web_app/views/candidate.xml create mode 100644 addons_extensions/hr_recruitment_web_app/views/hr_candidate.xml create mode 100644 addons_extensions/hr_recruitment_web_app/views/jd.xml create mode 100644 addons_extensions/hr_recruitment_web_app/views/main.xml create mode 100644 addons_extensions/hr_recruitment_web_app/views/recruitment.xml create mode 100644 addons_extensions/hr_recruitment_web_app/views/recruitmnet_doc_upload_wizard.xml create mode 100644 addons_extensions/hr_recruitment_web_app/views/res_config_view.xml diff --git a/addons_extensions/hr_recruitment_web_app/__init__.py b/addons_extensions/hr_recruitment_web_app/__init__.py new file mode 100644 index 000000000..19240f4ea --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/__init__.py @@ -0,0 +1,2 @@ +from . import controllers +from . import models \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/__manifest__.py b/addons_extensions/hr_recruitment_web_app/__manifest__.py new file mode 100644 index 000000000..bd4406087 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/__manifest__.py @@ -0,0 +1,50 @@ +# __manifest__.py +{ + 'name': 'Recruitment web app', + 'version': '18.0', + 'category': 'Tools', + "author": "FTPROTECH PVT LTD", + "website": "https://www.ftprotech.in/", + 'summary': 'Extracts the information of candidates from the resumes and creates applications in recruitment.', + 'depends': ['base', 'web', 'web_editor', 'sms', 'hr_recruitment', 'hr_recruitment_extended', 'base_setup','website_hr_recruitment_extended'], + + 'assets': { + 'web.assets_frontend': [ + 'hr_recruitment_web_app/static/lib/ckeditor/ckeditor.js', + + 'hr_recruitment_web_app/static/src/js/ats.js', + 'hr_recruitment_web_app/static/src/js/job_requests.js', + 'hr_recruitment_web_app/static/src/js/applicants.js', + 'hr_recruitment_web_app/static/src/css/candidate.css', + # + # + 'hr_recruitment_web_app/static/src/css/colors.css', + 'hr_recruitment_web_app/static/src/css/ats.css', + 'hr_recruitment_web_app/static/src/css/list.css', + 'hr_recruitment_web_app/static/src/css/content.css', + 'hr_recruitment_web_app/static/src/css/applicants.css', + 'hr_recruitment_web_app/static/src/css/jd.css', + # 'hr_recruitment_web_application/static/src/css/applicants_details.css', + # 'hr_recruitment_web_application/static/src/css/ats_candidate.css', + ], + }, + + 'data': [ + "security/ir.model.access.csv", + 'views/recruitmnet_doc_upload_wizard.xml', + 'views/hr_candidate.xml', + 'views/res_config_view.xml', + 'views/main.xml', + 'views/recruitment.xml', + 'views/jd.xml', + 'views/applicants.xml', + 'views/candidate.xml', + + ], + 'images': ['static/description/banner.png'], + 'external_dependencies': { + 'python': ['pytesseract', 'pdf2image', 'pypdf'], + }, + 'installable': True, + 'application': True, +} diff --git a/addons_extensions/hr_recruitment_web_app/controllers/__init__.py b/addons_extensions/hr_recruitment_web_app/controllers/__init__.py new file mode 100644 index 000000000..72a8479c9 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/controllers/__init__.py @@ -0,0 +1 @@ +from . import web_recruitment \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/controllers/web_recruitment.py b/addons_extensions/hr_recruitment_web_app/controllers/web_recruitment.py new file mode 100644 index 000000000..a62a8e26a --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/controllers/web_recruitment.py @@ -0,0 +1,1294 @@ +import os +import tempfile + +from odoo import http +from odoo.http import request, Response, content_disposition +import json +import requests +import re +import base64 + + + +class ATSController(http.Controller): + + @http.route('/myATS', type='http', auth='user', website=True) + def index(self, **kw): + return request.render('hr_recruitment_web_app.ats_main_home_page') + + @http.route('/myATS/data', type='json', auth='user') + def my_data(self): + records = request.env['res.partner'].search([], limit=5) + return [{'name': r.name} for r in records] + + @http.route('/myATS/page/', type='http', auth='user', website=True) + def render_partial_content(self, page, **kwargs): + if page == "job_requests": + 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": + applicants = request.env['hr.applicant'].search([], order='create_date desc') + return request.render('hr_recruitment_web_app.applicants_list_partial_page', {'applicants': applicants}) + elif page == "candidates": + candidates = request.env['hr.candidate'].search([], order='create_date desc') + return request.render('hr_recruitment_web_app.candidates_list_partial_page', {'candidates': candidates}) + return "

Page Not Found

" + + @http.route('/myATS/job/detail/', type='http', auth='user', csrf=False) + def job_detail_ajax(self, job_id): + job = request.env['hr.job.recruitment'].sudo().browse(job_id) + if not job.exists(): + return request.not_found() + + job_categories = request.env['job.category'].sudo().search([]) + job_ids = request.env['hr.job'].sudo().search([]) + progress = 0 + if job.no_of_recruitment: + progress = min(100, (job.no_of_hired_employee / job.no_of_recruitment) * 100) + + return request.env['ir.ui.view']._render_template( + 'hr_recruitment_web_app.job_detail_partial', + { + 'job': job, + 'job_ids': job_ids, + 'job_categories': job_categories, + 'progress': progress, # 👈 add this + } + ) + + @http.route('/myATS/job/create', type='http', auth='user', methods=['POST'], csrf=False) + def create_job_request(self, **post): + try: + # Get the JSON data from the request body + try: + data = json.loads(request.httprequest.data) + except ValueError: + return Response( + json.dumps({ + 'success': False, + 'error': 'Invalid JSON data' + }), + content_type='application/json', + status=400 + ) + # Prepare vals dictionary for job creation + vals = {} + + job_requests = request.env['hr.job.recruitment'].sudo().search( + [('recruitment_sequence', '=', str(data['sequence']))]) + if job_requests: + return Response(json.dumps({ + 'success': False, + 'error': '\n\nJD creation Failed Duplicate Sequence,\n\n(%s) Already Exists\n\nCreated by: "%s"' % ( + str(data['sequence']), job_requests.create_uid.display_name), + }), + content_type='application/json', + ) + # Add only if value exists + if data.get('position_id'): + vals['job_id'] = int(data['position_id']) + + if 'sequence' in data: + vals['recruitment_sequence'] = data['sequence'] + + if data.get('category'): + vals['job_category'] = int(data['category']) + + if 'priority' in data: + vals['job_priority'] = data.get('priority', 'medium') + + if data.get('employment_type_id'): + vals['contract_type_id'] = int(data['employment_type_id']) + + if 'no_of_positions' in data: + vals['no_of_recruitment'] = int(data.get('no_of_positions', 1)) + + if 'description' in data: + vals['description'] = data.get('description', '') + + if data.get('primary_recruiter_id'): + vals['user_id'] = int(data['primary_recruiter_id']) + else: + vals['user_id'] = request.env.user.id + + if data.get('client_company_id'): + vals['address_id'] = int(data['client_company_id']) + + if data.get('client_id'): + vals['requested_by'] = int(data['client_id']) + + if data.get('target_from'): + vals['target_from'] = data['target_from'] + + if data.get('target_to'): + vals['target_to'] = data['target_to'] + + if 'eligible_submissions' in data: + vals['no_of_eligible_submissions'] = int(data.get('eligible_submissions', 0)) + + if 'budget' in data: + vals['budget'] = data.get('budget', 0) or 'N/A' + + if 'work_type' in data: + vals['recruitment_type'] = data.get('work_type', 'internal') + + if 'experience_id' in data: + vals['experience'] = int(data.get('experience_id', 0)) + + vals['create_uid'] = request.env.user.id + # Create the job position + job = request.env['hr.job.recruitment'].sudo().create(vals) + + # Handle many2many fields + if data.get('primary_skill_ids'): + job.write({ + 'skill_ids': [(6, 0, [int(id) for id in data['primary_skill_ids']])] + }) + + if data.get('secondary_skill_ids'): + job.write({ + 'secondary_skill_ids': [(6, 0, [int(id) for id in data['secondary_skill_ids']])] + }) + + if data.get('location_ids'): + job.write({ + 'locations': [(6, 0, [int(id) for id in data['location_ids']])] + }) + + if data.get('stage_ids'): + job.write({ + 'recruitment_stage_ids': [(6, 0, [int(id) for id in data['stage_ids']])] + }) + + if data.get('secondary_recruiter_ids'): + job.write({ + 'interviewer_ids': [(6, 0, [int(id) for id in data['secondary_recruiter_ids']])] + }) + # Return proper JSON response + return Response( + json.dumps({ + 'success': True, + 'job_id': job.id, + 'message': 'JD created successfully' + }), + content_type='application/json', + ) + + except Exception as e: + error_msg = str(e) + print("Job creation error: %s", error_msg) # Add this line + return Response( + json.dumps({ + 'success': False, + 'error': error_msg, + 'message': 'Failed to create JD', + }), + content_type='application/json', + status=400 if 'duplicate key' in error_msg else 500 + ) + + @http.route('/myATS/job/save', type='http', auth='user', methods=['POST'], csrf=False) + def save_job_details(self, **post): + try: + # Parse the JSON data from the request body + data = json.loads(request.httprequest.data) + id = int(data.get('id', 0)) + + if not id: + return Response( + json.dumps({'success': False, 'error': 'Invalid job ID'}), + content_type='application/json', + status=400 + ) + + job = request.env['hr.job.recruitment'].sudo().browse(id) + if not job.exists(): + return Response( + json.dumps({'success': False, 'error': 'Job not found'}), + content_type='application/json', + status=404 + ) + + vals = { + 'recruitment_sequence': data.get('job_sequence', ''), + 'job_id': int(data.get('job_id', 0)), + 'job_category': int(data.get('category', 0)), + 'description': data.get('description', ''), + } + + job.write(vals) + + return Response( + json.dumps({'success': True}), + content_type='application/json' + ) + + except Exception as e: + return Response( + json.dumps({'success': False, 'error': str(e)}), + content_type='application/json', + status=500 + ) + + @http.route('/get_client_companies', type='json', auth='public', csrf=False) + def get_client_companies(self): + # Safely access the JSON body from the request + data = request.httprequest.get_json(force=True, silent=True) or {} + + work_type = data.get('type') + domain = [('is_company', '=', True)] + if work_type: + domain.append(('contact_type', '=', work_type)) + + companies = request.env['res.partner'].sudo().search(domain) + return [{'id': c.id, 'name': c.name} for c in companies] + + @http.route('/get_clients_by_company', type='json', auth='public', csrf=False) + def get_clients_by_company(self): + data = request.httprequest.get_json(force=True, silent=True) or {} + company_id = data.get('company_id') + type = data.get('type') + if not company_id and not type: + return [] + domain = [] + if type: + domain.append(('contact_type', '=', type)) + if company_id: + domain.append('|') + domain.append(('parent_id', '=', int(company_id))) + domain.append(('id', '=', int(company_id))) + + clients = request.env['res.partner'].sudo().search(domain) + + return [{'id': c.id, 'name': c.name, 'company_id': c.parent_id.id if c.parent_id else request.env.company.id} + for c in clients] + + @http.route('/jd/upload', type='http', auth='user', methods=['POST'], csrf=False) + def upload_jd(self, **post): + try: + file = http.request.httprequest.files.get('file') + if not file: + return http.Response( + json.dumps({"error": "No file uploaded"}), + status=400, + content_type='application/json' + ) + + # Extract text from file + text_content = self._extract_text_from_file(file) + if not text_content: + return http.Response( + json.dumps({"error": "Could not extract text from file"}), + status=400, + content_type='application/json' + ) + + # Get structured JD data + jd_data = self._get_jd_data_from_text(text_content) + print(jd_data) + if not jd_data: + return http.Response( + json.dumps({"error": "Failed to parse JD data"}), + status=400, + content_type='application/json' + ) + + # Process skills and locations + processed_data = self._process_skills_and_locations(jd_data) + + return http.Response( + json.dumps(processed_data), + status=200, + content_type='application/json' + ) + + except Exception as e: + print("JD Upload Error: %s", str(e)) + return http.Response( + json.dumps({"error": str(e)}), + status=500, + content_type='application/json' + ) + + def _process_skills_and_locations(self, jd_data): + """Create missing skills and locations, return IDs with names""" + env = http.request.env + + # Process skills + skill_type = request.env.ref('hr_recruitment_extended.hr_skill_type_additional') + primary_skills = [] + secondary_skills = [] + + if jd_data.get('primary_skills'): + for skill_name in jd_data['primary_skills']: + skill = env['hr.skill'].search([('name', 'ilike', skill_name)], limit=1) + if not skill: + skill = request.env['hr.skill'].create({ + 'name': skill_name, + 'skill_type_id': skill_type.id + }) + primary_skills.append({ + 'id': skill.id, + 'name': skill.name + }) + + if jd_data.get('secondary_skills'): + for skill_name in jd_data['secondary_skills']: + skill = request.env['hr.skill'].search([('name', 'ilike', skill_name)], limit=1) + if not skill: + skill = request.env['hr.skill'].create({ + 'name': skill_name, + 'skill_type_id': skill_type.id + }) + secondary_skills.append({ + 'id': skill.id, + 'name': skill.name + }) + + # Process locations + locations = [] + if jd_data.get('locations'): + for loc_name in jd_data['locations']: + location = request.env['hr.location'].search([('location_name', 'ilike', loc_name)], limit=1) + if not location: + location = request.env['hr.location'].create({ + 'location_name': loc_name + }) + locations.append({ + 'id': location.id, + 'name': location.location_name + }) + + # Process experience + experience_id = None + experience_name = None + if jd_data.get('required_experience'): + try: + # Extract numeric value from experience string (e.g., "4+" -> 4) + exp_years = int(re.search(r'\d+', jd_data['required_experience']).group()) + + # Get all experiences ordered by range + experiences = env['candidate.experience'].search([], order='id') + + # Find the most appropriate experience range + for exp in experiences: + # Parse the range from display name (format: "eX (Y - Z years)" or similar) + range_match = re.search(r'(\d+)\s*-\s*(\d+)', exp.display_name) + if range_match: + min_exp, max_exp = map(int, range_match.groups()) + if min_exp <= exp_years <= max_exp: + experience_id = exp.id + experience_name = exp.display_name + break + # Handle "+" ranges (e.g., "4+ years") + elif '+' in jd_data['required_experience']: + min_match = re.search(r'(\d+)\+', exp.display_name) + if min_match and exp_years >= int(min_match.group(1)): + experience_id = exp.id + experience_name = exp.display_name + break + + # If no range matched but we have a "+" requirement, find closest + if not experience_id and '+' in jd_data['required_experience']: + closest_exp = None + for exp in experiences: + nums = re.findall(r'\d+', exp.display_name) + if nums and int(nums[0]) <= exp_years: + if not closest_exp or int(nums[0]) > int(re.findall(r'\d+', closest_exp.display_name)[0]): + closest_exp = exp + if closest_exp: + experience_id = closest_exp.id + experience_name = closest_exp.display_name + + # Final fallback to first experience if still no match + if not experience_id and experiences: + experience_id = experiences[0].id + experience_name = experiences[0].display_name + + except Exception as e: + print(f"Error processing experience: {str(e)}") + if experiences: + experience_id = experiences[0].id + experience_name = experiences[0].display_name + + # Return enhanced data + return { + **jd_data, + 'primary_skills': primary_skills, + 'secondary_skills': secondary_skills, + 'locations': locations, + 'experience': { + 'id': experience_id, + 'name': experience_name + } if experience_id else None + } + + def _extract_text_from_file(self, file): + """Extract text content from uploaded file, including links""" + try: + # Save to temporary file + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + file.save(temp_file) + temp_path = temp_file.name + + ext = os.path.splitext(file.filename)[1].lower() + + text = "" + if ext == '.pdf': + import fitz # PyMuPDF + doc = fitz.open(temp_path) + for page in doc: + text += page.get_text() + for link in page.get_links(): + if "uri" in link: + text += f"\n[LINK]: {link['uri']}" + + elif ext == '.docx': + import docx + doc = docx.Document(temp_path) + for para in doc.paragraphs: + text += para.text + "\n" + + # Extract hyperlinks + for rel in doc.part.rels.values(): + if "hyperlink" in rel.reltype: + text += f"\n[LINK]: {rel.target_ref}" + + elif ext in ('.txt', '.text'): + with open(temp_path, 'r', encoding='utf-8') as f: + text = f.read() + + else: + raise ValueError(f"Unsupported file type: {ext}") + + os.unlink(temp_path) + return text.strip() + + except Exception as e: + print("Text extraction error: %s" % str(e)) + try: + os.unlink(temp_path) + except: + pass + return None + + def _get_jd_data_from_text(self, text_content): + """Enhanced JD parser with intelligent field extraction""" + # First get all available jobs for matching + all_jobs = request.env['hr.job'].search_read([], ['name']) + job_titles = [job['name'].lower() for job in all_jobs] + + api_url = "https://api.together.xyz/v1/chat/completions" + together_api_key = request.env['ir.config_parameter'].sudo().get_param( + 'hr_recruitment_web_app.together_api_key', + '5b7b753820a6985179720e4b0faeb9dea58a56c3ef126c71dd4d50bb20a57e0e' + ) + + headers = { + 'Authorization': f'Bearer {together_api_key}', + 'Content-Type': 'application/json', + } + + payload = { + "messages": [ + { + "role": "system", + "content": f"""Analyze this job description and extract structured data with these rules: + + 1. SEQUENCE: + - Look for any unique identification code/number in the text + - It might be labeled as: Request ID, JD Number, Ref No, etc. + - Or standalone patterns like: ABC-123, 123-456, etc. + - Return the first matching unique code found + + 2. DATES: + - Find any date ranges in the text (formats: MM/DD/YYYY, DD-MM-YYYY, etc.) + - If exactly two dates found, assume start/end dates + - Convert to YYYY-MM-DD format + + 3. LOCATIONS: + - Extract only the city/region name (remove building/office details) + - Clean special formats like: 'Hyderabad_SEZ' → 'Hyderabad' + - Return as array + + 4. JOB TITLE: + - Match against these existing job titles: {job_titles} + - Use closest match if not exact + - Remove department prefixes if needed (e.g., 'Engineering - ' prefix) + + 5. SKILLS CLASSIFICATION: + - PRIMARY: Must-have requirements (after words like 'essential', 'required', 'must have') + - SECONDARY: Nice-to-have (after words like 'preferred', 'plus', 'bonus') + - Technical skills only (no soft skills) + + 6. EDUCATION: + - Include in description as bullet point: "• Education: [requirements]" + - Also extract separately for structured data + + 7. DESCRIPTION FORMAT: + - Keep original bullet points/numbering + - Add education point at end + - Preserve all technical details + - Make it look very very professional and correct mistakes + + Return JSON with these fields: + - sequence (string) + - target_start_date (string/YYYY-MM-DD or null) + - target_end_date (string/YYYY-MM-DD or null) + - locations (array) + - required_experience (string) + - primary_skills (array) + - secondary_skills (array) + - description (string) + - job_title (string - matched to existing jobs) + - employment_type (string) + - education_requirements (array)""" + }, + { + "role": "user", + "content": text_content + } + ], + "model": "Qwen/Qwen2.5-72B-Instruct-Turbo", + "response_format": {"type": "json_object"}, + "temperature": 0.2 # More deterministic output + } + + try: + response = requests.post(api_url, json=payload, headers=headers, timeout=30) + response.raise_for_status() + + json_response = response.json() + if 'choices' in json_response and len(json_response['choices']) > 0: + try: + result = json.loads(json_response['choices'][0]['message']['content']) + + # Post-processing cleanup + result = self._clean_parsed_jd_data(result, text_content) + return result + + except (json.JSONDecodeError, KeyError) as e: + print("Failed to parse API response: %s", str(e)) + return None + return None + + except requests.exceptions.RequestException as e: + print("API request failed: %s", str(e)) + return None + + def _clean_parsed_jd_data(self, data, original_text): + """Additional cleaning and validation of parsed JD data""" + # Clean sequence number + if 'sequence' in data: + # Remove any non-alphanumeric characters except hyphens + data['sequence'] = re.sub(r'[^\w-]', '', str(data['sequence'])).strip() + + # Clean locations - extract just city names + if 'locations' in data and isinstance(data['locations'], list): + cleaned_locations = [] + for loc in data['locations']: + # Remove special suffixes and building info + clean_loc = re.sub(r'(_SEZ|_Park|-Bldg.*|Building.*)', '', loc, flags=re.IGNORECASE) + clean_loc = clean_loc.split('-')[0].strip() + cleaned_locations.append(clean_loc) + data['locations'] = list(set(cleaned_locations)) # Remove duplicates + + # Normalize experience + if 'required_experience' in data: + # Extract first number found + exp_match = re.search(r'(\d+)', str(data['required_experience'])) + data['required_experience'] = exp_match.group(1) if exp_match else None + + # Ensure description includes education + if 'education_requirements' in data and data['education_requirements']: + edu_text = "• Education: " + ", ".join(data['education_requirements']) + if 'description' in data and edu_text not in data['description']: + data['description'] += "\n\n" + edu_text + + # Fallback for dates if not found in structured parsing + if ('target_start_date' not in data or 'target_end_date' not in data): + dates_found = re.findall(r'\b\d{1,2}[/-]\d{1,2}[/-]\d{2,4}\b', original_text) + if len(dates_found) >= 2: + try: + data['target_start_date'] = self._convert_date_format(dates_found[0]) + data['target_end_date'] = self._convert_date_format(dates_found[1]) + except: + pass + + return data + + def _convert_date_format(self, date_str): + """Convert various date formats to YYYY-MM-DD""" + try: + # Handle different separators + for sep in ['/', '-']: + if sep in date_str: + parts = date_str.split(sep) + if len(parts) == 3: + # Handle MM/DD/YYYY or DD-MM-YYYY formats + if len(parts[2]) == 4: # Has 4-digit year + if len(parts[0]) == 2: # DD-MM-YYYY format + day, month, year = parts + else: # MM/DD/YYYY format + month, day, year = parts + return f"{year}-{month.zfill(2)}-{day.zfill(2)}" + return None + except: + return None + + @http.route('/myATS/applicant/detail/', type='http', auth='user', csrf=False) + def applicant_detail_ajax(self, applicant_id): + applicant = request.env['hr.applicant'].sudo().browse(applicant_id) + if not applicant.exists(): + return request.not_found() + + # Prepare resume data + resume_attachment = None + if applicant.resume: + request.env.cr.execute( + """select id from ir_attachment where res_model = 'hr.candidate' and res_id=%s and res_field='resume'""" % ( + applicant.candidate_id.id)) + resume_attachment = request.env.cr.fetchone() + + resume_data = { + 'attachment_id': resume_attachment[0] if resume_attachment else None, + 'name': applicant.resume_name or 'Resume', + 'review_status': 'pass' # Default status for resume + } + + # Prepare post onboarding attachments + post_onboarding_attachments = [] + for attachment in applicant.joining_attachment_ids: + # Find the related ir.attachment + + request.env.cr.execute( + """select id from ir_attachment where res_model = 'employee.recruitment.attachments' and res_id=%s""" % ( + attachment.id)) + attachment_id = request.env.cr.fetchone() + + post_onboarding_attachments.append({ + 'id': attachment.id, + 'attachment_id': attachment_id[0] if attachment_id else None, + 'recruitment_attachment': attachment.recruitment_attachment_id.display_name, + 'name': attachment.name, + 'review_status': attachment.review_status or 'pending' + }) + + return request.env['ir.ui.view']._render_template( + 'hr_recruitment_web_app.applicants_detail_partial', + { + 'applicant': applicant, + 'resume': resume_data, + 'post_onboarding_attachments': post_onboarding_attachments + } + ) + + @http.route('/resume/upload', type='http', auth='user', methods=['POST'], csrf=False) + def upload_resume(self, **post): + try: + file = http.request.httprequest.files.get('file') + type = http.request.httprequest.files.get('type') + if not type: + type = 'applicant' + if not file: + return http.Response( + json.dumps({"error": "No file uploaded"}), + status=400, + content_type='application/json' + ) + + # Extract text from file + text_content = self._extract_text_from_file(file) + if not text_content: + return http.Response( + json.dumps({"error": "Could not extract text from file"}), + status=400, + content_type='application/json' + ) + + # Get structured resume data + resume_data = self._get_resume_data_from_text(text_content, type) + if not resume_data: + return http.Response( + json.dumps({"error": "Failed to parse resume data"}), + status=400, + content_type='application/json' + ) + + # Process skills and locations + processed_data = self._process_resume_data(resume_data) + + return http.Response( + json.dumps(processed_data), + status=200, + content_type='application/json' + ) + + except Exception as e: + print("Resume Upload Error: %s", str(e)) + return http.Response( + json.dumps({"error": str(e)}), + status=500, + content_type='application/json' + ) + + def _process_resume_data(self, resume_data): + """Process resume data - create missing skills, locations, etc.""" + env = http.request.env + + # Process skills + skill_type = request.env.ref('hr_recruitment_extended.hr_skill_type_additional') + skills = [] + # Safely get personal info with defaults + personal_info = resume_data.get('personal_info', {}) + email = personal_info.get('email', '').strip() + phone = personal_info.get('phone', '').strip() + + # Only search for candidate if we have at least one identifier + if email or phone: + domain = [] + if email: + domain.append(('email_from', '=', email)) + if phone: + if len(domain) > 0: + domain.insert(0, '|') + domain.append(('partner_phone', '=', phone)) + + candidate = request.env['hr.candidate'].sudo().search(domain, limit=1) + if candidate: + resume_data['candidate_id'] = candidate.id # Store just the ID + + if resume_data.get('skills'): + for skill_name in resume_data['skills']: + skill = env['hr.skill'].search([('name', 'ilike', skill_name)], limit=1) + if not skill: + skill = request.env['hr.skill'].create({ + 'name': skill_name, + 'skill_type_id': skill_type.id + }) + skills.append({ + 'id': skill.id, + 'name': skill.name + }) + + # Process experience + experience_id = None + experience_name = None + if resume_data.get('total_experience'): + try: + experiences = env['candidate.experience'].search([], order='id') + exp_years = float(resume_data['total_experience']) + + for exp in experiences: + range_match = re.search(r'(\d+)\s*-\s*(\d+)', exp.display_name) + if range_match: + min_exp, max_exp = map(float, range_match.groups()) + if min_exp <= exp_years <= max_exp: + experience_id = exp.id + experience_name = exp.display_name + break + + if not experience_id and experiences: + experience_id = experiences[0].id + experience_name = experiences[0].display_name + + except Exception as e: + print(f"Error processing experience: {str(e)}") + if experiences: + experience_id = experiences[0].id + experience_name = experiences[0].display_name + + # Return enhanced data + return { + **resume_data, + 'skills': skills, + 'experience': { + 'id': experience_id, + 'name': experience_name + } if experience_id else None + } + + def _get_resume_data_from_text(self, text_content, type): + """Enhanced resume parser with intelligent field extraction""" + api_content = """Analyze this resume/CV and extract structured data with these rules: + + 1. PERSONAL INFORMATION: + - Extract full name (first + last) + - Extract email (validate format) + - Extract phone numbers (prioritize mobile numbers) + - Extract LinkedIn profile URL if present + - Extract date of birth if present (convert to YYYY-MM-DD) + - Extract gender if mentioned + + 2. CONTACT INFORMATION: + - Current location (city, country) + - Address if present (split into street, street2, city, state, zip, country) + - Permanent address if different + + 3. PROFESSIONAL INFORMATION: + - Current/most recent job title + - Current company + - Current location + - Total experience in years (calculate from work history) + - Notice period in days (extract from text or calculate standard) + - Current salary if mentioned + - Expected salary if mentioned + - Skills (technical only, no soft skills) + - Holding offer status if mentioned + + + 4. SKILLS CLASSIFICATION: + - all Technical skills (no soft skills) + + Return JSON with these fields: + - personal_info (object with name, email, LinkedIn, phone, date of birth, marital status, gender, etc.) + - contact_info (object with addresses, location) + - professional_info (object with current job, experience, current company etc.) + - skills (array) + - total_experience (float) + - notice_period (int) + - current_ctc (float) + - expected_salary (float) + - holding_offer (boolean)""" + if type == 'candidate': + api_content = """Analyze this resume/CV and extract structured data with these rules: + + 1. PERSONAL INFORMATION: + - Extract full name (first + last) + - Extract email (validate format) + - Extract phone numbers (prioritize mobile numbers) + - Extract LinkedIn profile URL if present + - Extract date of birth if present (convert to YYYY-MM-DD) + - Extract gender if mentioned + + 2. CONTACT INFORMATION: + - Current location (city, country) + - Address if present (split into street, street2, city, state, zip, country) + - Permanent address if different + + + 3. SKILLS CLASSIFICATION: + - all Technical skills (no soft skills) + + Return JSON with these fields: + - personal_info (object with name, email, LinkedIn, phone, date of birth, marital status, gender, etc.) + - contact_info (object with addresses, location) + - skills (array) + - total_experience (float) + - notice_period (int) + - current_ctc (float) + - expected_salary (float) + - holding_offer (boolean)""" + api_url = "https://api.together.xyz/v1/chat/completions" + together_api_key = request.env['ir.config_parameter'].sudo().get_param( + 'hr_recruitment_web_app.together_api_key', + '5b7b753820a6985179720e4b0faeb9dea58a56c3ef126c71dd4d50bb20a57e0e' + ) + + headers = { + 'Authorization': f'Bearer {together_api_key}', + 'Content-Type': 'application/json', + } + + payload = { + "messages": [ + { + "role": "system", + "content": api_content + }, + { + "role": "user", + "content": text_content + } + ], + "model": "Qwen/Qwen2.5-72B-Instruct-Turbo", + "response_format": {"type": "json_object"}, + "temperature": 0.2 + } + + try: + response = requests.post(api_url, json=payload, headers=headers, timeout=30) + response.raise_for_status() + + json_response = response.json() + if 'choices' in json_response and len(json_response['choices']) > 0: + try: + result = json.loads(json_response['choices'][0]['message']['content']) + return self._clean_parsed_resume_data(result, text_content) + except (json.JSONDecodeError, KeyError) as e: + print("Failed to parse API response: %s", str(e)) + return None + return None + + except requests.exceptions.RequestException as e: + print("API request failed: %s", str(e)) + return None + + def _clean_parsed_resume_data(self, data, original_text): + """Additional cleaning and validation of parsed resume data""" + # Clean phone numbers + if 'personal_info' in data and 'phone' in data['personal_info']: + phone = re.sub(r'[^\d+]', '', data['personal_info']['phone']) + data['personal_info']['phone'] = phone[:15] # Limit to 15 chars + + # Clean email + if 'personal_info' in data and 'email' in data['personal_info']: + data['personal_info']['email'] = data['personal_info']['email'].strip().lower() + + # Convert experience to float + if 'total_experience' in data: + try: + data['total_experience'] = float(data['total_experience']) + except: + data['total_experience'] = 0.0 + + # Convert notice period to days + if 'notice_period' in data: + if isinstance(data['notice_period'], str): + # Handle "2 months" or "60 days" formats + if 'month' in data['notice_period'].lower(): + try: + months = float(re.search(r'(\d+)', data['notice_period']).group(1)) + data['notice_period'] = int(months * 30) + except: + data['notice_period'] = 60 # Default to 2 months + else: + try: + data['notice_period'] = int(re.search(r'(\d+)', data['notice_period']).group(1)) + except: + data['notice_period'] = 60 + + # Ensure skills array exists + if 'skills' not in data: + data['skills'] = [] + + return data + + @http.route('/myATS/candidate/detail/', type='http', auth='user', csrf=False) + def candidate_detail_ajax(self, candidate_id): + candidate = request.env['hr.candidate'].sudo().browse(candidate_id) + if not candidate.exists(): + return request.not_found() + + # Prepare resume data + resume_attachment = None + if candidate.resume: + request.env.cr.execute( + """select id from ir_attachment where res_model = 'hr.candidate' and res_id=%s and res_field='resume'""" % ( + candidate.id)) + resume_attachment = request.env.cr.fetchone() + + resume_data = { + 'attachment_id': resume_attachment[0] if resume_attachment else None, + 'name': candidate.resume_name or 'Resume', + 'review_status': 'pass' # Default status for resume + } + + return request.env['ir.ui.view']._render_template( + 'hr_recruitment_web_app.candidates_detail_partial', + { + 'candidate': candidate, + 'resume': resume_data, + } + ) + + @http.route('/myATS/candidate/create', type='http', auth='user', methods=['POST'], csrf=False) + def create_new_candidate(self, **data): + try: + # Prepare vals dictionary for job creation + vals = {} + if len(data['sequence']) > 0: + candidates = request.env['hr.candidate'].sudo().search( + [('candidate_sequence', '=', str(data['sequence']))]) + + if candidates: + return Response(json.dumps({ + 'success': False, + 'error': '\n\nCandidate creation Failed Duplicate Sequence,\n\n(%s) Already Exists\n\nCreated by: "%s"' % ( + str(data['sequence']), candidates.create_uid.display_name), + }), + content_type='application/json', + ) + # Add only if value exists + if data.get('partner_name'): + vals['partner_name'] = data['partner_name'] + + if 'sequence' in data: + vals['candidate_sequence'] = data['sequence'] if len(data['sequence']) > 0 else '/' + + if data.get('email'): + vals['email_from'] = data['email'] + + if data.get('phone'): + vals['partner_phone'] = data['phone'] + + if data.get('mobile'): + vals['alternate_phone'] = data['mobile'] + + if data.get('linkedin_profile'): + vals['linkedin_profile'] = data['linkedin_profile'] + + if data.get('type_id'): + vals['type_id'] = int(data['type_id']) + + if data.get('user_id'): + vals['user_id'] = int(data['user_id']) + else: + vals['user_id'] = request.env.user.id + + if data.get('availability'): + vals['availability'] = data['availability'] + + vals['create_uid'] = request.env.user.id + + # Handle image upload + + image_file = request.httprequest.files.get('image_1920') + resume_file = request.httprequest.files.get('resume_file') + + if image_file: + vals['candidate_image'] = base64.b64encode(image_file.read()) + + if resume_file: + vals['resume'] = base64.b64encode(resume_file.read()) + if vals['resume']: + attachment = request.env.ref("hr_recruitment_extended.employee_recruitment_attachments_preview") + file = attachment.sudo().write({ + 'datas': vals['resume'], + }) + if file: + vals['resume_type'] = attachment.mimetype + vals['resume_name'] = resume_file.filename + else: + vals['resume_type'] = '' + vals['resume_name'] = resume_file.filename + # Create the candidate first (needs to exist before we can attach files) + candidate = request.env['hr.candidate'].sudo().create(vals) + + skill_ids = request.httprequest.form.getlist('skill_ids') + if skill_ids: + Skill = request.env['hr.skill'].sudo() + CandidateSkill = request.env['hr.candidate.skill'].sudo() + + valid_skills = Skill.browse([int(sid) for sid in skill_ids]).exists() + + created_candidate_skill_ids = [] + for skill in valid_skills: + skill_level = request.env['hr.skill.level'].sudo().search([ + ('skill_type_id', '=', skill.skill_type_id.id) + ], order='level_progress', limit=1) + + if not skill_level: + continue + + candidate_skill = CandidateSkill.create({ + 'candidate_id': candidate.id, + 'skill_id': skill.id, + 'skill_type_id': skill.skill_type_id.id, + 'skill_level_id': skill_level.id, + }) + created_candidate_skill_ids.append(candidate_skill.id) + + if created_candidate_skill_ids: + candidate.write({ + 'candidate_skill_ids': [(6, 0, created_candidate_skill_ids)] + }) + + return Response( + json.dumps({ + 'success': True, + 'candidate_id': candidate.id, + 'message': 'Candidate created successfully' + }), + content_type='application/json', + ) + + except Exception as e: + error_msg = str(e) + print("candidate creation error: %s", error_msg) # Add this line + return Response( + json.dumps({ + 'success': False, + 'error': error_msg, + 'message': 'Failed to create candidate', + }), + content_type='application/json', + status=400 if 'duplicate key' in error_msg else 500 + ) + + @http.route('/myATS/job/matching_candidates/', type='http', auth='user') + def matching_candidates(self, job_id, min_match=10, **kwargs): + """ + Returns HTML partial with matching candidates for a job + min_match: Minimum percentage match to include (default 20%) + """ + try: + job = request.env['hr.job.recruitment'].browse(job_id) + if not job.exists(): + return request.render('hr_recruitment_web_app.error_template', { + 'message': "Job not found" + }) + + job_primary_skills = job.skill_ids + job_secondary_skills = job.secondary_skill_ids + + Candidate = request.env['hr.candidate'] + candidates = Candidate.search([('active', '=', True)]) + + matched_candidates = [] + for candidate in candidates: + candidate_skills = candidate.skill_ids + + # Calculate matches + matched_primary = set(job_primary_skills.ids) & set(candidate_skills.ids) + primary_pct = (len(matched_primary) / len(job_primary_skills.ids)) * 100 if job_primary_skills else 0 + + matched_secondary = set(job_secondary_skills.ids) & set(candidate_skills.ids) + secondary_pct = (len(matched_secondary) / len( + job_secondary_skills.ids)) * 100 if job_secondary_skills else 0 + + # Only include if meets minimum match threshold + if primary_pct >= min_match or secondary_pct >= min_match: + matched_candidates.append({ + 'candidate': candidate, + 'primary_pct': round(primary_pct, 1), + 'secondary_pct': round(secondary_pct, 1), + 'matched_primary_skills': job_primary_skills.filtered(lambda s: s.id in matched_primary).mapped( + 'name'), + 'matched_secondary_skills': job_secondary_skills.filtered( + lambda s: s.id in matched_secondary).mapped('name'), + 'candidate_data': { + 'email': candidate.email_from, + 'phone': candidate.partner_phone, + 'manager': candidate.user_id.display_name if candidate.user_id else 'Unassigned', + 'applications': [(app.display_name, app.recruitment_stage_id.display_name) for app in + request.env['hr.applicant'].sudo().search( + [('candidate_id', '=', candidate.id)])] + } + }) + + # Sort by primary match (highest first), then secondary + matched_candidates.sort(key=lambda x: (-x['primary_pct'], -x['secondary_pct'])) + + return request.render('hr_recruitment_web_app.matching_candidates_content', { + 'candidates': [mc['candidate'] for mc in matched_candidates], + 'match_data': {mc['candidate'].id: mc for mc in matched_candidates}, + 'min_match': min_match + }) + + except Exception as e: + return request.render('hr_recruitment_web_app.error_template', { + 'message': f"Error loading matching candidates: {str(e)}" + }) + + @http.route('/myATS/job/candidate_details/', type='json', auth='user') + def get_candidate_details(self, candidate_id, **kwargs): + """ + Returns JSON data with detailed candidate information + """ + try: + candidate = request.env['hr.candidate'].browse(candidate_id) + if not candidate.exists(): + return {'error': 'Candidate not found'} + + # Get the current job ID from session or parameters if needed + job_id = request.session.get('current_job_id') + job = request.env['hr.job.recruitment'].browse(job_id) if job_id else None + + # Recalculate matches if needed, or use stored data + if job: + job_primary_skills = job.skill_ids + job_secondary_skills = job.secondary_skill_ids + candidate_skills = candidate.skill_ids + + matched_primary = set(job_primary_skills.ids) & set(candidate_skills.ids) + primary_pct = (len(matched_primary) / len(job_primary_skills.ids)) * 100 if job_primary_skills else 0 + + matched_secondary = set(job_secondary_skills.ids) & set(candidate_skills.ids) + secondary_pct = (len(matched_secondary) / len( + job_secondary_skills.ids)) * 100 if job_secondary_skills else 0 + + matched_primary_skills = job_primary_skills.filtered(lambda s: s.id in matched_primary).mapped('name') + matched_secondary_skills = job_secondary_skills.filtered(lambda s: s.id in matched_secondary).mapped( + 'name') + else: + primary_pct = 0 + secondary_pct = 0 + matched_primary_skills = [] + matched_secondary_skills = [] + + applications = [(app.display_name, app.recruitment_stage_id.display_name) + for app in request.env['hr.applicant'].sudo().search([('candidate_id', '=', candidate.id)])] + + return { + 'candidate': { + 'id': candidate.id, + 'display_name': candidate.display_name, + 'candidate_image': candidate.candidate_image, + 'email_from': candidate.email_from, + 'partner_phone': candidate.partner_phone, + }, + 'primary_pct': round(primary_pct, 1), + 'secondary_pct': round(secondary_pct, 1), + 'matched_primary_skills': matched_primary_skills, + 'matched_secondary_skills': matched_secondary_skills, + 'candidate_data': { + 'email': candidate.email_from, + 'phone': candidate.partner_phone, + 'manager': candidate.user_id.display_name if candidate.user_id else 'Unassigned', + 'applications': applications + } + } + except Exception as e: + return {'error': str(e)} + + @http.route('/myATS/job/applicants/', type='http', auth='user') + def applicants(self, job_id, **kwargs): + """ + Returns HTML partial with applicants grouped by stage + """ + try: + # 1. Get the job from database + job = request.env['hr.job.recruitment'].browse(job_id) + if not job.exists(): + return request.render('hr_recruitment_web_app.error_template', { + 'message': "Job not found" + }) + + # 2. Get all applicants for this job + applicants = request.env['hr.applicant'].search([ + ('hr_job_recruitment', '=', job.id), + ('active', '=', True) + ], order='create_date desc') + + # 3. Group by stage + stages = {} + for applicant in applicants: + stage = applicant.stage_id + if stage.id not in stages: + stages[stage.id] = { + 'name': stage.name, + 'applicants': [] + } + + stages[stage.id]['applicants'].append({ + 'id': applicant.id, + 'name': applicant.partner_name or applicant.name, + 'application_date': applicant.create_date.strftime('%Y-%m-%d'), + 'status': applicant.priority, + 'resume_url': '/web/content/%s?download=true' % applicant.attachment_ids[ + 0].id if applicant.attachment_ids else '#', + 'stage_name': stage.name + }) + + # 4. Return HTML partial + return request.render('hr_recruitment_web_app.applicants_content', { + 'stages': stages.values(), + 'job_title': job.name, + 'total_applicants': len(applicants) + }) + + except Exception as e: + return request.render('hr_recruitment_web_app.error_template', { + 'message': "Error loading applicants" + }) \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/models/__init__.py b/addons_extensions/hr_recruitment_web_app/models/__init__.py new file mode 100644 index 000000000..ae1fcc97b --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/models/__init__.py @@ -0,0 +1,2 @@ +from . import recruitment_doc_upload_wizard +from . import res_config_settings \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/models/recruitment_doc_upload_wizard.py b/addons_extensions/hr_recruitment_web_app/models/recruitment_doc_upload_wizard.py new file mode 100644 index 000000000..605aaf474 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/models/recruitment_doc_upload_wizard.py @@ -0,0 +1,216 @@ +from odoo import models, fields, api +from pypdf import PdfReader +from datetime import datetime +import base64 +import re +from dateutil.relativedelta import relativedelta +import logging +import requests +from io import BytesIO +from pdf2image import convert_from_bytes +from PIL import Image +import pytesseract +import json +from docx import Document +# import binascii + +from odoo.tools.mimetypes import guess_mimetype +_logger = logging.getLogger(__name__) + + +class RecruitmentDocUploadWizard(models.TransientModel): + _name = 'recruitment.doc.upload.wizard' + _description = 'Recruitment Document Upload Wizard' + + # Define the fields in the wizard + name = fields.Char("Name") + json_data = fields.Text("Json Data") + file_name = fields.Char('File Name') + file_data = fields.Binary('File Data', required=True) + active = fields.Boolean(default=True) + mimetype = fields.Char(string="Type", readonly=True) + file_html_text = fields.Html() + + def compute_mimetype(self): + for record in self: + record.mimetype = '' + if record.file_data: + try: + # Fix padding + padded_data = record.file_data + b'=' * (-len(record.file_data) % 4) + binary = base64.b64decode(padded_data) + record.mimetype = guess_mimetype(binary) + except Exception: + record.mimetype = 'Invalid base64' + + def action_upload(self): + # Implement the logic for file upload here + # You can use the fields file_data, file_name, etc., to save the data in the desired model + pass + + + def action_fetch_json(self): + for record in self: + record.compute_mimetype() + if not record.file_data: + record.json_data = "No file content provided." + continue + + binary = base64.b64decode(record.file_data) + file_type = record.mimetype + text_content = "" + + try: + if file_type == "application/pdf": + try: + pdf_reader = PdfReader(BytesIO(binary)) + for page in pdf_reader.pages: + page_text = page.extract_text() + text_content += page_text + if not text_content: + images = convert_from_bytes(binary, dpi=300) + extracted_text = [] + for image in images: + text = pytesseract.image_to_string(image) + extracted_text.append(text) + text_content = "\n".join(extracted_text) + + except Exception as e: + _logger.error("Error reading PDF: %s", str(e)) + text_content = "" + + elif file_type in ["image/png", "image/jpeg", "image/jpg"]: + try: + image = Image.open(BytesIO(binary)) + text_content = pytesseract.image_to_string(image) + except Exception as e: + _logger.error("Error processing image: %s", str(e)) + text_content = "" + + elif file_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': + try: + doc = Document(BytesIO(binary)) + text_content = '' + + for section in doc.sections: + header = section.header + for paragraph in header.paragraphs: + text_content += paragraph.text + '\n' + + for paragraph in doc.paragraphs: + text_content += paragraph.text + '\n' + except Exception as e: + _logger.error("Error processing DOCX: %s", str(e)) + text_content = "" + + else: + _logger.error("Unsupported file type: %s", file_type) + record.json_data = f"Unsupported file type: {file_type}" + continue + record.file_html_text = text_content + json_response = record.get_json_from_model(text_content) + import pdb + pdb.set_trace() + if json_response and "choices" in json_response and len(json_response["choices"]) > 0: + message_content = json_response["choices"][0].get("message", {}).get("content", "") + + if message_content: + match = re.search(r'```json\n(.*?)\n```', message_content, re.DOTALL) + if match: + clean_json_str = match.group(1).strip() # Extract JSON content + try: + parsed_json = json.loads(clean_json_str) + record.json_data = json.dumps(parsed_json, indent=4) + file_name = parsed_json.get("name", "") + if file_name: + self.write({'file_name': file_name}) + + except json.JSONDecodeError as e: + _logger.error("Error parsing JSON: %s", str(e)) + record.json_data = "Error parsing JSON" + else: + _logger.error("No valid JSON found in the content") + record.json_data = "No valid JSON format found" + else: + _logger.error("No message content found in the response") + record.json_data = "No message content found" + else: + _logger.error("No valid response or choices in the API response") + record.json_data = "No valid JSON data received." + + except Exception as e: + _logger.error("Unexpected error during OCR processing: %s", str(e)) + record.json_data = "An unexpected error occurred during file processing." + + _logger.info("Stored JSON data for file: %s", record.file_name) + + + def normalize_gender(self, gender): + if gender: + return gender.replace(" ", "").lower() + return gender + + def normalize_marital_status(self, marital_status): + if marital_status: + return marital_status.replace(" ", "").lower() + return marital_status + + def parse_experience(self, experience_str): + years = 0 + months = 0 + + year_match = re.search(r'(\d+)\s*[\+]*\s*years?', experience_str, re.IGNORECASE) + month_match = re.search(r'(\d+)\s*months?', experience_str, re.IGNORECASE) + + if year_match: + years = int(year_match.group(1)) + if month_match: + months = int(month_match.group(1)) + + return years, months + + def get_json_from_model(self, text_content): + print(text_content) + api_url = "https://api.together.xyz/v1/chat/completions" + together_api_key = self.env['ir.config_parameter'].sudo().get_param('hr_recruitment_web_app.together_api_key') + headers = { + 'Authorization': 'Bearer %s' % together_api_key, + 'Content-Type': 'application/json', + } + current_date = datetime.now() + previous_month_date = current_date - relativedelta(months=1) + previous_month_year = previous_month_date.strftime("%B %Y") + payload = { + "messages": [ + { + "role": "system", + "content": "provide the json data from the above content for below fields---\n\nname-- particularly the full name of the candidate\nskills-- the skills of the candidate mentioned in the text specifically under skills section (add both soft and technical skills in this). \nemail -- the contact email of the candidate \nphone -- contact number of candidate usually a 10-12 number digits\ndegree-- the degree or qualification of the candidate mentioned in resume (only the name of the degrees or qualifications and not the whole details) " + f"\n experience in years and months in the format: Title of the experience (type of experience) (from month/year to month/year) -> years and months (If the end date is marked as 'present' or 'till now', assume today's date is {previous_month_year} and calculate the months also properly). \n" + "\n Total Experience (Non-Overlapping) : in years and months \n" + "\n location-- search for the location or place mentioned in the resume where the candidate belong to. \n gender-- the gender of the candidate if mentioned. \ndate_of_birth-- the date of birth of the candidate in the format-%d/%m/%Y \nmarital_status-- the marital status of the candidate \n languages-- the languages known by the candidate mentioned in resume(not technical languages but the spoken ones specifically mentioned under languages section)\n" + }, + { + "role": "user", + "content": text_content + } + ], + "model": "Qwen/Qwen2.5-72B-Instruct-Turbo", + } + + try: + response = requests.post(api_url, json=payload, headers=headers) + + if response.status_code == 200: + try: + json_response = response.json() + return json_response + except ValueError as e: + _logger.error("Error parsing JSON: %s", str(e)) + return {} + else: + _logger.error("Error in API call: %s", response.text) + return {} + + except Exception as e: + _logger.error("Exception during API call: %s", str(e)) + return {} \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/models/res_config_settings.py b/addons_extensions/hr_recruitment_web_app/models/res_config_settings.py new file mode 100644 index 000000000..f0e17d45a --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/models/res_config_settings.py @@ -0,0 +1,7 @@ +from odoo import api, fields, models, _ + + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + together_api_key = fields.Char(config_parameter='hr_recruitment_web_app.together_api_key', string="Together API key") \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/security/ir.model.access.csv b/addons_extensions/hr_recruitment_web_app/security/ir.model.access.csv new file mode 100644 index 000000000..9b3e0fca2 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_recruitment_doc_upload_wizard_user,recruitment.doc.upload.wizard user,model_recruitment_doc_upload_wizard,base.group_user,1,1,1,1 diff --git a/addons_extensions/hr_recruitment_web_app/static/description/banner.png b/addons_extensions/hr_recruitment_web_app/static/description/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..2306fb0ff95169064bef455f99254b7e67f26fff GIT binary patch literal 76312 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 literal 0 HcmV?d00001 diff --git a/addons_extensions/hr_recruitment_web_app/static/description/banner_copy.png b/addons_extensions/hr_recruitment_web_app/static/description/banner_copy.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca6a3d1fd77fa73409a4c880d09a2b3e8308345 GIT binary patch literal 58167 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

6U1{SF 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 OdH?p~n@V}p;Qt44?N>Gc literal 0 HcmV?d00001 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 new file mode 100644 index 000000000..9416f2c65 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/css/applicants.css @@ -0,0 +1,498 @@ +@import url('colors.css'); + +/* ========= application creation css ========= */ +/* ===== Application Modal Styles ===== */ +.application-creation-modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 1000; + justify-content: center; + align-items: center; + opacity: 0; + transition: opacity 0.3s ease; +} + +.application-creation-modal.show { + display: flex; + opacity: 1; +} + +.application-creation-modal .application-creation-content { + background-color: var(--white); + width: 85%; + max-width: 1200px; + border-radius: 8px; + box-shadow: 0 5px 20px var(--shadow-dark); + transform: translateY(-20px); + transition: transform 0.3s ease; + max-height: 90vh; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.application-creation-modal.show .application-creation-content { + transform: translateY(0); +} + +.application-creation-modal .application-creation-header { + padding: 20px; + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue) 100%); + color: var(--white); + border-radius: 8px 8px 0 0; + display: flex; + justify-content: space-between; + align-items: center; + position: sticky; + top: 0; + z-index: 100; +} + +.application-creation-modal .header-icon-container { + display: flex; + align-items: center; + gap: 15px; +} + +.application-creation-modal .header-icon { + font-size: 24px; + color: var(--white); +} + +.application-creation-modal .application-creation-header h3 { + margin: 0; + font-size: 1.4rem; + font-weight: 600; + color: var(--white); +} + +.application-creation-modal .application-creation-close { + font-size: 28px; + cursor: pointer; + transition: transform 0.2s; + color: var(--white); + background: none; + border: none; +} + +.application-creation-modal .application-creation-close:hover { + transform: scale(1.2); + color: var(--gray-200); +} + +.application-creation-modal .application-creation-body { + padding: 25px; + overflow-y: auto; + flex-grow: 1; +} + +.application-creation-modal .form-section { + background-color: var(--white); + border-radius: 6px; + padding: 20px; + box-shadow: 0 2px 5px var(--shadow-color); + border-left: 4px solid var(--secondary-purple); + margin-bottom: 20px; +} + +.application-creation-modal .section-title { + margin-top: 0; + margin-bottom: 20px; + color: var(--text-primary); + font-size: 18px; + display: flex; + align-items: center; + gap: 10px; +} + +.application-creation-modal .section-title i { + color: var(--secondary-purple); +} + +.application-creation-modal .form-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 20px; +} + +.application-creation-modal .form-group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.application-creation-modal .form-group label { + font-weight: 500; + color: var(--text-secondary); + font-size: 14px; +} + +.application-creation-modal .form-input, +.application-creation-modal .form-select, +.application-creation-modal .form-textarea { + width: 100%; + padding: 10px 12px; + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 14px; + transition: border-color 0.3s, box-shadow 0.3s; + background-color: var(--white); + color: var(--text-primary); +} + +.application-creation-modal .form-input:focus, +.application-creation-modal .form-select:focus, +.application-creation-modal .form-textarea:focus { + border-color: var(--secondary-purple); + box-shadow: 0 0 0 3px var(--primary-blue-light); + outline: none; +} + +/* Checkbox styles */ +.application-creation-modal .same-as-current { + display: flex; + align-items: center; + gap: 8px; + margin-top: 10px; +} + +.application-creation-modal .same-as-current input[type="checkbox"] { + width: auto; +} + +/* Education entries */ +.application-creation-modal .education-entries { + margin-bottom: 15px; +} + +.application-creation-modal .education-entry { + position: relative; + padding: 15px; + background-color: var(--gray-50); + border-radius: 6px; + margin-bottom: 15px; + border: 1px solid var(--border-light); +} + +.application-creation-modal .remove-education { + position: absolute; + top: 10px; + right: 10px; + background: none; + border: none; + color: var(--danger); + cursor: pointer; + font-size: 12px; + display: flex; + align-items: center; + gap: 5px; +} + +.application-creation-modal .remove-education:hover { + text-decoration: underline; +} + +.application-creation-modal .add-education { + background-color: var(--primary-blue); + color: var(--white); + border: none; + padding: 8px 15px; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 20px; + transition: background-color 0.3s; +} + +.application-creation-modal .add-education:hover { + background-color: var(--primary-blue-dark); +} + +/* Skills section */ +.application-creation-modal .skills-container { + margin-top: 20px; +} + +/* Upload area */ + +/* Resume Section */ +.application-creation-modal .resume-upload-container { + display: flex; + gap: 20px; +} + +.application-creation-modal .upload-area { + flex: 1; + border: 2px dashed var(--border-color); + border-radius: 6px; + padding: 30px; + text-align: center; + cursor: pointer; + transition: all 0.3s; + max-width: 30%; +} + +.application-creation-modal .upload-area:hover { + border-color: var(--primary-blue); + background-color: var(--gray-50); +} + +.application-creation-modal .upload-icon { + font-size: 40px; + color: var(--primary-blue); + margin-bottom: 10px; +} + +.application-creation-modal .upload-area h5 { + margin: 0 0 5px; + color: var(--text-primary); +} + +.application-creation-modal .upload-area p { + margin: 0; + color: var(--text-muted); + font-size: 14px; +} + +.application-creation-modal .resume-preview { + flex: 1; + border: 1px solid var(--border-light); + border-radius: 6px; + padding: 15px; + min-height: 200px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: var(--gray-50); +} + +.application-creation-modal .resume-preview-placeholder { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + color: var(--text-muted); + height: 100%; +} + +.application-creation-modal .resume-preview-placeholder i { + font-size: 40px; + margin-bottom: 10px; + color: var(--primary-blue); +} + +.application-creation-modal .btn-danger { + background-color: var(--danger); + color: white; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; +} + +.application-creation-modal .btn-danger:hover { + background-color: #dc3545; +} + +/* Additional attachments */ +.application-creation-modal .additional-attachments { + margin-top: 20px; +} + +.application-creation-modal .attachments-list { + margin: 10px 0; +} + +.application-creation-modal .add-attachment { + background-color: transparent; + color: var(--primary-blue); + border: 1px solid var(--primary-blue); + padding: 8px 15px; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; + transition: all 0.3s; +} + +.application-creation-modal .add-attachment:hover { + background-color: var(--primary-blue-light); +} + +/* Form actions */ +.application-creation-modal .form-actions { + position: sticky; + bottom: 0; + background: var(--white); + padding: 15px 25px; + border-top: 1px solid var(--border-light); + z-index: 100; + margin-top: auto; + display: flex; + justify-content: space-between; + align-items: center; +} + +.application-creation-modal .btn-cancel { + padding: 10px 20px; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + transition: transform 0.2s, box-shadow 0.2s; + background-color: var(--gray-100); + color: var(--text-secondary); + border: 1px solid var(--border-color); +} + +.application-creation-modal .btn-cancel:hover { + background-color: var(--gray-200); +} + +.application-creation-modal .btn-application-primary { + padding: 10px 20px; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + transition: transform 0.2s, box-shadow 0.2s; + display: flex; + align-items: center; + gap: 8px; + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue) 100%); + color: var(--white); + border: none; +} + +.application-creation-modal .btn-application-primary:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px var(--shadow-color); + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue-dark) 100%); +} + +.application-creation-modal .footer-right { + display: flex; + gap: 10px; +} + +/* SELECT2 custom styles */ +.application-creation-modal .select2-container { + z-index: 10000 !important; + width: 100% !important; +} + +.application-creation-modal .select2-container--default .select2-selection--multiple, +.application-creation-modal .select2-container--default .select2-selection--single { + border: 1px solid var(--border-color) !important; + border-radius: 4px !important; + min-height: 40px; + background-color: var(--white); + padding: 6px 8px !important; + flex-wrap: wrap !important; + gap: 4px; +} + +.application-creation-modal .select2-container--default .select2-selection--multiple .select2-selection__choice { + background-color: var(--primary-blue) !important; + border: none !important; + color: var(--white) !important; + padding: 2px 8px !important; + +} + +.application-creation-modal .select2-container--default .select2-selection--multiple .select2-selection__choice__remove { + color: var(--white) !important; +} + +.application-creation-modal .select2-dropdown { + border: 1px solid var(--border-color) !important; + box-shadow: 0 2px 5px var(--shadow-color) !important; +} + +.application-creation-modal .select2-container--default .select2-selection__rendered { + display: flex !important; + align-items: center !important; + vertical-align: middle !important; + line-height: normal !important; + color: var(--text-primary); +} + +.application-creation-modal .select2-container--default .select2-selection--multiple .select2-selection__rendered { + display: flex !important; + flex-wrap: wrap !important; + align-items: center !important; + width: 100% !important; + padding: 2px 5px !important; + overflow: visible !important; + box-sizing: border-box !important; +} + +.application-creation-modal .select2-container--default .select2-results__option--highlighted[aria-selected] { + background-color: var(--primary-blue) !important; + color: var(--white) !important; +} + +/* Scrollbar styling */ +.application-creation-modal .application-creation-body::-webkit-scrollbar { + width: 8px; +} + +.application-creation-modal .application-creation-body::-webkit-scrollbar-track { + background: var(--gray-100); +} + +.application-creation-modal .application-creation-body::-webkit-scrollbar-thumb { + background: var(--primary-blue); + border-radius: 4px; +} + +.application-creation-modal .application-creation-body::-webkit-scrollbar-thumb:hover { + background: var(--primary-blue-dark); +} + +/* Responsive adjustments */ +@media (max-width: 1024px) { + .application-creation-modal .application-creation-content { + width: 90%; + } +} + +@media (max-width: 768px) { + .application-creation-modal .application-creation-content { + width: 95%; + height: 95vh; + } + + .application-creation-modal .form-grid { + grid-template-columns: 1fr; + } +} + +/* Special cases */ +.application-creation-modal .marital-anniversary { + display: none; +} + +.application-creation-modal #application-marital[value="married"] ~ .marital-anniversary { + display: flex; +} + +.application-creation-modal .form-section.profile-section:first-child { + margin-top: 0; +} + +.application-creation-modal .select2-dropdown { + border: 1px solid var(--border-color) !important; + box-shadow: 0 2px 5px var(--shadow-color) !important; +} + + + diff --git a/addons_extensions/hr_recruitment_web_app/static/src/css/ats.css b/addons_extensions/hr_recruitment_web_app/static/src/css/ats.css new file mode 100644 index 000000000..53d7ae7b9 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/css/ats.css @@ -0,0 +1,217 @@ +@import url('colors.css'); + +/* ===== ATS Custom Layout Reset ===== */ +body.ats-app { + margin: 0; + padding: 0; + font-family: "Segoe UI", sans-serif; + background-color: var(--body-bg); + color: var(--text-primary); + height: 100vh; + overflow: hidden; +} + +/* ===== Header ===== */ +.ats-app .main-header { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 1rem; + font-size: 1.8rem; + font-weight: 600; + padding: 1rem; + position: relative; /* For absolute positioning of toggle button */ +} + +/* Logo and title alignment */ +.ats-app .main-header img { + height: 40px; + width: auto; +} + +.ats-app .main-header span { + display: flex; + align-items: center; + height: 40px; /* Match logo height */ +} + +/* ===== Layout Container ===== */ +.ats-app .layout-container { + display: flex; + height: 100%; /* Adjust for header height */ + overflow: hidden; +} + +/* ===== Sidebar ===== */ +.ats-app .sidebar { + background-color: var(--sidebar-bg); + color: var(--sidebar-text); + padding: 1rem 1rem 2rem; + box-shadow: 2px 0 10px rgba(0, 0, 0, 0.05); + transition: all 0.4s ease-in-out; + position: relative; + overflow: hidden; + display: flex; + flex-direction: column; +} + +/* Expanded Sidebar */ +.ats-app .sidebar.expanded { + width: 240px; /* Use fixed width for better consistency */ + min-width: 240px; +} + +/* Collapsed Sidebar */ +.ats-app .sidebar.collapsed { + width: 60px; + min-width: 60px; + padding: 1rem 0.4rem 2rem; +} + +/* Hide content in collapsed state */ +.ats-app .sidebar.collapsed .menu-list, +.ats-app .sidebar.collapsed .main-header span { + display: none; +} + +/* ===== Sidebar Menu ===== */ +.ats-app .menu-list { + list-style: none; + padding-top: 1rem; + margin: 2rem 0; + flex-grow: 1; +} + +.ats-app .list-title { + color: var(--text-secondary); + font-size: 0.9rem; +} + +.ats-app .menu-list li { + margin-bottom: 1.2rem; +} + +.ats-app .menu-list a { + display: block; + color: var(--sidebar-text); + text-decoration: none; + padding: 0.7rem 1rem; + border-radius: 8px; + transition: all 0.3s ease; + font-size: 1.1rem; +} + +.ats-app .menu-list a:hover { + background-color: #DBEDFE; + color: #0061FF; + transform: translateX(6px); + box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2); + font-weight: 600; + letter-spacing: 0.5px; +} + +/* ===== Toggle Button ===== */ +.ats-app .toggle-btn { + position: absolute; + top: 1.5rem; + right: -12px; + background-color: var(--sidebar-bg); + color: var(--text-primary); + border: 1px solid var(--border-color); + padding: 0.5rem; + cursor: pointer; + border-radius: 50%; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + z-index: 10; + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; +} + +.ats-app .toggle-btn:hover { + background-color: #e1e5eb; +} + +/* ===== Main Content Area ===== */ +.ats-app .content-area { + flex: 1; + padding: 2rem; + background-color: var(--content-bg); + overflow-y: auto; + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.02); + border-left: 1px solid #dcdde1; + min-width: 0; +} + +/* ===== Responsive Design ===== */ +@media (max-width: 1024px) { + .ats-app .layout-container { + flex-direction: column; + height: auto; + } + + .ats-app .sidebar, + .ats-app .sidebar.expanded, + .ats-app .sidebar.collapsed { + width: 100%; + padding: 1rem; + text-align: center; + } + + .ats-app .sidebar { + overflow: hidden; + max-height: 15%; /* expanded */ + transition: all 0.4s ease-in-out; + } + + .ats-app .sidebar.collapsed { + max-height: 1%; + padding: 0; + } + + .ats-app .sidebar.collapsed .menu-list, + .ats-app .sidebar.collapsed .main-header h1 { + display: none; + } + + .ats-app .menu-list { + display: flex; + justify-content: center; + flex-wrap: wrap; + gap: 0.5rem; + } + + .menu-list i { + margin-right: 8px; + font-size: 1.1rem; + vertical-align: middle; + } + + .ats-app .menu-list li { + margin-bottom: 0; + } + + .ats-app .menu-list a { + padding: 0.5rem 1rem; + font-size: 1rem; + } + + .ats-app .toggle-btn { + position: relative; + top: auto; + right: auto; + transform: none; + margin: 1rem auto 0 auto; + display: block; + border-radius: 6px; + } + + .ats-app .content-area { + padding: 1rem; + border-left: none; + } +} + diff --git a/addons_extensions/hr_recruitment_web_app/static/src/css/candidate.css b/addons_extensions/hr_recruitment_web_app/static/src/css/candidate.css new file mode 100644 index 000000000..1733db7b0 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/css/candidate.css @@ -0,0 +1,667 @@ +@import url('colors.css'); + + +/* ====== candidate creation template ======= */ + +/* ===== Candidate Form Styles ===== */ +.candidate-form-modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 1000; + justify-content: center; + align-items: center; + opacity: 0; + transition: opacity 0.3s ease; +} + +.candidate-form-modal.show { + display: flex; + opacity: 1; +} + +.candidate-form-modal .candidate-form-content { + background-color: var(--white); + width: 90%; + max-width: 1400px; + border-radius: 8px; + box-shadow: 0 5px 20px var(--shadow-dark); + transform: translateY(-20px); + transition: transform 0.3s ease; + max-height: 90vh; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.candidate-form-modal.show .candidate-form-content { + transform: translateY(0); +} + +.candidate-form-modal .candidate-form-header { + padding: 20px; + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue) 100%); + color: var(--white); + border-radius: 8px 8px 0 0; + display: flex; + justify-content: space-between; + align-items: center; + position: sticky; + top: 0; + z-index: 100; +} + +.candidate-form-modal .header-icon-container { + display: flex; + align-items: center; + gap: 15px; +} + +.candidate-form-modal .header-icon { + font-size: 24px; + color: var(--white); +} + +.candidate-form-modal .candidate-form-header h3 { + margin: 0; + font-size: 1.4rem; + font-weight: 600; + color: var(--white); +} + +.candidate-form-modal .candidate-form-close { + font-size: 28px; + cursor: pointer; + transition: transform 0.2s; + color: var(--white); + background: none; + border: none; +} + +.candidate-form-modal .candidate-form-close:hover { + transform: scale(1.2); + color: var(--gray-200); +} + +.candidate-form-modal .candidate-form-body { + padding: 25px; + overflow-y: auto; + flex-grow: 1; +} + +/* Header Section with Avatar */ +.candidate-form-modal .header-section { + display: flex; + align-items: center; + margin-bottom: 20px; + padding-bottom: 20px; + border-bottom: 1px solid var(--border-light); +} + +.candidate-form-modal .avatar-container { + display: flex; + align-items: center; + gap: 20px; + width: 100%; +} + +.candidate-form-modal .candidate-avatar { + position: relative; + width: 120px; + height: 120px; + border-radius: 50%; + overflow: hidden; + border: 3px solid var(--primary-blue); + box-shadow: 0 3px 10px var(--shadow-color); + margin-right: 20px; +} + +.candidate-form-modal .candidate-avatar img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.candidate-form-modal .avatar-upload { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background-color: rgba(0, 0, 0, 0.5); + color: white; + text-align: center; + padding: 5px; + cursor: pointer; + transition: background-color 0.3s; +} + +.candidate-form-modal .avatar-upload:hover { + background-color: rgba(0, 0, 0, 0.7); +} + +.candidate-form-modal .avatar-upload i { + margin-right: 5px; +} + +.candidate-form-modal .avatar-upload input { + display: none; +} + +.candidate-form-modal .basic-info { + flex-grow: 1; +} + +/* Button Box Section */ +.candidate-form-modal .button-box { + display: flex; + gap: 15px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.candidate-form-modal .stat-button { + flex: 1; + min-width: 200px; + display: flex; + align-items: center; + gap: 10px; + padding: 12px 15px; + background-color: var(--gray-50); + border: 1px solid var(--border-light); + border-radius: 6px; + cursor: pointer; + transition: all 0.3s; +} + +.candidate-form-modal .stat-button:hover { + background-color: var(--gray-100); + transform: translateY(-2px); + box-shadow: 0 2px 5px var(--shadow-color); +} + +.candidate-form-modal .stat-button i { + font-size: 24px; + color: var(--primary-blue); +} + +.candidate-form-modal .stat-info { + display: flex; + flex-direction: column; +} + +.candidate-form-modal .stat-value { + font-weight: 600; + color: var(--text-primary); +} + +.candidate-form-modal .stat-text { + font-size: 12px; + color: var(--text-muted); +} + +/* Form Sections */ +.candidate-form-modal .form-section { + background-color: var(--white); + border-radius: 6px; + padding: 20px; + box-shadow: 0 2px 5px var(--shadow-color); + border-left: 4px solid var(--secondary-purple); + margin-bottom: 20px; +} + +.candidate-form-modal .section-title { + margin-top: 0; + margin-bottom: 20px; + color: var(--text-primary); + font-size: 18px; + display: flex; + align-items: center; + gap: 10px; +} + +.candidate-form-modal .section-title i { + color: var(--secondary-purple); +} + +.candidate-form-modal .form-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 20px; +} + +.candidate-form-modal .form-group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.candidate-form-modal .form-group label { + font-weight: 500; + color: var(--text-secondary); + font-size: 14px; +} + +.candidate-form-modal .form-input, +.candidate-form-modal .form-select, +.candidate-form-modal .form-textarea { + width: 100%; + padding: 10px 12px; + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 14px; + transition: border-color 0.3s, box-shadow 0.3s; + background-color: var(--white); + color: var(--text-primary); +} + +.candidate-form-modal .form-input:focus, +.candidate-form-modal .form-select:focus, +.candidate-form-modal .form-textarea:focus { + border-color: var(--secondary-purple); + box-shadow: 0 0 0 3px var(--primary-blue-light); + outline: none; +} + +/* Resume Section */ +.candidate-form-modal .resume-upload-container { + display: flex; + gap: 20px; +} + +.candidate-form-modal .resume-upload-area { + flex: 1; + border: 2px dashed var(--border-color); + border-radius: 6px; + padding: 30px; + text-align: center; + cursor: pointer; + transition: all 0.3s; + max-width: 30%; +} + +.candidate-form-modal .resume-upload-area:hover { + border-color: var(--primary-blue); + background-color: var(--gray-50); +} + +.candidate-form-modal .upload-icon { + font-size: 40px; + color: var(--primary-blue); + margin-bottom: 10px; +} + +.candidate-form-modal .resume-upload-area h5 { + margin: 0 0 5px; + color: var(--text-primary); +} + +.candidate-form-modal .resume-upload-area p { + margin: 0; + color: var(--text-muted); + font-size: 14px; +} + +.candidate-form-modal .resume-preview { + flex: 1; + border: 1px solid var(--border-light); + border-radius: 6px; + padding: 15px; + min-height: 200px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: var(--gray-50); +} + +.candidate-form-modal .resume-preview-placeholder { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + color: var(--text-muted); + height: 100%; +} + +.candidate-form-modal .resume-preview-placeholder i { + font-size: 40px; + margin-bottom: 10px; + color: var(--primary-blue); +} + +.candidate-form-modal .btn-danger { + background-color: var(--danger); + color: white; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; +} + +.candidate-form-modal .btn-danger:hover { + background-color: #dc3545; +} + +/* Make sure dropzone doesn't interfere with child elements */ +.candidate-form-modal .resume-upload-area > * { + pointer-events: none; +} + +.candidate-form-modal .resume-upload-area input { + pointer-events: auto; +} + +.candidate-form-modal #resume-iframe { + width: 100%; + height: 500px; + border: none; +} + +.candidate-form-modal #resume-image { + max-width: 100%; + max-height: 500px; + object-fit: contain; +} + +.candidate-form-modal #unsupported-format { + text-align: center; + color: var(--danger); +} + +.candidate-form-modal #unsupported-format i { + font-size: 40px; + margin-bottom: 10px; +} + +.candidate-form-modal #download-resume { + display: inline-flex; + align-items: center; + gap: 5px; +} + +/* Skills Section */ +.candidate-form-modal .skills-container { + margin-top: 15px; +} + +.candidate-form-modal .skills-list { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 15px; +} + +.candidate-form-modal .skill-tag { + background-color: var(--primary-blue); + color: white; + padding: 5px 10px; + border-radius: 4px; + font-size: 14px; + display: flex; + align-items: center; + gap: 5px; +} + +.candidate-form-modal .skill-tag i { + cursor: pointer; + font-size: 12px; +} + +.candidate-form-modal .btn-add-skill { + background-color: transparent; + color: var(--primary-blue); + border: 1px solid var(--primary-blue); + padding: 8px 15px; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; + transition: all 0.3s; +} + +.candidate-form-modal .btn-add-skill:hover { + background-color: var(--primary-blue-light); +} + +/* Notebook Tabs */ +.candidate-form-modal .notebook-tabs { + display: flex; + border-bottom: 1px solid var(--border-light); + margin-bottom: 20px; +} + +.candidate-form-modal .tab { + padding: 10px 20px; + cursor: pointer; + border-bottom: 3px solid transparent; + transition: all 0.3s; +} + +.candidate-form-modal .tab.active { + border-bottom-color: var(--primary-blue); + color: var(--primary-blue); + font-weight: 600; +} + +.candidate-form-modal .tab:hover:not(.active) { + background-color: var(--gray-50); +} + +.candidate-form-modal .notebook-content { + margin-top: 15px; +} + +.candidate-form-modal .tab-content { + display: none; +} + +.candidate-form-modal .tab-content.active { + display: block; +} + +/* Sub-sections in notebook */ +.candidate-form-modal .sub-section { + margin-bottom: 30px; +} + +.candidate-form-modal .sub-section-title { + display: flex; + align-items: center; + gap: 10px; + color: var(--text-primary); + font-size: 16px; + margin-bottom: 15px; +} + +.candidate-form-modal .sub-section-title i { + color: var(--secondary-purple); +} + +/* Form Actions */ +.candidate-form-modal .form-actions { + position: sticky; + bottom: 0; + background: var(--white); + padding: 15px 25px; + border-top: 1px solid var(--border-light); + z-index: 100; + margin-top: auto; + display: flex; + justify-content: space-between; + align-items: center; +} + +.candidate-form-modal .btn-cancel { + padding: 10px 20px; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + transition: transform 0.2s, box-shadow 0.2s; + background-color: var(--gray-100); + color: var(--text-secondary); + border: 1px solid var(--border-color); +} + +.candidate-form-modal .btn-cancel:hover { + background-color: var(--gray-200); +} + +.candidate-form-modal .btn-candidate-primary { + padding: 10px 20px; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + transition: transform 0.2s, box-shadow 0.2s; + display: flex; + align-items: center; + gap: 8px; + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue) 100%); + color: var(--white); + border: none; +} + +.candidate-form-modal .btn-candidate-primary:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px var(--shadow-color); + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue-dark) 100%); +} + +.candidate-form-modal .footer-right { + display: flex; + gap: 10px; +} + +.candidate-form-modal .select2-container { + z-index: 10000 !important; + width: 100% !important; +} + +.candidate-form-modal .select2-container--default .select2-selection--multiple, +.candidate-form-modal .select2-container--default .select2-selection--single { + border: 1px solid var(--border-color) !important; + border-radius: 4px !important; + min-height: 40px; + background-color: var(--white); + padding: 5px 5px 0 5px !important; +} + +.candidate-form-modal .select2-container--default .select2-selection--multiple .select2-selection__choice { + background-color: var(--primary-blue) !important; + border: none !important; + color: var(--white) !important; + padding: 2px 8px !important; +} + +.candidate-form-modal .select2-container--default .select2-selection--multiple .select2-selection__choice__remove { + color: var(--white) !important; +} + +.application-creation-modal .select2-dropdown { + border: 1px solid var(--border-color) !important; + box-shadow: 0 2px 5px var(--shadow-color) !important; +} + +.candidate-form-modal .select2-container--default .select2-selection__rendered { + display: flex !important; + align-items: center !important; + vertical-align: middle !important; + line-height: normal !important; + color: var(--text-primary); + padding: 2px 5px !important; +} +.candidate-form-modal .select2-container--default .select2-selection--multiple .select2-selection__rendered { + display: flex !important; + flex-wrap: wrap !important; + align-items: center !important; + width: 100% !important; + padding: 2px 5px !important; + overflow: visible !important; + box-sizing: border-box !important; +} + +.candidate-form-modal .select2-container--default .select2-results__option--highlighted[aria-selected] { + background-color: var(--primary-blue) !important; + color: var(--white) !important; +} + +/* Scrollbar styling */ +.candidate-form-modal .candidate-form-body::-webkit-scrollbar { + width: 8px; +} + +.candidate-form-modal .candidate-form-body::-webkit-scrollbar-track { + background: var(--gray-100); +} + +.candidate-form-modal .candidate-form-body::-webkit-scrollbar-thumb { + background: var(--primary-blue); + border-radius: 4px; +} + +.candidate-form-modal .candidate-form-body::-webkit-scrollbar-thumb:hover { + background: var(--primary-blue-dark); +} + + + +.candidate-form-modal .btn-candidate-primary { + padding: 10px 20px; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + transition: transform 0.2s, box-shadow 0.2s; + display: flex; + align-items: center; + gap: 8px; + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue) 100%); + color: var(--white); + border: none; +} + +.candidate-form-modal .btn-candidate-primary:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px var(--shadow-color); + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue-dark) 100%); +} + + +/* Responsive adjustments */ +@media (max-width: 1024px) { + .candidate-form-modal .candidate-form-content { + width: 95%; + } + + .candidate-form-modal .resume-upload-container { + flex-direction: column; + } +} + +@media (max-width: 768px) { + .candidate-form-modal .candidate-form-content { + width: 98%; + height: 95vh; + } + + .candidate-form-modal .form-grid { + grid-template-columns: 1fr; + } + + .candidate-form-modal .avatar-container { + flex-direction: column; + text-align: center; + } + + .candidate-form-modal .button-box { + justify-content: center; + } + + .candidate-form-modal .stat-button { + min-width: 150px; + } +} diff --git a/addons_extensions/hr_recruitment_web_app/static/src/css/colors.css b/addons_extensions/hr_recruitment_web_app/static/src/css/colors.css new file mode 100644 index 000000000..10a62fe2f --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/css/colors.css @@ -0,0 +1,66 @@ +:root { + /* Primary Colors */ + --primary-blue: #3498db; + --primary-blue-dark: #2980b9; + --primary-blue-light: #e8f0ff; + + /* Secondary Colors */ + --secondary-purple: #6f42c1; + --secondary-green: #28a745; + --secondary-red: #dc3545; + --secondary-yellow: #ffc107; + + /* Grayscale */ + --white: #ffffff; + --gray-100: #f8f9fa; + --gray-200: #e9ecef; + --gray-300: #dee2e6; + --gray-400: #ced4da; + --gray-500: #adb5bd; + --gray-600: #6c757d; + --gray-700: #495057; + --gray-800: #343a40; + --gray-900: #212529; + --black: #000000; + + /* Semantic Colors */ + --success: #28a745; + --info: #17a2b8; + --warning: #ffc107; + --danger: #dc3545; + + /* Background Colors */ + --body-bg: #f5f6fa; + --sidebar-bg: #FAFCFF; + --create-model-bg: #FAFCFF; + --content-bg: #E3E9EF; + --active-search-bg: #ffffff; + --active-search-hover-bg: #f0f0f0; + --add-btn-bg: #3498db; + --add-btn-hover-bg: #2980b9; + --side-panel-bg: #FAFCFF; + --side-panel-item-hover: #f0f8ff; + --side-panel-item-selected: #d7eaff; + + /* Text Colors */ + --text-primary: #2f3542; + --text-secondary: #4B5865; + --text-muted: #6c757d; + --sidebar-text: #0F1419; + --active-search-text: #333; + --add-btn-color: #ffffff; + + /* Border Colors */ + --border-color: #dcdde1; + --border-light: #e0e0e0; + + /* Shadow Colors */ + --shadow-color: rgba(0, 0, 0, 0.1); + --shadow-dark: rgba(0, 0, 0, 0.2); + + /* Status Colors */ + --status-new: #3498db; + --status-interview: #f39c12; + --status-hired: #2ecc71; + --status-rejected: #e74c3c; +} \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/static/src/css/content.css b/addons_extensions/hr_recruitment_web_app/static/src/css/content.css new file mode 100644 index 000000000..c86066b67 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/css/content.css @@ -0,0 +1,1055 @@ +@import url('colors.css'); + +/* Main Container */ +#ats-details-container { + overflow-y: auto; + max-height: 100%; + position: relative; + background-color: var(--content-bg); +} + +/* Grid Layout */ +.ats-grid { + display: grid; + grid-template-columns: repeat(12, 1fr); + grid-auto-rows: minmax(100px, auto); + gap: 20px; + padding: 20px; + font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + color: var(--text-primary); + background-color: var(--content-bg); + max-width: 100%; + margin: 0 auto; + transition: all 0.3s ease; + overflow: hidden; +} + +/* Card Base */ +.ats-grid .ats-card { + overflow: hidden; + background-color: var(--sidebar-bg); + border-radius: 12px; + padding: 25px; + margin-bottom: 25px; + box-shadow: 0 4px 20px var(--shadow-color); + transition: all 0.3s ease; + border: 1px solid var(--border-light); +} + +/* Hover Effect */ +.ats-grid .ats-card:hover { + box-shadow: 0 8px 30px var(--shadow-dark); + transform: translateY(-5px); +} + +/* Width Span Utilities */ +.ats-grid .span-1 { grid-column: span 1; } +.ats-grid .span-2 { grid-column: span 2; } +.ats-grid .span-3 { grid-column: span 3; } +.ats-grid .span-4 { grid-column: span 4; } +.ats-grid .span-5 { grid-column: span 5; } +.ats-grid .span-6 { grid-column: span 6; } +.ats-grid .span-7 { grid-column: span 7; } +.ats-grid .span-8 { grid-column: span 8; } +.ats-grid .span-9 { grid-column: span 9; } +.ats-grid .span-10 { grid-column: span 10; } +.ats-grid .span-11 { grid-column: span 11; } +.ats-grid .span-12 { grid-column: span 12; } + +/* Navigation Sidebar */ +.ats-grid #ats-overview { + background-color: var(--gray-800); + color: var(--white); + padding: 20px; + border-radius: 12px; + box-shadow: 0 8px 24px var(--shadow-dark); + transition: all 0.3s ease; + font-family: 'Segoe UI', Tahoma, sans-serif; + width: 220px; + border: 1px solid var(--gray-700); +} + +.ats-grid #ats-overview h3, +.ats-grid #ats-overview .section-title { + border-bottom: 1px solid var(--gray-700); + margin-bottom: 12px; + padding-bottom: 8px; + font-weight: 600; + color: var(--gray-200); +} + +.ats-grid .overview-nav { + padding: 10px 0; +} + +.ats-grid .nav-list { + list-style: none; + padding: 0; + margin: 0; +} + +.ats-grid .nav-list li { + margin-bottom: 8px; + position: relative; + padding-left: 0px; +} + +.ats-grid .nav-link { + display: flex; + align-items: center; + padding-top: 5px; + padding-bottom: 5px; + color: var(--gray-300); + text-decoration: none; + border-radius: 6px; + transition: all 0.3s ease; + font-size: 14px; +} + +.ats-grid .nav-link:hover { + background-color: var(--gray-700); + color: var(--white); + transform: translateX(6px); + box-shadow: 3px 3px 10px var(--shadow-dark); + font-weight: 600; + letter-spacing: 0.5px; +} + +.ats-grid .nav-link i { + width: 20px; + text-align: center; +} + +/* Header Section */ +.ats-grid .ats-title { + font-size: 28px; + font-weight: 600; + margin-bottom: 15px; + color: var(--text-primary); +} + +.ats-grid .ats-meta { + display: flex; + flex-wrap: wrap; + gap: 15px; + margin-bottom: 20px; + color: var(--text-muted); +} + +.ats-grid .meta-item { + display: flex; + align-items: center; + font-size: 14px; +} + +/* Status Bar */ +.ats-grid .status-bar { + background-color: var(--gray-100); + padding: 15px; + border-radius: 8px; + margin-bottom: 20px; +} + +.ats-grid .recruitment-status { + margin-bottom: 10px; +} + +.ats-grid .status-label { + font-weight: 600; + color: var(--text-secondary); +} + +.ats-grid .status-value { + font-weight: 500; + color: var(--text-primary); +} + +.ats-grid .recruitment-progress .progress { + height: 10px; + border-radius: 5px; + background-color: var(--gray-200); +} + +.ats-grid .progress-bar { + background-color: var(--primary-blue); +} + +/* Section Titles */ +.ats-grid .section-title { + margin: 0; + padding-bottom: 20px; + font-size: 18px; + font-weight: 600; + color: var(--text-primary); + display: flex; + align-items: center; + border-bottom: 2px solid var(--gray-200); + transition: all 0.3s ease; +} + +.ats-grid .ats-card:hover .section-title { + border-color: var(--gray-300); +} + +.ats-grid .section-title i { + color: var(--text-muted); + transition: all 0.3s ease; +} + + +.ats-grid .section-title small { + margin-left: auto; /* This pushes the small element to the right */ + font-weight: normal; + font-size: 0.85em; + color: var(--text-muted); +} + +/* Detail Grid */ +.ats-grid .detail-grid { + display: grid; + grid-template-columns: 1fr; + gap: 10px; + margin-top: 0px; +} + +.ats-grid .detail-row { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: center; +} + +.ats-grid .detail-row:hover { + background-color: var(--gray-100); + border-radius: 3px; +} + +.ats-grid .detail-label { + font-weight: 500; + color: var(--text-secondary); + min-width: 120px; + font-size: 15px; + flex-shrink: 0; +} + +.ats-grid .span-6 .detail-label { + min-width: 160px; +} + +.ats-grid .detail-value { + color: var(--text-primary); + font-weight: 400; + flex: 1; + font-size: 13px; + word-break: break-word; + overflow-wrap: break-word; +} + +/* Skills and Location Badges */ +.ats-grid .skills-list { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.ats-grid .skill-badge, +.ats-grid .location-badge { + background-color: var(--gray-100); + color: var(--primary-blue); + padding: 6px 12px; + border-radius: 20px; + transition: all 0.3s ease; +} + +.ats-grid .skill-badge:hover, +.ats-grid .location-badge:hover { + background-color: var(--gray-200); + transform: translateY(-3px); + box-shadow: 0 4px 8px rgba(15, 81, 50, 0.1); +} + +/* Team Members */ +.ats-grid .team-member { + margin-bottom: 20px; +} + +.ats-grid .member-header { + font-weight: 600; + color: var(--text-primary); + margin-bottom: 10px; + display: flex; + align-items: center; +} + +.ats-grid .member-title { + margin-left: 5px; +} + +.ats-grid .recruiter-photo { + width: 60px; + height: 60px; + object-fit: cover; + border: 2px solid var(--gray-200); +} + +.ats-grid .member-name { + font-weight: 600; + color: var(--text-primary); +} + +.ats-grid .member-email { + font-size: 13px; + color: var(--text-muted); +} + +/* Description Content */ +.ats-grid .description-content { + line-height: 1.6; + color: var(--text-primary); +} + +.ats-grid .description-content p { + margin-bottom: 15px; +} + +.ats-grid .description-content ul, +.ats-grid .description-content ol { + padding-left: 20px; + margin-bottom: 15px; +} + +/* Responsive fallback */ +@media (max-width: 768px) { + .ats-grid { + grid-template-columns: repeat(2, 1fr); + } + .ats-grid .ats-card { + grid-column: span 2 !important; + } +} + +@media print { + #ats-details-container { + max-height: none; + overflow-y: visible; + } +} + + +/* Smart Button Container */ +.smart-button-container { + position: fixed; + top: 20%; + right: 1%; + z-index: 1000; + display: flex; + gap: 10px; + flex-direction: column; + align-items: flex-end; +} + +.smart-button { + background-color: var(--primary-blue); + color: var(--white); + border: none; + border-radius: 8px; + padding: 10px 16px; + font-weight: 500; + font-size: 14px; + box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3); + transition: all 0.3s ease; + display: flex; + align-items: center; + gap: 8px; + min-width: 180px; + justify-content: center; +} + +.smart-button:hover { + background-color: var(--primary-blue-dark); + transform: translateY(-3px); + box-shadow: 0 6px 16px rgba(52, 152, 219, 0.4); +} + +.smart-button:active { + transform: translateY(1px); + box-shadow: 0 2px 8px rgba(52, 152, 219, 0.3); +} + +.smart-button i { + transition: transform 0.3s ease; +} + +.smart-button:hover i { + transform: rotate(15deg); +} + +/* Published Ribbon */ +.status-ribbon { + position: absolute; + top: 35px; + right: -30px; + transform: rotate(45deg); + padding: 8px 40px; + font-size: 14px; + font-weight: 600; + color: var(--white); + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2); + z-index: 100; + transition: all 0.3s ease; + text-transform: uppercase; + letter-spacing: 1px; +} + +.status-ribbon.ribbon-published { + background: linear-gradient(45deg, var(--success), #2ecc71); +} + +.status-ribbon.ribbon-not-published { + background: linear-gradient(45deg, var(--danger), #e74c3c); +} + +.status-ribbon:hover { + transform: rotate(45deg) scale(1.05); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); +} + +/* Professional Typography */ +.ats-grid { + font-family: 'Inter', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + letter-spacing: 0.01em; +} + +.ats-grid .ats-title { + font-size: 28px; + font-weight: 700; + letter-spacing: -0.01em; + line-height: 1.2; + margin-bottom: 16px; + color: var(--text-primary); +} + +.ats-grid .section-title { + font-size: 18px; + font-weight: 600; + letter-spacing: -0.01em; + margin-bottom: 20px; + padding-bottom: 12px; + border-bottom: 2px solid var(--gray-200); +} + +.ats-grid .detail-label { + font-weight: 600; + color: var(--text-secondary); + font-size: 15px; +} + +.ats-grid .detail-value { + font-weight: 500; + color: var(--text-primary); + font-size: 15px; +} + +.ats-grid .meta-item { + font-size: 14px; + font-weight: 500; + color: var(--text-secondary); +} + +.ats-grid .status-label { + font-weight: 600; + color: var(--text-secondary); + font-size: 14px; +} + +.ats-grid .status-value { + font-weight: 500; + color: var(--text-primary); + font-size: 14px; +} + +.ats-grid .skill-badge, +.ats-grid .location-badge { + font-size: 13px; + font-weight: 500; +} + +/* Smooth animations for all interactive elements */ +.ats-grid .ats-card { + transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +.ats-grid .detail-row { + transition: background-color 0.2s ease; +} + +.ats-grid .nav-link { + transition: all 0.3s ease; +} + +.ats-grid .skill-badge, +.ats-grid .location-badge { + transition: all 0.3s ease; +} + +/* Professional shadows and borders */ +.ats-grid .ats-card { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + border: 1px solid rgba(0, 0, 0, 0.05); +} + +.ats-grid .ats-card:hover { + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); + border-color: rgba(0, 0, 0, 0.08); +} + +/* Close button styling */ +.close-detail { + position: absolute; + top: 15px; + left: 15px; + width: 36px; + height: 36px; + border-radius: 50%; + background-color: var(--white); + border: none; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + z-index: 100; + cursor: pointer; + transition: all 0.3s ease; +} + +.close-detail:hover { + background-color: var(--gray-100); + transform: rotate(90deg); +} + +.close-detail span { + font-size: 20px; + color: var(--text-secondary); + line-height: 1; +} + + +/* ===== Work Experience Section ===== */ +.ats-grid .experience-list { + display: flex; + flex-direction: column; + gap: 20px; + margin-top: 15px; +} + +.ats-grid .experience-item { + background-color: var(--white); + border-radius: 10px; + padding: 20px; + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); + border-left: 4px solid var(--primary-blue); + transition: all 0.3s ease; + position: relative; +} + +.ats-grid .experience-item:hover { + transform: translateY(-3px); + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.12); +} + +.ats-grid .exp-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 12px; +} + +.ats-grid .exp-header h5 { + font-size: 18px; + font-weight: 600; + color: var(--text-primary); + margin: 0; +} + +.ats-grid .exp-company { + font-size: 16px; + color: var(--primary-blue); + font-weight: 500; + background-color: rgba(52, 152, 219, 0.1); + padding: 4px 12px; + border-radius: 20px; +} + +.ats-grid .exp-duration { + display: flex; + align-items: center; + font-size: 14px; + color: var(--text-secondary); + margin-bottom: 8px; +} + +.ats-grid .exp-duration i { + color: var(--primary-blue); + margin-right: 8px; +} + +.ats-grid .exp-ctc { + display: flex; + align-items: center; + font-size: 14px; + color: var(--text-primary); + font-weight: 500; +} + +.ats-grid .exp-ctc i { + color: var(--success); + margin-right: 8px; +} + +/* ===== Education Section ===== */ +.ats-grid .education-list { + display: flex; + flex-direction: column; + gap: 20px; + margin-top: 15px; +} + +.ats-grid .education-item { + background-color: var(--white); + border-radius: 10px; + padding: 20px; + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); + border-left: 4px solid var(--success); + transition: all 0.3s ease; + position: relative; +} + +.ats-grid .education-item:hover { + transform: translateY(-3px); + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.12); +} + +.ats-grid .edu-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 12px; +} + +.ats-grid .edu-header h5 { + font-size: 18px; + font-weight: 600; + color: var(--text-primary); + margin: 0; +} + +.ats-grid .edu-type { + font-size: 14px; + color: var(--white); + font-weight: 500; + background-color: var(--success); + padding: 4px 12px; + border-radius: 20px; +} + +.ats-grid .edu-university { + font-size: 15px; + color: var(--text-secondary); + margin-bottom: 8px; + font-style: italic; +} + +.ats-grid .edu-duration { + display: flex; + align-items: center; + font-size: 14px; + color: var(--text-secondary); + margin-bottom: 8px; +} + +.ats-grid .edu-duration i { + color: var(--success); + margin-right: 8px; +} + +.ats-grid .edu-marks { + display: flex; + align-items: center; + font-size: 14px; + color: var(--text-primary); + font-weight: 500; +} + +.ats-grid .edu-marks i { + color: var(--warning); + margin-right: 8px; +} + +/* ===== Skills Section ===== */ +.ats-grid .skills-container { + display: flex; + flex-direction: column; + gap: 15px; + margin-top: 15px; +} + +.ats-grid .skill-item { + background-color: var(--white); + border-radius: 10px; + padding: 15px 20px; + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; +} + +.ats-grid .skill-item:hover { + transform: translateY(-3px); + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.12); +} + +.ats-grid .skill-info { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; +} + +.ats-grid .skill-name { + font-size: 16px; + font-weight: 600; + color: var(--text-primary); +} + +.ats-grid .skill-type { + font-size: 13px; + color: var(--white); + background-color: var(--primary-blue); + padding: 3px 10px; + border-radius: 15px; +} + +.ats-grid .skill-level { + display: flex; + flex-direction: column; + gap: 8px; +} + +.ats-grid .skill-level-name { + font-size: 13px; + color: var(--text-secondary); + text-align: right; +} + +.ats-grid .progress { + height: 8px; + border-radius: 4px; + background-color: var(--gray-200); + overflow: hidden; +} + +.ats-grid .progress-bar { + height: 100%; + border-radius: 4px; + background: linear-gradient(90deg, var(--primary-blue), #3498db); + transition: width 1s ease-in-out; +} + +/* ===== Attachments Section ===== */ +.ats-grid .attachments-list { + display: flex; + flex-direction: column; + gap: 15px; + margin-top: 15px; +} + +.ats-grid .attachment-card { + background-color: var(--white); + border-radius: 10px; + padding: 15px 20px; + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; +} + +.ats-grid .attachment-card:hover { + transform: translateY(-3px); + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.12); +} + +.ats-grid .attachment-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; +} + +.ats-grid .attachment-title { + font-size: 16px; + font-weight: 600; + color: var(--text-primary); + word-break: break-word; + max-width: 70%; +} + +.ats-grid .attachment-badge { + font-size: 12px; + color: var(--white); + padding: 3px 10px; + border-radius: 15px; +} + +.ats-grid .attachment-badge.bg-success { + background-color: var(--success); +} + +.ats-grid .attachment-badge.bg-danger { + background-color: var(--danger); +} + +.ats-grid .attachment-badge.bg-secondary { + background-color: var(--gray-500); +} + +.ats-grid .attachment-actions { + display: flex; + gap: 10px; +} + +.ats-grid .document-action-btn { + display: flex; + align-items: center; + gap: 5px; + font-size: 13px; + padding: 6px 12px; + border-radius: 6px; + transition: all 0.2s ease; +} + +.ats-grid .document-action-btn:hover { + transform: translateY(-2px); +} + +.ats-grid .preview-btn { + background-color: var(--primary-blue); + color: var(--white); + border: 1px solid var(--primary-blue); +} + +.ats-grid .preview-btn:hover { + background-color: var(--white); + color: var(--primary-blue); +} + +.ats-grid .download-btn { + background-color: var(--success); + color: var(--white); + border: 1px solid var(--success); +} + +.ats-grid .download-btn:hover { + background-color: var(--white); + color: var(--success); +} + +/* ===== Timeline Section ===== */ +.ats-grid .timeline { + position: relative; + margin-top: 20px; + padding-left: 30px; +} + +.ats-grid .timeline::before { + content: ''; + position: absolute; + top: 0; + left: 8px; + height: 100%; + width: 2px; + background-color: var(--gray-300); +} + +.ats-grid .timeline-item { + position: relative; + margin-bottom: 25px; +} + +.ats-grid .timeline-point { + position: absolute; + left: -30px; + width: 16px; + height: 16px; + border-radius: 50%; + background-color: var(--primary-blue); + border: 3px solid var(--white); + box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.3); +} + +.ats-grid .timeline-point.point-interview { + background-color: var(--warning); + box-shadow: 0 0 0 3px rgba(243, 156, 18, 0.3); +} + +.ats-grid .timeline-content { + background-color: var(--white); + border-radius: 8px; + padding: 15px 20px; + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; +} + +.ats-grid .timeline-content:hover { + transform: translateY(-3px); + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.12); +} + +.ats-grid .timeline-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; +} + +.ats-grid .timeline-header h5 { + font-size: 16px; + font-weight: 600; + color: var(--text-primary); + margin: 0; +} + +.ats-grid .timeline-date { + font-size: 13px; + color: var(--text-secondary); +} + +.ats-grid .timeline-body { + font-size: 14px; + color: var(--text-secondary); + line-height: 1.5; +} + +.ats-grid .timeline-body p { + margin: 0; +} + +/* ===== Alert Messages ===== */ +.ats-grid .alert { + border-radius: 8px; + padding: 15px 20px; + border: none; + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); +} + +.ats-grid .alert-info { + background-color: rgba(23, 162, 184, 0.1); + color: var(--info); + border-left: 4px solid var(--info); +} + +/* ===== Responsive Design ===== */ +@media (max-width: 768px) { + .ats-grid .exp-header, .ats-grid .edu-header { + flex-direction: column; + gap: 8px; + } + + .ats-grid .skill-info { + flex-direction: column; + align-items: flex-start; + gap: 8px; + } + + .ats-grid .attachment-header { + flex-direction: column; + align-items: flex-start; + gap: 8px; + } + + .ats-grid .attachment-title { + max-width: 100%; + } + + .ats-grid .timeline-header { + flex-direction: column; + align-items: flex-start; + gap: 5px; + } +} + +/* ===== Avatar Styling ===== */ +.ats-grid .avatar-wrapper { + position: relative; + width: 120px; + height: 120px; + margin-left: auto; +} + +.ats-grid .avatar-img { + width: 100%; + height: 100%; + object-fit: cover; + border: 3px solid var(--primary-blue); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +.ats-grid .avatar-placeholder { + width: 100%; + height: 100%; + background: linear-gradient(135deg, var(--primary-blue), #3498db); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + border: 3px solid var(--primary-blue); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + position: relative; + overflow: hidden; +} + +.ats-grid .avatar-placeholder::before { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient( + to right, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 0.1) 50%, + rgba(255, 255, 255, 0) 100% + ); + transform: rotate(30deg); +} + +.ats-grid .applicant-img-placeholder { + font-size: 48px; + font-weight: 700; + color: white; + text-transform: uppercase; + position: relative; + z-index: 1; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.ats-grid .avatar-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.3s ease; + cursor: pointer; +} + +.ats-grid .avatar-wrapper:hover .avatar-overlay { + opacity: 1; +} + +.ats-grid .avatar-overlay i { + color: white; + font-size: 24px; +} \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/static/src/css/jd.css b/addons_extensions/hr_recruitment_web_app/static/src/css/jd.css new file mode 100644 index 000000000..c13626614 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/css/jd.css @@ -0,0 +1,1122 @@ +@import url('colors.css'); + +/* ===== JD Modal Styles - Professional Version ===== */ +.new-jd-container.jd-modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 1000; + justify-content: center; + align-items: center; + opacity: 0; + transition: opacity 0.3s ease; +} + +.new-jd-container.jd-modal.show { + display: flex; + opacity: 1; +} + +.new-jd-container .jd-modal-content { + background-color: var(--white); + width: 85%; + max-width: 1200px; + border-radius: 8px; + box-shadow: 0 5px 20px var(--shadow-dark); + transform: translateY(-20px); + transition: transform 0.3s ease; + max-height: 90vh; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.new-jd-container.jd-modal.show .jd-modal-content { + transform: translateY(0); +} + +.new-jd-container .jd-modal-header { + padding: 20px; + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue) 100%); + color: var(--white); + border-radius: 8px 8px 0 0; + display: flex; + justify-content: space-between; + align-items: center; + position: sticky; + top: 0; + z-index: 100; +} + +.new-jd-container .header-content { + display: flex; + align-items: center; + gap: 15px; +} + +.new-jd-container .header-icon { + font-size: 24px; + color: var(--white); +} + +.new-jd-container .jd-modal-header h3 { + margin: 0; + font-size: 1.4rem; + font-weight: 600; + color: var(--white); +} + +.new-jd-container .jd-modal-close { + font-size: 28px; + cursor: pointer; + transition: transform 0.2s; + color: var(--white); + background: none; + border: none; +} + +.new-jd-container .jd-modal-close:hover { + transform: scale(1.2); + color: var(--gray-200); +} + +.new-jd-container .jd-modal-body { + padding: 25px; + overflow-y: auto; + flex-grow: 1; +} + +.new-jd-container .form-section { + background-color: var(--white); + border-radius: 6px; + padding: 20px; + box-shadow: 0 2px 5px var(--shadow-color); + border-left: 4px solid var(--secondary-purple); + margin-bottom: 20px; +} + +.new-jd-container .section-title { + margin-top: 0; + margin-bottom: 20px; + color: var(--text-primary); + font-size: 18px; + display: flex; + align-items: center; + gap: 10px; +} + +.new-jd-container .section-title i { + color: var(--secondary-purple); +} + +.new-jd-container .form-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 20px; +} + +.new-jd-container .form-group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.new-jd-container .form-group label { + font-weight: 500; + color: var(--text-secondary); + font-size: 14px; +} + +.new-jd-container .form-control, +.new-jd-container .form-input, +.new-jd-container .form-select, +.new-jd-container .form-textarea { + width: 100%; + padding: 10px 12px; + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 14px; + transition: border-color 0.3s, box-shadow 0.3s; + background-color: var(--white); + color: var(--text-primary); +} + +.new-jd-container .form-control:focus, +.new-jd-container .form-input:focus, +.new-jd-container .form-select:focus, +.new-jd-container .form-textarea:focus { + border-color: var(--secondary-purple); + box-shadow: 0 0 0 3px var(--primary-blue-light); + outline: none; +} + +.new-jd-container .radio-group { + display: flex; + gap: 15px; +} + +.new-jd-container .radio-option { + flex: 1; +} + +.new-jd-container .radio-option input[type="radio"] { + display: none; +} + +.new-jd-container .radio-option label { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 10px; + border: 1px solid var(--border-color); + border-radius: 6px; + cursor: pointer; + transition: all 0.3s; + background-color: var(--gray-100); + font-weight: normal; + margin: 0; +} + +.new-jd-container .radio-option input[type="radio"]:checked + label { + border-color: var(--primary-blue); + background-color: rgba(52, 152, 219, 0.1); + color: var(--primary-blue); +} + +.new-jd-container .two-columns { + display: flex; + gap: 15px; +} + +.new-jd-container .two-columns .half-width { + width: 48%; +} + +.new-jd-container .input-with-icon { + position: relative; + display: flex; + align-items: center; +} + +.new-jd-container .input-with-icon i { + position: absolute; + left: 10px; + color: var(--text-muted); +} + +.new-jd-container .input-with-icon input, +.new-jd-container .input-with-icon select { + padding-left: 35px; + width: 100%; +} + +.new-jd-container .jd-modal-footer { + padding: 15px 20px; + background-color: var(--white); + border-top: 1px solid var(--border-light); + display: flex; + justify-content: space-between; + align-items: center; + position: sticky; + bottom: 0; + z-index: 100; +} + +.new-jd-container .btn { + padding: 10px 20px; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + transition: transform 0.2s, box-shadow 0.2s; + display: flex; + align-items: center; + gap: 8px; +} + +.new-jd-container .btn-secondary { + background-color: var(--gray-100); + color: var(--text-secondary); + border: 1px solid var(--border-color); +} + +.new-jd-container .btn-secondary:hover { + background-color: var(--gray-200); +} + +.new-jd-container .btn-primary { + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue) 100%); + color: var(--white); + border: none; +} + +.new-jd-container .btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px var(--shadow-color); + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue-dark) 100%); +} + +.new-jd-container .footer-right { + display: flex; + gap: 10px; +} + +/* Select2 custom styles to match the theme */ +.new-jd-container .select2-container--default .select2-selection--multiple, +.new-jd-container .select2-container--default .select2-selection--single { + border: 1px solid var(--border-color) !important; + border-radius: 4px !important; + min-height: 40px; + background-color: var(--white); +} + +.new-jd-container .select2-container--default .select2-selection--multiple .select2-selection__choice { + background-color: var(--primary-blue) !important; + border: none !important; + color: var(--white) !important; +} + +.new-jd-container .select2-container--default .select2-selection--multiple .select2-selection__choice__remove { + color: var(--white) !important; +} + +.new-jd-container .select2-dropdown { + border: 1px solid var(--border-color) !important; + box-shadow: 0 2px 5px var(--shadow-color) !important; +} + +/* Scrollbar styling */ +.new-jd-container .jd-modal-body::-webkit-scrollbar { + width: 8px; +} + +.new-jd-container .jd-modal-body::-webkit-scrollbar-track { + background: var(--gray-100); +} + +.new-jd-container .jd-modal-body::-webkit-scrollbar-thumb { + background: var(--primary-blue); + border-radius: 4px; +} + +.new-jd-container .jd-modal-body::-webkit-scrollbar-thumb:hover { + background: var(--primary-blue-dark); +} + +/* CKEditor styles */ +.new-jd-container .ck.ck-label.ck-voice-label { + display: none !important; +} + +.new-jd-container .ck.ck-editor__editable { + min-height: 200px !important; + background-color: var(--white); + color: var(--text-primary); + border: 1px solid var(--gray-300) !important; +} + +.new-jd-container #job-description-editor { + min-height: 200px; + min-width: 100%; +} + +.new-jd-container .oe_editor * { + white-space: pre-wrap !important; + word-break: break-word !important; +} + +/* SELECT2 custom styles */ +.new-jd-container .select2-container { + z-index: 10000 !important; + width: 100% !important; +} + +.new-jd-container .select2-container--default .select2-selection__rendered { + display: flex !important; + align-items: center !important; + vertical-align: middle !important; + line-height: normal !important; + color: var(--text-primary); +} + +.new-jd-container .select2-container--default .select2-results__option--highlighted[aria-selected] { + background-color: var(--primary-blue) !important; + color: var(--white) !important; +} + +.new-jd-container .select2-container--default .select2-results__option[aria-selected=true] { + background-color: var(--gray-200) !important; + color: var(--text-primary) !important; +} + +.new-jd-container .select2-container--default .select2-search--dropdown .select2-search__field { + border: 1px solid var(--gray-300) !important; + border-radius: 4px !important; + padding: 6px 8px !important; +} + +.new-jd-container .select2-container--default .select2-selection--multiple .select2-selection__rendered { + display: flex !important; + flex-wrap: wrap !important; + align-items: center !important; + width: 100% !important; + padding: 2px 5px !important; + overflow: visible !important; + box-sizing: border-box !important; +} + +.new-jd-container .select2-container--default .select2-selection--multiple .select2-selection__choice { + display: inline-flex !important; + align-items: center !important; + background-color: var(--primary-blue) !important; + color: var(--white) !important; + border: none !important; + border-radius: 4px !important; + padding: 2px 8px !important; + margin: 2px !important; + max-width: 100% !important; + box-sizing: border-box !important; + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + float: none !important; + position: relative !important; + line-height: 1.5 !important; +} + +.new-jd-container .select2-container--default .select2-selection--multiple .select2-selection__choice__remove { + color: var(--white) !important; + margin-right: 5px !important; + order: -1 !important; +} + +/* Secondary Recruiter Specific Styles */ +.new-jd-container #secondary-recruiter + .select2-container--default .select2-selection--multiple { + height: auto !important; + min-height: 40px !important; + padding: 5px 5px 0 5px !important; +} + +.new-jd-container #secondary-recruiter + .select2-container--default .select2-selection__rendered { + display: block !important; + padding: 0 !important; + width: 100% !important; +} + +.new-jd-container #secondary-recruiter + .select2-container--default .select2-selection__choice { + display: flex !important; + align-items: center !important; + background-color: var(--primary-blue) !important; + color: var(--white) !important; + border: none !important; + border-radius: 4px !important; + padding: 4px 8px !important; + margin: 0 5px 5px 0 !important; + width: calc(100% - 10px) !important; + box-sizing: border-box !important; + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + float: none !important; +} + +/* Avatar styles for secondary recruiters */ +.new-jd-container #secondary-recruiter + .select2-container--default .select2-selection__choice .user-avatar { + width: 18px !important; + height: 18px !important; + border-radius: 50% !important; + margin-right: 8px !important; + object-fit: cover !important; + display: inline-block !important; + vertical-align: middle !important; +} + +/* Input field in multiple select */ +.new-jd-container .select2-container--default .select2-search--inline .select2-search__field { + margin: 0 !important; + padding: 0 !important; + height: auto !important; + min-height: 28px !important; + line-height: 28px !important; + width: 100% !important; + flex-grow: 1 !important; +} + +.new-jd-container .select2-selection__choice { + cursor: move; + user-select: none; +} + +.new-jd-container .select2-selection__choice:hover { + background-color: var(--active-search-hover-bg); +} + +/* Highlight drop target */ +.new-jd-container .select2-container--default .select2-selection--multiple.drag-over { + background-color: var(--side-panel-item-hover); + border: 2px dashed #3498db; +} + + +.new-jd-container .form-actions { + position: sticky; + bottom: 0; + background: var(--white); + padding: 15px 25px; + border-top: 1px solid var(--border-light); + z-index: 100; + margin-top: auto; + display: flex; + justify-content: space-between; + align-items: center; +} + +.new-jd-container .btn-cancel, .application-creation-modal .btn-jd-primary { + padding: 10px 20px; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + transition: transform 0.2s, box-shadow 0.2s; +} + +.new-jd-container .btn-cancel { + background-color: var(--gray-100); + color: var(--text-secondary); + border: 1px solid var(--border-color); +} + +.new-jd-container .btn-cancel:hover { + background-color: var(--gray-200); +} + +.new-jd-container .btn-jd-primary { + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue) 100%); + color: var(--white); + border: none; +} + +.new-jd-container .btn-jd-primary:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px var(--shadow-color); + background: linear-gradient(135deg, var(--secondary-purple) 0%, var(--primary-blue-dark) 100%); +} + +.new-jd-container .footer-right { + display: flex; + gap: 10px; +} + +/* Responsive adjustments */ +@media (max-width: 1024px) { + .new-jd-container .jd-modal-content { + width: 90%; + } +} + +@media (max-width: 768px) { + .new-jd-container .jd-modal-content { + width: 95%; + height: 95vh; + } + + .new-jd-container .form-grid { + grid-template-columns: 1fr; + } + + .new-jd-container .two-columns { + flex-direction: column; + } + + .new-jd-container .two-columns .half-width { + width: 100% !important; + } + + .new-jd-container .radio-group { + flex-direction: column; + } +} + +.new-jd-container .form-section.profile-section:first-child { + margin-top: 0; +} + +/* Client Information Section */ +.new-jd-container .client-session { + padding-top: 16px; +} + +.new-jd-container .client-session .form-grid, +.new-jd-container .additional-info .form-grid{ + grid-template-columns: repeat(2, 1fr); + gap: 8px; +} + +/* Description Section */ +.new-jd-container .form-section.description-section { + margin-bottom: 0; +} + +.new-jd-container .form-group.full-width { + grid-column: 1 / -1; +} + +/* Make sure the editor takes full width */ +.new-jd-container #job-description-editor { + width: 100%; + min-width: 100%; +} + +/* Adjust form grid for better spacing */ +.new-jd-container .form-grid { + gap: 15px; +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + .new-jd-container .form-section.profile-section:nth-child(3) .form-grid, + .new-jd-container .form-grid { + grid-template-columns: 1fr; + } + + .new-jd-container .form-group.full-width { + grid-column: auto; + } +} + + +/* Popup container styles */ +.popup-container { + position: fixed; + width: 400px; + max-height: 70vh; + min-height: 70vh; + background: white; + border-radius: 8px 8px 0 0; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); + z-index: 1000; + display: flex; + flex-direction: column; + overflow: hidden; + transition: transform 0.3s ease, opacity 0.3s ease; + transform: translateY(100%); + opacity: 0; + bottom: 30px; /* Consistent bottom spacing */ + right: 30px; /* Base right spacing */ +} + +.popup-container.visible { + transform: translateY(0); + opacity: 1; +} + +.popup-header { + padding: 12px 16px; + background: #f8f9fa; + border-bottom: 1px solid #e9ecef; + display: flex; + justify-content: space-between; + align-items: center; +} + +.popup-header h5 { + margin: 0; + font-size: 16px; + font-weight: 600; +} + +.popup-close { + background: none; + border: none; + font-size: 24px; + line-height: 1; + cursor: pointer; + padding: 0 0 4px 0; + color: #6c757d; +} + +.popup-body { + flex: 1; + overflow-y: auto; + position: relative; +} + +.popup-content { + padding: 16px; +} + +.loading-spinner { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + background: rgba(255, 255, 255, 0.8); +} + +.spinner { + width: 40px; + height: 40px; + border: 4px solid #f3f3f3; + border-top: 4px solid #3498db; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Stacking multiple popups - now using CSS variables for consistency */ +.popup-container { + --popup-width: 400px; + --spacing: 30px; + --gap: 20px; +} + +.popup-container:nth-last-child(1) { + right: var(--spacing); + bottom: var(--spacing); +} + +.popup-container:nth-last-child(2) { + right: calc(var(--spacing) + var(--popup-width) + var(--gap)); + bottom: var(--spacing); +} + +.popup-container:nth-last-child(3) { + right: calc(var(--spacing) + (var(--popup-width) + var(--gap)) * 2); + bottom: var(--spacing); +} + + + + +/* ===== Main Container ===== */ +.matching-candidates-container { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + padding: 20px; + max-width: 1200px; + margin: 0 auto; +} + +/* ===== Search Box ===== */ +.matching-candidates-container .mc-search-box { + position: relative; + display: flex; + align-items: center; + gap: 15px; + margin-bottom: 25px; + max-width: 500px; +} + +.matching-candidates-container .mc-search-input { + padding: 12px 15px 12px 40px; + border: 1px solid var(--gray-300); + border-radius: 8px; + font-size: 14px; + width: 100%; + transition: all 0.3s ease; + background-color: var(--gray-100); + box-shadow: 0 2px 5px rgba(0,0,0,0.05); +} + +.matching-candidates-container .mc-search-input:focus { + outline: none; + border-color: var(--primary-blue); + box-shadow: 0 0 0 3px var(--primary-blue-light); + background-color: var(--white); +} + +.matching-candidates-container .mc-search-icon { + position: absolute; + left: 15px; + color: var(--gray-500); +} + +.matching-candidates-container .mc-match-threshold { + background-color: var(--primary-blue-light); + color: var(--primary-blue-dark); + padding: 8px 15px; + border-radius: 20px; + font-size: 13px; + font-weight: 500; + white-space: nowrap; +} + +/* ===== Cards Container ===== */ +.matching-candidates-container .mc-cards-container { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 20px; +} + +/* ===== Individual Card Styles ===== */ +.matching-candidates-container .mc-card { + background: var(--white); + border-radius: 12px; + padding: 20px; + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08); + transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); + cursor: pointer; + text-align: center; + border: 1px solid var(--gray-200); +} + +.matching-candidates-container .mc-card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.12); + border-color: var(--primary-blue); +} + +/* ===== Avatar Wrapper ===== */ +.matching-candidates-container .mc-avatar-wrapper { + position: relative; + margin-bottom: 15px; +} + +.matching-candidates-container .mc-avatar { + width: 100px; + height: 100px; + border-radius: 50%; + background-color: var(--gray-200); + display: inline-flex; + align-items: center; + justify-content: center; + overflow: hidden; + position: relative; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease; +} + +.matching-candidates-container .mc-card:hover .mc-avatar { + transform: scale(1.05); +} + +.matching-candidates-container .mc-avatar-img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.matching-candidates-container .mc-avatar-initials { + font-size: 36px; + font-weight: bold; + color: var(--primary-blue-dark); +} +/* ===== Percentage Circles ===== */ +.matching-candidates-container .mc-percentage-circles { + display: flex; + justify-content: center; + gap: 15px; + margin-top: 15px; +} + +.matching-candidates-container .mc-percentage-circle { + width: 70px; + height: 70px; + border-radius: 50%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); +} + +.matching-candidates-container .mc-primary-circle { + background: var(--gray-200); + position: relative; + overflow: hidden; +} + +.matching-candidates-container .mc-primary-circle::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: conic-gradient(var(--primary-blue) 0% var(--primary-percent), transparent var(--primary-percent) 100%); +} + +.matching-candidates-container .mc-secondary-circle { + background: var(--gray-200); + position: relative; + overflow: hidden; +} + +.matching-candidates-container .mc-secondary-circle::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: conic-gradient(var(--secondary-green) 0% var(--secondary-percent), transparent var(--secondary-percent) 100%); +} + +.matching-candidates-container .mc-percentage-value { + font-size: 18px; + font-weight: 700; + color: var(--text-primary); + position: relative; + z-index: 1; +} + +.matching-candidates-container .mc-percentage-label { + font-size: 11px; + font-weight: 600; + color: var(--text-primary); + text-transform: uppercase; + margin-top: 2px; + position: relative; + z-index: 1; +} + +/* Add this to your existing CSS */ +.matching-candidates-container .mc-percentage-circle::after { + content: ''; + position: absolute; + top: 5px; + left: 5px; + right: 5px; + bottom: 5px; + background: var(--white); + border-radius: 50%; + z-index: 0; +} + +/* ===== Modal Styles ===== */ +.matching-candidates-container .mc-modal { + display: none; + position: fixed; + z-index: 1000; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.5); + animation: fadeIn 0.3s; +} + +.matching-candidates-container .mc-modal-content { + background-color: var(--white); + margin: 5% auto; + padding: 30px; + border-radius: 12px; + box-shadow: 0 5px 30px rgba(0,0,0,0.3); + width: 80%; + max-width: 700px; + max-height: 80vh; + overflow-y: auto; + position: relative; + animation: slideIn 0.3s; +} + +.matching-candidates-container .mc-close-modal { + position: absolute; + right: 25px; + top: 20px; + font-size: 28px; + font-weight: bold; + color: var(--gray-500); + cursor: pointer; + transition: color 0.3s; +} + +.matching-candidates-container .mc-close-modal:hover { + color: var(--primary-blue); +} + + + +/* ===== Detail View Styles ===== */ +.mc-detail-container { + padding: 20px; +} + +.mc-detail-container .mc-detail-header { + display: flex; + align-items: center; + margin-bottom: 30px; + padding-bottom: 20px; + border-bottom: 1px solid var(--gray-200); +} + +.mc-detail-container .mc-detail-avatar { + width: 80px; + height: 80px; + border-radius: 50%; + background-color: var(--gray-200); + overflow: hidden; + margin-right: 20px; + flex-shrink: 0; +} + +.mc-detail-container .mc-detail-avatar-img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.mc-detail-container .mc-detail-avatar-initials { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + font-size: 32px; + font-weight: bold; + color: var(--primary-blue-dark); +} + +.mc-detail-container .mc-detail-name { + margin: 0; + color: var(--text-primary); + font-size: 1.8rem; +} + +.mc-detail-container .mc-detail-section { + margin-bottom: 25px; +} + +.mc-detail-container .mc-detail-section h4 { + color: var(--primary-blue-dark); + margin-bottom: 15px; + padding-bottom: 8px; + border-bottom: 1px solid var(--gray-200); +} + +.mc-detail-container .mc-detail-row { + display: flex; + margin-bottom: 10px; +} + +.mc-detail-container .mc-detail-label { + font-weight: 600; + color: var(--text-primary); + width: 120px; + flex-shrink: 0; +} + +.mc-detail-container .mc-detail-value { + color: var(--text-secondary); +} + +.mc-detail-container .mc-detail-skills { + display: flex; + gap: 30px; + margin-top: 15px; +} + +.mc-detail-container .mc-detail-skill-category { + flex: 1; +} + +.mc-detail-container .mc-detail-skill-category h5 { + color: var(--text-primary); + margin-bottom: 10px; + font-size: 1rem; +} + +.mc-detail-container .mc-skill-list { + list-style: none; + padding: 0; + margin: 0; +} + +.mc-detail-container .mc-skill-list li { + padding: 6px 0; + border-bottom: 1px dashed var(--gray-200); +} + +.mc-detail-container .mc-applications-list { + display: flex; + flex-direction: column; + gap: 10px; +} + +.mc-detail-container .mc-application { + display: flex; + justify-content: space-between; + padding: 10px; + background-color: var(--gray-100); + border-radius: 6px; +} + +.mc-detail-container .mc-application-name { + font-weight: 500; +} + +.mc-detail-container .mc-application-stage { + background-color: var(--primary-blue-light); + color: var(--primary-blue-dark); + padding: 3px 8px; + border-radius: 12px; + font-size: 12px; +} + +/* ===== Empty State ===== */ +.mc-detail-container .mc-empty-state { + text-align: center; + padding: 60px 20px; + background-color: var(--gray-100); + border-radius: 12px; + margin-top: 30px; +} + +.mc-detail-container .mc-empty-icon { + font-size: 48px; + margin-bottom: 15px; + opacity: 0.7; +} + +.mc-detail-container .mc-empty-state h4 { + color: var(--text-primary); + margin-bottom: 10px; +} + +.mc-detail-container .mc-empty-state p { + color: var(--text-secondary); + margin: 0; +} + +/* ===== Responsive Adjustments ===== */ +@media (max-width: 768px) { + .matching-candidates-container .mc-cards-container { + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + } + + .matching-candidates-container .mc-percentage-circles { + flex-direction: column; + align-items: center; + } + + .matching-candidates-container .mc-modal-content { + width: 95%; + margin: 10% auto; + } + + .mc-detail-container .mc-detail-skills { + flex-direction: column; + gap: 20px; + } + + .mc-detail-container .mc-detail-header { + flex-direction: column; + text-align: center; + } + + .mc-detail-container .mc-detail-avatar { + margin-right: 0; + margin-bottom: 15px; + } +} \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/static/src/css/list.css b/addons_extensions/hr_recruitment_web_app/static/src/css/list.css new file mode 100644 index 000000000..b3ccde4dc --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/css/list.css @@ -0,0 +1,708 @@ +@import url('colors.css'); +/* ===== Job List View Styling ===== */ +.ats-list-container { + display: flex; + flex-direction: column; + height: 99%; + width: 100%; + border: 1px solid var(--border-color); + border-radius: 6px; + overflow: hidden; + box-shadow: 0 2px 8px var(--shadow-color); + background-color: var(--body-bg); + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} +.ats-list-container .ats-list-search { + flex: 0 0 auto; + padding: 12px; + background-color: var(--gray-100); + border-bottom: 1px solid var(--border-light); +} +.ats-list-container .ats-list-search input { + width: 100%; + padding: 10px 14px; + font-size: 14px; + border: 1px solid var(--gray-300); + border-radius: 6px; + outline: none; + transition: border-color 0.3s ease; + background-color: var(--white); + color: var(--text-primary); +} +.ats-list-container .ats-list-search input:focus { + border-color: var(--primary-blue); +} +.ats-list-container .ats-list-body { + flex: 1; + display: flex; + height: calc(100vh - 70px); /* header + search box approx height */ + overflow: hidden; + position: relative; +} + +.ats-list-container .ats-actions-header { + padding: 10px 15px; + background-color: var(--content-bg); + border-radius: 6px; + border-left: 4px solid var(--primary-blue); + display: flex; + align-items: center; +} +.ats-list-container .ats-actions-header .section-title { + font-size: 18px; + font-weight: 600; + color: var(--text-primary); +} +.ats-list-container .ats-actions-header .btn { + font-size: 14px; + font-weight: 500; + padding: 6px 15px; + border-radius: 4px; + transition: all 0.3s ease; +} +.ats-list-container .ats-actions-header #activeRecords { + margin-right: auto; + background-color: var(--active-search-bg); + color: var(--active-search-text); + border: 1px solid var(--gray-300); + padding: 10px 20px; + border-radius: 6px; + font-weight: 500; + box-shadow: 0 2px 4px var(--shadow-color); + transition: all 0.3s ease-in-out; + cursor: pointer; +} +.ats-list-container .job-actions-header #activeRecords:hover { + background-color: var(--active-search-hover-bg); + color: var(--active-search-text); + box-shadow: 0 4px 8px var(--shadow-dark); +} +/* Button Styles */ +.ats-list-container .ats-actions-header .add-create-btn { + margin-left: auto; + background-color: var(--add-btn-bg); + color: var(--add-btn-color); + border: none; + padding: 10px 20px; + border-radius: 6px; + font-weight: bold; + display: flex; + align-items: center; + gap: 8px; + box-shadow: 0 2px 6px rgba(52, 152, 219, 0.2); + transition: all 0.3s ease-in-out; + cursor: pointer; +} +.ats-list-container .ats-actions-header .add-create-btn:hover { + background-color: var(--add-btn-hover-bg); + transform: scale(1.05); + box-shadow: 0 6px 12px rgba(41, 128, 185, 0.3); +} +.ats-list-container .ats-actions-header .add-create-btn .plus-icon { + font-size: 20px; + font-weight: bold; + line-height: 1; + display: inline-block; + transition: transform 0.3s ease; +} +.ats-list-container .ats-actions-header .add-create-btn:hover .plus-icon { + transform: scale(1.3); +} +/* ===== Job List Panel ===== */ +.ats-list-container .ats-list-left { + width: 30%; + padding: 0; + overflow-y: auto; + background-color: var(--content-bg); + position: relative; + max-height: 100%; + display: flex; + flex-direction: column; +} +.ats-list-container .ats-list-left ul { + list-style: none; + padding: 12px 12px 20px 12px; + margin: 0; + flex: 1; + overflow-y: auto; +} +/* ===== Kanban View (Full Screen) ===== */ +.ats-list-container:not(.ats-selected) .ats-list-left { + width: 100%; + display: flex; + flex-direction: column; +} +.ats-list-container:not(.ats-selected) .ats-list-left ul { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + grid-auto-rows: 1fr; /* Equal height rows */ + grid-gap: 16px; + padding: 16px; + overflow-y: auto; + width: 100%; + box-sizing: border-box; + align-content: start; /* Align items to the top */ +} +.ats-list-container:not(.ats-selected) .ats-item { + padding: 16px; + margin-bottom: 0; + border: 1px solid var(--gray-200); + border-radius: 8px; + cursor: pointer; + transition: all 0.3s ease; + background-color: var(--white); + box-shadow: 0 2px 6px var(--shadow-color); + display: flex; + flex-direction: column; + position: relative; + overflow: hidden; + height: auto; /* Fill the grid cell */ + min-height: 150; /* Minimum height */ +} +.ats-list-container:not(.ats-selected) .ats-item::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 6px; + height: 100%; + background-color: var(--primary-blue); + transform: scaleY(0); + transition: transform 0.3s ease; +} +.ats-list-container:not(.ats-selected) .ats-item:hover { + transform: translateY(-4px); + box-shadow: 0 8px 16px var(--shadow-dark); + border-color: var(--primary-blue); +} +.ats-list-container:not(.ats-selected) .ats-item:hover::before { + transform: scaleY(1); +} +.ats-list-container:not(.ats-selected) .ats-item .ats-title { + font-size: 16px; + font-weight: 600; + color: var(--text-primary); + margin-bottom: 8px; + padding-right: 20px; +} +.ats-list-container:not(.ats-selected) .ats-item .ats-meta { + font-size: 14px; + color: var(--text-secondary); + margin-bottom: 12px; + display: flex; + align-items: center; +} +.ats-list-container:not(.ats-selected) .ats-item .ats-meta i { + margin-right: 6px; + color: var(--primary-blue); +} +.ats-list-container:not(.ats-selected) .ats-item .ats-badges { + margin-top: auto; + display: flex; + flex-wrap: wrap; + gap: 6px; +} +.ats-list-container:not(.ats-selected) .ats-item .job-badge { + margin-right: 0; + padding: 4px 10px; + font-size: 12px; + border-radius: 12px; + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 28px; + height: 24px; +} +.ats-list-container:not(.ats-selected) .ats-item .badge-primary { + background-color: var(--primary-blue); +} +.ats-list-container:not(.ats-selected) .ats-item .badge-warning { + background-color: var(--warning); + color: var(--black); +} +.ats-list-container:not(.ats-selected) .ats-item .badge-success { + background-color: var(--success); +} +.ats-list-container:not(.ats-selected) .ats-item .badge-danger { + background-color: var(--danger); +} +/* ===== List View (When Job Selected) ===== */ +.ats-list-container.ats-selected .ats-item { + padding: 10px 12px; + margin-bottom: 8px; + border: 1px solid var(--gray-200); + border-radius: 6px; + cursor: pointer; + transition: background-color 0.2s, box-shadow 0.2s; + background-color: var(--sidebar-bg); +} +.ats-list-container.ats-selected .ats-item:hover { + background-color: var(--side-panel-item-hover); + box-shadow: 0 1px 4px var(--shadow-color); +} +.ats-list-container.ats-selected .ats-item.selected { + background-color: var(--side-panel-item-selected); + border: 1px solid var(--primary-blue); +} +/* ===== Job Detail Panel ===== */ +.ats-list-container .ats-detail { + width: 70%; + padding: 20px; + overflow-y: auto; + overflow-x: hidden; + background-color: var(--content-bg); + color: var(--text-primary); + position: relative; + flex: 1; + transition: all 0.3s ease; +} +.ats-list-container .ats-detail h3 { + margin-top: 0; + font-size: 20px; + color: var(--primary-blue); +} +.ats-list-container .ats-detail p { + margin: 8px 0; + line-height: 1.6; + color: var(--text-secondary); +} +.ats-list-container .ats-detail em { + color: var(--text-muted); +} +/* ===== Panel Controls ===== */ +.ats-list-container .panel-controls { + position: sticky; + top: 0; + background: var(--white); + z-index: 100; + padding: 8px 0; + display: flex; + justify-content: flex-end; +} +.ats-list-container .panel-controls button { + background-color: var(--gray-200); + border: none; + color: var(--text-primary); + font-size: 14px; + margin-left: 5px; + padding: 2px 6px; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.2s ease; +} +.ats-list-container .panel-controls button:hover { + background-color: var(--gray-300); +} +/* ======Job stats====== */ +.ats-list-container .job-stats-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 16px; + background-color: var(--content-bg); + border-bottom: 1px solid var(--border-color); + position: sticky; + top: 0; + z-index: 10; +} +.ats-list-container .job-stats-values { + display: flex; + gap: 12px; + flex-wrap: wrap; +} +.ats-list-container .close-stats { + background: none; + border: none; + font-size: 18px; + color: var(--gray-600); + cursor: pointer; + padding: 4px 8px; + transition: color 0.3s; +} +.ats-list-container .close-stats:hover { + color: var(--gray-900); +} +.ats-list-container .badge { + padding: 6px 10px; + border-radius: 14px; + font-size: 12px; + font-weight: 600; + color: var(--white); +} +.ats-list-container .stat-toggle.crossed { + text-decoration: line-through; + opacity: 0.6; + cursor: pointer; +} +.ats-list-container .stat-toggle { + cursor: pointer; + margin-right: 8px; +} +.ats-list-container .job-badges { + margin-top: 6px; +} +.ats-list-container .job-badge { + margin-right: 6px; + padding: 4px 10px; + font-size: 12px; + border-radius: 12px; + display: inline-block; +} +.ats-list-container .badge-primary { background-color: var(--primary-blue); } +.ats-list-container .badge-warning { background-color: var(--warning); color: var(--black); } +.ats-list-container .badge-success { background-color: var(--success); } +.ats-list-container .badge-danger { background-color: var(--danger); } +/* ===== Sidebar Toggle ===== */ +.ats-list-container .ats-list-left { + width: 30%; + min-width: 300px; + transition: all 0.3s ease; + position: relative; + overflow-x: hidden; +} +.ats-list-container .ats-list-left.collapsed { + width: 5%; + min-width: 5%; + padding: 0; + border-right: none; +} +.ats-list-container .ats-detail { + width: 70%; + transition: all 0.3s ease; +} +.ats-list-container .ats-list-left.collapsed + .ats-detail { + width: 95%; +} +/* Toggle Button */ +.ats-list-container .ats-list-toggle-btn { + position: absolute; + top: 50%; + right: -12px; + transform: translateY(-50%); + background-color: var(--gray-100); + color: var(--text-primary); + border: none; + padding: 0.5rem 0.7rem; + cursor: pointer; + border-radius: 0 6px 6px 0; + box-shadow: 0 2px 5px var(--shadow-color); + z-index: 20; + display: flex; + align-items: center; + justify-content: center; + transition: right 0.3s ease; +} +/* Button in collapsed state */ +.ats-list-container .ats-list-left.collapsed .ats-list-toggle-btn { + right: -12px; + transform: translateY(-50%); +} +.ats-list-container .ats-list-toggle-btn:hover { + background-color: var(--gray-200); +} +/* Hide content in collapsed state */ +.ats-list-container .ats-list-left.collapsed > *:not(.job-list-toggle-btn) { + display: none; +} +/* ===== Layout States ===== */ +/* Initial state: job list takes full width */ +.ats-list-container:not(.ats-selected) .ats-list-left { + width: 100%; +} +.ats-list-container:not(.ats-selected) .ats-detail { + display: none; +} +/* When a job is selected */ +.ats-list-container.ats-selected .ats-list-left { + width: 30%; +} +.ats-list-container.ats-selected .ats-detail { + width: 70%; + display: block; + overflow: hidden; +} +/* When sidebar is collapsed */ +.ats-list-container.ats-selected .ats-list-left.collapsed { + width: 5%; + min-width: 5%; +} +.ats-list-container.ats-selected .ats-list-left.collapsed + .ats-detail { + width: 95%; +} + +.ats-list-container:not(.ats-selected) .ats-list-toggle-btn { + display: none; +} + +.ats-list-container.ats-selected .ats-list-toggle-btn { + display: flex; +} +/* Close button styling */ +.close-detail { + position: absolute; + top: 10px; + right: 10px; + z-index: 100; + background: transparent; + border: none; + font-size: 1.5rem; + color: var(--gray-600); + cursor: pointer; + padding: 0; + width: 30px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + transition: all 0.2s ease; +} +.close-detail:hover { + background-color: var(--gray-200); + color: var(--gray-900); +} +/* Transitions for smooth resizing */ +.ats-list-container .ats-list-left, +.ats-list-container .ats-detail { + transition: width 0.3s ease; +} +/* ===== Responsive Adjustments ===== */ +@media (max-width: 768px) { + .ats-list-container:not(.ats-selected) .ats-list-left ul { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + grid-gap: 12px; + padding: 12px; + } + + .ats-list-container:not(.ats-selected) .ats-item { + padding: 12px; + min-height: 160px; + } + + .ats-list-container.ats-selected .ats-list-left { + width: 40%; + } + + .ats-list-container.ats-selected .ats-detail { + width: 60%; + } + + .ats-list-container.ats-selected .ats-list-left.collapsed { + width: 10%; + min-width: 10%; + } + + .ats-list-container.ats-selected .ats-list-left.collapsed + .ats-detail { + width: 90%; + } +} + + +/* ===== Applicant List Styling ===== */ +.ats-list-container .ats-list { + list-style: none; + padding: 12px 12px 20px 12px; + margin: 0; + flex: 1; + overflow-y: auto; +} + +.ats-list-container .ats-item-content { + display: flex; + justify-content: space-between; + align-items: center; +} + +.ats-list-container .ats-info { + flex: 1; +} + +.ats-list-container .ats-avatar { + margin-left: 12px; + flex-shrink: 0; +} + +.ats-list-container .ats-item-image { + width: 50px; + height: 50px; + border-radius: 50%; + object-fit: cover; +} + +.ats-list-container .ats-item-initials { + width: 50px; + height: 50px; + border-radius: 50%; + background-color: var(--primary-blue); + color: white; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + font-size: 18px; +} + +/* ===== Applicant Modal Styling ===== */ +.applicant-detail-modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; +} + +.applicant-detail-modal.active { + display: flex; + align-items: center; + justify-content: center; +} + +.modal-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); +} + +.applicant-modal-content { + position: relative; + background-color: var(--white); + border-radius: 8px; + width: 90%; + max-width: 600px; + max-height: 90vh; + overflow-y: auto; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); + z-index: 1001; +} + +.applicant-close-modal { + position: absolute; + top: 10px; + right: 15px; + font-size: 24px; + font-weight: bold; + color: var(--gray-600); + cursor: pointer; + z-index: 1002; +} + +.applicant-close-modal:hover { + color: var(--gray-900); +} + +.applicant-status-ribbon { + position: absolute; + top: 0; + left: 0; + width: 100%; + padding: 8px 15px; + background-color: var(--primary-blue); + color: var(--white); + font-weight: 600; + border-radius: 8px 8px 0 0; +} + +.modal-applicant-container { + display: flex; + padding: 50px 20px 20px; +} + +.modal-applicant-left { + flex: 0 0 auto; + margin-right: 20px; +} + +.modal-applicant-image { + width: 120px; + height: 120px; + border-radius: 50%; + object-fit: cover; + border: 3px solid var(--primary-blue); +} + +.modal-applicant-initials { + width: 120px; + height: 120px; + border-radius: 50%; + background-color: var(--primary-blue); + color: white; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + font-size: 48px; + border: 3px solid var(--primary-blue); +} + +.modal-applicant-right { + flex: 1; +} + +.modal-applicant-name { + margin-top: 0; + color: var(--text-primary); + border-bottom: 1px solid var(--border-color); + padding-bottom: 10px; +} + +.modal-applicant-details { + margin-top: 15px; +} + +.detail-row { + display: flex; + margin-bottom: 10px; +} + +.detail-label { + flex: 0 0 140px; + font-weight: 600; + color: var(--text-secondary); +} + +.detail-value { + flex: 1; + color: var(--text-primary); +} + +.recruiter-info { + margin-top: 20px; + padding-top: 15px; + border-top: 1px solid var(--border-color); +} + +.recruiter-avatar { + display: flex; + align-items: center; +} + +.recruiter-image { + width: 40px; + height: 40px; + border-radius: 50%; + object-fit: cover; + margin-right: 10px; +} + +.recruiter-initials { + width: 40px; + height: 40px; + border-radius: 50%; + background-color: var(--gray-300); + color: var(--text-primary); + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + margin-right: 10px; +} + +.recruiter-tooltip { + font-weight: 500; + color: var(--text-primary); +} \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/static/src/css/select2.min.css b/addons_extensions/hr_recruitment_web_app/static/src/css/select2.min.css new file mode 100644 index 000000000..7c18ad59d --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/css/select2.min.css @@ -0,0 +1 @@ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} diff --git a/addons_extensions/hr_recruitment_web_app/static/src/img/logo.jpeg b/addons_extensions/hr_recruitment_web_app/static/src/img/logo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a1384235975623cdac384d63017453133599946c GIT binary patch literal 121212 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

u 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 !1`OVvxxSk_V} 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 { + item.addEventListener("click", function() { + console.log("Applicant item clicked"); // Add this for debugging + document.querySelectorAll(".ats-item.applicants-item.selected").forEach(el => el.classList.remove("selected")); + this.classList.add("selected"); + + applicantDetailArea.style.display = 'block'; + container.classList.add('ats-selected'); + sidebar.classList.remove('collapsed'); + toggleBtn.style.display = 'flex'; + + const applicantId = this.dataset.id; + console.log("Applicant ID:", applicantId); // Add this for debugging + + // Show loading state + if (applicantDetailArea) { + applicantDetailArea.innerHTML = '

Loading applicant details...

'; + } + + fetch(`/myATS/applicant/detail/${applicantId}`, { + headers: { "X-Requested-With": "XMLHttpRequest" } + }) + .then(res => { + if (!res.ok) throw new Error('Network response was not ok'); + return res.text(); + }) + .then(html => { + console.log("Response received"); // Add this for debugging + if (applicantDetailArea) { + applicantDetailArea.innerHTML = html; + initApplicantDetailEdit(); // Initialize edit functionality + + // Add close button functionality + const closeBtn = applicantDetailArea.querySelector('.close-detail'); + if (closeBtn) { + closeBtn.addEventListener('click', function() { + applicantDetailArea.style.display = 'none'; + container.classList.remove('ats-selected'); + document.querySelectorAll(".ats-item.applicants-item.selected").forEach(el => el.classList.remove("selected")); + }); + } + } + }) + .catch(error => { + console.error('Error loading applicant details:', error); + if (applicantDetailArea) { + applicantDetailArea.innerHTML = '
Error loading applicant details. Please try again.
'; + } + }); + }); + }); + + // Search functionality - use correct ID + const search = document.getElementById("applicants-search"); + if (search) { + search.addEventListener("input", function() { + const query = this.value.toLowerCase(); + let visibleCount = 0; + // Also fix this selector to use both classes + document.querySelectorAll(".ats-item.applicants-item").forEach(item => { + const match = item.textContent.toLowerCase().includes(query); + item.style.display = match ? "" : "none"; + if (match) visibleCount++; + }); + const countElement = document.getElementById("active-records-count"); + if (countElement) { + countElement.textContent = visibleCount; + } + }); + } + + // Sidebar Toggle + if (toggleBtn && sidebar) { + toggleBtn.addEventListener("click", function(e) { + e.stopPropagation(); + sidebar.classList.toggle("collapsed"); + }); + } + + // Applicant Modal Handling + const modal = document.querySelector('.applicant-detail-modal'); + if (modal) { + const closeModal = modal.querySelector('.applicant-close-modal'); + + // Event delegation for image clicks - use correct classes + document.addEventListener('click', function(e) { + const img = e.target.closest('.ats-item-image, .ats-item-initials'); + if (!img) return; + + const applicantItem = img.closest('.ats-item.applicants-item'); + if (!applicantItem) return; + + e.preventDefault(); + e.stopImmediatePropagation(); + + // Get applicant data with null checks + const applicantId = applicantItem.dataset.id; + const nameElement = applicantItem.querySelector('.ats-title'); + const jobElement = applicantItem.querySelector('#job_request'); + const stageElement = applicantItem.querySelector('#applicant_stage'); + const createDate = applicantItem.querySelector('#create_date'); + const applicantEmail = applicantItem.querySelector('#applicant_email'); + const applicantPhone = applicantItem.querySelector('#applicant_phone'); + const alternatePhone = applicantItem.querySelector('#alternate_phone'); + const recruiterName = applicantItem.querySelector('#recruiter_name'); + const recruiterImage = applicantItem.querySelector('#recruiter_image'); + const recruiterUserId = applicantItem.querySelector('#recruiter_id'); + + const name = nameElement ? nameElement.textContent : 'N/A'; + const job = jobElement ? jobElement.textContent : 'N/A'; + const stage = stageElement ? stageElement.textContent : 'N/A'; + const date = createDate ? createDate.textContent : 'N/A'; + const email = applicantEmail ? applicantEmail.textContent : 'N/A'; + const phone = applicantPhone ? applicantPhone.textContent : 'N/A'; + const altPhone = alternatePhone ? alternatePhone.textContent : 'N/A'; + const recruiter = recruiterName ? recruiterName.textContent : 'N/A'; + const recruiterId = recruiterUserId ? recruiterUserId.textContent: null; + const photoSrc = img.classList.contains('ats-item-image') ? img.src : null; + const initials = img.classList.contains('ats-item-initials') ? img.textContent : null; + + // Populate modal with applicant data + modal.querySelector('.modal-applicant-name').textContent = name; + modal.querySelector('.modal-applicant-job').textContent = job; + modal.querySelector('.modal-applicant-stage').textContent = stage; + modal.querySelector('.modal-applicant-date').textContent = date; + modal.querySelector('.modal-applicant-email').textContent = email; + modal.querySelector('.modal-applicant-phone').textContent = phone; + modal.querySelector('.modal-applicant-altphone').textContent = altPhone; + + // Handle applicant image + if (photoSrc) { + const modalImg = modal.querySelector('.modal-applicant-image'); + modalImg.src = photoSrc; + modalImg.style.display = 'block'; + modal.querySelector('.modal-applicant-initials').style.display = 'none'; + } else { + modal.querySelector('.modal-applicant-initials').textContent = initials; + modal.querySelector('.modal-applicant-initials').style.display = 'flex'; + modal.querySelector('.modal-applicant-image').style.display = 'none'; + } + + // Handle recruiter info + const recruiterImageEl = modal.querySelector('.recruiter-image'); + const recruiterInitialsEl = modal.querySelector('.recruiter-initials'); + const recruiterTooltip = modal.querySelector('.recruiter-tooltip'); + + if (recruiterImage && recruiterId) { + const recruiterSrc = `/web/image/res.users/${recruiterId}/image_128`; + recruiterImageEl.src = recruiterSrc; + recruiterImageEl.style.display = 'block'; + recruiterInitialsEl.style.display = 'none'; + recruiterSrc.onerror = function () { + recruiterImageEl.style.display = 'none'; + }; + } else if (recruiterName) { + recruiterInitialsEl.textContent = recruiterName.textContent.charAt(0).toUpperCase(); + recruiterInitialsEl.style.display = 'flex'; + recruiterImageEl.style.display = 'none'; + } + recruiterTooltip.textContent = recruiter; + + // Set status ribbon class based on stage - use correct selector + const statusRibbon = modal.querySelector('.applicant-status-ribbon'); + if (statusRibbon) { + // Remove all existing status classes + statusRibbon.classList.remove('new', 'interview', 'hired', 'rejected'); + // Add appropriate class based on stage + if (stage.toLowerCase().includes('interview')) { + statusRibbon.classList.add('interview'); + } else if (stage.toLowerCase().includes('hired')) { + statusRibbon.classList.add('hired'); + } else if (stage.toLowerCase().includes('reject')) { + statusRibbon.classList.add('rejected'); + } else { + statusRibbon.classList.add('new'); + } + } + + // Show modal + modal.style.display = 'flex'; + setTimeout(() => { + modal.classList.add('show'); + }, 10); + document.body.style.overflow = 'hidden'; + }); + + // Close modal handlers + closeModal.addEventListener('click', function() { + modal.classList.remove('show'); + setTimeout(() => { + modal.style.display = 'none'; + }, 300); + document.body.style.overflow = ''; + }); + + modal.addEventListener('click', function(e) { + if (e.target === modal) { + modal.classList.remove('show'); + document.body.style.overflow = ''; + } + }); + + // Close with ESC key + document.addEventListener('keydown', function(e) { + if (e.key === 'Escape' && modal.classList.contains('show')) { + modal.classList.remove('show'); + document.body.style.overflow = ''; + } + }); + } + + const createApplication = document.getElementById('add-application-create-btn'); + const applicantModal = document.getElementById('application-creation-modal'); + const closeModal = document.querySelectorAll('.application-creation-close, .btn-cancel'); + if (createApplication) { + createApplication.addEventListener('click', function(e) { + e.preventDefault(); + applicantModal.style.display = 'flex'; + setTimeout(() => { + applicantModal.classList.add('show'); + }, 10); + document.body.style.overflow = 'hidden'; + setTimeout(() => { + initSelect2(); + initResumeUploadHandlers(); + }, 100); + setTimeout(createApplicationForm, 100); + }); + } + if (closeModal) { + closeModal.forEach(btn => { + btn.addEventListener('click', function() { + applicantModal.classList.remove('show'); + setTimeout(() => { + applicantModal.style.display = 'none'; + }, 300); + document.body.style.overflow = ''; + }); + }); + } + // 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 = ''; + } + }); + // 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 resumeIframe = document.getElementById('resume-iframe'); + const resumeImage = document.getElementById('resume-image'); + const unsupportedFormat = document.getElementById('unsupported-format'); + const downloadResume = document.getElementById('download-resume'); + const attachmentsList = document.querySelector('.attachments-list'); + const addAttachmentBtn = document.querySelector('.add-attachment'); + + function initResumeUploadHandlers() { + // Create remove button + const removeResumeBtn = document.createElement('button'); + removeResumeBtn.innerHTML = ' Remove Resume'; + removeResumeBtn.className = 'btn btn-danger btn-sm mt-2'; + removeResumeBtn.style.display = 'none'; + resumePreview.appendChild(removeResumeBtn); + + // Handle remove resume + removeResumeBtn.addEventListener('click', function() { + resetResumePreview(); + }); + + function resetResumePreview() { + // Clear file input + resumeUpload.value = ''; + currentResumeFile = null; + // Reset preview + resumePlaceholder.style.display = 'flex'; + resumeIframe.style.display = 'none'; + resumeImage.style.display = 'none'; + unsupportedFormat.style.display = 'none'; + removeResumeBtn.style.display = 'none'; + // Reset iframe/src to prevent memory leaks + if (resumeIframe.src) { + URL.revokeObjectURL(resumeIframe.src); + resumeIframe.src = ''; + } + if (resumeImage.src) { + URL.revokeObjectURL(resumeImage.src); + resumeImage.src = ''; + } + if (downloadResume.href) { + URL.revokeObjectURL(downloadResume.href); + downloadResume.href = '#'; + } + } + + // Handle click on dropzone + resumeDropzone.addEventListener('click', function(e) { + if (e.target === this || e.target.classList.contains('upload-icon') || + e.target.tagName === 'H5' || e.target.tagName === 'P') { + resumeUpload.click(); + } + }); + + // Handle drag and drop + resumeDropzone.addEventListener('dragover', function(e) { + e.preventDefault(); + e.stopPropagation(); + this.classList.add('dragover'); + this.style.borderColor = '#3498db'; + this.style.backgroundColor = 'rgba(52, 152, 219, 0.1)'; + }); + + resumeDropzone.addEventListener('dragleave', function(e) { + e.preventDefault(); + e.stopPropagation(); + this.classList.remove('dragover'); + this.style.borderColor = ''; + this.style.backgroundColor = ''; + }); + + resumeDropzone.addEventListener('drop', function(e) { + e.preventDefault(); + e.stopPropagation(); + this.classList.remove('dragover'); + this.style.borderColor = ''; + this.style.backgroundColor = ''; + if (e.dataTransfer.files.length) { + const file = e.dataTransfer.files[0]; + handleResumeFile(file); + } + }); + + // Handle file selection from the regular input + resumeUpload.addEventListener('change', function(e) { + if (this.files.length) { + handleResumeFile(this.files[0]); + } + }); + + function handleResumeFile(file) { + const validTypes = [ + 'application/pdf', + 'application/msword', + 'application/wps-office.docx', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'image/jpeg', + 'image/png', + 'text/plain' + ]; + if (!validTypes.includes(file.type)) { + alert('Please upload a valid file type (PDF, Word, Image, or Text)'); + return; + } + currentResumeFile = file; + // Hide placeholder + resumePlaceholder.style.display = 'none'; + // Set up download link + const fileURL = URL.createObjectURL(file); + downloadResume.href = fileURL; + downloadResume.download = file.name; + removeResumeBtn.style.display = 'block'; + // Check file type and show appropriate preview + if (file.type === 'application/pdf') { + // PDF preview + resumeIframe.src = fileURL; + resumeIframe.style.display = 'block'; + resumeImage.style.display = 'none'; + unsupportedFormat.style.display = 'none'; + } else if (file.type.match('image.*')) { + // Image preview + resumeImage.src = fileURL; + resumeImage.style.display = 'block'; + resumeIframe.style.display = 'none'; + unsupportedFormat.style.display = 'none'; + } else { + // Unsupported format for preview + unsupportedFormat.style.display = 'flex'; + resumeIframe.style.display = 'none'; + resumeImage.style.display = 'none'; + } + // Update the actual resume-upload input + const dataTransfer = new DataTransfer(); + dataTransfer.items.add(file); + resumeUpload.files = dataTransfer.files; + } + } + + if (addAttachmentBtn) { + addAttachmentBtn.addEventListener('click', () => { + const input = document.createElement('input'); + input.type = 'file'; + input.multiple = true; + input.accept = '.pdf,.doc,.docx,.jpg,.png'; + input.onchange = (e) => { + if (e.target.files.length) { + handleFiles(e.target.files, true); + } + }; + input.click(); + }); + } + + function createApplicationForm() { + const anniversaryField = document.getElementById('marital-anniversary-field'); + const maritalStatus = document.getElementById('application-marital'); + maritalStatus.addEventListener('change', () => { + if (maritalStatus.value !== 'married') { + document.getElementById('marital-anniversary-field').style.display = 'none'; + document.getElementById('application-anniversary').setAttribute('disabled', 'disabled'); + } else { + document.getElementById('marital-anniversary-field').style.display = 'block'; + document.getElementById('application-anniversary').removeAttribute('disabled'); + } + }); + } + + function initSelect2() { + // Check if Select2 is already initialized + const applicantSkills = document.getElementById('application-skills'); + if (applicantSkills) { + $(applicantSkills).select2({ + placeholder: 'Select skills', + allowClear: true, + dropdownParent: $('.application-creation-modal'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + const applicantPosition = document.getElementById('application-position'); + if (applicantPosition) { + $(applicantPosition).select2({ + placeholder: 'Select Job', + allowClear: false, + dropdownParent: $('.application-creation-modal'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + const applicantCandidate = document.getElementById('application-candidate'); + if (applicantCandidate) { + $(applicantCandidate).select2({ + placeholder: 'Select Candidate', + allowClear: true, + dropdownParent: $('.application-creation-modal'), + width: '100%', + templateResult: formatCandidate, + templateSelection: formatCandidateSelection, + escapeMarkup: function(m) { return m; } + }).on('change', function() { + const selectedOption = $(this).find('option:selected'); + if (selectedOption.val()) { + // Populate fields from candidate data + $('#application-email').val(selectedOption.data('email') || ''); + $('#application-phone').val(selectedOption.data('phone') || ''); + $('#application-alt-phone').val(selectedOption.data('altPhone') || ''); + $('#application-linkedin').val(selectedOption.data('linkedin') || ''); + // For skills + let skillIds = selectedOption.data('skillIds'); + // Convert to array if it's a string + if (typeof skillIds === 'string') { + try { + skillIds = JSON.parse(skillIds); + } catch (e) { + skillIds = []; + } + } + // Ensure skillIds is an array + skillIds = Array.isArray(skillIds) ? skillIds : []; + // Set the values in Select2 and trigger change + $('#application-skills').val(skillIds).trigger('change'); + } else { + $('#application-email').val(''); + $('#application-phone').val(''); + $('#application-alt-phone').val(''); + $('#application-linkedin').val(''); + // For skills + let skillIds = []; + + // Ensure skillIds is an array + skillIds = Array.isArray(skillIds) ? skillIds : []; + $('#application-skills').val(skillIds).trigger('change'); + } + }); + } + } + + function formatCandidate(candidate) { + if (!candidate.id) { + return candidate.text; + } + var imageUrl = $(candidate.element).data('image') || '/web/static/img/placeholder.png'; + var $candidate = $( + '' + + '' + + '' + candidate.text + '' + + '' + ); + return $candidate; + } + + function formatCandidateSelection(candidate) { + if (!candidate.id) { + return candidate.text; + } + var imageUrl = $(candidate.element).data('image') || '/web/static/img/placeholder.png'; + var $candidate = $( + '' + + '' + + '' + candidate.text + '' + + '' + ); + return $candidate; + } + + function handleFiles(files, isAdditional = false) { + Array.from(files).forEach(file => { + if (!file.type.match('application/pdf|application/msword|application/vnd.openxmlformats-officedocument.wordprocessingml.document|image.*')) { + alert('Only PDF, DOC, DOCX, JPG, and PNG files are allowed'); + return; + } + if (file.size > 10 * 1024 * 1024) { // 10MB limit + alert('File size must be less than 10MB'); + return; + } + if (isAdditional) { + addAttachmentToList(file); + } else { + updateResumeUpload(file); + } + }); + } + + function updateResumeUpload(file) { + // You can preview or process the resume file here + const dropzone = document.getElementById('resume-dropzone'); + dropzone.innerHTML = ` + +
${file.name}
+

${(file.size / 1024 / 1024).toFixed(2)} MB

+ + + `; + // Re-attach event listeners + document.querySelector('.remove-resume').addEventListener('click', () => { + resetResumeUpload(); + }); + } + + function resetResumeUpload() { + const dropzone = document.getElementById('resume-dropzone'); + dropzone.innerHTML = ` + +
Upload Resume
+

Drag & drop your resume here or click to browse

+ + `; + // Re-attach event listeners + setupFileUpload(); + } + + function addAttachmentToList(file) { + const attachmentItem = document.createElement('div'); + attachmentItem.className = 'attachment-item'; + attachmentItem.innerHTML = ` +
+
+ ${file.name} + ${(file.size / 1024 / 1024).toFixed(2)} MB +
+
+ +
+
+ `; + attachmentsList.appendChild(attachmentItem); + attachmentItem.querySelector('.remove-attachment').addEventListener('click', () => { + attachmentItem.remove(); + }); + } + + function setupFileUpload() { + // Re-initialize event listeners if needed + const resumeDropzone = document.getElementById('resume-dropzone'); + const resumeUpload = document.getElementById('resume-upload'); + if (resumeDropzone && resumeUpload) { + resumeDropzone.addEventListener('click', () => { + resumeUpload.click(); + }); + } + } + + const uploadBtn = document.getElementById('upload-resume') + if (uploadBtn) { + uploadBtn.addEventListener('click', function (e) { + e.preventDefault(); + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = '.pdf,.doc,.docx,.txt'; + fileInput.onchange = async (e) => { + const file = e.target.files[0]; + if (!file) return; + // Show loading state + const button = document.getElementById('upload-resume'); + const originalText = button.innerHTML; + button.innerHTML = ' Processing Resume...'; + button.disabled = true; + try { + const formData = new FormData(); + formData.append('file', file); + formData.append('type', 'applicant'); + const response = await fetch('/resume/upload', { + method: 'POST', + body: formData, + credentials: 'same-origin' + }); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const result = await response.json(); + populateApplicationForm(result); + } catch (error) { + console.error('Error parsing Resume:', error); + showNotification('Failed to parse Resume. Please try again or enter manually.', 'danger'); + } finally { + button.innerHTML = originalText; + button.disabled = false; + } + }; + fileInput.click(); + }); + } + + function populateApplicationForm(resumeData) { + // Add this CSS class definition dynamically + const style = document.createElement('style'); + style.textContent = ` + .populated-field { + background-color: #f5f5f5 !important; + transition: background-color 0.3s ease; + } + `; + document.head.appendChild(style); + + // Helper function to set value with visual feedback + function setValueWithFeedback(element, value) { + if (element && value) { + element.value = value; + element.classList.add('populated-field'); + return true; + } + return false; + } + + // Helper function for select elements + function setSelectValueWithFeedback(selectElement, value, compareAsText = false) { + if (!selectElement || !value) return false; + for (let i = 0; i < selectElement.options.length; i++) { + const option = selectElement.options[i]; + const match = compareAsText + ? option.text.toLowerCase().includes(value.toLowerCase()) + : option.value.toLowerCase() === value.toLowerCase(); + if (match) { + selectElement.value = option.value; + selectElement.classList.add('populated-field'); + return true; + } + } + return false; + } + + // Section 1: Basic Information + if (resumeData.personal_info) { + const personal = resumeData.personal_info; + if (resumeData.candidate_id) { + let candidateId = resumeData.candidate_id; + $('#application-candidate').val(candidateId).trigger('change') + .addClass('populated-field'); + } else { + setValueWithFeedback(document.getElementById('application-fullname'), personal.name); + setValueWithFeedback(document.getElementById('application-email'), personal.email); + setValueWithFeedback(document.getElementById('application-phone'), personal.phone); + setValueWithFeedback(document.getElementById('application-linkedin'), personal.linkedin); + // Skills + if (resumeData.skills?.length) { + const skillValues = resumeData.skills.map(skill => skill.id); + $('#application-skills').val(skillValues).trigger('change') + .addClass('populated-field'); + } + } + setSelectValueWithFeedback( + document.getElementById('application-gender'), + personal.gender + ); + setValueWithFeedback(document.getElementById('application-dob'), personal.dob); + } + + // Professional Information + if (resumeData.professional_info) { + const prof = resumeData.professional_info; + setValueWithFeedback(document.getElementById('application-current-org'), prof.current_company); + setValueWithFeedback( + document.getElementById('application-current-location'), + prof.current_location?.city + ); + setValueWithFeedback(document.getElementById('application-notice-period'), prof.notice_period); + if (prof.notice_period) { + setSelectValueWithFeedback( + document.getElementById('application-notice-negotiable'), + 'yes' + ); + } + setSelectValueWithFeedback( + document.getElementById('application-holding-offer'), + prof.holding_offer ? 'yes' : 'no' + ); + setValueWithFeedback(document.getElementById('application-total-exp'), prof.total_experience); + } + + // Salary Information + setValueWithFeedback(document.getElementById('application-current-ctc'), resumeData.current_ctc); + setValueWithFeedback(document.getElementById('application-expected-salary'), resumeData.expected_salary); + + // Address Information + if (resumeData.contact_info?.current_address) { + const addr = resumeData.contact_info.current_address; + setValueWithFeedback(document.getElementById('application-current-street'), addr.street); + setValueWithFeedback(document.getElementById('application-current-city'), addr.city); + setSelectValueWithFeedback( + document.getElementById('application-current-state'), + addr.state, + true // Compare as text + ); + setSelectValueWithFeedback( + document.getElementById('application-current-country'), + addr.country, + true // Compare as text + ); + setValueWithFeedback(document.getElementById('application-current-zip'), addr.zip); + } + + // Show notification + showNotification('Resume uploaded and fields populated successfully!', 'success'); + } + + // Helper function to show notifications + function showNotification(message, type = 'info') { + // Check if notification container exists, create if not + let notificationContainer = document.getElementById('notification-container'); + if (!notificationContainer) { + notificationContainer = document.createElement('div'); + notificationContainer.id = 'notification-container'; + notificationContainer.style.position = 'fixed'; + notificationContainer.style.top = '20px'; + notificationContainer.style.right = '20px'; + notificationContainer.style.zIndex = '9999'; + document.body.appendChild(notificationContainer); + } + + // Create notification element + const notification = document.createElement('div'); + notification.className = `alert alert-${type} alert-dismissible fade show`; + notification.innerHTML = ` + ${message} + + `; + + // Add to container + notificationContainer.appendChild(notification); + + // Auto remove after 5 seconds + setTimeout(() => { + notification.classList.remove('show'); + setTimeout(() => { + notification.remove(); + }, 300); + }, 5000); + } +} + +function scrollToTarget(targetElement, offset = 100) { + const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - offset; + // First try scrolling the container + const container = document.getElementById('ats-details-container'); + if (container && container.scrollHeight > container.clientHeight) { + const containerTop = container.getBoundingClientRect().top; + const scrollPosition = targetPosition - containerTop - offset; + container.scrollTo({ + top: scrollPosition, + behavior: 'smooth' + }); + } else { + // Fallback to window scrolling + window.scrollTo({ + top: targetPosition, + behavior: 'smooth' + }); + } +} + +function initApplicantDetailEdit() { + // Recruiter photo toggle + const recruiterTrigger = document.getElementById('recruiter-photo-trigger'); + const recruiterInfo = document.getElementById('recruiter-info'); + if (recruiterTrigger && recruiterInfo) { + recruiterTrigger.addEventListener('click', function() { + recruiterInfo.classList.toggle('show'); + }); + } + + // Improved smooth scroll navigation + document.querySelectorAll('.nav-link').forEach(link => { + link.addEventListener('click', function(e) { + e.preventDefault(); + const targetId = this.getAttribute('href'); + const targetElement = document.querySelector(targetId); + if (targetElement) { + scrollToTarget(targetElement); + // Highlight effect + targetElement.style.boxShadow = '0 0 0 3px rgba(13, 110, 253, 0.5)'; + targetElement.style.transition = 'box-shadow 0.3s ease'; + setTimeout(() => { + targetElement.style.boxShadow = 'none'; + }, 2000); + } + }); + }); +} + +// Initialize the page when DOM is ready +document.addEventListener('DOMContentLoaded', initApplicantsPage); \ No newline at end of file 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 new file mode 100644 index 000000000..caf3dd0bc --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/js/ats.js @@ -0,0 +1,46 @@ +/** @odoo-module */ + +document.addEventListener("DOMContentLoaded", function () { + console.log("ATS JS Loaded"); + const contentArea = document.getElementById("main-content"); + const jobDetailArea = document.getElementById("job-detail"); + + const toggleBtn = document.getElementById("sidebar-toggle-btn"); + const sidebar = document.getElementById("sidebar"); + + // ✅ Sidebar Toggle + if (toggleBtn && sidebar) { + toggleBtn.addEventListener("click", function () { + sidebar.classList.toggle("collapsed"); + sidebar.classList.toggle("expanded"); + }); + } + + document.querySelectorAll('.menu-list a[data-page]').forEach(link => { + link.addEventListener('click', async function (e) { + e.preventDefault(); + const page = this.dataset.page; + + try { + const res = await fetch(`/myATS/page/${page}`, { + headers: { "X-Requested-With": "XMLHttpRequest" } + }); + const html = await res.text(); + contentArea.innerHTML = html; + if (jobDetailArea) jobDetailArea.innerHTML = ""; + + // 🔽 Dynamically import JS module for the page + if (page === "job_requests") { + initJobListPage(); + } else if (page === "applicants") { + initApplicantsPage(); + } else if (page === "candidates") { + initCandidatesPage(); + } + + } catch (err) { + contentArea.innerHTML = `

Error loading page: ${err}

`; + } + }); + }); +}); 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 new file mode 100644 index 000000000..51b89010f --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/js/candidates.js @@ -0,0 +1,608 @@ +/** @odoo-module **/ +function initCandidatesPage() { + console.log("candidates Page Loaded"); + const candidateDetailArea = document.getElementById("candidates-detail"); + const container = document.querySelector('.ats-list-container'); // Added this line + const toggleBtn = document.getElementById("candidates-list-sidebar-toggle-btn"); // Added this line + const sidebar = document.getElementById("candidates-list-panel"); // Added this line + + document.querySelectorAll(".ats-item.candidates-item").forEach(item => { + item.addEventListener("click", function() { + document.querySelectorAll(".candidates-item.selected").forEach(el => el.classList.remove("selected")); + this.classList.add("selected"); + + // Show the detail panel and add necessary classes + candidateDetailArea.style.display = 'block'; // Added this line + container.classList.add('ats-selected'); // Added this line + sidebar.classList.remove('collapsed'); // Added this line + toggleBtn.style.display = 'flex'; // Added this line + + const candidateId = this.dataset.id; + console.log("Candidate ID:", candidateId); // Added for debugging + + // Show loading state + if (candidateDetailArea) { + candidateDetailArea.innerHTML = '

Loading candidate details...

'; + } + + fetch(`/myATS/candidate/detail/${candidateId}`, { + headers: { "X-Requested-With": "XMLHttpRequest" } + }) + .then(res => { + if (!res.ok) throw new Error('Network response was not ok'); + return res.text(); + }) + .then(html => { + console.log("Response received"); // Added for debugging + if (candidateDetailArea) { + candidateDetailArea.innerHTML = html; + + // Add close button functionality + const closeBtn = candidateDetailArea.querySelector('.close-detail'); + if (closeBtn) { + closeBtn.addEventListener('click', function() { + candidateDetailArea.style.display = 'none'; + container.classList.remove('ats-selected'); + document.querySelectorAll(".ats-item.candidates-item.selected").forEach(el => el.classList.remove("selected")); + }); + } + } + }) + .catch(error => { + console.error('Error loading candidate details:', error); + if (candidateDetailArea) { + candidateDetailArea.innerHTML = '
Error loading candidate details. Please try again.
'; + } + }); + }); + }); + + // Search functionality + const search = document.getElementById("candidates-search"); + if (search) { + search.addEventListener("input", function() { + const query = this.value.toLowerCase(); + let visibleCount = 0; + document.querySelectorAll(".ats-item.candidates-item").forEach(item => { + const match = item.textContent.toLowerCase().includes(query); + item.style.display = match ? "" : "none"; + if (match) visibleCount++; + }); + const countElement = document.getElementById("active-records-count"); + if (countElement) { + countElement.textContent = visibleCount; + } + }); + } + + // Sidebar Toggle + if (toggleBtn && sidebar) { // Added this check + toggleBtn.addEventListener("click", function(e) { + e.stopPropagation(); + sidebar.classList.toggle("collapsed"); + }); + } + + // Rest of your code remains the same... + const createCandidate = document.getElementById('add-candidate-create-btn'); + const candidateModal = document.getElementById('candidate-form-modal'); + const form = document.getElementById('candidate-form'); + const closeModal = document.querySelectorAll('.candidate-form-close, .btn-cancel'); + const avatarUpload = document.getElementById('avatar-upload'); + const candidateImage = document.getElementById('candidate-image'); + const avatarUploadIcon = document.querySelector('.avatar-upload i'); + + if (avatarUpload && candidateImage) { + // Make the entire avatar clickable + candidateImage.parentElement.style.cursor = 'pointer'; + // Handle click on avatar + candidateImage.parentElement.addEventListener('click', function(e) { + if (e.target !== avatarUpload && e.target !== avatarUploadIcon) { + avatarUpload.click(); + } + }); + // Handle file selection + avatarUpload.addEventListener('change', function(e) { + const file = e.target.files[0]; + if (file && file.type.match('image.*')) { + const reader = new FileReader(); + reader.onload = function(e) { + candidateImage.src = e.target.result; + }; + reader.readAsDataURL(file); + } + }); + } + + // Resume Upload Elements + 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 resumeIframe = document.getElementById('resume-iframe'); + const resumeImage = document.getElementById('resume-image'); + const unsupportedFormat = document.getElementById('unsupported-format'); + const downloadResume = document.getElementById('download-resume'); + const uploadResumeBtn = document.getElementById('upload-applicant-resume'); + let currentResumeFile = null; + + const saveBtn = document.getElementById('save-candidate'); + if (saveBtn) { + saveBtn.addEventListener('click', function (e) { + e.preventDefault(); + createNewCandidate(form, candidateModal); + }); + } + + if (createCandidate) { + createCandidate.addEventListener('click', function(e) { + e.preventDefault(); + candidateModal.style.display = 'flex'; + setTimeout(() => { + candidateModal.classList.add('show'); + }, 10); + document.body.style.overflow = 'hidden'; + setTimeout(() => { + initSelect2(); + initResumeUploadHandlers(); + }, 100); + }); + } + + if (closeModal) { + closeModal.forEach(btn => { + btn.addEventListener('click', function() { + 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; + var imageUrl = $(user.element).data('image') || '/web/static/img/placeholder.png'; + var $container = $( + '' + + '' + + '' + user.text + '' + + '' + ); + return $container; + } + + function formatUserSelection(user) { + if (!user.id) return user.text; + var imageUrl = $(user.element).data('image') || '/web/static/img/placeholder.png'; + var $container = $( + '' + + '' + + '' + user.text + '' + + '' + ); + return $container; + } + + function initSelect2() { + const candidateSkills = document.getElementById('candidate-skills'); + if (candidateSkills) { + $(candidateSkills).select2({ + placeholder: 'Select skills', + allowClear: true, + dropdownParent: $('.candidate-form-modal'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + const managerSelect = document.getElementById('manager'); + if (managerSelect) { + $(managerSelect).select2({ + placeholder: 'Select Manager', + allowClear: true, + templateResult: formatUserOption, + templateSelection: formatUserSelection, + escapeMarkup: function(m) { return m; } + }); + } + } + + function initResumeUploadHandlers() { + // Create remove button + const removeResumeBtn = document.createElement('button'); + removeResumeBtn.innerHTML = ' Remove Resume'; + removeResumeBtn.className = 'btn btn-danger btn-sm mt-2'; + removeResumeBtn.style.display = 'none'; + resumePreview.appendChild(removeResumeBtn); + + // Handle remove resume + removeResumeBtn.addEventListener('click', function() { + resetResumePreview(); + }); + + function resetResumePreview() { + // Clear file input + resumeUpload.value = ''; + currentResumeFile = null; + // Reset preview + resumePlaceholder.style.display = 'flex'; + resumeIframe.style.display = 'none'; + resumeImage.style.display = 'none'; + unsupportedFormat.style.display = 'none'; + removeResumeBtn.style.display = 'none'; + // Reset iframe/src to prevent memory leaks + if (resumeIframe.src) { + URL.revokeObjectURL(resumeIframe.src); + resumeIframe.src = ''; + } + if (resumeImage.src) { + URL.revokeObjectURL(resumeImage.src); + resumeImage.src = ''; + } + if (downloadResume.href) { + URL.revokeObjectURL(downloadResume.href); + downloadResume.href = '#'; + } + } + + // Unified upload handler for both preview and parsing + uploadResumeBtn.addEventListener('click', function(e) { + e.preventDefault(); + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = '.pdf,.doc,.docx,.txt,.jpg,.jpeg,.png'; + fileInput.onchange = async (e) => { + const file = e.target.files[0]; + if (!file) return; + + // First handle the preview + handleResumeFile(file); + + // Then try to parse the resume if it's a parseable type + if (file.type.match(/pdf|msword|openxmlformats|text/)) { + // Show loading state + const button = uploadResumeBtn; + const originalText = button.innerHTML; + button.innerHTML = ' Processing Resume...'; + button.disabled = true; + + try { + const formData = new FormData(); + formData.append('file', file); + formData.append('type', 'candidate'); + + const response = await fetch('/resume/upload', { + method: 'POST', + body: formData, + credentials: 'same-origin' + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const result = await response.json(); + populateCandidateForm(result); + } catch (error) { + console.error('Error parsing Resume:', error); + showNotification('Failed to parse Resume. Please try again or enter manually.', 'danger'); + } finally { + button.innerHTML = ' Upload Resume'; + button.disabled = false; + } + } + }; + fileInput.click(); + }); + + // Handle click on dropzone + resumeDropzone.addEventListener('click', function(e) { + if (e.target === this || e.target.classList.contains('upload-icon') || + e.target.tagName === 'H5' || e.target.tagName === 'P') { + resumeUpload.click(); + } + }); + + // Handle drag and drop + resumeDropzone.addEventListener('dragover', function(e) { + e.preventDefault(); + e.stopPropagation(); + this.classList.add('dragover'); + this.style.borderColor = '#3498db'; + this.style.backgroundColor = 'rgba(52, 152, 219, 0.1)'; + }); + + resumeDropzone.addEventListener('dragleave', function(e) { + e.preventDefault(); + e.stopPropagation(); + this.classList.remove('dragover'); + this.style.borderColor = ''; + this.style.backgroundColor = ''; + }); + + resumeDropzone.addEventListener('drop', function(e) { + e.preventDefault(); + e.stopPropagation(); + this.classList.remove('dragover'); + this.style.borderColor = ''; + this.style.backgroundColor = ''; + + if (e.dataTransfer.files.length) { + const file = e.dataTransfer.files[0]; + handleResumeFile(file); + } + }); + + // Handle file selection from the regular input + resumeUpload.addEventListener('change', function(e) { + if (this.files.length) { + handleResumeFile(this.files[0]); + } + }); + + function handleResumeFile(file) { + const validTypes = [ + 'application/pdf', + 'application/msword', + 'application/wps-office.docx', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'image/jpeg', + 'image/png', + 'text/plain' + ]; + + if (!validTypes.includes(file.type)) { + alert('Please upload a valid file type (PDF, Word, Image, or Text)'); + return; + } + + currentResumeFile = file; + + // Hide placeholder + resumePlaceholder.style.display = 'none'; + + // Set up download link + const fileURL = URL.createObjectURL(file); + downloadResume.href = fileURL; + downloadResume.download = file.name; + removeResumeBtn.style.display = 'block'; + + // Check file type and show appropriate preview + if (file.type === 'application/pdf') { + // PDF preview + resumeIframe.src = fileURL; + resumeIframe.style.display = 'block'; + resumeImage.style.display = 'none'; + unsupportedFormat.style.display = 'none'; + } else if (file.type.match('image.*')) { + // Image preview + resumeImage.src = fileURL; + resumeImage.style.display = 'block'; + resumeIframe.style.display = 'none'; + unsupportedFormat.style.display = 'none'; + } else { + // Unsupported format for preview + unsupportedFormat.style.display = 'flex'; + resumeIframe.style.display = 'none'; + resumeImage.style.display = 'none'; + } + + // Update the actual resume-upload input + const dataTransfer = new DataTransfer(); + dataTransfer.items.add(file); + resumeUpload.files = dataTransfer.files; + } + } + + function populateCandidateForm(resumeData) { + // Add CSS for visual feedback + const style = document.createElement('style'); + style.textContent = ` + .populated-field { + background-color: #f5f5f5 !important; + transition: background-color 0.3s ease; + } + .select2-populated .select2-selection--multiple { + background-color: #f5f5f5 !important; + } + .select2-populated .select2-selection__choice { + background-color: #e8f5e9 !important; + border-color: #c8e6c9 !important; + } + `; + document.head.appendChild(style); + + // Helper function to set value with visual feedback + function setValueWithFeedback(elementId, value) { + const element = document.getElementById(elementId); + if (element && value) { + element.value = value; + element.classList.add('populated-field'); + + // Special handling for Select2 if this element uses it + if ($(element).hasClass('select2-hidden-accessible')) { + $(element).next('.select2-container') + .find('.select2-selection') + .addClass('populated-field'); + } + return true; + } + return false; + } + + // Section 1: Basic Information + if (resumeData.personal_info) { + const personal = resumeData.personal_info; + + // Set values with visual feedback + setValueWithFeedback('partner-name', personal.name); + setValueWithFeedback('email', personal.email); + setValueWithFeedback('phone', personal.phone); + setValueWithFeedback('linkedin', personal.linkedin); + + // If any of these fields are Select2 elements, ensure they get styled + ['partner-name', 'email', 'phone', 'linkedin'].forEach(id => { + const el = document.getElementById(id); + if (el && el.value && $(el).hasClass('select2-hidden-accessible')) { + $(el).next('.select2-container') + .find('.select2-selection') + .addClass('populated-field'); + } + }); + } + + // Skills - Handle Select2 with background color change + if (resumeData.skills?.length) { + const skillValues = resumeData.skills.map(skill => skill.id); + $('#candidate-skills') + .val(skillValues) + .trigger('change') + .addClass('populated-field'); + + // Add class to Select2 container for styling + $('#candidate-skills').next('.select2-container') + .find('.select2-selection--multiple') + .addClass('select2-populated'); + } + + // Show notification + showNotification('Resume uploaded and fields populated successfully!', 'success'); + } + + function showNotification(message, type) { + // Check if notification container exists, create if not + let notificationContainer = document.getElementById('notification-container'); + if (!notificationContainer) { + notificationContainer = document.createElement('div'); + notificationContainer.id = 'notification-container'; + notificationContainer.style.position = 'fixed'; + notificationContainer.style.top = '20px'; + notificationContainer.style.right = '20px'; + notificationContainer.style.zIndex = '9999'; + document.body.appendChild(notificationContainer); + } + + // Create notification element + const notification = document.createElement('div'); + notification.className = `alert alert-${type} alert-dismissible fade show`; + notification.innerHTML = ` + ${message} + + `; + + // Add to container + notificationContainer.appendChild(notification); + + // Auto remove after 5 seconds + setTimeout(() => { + notification.classList.remove('show'); + setTimeout(() => { + notification.remove(); + }, 300); + }, 5000); + } +} + +function createNewCandidate(form, modal) { + if (!form.checkValidity()) { + form.reportValidity(); + return; + } + + const formData = new FormData(); + + // Basic Information + formData.append('sequence', document.getElementById('candidate-sequence').value); + formData.append('partner_name', document.getElementById('partner-name').value); + + // Add image file if selected + const avatarUpload = document.getElementById('avatar-upload'); + if (avatarUpload.files.length > 0) { + formData.append('image_1920', avatarUpload.files[0]); + } + + // Contact Information + formData.append('email', document.getElementById('email').value); + formData.append('phone', document.getElementById('phone').value); + formData.append('mobile', document.getElementById('alternate-phone').value); + formData.append('linkedin_profile', document.getElementById('linkedin').value); + formData.append('type_id', document.getElementById('type').value); + formData.append('user_id', document.getElementById('manager').value); + formData.append('availability', document.getElementById('availability').value); + + // Skills + const skillOptions = document.getElementById('candidate-skills').selectedOptions; + for (let i = 0; i < skillOptions.length; i++) { + formData.append('skill_ids', skillOptions[i].value); + } + + // Add resume file if selected + const resumeUpload = document.getElementById('resume-upload'); + if (resumeUpload.files.length > 0) { + formData.append('resume_file', resumeUpload.files[0]); + } + + // Additional fields + formData.append('active', 'true'); + formData.append('color', '0'); + + fetch('/myATS/candidate/create', { + method: 'POST', + body: formData, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + } + }) + .then(async (response) => { + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.error || response.statusText); + } + return response.json(); + }) + .then(data => { + if (data.success) { + modal.classList.remove('show'); + document.body.style.overflow = ''; + form.reset(); + alert('Candidate created successfully!'); + + // Refresh the candidates list + fetch('/myATS/page/candidates', { + headers: { "X-Requested-With": "XMLHttpRequest" } + }) + .then(res => res.text()) + .then(html => { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + const newCandidate = doc.querySelector('.candidates-list-left'); + const existingCandidatesList = document.querySelector('.candidates-list-left'); + if (newCandidate && existingCandidatesList) { + existingCandidatesList.innerHTML = newCandidate.innerHTML; + initCandidatesPage(); + } + }); + } else { + throw new Error(data.error || 'Failed to save Candidate'); + } + }) + .catch(error => { + console.error('Error:', error); + alert("Error saving changes: " + error.message); + }); +} + +// Initialize the page when DOM is ready +document.addEventListener('DOMContentLoaded', initCandidatesPage); \ No newline at end of file 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 new file mode 100644 index 000000000..0be23f0a6 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/js/job_requests.js @@ -0,0 +1,1631 @@ +/** @odoo-module */ + +// Define all your page initialization functions first +function initJobListPage() { + console.log("Job List Page JS Loaded"); + const jobDetailArea = document.getElementById("job-detail"); + const headerBadges = document.querySelectorAll(".stat-toggle"); + const container = document.querySelector('.ats-list-container'); + const sidebar = document.getElementById("job-list-panel"); + const toggleBtn = document.getElementById("job-list-sidebar-toggle-btn"); + + // Initially hide the job detail panel + jobDetailArea.style.display = 'none'; + + // Badge click handler (unchanged) + headerBadges.forEach(badge => { + badge.addEventListener("click", function() { + this.classList.toggle("active"); + this.classList.toggle("crossed"); + const type = this.dataset.type; + document.querySelectorAll(`.job-badge[data-type="${type}"]`).forEach(jobBadge => { + jobBadge.style.display = this.classList.contains("active") ? "inline-block" : "none"; + }); + const activeJob = document.querySelector(".job-item.selected"); + if (!this.classList.contains("active")) { + // Handle inactive state + } else if (activeJob) { + // Handle active state + } + }); + }); + + // Job item click logic + document.querySelectorAll(".job-item").forEach(item => { + item.addEventListener("click", function() { + document.querySelectorAll(".job-item.selected").forEach(el => el.classList.remove("selected")); + this.classList.add("selected"); + + // Show job detail panel and adjust layout + jobDetailArea.style.display = 'block'; + container.classList.add('ats-selected'); + sidebar.classList.remove('collapsed'); + toggleBtn.style.display = 'flex'; + + const jobId = this.dataset.id; + fetch(`/myATS/job/detail/${jobId}`, { + headers: { "X-Requested-With": "XMLHttpRequest" } + }) + .then(res => res.text()) + .then(html => { + if (jobDetailArea) { + jobDetailArea.innerHTML = html; + initJobDetailEdit(); // Initialize edit functionality + + // Add close button functionality + const closeBtn = jobDetailArea.querySelector('.close-detail'); + if (closeBtn) { + closeBtn.addEventListener('click', function() { + jobDetailArea.style.display = 'none'; + container.classList.remove('ats-selected'); + document.querySelectorAll(".job-item.selected").forEach(el => el.classList.remove("selected")); + }); + } + } + }); + }); + }); + + // Search functionality (unchanged) + const search = document.getElementById("ats-search"); + if (search) { + search.addEventListener("input", function () { + const query = this.value.toLowerCase(); + let visibleCount = 0; + document.querySelectorAll(".ats-item").forEach(item => { + const match = item.textContent.toLowerCase().includes(query); + item.style.display = match ? "" : "none"; + if (match) visibleCount++; + }); + const countElement = document.getElementById("active-records-count"); + if (countElement) { + countElement.textContent = visibleCount; + } + }); + } + + // Sidebar Toggle + if (toggleBtn && sidebar) { + toggleBtn.addEventListener("click", function () { + sidebar.classList.toggle("collapsed"); + // Change the button icon based on state + if (sidebar.classList.contains("collapsed")) { + this.textContent = "☰"; + this.style.right = "-12px"; + this.style.transform = "translateY(-50%)"; + } else { + this.textContent = "☰"; + this.style.right = "-12px"; + } + }); + } + + initJDModal(); +} + +let editor = null; + +function initJobDetailEdit() { + const editBtn = document.getElementById('edit-job-btn'); + const cancelBtn = document.getElementById('cancel-edit'); + const editForm = document.getElementById('job-edit-form'); + const viewSection = document.getElementById('job-detail-view'); + const editSection = document.getElementById('job-detail-edit'); + + + if (editBtn) { + editBtn.addEventListener('click', function() { + viewSection.style.display = 'none'; + editSection.style.display = 'block'; + + // Initialize CKEditor + if (typeof CKEDITOR !== 'undefined') { + if (editor) { + editor.destroy(); + } + editor = CKEDITOR.replace('job-description-edit', { + toolbar: [ + { name: 'basicstyles', items: ['Bold', 'Italic', 'Underline', 'Strike', '-', 'RemoveFormat'] }, + { name: 'paragraph', items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent'] }, + { name: 'links', items: ['Link', 'Unlink'] }, + { name: 'document', items: ['Source'] } + ], + height: 300 + }); + } + }); + } + + if (cancelBtn) { + cancelBtn.addEventListener('click', function () { + const jobId = document.getElementById('job-edit-form').dataset.id; + + fetch(`/myATS/job/detail/${jobId}`, { + headers: { "X-Requested-With": "XMLHttpRequest" } + }) + .then(res => res.text()) + .then(html => { + const jobDetailArea = document.getElementById('job-detail'); + if (jobDetailArea) { + jobDetailArea.innerHTML = html; + initJobDetailEdit(); // re-init the edit handlers + } + }); + + if (editor) { + editor.destroy(); + editor = null; + } + }); + } + + + if (editForm) { + editForm.addEventListener('submit', function(e) { + e.preventDefault(); + saveJobDetails(this); + }); + } + + initSmartButtons(); +} + +function saveJobDetails(form) { + // Get CKEditor data properly + let description = ''; + if (editor && CKEDITOR.instances['job-description-edit']) { + description = CKEDITOR.instances['job-description-edit'].getData(); + } else { + description = document.getElementById('job-description-edit')?.innerHTML || ''; + } + + const jobId = form.dataset.id; + const formData = { + 'id': jobId, + 'job_id': form.querySelector('#job-id-edit').value, + 'job_sequence': form.querySelector('#job-sequence-edit').value, + 'category': form.querySelector('#job-category-edit').value, + 'description': description, + }; + + fetch('/myATS/job/save', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'X-Requested-With': 'XMLHttpRequest' + }, + body: JSON.stringify(formData) + }) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + }) + .then(data => { + if (data.success) { + // Update view with new data + document.getElementById('job-name-view').textContent = formData.name; + document.getElementById('job-description-view').innerHTML = formData.description; + + const selectedOption = document.querySelector('#job-category-edit option:checked'); + if (selectedOption) { + document.getElementById('job-category-view').textContent = selectedOption.textContent; + } + + document.getElementById('job-detail-view').style.display = 'block'; + document.getElementById('job-detail-edit').style.display = 'none'; + + if (editor) { + editor.destroy(); + editor = null; + } + + alert("Changes saved successfully"); + fetch('/myATS/page/job_requests', { + headers: { "X-Requested-With": "XMLHttpRequest" } + }) + .then(res => res.text()) + .then(html => { + // Replace only the left panel to avoid wiping out the whole page + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + const newJobList = doc.querySelector('.job-list-left'); + const existingJobList = document.querySelector('.job-list-left'); + + if (newJobList && existingJobList) { + existingJobList.innerHTML = newJobList.innerHTML; + initJobListPage(); // re-bind event listeners + } + }); + } else { + throw new Error(data.error || 'Unknown error occurred'); + } + }) + .catch(error => { + console.error('Error:', error); + alert("Error saving changes: " + error.message); + }); +} + +let wysiwyg = null; + + +function createJobDetails(form, modal) { + + if (!form.checkValidity()) { + form.reportValidity(); + return; + } + + // Get editor content + let description = ''; + if (wysiwyg) { + description = wysiwyg.getData(); + } else { + description = null +// description = document.getElementById('job-description').value || ''; + } + + // Collect form data + const formData = { + // Basic Information + sequence: document.getElementById('job-sequence').value, + position_id: document.getElementById('job-position').value, + category: document.getElementById('job-category').value, + priority: document.getElementById('job-priority').value, + work_type: document.querySelector('input[name="work-type"]:checked').value, + client_company_id: document.getElementById('client-company').value, + client_id: document.getElementById('client-id').value, + + // Employment Details + employment_type_id: document.getElementById('employment-type').value, + budget: document.getElementById('job-budget').value, + no_of_positions: document.getElementById('job-no-of-positions').value, + eligible_submissions: document.getElementById('job-eligible-submissions').value, + target_from: document.getElementById('target-from').value, + target_to: document.getElementById('target-to').value, + + // Skills & Requirements + primary_skill_ids: Array.from(document.getElementById('job-primary-skills').selectedOptions) + .map(option => option.value), + secondary_skill_ids: Array.from(document.getElementById('job-secondary-skills').selectedOptions) + .map(option => option.value), + experience_id: document.getElementById('job-experience').value, + + // Recruitment Team + primary_recruiter_id: document.getElementById('primary-recruiter').value, + secondary_recruiter_ids: Array.from(document.getElementById('secondary-recruiter').selectedOptions) + .map(option => option.value), + + // Additional Information + location_ids: Array.from(document.getElementById('job-locations').selectedOptions) + .map(option => option.value), + stage_ids: Array.from(document.getElementById('recruitment-stages').selectedOptions) + .map(option => option.value), + + // Description + description: description, + + // Attachments (if any) + attachment_ids: [] + }; + + fetch('/myATS/job/create', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'application/json' + }, + body: JSON.stringify(formData) + }).then(async (response) => { + const contentType = response.headers.get("content-type"); + const responseData = contentType && contentType.includes("application/json") + ? await response.json() + : await response.text(); + + if (!response.ok) { + // For 500 errors, check if we have a JSON response with error details + if (response.status === 500 && typeof responseData === 'object') { + throw new Error(responseData.error || responseData.message || "Internal server error"); + } else if (typeof responseData === 'string') { + throw new Error(responseData); + } else { + throw new Error(response.statusText); + } + } + + return responseData; + }) + .then(data => { + if (data.success) { + modal.classList.remove('show'); + document.body.style.overflow = ''; + form.reset(); + + if (wysiwyg) { + wysiwyg.destroy() + .then(() => { + wysiwyg = null; + }) + .catch(error => { + console.error('Error destroying editor:', error); + }); + } + + alert('Job created successfully!'); + fetch('/myATS/page/job_requests', { + headers: { "X-Requested-With": "XMLHttpRequest" } + }) + .then(res => res.text()) + .then(html => { + // Replace only the left panel to avoid wiping out the whole page + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + const newJobList = doc.querySelector('.job-list-left'); + const existingJobList = document.querySelector('.job-list-left'); + + if (newJobList && existingJobList) { + existingJobList.innerHTML = newJobList.innerHTML; + initJobListPage(); // re-bind event listeners + } + }); + } else { + throw new Error(data.error || 'Failed to save job'); + } + }) + .catch(error => { + console.error('Error:', error); + alert("Error saving changes: " + error.message); + }); +} + + +// Add this function to your existing JS +async function initJDModal() { + console.log('Initializing JD modal'); + const modal = document.getElementById('add-jd-modal'); + const addJdBtn = document.getElementById('add-jd-create-btn'); + const closeBtns = document.querySelectorAll('.jd-modal-close, .btn-cancel'); + const saveBtn = document.getElementById('save-jd'); + const form = document.getElementById('jd-form'); + const uploadBtn = document.getElementById('upload-jd') + + if (!modal) return; + + if (addJdBtn) { + addJdBtn.addEventListener('click', async function(e) { + e.preventDefault(); + modal.classList.add('show'); + document.body.style.overflow = 'hidden'; + + // Initialize WYSIWYG editor + const editorElement = document.getElementById('job-description-editor'); + +// editorElement.innerHTML = document.getElementById('job-description').value || ''; + + // Replace your current CKEditor initialization with this: + // Replace your CKEditor initialization with this: + if (editorElement && !wysiwyg) { + try { + await loadAssets([ + '/hr_recruitment_web_app/static/src/libs/ckeditor/build/ckeditor.js' + ]); + + ClassicEditor + .create(editorElement, { + toolbar: { + items: [ + 'heading', '|', + 'bold', 'italic', 'link', 'bulletedList', 'numberedList', '|', + 'blockQuote', 'uploadImage', '|', + 'undo', 'redo' + ] + }, + image: { + toolbar: [ + 'imageTextAlternative', + 'toggleImageCaption', + 'imageStyle:inline', + 'imageStyle:block', + 'imageStyle:side' + ], + upload: { + types: ['jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff'] + } + }, + simpleUpload: { + uploadUrl: '/web_editor/attachment/add', + withCredentials: true, + headers: { + 'X-CSRF-TOKEN': getCookie('csrftoken') || '', + 'X-Requested-With': 'XMLHttpRequest' + }, + additionalRequestData: { + 'res_model': 'hr.job', + 'res_id': 0, + 'callback': 'window.top' + } + }, + typing: { + undo: true + }, + keystrokes: [ + [ 32, 'insertText', ' ' ] // Handle spacebar + ] + }) + .then(editor => { + wysiwyg = editor; + const textarea = document.getElementById('job-description'); + + editor.model.document.on('change:data', () => { + document.getElementById('job-description').value = editor.getData(); + }); + + if (textarea) { + textarea.addEventListener('input', () => { + if (wysiwyg) { + wysiwyg.setData(textarea.value); + } + }); + } + }) + .catch(error => { + console.error('Error initializing CKEditor:', error); + }); + } catch (error) { + console.error('Error loading CKEditor:', error); + } + } + + setTimeout(initSelect2, 100); + }); + } + + // Close modal handlers + closeBtns.forEach(btn => { + btn.addEventListener('click', function(e) { + e.preventDefault(); + modal.classList.remove('show'); + document.body.style.overflow = ''; + form.reset(); + + if (wysiwyg) { + wysiwyg.destroy() + .then(() => { + wysiwyg = null; + }) + .catch(error => { + console.error('Error destroying editor:', error); + }); + } + }); + }); + + modal.addEventListener('click', function(e) { + if (e.target === modal) { + modal.classList.remove('show'); + document.body.style.overflow = ''; + form.reset(); + if (wysiwyg) { + wysiwyg.destroy() + .then(() => { + wysiwyg = null; + }) + .catch(error => { + console.error('Error destroying editor:', error); + }); + } + } + }); + + // Save JD + if (saveBtn) { + saveBtn.addEventListener('click', function (e) { + e.preventDefault(); + createJobDetails(form, modal); + }); + } + + if (uploadBtn) { + uploadBtn.addEventListener('click', function (e) { + e.preventDefault(); + // Create file input element + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = '.pdf,.doc,.docx,.txt'; + + fileInput.onchange = async (e) => { + const file = e.target.files[0]; + if (!file) return; + + // Show loading state + const button = document.getElementById('upload-jd'); + const originalText = button.innerHTML; + button.innerHTML = ' Processing JD...'; + button.disabled = true; + + try { + const formData = new FormData(); + formData.append('file', file); + + // Call your Odoo endpoint + const response = await fetch('/jd/upload', { + method: 'POST', + body: formData, + credentials: 'same-origin' + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const result = await response.json(); + + // Map all fields from the parsed result to the form + populateJDForm(result); + + // Show notification + showNotification('JD uploaded and fields populated successfully!', 'success'); + + } catch (error) { + console.error('Error parsing JD:', error); + showNotification('Failed to parse JD. Please try again or enter manually.', 'danger'); + } finally { + button.innerHTML = originalText; + button.disabled = false; + } + }; + + fileInput.click(); + }); + } + + function populateJDForm(jdData) { + // Section 1: Basic Information + if (jdData.sequence) { + document.getElementById('job-sequence').value = jdData.sequence; + } + + // Job Position - try to match with existing options + if (jdData.job_title) { + const jobSelect = document.getElementById('job-position'); + const options = jobSelect.options; + let found = false; + + // First try exact match + for (let i = 0; i < options.length; i++) { + if (options[i].text.toLowerCase() === jdData.job_title.toLowerCase()) { + jobSelect.value = options[i].value; + $(jobSelect).trigger('change'); + found = true; + break; + } + } + + // If not found, try partial match + if (!found) { + for (let i = 0; i < options.length; i++) { + if (options[i].text.toLowerCase().includes(jdData.job_title.toLowerCase()) || + jdData.job_title.toLowerCase().includes(options[i].text.toLowerCase())) { + jobSelect.value = options[i].value; + $(jobSelect).trigger('change'); + break; + } + } + } + } + + // Set work type based on employment type + if (jdData.employment_type) { + const employmentType = jdData.employment_type.toLowerCase(); + if (employmentType.includes('client') || employmentType.includes('external')) { + document.getElementById('work-type-external').checked = true; + } else { + document.getElementById('work-type-internal').checked = true; + } + } + + // Section 2: Employment Details + if (jdData.target_start_date) { + document.getElementById('target-from').value = jdData.target_start_date; + } + if (jdData.target_end_date) { + document.getElementById('target-to').value = jdData.target_end_date; + } + + // Set employment type dropdown + if (jdData.employment_type) { + const empTypeSelect = document.getElementById('employment-type'); + const options = empTypeSelect.options; + for (let i = 0; i < options.length; i++) { + if (options[i].text.toLowerCase().includes(jdData.employment_type.toLowerCase())) { + empTypeSelect.value = options[i].value; + break; + } + } + } + + // Set experience dropdown + if (jdData.experience) { + document.getElementById('job-experience').value = jdData.experience.id; + $(document.getElementById('job-experience')).trigger('change'); + } + + // Section 3: Skills & Requirements + if (jdData.primary_skills && jdData.primary_skills.length) { + const skillValues = jdData.primary_skills.map(skill => skill.id); + $('#job-primary-skills').val(skillValues).trigger('change'); + } + + if (jdData.secondary_skills && jdData.secondary_skills.length) { + const skillValues = jdData.secondary_skills.map(skill => skill.id); + $('#job-secondary-skills').val(skillValues).trigger('change'); + } + + // Section 5: Additional Information + if (jdData.locations && jdData.locations.length) { + const locationValues = jdData.locations.map(loc => loc.id); + $('#job-locations').val(locationValues).trigger('change'); + } + + if (jdData.description) { + setTimeout(() => { + const editor = document.getElementById('job-description-editor'); + const textarea = document.getElementById('job-description'); + + if (!editor || !textarea) { + console.error('Editor or textarea element not found!'); + return; + } + + const lines = jdData.description.split('\n').map(l => l.trim()).filter(l => l); + let formatted = ''; + let inBulletList = false; + + lines.forEach(line => { + const numberedMatch = line.match(/^(\d+\.\s+)(.*)/); + const bulletMatch = line.match(/^([•\-○]\s*)(.*)/); + const titleMatch = line.match(/^(.+?):\s*(.*)/); + + if (numberedMatch) { + // Close bullet list if previously opened + if (inBulletList) { + formatted += ''; + inBulletList = false; + } + formatted += `

${numberedMatch[1]}${numberedMatch[2]}

`; + } else if (bulletMatch) { + if (!inBulletList) { + formatted += '
    '; + inBulletList = true; + } + formatted += `
  • ${bulletMatch[2]}
  • `; + } else if (titleMatch) { + if (inBulletList) { + formatted += '
'; + inBulletList = false; + } + formatted += `

${titleMatch[1]}: ${titleMatch[2]}

`; + } else { + // Treat as bullet if short or point-like + if (line.length < 150 && /^[A-Za-z0-9].*/.test(line)) { + if (!inBulletList) { + formatted += '
    '; + inBulletList = true; + } + formatted += `
  • ${line}
  • `; + } else { + if (inBulletList) { + formatted += '
'; + inBulletList = false; + } + formatted += `

${line}

`; + } + } + }); + + // Close any open
    + if (inBulletList) { + formatted += '
'; + } + + editor.innerHTML = formatted; + textarea.value = formatted; + textarea.dispatchEvent(new Event('input', { bubbles: true })); + + console.log('Formatted:', formatted); + }, 300); + } + + } + + function showNotification(message, type) { + // Using Odoo's notification system + if (typeof Notification !== 'undefined') { + Notification.create({ + title: type === 'success' ? 'Success' : 'Error', + message: message, + type: type, + sticky: false + }); + } else { + // Fallback to alert + alert(`${type.toUpperCase()}: ${message}`); + } + } + + function getCookie(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== '') { + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + if (cookie.substring(0, name.length + 1) === (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + + // Helper function to load WYSIWYG assets + function loadAssets(assets) { + return Promise.all(assets.map(asset => { + return new Promise((resolve, reject) => { + const isCss = asset.endsWith('.css'); + const element = isCss + ? document.createElement('link') + : document.createElement('script'); + + if (isCss) { + element.rel = 'stylesheet'; + element.href = asset; + element.type = 'text/css'; + } else { + element.src = asset; + element.type = 'text/javascript'; + } + + element.onload = resolve; + element.onerror = () => reject(new Error(`Failed to load ${asset}`)); + document.head.appendChild(element); + }); + })); + } + + + // Populate categories (example) +// const categorySelect = document.getElementById('job-category'); +// if (categorySelect) { +// // You might want to fetch these from your backend +// const categories = ['IT', 'Marketing', 'Finance', 'HR', 'Operations']; +// categories.forEach(cat => { +// const option = document.createElement('option'); +// option.value = cat.toLowerCase(); +// option.textContent = cat; +// categorySelect.appendChild(option); +// }); +// } + + const workTypeRadios = document.querySelectorAll("input[name='work-type']"); + const companySelect = document.getElementById("client-company"); + const clientSelect = document.getElementById("client-id"); + + let clientToCompanyMap = {}; // New map + + function initSelect2() { + // Check if Select2 is already initialized + const primarySkillsSelect = document.getElementById('job-primary-skills'); + if (primarySkillsSelect) { + $(primarySkillsSelect).select2({ + placeholder: 'Select skills', + allowClear: true, + dropdownParent: $('.new-jd-container'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + const jobPosition = document.getElementById('job-position'); + if (jobPosition) { + $(jobPosition).select2({ + placeholder: 'Select Job Position', + dropdownParent: $('.new-jd-container'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + const clientCompany = document.getElementById('client-company'); + if (clientCompany) { + $(clientCompany).select2({ + placeholder: 'Select Client Company', + dropdownParent: $('.new-jd-container'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + const clientId = document.getElementById('client-id'); + if (clientId) { + $(clientId).select2({ + placeholder: 'Select client', + dropdownParent: $('.new-jd-container'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + const secondarySkillSelect = document.getElementById('job-secondary-skills'); + if (secondarySkillSelect) { + $(secondarySkillSelect).select2({ + placeholder: 'Select skills', + allowClear: true, + dropdownParent: $('.new-jd-container'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + const primaryRecruiterSelect = document.getElementById('primary-recruiter'); + if (primaryRecruiterSelect) { + $(primaryRecruiterSelect).select2({ + placeholder: 'Select Primary Recruiters', + allowClear: true, + templateResult: formatUserOption, + templateSelection: formatUserSelection, + escapeMarkup: function(m) { return m; } + }); + } + + const secondaryRecruiterSelect = document.getElementById('secondary-recruiter'); + if (secondaryRecruiterSelect) { + $(secondaryRecruiterSelect).select2({ + placeholder: 'Select Secondary Recruiters', + allowClear: true, + templateResult: formatUserOption, + templateSelection: formatUserSelection, + dropdownParent: $('.new-jd-container'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + const jobLocationsSelect = document.getElementById('job-locations'); + if (jobLocationsSelect) { + $(jobLocationsSelect).select2({ + placeholder: 'Select Job Locations', + allowClear: true, + dropdownParent: $('.new-jd-container'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + const RecruitmentStagesSelect = document.getElementById('recruitment-stages'); + if (RecruitmentStagesSelect) { + $(RecruitmentStagesSelect).select2({ + placeholder: 'Select Recruitment Stages', + allowClear: true, + dropdownParent: $('.new-jd-container'), + width: '100%', + escapeMarkup: function(m) { return m; } + }); + } + + initSkillsDragAndDrop(); + } + + function setPrimarySkills(skills, remove = false) { + const $select = $('#job-primary-skills'); + if ($select.hasClass("select2-hidden-accessible")) { + let current = $select.val() || []; + if (remove) { + // Remove the specified skills + current = current.filter(id => !skills.includes(id)); + } else { + // Add the specified skills (avoid duplicates) + current = Array.from(new Set(current.concat(skills))); + } + $select.val(current).trigger('change'); + } else { + setTimeout(() => setPrimarySkills(skills, remove), 100); + } + } + + function setSecondarySkills(skills, remove = false) { + const $select = $('#job-secondary-skills'); + if ($select.hasClass("select2-hidden-accessible")) { + let current = $select.val() || []; + if (remove) { + // Remove the specified skills + current = current.filter(id => !skills.includes(id)); + } else { + // Add the specified skills (avoid duplicates) + current = Array.from(new Set(current.concat(skills))); + } + $select.val(current).trigger('change'); + } else { + setTimeout(() => setSecondarySkills(skills, remove), 100); + } + } + + function isSkillInOptions(skillId, selectId) { + return $(`#${selectId} option[value="${skillId}"]`).length > 0; + } + function isSkillSelected(skillId, selectId) { + const selector = `#${selectId}`; + const selectedValues = $(selector).val() || []; + return selectedValues.includes(skillId.toString()); + } + // Add this new function + function initSkillsDragAndDrop() { + const skillRequirementsDiv = document.getElementById('skill_requirements'); + const primarySkills = document.getElementById('job-primary-skills'); + const secondarySkills = document.getElementById('job-secondary-skills'); + + if (!skillRequirementsDiv || !primarySkills || !secondarySkills) return; + + // Make options draggable + [primarySkills, secondarySkills].forEach(select => { + // Set draggable attribute on all options + Array.from(select.options).forEach(option => { + option.setAttribute('draggable', 'true'); + }); + + select.addEventListener('dragstart', function(e) { + if (e.target.tagName === 'OPTION') { + console.log('Drag started for option:', e.target.value); + e.dataTransfer.setData('text/plain', e.target.value); + e.dataTransfer.effectAllowed = 'move'; + e.target.classList.add('dragging'); + } + }); + + select.addEventListener('dragend', function(e) { + if (e.target.tagName === 'OPTION') { + console.log('Drag ended for option:', e.target.value); + e.target.classList.remove('dragging'); + } + }); + }); + + // Set up drop zones for both selects + [primarySkills, secondarySkills].forEach(select => { + const select2Container = $(`#${select.id}`).next('.select2-container'); + const select2Selection = select2Container.find('.select2-selection--multiple'); + console.log(select2Container); + console.log(select2Selection); + // Handle dragover for the Select2 container + select2Selection.on('dragover', function(e) { + e.preventDefault(); + e.originalEvent.dataTransfer.dropEffect = 'move'; + $(this).addClass('drag-over'); + console.log('Dragging over select:', select.id); + return false; + }); + + // Handle dragleave for the Select2 container + select2Selection.on('dragleave', function(e) { + console.log("drag leave feature"); + $(this).removeClass('drag-over'); + return false; + }); + + // Handle drop for the Select2 container + select2Selection.on('drop', function(e) { + console.log("dropping the data"); + e.preventDefault(); + e.stopPropagation(); + $(this).removeClass('drag-over'); + + const skillId = e.originalEvent.dataTransfer.getData('text/plain'); + const option = document.querySelector(`option[value="${skillId}"]`); + console.log('Moving option from', option.parentElement.id, 'to', select.id); + + console.log('Dropped skill ID:', skillId); + + if (!isSkillInOptions(skillId, select.id)) { + console.log('Skill does not exists in the selected dropdown'); + return; + } + + + // If the option is already in this select, do nothing + if (isSkillSelected(skillId, select.id)) { + console.log('Skill is already selected.'); + return; + } + + + // Remove from current select + const oldSelect = option.parentElement; + if (select.id == 'job-primary-skills'){ + setSecondarySkills(skillId, remove=true) + setPrimarySkills(skillId) + } else { + setPrimarySkills(skillId, remove=true) + setSecondarySkills(skillId) + } + + + + // Trigger Select2 updates + $(oldSelect).trigger('change'); + $(select).trigger('change'); + + console.log('Option moved successfully'); + return false; + }); + }); + + // Prevent default behavior for the parent container + skillRequirementsDiv.addEventListener('dragover', function(e) { + e.preventDefault(); + e.dataTransfer.dropEffect = 'none'; + return false; + }); + + skillRequirementsDiv.addEventListener('drop', function(e) { + console.log("drop feature"); + e.preventDefault(); + return false; + }); + + // Make Select2 choices draggable + $(document).on('mouseenter', '.select2-selection__choice', function() { + this.setAttribute('draggable', 'true'); + this.addEventListener('dragstart', function(e) { + console.log("dragstarted"); + const value = $(this).attr('title') || $(this).text().trim(); + console.log('Dragging choice:', value); + const option = $(primarySkills).find(`option:contains('${value}')`)[0] || + $(secondarySkills).find(`option:contains('${value}')`)[0]; + if (option) { + console.log('Found matching option:', option.value); + e.dataTransfer.setData('text/plain', option.value); + e.dataTransfer.effectAllowed = 'move'; + } else { + console.log('No matching option found for:', value); + } + }); + }); + } + + function formatUserOption(user) { + if (!user.id) return user.text; + var imageUrl = $(user.element).data('image') || '/web/static/img/placeholder.png'; + var $container = $( + '' + + '' + + '' + user.text + '' + + '' + ); + return $container; + } + + function formatUserSelection(user) { + if (!user.id) return user.text; + var imageUrl = $(user.element).data('image') || '/web/static/img/placeholder.png'; + var $container = $( + '' + + '' + + '' + user.text + '' + + '' + ); + return $container; + } + + function fetchCompanies(workType) { + fetch('/get_client_companies', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ type: workType }) + }) + .then(res => res.json()) + .then(data => { + const companies = data.result; + if (!Array.isArray(companies)) { + console.error("Expected an array, got:", companies); + return; + } + + companySelect.innerHTML = ''; + companies.forEach(company => { + companySelect.innerHTML += ``; + }); + + clientSelect.innerHTML = ''; + clientToCompanyMap = {}; // Reset map + }) + .catch(err => { + console.error("Error fetching companies:", err); + }); + } + + function fetchClients(companyId, workType) { + fetch('/get_clients_by_company', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ company_id: companyId, type: workType }) + }) + .then(res => res.json()) + .then(data => { + const clients = data.result; + if (!Array.isArray(clients)) { + console.error("Expected an array, got:", clients); + return; + } + + clientSelect.innerHTML = ''; + clientToCompanyMap = {}; // Reset map + + clients.forEach(client => { + clientSelect.innerHTML += ``; + clientToCompanyMap[client.id] = client.company_id; // Assuming `company_id` comes from backend + }); + }); + } + + + // Initial fetch on page load + const initialType = document.querySelector("input[name='work-type']:checked").value; + fetchCompanies(initialType); + fetchClients(null, initialType); + + + // Change on radio click + workTypeRadios.forEach(radio => { + console.log("radio clicked"); + radio.addEventListener("change", () => { + fetchCompanies(radio.value); + fetchClients(companyId = null, workType = radio.value); + + }); + }); + + companySelect.addEventListener("change", () => { + let selectedCompanyId = null; + if (companySelect.value){ + selectedCompanyId = companySelect.value; + } + clientSelect.innerHTML = ''; + const selectedType = document.querySelector("input[name='work-type']:checked").value; + fetchClients(selectedCompanyId, selectedType); + }); + + // On client selection + clientSelect.addEventListener("change", () => { + const selectedClientId = clientSelect.value; + + if (selectedClientId && clientToCompanyMap[selectedClientId]) { + const companyId = clientToCompanyMap[selectedClientId]; + companySelect.value = companyId; + } + }); +} + +// Track open popups +const openPopups = []; + +function initSmartButtons() { + // Matching Candidates button + document.getElementById('matching-jd-candidates')?.addEventListener('click', function() { + togglePopup('matchingCandidates', this.dataset.popupTitle || 'Matching Candidates'); + }); + + // Applicants button + document.getElementById('jd-applicants')?.addEventListener('click', function() { + togglePopup('applicants', this.dataset.popupTitle || 'Applicants'); + }); + + // Close buttons (using event delegation) + document.addEventListener('click', function(e) { + if (e.target.classList.contains('popup-close')) { + const popup = e.target.closest('.popup-container'); + closePopup(popup.id.replace('Popup', '')); + } + }); +} + +function togglePopup(type, title) { + debugger; + const popupId = `${type}Popup`; + let popup = document.getElementById(popupId); + + if (!popup) { + // Create popup if it doesn't exist + popup = document.createElement('div'); + popup.id = popupId; + popup.className = 'popup-container bottom-right'; + popup.innerHTML = document.getElementById(`${type}_popup`).innerHTML; + document.body.appendChild(popup); + } + + if (popup.classList.contains('visible')) { + closePopup(type); + } else { + openPopup(type, title); + } +} + +function openPopup(type, title) { + debugger; + const popupId = `${type}Popup`; + const popup = document.getElementById(popupId); + + if (!popup) return; + + // Update title + const titleEl = popup.querySelector('h5'); + if (titleEl) titleEl.textContent = title; + + // Show loading state + const loadingEl = popup.querySelector('.loading-spinner'); + const contentEl = popup.querySelector('.popup-content'); + + if (loadingEl) { + loadingEl.style.display = 'flex'; + loadingEl.innerHTML = '
'; + } + if (contentEl) { + contentEl.style.display = 'none'; + contentEl.innerHTML = ''; + } + + // Show popup + popup.classList.add('visible'); + + // Add to open popups array if not already there + if (!openPopups.includes(popupId)) { + openPopups.push(popupId); + } + + // Position popups + positionPopups(); + debugger; + // Fetch data + const jobId = document.querySelector('.job-detail-container')?.dataset?.jobId; + if (!jobId) { + console.error('No job ID found'); + return; + } + + const endpoint = type === 'matchingCandidates' + ? `/myATS/job/matching_candidates/${jobId}` + : `/myATS/job/applicants/${jobId}`; + + fetch(endpoint, { + headers: { "X-Requested-With": "XMLHttpRequest" } + }) + .then(response => { + if (!response.ok) throw new Error('Network response was not ok'); + return response.text(); + }) + .then(html => { + if (loadingEl) loadingEl.style.display = 'none'; + if (contentEl) { + contentEl.innerHTML = html; + contentEl.style.display = 'block'; + initMatchingCandidates(); + } + }) + .catch(error => { + console.error('Error loading popup content:', error); + if (loadingEl) { + loadingEl.innerHTML = ` +
+ Failed to load data. Please try again. +
+ `; + } + }); +} + +function closePopup(type) { + const popupId = `${type}Popup`; + const popup = document.getElementById(popupId); + + if (popup) { + popup.classList.remove('visible'); + + // Remove from open popups array + const index = openPopups.indexOf(popupId); + if (index > -1) { + openPopups.splice(index, 1); + } + + // Reposition remaining popups + positionPopups(); + } +} + +function positionPopups() { + // Reset all popup positions first + document.querySelectorAll('.popup-container').forEach(popup => { + popup.style.right = ''; + popup.style.bottom = ''; + }); + + // Position each visible popup + openPopups.forEach((popupId, index) => { + const popup = document.getElementById(popupId); + if (popup) { + popup.style.right = `${20 + (index * 420)}px`; // 400px width + 20px gap + popup.style.bottom = '0'; + } + }); +} + +function initMatchingCandidates() { + // Handle candidate card clicks + document.addEventListener('click', function(e) { + const card = e.target.closest('.mc-card'); + if (card) { + debugger; + const candidateId = parseInt(card.dataset.id); + showCandidateDetails(card); + } + + // Close modal + if (e.target.classList.contains('mc-close-modal')) { + closeCandidateModal(); + } + }); + + // Close modal when clicking outside + window.addEventListener('click', function(e) { + const modal = document.getElementById('candidateDetailModal'); + if (e.target === modal) { + closeCandidateModal(); + } + }); +} + +function showCandidateDetails(card) { + const modalContent = document.getElementById('candidateDetailContent'); + + // Parse the applications data + let applications = []; + try { + applications = JSON.parse(card.dataset.applications.replace(/'/g, '"')); + } catch (e) { + console.error('Error parsing applications:', e); + } + + // Parse skills data + let primarySkills = []; + let secondarySkills = []; + try { + primarySkills = card.dataset.matchPrimarySkills ? + JSON.parse(card.dataset.matchPrimarySkills.replace(/'/g, '"')) : []; + secondarySkills = card.dataset.matchSecondarySkills ? + JSON.parse(card.dataset.matchSecondarySkills.replace(/'/g, '"')) : []; + } catch (e) { + console.error('Error parsing skills:', e); + } + + // Create the HTML structure + modalContent.innerHTML = ` +
+
+
+ ${card.dataset.image ? + `Candidate` : + `
+ ${card.dataset.candidate ? card.dataset.candidate.charAt(0).toUpperCase() : '?'} +
` + } +
+

+ ${card.dataset.candidate || 'Unnamed Candidate'} +

+
+ +
+

Contact Information

+
+ Email: + + ${card.dataset.email ? + `${card.dataset.email}` : + 'Not provided'} + +
+
+ Phone: + + ${card.dataset.phone ? + `${card.dataset.phone}` : + 'Not provided'} + +
+
+ Recruiter: + + ${card.dataset.manager || 'Unassigned'} + +
+
+ +
+

Skills Match

+
+
+
Primary Skills (${parseInt(card.dataset.primaryPercent) || 0}% Match)
+ ${primarySkills.length > 0 ? + `
    + ${primarySkills.map(skill => `
  • ${skill}
  • `).join('')} +
` : + '

No primary skills matched

'} +
+
+
Secondary Skills (${parseInt(card.dataset.secondaryPercent) || 0}% Match)
+ ${secondarySkills.length > 0 ? + `
    + ${secondarySkills.map(skill => `
  • ${skill}
  • `).join('')} +
` : + '

No secondary skills matched

'} +
+
+
+ +
+

Applications

+ ${applications.length > 0 ? + `
+ ${applications.map(app => ` +
+ ${app[0] || 'Untitled Application'} + ${app[1]} +
+ `).join('')} +
` : + '

No applications found

'} +
+
+ `; + + // Show modal + document.getElementById('candidateDetailModal').style.display = 'block'; +} + +function renderCandidateDetail(data) { + const detailContainer = document.getElementById('candidateDetailContent'); + // Here you would create the HTML structure based on your template + // and populate it with the data received from the server + detailContainer.innerHTML = ` +
+
+ +

${data.candidate.display_name || 'Unnamed Candidate'}

+
+ +
+ `; + // You would continue with all the other fields from your template +} + +function closeCandidateModal() { + document.getElementById('candidateDetailModal').style.display = 'none'; +} + +// +//// Add this function to initialize the popup functionality +//function initSmartButtons() { +// document.querySelectorAll('.smart-button').forEach(button => { +// console.log("event-exist"); +// button.addEventListener('click', function() { +// console.log("event-clicked"); +// const jobId = document.querySelector('.job-detail-container').getAttribute('data-job-id'); +// const popupType = this.dataset.popupType; +// const popupTitle = this.dataset.popupTitle; +// console.log(jobId); +// console.log(popupType); +// console.log(popupTitle); +// showSmartPopup(jobId, popupType, popupTitle); +// }); +// }); +//} +// +//function showSmartPopup(jobId, popupType, popupTitle) { +// // Create or get the canvas element +// debugger; +// let canvasId = popupType + 'Canvas'; +// let canvas = document.getElementById(canvasId); +// +// if (!canvas) { +// // Create the canvas from template if it doesn't exist +// const template = document.getElementById(popupType + '_popup'); +// if (template) { +// const clone = template.content.cloneNode(true); +// document.body.appendChild(clone); +// canvas = document.getElementById(canvasId); +// } +// } +// +// if (canvas) { +// // Initialize the offcanvas if not already initialized +// if (!canvas._offcanvas) { +// canvas._offcanvas = new bootstrap.Offcanvas(canvas); +// } +// +// // Show the offcanvas +// canvas._offcanvas.show(); +// +// // Load content +// loadPopupContent(jobId, popupType); +// } +//} +// +//function loadPopupContent(jobId, popupType) { +// console.log("loadPopupContent"); +// const canvas = document.getElementById(popupType + 'Canvas'); +// if (!canvas) return; +// +// const loadingSpinner = canvas.querySelector('.loading-spinner'); +// const contentArea = canvas.querySelector(`.${popupType.replace('_', '-')}-list`); +// +// // Show loading spinner +// if (loadingSpinner) loadingSpinner.style.display = 'block'; +// if (contentArea) contentArea.innerHTML = ''; +// +// // Determine the endpoint based on popup type +// let endpoint = ''; +// if (popupType === 'matchingCandidates') { +// endpoint = `/myATS/job/${jobId}/matching_candidates`; +// } else if (popupType === 'applicants') { +// endpoint = `/myATS/job/${jobId}/applicants`; +// } +// +// if (endpoint) { +// fetch(endpoint, { +// headers: { "X-Requested-With": "XMLHttpRequest" } +// }) +// .then(response => response.text()) +// .then(html => { +// if (contentArea) { +// contentArea.innerHTML = html; +// // Initialize any interactive elements in the popup if needed +// initPopupInteractiveElements(popupType); +// } +// }) +// .catch(error => { +// console.error(`Error loading ${popupType}:`, error); +// if (contentArea) { +// contentArea.innerHTML = ` +//
+// Failed to load ${popupType.replace('_', ' ')}. Please try again. +//
+// `; +// } +// }) +// .finally(() => { +// if (loadingSpinner) loadingSpinner.style.display = 'none'; +// }); +// } +//} +// +//function initPopupInteractiveElements(popupType) { +// // Initialize any interactive elements specific to each popup type +// if (popupType === 'matching_candidates') { +// // Add event listeners for matching candidates popup +// document.querySelectorAll('.match-candidate-action').forEach(button => { +// button.addEventListener('click', function() { +// const candidateId = this.dataset.candidateId; +// // Handle candidate action +// }); +// }); +// } else if (popupType === 'applicants') { +// // Add event listeners for applicants popup +// document.querySelectorAll('.applicant-action').forEach(button => { +// button.addEventListener('click', function() { +// const applicantId = this.dataset.applicantId; +// // Handle applicant action +// }); +// }); +// } +//} diff --git a/addons_extensions/hr_recruitment_web_app/static/src/js/jquery.js b/addons_extensions/hr_recruitment_web_app/static/src/js/jquery.js new file mode 100644 index 000000000..e24ae4561 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/static/src/js/jquery.js @@ -0,0 +1,10993 @@ +/*! + * jQuery JavaScript Library v3.6.3 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2022-12-20T21:28Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket trac-14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.3", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.9 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2022-12-19 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + + // `qSA` may not throw for unrecognized parts using forgiving parsing: + // https://drafts.csswg.org/selectors/#forgiving-selector + // like the `:has()` pseudo-class: + // https://drafts.csswg.org/selectors/#relational + // `CSS.supports` is still expected to return `false` then: + // https://drafts.csswg.org/css-conditional-4/#typedef-supports-selector-fn + // https://drafts.csswg.org/css-conditional-4/#dfn-support-selector + if ( support.cssSupportsSelector && + + // eslint-disable-next-line no-undef + !CSS.supports( "selector(:is(" + newSelector + "))" ) ) { + + // Support: IE 11+ + // Throw to get to the same code path as an error directly in qSA. + // Note: once we only support browser supporting + // `CSS.supports('selector(...)')`, we can most likely drop + // the `try-catch`. IE doesn't implement the API. + throw new Error(); + } + + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + // Support: Chrome 105+, Firefox 104+, Safari 15.4+ + // Make sure forgiving mode is not used in `CSS.supports( "selector(...)" )`. + // + // `:is()` uses a forgiving selector list as an argument and is widely + // implemented, so it's a good one to test against. + support.cssSupportsSelector = assert( function() { + /* eslint-disable no-undef */ + + return CSS.supports( "selector(*)" ) && + + // Support: Firefox 78-81 only + // In old Firefox, `:is()` didn't use forgiving parsing. In that case, + // fail this test as there's no selector to test against that. + // `CSS.supports` uses unforgiving parsing + document.querySelectorAll( ":is(:jqfake)" ) && + + // `*` is needed as Safari & newer Chrome implemented something in between + // for `:has()` - it throws in `qSA` if it only contains an unsupported + // argument but multiple ones, one of which is supported, are fine. + // We want to play safe in case `:is()` gets the same treatment. + !CSS.supports( "selector(:is(*,:jqfake))" ); + + /* eslint-enable */ + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + // el.querySelectorAll( "\\\f" ); + // rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + // el.querySelectorAll( "*,:x" ); + // rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + // matches.call( el, "[s!='']:x" ); + // rbuggyMatches.push( "!=", pseudos ); + } ); + } + + if ( !support.cssSupportsSelector ) { + + // Support: Chrome 105+, Safari 15.4+ + // `:has()` uses a forgiving selector list as an argument so our regular + // `try-catch` mechanism fails to catch `:has()` with arguments not supported + // natively like `:has(:contains("Foo"))`. Where supported & spec-compliant, + // we now use `CSS.supports("selector(:is(SELECTOR_TO_BE_TESTED))")`, but + // outside that we mark `:has` as buggy. + rbuggyQSA.push( ":has" ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + + // Support: IE <9 only + // IE doesn't have `contains` on `document` so we need to check for + // `documentElement` presence. + // We need to fall back to `a` when `documentElement` is missing + // as `ownerDocument` of elements within ` + diff --git a/addons_extensions/hr_recruitment_web_app/views/recruitment.xml b/addons_extensions/hr_recruitment_web_app/views/recruitment.xml new file mode 100644 index 000000000..d89d9f291 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/views/recruitment.xml @@ -0,0 +1,19 @@ + + + + My WebApp + ir.actions.act_url + /myATS + new + + + + + + + \ No newline at end of file diff --git a/addons_extensions/hr_recruitment_web_app/views/recruitmnet_doc_upload_wizard.xml b/addons_extensions/hr_recruitment_web_app/views/recruitmnet_doc_upload_wizard.xml new file mode 100644 index 000000000..55aca1669 --- /dev/null +++ b/addons_extensions/hr_recruitment_web_app/views/recruitmnet_doc_upload_wizard.xml @@ -0,0 +1,50 @@ + + + + recruitment.doc.upload.wizard.form + recruitment.doc.upload.wizard + +
+ + + + + + + + +