chore(lint): remove all explicit any + sweep dead imports

- Fix all 12 no-explicit-any (NPool, NostrEvent[], LabProfile, structural
  Cluster type, explicit SkateSpot cast) -> 0 remaining
- Remove unused imports/vars across 48 files (manual + a verified codemod for
  unused import specifiers only); tsc + tests + boot smoke all green
- Warning backlog: 182 -> 76 (remaining: ~55 no-unused-vars locals,
  14 react-hooks/exhaustive-deps, 7 react-refresh)
- AGENTS.md baseline updated
This commit is contained in:
SkateSpots 2026-09-26 21:40:42 +07:00
parent 30ef511e78
commit d1f8870379
49 changed files with 98 additions and 562 deletions

View file

@ -79,8 +79,9 @@ 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, **182 warnings**,
**86 tests**, build ok. `package.json` version **1.4.5**.
- **Baselines** (verified 2026-09-26): `npm test` → 0 errors, **76 warnings**
(mostly ~55 `no-unused-vars` + 14 `react-hooks/exhaustive-deps` + 7
`react-refresh`), **101 tests**, build ok. `package.json` version **1.4.5**.
- **Untracked local junk — do NOT commit**: `assets/`, `resources/`,
`cvm-server/`, `bun.lock`.

View file

@ -20,29 +20,11 @@ import { LabLinkField } from '@/components/LabLinkField';
import { isCrewVideoUrl, parseCrewVideo } from '@/lib/videoEmbed';
import { CrewSponsorPicker } from '@/components/crew/CrewSponsorPicker';
import { NofferField } from '@/components/NofferField';
import {
SKATE_CREW_KIND,
SKATE_SPOT_KIND,
SKATE_SHOP_KIND,
parseAddrCoord,
ZAP_GOAL_KIND,
CREW_VIBE_LABELS,
CREW_FOCUS_LABELS,
CREW_FOCUS_DESCRIPTIONS,
CREW_FOCUS_TAG,
CREW_LOOKING_FOR_OPTIONS,
CREW_ROLE_META,
CREW_ROLE_ORDER,
SHOW_CREW_TREASURY,
isValidNoffer,
type SkateCrew,
type CrewFocus,
type CrewRole,
} from '@/lib/types';
import { SKATE_CREW_KIND, SKATE_SPOT_KIND, SKATE_SHOP_KIND, parseAddrCoord, ZAP_GOAL_KIND, CREW_VIBE_LABELS, CREW_FOCUS_LABELS, CREW_FOCUS_DESCRIPTIONS, CREW_FOCUS_TAG, CREW_LOOKING_FOR_OPTIONS, CREW_ROLE_META, CREW_ROLE_ORDER, SHOW_CREW_TREASURY, isValidNoffer, type SkateCrew, type CrewFocus, type CrewRole } from '@/lib/types';
import { useCrewGoal } from '@/hooks/useCrewGoal';
import { useAppContext } from '@/hooks/useAppContext';
import { cn } from '@/lib/utils';
import { Users, Upload, X, Loader2, MapPin, Plus, ShieldCheck, AtSign, HardHat, Camera, GraduationCap, Sparkles, Target, Megaphone, Music, Palette, Dumbbell, Eye, Store, Lock, Film, Check, ArrowRight, ArrowLeft as ArrowLeftIcon, Server } from 'lucide-react';
import { Users, Upload, X, Loader2, MapPin, Plus, ShieldCheck, AtSign, HardHat, Camera, GraduationCap, Sparkles, Target, Megaphone, Music, Palette, Dumbbell, Eye, Store, Film, Check, ArrowRight, ArrowLeft as ArrowLeftIcon, Server } from 'lucide-react';
const FOCUS_ORDER: CrewFocus[] = ['mixed', 'builder', 'photo', 'coaching', 'art', 'music', 'wellness'];
const FOCUS_ICONS: Record<CrewFocus, typeof Users> = {

View file

@ -3,15 +3,15 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Badge } from '@/components/ui/badge';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Skeleton } from '@/components/ui/skeleton';
import { useFollowing, useFollowers, useFollowActions } from '@/hooks/useFollowing';
import { useAuthor } from '@/hooks/useAuthor';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { genUserName } from '@/lib/genUserName';
import { Users, UserPlus, UserMinus, Loader2, AlertCircle } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Users, UserPlus, UserMinus, Loader2 } from 'lucide-react';
function FollowingUserCard({ pubkey, onUnfollow }: { pubkey: string; onUnfollow: (pubkey: string) => void }) {
const author = useAuthor(pubkey);

View file

@ -5,25 +5,12 @@ import { useAuthor } from '@/hooks/useAuthor';
import { useToast } from '@/hooks/useToast';
import { genUserName } from '@/lib/genUserName';
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
import { Progress } from '@/components/ui/progress';
import { Badge } from '@/components/ui/badge';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription
} from '@/components/ui/dialog';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import {
Heart,
CheckCircle2,
Sparkles,
UserPlus,
Crown,
Zap,
} from 'lucide-react';
import { CheckCircle2, Sparkles, Crown, Zap } from 'lucide-react';
// The founder's npub - decode to hex pubkey
const FOUNDER_PUBKEY = '20e7c953439e66f3882ab96fe0faa8ba246d6fb12c03b0cb4e2dc4623b8bcb21';

