diff --git a/src/pages/EventsPage.tsx b/src/pages/EventsPage.tsx
index 3310261..bbdf4a5 100644
--- a/src/pages/EventsPage.tsx
+++ b/src/pages/EventsPage.tsx
@@ -15,6 +15,7 @@ import { SortDropdown, type SortOption } from '@/components/SortDropdown';
import { useSkateEvents } from '@/hooks/useSkateEvents';
import { useTours } from '@/hooks/useTours';
import { useCurrentUser } from '@/hooks/useCurrentUser';
+import { useFollowing } from '@/hooks/useFollowing';
import { useBatchTrustScores } from '@/hooks/useBatchTrustScores';
import { useComments } from '@/hooks/useComments';
import { useTranslation } from '@/contexts/LanguageContext';
@@ -37,6 +38,9 @@ export default function EventsPage() {
});
const { user } = useCurrentUser();
+ const { data: followingList } = useFollowing(user?.pubkey);
+ const followCount = followingList?.length ?? 0;
+ const smartDefault: TrustFilterLevel = (user && followCount >= 5) ? 'trusted' : 'all';
const { data: events, isLoading: eventsLoading } = useSkateEvents(100);
const { data: tours, isLoading: toursLoading } = useTours(100);
@@ -47,7 +51,7 @@ export default function EventsPage() {
const [searchQuery, setSearchQuery] = useState('');
const [selectedTypes, setSelectedTypes] = useState([]);
const [activeTab, setActiveTab] = useState<'upcoming' | 'past'>('upcoming');
- const [trustFilter, setTrustFilter] = useState('all');
+ const [trustFilter, setTrustFilter] = useState(smartDefault);
const [sortBy, setSortBy] = useState('recent');
// Tour filters
@@ -55,7 +59,7 @@ export default function EventsPage() {
const [tourCategory, setTourCategory] = useState('all');
const [tourSkillLevel, setTourSkillLevel] = useState('all');
const [tourVerifiedOnly, setTourVerifiedOnly] = useState(false);
- const [tourTrustFilter, setTourTrustFilter] = useState('all');
+ const [tourTrustFilter, setTourTrustFilter] = useState(smartDefault);
const [tourSortBy, setTourSortBy] = useState('recent');
const now = Math.floor(Date.now() / 1000);
@@ -116,9 +120,17 @@ export default function EventsPage() {
return true;
});
- // Apply trust filter
+ // Apply trust filter (soft for 'trusted', strict for 'verified'/'following')
if (trustScores && tourTrustFilter !== 'all') {
- filtered = filterByTrustLevel(filtered, tourTrustFilter, getTrustScore);
+ if (tourTrustFilter === 'trusted') {
+ filtered.sort((a, b) => {
+ const tA = (getTrustScore(a.pubkey) ?? -1) >= 60 ? 1 : 0;
+ const tB = (getTrustScore(b.pubkey) ?? -1) >= 60 ? 1 : 0;
+ return tB - tA;
+ });
+ } else {
+ filtered = filterByTrustLevel(filtered, tourTrustFilter, getTrustScore);
+ }
}
// Apply sorting
@@ -172,9 +184,17 @@ export default function EventsPage() {
return true;
});
- // Apply trust filter
+ // Apply trust filter (soft for 'trusted', strict for 'verified'/'following')
if (trustScores && trustFilter !== 'all') {
- filtered = filterByTrustLevel(filtered, trustFilter, getTrustScore);
+ if (trustFilter === 'trusted') {
+ filtered.sort((a, b) => {
+ const tA = (getTrustScore(a.pubkey) ?? -1) >= 60 ? 1 : 0;
+ const tB = (getTrustScore(b.pubkey) ?? -1) >= 60 ? 1 : 0;
+ return tB - tA;
+ });
+ } else {
+ filtered = filterByTrustLevel(filtered, trustFilter, getTrustScore);
+ }
}
// Split into upcoming and past
diff --git a/src/pages/MapPage.tsx b/src/pages/MapPage.tsx
index 951dd5a..304bc6f 100644
--- a/src/pages/MapPage.tsx
+++ b/src/pages/MapPage.tsx
@@ -26,6 +26,7 @@ import { useMarketplaceItems } from '@/hooks/useMarketplace';
import { useTours } from '@/hooks/useTours';
import { useBtcMapPlaces } from '@/hooks/useBtcMapPlaces';
import { useCurrentUser } from '@/hooks/useCurrentUser';
+import { useFollowing } from '@/hooks/useFollowing';
import { useBatchTrustScores } from '@/hooks/useBatchTrustScores';
import { useMultipleSpotWeather } from '@/hooks/useSpotWeather';
import { useComments } from '@/hooks/useComments';
@@ -333,6 +334,8 @@ export default function MapPage() {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const { user } = useCurrentUser();
+ const { data: followingList } = useFollowing(user?.pubkey);
+ const followCount = followingList?.length ?? 0;
const { data: spots, isLoading: spotsLoading } = useSkateSpots(200);
const { data: shops, isLoading: shopsLoading } = useShops(200);
const { data: marketplaceItems, isLoading: marketplaceLoading } = useMarketplaceItems(200);
@@ -348,7 +351,12 @@ export default function MapPage() {
const [selectedSpot, setSelectedSpot] = useState(null);
const [weatherEnabled, setWeatherEnabled] = useState(false);
const [weatherFilter, setWeatherFilter] = useState<'all' | 'good' | 'perfect'>('all');
- const [trustFilter, setTrustFilter] = useState('all');
+ // Smart WoT default:
+ // - Logged out or <5 follows → 'all' (show everything, don't punish new/anon users)
+ // - Logged in with ≥5 follows → 'trusted' (sort trusted first, badge unverified)
+ // User can always override with the TrustFilter dropdown
+ const smartDefault: TrustFilterLevel = (user && followCount >= 5) ? 'trusted' : 'all';
+ const [trustFilter, setTrustFilter] = useState(smartDefault);
const [sortBy, setSortBy] = useState('recent');
const [userLocation, setUserLocation] = useState<{lat: number; lon: number} | null>(null);
@@ -540,9 +548,23 @@ export default function MapPage() {
return true;
});
- // Apply trust filter
+ // 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') {
- filtered = filterByTrustLevel(filtered, trustFilter, getTrustScore);
+ 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 sorting
diff --git a/src/pages/ShopDetailPage.tsx b/src/pages/ShopDetailPage.tsx
index 56aed29..5a5dd54 100644
--- a/src/pages/ShopDetailPage.tsx
+++ b/src/pages/ShopDetailPage.tsx
@@ -12,6 +12,8 @@ import { Skeleton } from '@/components/ui/skeleton';
import { Button } from '@/components/ui/button';
import { ZapButton } from '@/components/ZapButton';
import { CommentsSection } from '@/components/comments/CommentsSection';
+import { sanitizeUrl, sanitizeTel, sanitizeEmail, urlDomain } from '@/lib/sanitizeUrl';
+import { OfficialBadge } from '@/components/OfficialBadge';
import { useShop } from '@/hooks/useShops';
import { useAuthor } from '@/hooks/useAuthor';
import { useNostrPublish } from '@/hooks/useNostrPublish';
@@ -243,6 +245,7 @@ export default function ShopDetailPage() {
Verified
)}
+
{shop.location && (
@@ -360,22 +363,22 @@ export default function ShopDetailPage() {
- {shop.phone && (
-
+ {sanitizeTel(shop.phone) && (
+
{shop.phone}
)}
- {shop.email && (
-
+ {sanitizeEmail(shop.email) && (
+
{shop.email}
)}
- {shop.website && (
-
+ {sanitizeUrl(shop.website) && (
+
- {shop.website.replace(/^https?:\/\//, '')}
+ {urlDomain(shop.website!)}
)}
{shop.instagram && (