import { useState, useEffect } from "react"; import { useParams, useNavigate, Link, useLocation } from "react-router-dom"; import { ArrowLeft, Edit2, Trash2, Plus, ExternalLink } from "lucide-react"; import { getCollection, getCollectionItems, removeItemFromCollection, deleteCollection, resolveHandle, } from "../api/client"; import { useAuth } from "../context/AuthContext"; import CollectionModal from "../components/CollectionModal"; import CollectionIcon from "../components/CollectionIcon"; import AnnotationCard, { HighlightCard } from "../components/AnnotationCard"; import BookmarkCard from "../components/BookmarkCard"; import ShareMenu from "../components/ShareMenu"; export default function CollectionDetail() { const { rkey, handle, "*": wildcardPath } = useParams(); const location = useLocation(); const navigate = useNavigate(); const { user } = useAuth(); const [collection, setCollection] = useState(null); const [items, setItems] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [isEditModalOpen, setIsEditModalOpen] = useState(false); const [refreshTrigger, setRefreshTrigger] = useState(0); const searchParams = new URLSearchParams(location.search); const paramAuthorDid = searchParams.get("author"); const isOwner = user?.did && (collection?.creator?.did === user.did || paramAuthorDid === user.did); useEffect(() => { let active = true; const fetchContext = async () => { if (active) { setLoading(true); setError(null); } try { let targetUri = null; let targetDid = paramAuthorDid || user?.did; if (handle && rkey) { try { targetDid = await resolveHandle(handle); if (!active) return; targetUri = `at://${targetDid}/at.margin.collection/${rkey}`; } catch (e) { console.error("Failed to resolve handle", e); if (active) setError("Could not resolve user handle"); } } else if (wildcardPath) { targetUri = decodeURIComponent(wildcardPath); } else if (rkey && targetDid) { targetUri = `at://${targetDid}/at.margin.collection/${rkey}`; } if (!targetUri) { if (active) { if (!user && !handle && !paramAuthorDid) { setError("Please log in to view your collections"); } else if (!error) { setError("Invalid collection URL"); } } return; } if (!targetDid && targetUri.startsWith("at://")) { const parts = targetUri.split("/"); if (parts.length > 2) targetDid = parts[2]; } const collectionData = await getCollection(targetUri); if (!active) return; setCollection(collectionData); const itemsData = await getCollectionItems(collectionData.uri); if (!active) return; setItems(itemsData || []); } catch (err) { console.error("Fetch failed:", err); if (active) { if ( err.message.includes("404") || err.message.includes("not found") ) { setError("Collection not found"); } else { setError(err.message || "Failed to load collection"); } } } finally { if (active) setLoading(false); } }; fetchContext(); return () => { active = false; }; }, [ paramAuthorDid, user?.did, handle, rkey, wildcardPath, refreshTrigger, error, user, ]); const handleEditSuccess = () => { setIsEditModalOpen(false); setRefreshTrigger((v) => v + 1); }; const handleDeleteItem = async (itemUri) => { if (!confirm("Remove this item from the collection?")) return; try { await removeItemFromCollection(itemUri); setItems((prev) => prev.filter((i) => i.uri !== itemUri)); } catch (err) { console.error(err); alert("Failed to remove item"); } }; if (loading) { return (
{collection.description}
)}{isOwner ? 'Add items to this collection from your feed or bookmarks using the "Collect" button.' : "This collection has no items yet."}
Item could not be loaded