"]
+ }]
+}
diff --git a/job-notifier/notify.wav b/job-notifier/notify.wav
new file mode 100644
index 0000000..22d8da9
Binary files /dev/null and b/job-notifier/notify.wav differ
diff --git a/job-notifier/offscreen.html b/job-notifier/offscreen.html
new file mode 100644
index 0000000..720ac6b
--- /dev/null
+++ b/job-notifier/offscreen.html
@@ -0,0 +1,9 @@
+
+
+
+ Sound Player
+
+
+
+
+
diff --git a/job-notifier/offscreen.js b/job-notifier/offscreen.js
new file mode 100644
index 0000000..78308c1
--- /dev/null
+++ b/job-notifier/offscreen.js
@@ -0,0 +1,21 @@
+let audioContext;
+let audioBuffer;
+
+chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
+ if (message.action === 'playSound') {
+ playNotificationSound();
+ }
+});
+
+async function playNotificationSound() {
+ if (!audioContext) {
+ audioContext = new AudioContext();
+ const response = await fetch(chrome.runtime.getURL('notify.wav'));
+ const arrayBuffer = await response.arrayBuffer();
+ audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
+ }
+ const source = audioContext.createBufferSource();
+ source.buffer = audioBuffer;
+ source.connect(audioContext.destination);
+ source.start(0);
+}
diff --git a/job-notifier/popup.html b/job-notifier/popup.html
new file mode 100644
index 0000000..f3556b5
--- /dev/null
+++ b/job-notifier/popup.html
@@ -0,0 +1,104 @@
+
+
+
+ Andela Job Notifier
+
+
+
+Andela Job Notifier
+
+
+
+
+
+
+
+
+
+
diff --git a/job-notifier/popup.js b/job-notifier/popup.js
new file mode 100644
index 0000000..12fffbe
--- /dev/null
+++ b/job-notifier/popup.js
@@ -0,0 +1,76 @@
+// popup.js
+
+function sortJobsById(jobs) {
+ return jobs.slice().sort(function(a, b) {
+ return (parseInt(b.id, 10) || 0) - (parseInt(a.id, 10) || 0);
+ });
+}
+
+function updateUI(data) {
+ var lastAndelaJobs = data.lastAndelaJobs || [];
+ var lastAndelaUpdated = data.lastAndelaUpdated;
+ var totalAndelaMatching = data.totalAndelaMatching || 0;
+
+ document.getElementById('jobCount').textContent = totalAndelaMatching + ' jobs found';
+
+ var jobList = document.getElementById('jobList');
+ jobList.innerHTML = '';
+
+ if (lastAndelaJobs.length === 0) {
+ jobList.innerHTML = 'No jobs found yet. Click "Check Now" to scan for jobs.
';
+ } else {
+ var sortedJobs = sortJobsById(lastAndelaJobs);
+
+ sortedJobs.slice(0, 10).forEach(function(job) {
+ var jobElement = document.createElement('div');
+ jobElement.className = 'job-item';
+
+ var postedDate = job.posted_date || 'Recently posted';
+ var companyName = typeof job.company === 'object' ? (job.company && job.company.name || 'Company') : (job.company || 'Company');
+
+ jobElement.innerHTML =
+ '' + job.title + '
' +
+ '' + companyName + '
' +
+ '' + (job.location || 'Remote') + '
' +
+ '' + postedDate + '
';
+
+ jobElement.addEventListener('click', function() {
+ var url = job.url || ('https://app.andela.com/job-postings/' + job.id);
+ chrome.tabs.create({ url: url });
+ });
+
+ jobList.appendChild(jobElement);
+ });
+ }
+
+ var status = document.getElementById('status');
+ status.textContent = lastAndelaUpdated ?
+ 'Last checked: ' + new Date(lastAndelaUpdated).toLocaleString() :
+ 'Not checked yet';
+}
+
+document.addEventListener('DOMContentLoaded', function() {
+ document.getElementById('checkNow').addEventListener('click', function() {
+ console.log('Manual check triggered');
+ chrome.runtime.sendMessage({ action: 'checkNow' }, function(response) {
+ console.log('Check initiated');
+ });
+ });
+
+ document.getElementById('openSettings').addEventListener('click', function() {
+ chrome.tabs.create({ url: 'settings.html' });
+ });
+
+ chrome.storage.local.get(['lastAndelaJobs', 'lastAndelaUpdated', 'totalAndelaMatching'], function(result) {
+ updateUI(result);
+ });
+
+ chrome.storage.onChanged.addListener(function(changes, areaName) {
+ if (areaName === 'local' && (changes.lastAndelaJobs || changes.lastAndelaUpdated || changes.totalAndelaMatching)) {
+ console.log('Storage updated, refreshing UI...');
+ chrome.storage.local.get(['lastAndelaJobs', 'lastAndelaUpdated', 'totalAndelaMatching'], function(result) {
+ updateUI(result);
+ });
+ }
+ });
+});
diff --git a/job-notifier/settings.html b/job-notifier/settings.html
new file mode 100644
index 0000000..bca0101
--- /dev/null
+++ b/job-notifier/settings.html
@@ -0,0 +1,83 @@
+
+
+
+Andela Notifier - Settings
+
+
+
+Settings
+
+
+ Your credentials are stored locally in your browser and never sent anywhere except to your own Apps Script.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+← Back to Jobs
+
+
+
+
diff --git a/job-notifier/settings.js b/job-notifier/settings.js
new file mode 100644
index 0000000..d785112
--- /dev/null
+++ b/job-notifier/settings.js
@@ -0,0 +1,69 @@
+// settings.js - Handle secure configuration storage
+
+document.addEventListener('DOMContentLoaded', function () {
+ chrome.storage.local.get(
+ [
+ 'appsScriptUrl',
+ 'appsScriptKey',
+ 'loginEmail',
+ 'ntfyServer',
+ 'ntfyTopic',
+ 'ntfyToken',
+ ],
+ function (result) {
+ if (result.appsScriptUrl)
+ document.getElementById('appsScriptUrl').value = result.appsScriptUrl;
+ if (result.appsScriptKey)
+ document.getElementById('appsScriptKey').value = result.appsScriptKey;
+ if (result.loginEmail)
+ document.getElementById('loginEmail').value = result.loginEmail;
+ document.getElementById('ntfyServer').value =
+ result.ntfyServer || 'https://notify.tstitagency.com';
+ if (result.ntfyTopic)
+ document.getElementById('ntfyTopic').value = result.ntfyTopic;
+ if (result.ntfyToken)
+ document.getElementById('ntfyToken').value = result.ntfyToken;
+ },
+ );
+
+ document.getElementById('saveBtn').addEventListener('click', function () {
+ var appsScriptUrl = document.getElementById('appsScriptUrl').value.trim();
+ var appsScriptKey = document.getElementById('appsScriptKey').value.trim();
+ var loginEmail = document.getElementById('loginEmail').value.trim();
+ var ntfyServer = document.getElementById('ntfyServer').value.trim();
+ var ntfyTopic = document.getElementById('ntfyTopic').value.trim();
+ var ntfyToken = document.getElementById('ntfyToken').value.trim();
+
+ if (!appsScriptUrl)
+ return showStatus('Please enter Apps Script URL', 'error');
+ if (!appsScriptUrl.startsWith('https://script.google.com/'))
+ return showStatus('Invalid Apps Script URL', 'error');
+ if (!appsScriptKey) return showStatus('Please enter Secret Key', 'error');
+ if (!loginEmail || !loginEmail.includes('@'))
+ return showStatus('Please enter a valid email', 'error');
+
+ chrome.storage.local.set(
+ {
+ appsScriptUrl: appsScriptUrl,
+ appsScriptKey: appsScriptKey,
+ loginEmail: loginEmail,
+ ntfyServer: ntfyServer,
+ ntfyTopic: ntfyTopic,
+ ntfyToken: ntfyToken,
+ },
+ function () {
+ showStatus('Settings saved successfully!', 'success');
+ },
+ );
+ });
+});
+
+function showStatus(message, type) {
+ var statusEl = document.getElementById('status');
+ statusEl.textContent = message;
+ statusEl.className = 'status ' + type;
+ statusEl.style.display = 'block';
+ setTimeout(function () {
+ statusEl.style.display = 'none';
+ }, 3000);
+}