From 85cb76b4588645978caa9334d854df2548be4e0e Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Mon, 7 Sep 2026 23:03:34 +0700 Subject: [PATCH] Map audit: fix dead trusted-first sort + broken stash-card borders (1.2.36) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two real bugs surfaced auditing the Map page. 1. The "trusted-first" soft sort was silently dead for the default config. filteredSpots ran a standalone .sort() to float trusted content up, then IMMEDIATELY ran a second unconditional .sort() by sortBy — which re-ordered everything and wiped the trust ordering. For a logged-in user with ≥5 follows the smart default is trustFilter='trusted' + sortBy='recent', so the documented "sort trusted first, badge unverified" behaviour never actually happened. Fixed by folding the trust tier into the MAIN comparator as its primary key, with the chosen sortBy as the tiebreaker within each tier. Strict modes (verified/following) still hard-filter as before. 2. MiniStashCard (gear pins in the map drawer) built its border colour with an interpolated Tailwind class (`border-${colour}-500/40`) that the JIT compiler can't see, so it was never generated — dead class emitting an invalid string into the DOM. The inline style={{ borderColor }} that actually worked was also applied unconditionally, overriding the intended cyan border on WISHLIST items with the rarity colour. Now: wishlist keeps its static cyan border; gear uses the rarity colour via inline style only. Geolocation (native vs web, denied/timeout/no-provider handling), batched trust/status/comment/weather queries, and the layer plumbing into SpotMap were all audited and are sound. Co-authored-by: shakespeare.diy --- package.json | 2 +- src/pages/MapPage.tsx | 51 ++++++++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 592b2fd..ddcfb43 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "skate-spots", "private": true, - "version": "1.2.35", + "version": "1.2.36", "type": "module", "homepage": "https://skate-spots.com", "scripts": { diff --git a/src/pages/MapPage.tsx b/src/pages/MapPage.tsx index 628e7d5..fda8625 100644 --- a/src/pages/MapPage.tsx +++ b/src/pages/MapPage.tsx @@ -98,10 +98,16 @@ function MiniStashCard({ item, onDelete }: { item: StashItem; onDelete: () => vo const hasImage = item.images && item.images.length > 0; return ( -
+
{/* Wishlist badge */} {isWishlist && ( @@ -833,27 +839,28 @@ export default function MapPage() { return true; }); - // Apply trust filter — when 'trusted', sort trusted content to the top - // rather than hiding untrusted content (avoids penalising new users/anon browsers) - // Strict filtering (verified/following) still hides low-trust content as expected - if (trustScores && trustFilter !== 'all') { - if (trustFilter === 'trusted') { - // Soft mode: sort trusted first, keep everything visible - filtered.sort((a, b) => { - const scoreA = getTrustScore(a.pubkey) ?? -1; - const scoreB = getTrustScore(b.pubkey) ?? -1; - const trustedA = scoreA >= 60 ? 1 : 0; - const trustedB = scoreB >= 60 ? 1 : 0; - return trustedB - trustedA; - }); - } else { - // Strict modes (verified, following) — actually filter - filtered = filterByTrustLevel(filtered, trustFilter, getTrustScore); - } + // Apply trust filter. + // • 'trusted' (soft): keep everything visible but float trusted content to + // the top. This must be folded into the MAIN sort below as its primary + // key — running it as a separate .sort() first is pointless because the + // sort() that follows would immediately re-order everything and wipe it + // out (which it silently did for the default trusted+recent combo). + // • 'verified'/'following' (strict): actually hide low-trust content. + const softTrust = trustFilter === 'trusted'; + if (trustScores && trustFilter !== 'all' && !softTrust) { + filtered = filterByTrustLevel(filtered, trustFilter, getTrustScore); } - // Apply sorting + // Trust tier (1 = trusted, 0 = not) used as the primary sort key in soft mode. + const trustTier = (pubkey: string) => ((getTrustScore(pubkey) ?? -1) >= 60 ? 1 : 0); + + // Apply sorting. In soft-trust mode, trusted content sorts first and the + // chosen `sortBy` becomes the tiebreaker WITHIN each trust tier. filtered.sort((a, b) => { + if (softTrust && trustScores) { + const tierDiff = trustTier(b.pubkey) - trustTier(a.pubkey); + if (tierDiff !== 0) return tierDiff; + } switch (sortBy) { case 'trust': { const scoreA = getTrustScore(a.pubkey) || 0;