Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 79 additions & 37 deletions joPilot_extension/background.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// background.js – Handles API communication and other background tasks for the Chrome extension

import api from '../api/api-service'; // Import the API instance
//import api from '../api/api-service'; // Import the API instance

//Utility function to log messages
const log = (message, data = null) => {
console.log(`[Background.js] ${message}`, data);
console.log(`[Background.js] ${message}`, data !== null ? data : '');
};

//Listen for messages from other parts of the extension
Expand All @@ -13,41 +11,99 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {

switch (message.type)
{
case 'testApiConnection':
handleTestApiConnection(sendResponse);
return true; //Keep the message channel open for async response
// case 'testApiConnection':
// handleTestApiConnection(sendResponse);
// return true; //Keep the message channel open for async response

case 'getUserData':
handleGetUserData(message.payload, sendResponse);
return true;
// case 'getUserData':
// handleGetUserData(message.payload, sendResponse);
// return true;

case 'saveToStorage':
handleSaveToStorage(message.payload, sendResponse);
return true;
return true; // Keep channel open for async response

case 'fetchFromStorage':
handleFetchFromStorage(message.payload, sendResponse);
return true;
return true; // Keep channel open for async response

case 'triggerAutofill': // <<< ADD THIS CASE
handleTriggerAutofill(sendResponse);
return true; // Keep channel open for async response

default:
log('Unknown message type', message.type);
sendResponse({ success: false, error: 'Unknown message type' });
return false;
return false; // No async response needed
}
});

//Handle API connection test
const handleTestApiConnection = (sendResponse) => {
log('Testing API connection...');
api.get('/test')
.then(response => {
log('API Response', response.data);
sendResponse({ success: true, data: response.data });
})
.catch(error => {
log('API Error', error);
sendResponse({ success: false, error: error.message });
const handleFetchFromStorage = (keys, sendResponse) => {
log('Fetching data from storage', keys);
const validKeys = Array.isArray(keys) || typeof keys === 'object' || keys === null ? keys : null;
chrome.storage.local.get(validKeys, (result) => {
if (chrome.runtime.lastError) {
log('Error fetching from storage', chrome.runtime.lastError);
sendResponse({ success: false, error: chrome.runtime.lastError.message });
} else {
log('Data fetched from storage successfully', result);
sendResponse({ success: true, data: result });
}
});
};

// Handle the autofill trigger from the popup
const handleTriggerAutofill = (sendResponse) => {
log('Autofill triggered. Fetching data...');
chrome.storage.local.get(null, (autofillData) => {
if (chrome.runtime.lastError) {
log('Error fetching autofill data from storage', chrome.runtime.lastError);
sendResponse({ success: false, error: `Storage fetch error: ${chrome.runtime.lastError.message}` });
return;
}

if (Object.keys(autofillData).length === 0) {
log('No autofill data found in storage.');
sendResponse({ success: false, error: 'No autofill data found.' });
return;
}

log('Autofill data fetched', autofillData);

// Get the active tab
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs.length === 0 || !tabs[0].id) { // Check if tab exists and has an ID
log("No active tab found or tab has no ID.");
sendResponse({ success: false, error: "No active tab found." });
return;
}
const activeTabId = tabs[0].id;
const messageToSend = { type: 'fillForm', data: autofillData };

// --- ADD THESE LOGS ---
console.log(`<<< BACKGROUND: Attempting to send message to Tab ID: ${activeTabId} >>>`);
console.log("<<< BACKGROUND: Message Content: >>>", messageToSend);
// --- END OF ADDED LOGS ---

chrome.tabs.sendMessage(
activeTabId,
messageToSend,
(response) => {
if (chrome.runtime.lastError) {
console.error('<<< BACKGROUND: Error sending message to content script: >>>', chrome.runtime.lastError.message);
sendResponse({ success: false, error: `Could not communicate with content script: ${chrome.runtime.lastError.message}. Is the content script active on this page?` });
} else if (response && response.success) {
log('<<< BACKGROUND: Content script responded with success. >>>', response);
sendResponse({ success: true });
} else {
log('<<< BACKGROUND: Content script responded with failure or no response. >>>', response);
sendResponse({ success: false, error: response?.error || 'Content script failed or did not respond.' });
}
}
);
});
});
};

//Handle fetching user data from the API
Expand Down Expand Up @@ -76,18 +132,4 @@ const handleSaveToStorage = (payload, sendResponse) => {
sendResponse({ success: true });
}
});
};

