// content.js - Handles job extraction and login automation 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; console.log( '[Andela Content Script] Login check - hasForm:', hasLoginForm, 'isLoginUrl:', isLoginUrl, ); return hasLoginForm || (isLoginUrl && !!emailInput); } function enterEmailAndClickLogin(email) { try { console.log('[Andela Content Script] Attempting to enter email:', email); var emailInput = document.querySelector('input[type="email"]#email'); if (!emailInput) { console.log('[Andela Content Script] Email input not found'); 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 })); console.log( '[Andela Content Script] Email entered, looking for submit button...', ); 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 btnText = buttons[i].textContent.toLowerCase(); if ( btnText.indexOf('login') !== -1 || btnText.indexOf('sign in') !== -1 || btnText.indexOf('continue') !== -1 || btnText.indexOf('submit') !== -1 ) { submitButton = buttons[i]; break; } } } if (submitButton) { console.log( '[Andela Content Script] Clicking submit button:', submitButton.textContent, ); submitButton.click(); } else { console.log( '[Andela Content Script] Submit button not found, trying form submit', ); 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 || ''); } // Walks the page in DOM order and tags every "See more" button and every // job-posting link with the heading text of the section it falls under. function getPageSections() { var elements = document.querySelectorAll( 'h3, button, a[href*="/job-postings/"]', ); var currentHeading = ''; var seeMoreButtons = []; // { button, heading } var jobLinks = []; // { link, heading } 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 }; } // Only expands "See more" under opportunity sections — leaves the // applied-jobs section collapsed as-is. 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) { console.log( '[Andela Content Script] Done expanding opportunity "See more" buttons after', rounds - 1, 'click(s)', ); resolve(); return; } console.log('[Andela Content Script] Clicking:', btn.textContent.trim()); 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() { console.log('[Andela Content Script] Extracting jobs...'); var jobs = []; var seen = {}; var jobLinks = getPageSections().jobLinks; console.log( '[Andela Content Script] Found ' + jobLinks.length + ' job-posting links', ); 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); console.log( '[Andela Content Script] Extracted job:', job.title, '(' + job.id + ')', '-', job.kind, ); } } catch (err) { console.error( '[Andela Content Script] Error extracting a job card:', err, ); } }); console.log( '[Andela Content Script] Extracted ' + jobs.length + ' jobs total', ); return jobs; } chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { console.log('[Andela Content Script] Received message:', request); if (request.action === 'extractJobs') { expandAllSeeMoreButtons().then(function () { setTimeout(function () { try { var jobs = extractJobsFromPage(); sendResponse({ jobs: jobs }); } catch (error) { console.error('[Andela Content Script] Error:', error); sendResponse({ jobs: [] }); } }, 500); }); return true; } if (request.action === 'checkLoginPage') { var result = isLoginPage(); console.log('[Andela Content Script] Is login page:', result); sendResponse({ isLoginPage: result }); } if (request.action === 'enterEmailAndLogin') { var success = enterEmailAndClickLogin(request.email); sendResponse({ success: success }); } if (request.action === 'extractPostedDate') { var el = document.querySelector('span.text-success-500'); var postedText = el ? el.textContent.trim() : ''; console.log( '[Andela Content Script] Extracted posted date text:', postedText, ); sendResponse({ postedDate: postedText }); } return true; });