import { useState, useEffect, useCallback } from "react"; import { Link } from "react-router-dom"; import { Plus } from "lucide-react"; import { useAuth } from "../context/AuthContext"; import { getUserBookmarks, deleteBookmark, createBookmark, getURLMetadata, } from "../api/client"; import { BookmarkIcon } from "../components/Icons"; import BookmarkCard from "../components/BookmarkCard"; import AddToCollectionModal from "../components/AddToCollectionModal"; export default function Bookmarks() { const { user, isAuthenticated, loading } = useAuth(); const [bookmarks, setBookmarks] = useState([]); const [loadingBookmarks, setLoadingBookmarks] = useState(true); const [error, setError] = useState(null); const [showAddForm, setShowAddForm] = useState(false); const [newUrl, setNewUrl] = useState(""); const [newTitle, setNewTitle] = useState(""); const [submitting, setSubmitting] = useState(false); const [fetchingTitle, setFetchingTitle] = useState(false); const [collectionModalState, setCollectionModalState] = useState({ isOpen: false, uri: null, }); const loadBookmarks = useCallback(async () => { if (!user?.did) return; try { setLoadingBookmarks(true); const data = await getUserBookmarks(user.did); setBookmarks(data.items || []); } catch (err) { console.error("Failed to load bookmarks:", err); setError(err.message); } finally { setLoadingBookmarks(false); } }, [user]); useEffect(() => { if (isAuthenticated && user) { loadBookmarks(); } }, [isAuthenticated, user, loadBookmarks]); const handleDelete = async (uri) => { if (!confirm("Delete this bookmark?")) return; try { const parts = uri.split("/"); const rkey = parts[parts.length - 1]; await deleteBookmark(rkey); setBookmarks((prev) => prev.filter((b) => (b.id || b.uri) !== uri)); } catch (err) { alert("Failed to delete: " + err.message); } }; const handleUrlBlur = async () => { if (!newUrl.trim() || newTitle.trim()) return; try { new URL(newUrl); } catch { return; } try { setFetchingTitle(true); const data = await getURLMetadata(newUrl.trim()); if (data.title && !newTitle) { setNewTitle(data.title); } } catch (err) { console.error("Failed to fetch title:", err); } finally { setFetchingTitle(false); } }; const handleAddBookmark = async (e) => { e.preventDefault(); if (!newUrl.trim()) return; try { setSubmitting(true); await createBookmark(newUrl.trim(), newTitle.trim() || undefined); setNewUrl(""); setNewTitle(""); setShowAddForm(false); await loadBookmarks(); } catch (err) { alert("Failed to add bookmark: " + err.message); } finally { setSubmitting(false); } }; if (loading) return (
You need to be logged in with your Bluesky account
Sign in with BlueskyPages you've saved for later
{error}
Click "Add Bookmark" above to save a page, or use the browser extension.