// content.js - Handles job extraction, login automation, and profile // title switching for app.andela.com console.log('[Andela Content Script] Loaded on', window.location.href); function isLoginPage() { var emailInput = document.querySelector('input[type="email"]#email'); var emailLabel = document.querySelector('label[for="email"]'); var hasLoginForm = !!(emailInput && emailLabel); var isLoginUrl = window.location.pathname.indexOf('/login') === 0; return hasLoginForm || (isLoginUrl && !!emailInput); } function enterEmailAndClickLogin(email) { try { var emailInput = document.querySelector('input[type="email"]#email'); if (!emailInput) return false; emailInput.focus(); emailInput.value = email; emailInput.dispatchEvent(new Event('input', { bubbles: true })); emailInput.dispatchEvent(new Event('change', { bubbles: true })); emailInput.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true })); setTimeout(function () { var submitButton = document.querySelector('button[type="submit"]'); if (!submitButton) { var buttons = document.querySelectorAll('button'); for (var i = 0; i < buttons.length; i++) { var t = buttons[i].textContent.toLowerCase(); if ( t.indexOf('login') !== -1 || t.indexOf('sign in') !== -1 || t.indexOf('continue') !== -1 || t.indexOf('submit') !== -1 ) { submitButton = buttons[i]; break; } } } if (submitButton) { submitButton.click(); } else { var form = emailInput.closest('form'); if (form) { if (form.requestSubmit) form.requestSubmit(); else form.submit(); } } }, 500); return true; } catch (err) { console.error('[Andela Content Script] Error entering email:', err); return false; } } // A section counts as "opportunities" if its heading contains this word — // matches "Open Full-Stack Engineer opportunities", "Open AI Engineer // opportunities", etc. Anything else (e.g. "Your applications") is // treated as already-applied. function isOpportunitySection(headingText) { return /opportunit/i.test(headingText || ''); } function getPageSections() { var elements = document.querySelectorAll( 'h3, button, a[href*="/job-postings/"]', ); var currentHeading = ''; var seeMoreButtons = []; var jobLinks = []; elements.forEach(function (el) { if (el.tagName === 'H3') { currentHeading = el.textContent.trim(); console.log( '[Andela Content Script] Section heading found:', currentHeading, ); return; } if (el.tagName === 'BUTTON') { var text = (el.textContent || '').trim().toLowerCase(); if (text.indexOf('see') === 0 && text.indexOf('more') !== -1) { seeMoreButtons.push({ button: el, heading: currentHeading }); } return; } if (el.tagName === 'A') { jobLinks.push({ link: el, heading: currentHeading }); } }); return { seeMoreButtons: seeMoreButtons, jobLinks: jobLinks }; } function expandAllSeeMoreButtons(maxRounds) { maxRounds = maxRounds || 25; return new Promise(function (resolve) { var rounds = 0; function findSeeMoreButton() { var sections = getPageSections(); for (var i = 0; i < sections.seeMoreButtons.length; i++) { var entry = sections.seeMoreButtons[i]; if (isOpportunitySection(entry.heading)) return entry.button; } return null; } function clickNext() { rounds++; var btn = findSeeMoreButton(); if (!btn || rounds > maxRounds) { resolve(); return; } btn.click(); setTimeout(clickNext, 700); } clickNext(); }); } function extractJobFromLink(link) { var href = link.getAttribute('href') || ''; var idMatch = href.match(/\/job-postings\/(\d+)/); var id = idMatch ? idMatch[1] : href; var card = link.closest('div.rounded-lg.border.border-neutral-200.bg-white') || link.parentElement; var title = ''; var company = ''; var titleEl = card ? card.querySelector('.text-primary-900.font-semibold') : null; if (titleEl) { var clone = titleEl.cloneNode(true); var companySpan = clone.querySelector('span.font-normal'); if (companySpan) { company = companySpan.textContent.replace(/^[\s—-]+/, '').trim(); companySpan.remove(); } title = clone.textContent.trim(); } var paragraphs = card ? card.querySelectorAll('p') : []; var startInfo = paragraphs[0] ? paragraphs[0].textContent.trim() : ''; var locationInfo = paragraphs[1] ? paragraphs[1].textContent.trim() : ''; var skillEls = card ? card.querySelectorAll('.flex.flex-wrap.gap-2 span') : []; var skills = Array.prototype.map.call(skillEls, function (s) { return s.textContent.trim(); }); var url = href; if (url && url.indexOf('http') !== 0) url = window.location.origin + url; return { id: id, title: title, company: company || 'Company', posted_date: startInfo || '', location: locationInfo || '', skills: skills, url: url, }; } function extractJobsFromPage() { var jobs = []; var seen = {}; var jobLinks = getPageSections().jobLinks; jobLinks.forEach(function (entry) { try { var job = extractJobFromLink(entry.link); if (!job.id || seen[job.id]) return; seen[job.id] = true; job.section = entry.heading; job.kind = isOpportunitySection(entry.heading) ? 'opportunity' : 'applied'; if (job.title) jobs.push(job); } catch (err) { console.error( '[Andela Content Script] Error extracting a job card:', err, ); } }); return jobs; } // ============================================ // Profile title switching (used to surface jobs for other roles) // ============================================ function getCurrentProfileTitle() { var el = document.querySelector('.text-primary-600.mt-0\\.5.text-sm'); return el ? el.textContent.trim() : ''; } function waitFor(conditionFn, timeoutMs, intervalMs) { timeoutMs = timeoutMs || 5000; intervalMs = intervalMs || 200; return new Promise(function (resolve) { var elapsed = 0; function check() { var result = conditionFn(); if (result) { resolve(result); return; } elapsed += intervalMs; if (elapsed >= timeoutMs) { resolve(null); return; } setTimeout(check, intervalMs); } check(); }); } // Plain .click() doesn't reliably open this dropdown when dispatched // programmatically — needs the full pointer-event sequence instead. function dispatchFullClick(el) { el.focus(); ['pointerdown', 'mousedown', 'pointerup', 'mouseup', 'click'].forEach( function (type) { el.dispatchEvent( new MouseEvent(type, { bubbles: true, cancelable: true, view: window }), ); }, ); } async function setProfessionalTitle(title) { console.log( '[Andela Content Script] setProfessionalTitle: looking for edit button...', ); var editBtn = await waitFor(function () { return document.querySelector('button[aria-label="Edit profile details"]'); }, 6000); if (!editBtn) { console.log('[Andela Content Script] STEP FAILED: edit button not found'); return false; } console.log( '[Andela Content Script] STEP OK: edit button found, clicking...', ); editBtn.click(); console.log( '[Andela Content Script] looking for professional_title input...', ); var titleInput = await waitFor(function () { return document.querySelector('#professional_title'); }, 5000); if (!titleInput) { console.log( '[Andela Content Script] STEP FAILED: professional_title input not found (modal may not have opened)', ); return false; } console.log( '[Andela Content Script] STEP OK: input found, opening dropdown...', ); dispatchFullClick(titleInput); console.log('[Andela Content Script] looking for option matching:', title); var optionEl = await waitFor( function () { var options = document.querySelectorAll('[role="option"]'); for (var i = 0; i < options.length; i++) { var span = options[i].querySelector('span.col-start-2') || options[i]; if ( span && span.textContent.trim().toLowerCase() === title.toLowerCase() ) { return options[i]; } } return null; }, 5000, 400, ); if (!optionEl) { console.log( '[Andela Content Script] STEP FAILED: no option matched "' + title + '"', ); return false; } console.log('[Andela Content Script] STEP OK: option found, clicking...'); optionEl.click(); await new Promise(function (r) { setTimeout(r, 400); }); console.log('[Andela Content Script] looking for save button...'); var saveBtn = document.querySelector( 'button[type="submit"][form="edit-profile-details-form"]', ); if (!saveBtn) { console.log('[Andela Content Script] STEP FAILED: save button not found'); return false; } console.log( '[Andela Content Script] STEP OK: save button found, clicking...', ); saveBtn.click(); console.log('[Andela Content Script] waiting for modal to close...'); var closed = await waitFor(function () { return !document.querySelector('#professional_title'); }, 15000); console.log( '[Andela Content Script] setProfessionalTitle(' + title + ') closed modal:', !!closed, ); return !!closed; } chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { if (request.action === 'extractJobs') { expandAllSeeMoreButtons().then(function () { setTimeout(function () { try { sendResponse({ jobs: extractJobsFromPage() }); } catch (error) { console.error('[Andela Content Script] Error:', error); sendResponse({ jobs: [] }); } }, 500); }); return true; } if (request.action === 'checkLoginPage') { sendResponse({ isLoginPage: isLoginPage() }); return true; } if (request.action === 'enterEmailAndLogin') { sendResponse({ success: enterEmailAndClickLogin(request.email) }); return true; } if (request.action === 'extractPostedDate') { var el = document.querySelector('span.text-success-500'); sendResponse({ postedDate: el ? el.textContent.trim() : '' }); return true; } if (request.action === 'getCurrentProfileTitle') { sendResponse({ title: getCurrentProfileTitle() }); return true; } if (request.action === 'setProfessionalTitle') { setProfessionalTitle(request.title).then(function (success) { sendResponse({ success: success }); }); return true; } return true; });