//Handle fetching data from Chrome storage
const handleFetchFromStorage = (keys, sendResponse) => {
log('Fetching data from storage', keys);
chrome.storage.local.get(keys, (result) => {
if (chrome.runtime.lastError) {
log('Error fetching from storage', chrome.runtime.lastError);
sendResponse({ success: false, error: chrome.runtime.lastError.message });
} else {
log('Data fetched from storage successfully', result);
sendResponse({ success: true, data: result });
}
});
};
44 changes: 26 additions & 18 deletions joPilot_extension/manifest.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
{
"manifest_version": 2,
"name": "JoPilot",
"version": "1.0",
"description": "Companion for Job Applications",
"icons": {
"16": "public/favicon.png"
},
"browser_action": {
"default_popup": "popup/popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"storage",
"activeTab"
]
"manifest_version": 2,
"name": "JoPilot",
"version": "1.0",
"description": "Companion for Job Applications",
"icons": {
"16": "public/favicon.png"
},
"browser_action": {
"default_popup": "popup/popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"storage",
"activeTab"
],

"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["public/contentScript.js"],
"run_at": "document_idle"
}
]
}
93 changes: 74 additions & 19 deletions joPilot_extension/popup/popup.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,87 @@
// popup.js – Handles button interactions and communicates with background.js
//primarily used for scripts for popup.html which is the body of the extension


// Utility function to display output in the popup
const displayOutput = (message) => {
const outputDiv = document.getElementById('output');
outputDiv.textContent = message;

if (outputDiv) {
outputDiv.textContent = message;
} else {
console.error("Output div not found in popup.html");
}
};

// Add event listener for sync button
document.getElementById('syncButton').addEventListener('click', () => {
chrome.runtime.sendMessage({ type: 'syncData' }, (response) => {
if (response.success) {
displayOutput(`Data synced: ${JSON.stringify(response.data)}`);
} else {
displayOutput(`Error: ${response.error}`);
}
const syncButton = document.getElementById('syncButton');
if (syncButton) {
syncButton.addEventListener('click', () => {
chrome.runtime.sendMessage({ type: 'syncData' }, (response) => {
if (chrome.runtime.lastError) {
displayOutput(`Error: ${chrome.runtime.lastError.message}`);
return;
}
if (response) {
if (response.success) {
displayOutput(`Data synced: ${JSON.stringify(response.data || {})}`);
} else {
displayOutput(`Error: ${response.error || 'Unknown error during sync'}`);
}
} else {
displayOutput('No response received from background script during sync.');
}
});
});
});
} else {
console.error("Sync button not found in popup.html");
}

// Add event listener for autofill data
document.getElementById('autofillButton').addEventListener('click', () => {
chrome.runtime.sendMessage({ type: 'autofilledData' }, (response) => {
if (response.success) {
displayOutput('Information filled successfully!');
} else {
displayOutput(`Error: ${response.error}`);
}
const autofillButton = document.getElementById('autofillButton');
if (autofillButton) {
autofillButton.addEventListener('click', () => {

console.log("<<< POPUP: Autofill button clicked! Attempting to send 'triggerAutofill' message... >>>");

chrome.runtime.sendMessage({ type: 'triggerAutofill' }, (response) => {

if (chrome.runtime.lastError) {
console.error("<<< POPUP: Error received after sending message: >>>", chrome.runtime.lastError.message);
displayOutput(`Error: ${chrome.runtime.lastError.message}`);
return;
}
if (response) {
console.log("<<< POPUP: Response received from background: >>>", response);
if (response.success) {
displayOutput('Autofill requested successfully!');
} else {
displayOutput(`Error: ${response.error || 'Unknown error during autofill trigger'}`);
}
} else {
console.log("<<< POPUP: No response received from background script. >>>");
displayOutput('No response received from background script for autofill trigger.');
}
});


});
});
} else {
console.error("Autofill button not found in popup.html");
}

// Create an output div if it doesn't exist, for debugging purposes
if (!document.getElementById('output')) {
const outputDiv = document.createElement('div');
outputDiv.id = 'output';
outputDiv.style.marginTop = '10px';
outputDiv.style.padding = '5px';
outputDiv.style.border = '1px solid #ccc';
outputDiv.style.minHeight = '20px';
outputDiv.style.wordWrap = 'break-word';

const buttonContainer = document.getElementById('buttonContainer');
if (buttonContainer) {
buttonContainer.parentNode.insertBefore(outputDiv, buttonContainer.nextSibling);
} else {
document.body.appendChild(outputDiv); // Fallback append
}
}
Loading