Margin is an open annotation layer for the internet. Powered by the AT Protocol. margin.at
extension web atproto comments
at ui-refactor 134 lines 3.8 kB view raw
1import { useState, useEffect, useCallback } from "react"; 2import { Folder, Plus } from "lucide-react"; 3import { getCollections } from "../api/client"; 4import { useAuth } from "../context/AuthContext"; 5import CollectionModal from "../components/CollectionModal"; 6import CollectionRow from "../components/CollectionRow"; 7 8export default function Collections() { 9 const { user } = useAuth(); 10 const [collections, setCollections] = useState([]); 11 const [loading, setLoading] = useState(true); 12 const [error, setError] = useState(null); 13 const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); 14 const [editingCollection, setEditingCollection] = useState(null); 15 16 const fetchCollections = useCallback(async () => { 17 try { 18 setLoading(true); 19 const data = await getCollections(user.did); 20 setCollections(data.items || []); 21 } catch (err) { 22 console.error(err); 23 setError("Failed to load collections"); 24 } finally { 25 setLoading(false); 26 } 27 }, [user]); 28 29 useEffect(() => { 30 if (user) { 31 fetchCollections(); 32 } 33 }, [user, fetchCollections]); 34 35 const handleCreateSuccess = () => { 36 fetchCollections(); 37 setIsCreateModalOpen(false); 38 setEditingCollection(null); 39 }; 40 41 const handleDelete = () => { 42 fetchCollections(); 43 setEditingCollection(null); 44 }; 45 46 if (loading) { 47 return ( 48 <div className="feed-page"> 49 <div 50 style={{ 51 display: "flex", 52 justifyContent: "center", 53 padding: "60px 0", 54 }} 55 > 56 <div className="spinner"></div> 57 </div> 58 </div> 59 ); 60 } 61 62 return ( 63 <div className="feed-page"> 64 <div 65 className="page-header" 66 style={{ 67 display: "flex", 68 justifyContent: "space-between", 69 alignItems: "flex-start", 70 }} 71 > 72 <div> 73 <h1 className="page-title">Collections</h1> 74 <p className="page-description"> 75 Organize your annotations, highlights, and bookmarks 76 </p> 77 </div> 78 <button 79 onClick={() => setIsCreateModalOpen(true)} 80 className="btn btn-primary" 81 > 82 <Plus size={20} /> 83 New Collection 84 </button> 85 </div> 86 87 {error ? ( 88 <div className="empty-state card"> 89 <div className="empty-state-icon"></div> 90 <h3 className="empty-state-title">Something went wrong</h3> 91 <p className="empty-state-text">{error}</p> 92 </div> 93 ) : collections.length === 0 ? ( 94 <div className="empty-state card"> 95 <div className="empty-state-icon"> 96 <Folder size={32} /> 97 </div> 98 <h3 className="empty-state-title">No collections yet</h3> 99 <p className="empty-state-text mb-6"> 100 Create your first collection to start organizing your web 101 annotations. 102 </p> 103 <button 104 onClick={() => setIsCreateModalOpen(true)} 105 className="btn btn-secondary" 106 > 107 Create Collection 108 </button> 109 </div> 110 ) : ( 111 <div className="collections-list"> 112 {collections.map((collection) => ( 113 <CollectionRow 114 key={collection.uri} 115 collection={collection} 116 onEdit={() => setEditingCollection(collection)} 117 /> 118 ))} 119 </div> 120 )} 121 122 <CollectionModal 123 isOpen={isCreateModalOpen || !!editingCollection} 124 onClose={() => { 125 setIsCreateModalOpen(false); 126 setEditingCollection(null); 127 }} 128 onSuccess={handleCreateSuccess} 129 onDelete={handleDelete} 130 collectionToEdit={editingCollection} 131 /> 132 </div> 133 ); 134}