From 6def78fffe9f7399bc4567a7533423feb5bae2ce Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Sat, 26 Sep 2026 22:20:21 +0700 Subject: [PATCH] chore(lint): clear all no-unused-vars warnings (position-precise) Removed/renamed the remaining 39 unused locals/dead code, file-by-file: - unused destructured bindings/params (remove the binding, keep the call) - unused single-line pure consts and dead functions/interfaces removed - deleted the dead _FeedItem component and its now-unused imports - amber _readChunks self-call fixed; SpotMap popup call site updated Warnings: 182 -> 7 (only react-refresh/only-export-components remain). no-explicit-any=0, exhaustive-deps=0, no-unused-vars=0. Gate: 101 tests, 0 errors, boot smoke green. AGENTS.md baseline + guidance updated. --- AGENTS.md | 15 ++-- src/components/FollowListManager.tsx | 2 +- src/components/GearSwapItemCard.tsx | 4 +- src/components/LanguageToggle.tsx | 2 +- src/components/NostrProvider.tsx | 2 +- src/components/QualityMeter.tsx | 2 +- src/components/SortDropdown.tsx | 1 - src/components/SpotMap.tsx | 5 +- src/components/SpotOwnership.tsx | 2 - src/components/TourCard.tsx | 2 +- src/components/WalletModal.tsx | 1 - src/components/auth/MnemonicSignupDialog.tsx | 2 +- src/components/wallet/CashuWalletCard.tsx | 3 +- src/hooks/useBTCMap.ts | 18 ---- src/hooks/useFollowing.ts | 2 +- src/hooks/useListingRestrictions.ts | 2 +- src/hooks/wallet/useHistoryManager.ts | 1 - src/lib/amber.ts | 4 +- src/pages/CoachDetailPage.tsx | 1 - src/pages/CollectionDetailPage.tsx | 3 +- src/pages/CommunityStatsPage.tsx | 6 -- src/pages/CreateListingPage.tsx | 2 +- src/pages/CrewDetailPage.tsx | 92 ++------------------ src/pages/Index.tsx | 1 - src/pages/MapPage.tsx | 8 +- src/pages/RiderCardPage.tsx | 6 +- src/pages/SettingsPage.tsx | 17 ---- 27 files changed, 37 insertions(+), 169 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6f1ec8b..c214c6e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -79,15 +79,16 @@ session with **no other memory of this project**. So: - **Lazy routes**: every route uses `lazyWithRetry` (`src/lib/lazyWithRetry.ts`) — retries, then one full reload per session, so a chunk-load failure self-heals instead of showing the error boundary. -- **Baselines** (verified 2026-09-26): `npm test` → 0 errors, **46 warnings** - (39 `no-unused-vars`, 7 `react-refresh`), **101 tests**, build ok. +- **Baselines** (verified 2026-09-26): `npm test` → 0 errors, **7 warnings** + (all `react-refresh/only-export-components`), **101 tests**, build ok. `package.json` version **1.4.5**. - - ✅ `no-explicit-any` = 0; ✅ `react-hooks/exhaustive-deps` = 0 (shared getters - are `useCallback`-memoised; intentional mount-only effects carry a justified - `eslint-disable-next-line` with a comment). + - ✅ `no-explicit-any` = 0 · ✅ `react-hooks/exhaustive-deps` = 0 · + ✅ `no-unused-vars` = 0. Remaining: `react-refresh` (dev-only DX — files + exporting non-components next to components; fix by moving the export out). - ⚠️ Do **not** mass-fix `no-unused-vars` by name or blanket rename — shadowed - names (`isUnfollowing`) and typed shorthand destructuring make it unsafe. - Fix file-by-file, position-precise, opportunistically. + names and typed shorthand destructuring make it unsafe. Fix position-precise. + Renaming a component to `_Name` also trips `rules-of-hooks` — delete it or + suppress instead. - **Untracked local junk — do NOT commit**: `assets/`, `resources/`, `cvm-server/`, `bun.lock`. diff --git a/src/components/FollowListManager.tsx b/src/components/FollowListManager.tsx index bf1ce90..cfd77e3 100644 --- a/src/components/FollowListManager.tsx +++ b/src/components/FollowListManager.tsx @@ -102,7 +102,7 @@ export function FollowListManager() { const { user } = useCurrentUser(); const { data: following = [], isLoading: followingLoading } = useFollowing(); const { data: followers = [], isLoading: followersLoading } = useFollowers(); - const { unfollow, followByIdentifier, isFollowing, isUnfollowing } = useFollowActions(); + const { unfollow, followByIdentifier, isFollowing } = useFollowActions(); const [followInput, setFollowInput] = useState(''); diff --git a/src/components/GearSwapItemCard.tsx b/src/components/GearSwapItemCard.tsx index 4083977..1a550bd 100644 --- a/src/components/GearSwapItemCard.tsx +++ b/src/components/GearSwapItemCard.tsx @@ -14,7 +14,7 @@ import { useToast } from '@/hooks/useToast'; import { isAdminPubkey } from '@/lib/admins'; import { genUserName } from '@/lib/genUserName'; import { getSkateboardRating, getTrustLevel, SELLER_TRUST_BADGES } from '@/lib/skateboardRating'; -import { GEAR_CONDITIONS, GEAR_CATEGORIES, PRICE_TYPES, formatPrice, type MarketplaceItem } from '@/lib/types'; +import { GEAR_CONDITIONS, GEAR_CATEGORIES, formatPrice, type MarketplaceItem } from '@/lib/types'; import { MessageCircle, MapPin, Search, CheckCircle, ShieldCheck, AlertTriangle, MoreVertical, Flag, Trash2, RotateCcw, Loader2 } from 'lucide-react'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from '@/components/ui/dropdown-menu'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog'; @@ -28,7 +28,7 @@ interface GearSwapItemCardProps { isFollowing?: boolean; } -export function GearSwapItemCard({ item, trustScore, salesCount, isFollowing }: GearSwapItemCardProps) { +export function GearSwapItemCard({ item, trustScore, salesCount }: GearSwapItemCardProps) { const { user } = useCurrentUser(); const navigate = useNavigate(); const author = useAuthor(item.pubkey); diff --git a/src/components/LanguageToggle.tsx b/src/components/LanguageToggle.tsx index eaa1abc..3b1ebde 100644 --- a/src/components/LanguageToggle.tsx +++ b/src/components/LanguageToggle.tsx @@ -34,7 +34,7 @@ interface LanguageToggleProps { * Language toggle dropdown for switching between English and Spanish */ export function LanguageToggle({ compact = false, className, variant = 'ghost' }: LanguageToggleProps) { - const { language, setLanguage, t } = useTranslation(); + const { language, setLanguage } = useTranslation(); const currentLanguage = languages.find(l => l.code === language) || languages[0]; diff --git a/src/components/NostrProvider.tsx b/src/components/NostrProvider.tsx index a64408c..1dd8b44 100644 --- a/src/components/NostrProvider.tsx +++ b/src/components/NostrProvider.tsx @@ -155,7 +155,7 @@ const NostrProvider: React.FC = (props) => { return routes; }, - eventRouter(event: NostrEvent) { + eventRouter(_event: NostrEvent) { // `resolveRelays` applies the blocklist and adds local relays. const resolved = resolveRelays(relayMetadata.current); const writeRelays = resolved.write.length > 0 diff --git a/src/components/QualityMeter.tsx b/src/components/QualityMeter.tsx index 3201230..8553768 100644 --- a/src/components/QualityMeter.tsx +++ b/src/components/QualityMeter.tsx @@ -122,7 +122,7 @@ export function QualityMeter({ return items; }, [type, hasLocation, hasPhotos, photoCount, hasDescription, descriptionLength, hasPhone, hasWebsite, hasHours, hasSpotType]); - const { score, maxScore, completedItems, totalItems } = useMemo(() => { + const { score, maxScore } = useMemo(() => { const completed = checks.filter(c => c.completed); const total = checks.reduce((sum, c) => sum + c.points, 0); const current = completed.reduce((sum, c) => sum + c.points, 0); diff --git a/src/components/SortDropdown.tsx b/src/components/SortDropdown.tsx index b0995ef..1778888 100644 --- a/src/components/SortDropdown.tsx +++ b/src/components/SortDropdown.tsx @@ -50,7 +50,6 @@ export function SortDropdown({ onChange, className, showProximity = false, - contentType = 'generic', }: SortDropdownProps) { const selectedOption = SORT_OPTIONS[value]; const Icon = selectedOption.icon; diff --git a/src/components/SpotMap.tsx b/src/components/SpotMap.tsx index 5e95f48..ea549b7 100644 --- a/src/components/SpotMap.tsx +++ b/src/components/SpotMap.tsx @@ -661,8 +661,7 @@ function createPopupContent( function createEnhancedPopupContent( spot: SkateSpot, marketplaceItems: MarketplaceItem[], - onViewDetails: () => void, - weatherData?: SpotWeatherData + onViewDetails: () => void ): HTMLElement { const container = document.createElement('div'); container.className = 'p-2 min-w-[250px] max-w-[350px]'; @@ -1122,7 +1121,7 @@ export function SpotMap({ // Use enhanced popup if there are marketplace items, otherwise use standard const popupContent = hasGear - ? createEnhancedPopupContent(primarySpot, group.marketplaceItems, () => handleViewDetails(primarySpot), spotWeather) + ? createEnhancedPopupContent(primarySpot, group.marketplaceItems, () => handleViewDetails(primarySpot)) : createPopupContent(primarySpot, () => handleViewDetails(primarySpot), spotWeather); marker.bindPopup(popupContent, { diff --git a/src/components/SpotOwnership.tsx b/src/components/SpotOwnership.tsx index fde9421..9eb75fd 100644 --- a/src/components/SpotOwnership.tsx +++ b/src/components/SpotOwnership.tsx @@ -23,7 +23,6 @@ import { } from '@/components/ui/alert-dialog'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useNostrPublish } from '@/hooks/useNostrPublish'; -import { useAuthor } from '@/hooks/useAuthor'; import { useToast } from '@/hooks/useToast'; import { useQueryClient } from '@tanstack/react-query'; import { SKATE_SPOT_KIND, type SkateSpot } from '@/lib/types'; @@ -47,7 +46,6 @@ export function SpotOwnership({ spot }: SpotOwnershipProps) { const { mutateAsync: publishEvent, isPending: isPublishing } = useNostrPublish(); const { toast } = useToast(); const queryClient = useQueryClient(); - const ownerProfile = useAuthor(spot.pubkey); const [transferOpen, setTransferOpen] = useState(false); const [claimOpen, setClaimOpen] = useState(false); diff --git a/src/components/TourCard.tsx b/src/components/TourCard.tsx index b7f9eb5..c3c26e3 100644 --- a/src/components/TourCard.tsx +++ b/src/components/TourCard.tsx @@ -24,7 +24,7 @@ interface TourCardProps { compact?: boolean; } -function getCategoryIcon(category: TourCategory) { +function _getCategoryIcon(category: TourCategory) { switch (category) { case 'local': return ; diff --git a/src/components/WalletModal.tsx b/src/components/WalletModal.tsx index 76bb883..ed55d79 100644 --- a/src/components/WalletModal.tsx +++ b/src/components/WalletModal.tsx @@ -86,7 +86,6 @@ const WalletContent = forwardRef void; }>(({ webln, - hasNWC, connections, connectionInfo, activeConnection, diff --git a/src/components/auth/MnemonicSignupDialog.tsx b/src/components/auth/MnemonicSignupDialog.tsx index e1fbbf9..b535e77 100644 --- a/src/components/auth/MnemonicSignupDialog.tsx +++ b/src/components/auth/MnemonicSignupDialog.tsx @@ -28,7 +28,7 @@ const MnemonicSignupDialog: React.FC = ({ const [showMnemonic, setShowMnemonic] = useState(true); const [verifyIndices, setVerifyIndices] = useState([]); const [verifyInputs, setVerifyInputs] = useState>({}); - const [isVerified, setIsVerified] = useState(false); + const [, setIsVerified] = useState(false); const login = useLoginActions(); // Generate new mnemonic diff --git a/src/components/wallet/CashuWalletCard.tsx b/src/components/wallet/CashuWalletCard.tsx index ec97c6d..c4fa384 100644 --- a/src/components/wallet/CashuWalletCard.tsx +++ b/src/components/wallet/CashuWalletCard.tsx @@ -142,7 +142,6 @@ function CashuWalletCardNative() { balances, mints, totalBalance, - isInitialized, isLoading: walletLoading, error: walletError, mnemonic, @@ -192,7 +191,7 @@ function CashuWalletCardNative() { sentTokenQRCode, } = useTokenOperations({ coco, activeMintUrl, generateQRCode, getEncodedToken }); - const { history, isLoading: historyLoading } = useHistoryManager({ + const { history } = useHistoryManager({ coco, repositories, mints, diff --git a/src/hooks/useBTCMap.ts b/src/hooks/useBTCMap.ts index 5f23f1e..edf71af 100644 --- a/src/hooks/useBTCMap.ts +++ b/src/hooks/useBTCMap.ts @@ -23,24 +23,6 @@ export interface BTCMapMerchant { }; } -interface BTCMapResponse { - type: string; - features: Array<{ - type: string; - geometry: { - type: string; - coordinates: [number, number]; // [lon, lat] - }; - properties: { - id: string; - name?: string; - 'payment:lightning'?: string; - 'payment:onchain'?: string; - [key: string]: string | undefined; - }; - }>; -} - /** * Fetch Bitcoin-accepting merchants from BTCMap API * Uses bounding box to get merchants in the visible map area diff --git a/src/hooks/useFollowing.ts b/src/hooks/useFollowing.ts index f56f6b8..a1a954e 100644 --- a/src/hooks/useFollowing.ts +++ b/src/hooks/useFollowing.ts @@ -114,7 +114,7 @@ export function useFollowActions() { return targetPubkey; }, - onSuccess: (targetPubkey) => { + onSuccess: (_targetPubkey) => { // Invalidate queries to refetch queryClient.invalidateQueries({ queryKey: ['following', user?.pubkey] }); queryClient.invalidateQueries({ queryKey: ['trust-score'] }); diff --git a/src/hooks/useListingRestrictions.ts b/src/hooks/useListingRestrictions.ts index ab27421..7f9c4da 100644 --- a/src/hooks/useListingRestrictions.ts +++ b/src/hooks/useListingRestrictions.ts @@ -62,7 +62,7 @@ interface LastListingRecord { export function useListingRestrictions(linkedSpotPubkey?: string): ListingRestrictions { const { nostr } = useNostr(); const { user, metadata } = useCurrentUser(); - const [lastListingRecord, setLastListingRecord] = useLocalStorage( + const [lastListingRecord] = useLocalStorage( 'last-listing-record', null ); diff --git a/src/hooks/wallet/useHistoryManager.ts b/src/hooks/wallet/useHistoryManager.ts index 64d852f..cbcd992 100644 --- a/src/hooks/wallet/useHistoryManager.ts +++ b/src/hooks/wallet/useHistoryManager.ts @@ -22,7 +22,6 @@ interface UseHistoryManagerProps { export function useHistoryManager({ coco, repositories, - mints, }: UseHistoryManagerProps) { const [history, setHistory] = useState([]); const [isLoading, setIsLoading] = useState(false); diff --git a/src/lib/amber.ts b/src/lib/amber.ts index 9af8794..9fc015c 100644 --- a/src/lib/amber.ts +++ b/src/lib/amber.ts @@ -649,7 +649,7 @@ export function decodeAmberResult(result: string): string { const reader = ds.readable.getReader(); const chunks: Uint8Array[] = []; - const readChunks = async (): Promise => { + const _readChunks = async (): Promise => { const { done, value } = await reader.read(); if (done) { const combined = new Uint8Array(chunks.reduce((acc, c) => acc + c.length, 0)); @@ -661,7 +661,7 @@ export function decodeAmberResult(result: string): string { return new TextDecoder().decode(combined); } chunks.push(value); - return readChunks(); + return _readChunks(); }; // For sync usage, we'll just return the raw result diff --git a/src/pages/CoachDetailPage.tsx b/src/pages/CoachDetailPage.tsx index 8af3ff2..04f6dc1 100644 --- a/src/pages/CoachDetailPage.tsx +++ b/src/pages/CoachDetailPage.tsx @@ -21,7 +21,6 @@ import { useAuthor } from '@/hooks/useAuthor'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { DeleteEntityDialog } from '@/components/DeleteEntityDialog'; import { isAdminPubkey } from '@/lib/admins'; -import { genUserName } from '@/lib/genUserName'; import { COACH_SKILL_LABELS, COACH_SKILL_DESCRIPTIONS, FILMING_SERVICE_LABELS, FILMING_SERVICE_DESCRIPTIONS, FILMING_SKILL_LABELS, FILMING_SKILL_DESCRIPTIONS, EDITOR_SERVICE_LABELS, EDITOR_SERVICE_DESCRIPTIONS, EDITOR_SKILL_LABELS, EDITOR_SKILL_DESCRIPTIONS, PHOTO_SERVICE_LABELS, PHOTO_SERVICE_DESCRIPTIONS, PHOTO_CAMERA_LABELS, PHOTO_LENS_LABELS, PHOTO_LIGHTING_LABELS, PHOTO_SUPPORT_LABELS, PHOTO_STYLE_LABELS, BUILDER_SERVICE_LABELS, BUILDER_SERVICE_DESCRIPTIONS, BUILDER_SKILL_LABELS, BUILDER_SCALE_LABELS, ARTIST_SERVICE_LABELS, ARTIST_SERVICE_DESCRIPTIONS, ARTIST_MEDIUM_LABELS, ARTIST_TOOL_LABELS, GRAFFITI_STYLE_LABELS, GRAFFITI_STYLE_DESCRIPTIONS, GRAFFITI_MEDIUM_LABELS, GRAFFITI_CONTEXT_LABELS, TATTOO_STYLE_LABELS, TATTOO_STYLE_DESCRIPTIONS, TATTOO_METHOD_LABELS, TRAINER_FOCUS_LABELS, TRAINER_FOCUS_DESCRIPTIONS, TRAINER_INJURY_LABELS, TRAINER_CREDENTIAL_LABELS, MUSICIAN_GENRE_LABELS, MUSICIAN_INSTRUMENT_LABELS, JUDGE_FORMAT_LABELS, JUDGE_SPECIALTY_LABELS, JUDGE_LEVEL_LABELS, SKATE_COACH_KIND, SKATE_FILMER_KIND, SKATE_EDITOR_KIND, SKATE_PHOTOGRAPHER_KIND, SKATE_BUILDER_KIND, SKATE_ARTIST_KIND, SKATE_GRAFFITI_KIND, SKATE_TATTOO_KIND, SKATE_TRAINER_KIND, SKATE_MUSICIAN_KIND, SKATE_JUDGE_KIND } from '@/lib/types'; import { sanitizeUrl, sanitizeTel, sanitizeEmail, urlDomain } from '@/lib/sanitizeUrl'; import { OfficialBadge } from '@/components/OfficialBadge'; diff --git a/src/pages/CollectionDetailPage.tsx b/src/pages/CollectionDetailPage.tsx index 9014e6e..9a4c208 100644 --- a/src/pages/CollectionDetailPage.tsx +++ b/src/pages/CollectionDetailPage.tsx @@ -2,7 +2,7 @@ import { useParams, Link, useNavigate } from 'react-router-dom'; import { useSeoMeta } from '@unhead/react'; import { useNostr } from '@nostrify/react'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { Layout } from '@/components/Layout'; import { PageError } from '@/components/ErrorState'; import { SpotCard, SpotCardSkeleton } from '@/components/SpotCard'; @@ -51,7 +51,6 @@ export default function CollectionDetailPage() { const { deleteCollection, isPending: isDeleting } = useDeleteSpotCollection(); const { toast } = useToast(); const navigate = useNavigate(); - const queryClient = useQueryClient(); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [removingSpotId, setRemovingSpotId] = useState(null); diff --git a/src/pages/CommunityStatsPage.tsx b/src/pages/CommunityStatsPage.tsx index 0c2cb98..5269746 100644 --- a/src/pages/CommunityStatsPage.tsx +++ b/src/pages/CommunityStatsPage.tsx @@ -31,12 +31,6 @@ function labCraftTotal(s: { ); } -function formatSats(sats: number): string { - if (sats >= 1_000_000) return `${(sats / 1_000_000).toFixed(1)}M`; - if (sats >= 1_000) return `${Math.round(sats / 1_000)}k`; - return sats.toLocaleString(); -} - const CHART_TOOLTIP_STYLE = { backgroundColor: '#0d0d0d', border: '1px solid rgba(255,255,255,0.1)', diff --git a/src/pages/CreateListingPage.tsx b/src/pages/CreateListingPage.tsx index f2fac34..332c703 100644 --- a/src/pages/CreateListingPage.tsx +++ b/src/pages/CreateListingPage.tsx @@ -48,7 +48,7 @@ export default function CreateListingPage() { // Anti-spam restrictions const restrictions = useListingRestrictions(linkedSpot?.pubkey); const [feePaid, setFeePaid] = useState(false); - const [lastListingRecord, setLastListingRecord] = useLocalStorage<{ timestamp: number; spotOwnerPubkey?: string } | null>( + const [, setLastListingRecord] = useLocalStorage<{ timestamp: number; spotOwnerPubkey?: string } | null>( 'last-listing-record', null ); diff --git a/src/pages/CrewDetailPage.tsx b/src/pages/CrewDetailPage.tsx index 732dd67..cdc5646 100644 --- a/src/pages/CrewDetailPage.tsx +++ b/src/pages/CrewDetailPage.tsx @@ -33,14 +33,12 @@ import { ConfirmMembershipCard } from '@/components/ConfirmMembershipCard'; import { MemberVisibilityControl } from '@/components/MemberVisibilityControl'; import { LinkedLabCard } from '@/components/CrossLinkCards'; import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'; -import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog'; import { useCollectiveMembers } from '@/hooks/useCollectiveMembers'; import { useCrewRole } from '@/hooks/useCrewRole'; -import { useCrewModeration, useHideCrewPost } from '@/hooks/useCrewModeration'; +import { useHideCrewPost } from '@/hooks/useCrewModeration'; import { CrewInviteDialog } from '@/components/CrewInviteDialog'; import { DeleteEntityDialog } from '@/components/DeleteEntityDialog'; import { useToast } from '@/hooks/useToast'; -import { NoteContent } from '@/components/NoteContent'; import { useCrew } from '@/hooks/useCrews'; import { useCrewFeed } from '@/hooks/useCrewFeed'; import { useAuthor } from '@/hooks/useAuthor'; @@ -49,83 +47,9 @@ import { genUserName } from '@/lib/genUserName'; import { SKATE_CREW_KIND, SHOW_CREW_TREASURY, CREW_LOOKING_FOR_LABELS, type CrewRole } from '@/lib/types'; import { sanitizeUrl, urlDomain } from '@/lib/sanitizeUrl'; import NotFound from './NotFound'; -import { Users, MapPin, ArrowLeft, Calendar, Globe, Instagram, Edit, MessageSquare, Zap, ShieldCheck, EyeOff, Music } from 'lucide-react'; +import { Users, MapPin, ArrowLeft, Calendar, Globe, Instagram, Edit, MessageSquare, Zap, ShieldCheck, Music } from 'lucide-react'; import type { NostrEvent } from '@nostrify/nostrify'; -function FeedItem({ - event, - canModerate, - onHide, - isHiding, -}: { - event: NostrEvent; - canModerate?: boolean; - onHide?: (event: NostrEvent) => void; - isHiding?: boolean; -}) { - const author = useAuthor(event.pubkey); - const metadata = author.data?.metadata; - const name = metadata?.name ?? genUserName(event.pubkey); - const npub = nip19.npubEncode(event.pubkey); - - return ( -
-
- - - - {name.slice(0, 2).toUpperCase()} - - - - {name} - - - {new Date(event.created_at * 1000).toLocaleDateString()} - - {canModerate && onHide && ( - - - - - - - Hide this post? - - As a crew moderator you can hide this post from the crew feed for everyone. - The original note stays on Nostr — this only removes it from this crew's feed. - - - - Cancel - onHide(event)} - className="bg-red-600 hover:bg-red-700" - > - Hide post - - - - - )} -
-
- -
-
- ); -} - export default function CrewDetailPage() { const { pubkey, identifier } = useParams<{ pubkey: string; identifier: string }>(); const { data: crew, isLoading, error, refetch } = useCrew(identifier || '', pubkey); @@ -143,27 +67,21 @@ export default function CrewDetailPage() { // Feed = founder + listed members const feedAuthors = crew ? [crew.pubkey, ...crew.members] : []; - const { data: feed, isLoading: feedLoading } = useCrewFeed(feedAuthors); + const { data: feed } = useCrewFeed(feedAuthors); // Crew-hosted events (jams, comps, meetups). const { data: crewEvents } = useCrewEvents(crew?.pubkey, crew?.identifier); // Moderation — founder + admins can hide feed posts (NIP-32 labels). const crewCoord = crew ? `${SKATE_CREW_KIND}:${crew.pubkey}:${crew.identifier}` : ''; - const moderators = crew ? Array.from(new Set([crew.pubkey, ...crew.admins])) : []; - const { data: hiddenIds } = useCrewModeration({ - crewCoord, - moderators, - enabled: !!crew, - }); - const { mutateAsync: hidePost, isPending: isHiding } = useHideCrewPost(crewCoord); + const { mutateAsync: hidePost } = useHideCrewPost(crewCoord); // Unread dot on the Chat tab — cheap, member-only, no background decryption. const isCrewMember = !!user && !!crew && (user.pubkey === crew.pubkey || crew.members.includes(user.pubkey)); const { hasUnread: chatHasUnread } = useCrewChatUnread(crew ?? undefined, isCrewMember); - const handleHidePost = async (ev: NostrEvent) => { + const _handleHidePost = async (ev: NostrEvent) => { try { await hidePost({ postId: ev.id, postAuthor: ev.pubkey }); toast({ title: 'Post hidden', description: 'Removed from the crew feed for everyone.' }); diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 9b3ac7d..790f822 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -491,7 +491,6 @@ function LabProfileCard({ profile }: { profile: LabProfile }) { } function NewToNostrSection() { - const { t } = useTranslation(); const { user } = useCurrentUser(); // Don't show this section if user is already logged in diff --git a/src/pages/MapPage.tsx b/src/pages/MapPage.tsx index 0ad6a72..6e28479 100644 --- a/src/pages/MapPage.tsx +++ b/src/pages/MapPage.tsx @@ -172,7 +172,7 @@ function MiniStashCard({ item, onDelete }: { item: StashItem; onDelete: () => vo // Stash drawer component function StashDrawer() { const { user } = useCurrentUser(); - const { items, stats, isLoading, addItem, removeItem, isEncryptionAvailable } = useStash(); + const { items, stats, isLoading, removeItem, isEncryptionAvailable } = useStash(); const author = useAuthor(user?.pubkey || ''); const metadata = author.data?.metadata; const displayName = metadata?.name ?? genUserName(user?.pubkey || ''); @@ -625,7 +625,7 @@ export default function MapPage() { const showWelcomeBanner = !user && !welcomeDismissed; // Track Sasquatch panel open state so the Add Spot FAB can step aside - const [sasquatchPanelOpen, setSasquatchPanelOpen] = useState(false); + const [, setSasquatchPanelOpen] = useState(false); useEffect(() => { const handler = (e: Event) => { setSasquatchPanelOpen((e as CustomEvent<{ open: boolean }>).detail.open); @@ -771,7 +771,7 @@ export default function MapPage() { // Fetch BTC Map places when enabled - const { data: btcMapPlaces, isLoading: btcMapLoading, error: btcMapError } = useBtcMapPlaces({ + const { data: btcMapPlaces, isLoading: btcMapLoading } = useBtcMapPlaces({ lat: mapCenter.lat, lon: mapCenter.lon, radiusKm: 50, // 50km radius @@ -881,7 +881,7 @@ export default function MapPage() { }, [allLocations]); // Fetch weather data for all spots - const { data: weatherData, isLoading: weatherLoading } = useMultipleSpotWeather( + const { data: weatherData } = useMultipleSpotWeather( spotGeohashes, weatherEnabled ); diff --git a/src/pages/RiderCardPage.tsx b/src/pages/RiderCardPage.tsx index 24b92e2..fe9ca4d 100644 --- a/src/pages/RiderCardPage.tsx +++ b/src/pages/RiderCardPage.tsx @@ -119,7 +119,7 @@ function fillTextFit(ctx: CanvasRenderingContext2D, text: string, x: number, y: } // Draw a labeled row: small muted label above, value below -function drawLabeledRow( +function _drawLabeledRow( ctx: CanvasRenderingContext2D, label: string, value: string, x: number, y: number, maxW: number, @@ -553,7 +553,7 @@ function memberSince(createdAt: number) { } // Verification URL — scanning this on a phone opens the profile on skate-spots.org -function verifyUrl(pubkey: string) { +function _verifyUrl(pubkey: string) { if (!pubkey) return 'https://skate-spots.org'; return `https://skate-spots.org/${nip19.npubEncode(pubkey)}`; } @@ -1490,7 +1490,7 @@ export default function RiderCardPage() { } // ─── Inline award form (used on the Award tab) ──────────────────────────────── -function AwardBadgeInline({ issuerPubkey, onSuccess }: { issuerPubkey: string; onSuccess: () => void }) { +function AwardBadgeInline({ issuerPubkey: _issuerPubkey, onSuccess }: { issuerPubkey: string; onSuccess: () => void }) { const { mutate: publishEvent, isPending } = useNostrPublish(); const { toast } = useToast(); const [recipientNpub, setRecipientNpub] = useState(''); diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 0f62ab6..c9b9b9a 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -12,7 +12,6 @@ import { CVMHealthCheck } from '@/components/CVMHealthCheck'; import { LanguageSelector } from '@/components/LanguageToggle'; import { DesktopNavManager } from '@/components/DesktopNavManager'; import { MyDataTab } from '@/components/MyDataTab'; -import { useTranslation } from '@/contexts/LanguageContext'; import { useQueryClient } from '@tanstack/react-query'; import { useNostr } from '@nostrify/react'; import { NSchema as n } from '@nostrify/nostrify'; @@ -544,7 +543,6 @@ function RelaysScreen({ onBack }: { onBack: () => void }) { // ─── Appearance sub-screen ──────────────────────────────────────────────────── function AppearanceScreen({ onBack }: { onBack: () => void }) { - const { t } = useTranslation(); return (
@@ -1148,21 +1146,6 @@ export default function SettingsPage() { const handleNavigate = (s: Section) => setSection(s); const handleBack = () => setSection(null); - const sectionTitles: Record, string> = { - profile: 'Edit Profile', - follows: 'Follows', - nip05: 'NIP-05 Verification', - security: 'Security', - mydata: 'My Data', - language: 'Language', - appearance: 'Appearance', - relays: 'Relays', - crewnetwork: 'Crew Network', - wallet: 'Wallet', - stash: 'My Stash', - advanced: 'Advanced', - }; - return (