mirror of
https://github.com/clucraft/PriceGhost.git
synced 2026-04-25 00:36:32 +02:00
fix: Always show price selection modal and use browser for JS-heavy sites
- Always show price selection modal when adding a product so users can verify - Use browser rendering for known JS-heavy sites (Best Buy, Target, Walmart, Costco) - Update modal text to say "Confirm Price" for single candidates Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4fd04cd160
commit
cf23ac9db1
4 changed files with 67 additions and 31 deletions
|
|
@ -89,24 +89,40 @@ router.post('/', async (req: AuthRequest, res: Response) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// If needsReview is true and there are multiple candidates, return them for user selection
|
||||
if (scrapedData.needsReview && scrapedData.priceCandidates.length > 1) {
|
||||
res.status(200).json({
|
||||
needsReview: true,
|
||||
name: scrapedData.name,
|
||||
imageUrl: scrapedData.imageUrl,
|
||||
stockStatus: scrapedData.stockStatus,
|
||||
priceCandidates: scrapedData.priceCandidates.map(c => ({
|
||||
price: c.price,
|
||||
currency: c.currency,
|
||||
method: c.method,
|
||||
context: c.context,
|
||||
confidence: c.confidence,
|
||||
})),
|
||||
suggestedPrice: scrapedData.price,
|
||||
url,
|
||||
});
|
||||
return;
|
||||
// Always show price selection modal when adding a product so user can verify
|
||||
// Show if we have at least one candidate with a price
|
||||
if (scrapedData.priceCandidates.length > 0 || scrapedData.price) {
|
||||
// Make sure we have at least one candidate to show
|
||||
const candidates = scrapedData.priceCandidates.length > 0
|
||||
? scrapedData.priceCandidates
|
||||
: scrapedData.price
|
||||
? [{
|
||||
price: scrapedData.price.price,
|
||||
currency: scrapedData.price.currency,
|
||||
method: scrapedData.selectedMethod || 'ai' as const,
|
||||
context: 'Extracted price',
|
||||
confidence: 0.8
|
||||
}]
|
||||
: [];
|
||||
|
||||
if (candidates.length > 0) {
|
||||
res.status(200).json({
|
||||
needsReview: true,
|
||||
name: scrapedData.name,
|
||||
imageUrl: scrapedData.imageUrl,
|
||||
stockStatus: scrapedData.stockStatus,
|
||||
priceCandidates: candidates.map(c => ({
|
||||
price: c.price,
|
||||
currency: c.currency,
|
||||
method: c.method,
|
||||
context: c.context,
|
||||
confidence: c.confidence,
|
||||
})),
|
||||
suggestedPrice: scrapedData.price,
|
||||
url,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create product with stock status
|
||||
|
|
|
|||
|
|
@ -1295,12 +1295,27 @@ export async function scrapeProductWithVoting(
|
|||
|
||||
let html: string = '';
|
||||
|
||||
// Sites known to require JavaScript rendering
|
||||
const jsHeavySites = [
|
||||
/bestbuy\.com/i,
|
||||
/target\.com/i,
|
||||
/walmart\.com/i,
|
||||
/costco\.com/i,
|
||||
];
|
||||
const requiresBrowser = jsHeavySites.some(pattern => pattern.test(url));
|
||||
|
||||
try {
|
||||
let usedBrowser = false;
|
||||
|
||||
// Fetch HTML
|
||||
try {
|
||||
const response = await axios.get<string>(url, {
|
||||
// For JS-heavy sites, go straight to browser
|
||||
if (requiresBrowser) {
|
||||
console.log(`[Voting] ${new URL(url).hostname} requires browser rendering, using Puppeteer...`);
|
||||
html = await scrapeWithBrowser(url);
|
||||
usedBrowser = true;
|
||||
} else {
|
||||
// Fetch HTML
|
||||
try {
|
||||
const response = await axios.get<string>(url, {
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
||||
|
|
@ -1323,13 +1338,14 @@ export async function scrapeProductWithVoting(
|
|||
maxRedirects: 5,
|
||||
});
|
||||
html = response.data;
|
||||
} catch (axiosError) {
|
||||
if (axiosError instanceof AxiosError && axiosError.response?.status === 403) {
|
||||
console.log(`[Voting] HTTP blocked (403) for ${url}, using browser...`);
|
||||
html = await scrapeWithBrowser(url);
|
||||
usedBrowser = true;
|
||||
} else {
|
||||
throw axiosError;
|
||||
} catch (axiosError) {
|
||||
if (axiosError instanceof AxiosError && axiosError.response?.status === 403) {
|
||||
console.log(`[Voting] HTTP blocked (403) for ${url}, using browser...`);
|
||||
html = await scrapeWithBrowser(url);
|
||||
usedBrowser = true;
|
||||
} else {
|
||||
throw axiosError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -265,9 +265,13 @@ export default function PriceSelectionModal({
|
|||
|
||||
<div className="price-modal">
|
||||
<div className="price-modal-header">
|
||||
<h2 className="price-modal-title">Multiple Prices Found</h2>
|
||||
<h2 className="price-modal-title">
|
||||
{candidates.length > 1 ? 'Multiple Prices Found' : 'Confirm Price'}
|
||||
</h2>
|
||||
<p className="price-modal-subtitle">
|
||||
We found different prices for this product. Please select the correct one.
|
||||
{candidates.length > 1
|
||||
? 'We found different prices for this product. Please select the correct one.'
|
||||
: 'Please verify this is the correct price for the product.'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/client.ts","./src/components/authform.tsx","./src/components/layout.tsx","./src/components/passwordinput.tsx","./src/components/pricechart.tsx","./src/components/productcard.tsx","./src/components/productform.tsx","./src/components/sparkline.tsx","./src/components/stocktimeline.tsx","./src/context/authcontext.tsx","./src/context/toastcontext.tsx","./src/hooks/useauth.ts","./src/pages/dashboard.tsx","./src/pages/login.tsx","./src/pages/productdetail.tsx","./src/pages/register.tsx","./src/pages/settings.tsx"],"version":"5.9.3"}
|
||||
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/api/client.ts","./src/components/aistatusbadge.tsx","./src/components/authform.tsx","./src/components/layout.tsx","./src/components/notificationbell.tsx","./src/components/particlebackground.tsx","./src/components/passwordinput.tsx","./src/components/pricechart.tsx","./src/components/priceselectionmodal.tsx","./src/components/productcard.tsx","./src/components/productform.tsx","./src/components/sparkline.tsx","./src/components/stocktimeline.tsx","./src/context/authcontext.tsx","./src/context/toastcontext.tsx","./src/hooks/useauth.ts","./src/pages/dashboard.tsx","./src/pages/login.tsx","./src/pages/notificationhistory.tsx","./src/pages/productdetail.tsx","./src/pages/register.tsx","./src/pages/settings.tsx"],"version":"5.9.3"}
|
||||
Loading…
Add table
Add a link
Reference in a new issue