View file

@ -1,5 +1,5 @@
import { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { nip19 } from 'nostr-tools';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
@ -15,37 +15,9 @@ 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 {
MessageCircle,
MapPin,
Search,
Tag,
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';
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';
import { ReportDialog } from '@/components/ReportDialog';
import { formatDistanceToNow } from 'date-fns';

View file

@ -5,7 +5,6 @@ import { cn } from '@/lib/utils';
import { isNativePlatform } from '@/lib/platform';
import { useNavPreferences, useDesktopNavPreferences, type NavTab } from '@/hooks/useNavPreferences';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Sheet, SheetContent, SheetTrigger, SheetTitle } from '@/components/ui/sheet';
import {
DropdownMenu,
@ -25,7 +24,6 @@ import {
MapPin,
Calendar,
Menu,
Home,
Wallet,
Settings,
GraduationCap,
@ -36,12 +34,10 @@ import {
MessageCircle,
LogOut,
User,
LogIn,
Plus,
CheckCircle2,
Database,
Package,
Zap,
Heart,
CreditCard,
Radio,

View file

@ -1,26 +1,13 @@
import { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { nip19 } from 'nostr-tools';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
import { ImageWithFallback } from '@/components/ImageWithFallback';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogFooter,
} from '@/components/ui/dialog';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuSeparator,
} from '@/components/ui/dropdown-menu';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from '@/components/ui/dropdown-menu';
import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label';
import { useAuthor } from '@/hooks/useAuthor';
@ -40,25 +27,7 @@ import { useListingTrade, useTradeAttestation, useTradeReputation, useListingTra
import { DeleteEntityDialog } from '@/components/DeleteEntityDialog';
import { genUserName } from '@/lib/genUserName';
import { TrustBadge } from '@/components/TrustBadge';
import {
MessageCircle,
Clock,
Search,
Tag,
Flag,
MoreVertical,
ShieldCheck,
ShieldAlert,
Calendar,
Package,
AlertTriangle,
CheckCircle,
RotateCcw,
Trash2,
Loader2,
Send,
Lock,
} from 'lucide-react';
import { MessageCircle, Clock, Search, Tag, Flag, MoreVertical, ShieldCheck, Calendar, Package, AlertTriangle, CheckCircle, RotateCcw, Trash2, Loader2, Send, Lock } from 'lucide-react';
import { formatDistanceToNow } from 'date-fns';
import type { MarketplaceItem } from '@/lib/types';
import { GEAR_CONDITIONS, GEAR_CATEGORIES, PRICE_TYPES, LISTING_REPORT_REASONS, formatPrice } from '@/lib/types';

View file

@ -1,13 +1,11 @@
import { useMemo } from 'react';
import { Card, CardContent } from '@/components/ui/card';
import { Progress } from '@/components/ui/progress';
import {
Zap,
Camera,
FileText,
MapPin,
Phone,
Globe,
Clock,
Check,
Circle,

View file

@ -8,7 +8,7 @@
*/
import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { ScrollArea } from '@/components/ui/scroll-area';
import { X, Minimize2, HelpCircle, Send, Loader2, Wifi, WifiOff } from 'lucide-react';

View file

@ -1,15 +1,6 @@
import { Card, CardContent } from '@/components/ui/card';
import { Progress } from '@/components/ui/progress';
import {
Zap,
Check,
Circle,
Camera,
FileText,
MapPin,
Phone,
Clock,
} from 'lucide-react';
import { Zap, Check, Circle, Camera, FileText, MapPin, Phone, Clock } from 'lucide-react';
import { cn } from '@/lib/utils';
interface ShopBountyCardProps {

View file

@ -1,11 +1,5 @@
import { ArrowUpDown, Clock, TrendingUp, MapPin, MessageCircle, Zap, Shield } from 'lucide-react';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { ArrowUpDown, Clock, TrendingUp, MapPin, Zap, Shield } from 'lucide-react';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { cn } from '@/lib/utils';
export type SortOption =

View file

@ -3,9 +3,6 @@ import L from 'leaflet';
import 'leaflet.markercluster';
import ngeohash from 'ngeohash';
import { useNavigate } from 'react-router-dom';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { MapPin } from 'lucide-react';
import type { SkateSpot, MarketplaceItem, SkateTour, SkateEvent, SkateCrew } from '@/lib/types';
import { SPOT_TYPE_LABELS, formatPrice } from '@/lib/types';
import type { SpotWeatherData } from '@/hooks/useSpotWeather';
@ -932,7 +929,7 @@ export function SpotMap({
showCoverageOnHover: false, // don't draw polygons on hover
spiderfyOnMaxZoom: true, // spread out overlapping pins at max zoom
removeOutsideVisibleBounds: true,
iconCreateFunction: (cluster: any) => {
iconCreateFunction: (cluster: { getChildCount: () => number }) => {
const count = cluster.getChildCount();
return L.divIcon({
html: `

View file

@ -5,12 +5,7 @@ import { Badge } from '@/components/ui/badge';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Skeleton } from '@/components/ui/skeleton';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import { Route, Clock, MapPin, Users, Zap, Globe, Calendar, Trophy, Skull, MoreVertical, Flag } from 'lucide-react';
import { useAuthor } from '@/hooks/useAuthor';
import { useCurrentUser } from '@/hooks/useCurrentUser';

View file

@ -1,24 +1,8 @@
import { useState, forwardRef } from 'react';
import { Wallet, Plus, Trash2, Zap, Globe, WalletMinimal, CheckCircle, X, ShieldAlert } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog';
import {
Drawer,
DrawerContent,
DrawerDescription,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
DrawerClose,
} from '@/components/ui/drawer';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle, DrawerTrigger, DrawerClose } from '@/components/ui/drawer';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';

View file

@ -8,8 +8,8 @@ import { Button } from '@/components/ui/button';
import { useWhosSkatingAtSpot, SKATING_STATUSES } from '@/hooks/useUserStatus';
import { useAuthor } from '@/hooks/useAuthor';
import { genUserName } from '@/lib/genUserName';
import { formatDistanceToNow } from 'date-fns';
import { Users, MessageCircle, Zap } from 'lucide-react';
import { Users, MessageCircle } from 'lucide-react';
import { cn } from '@/lib/utils';
interface WhosSkatingProps {

View file

@ -13,7 +13,7 @@ import { useCrewZap, splitAmount, type CrewZapResult } from '@/hooks/useCrewZap'
import { useToast } from '@/hooks/useToast';
import { genUserName } from '@/lib/genUserName';
import { Zap, Check, Copy, Loader2, X, Users, AlertCircle } from 'lucide-react';
import { cn } from '@/lib/utils';
const PRESETS = [210, 500, 1000, 2100, 5000];

View file

@ -8,12 +8,7 @@ import { toast } from '@/hooks/useToast';
import { useLoginActions } from '@/hooks/useLoginActions';
import { nip19 } from 'nostr-tools';
import { cn } from '@/lib/utils';
import {
generateMnemonicPhrase,
privateKeyFromMnemonic,
mnemonicToWords,
wordsToMnemonic
} from '@/lib/nip06';
import { generateMnemonicPhrase, privateKeyFromMnemonic, mnemonicToWords } from '@/lib/nip06';
// qrcode imported lazily in async function
interface MnemonicSignupDialogProps {

View file

@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react';
import { useEffect, useRef } from 'react';
interface QRCodeCanvasProps {
value: string;

View file

@ -2,21 +2,7 @@ import { useState } from 'react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Alert, AlertDescription } from '@/components/ui/alert';
import {
Shield,
Eye,
EyeOff,
Wallet,
AlertTriangle,
ChevronDown,
ChevronUp,
Nut,
Zap,
Globe,
Lock,
CheckCircle2,
Info,
} from 'lucide-react';
import { Shield, Eye, AlertTriangle, ChevronDown, ChevronUp, Nut, Zap, Globe, Lock, CheckCircle2, Info } from 'lucide-react';
import { cn } from '@/lib/utils';
interface LightningPrivacyTipsProps {

View file

@ -1,4 +1,4 @@
import { useMemo } from 'react';
import { useNostr } from '@nostrify/react';
import { useQuery } from '@tanstack/react-query';
import type { NostrEvent } from '@nostrify/nostrify';

View file

@ -1,4 +1,4 @@
import { useCallback, useMemo } from 'react';
import { useCallback } from 'react';
import { useNostr } from '@nostrify/react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { nip44, nip19, generateSecretKey, finalizeEvent, getEventHash } from 'nostr-tools';

View file

@ -1,5 +1,6 @@
import { useNostr } from '@nostrify/react';
import { useQuery } from '@tanstack/react-query';
import type { NostrEvent } from '@nostrify/nostrify';
import { useAppContext } from '@/hooks/useAppContext';
const REPORT_KIND = 1984; // NIP-56 Report kind
@ -38,7 +39,7 @@ export function useListingReports(eventId: string, pubkey: string) {
.filter(r => r.read)
.map(r => r.url);
const allEvents: any[] = [];
const allEvents: NostrEvent[] = [];
for (const relayUrl of readRelays) {
try {
@ -60,7 +61,7 @@ export function useListingReports(eventId: string, pubkey: string) {
}
// Deduplicate by event ID
const eventMap = new Map<string, any>();
const eventMap = new Map<string, NostrEvent>();
for (const event of allEvents) {
if (!eventMap.has(event.id)) {
eventMap.set(event.id, event);
@ -140,7 +141,7 @@ export function useBatchListingReports(eventIds: string[]) {
.filter(r => r.read)
.map(r => r.url);
const allEvents: any[] = [];
const allEvents: NostrEvent[] = [];
for (const relayUrl of readRelays) {
try {
@ -162,7 +163,7 @@ export function useBatchListingReports(eventIds: string[]) {
}
// Deduplicate by event ID
const eventMap = new Map<string, any>();
const eventMap = new Map<string, NostrEvent>();
for (const event of allEvents) {
if (!eventMap.has(event.id)) {
eventMap.set(event.id, event);

View file

@ -4,7 +4,7 @@ import { useNostr } from '@nostrify/react';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { MARKETPLACE_ITEM_KIND, SKATE_SPOT_KIND, SKATE_RELAY } from '@/lib/types';
import type { NostrEvent } from '@nostrify/nostrify';
// Platform fee destination
export const PLATFORM_LIGHTNING_ADDRESS = 'skatespots@minibits.cash';

View file

@ -1,4 +1,4 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query';
import { useNostrPublish } from '@/hooks/useNostrPublish';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { MARKETPLACE_ITEM_KIND } from '@/lib/types';

View file

@ -3,7 +3,7 @@ import { useMutation, type UseMutationResult } from "@tanstack/react-query";
import { useCurrentUser } from "./useCurrentUser";
import type { NostrEvent } from "@nostrify/nostrify";
import type { NostrEvent, NPool } from "@nostrify/nostrify";
/**
* Publishes a Nostr event with retry logic and improved error handling
@ -48,7 +48,7 @@ export function useNostrPublish(): UseMutationResult<NostrEvent> {
* Publishes event with retry logic and partial success handling
*/
async function publishEventWithRetry(
nostr: any,
nostr: NPool,
event: NostrEvent,
maxRetries = 1,
timeoutMs = 15000

View file

@ -2,7 +2,7 @@ import { useNostr } from '@nostrify/react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useCurrentUser } from './useCurrentUser';
import { useNostrPublish } from './useNostrPublish';
import { useCashu } from './wallet/useCashu';
import { useToast } from './useToast';
import type { NostrEvent } from '@nostrify/nostrify';

View file

@ -1,5 +1,6 @@
import { useNostr } from '@nostrify/react';
import { useQuery } from '@tanstack/react-query';
import type { NostrEvent } from '@nostrify/nostrify';
import { MARKETPLACE_ITEM_KIND } from '@/lib/types';
import { useAppContext } from '@/hooks/useAppContext';
@ -39,8 +40,8 @@ export function useSellerInfo(pubkey: string | undefined) {
.map(r => r.url);
// Query profile (kind 0) and marketplace listings in parallel
const profileEventsPromise: Promise<any[]>[] = [];
const listingEventsPromise: Promise<any[]>[] = [];
const profileEventsPromise: Promise<NostrEvent[]>[] = [];
const listingEventsPromise: Promise<NostrEvent[]>[] = [];
for (const relayUrl of readRelays) {
try {
@ -100,7 +101,7 @@ export function useSellerInfo(pubkey: string | undefined) {
}
// Deduplicate listings by d-tag
const listingMap = new Map<string, any>();
const listingMap = new Map<string, NostrEvent>();
for (const event of listingEvents) {
const d = event.tags.find(([name]: [string]) => name === 'd')?.[1];
if (d) {

View file

@ -1,5 +1,5 @@
import { useQuery } from '@tanstack/react-query';
import { useNostr } from '@nostrify/react';
import { useSkateRelays } from '@/hooks/useSkateRelays';
/**

View file

@ -15,19 +15,7 @@ import { useSkateShops } from '@/hooks/useSkateShops';
import { useSkateSpots } from '@/hooks/useSkateSpots';
import { genUserName } from '@/lib/genUserName';
import { nip19 } from 'nostr-tools';
import {
Trophy,
Medal,
Crown,
Store,
MapPin,
Zap,
Camera,
FileText,
Users,
ChevronRight,
Sparkles,
} from 'lucide-react';
import { Trophy, Medal, Crown, Store, MapPin, Zap, Camera, FileText, Users, Sparkles } from 'lucide-react';
import { cn } from '@/lib/utils';
// Leaderboard entry component

View file

@ -1,4 +1,4 @@
import { useMemo } from 'react';
import { useParams, Link, useNavigate } from 'react-router-dom';
import { useSeoMeta } from '@unhead/react';
import { useNostr } from '@nostrify/react';
@ -11,36 +11,14 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Skeleton } from '@/components/ui/skeleton';
import { Badge } from '@/components/ui/badge';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
import { useToast } from '@/hooks/useToast';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useAppContext } from '@/hooks/useAppContext';
import {
useSpotCollection,
useRemoveSpotFromCollection,
useDeleteSpotCollection,
} from '@/hooks/useSpotCollections';
import { useSpotCollection, useRemoveSpotFromCollection, useDeleteSpotCollection } from '@/hooks/useSpotCollections';
import type { NostrEvent } from '@nostrify/nostrify';
import { SKATE_SPOT_KIND, parseSkateSpot, type SkateSpot } from '@/lib/types';
import {
ArrowLeft,
FolderOpen,
MapPin,
Calendar,
Trash2,
X,
Share2,
Loader2,
AlertTriangle,
} from 'lucide-react';
import { ArrowLeft, FolderOpen, MapPin, Calendar, Trash2, X, Share2, Loader2, AlertTriangle } from 'lucide-react';
import NotFound from './NotFound';
import { useState } from 'react';
@ -104,7 +82,7 @@ export default function CollectionDetailPage() {
if (spotFilters.length === 0) return [];
const allEvents: any[] = [];
const allEvents: NostrEvent[] = [];
// Query each relay for all spots
for (const relayUrl of readRelays) {

View file

@ -12,22 +12,8 @@ import { cn } from '@/lib/utils';
const ANGOR_PROJECT_URL = 'https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z';
import { SKATE_RELAY } from '@/lib/types';
import {
AreaChart, Area,
BarChart, Bar,
XAxis, YAxis,
CartesianGrid, Tooltip,
ResponsiveContainer,
PieChart, Pie, Cell, Legend,
} from 'recharts';
import {
MapPin, Store, Calendar, GraduationCap,
Video, Scissors, Route, Users, Users2,
Camera, Hammer,
TrendingUp, Radio, Zap, ExternalLink,
Trophy, FlaskConical,
Palette, SprayCan, PenTool, Dumbbell, Music, Gavel,
} from 'lucide-react';
import { AreaChart, Area, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell, Legend } from 'recharts';
import { MapPin, Store, Calendar, GraduationCap, Video, Scissors, Route, Users, Users2, Camera, Hammer, TrendingUp, Radio, Zap, ExternalLink, Trophy, FlaskConical, Palette, SprayCan, PenTool, Dumbbell, Music, Gavel } from 'lucide-react';
// ─── Helpers ─────────────────────────────────────────────────────────────────

View file

@ -9,51 +9,20 @@ import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { useNostrPublish } from '@/hooks/useNostrPublish';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useUploadFile } from '@/hooks/useUploadFile';
import { useToast } from '@/hooks/useToast';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { useSkateSpot, useSkateSpots } from '@/hooks/useSkateSpots';
import { useListingRestrictions, LISTING_FEE_SATS, recordListingCreation } from '@/hooks/useListingRestrictions';
import { useListingRestrictions, recordListingCreation } from '@/hooks/useListingRestrictions';
import { LoginArea } from '@/components/auth/LoginArea';
import { Nip05Required } from '@/components/Nip05Required';
import { SpamFeePayment } from '@/components/SpamFeePayment';
import {
MARKETPLACE_ITEM_KIND,
GEAR_CATEGORIES,
GEAR_CONDITIONS,
PRICE_TYPES,
LISTING_TYPES,
SIZE_OPTIONS,
TRUCK_HEIGHTS,
WHEEL_HARDNESS,
EXPIRATION_OPTIONS,
CURRENCY_OPTIONS,
CATEGORY_REQUIRED_FIELDS,
} from '@/lib/types';
import {
ShoppingBag,
Upload,
X,
Loader2,
ArrowLeft,
MapPin,
AlertTriangle,
CheckCircle,
Search,
Clock,
Shield,
Zap,
} from 'lucide-react';
import ngeohash from 'ngeohash';
import { MARKETPLACE_ITEM_KIND, GEAR_CATEGORIES, GEAR_CONDITIONS, PRICE_TYPES, SIZE_OPTIONS, TRUCK_HEIGHTS, WHEEL_HARDNESS, EXPIRATION_OPTIONS, CURRENCY_OPTIONS, CATEGORY_REQUIRED_FIELDS } from '@/lib/types';
import { ShoppingBag, Upload, X, Loader2, ArrowLeft, MapPin, AlertTriangle, CheckCircle, Search, Clock, Shield, Zap } from 'lucide-react';
export default function CreateListingPage() {
useSeoMeta({

View file

@ -21,32 +21,7 @@ import { Nip05Required } from '@/components/Nip05Required';
import { FeaturedUpgrade } from '@/components/FeaturedEventUpgrade';
import { usePlatformFee } from '@/hooks/usePlatformFee';
import { SKATE_TOUR_KIND, TOUR_SKILL_LEVELS, TOUR_SPOT_TYPES, TOUR_CATEGORIES, type TourCategory, type DestructionChallenge, type SkateTour } from '@/lib/types';
import {
Route,
Upload,
X,
Loader2,
ArrowLeft,
MapPin,
Clock,
Users,
Zap,
Globe,
Info,
ChevronDown,
Store,
Percent,
Plane,
Car,
Skull,
Trophy,
Target,
Plus,
Trash2,
Calendar,
Eye,
EyeOff,
} from 'lucide-react';
import { Route, Upload, X, Loader2, ArrowLeft, MapPin, Clock, Users, Zap, Globe, Info, ChevronDown, Store, Percent, Plane, Car, Skull, Trophy, Target, Plus, Trash2, Calendar, EyeOff } from 'lucide-react';
import { Link } from 'react-router-dom';
import { cn } from '@/lib/utils';

View file

@ -33,17 +33,7 @@ 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 { 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';
@ -56,9 +46,8 @@ import { useCrewFeed } from '@/hooks/useCrewFeed';
import { useAuthor } from '@/hooks/useAuthor';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { genUserName } from '@/lib/genUserName';
import { SKATE_CREW_KIND, SKATE_SPOT_KIND, SHOW_CREW_TREASURY, CREW_LOOKING_FOR_LABELS, type CrewRole } from '@/lib/types';
import { SKATE_CREW_KIND, SHOW_CREW_TREASURY, CREW_LOOKING_FOR_LABELS, type CrewRole } from '@/lib/types';
import { sanitizeUrl, urlDomain } from '@/lib/sanitizeUrl';
import { cn } from '@/lib/utils';
import NotFound from './NotFound';
import { Users, MapPin, ArrowLeft, Calendar, Globe, Instagram, Edit, MessageSquare, Zap, ShieldCheck, EyeOff, Music } from 'lucide-react';
import type { NostrEvent } from '@nostrify/nostrify';

View file

@ -7,7 +7,7 @@ import { PageError } from '@/components/ErrorState';
import { SpotMap } from '@/components/SpotMap';
import { RouteDialog } from '@/components/RouteDialog';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Skeleton } from '@/components/ui/skeleton';
import { Button } from '@/components/ui/button';
@ -29,20 +29,7 @@ import { cn } from '@/lib/utils';
import { EVENT_TYPE_LABELS, SKATE_CREW_KIND, SKATE_MUSICIAN_KIND } from '@/lib/types';
import { Users } from 'lucide-react';
import NotFound from './NotFound';
import {
Calendar,
Clock,
MapPin,
ArrowLeft,
Share2,
Navigation,
CalendarPlus,
Pencil,
Music,
Megaphone,
XCircle,
CalendarClock,
} from 'lucide-react';
import { Calendar, Clock, MapPin, ArrowLeft, Share2, Navigation, CalendarPlus, Pencil, Music, Megaphone, XCircle, CalendarClock } from 'lucide-react';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useToast } from '@/hooks/useToast';

View file

@ -3,45 +3,21 @@ import { useSeoMeta } from '@unhead/react';
import { Link } from 'react-router-dom';
import { Layout } from '@/components/Layout';
import { PageHeader } from '@/components/PageHeader';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Input } from '@/components/ui/input';
import { Skeleton } from '@/components/ui/skeleton';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuCheckboxItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { DropdownMenu, DropdownMenuContent, DropdownMenuCheckboxItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import { useMarketplaceItems } from '@/hooks/useMarketplace';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useBatchTrustScores } from '@/hooks/useBatchTrustScores';
import { useBatchSellerSales } from '@/hooks/useSellerSales';
import { useFollowList } from '@/hooks/useFollowList';
import { GearSwapItemCard } from '@/components/GearSwapItemCard';
import { GEAR_CATEGORIES, type MarketplaceItem } from '@/lib/types';
import {
ShoppingCart,
Plus,
Search,
Filter,
ArrowUpDown,
Users,
ShieldCheck,
UserCheck,
AlertCircle,
Loader2,
} from 'lucide-react';
import { GEAR_CATEGORIES } from '@/lib/types';
import { ShoppingCart, Plus, Search, Filter, ArrowUpDown, Users, ShieldCheck, UserCheck, AlertCircle } from 'lucide-react';
type SortOption = 'newest' | 'price_low' | 'price_high' | 'trust';
type TrustFilter = 'all' | 'verified' | 'trusted' | 'following';

View file

@ -9,7 +9,7 @@ import { Card, CardContent } from '@/components/ui/card';
import { LoginArea } from '@/components/auth/LoginArea';
import { useSkateSpots } from '@/hooks/useSkateSpots';
import { useUpcomingSkateEvents } from '@/hooks/useSkateEvents';
import { useLabProfiles } from '@/hooks/useLabProfiles';
import { useLabProfiles, type LabProfile } from '@/hooks/useLabProfiles';
import { useZapLeaderboard } from '@/hooks/useZapLeaderboard';
import { SKATE_SPOT_KIND, type SkateSpot } from '@/lib/types';
import { useCurrentUser } from '@/hooks/useCurrentUser';
@ -417,7 +417,7 @@ function TheLabSection() {
);
}
function LabProfileCard({ profile }: { profile: any }) {
function LabProfileCard({ profile }: { profile: LabProfile }) {
const author = useAuthor(profile.pubkey);
const metadata = author.data?.metadata;
const displayName = metadata?.name ?? genUserName(profile.pubkey);

View file

@ -13,10 +13,8 @@ import { useZapTotals, zapTargetKey } from '@/hooks/useZapTotals';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Badge } from '@/components/ui/badge';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, SheetClose } from '@/components/ui/sheet';
import { Card, CardContent } from '@/components/ui/card';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet';
import { Skeleton } from '@/components/ui/skeleton';
import { Progress } from '@/components/ui/progress';
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
@ -43,7 +41,7 @@ import { useLocalStorage } from '@/hooks/useLocalStorage';
import { genUserName } from '@/lib/genUserName';
import { useTranslation } from '@/contexts/LanguageContext';
import { SPOT_CATEGORIES, SPOT_TYPE_LABELS, SHELTER_INFO } from '@/lib/types';
import type { SkateSpot, SkateShop, SkateTour } from '@/lib/types';
import type { SkateSpot } from '@/lib/types';
import ngeohash from 'ngeohash';
import {
Search,
@ -58,10 +56,7 @@ import {
Target,
Star,
Zap,
Lock,
Users,
ArrowRightLeft,
Crown,
Shield,
Trash2,
AlertTriangle,
@ -74,7 +69,6 @@ import {
LocateFixed,
LocateOff,
Store,
Info,
Layers,
Calendar,
MessageCircle,

View file

@ -2,17 +2,8 @@ import { useSeoMeta } from '@unhead/react';
import { Layout } from '@/components/Layout';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import {
ShoppingBag,
ExternalLink,
Package,
DollarSign,
Shield,
Zap,
Store,
ShoppingCart,
} from 'lucide-react';
import { ShoppingBag, ExternalLink, Package, DollarSign, Shield, Zap, Store } from 'lucide-react';
export default function MarketplacePage() {
useSeoMeta({

View file

@ -26,34 +26,7 @@ import { cn } from '@/lib/utils';
import { SKATER_STANCES, SKATER_STYLES, SKATER_LEVELS, NEWSLETTER_KIND } from '@/lib/types';
import { NewsletterIssueView } from '@/components/NewsletterIssueView';
import NotFound from './NotFound';
import {
MapPin,
Store,
MessageCircle,
Globe,
Zap,
Calendar,
ExternalLink,
Copy,
Check,
ShieldCheck,
Instagram,
Share2,
Users,
Crown,
Bot,
Pencil,
Package,
Tag,
ArrowRightLeft,
Bitcoin,
Award,
MessageSquareLock,
PersonStanding,
Sparkles,
Home,
Clock,
} from 'lucide-react';
import { MapPin, Store, MessageCircle, Globe, Zap, ExternalLink, Copy, Check, ShieldCheck, Instagram, Share2, Users, Crown, Bot, Pencil, Package, Tag, ArrowRightLeft, Bitcoin, Award, MessageSquareLock, PersonStanding, Sparkles, Home, Clock } from 'lucide-react';
import { useState, type ReactNode } from 'react';
import { UserStatusIndicator } from '@/components/UserStatusIndicator';
import { ShareProfileDialog } from '@/components/ShareProfileDialog';

View file

@ -2,7 +2,7 @@ import { useState } from 'react';
import { useSeoMeta } from '@unhead/react';
import { Link } from 'react-router-dom';
import { Layout } from '@/components/Layout';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog';
import { useCurrentUser } from '@/hooks/useCurrentUser';
@ -13,30 +13,7 @@ import { WalletModal } from '@/components/WalletModal';
import { RelayEducation } from '@/components/onboarding/RelayEducation';
import { useToast } from '@/hooks/useToast';
import { cn } from '@/lib/utils';
import {
CheckCircle2,
Globe,
Shield,
Video,
Zap,
MapPin,
Calendar,
GraduationCap,
AlertCircle,
ExternalLink,
Wallet,
ChevronDown,
Nut,
BookOpen,
ShoppingBag,
Package,
Key,
Smartphone,
MessageCircle,
Lock,
Users,
Download,
} from 'lucide-react';
import { CheckCircle2, Globe, Shield, Zap, MapPin, Calendar, GraduationCap, AlertCircle, ExternalLink, Wallet, ChevronDown, Nut, BookOpen, ShoppingBag, Package, Key, MessageCircle, Lock, Users, Download } from 'lucide-react';
import { FounderFollow } from '@/components/FounderFollow';
// ─── Accordion FAQ ────────────────────────────────────────────────────────────

View file

@ -3,14 +3,14 @@ import { useMemo } from 'react';
import { Layout } from '@/components/Layout';
import { Card, CardContent } from '@/components/ui/card';
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
import { Badge } from '@/components/ui/badge';
import { useSkateSpots } from '@/hooks/useSkateSpots';
import { useSkateEvents } from '@/hooks/useSkateEvents';
import { useAuthor } from '@/hooks/useAuthor';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useTrustScore } from '@/hooks/useTrustScore';
import { genUserName } from '@/lib/genUserName';
import { Trophy, MapPin, Calendar, Zap, Medal } from 'lucide-react';
import { Trophy, Medal } from 'lucide-react';
import { cn } from '@/lib/utils';
function ContributorRow({ pubkey, spots, events, rank }: { pubkey: string; spots: number; events: number; rank: number }) {

View file

@ -39,23 +39,7 @@ import { useQuery } from '@tanstack/react-query';
import { genUserName } from '@/lib/genUserName';
import { cn } from '@/lib/utils';
import type { NostrEvent } from '@nostrify/nostrify';
import {
Printer,
Loader2,
Share2,
Download,
Check,
Copy,
Award,
Zap,
Info,
Palette,
Shield,
ChevronUp,
ChevronDown,
User,
Building2,
} from 'lucide-react';
import { Printer, Loader2, Share2, Download, Check, Copy, Award, Zap, Info, Palette, Shield, ChevronUp, ChevronDown, User, Building2 } from 'lucide-react';
// ─── Card canvas renderer ─────────────────────────────────────────────────────
// Draws the card entirely via Canvas 2D API — 100% reliable export,
// no CSS capture, no scaling issues, no background-stripping.

View file

@ -4,7 +4,7 @@ import { Layout } from '@/components/Layout';
import { EditProfileForm } from '@/components/EditProfileForm';
import { SkaterDirectoryCard } from '@/components/SkaterDirectoryCard';
import { RelayListManager } from '@/components/RelayListManager';
import { FollowListManager } from '@/components/FollowListManager';
import { WalletModal } from '@/components/WalletModal';
import { SecuritySettings } from '@/components/SecuritySettings';
import { RelatrSettings } from '@/components/RelatrSettings';
@ -27,30 +27,7 @@ import { toast } from '@/hooks/useToast';
import { cn } from '@/lib/utils';
import { NIP05_PROVIDERS } from '@/lib/nip05Providers';
import QRCode from 'qrcode';
import {
User,
Radio,
Wallet,
Wrench,
RotateCcw,
Shield,
ExternalLink,
Languages,
RefreshCw,
AlertCircle,
Database,
Package,
ChevronRight,
ChevronLeft,
Network,
Copy,
Check,
Smartphone,
Download,
Globe,
Zap,
WifiOff,
} from 'lucide-react';
import { User, Radio, Wallet, Wrench, RotateCcw, Shield, ExternalLink, Languages, RefreshCw, AlertCircle, Database, Package, ChevronRight, ChevronLeft, Network, Copy, Check, Smartphone, Download, Globe, Zap, WifiOff } from 'lucide-react';
// ─── Types ────────────────────────────────────────────────────────────────────

View file

@ -9,6 +9,7 @@ import { ImageWithFallback } from '@/components/ImageWithFallback';
import { ImageLightbox } from '@/components/ImageLightbox';
import { SpotMap } from '@/components/SpotMap';
import { RouteDialog } from '@/components/RouteDialog';
import type { SkateSpot } from '@/lib/types';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
@ -441,7 +442,7 @@ export default function ShopDetailPage() {
<CardContent>
<div className="aspect-square rounded-lg overflow-hidden">
<SpotMap
spots={[spotForMap as any]}
spots={[spotForMap as unknown as SkateSpot]}
center={coordinates ? [coordinates.lat, coordinates.lng] : undefined}
zoom={15}
className="h-full"

View file

@ -4,17 +4,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Alert, AlertDescription } from '@/components/ui/alert';
import {
Smartphone,
Monitor,
Shield,
ExternalLink,
Star,
CheckCircle2,
Info,
Apple,
Chrome,
} from 'lucide-react';
import { Smartphone, Shield, ExternalLink, Star, CheckCircle2, Info, Apple, Chrome } from 'lucide-react';
// Platform detection
const isAndroid = typeof navigator !== 'undefined' && /Android/i.test(navigator.userAgent);

View file

@ -2,51 +2,20 @@ import { useState } from 'react';
import { Link } from 'react-router-dom';
import { useSeoMeta } from '@unhead/react';
import { Layout } from '@/components/Layout';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Card, CardContent, CardHeader } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Skeleton } from '@/components/ui/skeleton';
import { Badge } from '@/components/ui/badge';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
} from '@/components/ui/dialog';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
import { useToast } from '@/hooks/useToast';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import {
useMySpotCollections,
useCreateSpotCollection,
useDeleteSpotCollection,
useUpdateSpotCollection,
} from '@/hooks/useSpotCollections';
import { useMySpotCollections, useCreateSpotCollection, useDeleteSpotCollection, useUpdateSpotCollection } from '@/hooks/useSpotCollections';
import type { SpotCollection } from '@/lib/types';
import {
FolderPlus,
FolderOpen,
MapPin,
Plus,
Loader2,
Pencil,
Trash2,
Calendar,
ArrowRight,
Bookmark,
} from 'lucide-react';
import { FolderPlus, FolderOpen, MapPin, Plus, Loader2, Pencil, Trash2, Calendar, ArrowRight, Bookmark } from 'lucide-react';
import { cn } from '@/lib/utils';
function CollectionCard({

View file

@ -41,10 +41,6 @@ import {
Trash2,
AlertTriangle,
Shield,
Phone,
Mail,
Globe,
Instagram,
Cloud,
Wind,
Droplets,
@ -53,11 +49,8 @@ import {
Plus,
Bookmark,
Users,
Camera,
Tags,
GraduationCap,
Video,
Star,
Flag,
MoreHorizontal,
MessageCircle,
@ -70,7 +63,6 @@ import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { AddToCollectionDialog } from '@/components/AddToCollectionDialog';

View file

@ -2,7 +2,7 @@ import { useState, useMemo, useRef } from 'react';
import { useSeoMeta } from '@unhead/react';
import { useNavigate, Link } from 'react-router-dom';
import { Layout } from '@/components/Layout';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Input } from '@/components/ui/input';
@ -28,11 +28,8 @@ import { ImageWithFallback } from '@/components/ImageWithFallback';
import { useStash, STASH_CATEGORIES, CONDITION_LABELS, RARITY_TIERS, type StashItem } from '@/hooks/useStash';
import { useStashShowcaseSync } from '@/hooks/useStashShowcase';
import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useAuthor } from '@/hooks/useAuthor';
import { useSatsToUsd } from '@/hooks/useExchangeRate';
import { useUploadFile } from '@/hooks/useUploadFile';
import { genUserName } from '@/lib/genUserName';
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
import {
Package,
Plus,
@ -44,19 +41,13 @@ import {
Zap,
ArrowRightLeft,
Shield,
Sparkles,
Star,
Crown,
Gem,
Search,
AlertTriangle,
ShoppingCart,
Target,
Swords,
Heart,
Backpack,
Trophy,
Flame,
X,
ImagePlus,
Loader2,