Add product scanning functionality to eBay extension
- Introduced a new scanProductsForAccount feature in the background script to handle product scanning requests. - Implemented a timeout mechanism for scan requests to enhance reliability. - Updated content scripts to parse product lists and extract relevant data from eBay storefronts. - Enhanced error handling and logging for better debugging and user feedback. - Added methods to extract items sold and shop names from eBay profiles.
This commit is contained in:
@@ -1,11 +1,54 @@
|
||||
{"location":"BackgroundRippleEffect.jsx:84","message":"Grid cell visibility check","data":{"cellsCount":216,"cellWidth":56,"cellHeight":56,"cellOpacity":"1","cellBackgroundColor":"rgba(255, 255, 255, 0.05)","cellBorderColor":"rgba(255, 255, 255, 0.4)","cellDisplay":"block","rows":8,"cols":27,"cellSize":56},"timestamp":1768696693322,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
|
||||
{"location":"BackgroundRippleEffect.jsx:25","message":"Container visibility check","data":{"containerWidth":1070,"containerHeight":853,"zIndex":"0","opacity":"1","display":"block","visibility":"visible","calculatedCols":27,"calculatedRows":8,"viewportSize":{"width":0,"height":0},"pageBackground":"rgba(0, 0, 0, 0)"},"timestamp":1768696693324,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"BackgroundRippleEffect.jsx:84","message":"Grid cell visibility check","data":{"cellsCount":216,"cellWidth":56,"cellHeight":56,"cellOpacity":"1","cellBackgroundColor":"rgba(255, 255, 255, 0.05)","cellBorderColor":"rgba(255, 255, 255, 0.4)","cellDisplay":"block","rows":8,"cols":27,"cellSize":56},"timestamp":1768696693330,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
|
||||
{"location":"BackgroundRippleEffect.jsx:25","message":"Container visibility check","data":{"containerWidth":1070,"containerHeight":853,"zIndex":"0","opacity":"1","display":"block","visibility":"visible","calculatedCols":27,"calculatedRows":8,"viewportSize":{"width":0,"height":0},"pageBackground":"rgba(0, 0, 0, 0)"},"timestamp":1768696693330,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"BackgroundRippleEffect.jsx:84","message":"Grid cell visibility check","data":{"cellsCount":396,"cellWidth":56,"cellHeight":56,"cellOpacity":"1","cellBackgroundColor":"rgba(255, 255, 255, 0.05)","cellBorderColor":"rgba(255, 255, 255, 0.4)","cellDisplay":"block","rows":18,"cols":22,"cellSize":56},"timestamp":1768696693374,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
|
||||
{"location":"BackgroundRippleEffect.jsx:25","message":"Container visibility check","data":{"containerWidth":1070,"containerHeight":853,"zIndex":"0","opacity":"1","display":"block","visibility":"visible","calculatedCols":22,"calculatedRows":18,"viewportSize":{"width":1070,"height":853},"pageBackground":"rgba(0, 0, 0, 0)"},"timestamp":1768696693376,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"ebayParserService.js:341","message":"parseEbayAccount entry","data":{"url":"https://www.ebay.de/str/apecollection?_trksid=p4429486.m3561.l161210"},"timestamp":1768696699523,"sessionId":"debug-session","runId":"run2","hypothesisId":"C"}
|
||||
{"location":"ebayParserService.js:346","message":"parseEbayAccount: isExtensionAvailable result","data":{"extAvailable":false,"willTryExtension":false},"timestamp":1768696699525,"sessionId":"debug-session","runId":"run2","hypothesisId":"C"}
|
||||
{"location":"ebayParserService.js:94","message":"isExtensionAvailable check","data":{"hasFlag":false,"result":false},"timestamp":1768696699524,"sessionId":"debug-session","runId":"run2","hypothesisId":"C"}
|
||||
{"location":"BackgroundRippleEffect.jsx:84","message":"Grid cell visibility check","data":{"cellsCount":408,"cellWidth":56,"cellHeight":56,"cellOpacity":"1","cellBackgroundColor":"rgba(255, 255, 255, 0.05)","cellBorderColor":"rgba(255, 255, 255, 0.4)","cellDisplay":"block","rows":17,"cols":24,"cellSize":56},"timestamp":1768696852148,"sessionId":"debug-session","runId":"run1","hypothesisId":"B"}
|
||||
{"location":"BackgroundRippleEffect.jsx:25","message":"Container visibility check","data":{"containerWidth":1203,"containerHeight":840,"zIndex":"0","opacity":"1","display":"block","visibility":"visible","calculatedCols":24,"calculatedRows":17,"viewportSize":{"width":1203,"height":840},"pageBackground":"rgba(0, 0, 0, 0)"},"timestamp":1768696852149,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"productsService.js:116","message":"scanProductsForAccount: market derived","data":{"accountId":"696ccb2400395714987c","market":"DE","account_platform_market":"DE","account_url":"https://www.ebay.de/sch/i.html?item=397047173300&rt=nc&_trksid=p4429486.m3561.l161211&_ssn=miceusi"},"timestamp":1768741151411,"sessionId":"debug-session","runId":"run1","hypothesisId":"C"}
|
||||
{"location":"productsService.js:127","message":"scanProductsForAccount: currency derived","data":{"market":"DE","currency":"EUR","productsCollectionId":"products","databaseId":"eship-db","platformWillBeSetTo":"eBay"},"timestamp":1768741151411,"sessionId":"debug-session","runId":"post-fix","hypothesisId":"E"}
|
||||
{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_1","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_1\",\"product_title\":\"Scanned Item 1\",\"product_price\":58.5,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-1\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151507,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"}
|
||||
{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_1","created":0},"timestamp":1768741151644,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_2","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_2\",\"product_title\":\"Scanned Item 2\",\"product_price\":64,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-2\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151644,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"}
|
||||
{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_2","created":1},"timestamp":1768741151700,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_3","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_3\",\"product_title\":\"Scanned Item 3\",\"product_price\":69.5,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-3\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151701,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"}
|
||||
{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_3","created":2},"timestamp":1768741151751,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_4","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_4\",\"product_title\":\"Scanned Item 4\",\"product_price\":75,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-4\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151752,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"}
|
||||
{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_4","created":3},"timestamp":1768741151800,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"productsService.js:190","message":"scanProductsForAccount: payload before createDocument","data":{"platformProductId":"stub_1243_5","product_platform":"ebay","product_platform_type":"string","product_platform_length":4,"product_platform_JSON":"\"ebay\"","fullPayload":"{\"product_account_id\":\"696ccb2400395714987c\",\"product_platform\":\"ebay\",\"product_platform_market\":\"DE\",\"product_currency\":\"EUR\",\"product_platform_product_id\":\"stub_1243_5\",\"product_title\":\"Scanned Item 5\",\"product_price\":80.5,\"product_url\":\"https://www.ebay.de/itm/fake-696ccb24-5\"}","payloadKeys":["product_account_id","product_platform","product_platform_market","product_currency","product_platform_product_id","product_title","product_price","product_url"]},"timestamp":1768741151800,"sessionId":"debug-session","runId":"run2","hypothesisId":"D"}
|
||||
{"location":"productsService.js:185","message":"scanProductsForAccount: createDocument success","data":{"platformProductId":"stub_1243_5","created":4},"timestamp":1768741151844,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/goldbloom25?_trksid=p4429486.m3561.l161211"},"timestamp":1768741538650,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741538651,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:158","message":"parseViaExtension: chrome.runtime.sendMessage error","data":{"error":"Could not establish connection. Receiving end does not exist.","extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741538659,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:299","message":"parseEbayAccount: extension error, using stub","data":{"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1768741538659,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:304","message":"parseEbayAccount: stub result","data":{"itemsSold":null},"timestamp":1768741538660,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"AccountsPage.jsx:193","message":"handleFormSubmit: parsedData before save","data":{"hasStats":true,"itemsSold":null,"accountSellsValue":null},"timestamp":1768741540654,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"accountsService.js:72","message":"createManagedAccount: payload before Appwrite","data":{"account_sells":null,"accountData_account_sells":null},"timestamp":1768741540655,"sessionId":"debug-session","runId":"run1","hypothesisId":"E"}
|
||||
{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/goldbloom25?_trksid=p4429486.m3561.l161211"},"timestamp":1768741552261,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741552262,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:158","message":"parseViaExtension: chrome.runtime.sendMessage error","data":{"error":"Could not establish connection. Receiving end does not exist.","extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741552269,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:299","message":"parseEbayAccount: extension error, using stub","data":{"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1768741552269,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:304","message":"parseEbayAccount: stub result","data":{"itemsSold":null},"timestamp":1768741552270,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_0000uuvjdi","account_shop_name":"eBay Seller vjdi","account_sells":null}},"timestamp":1768741552270,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696cdaa40028f011f5d0","payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_0000uuvjdi","account_shop_name":"eBay Seller vjdi"},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name"]},"timestamp":1768741552270,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696cdaa40028f011f5d0"},"timestamp":1768741552346,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/ihaveitmusic?_trksid=p4429486.m3561.l161211"},"timestamp":1768741553567,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741553568,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:158","message":"parseViaExtension: chrome.runtime.sendMessage error","data":{"error":"Could not establish connection. Receiving end does not exist.","extensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741553574,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:299","message":"parseEbayAccount: extension error, using stub","data":{"error":"Could not establish connection. Receiving end does not exist."},"timestamp":1768741553574,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:304","message":"parseEbayAccount: stub result","data":{"itemsSold":null},"timestamp":1768741553574,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_0000h1nxit","account_shop_name":"eBay Seller nxit","account_sells":null}},"timestamp":1768741553575,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696cbd07000703cf5437","payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_0000h1nxit","account_shop_name":"eBay Seller nxit"},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name"]},"timestamp":1768741553575,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696cbd07000703cf5437"},"timestamp":1768741553651,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/goldbloom25?_trksid=p4429486.m3561.l161211"},"timestamp":1768741571041,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741571042,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:160","message":"parseViaExtension: response data from extension","data":{"hasStats":true,"itemsSold":1588,"stats":{"positiveRate":7,"feedbackCount":0,"itemsForSale":588,"itemsSold":1588}},"timestamp":1768741573909,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"goldbloom25","account_shop_name":"goldbloom25","account_sells":1588}},"timestamp":1768741573909,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696cdaa40028f011f5d0","payload":{"account_platform_market":"DE","account_platform_account_id":"goldbloom25","account_shop_name":"goldbloom25","account_sells":1588},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells"]},"timestamp":1768741573909,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696cdaa40028f011f5d0"},"timestamp":1768741574001,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/sch/i.html?item=397047173300&rt=nc&_trksid=p4429486.m3561.l161211&_ssn=miceusi"},"timestamp":1768741581711,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741581712,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:299","message":"parseEbayAccount: extension error, using stub","data":{"error":"timeout"},"timestamp":1768741596751,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_00002jm9ly","account_shop_name":"eBay Seller m9ly","account_sells":null}},"timestamp":1768741596752,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696ccb2400395714987c","payload":{"account_platform_market":"DE","account_platform_account_id":"ebay_00002jm9ly","account_shop_name":"eBay Seller m9ly"},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name"]},"timestamp":1768741596752,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"ebayParserService.js:304","message":"parseEbayAccount: stub result","data":{"itemsSold":null},"timestamp":1768741596752,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696ccb2400395714987c"},"timestamp":1768741596841,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"ebayParserService.js:292","message":"parseEbayAccount: route decision","data":{"extAvailable":true,"url":"https://www.ebay.de/str/ihaveitmusic?_trksid=p4429486.m3561.l161211"},"timestamp":1768741610165,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:135","message":"getExtensionId: found via cache","data":{"cachedExtensionId":"ikldokdleojiinjklkhkkhfhpfafeaoc"},"timestamp":1768741610165,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"ebayParserService.js:160","message":"parseViaExtension: response data from extension","data":{"hasStats":true,"itemsSold":280535,"stats":{"positiveRate":5,"feedbackCount":0,"itemsForSale":535,"itemsSold":280535}},"timestamp":1768741616427,"sessionId":"debug-session","runId":"run1","hypothesisId":"D"}
|
||||
{"location":"accountsService.js:133","message":"updateManagedAccount: before updateDocument","data":{"accountId":"696cbd07000703cf5437","payload":{"account_platform_market":"DE","account_platform_account_id":"ihaveitmusic","account_shop_name":"iHaveit","account_sells":280535},"payloadKeys":["account_platform_market","account_platform_account_id","account_shop_name","account_sells"]},"timestamp":1768741616428,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"AccountsPage.jsx:93","message":"handleRefreshAccount: update payload","data":{"payload":{"account_platform_market":"DE","account_platform_account_id":"ihaveitmusic","account_shop_name":"iHaveit","account_sells":280535}},"timestamp":1768741616427,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
{"location":"accountsService.js:147","message":"updateManagedAccount: success","data":{"accountId":"696cbd07000703cf5437"},"timestamp":1768741616513,"sessionId":"debug-session","runId":"run1","hypothesisId":"A"}
|
||||
|
||||
@@ -2,7 +2,9 @@ const STORAGE_KEY = "auth_jwt";
|
||||
const BACKEND_URL = "http://localhost:5173"; // TODO: Backend URL konfigurieren
|
||||
|
||||
const PARSE_TIMEOUT_MS = 15000; // 15 seconds
|
||||
const SCAN_TIMEOUT_MS = 20000; // 20 seconds (seller listing pages can be slower)
|
||||
const activeParseRequests = new Map(); // Map<tabId, { timeout, originalSender, resolve }>
|
||||
const activeScanRequests = new Map(); // Map<tabId, { timeout, sendResponse }>
|
||||
|
||||
// Messages from content script (der von der Web-App kommt)
|
||||
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
@@ -57,6 +59,11 @@ chrome.runtime.onMessageExternal.addListener((msg, sender, sendResponse) => {
|
||||
handleParseRequest(msg.url, sendResponse);
|
||||
return true; // async
|
||||
}
|
||||
|
||||
if (msg?.action === "SCAN_PRODUCTS" && msg.url && msg.accountId) {
|
||||
handleScanProductsRequest(msg.url, msg.accountId, sendResponse);
|
||||
return true; // async
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -167,6 +174,114 @@ async function cleanupParseRequest(tabId, data, error) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles eBay product scan request
|
||||
* Creates a hidden tab, waits for load, sends parse message to content script
|
||||
*/
|
||||
async function handleScanProductsRequest(url, accountId, sendResponse) {
|
||||
try {
|
||||
// Validate URL
|
||||
if (!url || typeof url !== 'string' || !url.toLowerCase().includes('ebay.')) {
|
||||
sendResponse({ ok: false, error: "Invalid eBay URL" });
|
||||
return;
|
||||
}
|
||||
|
||||
// Create hidden tab
|
||||
const tab = await chrome.tabs.create({
|
||||
url: url,
|
||||
active: false
|
||||
});
|
||||
|
||||
const tabId = tab.id;
|
||||
|
||||
// Set up timeout
|
||||
const timeoutId = setTimeout(() => {
|
||||
cleanupScanRequest(tabId, null, { ok: false, error: "timeout" });
|
||||
}, SCAN_TIMEOUT_MS);
|
||||
|
||||
// Store request info
|
||||
activeScanRequests.set(tabId, {
|
||||
timeout: timeoutId,
|
||||
sendResponse: sendResponse
|
||||
});
|
||||
|
||||
// Wait for tab to load, then send parse message
|
||||
const checkTabLoaded = (updatedTabId, changeInfo, updatedTab) => {
|
||||
if (updatedTabId !== tabId) return;
|
||||
|
||||
// Tab is fully loaded
|
||||
if (changeInfo.status === 'complete' && updatedTab.url) {
|
||||
chrome.tabs.onUpdated.removeListener(checkTabLoaded);
|
||||
|
||||
// Small delay to ensure DOM is ready
|
||||
setTimeout(() => {
|
||||
// Send parse message to content script
|
||||
chrome.tabs.sendMessage(tabId, { action: "PARSE_PRODUCT_LIST" })
|
||||
.then(response => {
|
||||
if (response && response.ok && response.data) {
|
||||
handleScanComplete(tabId, response.data);
|
||||
} else {
|
||||
cleanupScanRequest(tabId, null, { ok: false, error: response?.error || "Parsing failed" });
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error("Error sending parse message:", err);
|
||||
cleanupScanRequest(tabId, null, { ok: false, error: "Content script error" });
|
||||
});
|
||||
}, 1000); // 1 second delay for DOM ready
|
||||
}
|
||||
};
|
||||
|
||||
chrome.tabs.onUpdated.addListener(checkTabLoaded);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error in handleScanProductsRequest:", error);
|
||||
sendResponse({ ok: false, error: error.message || "Unknown error" });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles scan complete response from content script
|
||||
*/
|
||||
function handleScanComplete(tabId, data) {
|
||||
cleanupScanRequest(tabId, data, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up scan request: closes tab, clears timeout, sends response
|
||||
*/
|
||||
async function cleanupScanRequest(tabId, data, error) {
|
||||
const request = activeScanRequests.get(tabId);
|
||||
if (!request) return;
|
||||
|
||||
// Clear timeout
|
||||
if (request.timeout) {
|
||||
clearTimeout(request.timeout);
|
||||
}
|
||||
|
||||
// Remove from active requests
|
||||
activeScanRequests.delete(tabId);
|
||||
|
||||
// Close tab (always, even on error)
|
||||
try {
|
||||
await chrome.tabs.remove(tabId);
|
||||
} catch (err) {
|
||||
// Tab might already be closed
|
||||
console.warn("Could not close tab:", err);
|
||||
}
|
||||
|
||||
// Send response
|
||||
if (request.sendResponse) {
|
||||
if (error) {
|
||||
request.sendResponse(error);
|
||||
} else if (data) {
|
||||
request.sendResponse({ ok: true, data: data });
|
||||
} else {
|
||||
request.sendResponse({ ok: false, error: "Unknown error" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function getJwt() {
|
||||
const data = await chrome.storage.local.get(STORAGE_KEY);
|
||||
|
||||
@@ -3,20 +3,62 @@
|
||||
|
||||
const MESSAGE_SOURCE = "eship-webapp";
|
||||
|
||||
// Markiere Extension als verfügbar
|
||||
// #region agent log
|
||||
try {
|
||||
console.log('[ESHIP-CONTENT] Content script loaded');
|
||||
if (typeof window !== 'undefined') {
|
||||
window.__EBAY_EXTENSION__ = true;
|
||||
console.log('[ESHIP-CONTENT] window.__EBAY_EXTENSION__ set to true');
|
||||
} else {
|
||||
console.error('[ESHIP-CONTENT] window is undefined!');
|
||||
// Markiere Extension als verfügbar - MEHRFACH versuchen, da Timing variieren kann
|
||||
function setExtensionFlag() {
|
||||
try {
|
||||
const hasChrome = typeof chrome !== 'undefined';
|
||||
const hasRuntime = hasChrome && chrome.runtime;
|
||||
const runtimeId = hasRuntime ? chrome.runtime.id : null;
|
||||
if (typeof window !== 'undefined' && hasChrome && hasRuntime && runtimeId) {
|
||||
window.__EBAY_EXTENSION__ = true;
|
||||
window.__EBAY_EXTENSION_ID__ = runtimeId; // Extension-ID für chrome.runtime.sendMessage
|
||||
console.log('[ESHIP-CONTENT] window.__EBAY_EXTENSION__ set to true, ID:', runtimeId);
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[ESHIP-CONTENT] Error setting flag:', e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[ESHIP-CONTENT] Error setting flag:', e);
|
||||
return false;
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// Versuche Flag sofort zu setzen
|
||||
console.log('[ESHIP-CONTENT] Content script loaded');
|
||||
if (!setExtensionFlag()) {
|
||||
// Wenn window nicht verfügbar, warte auf DOMContentLoaded oder document.readyState
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
setExtensionFlag();
|
||||
});
|
||||
} else {
|
||||
// DOM ist bereits geladen, versuche nochmal
|
||||
setTimeout(() => {
|
||||
setExtensionFlag();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Sende Extension-ID an Web-App via postMessage (da Content Script Isolation verhindert, dass window-Properties geteilt werden)
|
||||
// Die Web-App kann dann die Extension-ID in ihrem eigenen Context speichern
|
||||
function sendExtensionIdToWebApp() {
|
||||
try {
|
||||
const runtimeId = chrome.runtime?.id;
|
||||
if (runtimeId) {
|
||||
// Sende Extension-ID an Web-App
|
||||
window.postMessage({
|
||||
source: "eship-extension",
|
||||
type: "EXTENSION_ID",
|
||||
extensionId: runtimeId
|
||||
}, "*");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[ESHIP-CONTENT] Error sending extension ID:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Sende Extension-ID beim Laden
|
||||
sendExtensionIdToWebApp();
|
||||
// Auch nach kurzer Verzögerung nochmal (falls Web-App noch nicht bereit ist)
|
||||
setTimeout(sendExtensionIdToWebApp, 500);
|
||||
|
||||
window.addEventListener("message", (event) => {
|
||||
// Sicherheitscheck: Nur Nachrichten von derselben Origin akzeptieren
|
||||
|
||||
@@ -24,6 +24,21 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
}
|
||||
return true; // async response
|
||||
}
|
||||
|
||||
if (message.action === "PARSE_PRODUCT_LIST") {
|
||||
try {
|
||||
const items = parseProductList();
|
||||
sendResponse({ ok: true, data: { items } });
|
||||
} catch (error) {
|
||||
// Niemals unhandled throws - immer graceful response
|
||||
console.error("Error parsing product list:", error);
|
||||
sendResponse({
|
||||
ok: false,
|
||||
error: error.message || "Failed to parse product list"
|
||||
});
|
||||
}
|
||||
return true; // async response
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -143,7 +158,27 @@ function extractSellerId() {
|
||||
*/
|
||||
function extractShopName() {
|
||||
try {
|
||||
// Methode 1: Spezifische Selektoren versuchen
|
||||
// Methode 1: Shop-Name aus Storefront-Link extrahieren
|
||||
// Pattern: <a href="/str/storename" data-track="...">Shop Name</a>
|
||||
try {
|
||||
const storefrontLinks = document.querySelectorAll('a[href*="/str/"]');
|
||||
for (const link of storefrontLinks) {
|
||||
// Prüfe ob Link data-track Attribut hat (typisch für Storefront-Links)
|
||||
if (link.hasAttribute('data-track') || link.href.includes('/str/')) {
|
||||
const linkText = link.textContent?.trim();
|
||||
if (linkText && linkText.length > 0 && linkText.length < 200) {
|
||||
// Prüfe dass es nicht nur ein URL-Pfad ist
|
||||
if (!linkText.match(/^https?:\/\//) && !linkText.match(/^\/str\//)) {
|
||||
return linkText;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue to next method
|
||||
}
|
||||
|
||||
// Methode 2: Spezifische Selektoren versuchen
|
||||
const shopNameSelectors = [
|
||||
'h1.shop-name',
|
||||
'.store-name',
|
||||
@@ -169,7 +204,7 @@ function extractShopName() {
|
||||
}
|
||||
}
|
||||
|
||||
// Methode 2: document.title parsen
|
||||
// Methode 3: document.title parsen
|
||||
try {
|
||||
const title = document.title || "";
|
||||
// Versuche Muster wie "Shop Name | eBay" zu extrahieren
|
||||
@@ -185,7 +220,7 @@ function extractShopName() {
|
||||
// Continue
|
||||
}
|
||||
|
||||
// Methode 3: h1 Tag als Fallback
|
||||
// Methode 4: h1 Tag als Fallback
|
||||
try {
|
||||
const h1 = document.querySelector('h1');
|
||||
if (h1) {
|
||||
@@ -204,6 +239,71 @@ function extractShopName() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extrahiert "Artikel verkauft" aus Storefront-Profilen
|
||||
* @returns {number|null} Anzahl verkaufter Artikel oder null
|
||||
*/
|
||||
function extractItemsSold() {
|
||||
try {
|
||||
// Suche nach Container
|
||||
const container = document.querySelector(".str-seller-card__store-stats-content");
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Finde div children, die "Artikel verkauft" enthalten
|
||||
const divs = container.querySelectorAll("div");
|
||||
for (const div of divs) {
|
||||
const divText = div.textContent || "";
|
||||
if (divText.includes("Artikel verkauft")) {
|
||||
// Suche nach span mit Klasse str-text-span BOLD (Klasse kann als "str-text-span BOLD" sein)
|
||||
const span1 = div.querySelector("span.str-text-span.BOLD");
|
||||
const span2 = div.querySelector("span.BOLD");
|
||||
const span3 = div.querySelector('span[class*="BOLD"]');
|
||||
const span = span1 || span2 || span3;
|
||||
if (span) {
|
||||
let valueText = span.textContent?.trim() || "";
|
||||
|
||||
// Normalisierung: Entferne Leerzeichen
|
||||
valueText = valueText.replace(/\s/g, "");
|
||||
|
||||
// Ersetze Tausendertrenner (. und ,) durch leeren String
|
||||
valueText = valueText.replace(/[.,]/g, "");
|
||||
|
||||
// Nur Digits behalten
|
||||
valueText = valueText.replace(/\D/g, "");
|
||||
|
||||
// Parse zu Integer
|
||||
if (valueText.length > 0) {
|
||||
const parsedValue = parseInt(valueText, 10);
|
||||
if (!isNaN(parsedValue) && parsedValue >= 0) {
|
||||
return parsedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Regex auf div-Text, falls Struktur abweicht
|
||||
const regexMatch = divText.match(/([\d.,]+)\s*Artikel\s*verkauft/i);
|
||||
if (regexMatch && regexMatch[1]) {
|
||||
let valueText = regexMatch[1].trim();
|
||||
valueText = valueText.replace(/\s/g, "").replace(/[.,]/g, "").replace(/\D/g, "");
|
||||
if (valueText.length > 0) {
|
||||
const parsedValue = parseInt(valueText, 10);
|
||||
if (!isNaN(parsedValue) && parsedValue >= 0) {
|
||||
return parsedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
// Graceful fallback bei Fehlern
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extrahiert Stats aus DOM (Feedback Score, Positive Rate, etc.)
|
||||
* @returns {object} Stats Objekt
|
||||
@@ -320,6 +420,16 @@ function extractStats() {
|
||||
// Continue
|
||||
}
|
||||
|
||||
// Items Sold (Artikel verkauft)
|
||||
try {
|
||||
const itemsSold = extractItemsSold();
|
||||
if (itemsSold !== null) {
|
||||
stats.itemsSold = itemsSold;
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
// Return empty stats object
|
||||
}
|
||||
@@ -358,4 +468,266 @@ function parseEbayPage() {
|
||||
stats: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parst Produktliste von eBay Storefront oder Seller Listings
|
||||
* @returns {Array} Array von Produkt-Items
|
||||
*/
|
||||
function parseProductList() {
|
||||
try {
|
||||
const url = window.location.href;
|
||||
const urlLower = url.toLowerCase();
|
||||
|
||||
// Determine page type
|
||||
const isStorePage = urlLower.includes('/str/') || urlLower.includes('/store/');
|
||||
const isSellerPage = urlLower.includes('/usr/');
|
||||
|
||||
// Check if seller profile without items (try to find link to listings)
|
||||
if (isSellerPage && !isStorePage) {
|
||||
const itemsLink = document.querySelector('a[href*="/usr/"][href*="?items="]') ||
|
||||
document.querySelector('a[href*="schid=mksr"]') ||
|
||||
Array.from(document.querySelectorAll('a')).find(a => {
|
||||
const text = (a.textContent || '').toLowerCase();
|
||||
return text.includes('artikel') || text.includes('angebote') ||
|
||||
text.includes('items for sale') || text.includes('see all items');
|
||||
});
|
||||
|
||||
if (!itemsLink) {
|
||||
// Try to find item cards directly
|
||||
const hasItems = findItemLinks().length > 0;
|
||||
if (!hasItems) {
|
||||
throw new Error("no_items_page");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract items
|
||||
const items = findItemLinks();
|
||||
|
||||
if (items.length === 0) {
|
||||
throw new Error("no_items_found");
|
||||
}
|
||||
|
||||
// Parse each item
|
||||
const parsedItems = [];
|
||||
const seenIds = new Set();
|
||||
|
||||
for (const itemLink of items) {
|
||||
try {
|
||||
const item = parseItemFromLink(itemLink);
|
||||
|
||||
// Deduplicate by platformProductId
|
||||
if (item.platformProductId && !seenIds.has(item.platformProductId)) {
|
||||
seenIds.add(item.platformProductId);
|
||||
parsedItems.push(item);
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue with next item if one fails
|
||||
console.warn("Failed to parse item:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Return max 60 items (first page)
|
||||
return parsedItems.slice(0, 60);
|
||||
|
||||
} catch (error) {
|
||||
// Re-throw to be caught by message handler
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Findet Item-Links auf der Seite
|
||||
* @returns {Array} Array von Link-Elementen
|
||||
*/
|
||||
function findItemLinks() {
|
||||
const links = [];
|
||||
|
||||
try {
|
||||
// Multiple selector fallbacks for item cards
|
||||
const selectors = [
|
||||
'a[href*="/itm/"]', // Direct item links
|
||||
'.s-item a[href*="/itm/"]', // Search result items
|
||||
'.srp-results .s-item a', // Search results
|
||||
'.ebay-item-card a[href*="/itm/"]', // Item cards
|
||||
'[class*="item-card"] a[href*="/itm/"]', // Generic item cards
|
||||
];
|
||||
|
||||
for (const selector of selectors) {
|
||||
try {
|
||||
const found = document.querySelectorAll(selector);
|
||||
if (found.length > 0) {
|
||||
// Filter out duplicates by href
|
||||
const hrefs = new Set();
|
||||
for (const link of found) {
|
||||
const href = link.href || link.getAttribute('href');
|
||||
if (href && href.includes('/itm/') && !hrefs.has(href)) {
|
||||
hrefs.add(href);
|
||||
links.push(link);
|
||||
}
|
||||
}
|
||||
if (links.length > 0) break; // Found items, stop trying other selectors
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue to next selector
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Return empty array on error
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parst ein einzelnes Item aus einem Link-Element
|
||||
* @param {Element} itemLink - Link-Element zu einem eBay-Item
|
||||
* @returns {object} Parsed Item-Data
|
||||
*/
|
||||
function parseItemFromLink(itemLink) {
|
||||
const item = {
|
||||
platformProductId: null,
|
||||
title: "",
|
||||
price: null,
|
||||
currency: null,
|
||||
url: "",
|
||||
status: "active",
|
||||
category: null,
|
||||
condition: null
|
||||
};
|
||||
|
||||
try {
|
||||
// URL (absolute)
|
||||
const href = itemLink.href || itemLink.getAttribute('href');
|
||||
if (href) {
|
||||
item.url = href.startsWith('http') ? href : new URL(href, window.location.origin).href;
|
||||
|
||||
// Extract platformProductId from URL: /itm/<id> or ?item=<id>
|
||||
const itmMatch = item.url.match(/\/itm\/(\d+)/);
|
||||
if (itmMatch && itmMatch[1]) {
|
||||
item.platformProductId = itmMatch[1];
|
||||
} else {
|
||||
const itemParamMatch = item.url.match(/[?&]item=(\d+)/);
|
||||
if (itemParamMatch && itemParamMatch[1]) {
|
||||
item.platformProductId = itemParamMatch[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: data attributes if present
|
||||
if (!item.platformProductId) {
|
||||
const dataItemId = itemLink.getAttribute('data-item-id') ||
|
||||
itemLink.closest('[data-item-id]')?.getAttribute('data-item-id');
|
||||
if (dataItemId) {
|
||||
item.platformProductId = dataItemId;
|
||||
}
|
||||
}
|
||||
|
||||
// Title: from link text or title element
|
||||
try {
|
||||
const titleElement = itemLink.querySelector('.s-item__title') ||
|
||||
itemLink.querySelector('[class*="title"]') ||
|
||||
itemLink.closest('.s-item')?.querySelector('.s-item__title');
|
||||
|
||||
if (titleElement) {
|
||||
item.title = titleElement.textContent?.trim() || "";
|
||||
} else {
|
||||
// Fallback: link text itself
|
||||
item.title = itemLink.textContent?.trim() || "";
|
||||
}
|
||||
|
||||
// Normalize title (remove extra whitespace)
|
||||
item.title = item.title.replace(/\s+/g, ' ').trim();
|
||||
} catch (e) {
|
||||
// Continue without title
|
||||
}
|
||||
|
||||
// Price + Currency
|
||||
try {
|
||||
const itemCard = itemLink.closest('.s-item') || itemLink.closest('[class*="item-card"]');
|
||||
if (itemCard) {
|
||||
const priceElement = itemCard.querySelector('.s-item__price') ||
|
||||
itemCard.querySelector('[class*="price"]') ||
|
||||
itemCard.querySelector('.BOLD');
|
||||
|
||||
if (priceElement) {
|
||||
const priceText = priceElement.textContent?.trim() || "";
|
||||
const parsed = parsePrice(priceText);
|
||||
item.price = parsed.price;
|
||||
item.currency = parsed.currency;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue without price
|
||||
}
|
||||
|
||||
// Category (optional)
|
||||
try {
|
||||
const categoryElement = itemLink.closest('.s-item')?.querySelector('[class*="category"]');
|
||||
if (categoryElement) {
|
||||
item.category = categoryElement.textContent?.trim() || null;
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue without category
|
||||
}
|
||||
|
||||
// Condition (optional)
|
||||
try {
|
||||
const conditionElement = itemLink.closest('.s-item')?.querySelector('[class*="condition"]');
|
||||
if (conditionElement) {
|
||||
item.condition = conditionElement.textContent?.trim() || null;
|
||||
}
|
||||
} catch (e) {
|
||||
// Continue without condition
|
||||
}
|
||||
|
||||
// Status: default "active" (storefront shows active listings)
|
||||
// Could check for "ended" indicators, but MVP keeps it simple
|
||||
item.status = "active";
|
||||
|
||||
} catch (e) {
|
||||
// Continue with partial data
|
||||
console.warn("Error parsing item:", e);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parst Preis-String in Zahl und Währung
|
||||
* @param {string} priceText - Preis-String z.B. "EUR 12,99" oder "$15.50"
|
||||
* @returns {object} { price: number|null, currency: string|null }
|
||||
*/
|
||||
function parsePrice(priceText) {
|
||||
const result = { price: null, currency: null };
|
||||
|
||||
try {
|
||||
if (!priceText) return result;
|
||||
|
||||
// Extract currency symbols/codes
|
||||
const currencyMatch = priceText.match(/(EUR|USD|GBP|€|\$|£)/i);
|
||||
if (currencyMatch) {
|
||||
const currencyCode = currencyMatch[1].toUpperCase();
|
||||
if (currencyCode === '€') result.currency = 'EUR';
|
||||
else if (currencyCode === '$') result.currency = 'USD';
|
||||
else if (currencyCode === '£') result.currency = 'GBP';
|
||||
else result.currency = currencyCode;
|
||||
}
|
||||
|
||||
// Extract numeric value (handle both comma and dot as decimal separator)
|
||||
const normalized = priceText
|
||||
.replace(/[^\d,.-]/g, '') // Remove non-numeric except , . -
|
||||
.replace(/\./g, '') // Remove thousand separators (assume dot)
|
||||
.replace(',', '.'); // Replace comma with dot for decimal
|
||||
|
||||
const price = parseFloat(normalized);
|
||||
if (!isNaN(price) && price >= 0) {
|
||||
result.price = price;
|
||||
}
|
||||
} catch (e) {
|
||||
// Return null values on error
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user