fix: clear price to null when a comparison finds no merchant offer
Several memory sticks (e.g. Crucial CT8G48C40U5, Patriot Signature Line,
Kingston FURY Beast) kept displaying their pc-builder.io catalog price
("€35.99", "€39.99"...) even after clicking "Compare prices" and getting
"No live price found, using catalog price" - an unconfirmed number was
being shown as if it were still valid, which is misleading given
pc-builder.io's catalog is known to go stale (see the earlier RTX 5070
€128 vs €66.89 case).
New clearPriceIfNoOffers(): when ScrapedPartsController#compare finds
zero offers across all 7 supported merchants, the part's price/priceSource
are reset to null, regardless of whether the price previously came from
the pc-builder.io catalog or an earlier verified merchant match - per
explicit product decision, an empty comparison always wins over keeping a
possibly-stale number around.
- ScrapedPartsController#compare now calls clearPriceIfNoOffers() in the
empty-offers branch, and returns the resulting price in the JSON
response so the frontend can mirror it exactly
- NewPartSearch.vue: comparePrices() now sets part.price from the
response's `price` field (mirroring exactly what the backend just
persisted) instead of only updating it on a cheaper find; removed the
now-inaccurate "using catalog price €X" message since that price no
longer exists once compared with no result
- 3 new tests for clearPriceIfNoOffers: clears an unverified
pc-builder.io price, also clears a previously-verified merchant price
when no longer confirmed, and is a no-op when there was no price to
begin with
Verified end-to-end against the reported Crucial CT8G48C40U5 example:
price went from 35.99 (pc-builder.io) to null after a real comparison
found zero matching offers on any merchant.
This commit is contained in:
1 parent
fa74791c92
commit
0ce6a7f4a7
4 files changed
+96
-19
No files matched your search
@@ -62,21 +62,20 @@ async function comparePrices(part: ScrapedPart) {
|
||||
}
|
||||
const data = await response.json()
|
||||
offers[part.id] = data.offers ?? []
|
||||
|
||||
// The backend already persists this exact value server-side (see
|
||||
// ScrapedPartsController#compare): the cheapest offer's price when
|
||||
// one was found (updatePriceIfCheaper), or null when no merchant
|
||||
// confirmed a price at all (clearPriceIfNoOffers) — an unverified
|
||||
// pc-builder.io catalog price is not kept around just because the
|
||||
// comparison came back empty. Mirror that here on the locally held
|
||||
// result so the display (e.g. "€979.95" or "No price yet") reflects
|
||||
// it immediately, instead of the initial search-result price sticking
|
||||
// around until the user re-runs the search from scratch.
|
||||
part.price = data.price ?? null
|
||||
|
||||
if (offers[part.id].length === 0) {
|
||||
compareErrors[part.id] = true
|
||||
return
|
||||
}
|
||||
|
||||
// The backend already persists the cheapest offer found as this
|
||||
// part's new best-known price when it beats the catalog price (see
|
||||
// ScrapedPartsController#compare / updatePriceIfCheaper). Mirror that
|
||||
// here on the locally held result so the displayed catalog price
|
||||
// (e.g. "€979.95") reflects it immediately, instead of staying stuck
|
||||
// at whatever price the initial search returned until the user
|
||||
// re-runs the search from scratch.
|
||||
const cheapest = offers[part.id][0]
|
||||
if (part.price === null || cheapest.price < part.price) {
|
||||
part.price = cheapest.price
|
||||
}
|
||||
} catch {
|
||||
compareErrors[part.id] = true
|
||||
@@ -185,10 +184,7 @@ function importPart(part: ScrapedPart) {
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<span v-if="compareErrors[part.id] && part.price !== null" class="text-xs text-gray-400">
|
||||
No live price found, using catalog price €{{ part.price.toFixed(2) }}
|
||||
</span>
|
||||
<span v-else-if="compareErrors[part.id]" class="text-xs text-gray-400">
|
||||
<span v-if="compareErrors[part.id]" class="text-xs text-gray-400">
|
||||
No price found on any merchant for this part.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user