From 90bfee879113a65018c3d307a326fe5613e46fce Mon Sep 17 00:00:00 2001 From: Victor Noguera Date: Tue, 19 May 2026 23:01:28 -0400 Subject: [PATCH] feat: add advanced filtering options for Stalker products including price, sales rank, and seller metrics --- src/server.ts | 53 ++++++++++++++++++++++++ src/web/frontend.tsx | 98 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/src/server.ts b/src/server.ts index aa4213b..428570d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -829,6 +829,20 @@ function parseStalkerProductFilters(filters: URLSearchParams) { const q = filters.get("q")?.trim() || ""; const sellerId = filters.get("sellerId")?.trim().toUpperCase() || ""; const runIdRaw = filters.get("runId")?.trim() || ""; + const verdict = filters.get("verdict")?.trim().toUpperCase() || ""; + const amazonIsSeller = filters.get("amazonIsSeller")?.trim() || ""; + const minPriceRaw = filters.get("minPrice")?.trim() || ""; + const maxPriceRaw = filters.get("maxPrice")?.trim() || ""; + const minMonthlySoldRaw = filters.get("minMonthlySold")?.trim() || ""; + const maxMonthlySoldRaw = filters.get("maxMonthlySold")?.trim() || ""; + const minSalesRankRaw = filters.get("minSalesRank")?.trim() || ""; + const maxSalesRankRaw = filters.get("maxSalesRank")?.trim() || ""; + const minSellerCountRaw = filters.get("minSellerCount")?.trim() || ""; + const maxSellerCountRaw = filters.get("maxSellerCount")?.trim() || ""; + const minRatingCountRaw = filters.get("minRatingCount")?.trim() || ""; + const maxRatingCountRaw = filters.get("maxRatingCount")?.trim() || ""; + const minConfidenceRaw = filters.get("minConfidence")?.trim() || ""; + const maxConfidenceRaw = filters.get("maxConfidence")?.trim() || ""; const conditions = [ "inv.can_sell = 1", @@ -849,6 +863,45 @@ function parseStalkerProductFilters(filters: URLSearchParams) { params.push(sellerId); } + if (verdict === "FBA" || verdict === "FBM" || verdict === "SKIP") { + conditions.push("analysis.verdict = ?"); + params.push(verdict); + } else if (verdict === "UNANALYZED") { + conditions.push("analysis.verdict IS NULL"); + } + + if (amazonIsSeller === "yes") { + conditions.push("inv.amazon_is_seller = 1"); + } else if (amazonIsSeller === "no") { + conditions.push("inv.amazon_is_seller = 0"); + } else if (amazonIsSeller === "unknown") { + conditions.push("inv.amazon_is_seller IS NULL"); + } + + const numericFilters: Array<[string, string, string]> = [ + [minPriceRaw, "inv.current_price >= ?", "minPrice"], + [maxPriceRaw, "inv.current_price <= ?", "maxPrice"], + [minMonthlySoldRaw, "inv.monthly_sold >= ?", "minMonthlySold"], + [maxMonthlySoldRaw, "inv.monthly_sold <= ?", "maxMonthlySold"], + [minSalesRankRaw, "inv.sales_rank >= ?", "minSalesRank"], + [maxSalesRankRaw, "inv.sales_rank <= ?", "maxSalesRank"], + [minSellerCountRaw, "inv.seller_count >= ?", "minSellerCount"], + [maxSellerCountRaw, "inv.seller_count <= ?", "maxSellerCount"], + [minRatingCountRaw, "s.rating_count >= ?", "minRatingCount"], + [maxRatingCountRaw, "s.rating_count <= ?", "maxRatingCount"], + [minConfidenceRaw, "analysis.confidence >= ?", "minConfidence"], + [maxConfidenceRaw, "analysis.confidence <= ?", "maxConfidence"], + ]; + + for (const [raw, condition] of numericFilters) { + if (!raw) continue; + const value = Number(raw); + if (Number.isFinite(value)) { + conditions.push(condition); + params.push(value); + } + } + if (q) { const wildcard = `%${q}%`; conditions.push( diff --git a/src/web/frontend.tsx b/src/web/frontend.tsx index 34685dd..533f3dc 100644 --- a/src/web/frontend.tsx +++ b/src/web/frontend.tsx @@ -1135,6 +1135,20 @@ function StalkerProductsExplorer({ const [search, setSearch] = useState(""); const [sellerId, setSellerId] = useState(""); const [runId, setRunId] = useState(""); + const [verdict, setVerdict] = useState(""); + const [amazonIsSeller, setAmazonIsSeller] = useState(""); + const [minPrice, setMinPrice] = useState(""); + const [maxPrice, setMaxPrice] = useState(""); + const [minMonthlySold, setMinMonthlySold] = useState(""); + const [maxMonthlySold, setMaxMonthlySold] = useState(""); + const [minSalesRank, setMinSalesRank] = useState(""); + const [maxSalesRank, setMaxSalesRank] = useState(""); + const [minSellerCount, setMinSellerCount] = useState(""); + const [maxSellerCount, setMaxSellerCount] = useState(""); + const [minRatingCount, setMinRatingCount] = useState(""); + const [maxRatingCount, setMaxRatingCount] = useState(""); + const [minConfidence, setMinConfidence] = useState(""); + const [maxConfidence, setMaxConfidence] = useState(""); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(50); const [sort, setSort] = useState({ field: "monthly_sold", direction: "DESC" }); @@ -1151,6 +1165,20 @@ function StalkerProductsExplorer({ if (search) params.set("q", search); if (sellerId) params.set("sellerId", sellerId); if (runId) params.set("runId", runId); + if (verdict) params.set("verdict", verdict); + if (amazonIsSeller) params.set("amazonIsSeller", amazonIsSeller); + if (minPrice) params.set("minPrice", minPrice); + if (maxPrice) params.set("maxPrice", maxPrice); + if (minMonthlySold) params.set("minMonthlySold", minMonthlySold); + if (maxMonthlySold) params.set("maxMonthlySold", maxMonthlySold); + if (minSalesRank) params.set("minSalesRank", minSalesRank); + if (maxSalesRank) params.set("maxSalesRank", maxSalesRank); + if (minSellerCount) params.set("minSellerCount", minSellerCount); + if (maxSellerCount) params.set("maxSellerCount", maxSellerCount); + if (minRatingCount) params.set("minRatingCount", minRatingCount); + if (maxRatingCount) params.set("maxRatingCount", maxRatingCount); + if (minConfidence) params.set("minConfidence", minConfidence); + if (maxConfidence) params.set("maxConfidence", maxConfidence); const res = await fetch(`/api/stalker/products?${params.toString()}`); const payload = (await res.json()) as StalkerProductsResponse; @@ -1164,7 +1192,49 @@ function StalkerProductsExplorer({ return () => { cancelled = true; }; - }, [search, sellerId, runId, page, pageSize, sort]); + }, [ + search, + sellerId, + runId, + verdict, + amazonIsSeller, + minPrice, + maxPrice, + minMonthlySold, + maxMonthlySold, + minSalesRank, + maxSalesRank, + minSellerCount, + maxSellerCount, + minRatingCount, + maxRatingCount, + minConfidence, + maxConfidence, + page, + pageSize, + sort, + ]); + + function resetFilters() { + setSearch(""); + setSellerId(""); + setRunId(""); + setVerdict(""); + setAmazonIsSeller(""); + setMinPrice(""); + setMaxPrice(""); + setMinMonthlySold(""); + setMaxMonthlySold(""); + setMinSalesRank(""); + setMaxSalesRank(""); + setMinSellerCount(""); + setMaxSellerCount(""); + setMinRatingCount(""); + setMaxRatingCount(""); + setMinConfidence(""); + setMaxConfidence(""); + setPage(1); + } return (
@@ -1197,11 +1267,37 @@ function StalkerProductsExplorer({ { setPage(1); setSearch(e.target.value); }} placeholder="Search ASIN, product, brand, category, or seller" /> { setPage(1); setSellerId(e.target.value.toUpperCase()); }} placeholder="Seller ID" /> { setPage(1); setRunId(e.target.value); }} placeholder="Run ID" /> + + + { setPage(1); setMinPrice(e.target.value); }} placeholder="Min price" /> + { setPage(1); setMaxPrice(e.target.value); }} placeholder="Max price" /> + { setPage(1); setMinMonthlySold(e.target.value); }} placeholder="Min monthly sold" /> + { setPage(1); setMaxMonthlySold(e.target.value); }} placeholder="Max monthly sold" /> + { setPage(1); setMinSalesRank(e.target.value); }} placeholder="Min rank" /> + { setPage(1); setMaxSalesRank(e.target.value); }} placeholder="Max rank" /> + { setPage(1); setMinSellerCount(e.target.value); }} placeholder="Min sellers" /> + { setPage(1); setMaxSellerCount(e.target.value); }} placeholder="Max sellers" /> + { setPage(1); setMinRatingCount(e.target.value); }} placeholder="Min seller rating count" /> + { setPage(1); setMaxRatingCount(e.target.value); }} placeholder="Max seller rating count" /> + { setPage(1); setMinConfidence(e.target.value); }} placeholder="Min confidence" /> + { setPage(1); setMaxConfidence(e.target.value); }} placeholder="Max confidence" /> +