diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 234618c..d484d52 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -1,5 +1,5 @@ import { useState, useRef, useEffect, lazy, Suspense } from 'react'; -import { Link, Outlet, useLocation } from 'react-router-dom'; +import { Link, Outlet, useLocation, useNavigate } from 'react-router-dom'; import { nip19 } from 'nostr-tools'; import { cn } from '@/lib/utils'; import { isNativePlatform } from '@/lib/platform'; @@ -39,7 +39,6 @@ import { User, Plus, CheckCircle2, - Database, Package, Heart, CreditCard, @@ -53,6 +52,7 @@ import { ChevronLeft, ChevronRight, ChevronDown, + ArrowLeft, Search, } from 'lucide-react'; import { OfflineIndicator } from '@/components/OfflineIndicator'; @@ -283,12 +283,6 @@ function MobileHeaderUserMenu({ {t('chromeUi.setStatus')} 🛹 - - - - {t('chromeUi.addSpot')} - - @@ -301,36 +295,6 @@ function MobileHeaderUserMenu({ {t('nav.settings')} - - - - {t('chromeUi.myData')} - - - - - - {t('chromeUi.myStash')} - - - - - - {t('nav.wallet')} - - - - - - {t('nav.leaderboards')} - - - - - - {t('nav.marketplace')} - - {/* ── Accounts: switch between logged-in npubs + add another ── */} @@ -512,6 +476,8 @@ function MobileNav({ export function Layout({ children, noPadding }: LayoutProps) { const location = useLocation(); + const navigate = useNavigate(); + const showMobileBack = location.pathname !== '/' && location.pathname !== '/map'; // The map is full-bleed (it manages its own height), so it gets no bottom // padding even though it shares this one persistent layout with every route. const isFullBleed = noPadding || location.pathname === '/' || location.pathname === '/map'; @@ -842,6 +808,22 @@ export function Layout({ children, noPadding }: LayoutProps) { {/* Mobile Header */}
+ {showMobileBack && ( + + )} - SKATESPOTS diff --git a/src/components/SpotCard.tsx b/src/components/SpotCard.tsx index 26bd617..e40a5d0 100644 --- a/src/components/SpotCard.tsx +++ b/src/components/SpotCard.tsx @@ -11,7 +11,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; -import { MapPin, Store, Bookmark, MoreVertical, Flag, ShieldCheck } from 'lucide-react'; +import { MapPin, Store, Bookmark, MoreVertical, Flag, ShieldCheck, Trash2 } from 'lucide-react'; import { useAuthor } from '@/hooks/useAuthor'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useVenuesWithPasses } from '@/hooks/useRiderCard'; @@ -23,6 +23,7 @@ import { OfficialBadge } from '@/components/OfficialBadge'; import { AddToCollectionDialog } from '@/components/AddToCollectionDialog'; import { ReportDialog } from '@/components/ReportDialog'; import { MuteMenuItem } from '@/components/MuteMenuItem'; +import { DeleteEntityDialog } from '@/components/DeleteEntityDialog'; import { SpotStatusBadge } from '@/components/SpotStatusBadge'; import type { SkateSpot } from '@/lib/types'; import { ACCESS_TYPE_INFO, SHELTER_INFO, SKATE_SHOP_KIND } from '@/lib/types'; @@ -30,6 +31,7 @@ import { spotTypeLabel } from '@/lib/spotTypeLabel'; import { ACCESS_TYPE_KEYS, SHELTER_SHORT_KEYS } from '@/lib/labelKeys'; import type { AggregatedSpotStatus } from '@/hooks/useSpotStatus'; import { useTranslation } from '@/contexts/language'; +import { isAdminPubkey } from '@/lib/admins'; import { cn } from '@/lib/utils'; interface SpotCardProps { @@ -48,10 +50,13 @@ export function SpotCard({ spot, status, community }: SpotCardProps) { const displayName = metadata?.name ?? genUserName(spot.pubkey); const [showCollectionDialog, setShowCollectionDialog] = useState(false); const [showReportDialog, setShowReportDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); // Determine if this is a shop or a spot const isShop = spot.types.includes('shop'); const isOwner = user?.pubkey === spot.pubkey; + const isAdmin = isAdminPubkey(user?.pubkey); + const canDelete = !!user && (isOwner || isAdmin); const route = isShop ? `/shop/${spot.pubkey}/${spot.identifier}` : `/spot/${spot.pubkey}/${spot.identifier}`; // Shops that actually issue access passes get a badge (one shared, cached query). @@ -245,7 +250,19 @@ export function SpotCard({ spot, status, community }: SpotCardProps) { - + + {canDelete && ( + { + e.preventDefault(); + setShowDeleteDialog(true); + }} + className="text-red-500 focus:text-red-500" + > + + {isOwner ? t('common.delete') : t('spotUi.removeAdmin')} + + )} {!isOwner && ( { @@ -275,6 +292,17 @@ export function SpotCard({ spot, status, community }: SpotCardProps) { /> )} + {/* Owner/admin delete confirmation */} + {canDelete && ( + + )} + {/* Report Dialog */}