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:
parent
30ef511e78
commit
d1f8870379
49 changed files with 98 additions and 562 deletions
|
|
@ -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`.
|
||||
|
||||
|
|
|
|||
|
|
@ -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> = {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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: `
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
interface QRCodeCanvasProps {
|
||||
value: string;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useNostr } from '@nostrify/react';
|
||||
|
||||
import { useSkateRelays } from '@/hooks/useSkateRelays';
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 ────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -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 }) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 ────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue