import React, { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; const cataas = (endpoint) => "https://cataas.com" + endpoint; const bookmarker = (endpoint) => "http://localhost:4000/api/v1" + endpoint; const Bookmarks = (props) => { // This gives us access to the :id in /u/:id const { id } = useParams(); // For standard headers in all Bookmarker requests const headers = { "Authorization": "Basic " + id, }; // The object describing the randomly fetched cat image const [randomCat, setRandomCat] = useState(null); // The state of the CreateNewBookmark form const [formState, setFormState] = useState({ category: "", notes: "", }); // The list of all categories that exist in the database const [categories, setCategories] = useState([]); // The collection of which posts are being shown const [activeCategory, setActiveCategory] = useState(null); const [categoryCollection, setCategoryCollection] = useState([]); // This gets run once and then never again, doing initial setup for our // component useEffect(() => { // Fetch and render a random cat picture showNewCat(); // Fetch the list of categories with more than one bookmark getAllCategories(); }, []); // When the active collection is changed, do this useEffect(() => { (async () => { // This should only be run if an activeCategory has been selected if (activeCategory != null) { const req = await fetch( bookmarker("/bookmark/category/" + activeCategory), { headers } ); // Update the state with the resultant JSON object setCategoryCollection(await req.json()); } })(); }, [activeCategory]); const showNewCat = async () => { // First, reset the cat picture. This will briefly rerender the // paragraph saying that the image is loading setRandomCat(null); const req = await fetch(cataas("/cat?json=true")); setRandomCat(await req.json()); }; const getAllCategories = async () => { const req = await fetch( bookmarker("/bookmark/categories"), { headers }); setCategories(await req.json()); }; const chooseCategory = (category) => { setActiveCategory(category); } const bookmarkCat = async () => { const req = await fetch(bookmarker("/bookmark"), { method: "POST", headers: {...headers, "Content-Type": "application/json" }, body: JSON.stringify({ ...formState, remote_id: randomCat.id }) }); // Update the category list in case a new one was added await getAllCategories(); // Reset the form fields setFormState({ category: "", notes: "", }); // Show a new cat await showNewCat(); }; const removeBookmark = async (id) => { const req = await fetch(bookmarker("/bookmark/" + id), { headers, method: "DELETE", }); // Filter out the deleted bookmark and then reload the component setCategoryCollection(categoryCollection.filter(c => c.id != id)); }; return (

Random Cat

{

Like this cat? Bookmark them.

Browse your collections

{ activeCategory != null && categoryCollection.length > 0 ? : <> }
); }; // A reusable form component that takes a list of objects representing // input properties and then renders them dynamically const Form = (props) => { const updaterFactory = (key) => (e) => props.setter({ ...props.state, [key]: e.target.value, }); return (
e.preventDefault() }> { props.inputs.map((data, i) =>

{ data.label }

) }
); }; // Renders the Form component for our specific needs in the case of bookmarking // a cat photo const NewBookmarkForm = (props) => (
); // Renders a list of buttons, each representing a category. When the button // is pressed, the activeCategory will be updated to reflect the category it // represents const SelectCategory = ({ categories, activeCategory, callback }) => { return ( <> { categories.length > 0 ? categories.map((category, i) => ) :

Nothing to show

} ); }; // Renders a list of photos followed by their notes const BookmarkCollection = ({ bookmarks, removeCallback }) => bookmarks.map((b, i) =>
{ b.notes != null && b.notes.length > 0 ?

{ b.notes }

: <> }
); export default Bookmarks;