feat: add advanced filtering options for Stalker products including price, sales rank, and seller metrics
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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<SortState>({ 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 (
|
||||
<div className="page">
|
||||
@@ -1197,11 +1267,37 @@ function StalkerProductsExplorer({
|
||||
<input value={search} onChange={(e) => { setPage(1); setSearch(e.target.value); }} placeholder="Search ASIN, product, brand, category, or seller" />
|
||||
<input value={sellerId} onChange={(e) => { setPage(1); setSellerId(e.target.value.toUpperCase()); }} placeholder="Seller ID" />
|
||||
<input value={runId} onChange={(e) => { setPage(1); setRunId(e.target.value); }} placeholder="Run ID" />
|
||||
<select value={verdict} onChange={(e) => { setPage(1); setVerdict(e.target.value); }}>
|
||||
<option value="">All verdicts</option>
|
||||
<option value="FBA">FBA</option>
|
||||
<option value="FBM">FBM</option>
|
||||
<option value="SKIP">SKIP</option>
|
||||
<option value="UNANALYZED">Unanalyzed</option>
|
||||
</select>
|
||||
<select value={amazonIsSeller} onChange={(e) => { setPage(1); setAmazonIsSeller(e.target.value); }}>
|
||||
<option value="">Amazon seller: all</option>
|
||||
<option value="yes">Amazon seller: yes</option>
|
||||
<option value="no">Amazon seller: no</option>
|
||||
<option value="unknown">Amazon seller: unknown</option>
|
||||
</select>
|
||||
<input value={minPrice} onChange={(e) => { setPage(1); setMinPrice(e.target.value); }} placeholder="Min price" />
|
||||
<input value={maxPrice} onChange={(e) => { setPage(1); setMaxPrice(e.target.value); }} placeholder="Max price" />
|
||||
<input value={minMonthlySold} onChange={(e) => { setPage(1); setMinMonthlySold(e.target.value); }} placeholder="Min monthly sold" />
|
||||
<input value={maxMonthlySold} onChange={(e) => { setPage(1); setMaxMonthlySold(e.target.value); }} placeholder="Max monthly sold" />
|
||||
<input value={minSalesRank} onChange={(e) => { setPage(1); setMinSalesRank(e.target.value); }} placeholder="Min rank" />
|
||||
<input value={maxSalesRank} onChange={(e) => { setPage(1); setMaxSalesRank(e.target.value); }} placeholder="Max rank" />
|
||||
<input value={minSellerCount} onChange={(e) => { setPage(1); setMinSellerCount(e.target.value); }} placeholder="Min sellers" />
|
||||
<input value={maxSellerCount} onChange={(e) => { setPage(1); setMaxSellerCount(e.target.value); }} placeholder="Max sellers" />
|
||||
<input value={minRatingCount} onChange={(e) => { setPage(1); setMinRatingCount(e.target.value); }} placeholder="Min seller rating count" />
|
||||
<input value={maxRatingCount} onChange={(e) => { setPage(1); setMaxRatingCount(e.target.value); }} placeholder="Max seller rating count" />
|
||||
<input value={minConfidence} onChange={(e) => { setPage(1); setMinConfidence(e.target.value); }} placeholder="Min confidence" />
|
||||
<input value={maxConfidence} onChange={(e) => { setPage(1); setMaxConfidence(e.target.value); }} placeholder="Max confidence" />
|
||||
<select value={String(pageSize)} onChange={(e) => { setPage(1); setPageSize(Number(e.target.value)); }}>
|
||||
<option value="25">25 / page</option>
|
||||
<option value="50">50 / page</option>
|
||||
<option value="100">100 / page</option>
|
||||
</select>
|
||||
<button onClick={resetFilters}>Reset filters</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user