import { useState } from 'react'; import { Link } from 'react-router-dom'; import { useSeoMeta } from '@unhead/react'; 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 { useToast } from '@/hooks/useToast'; import { useCurrentUser } from '@/hooks/useCurrentUser'; 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 { cn } from '@/lib/utils'; function CollectionCard({ collection, onEdit, onDelete, }: { collection: SpotCollection; onEdit: (collection: SpotCollection) => void; onDelete: (collection: SpotCollection) => void; }) { return ( {/* Image/Header */}
{collection.image ? ( {collection.title} ) : (
)} {/* Spot count badge */}
{collection.spotRefs.length} spot{collection.spotRefs.length !== 1 ? 's' : ''}
{/* Action buttons - always visible on mobile, hover on desktop */}

{collection.title}

{collection.description && (

{collection.description}

)}
{new Date(collection.createdAt * 1000).toLocaleDateString()} View
); } function CollectionCardSkeleton() { return ( ); } export default function SpotCollectionsPage() { const { user } = useCurrentUser(); const { data: collections, isLoading } = useMySpotCollections(); const { createCollection, isPending: isCreating } = useCreateSpotCollection(); const { deleteCollection, isPending: isDeleting } = useDeleteSpotCollection(); const { updateCollection, isPending: isUpdating } = useUpdateSpotCollection(); const { toast } = useToast(); const [showCreateDialog, setShowCreateDialog] = useState(false); const [showEditDialog, setShowEditDialog] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [selectedCollection, setSelectedCollection] = useState(null); const [newTitle, setNewTitle] = useState(''); const [newDescription, setNewDescription] = useState(''); const [editTitle, setEditTitle] = useState(''); const [editDescription, setEditDescription] = useState(''); useSeoMeta({ title: 'My Spot Collections - SkateSpots', description: 'Organize your favorite skate spots into personalized collections', }); const handleCreate = async (e: React.FormEvent) => { e.preventDefault(); if (!newTitle.trim()) return; try { await createCollection({ title: newTitle.trim(), description: newDescription.trim() || undefined, }); toast({ title: 'Collection created!', description: `"${newTitle}" is ready for spots`, }); setNewTitle(''); setNewDescription(''); setShowCreateDialog(false); } catch (error) { toast({ title: 'Failed to create collection', description: error instanceof Error ? error.message : 'Something went wrong', variant: 'destructive', }); } }; const handleEdit = (collection: SpotCollection) => { setSelectedCollection(collection); setEditTitle(collection.title); setEditDescription(collection.description || ''); setShowEditDialog(true); }; const handleEditSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!selectedCollection || !editTitle.trim()) return; try { await updateCollection({ collection: selectedCollection, title: editTitle.trim(), description: editDescription.trim() || undefined, }); toast({ title: 'Collection updated!', description: 'Your changes have been saved', }); setShowEditDialog(false); setSelectedCollection(null); } catch (error) { toast({ title: 'Failed to update collection', description: error instanceof Error ? error.message : 'Something went wrong', variant: 'destructive', }); } }; const handleDelete = (collection: SpotCollection) => { setSelectedCollection(collection); setShowDeleteDialog(true); }; const handleDeleteConfirm = async () => { if (!selectedCollection) return; try { await deleteCollection(selectedCollection); toast({ title: 'Collection deleted', description: `"${selectedCollection.title}" has been removed`, }); setShowDeleteDialog(false); setSelectedCollection(null); } catch (error) { toast({ title: 'Failed to delete collection', description: error instanceof Error ? error.message : 'Something went wrong', variant: 'destructive', }); } }; return ( <>
{/* Header */}

MY COLLECTIONS

Organize your favorite spots into personalized lists

{user && ( )}
{/* Not logged in state */} {!user && (

Log in to create collections

Save your favorite spots to personalized lists like "Barcelona Trip 2024" or "Best Rails in LA"

)} {/* Loading state */} {user && isLoading && (
{Array.from({ length: 6 }).map((_, i) => ( ))}
)} {/* Empty state */} {user && !isLoading && collections?.length === 0 && (

No collections yet

Create your first collection to start organizing spots

)} {/* Collections grid */} {user && !isLoading && collections && collections.length > 0 && (
{collections.map((collection) => ( ))}
)}
{/* Create Collection Dialog */} Create New Collection Give your collection a name and optional description
setNewTitle(e.target.value)} placeholder="Barcelona Trip 2024" className="bg-black border-gray-700 text-white h-11" autoFocus />