From 73a5c7fae9ffbe9ada721148c8c454a643aceebe Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Sun, 20 Feb 2022 16:11:50 +0100 Subject: chore!: restructure repo I separated public files from the config/dev files. It improves repo readability. I also moved dotenv helper to public/inc directory and extract the Matomo tracker in the same directory. --- .../react-small-apps/apps/notebook/src/App.js | 174 +++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 public/projects/react-small-apps/apps/notebook/src/App.js (limited to 'public/projects/react-small-apps/apps/notebook/src/App.js') diff --git a/public/projects/react-small-apps/apps/notebook/src/App.js b/public/projects/react-small-apps/apps/notebook/src/App.js new file mode 100644 index 0000000..6057342 --- /dev/null +++ b/public/projects/react-small-apps/apps/notebook/src/App.js @@ -0,0 +1,174 @@ +import { Navigate, Route, Routes, useLocation } from "react-router-dom"; +import { Footer, Header, Main, Nav, Page } from "./components/layout"; +import { useCallback, useEffect, useState } from "react"; +import { defaultPages } from "./config/pages"; +import "./App.css"; + +let pageId = 0; + +function App() { + const storedPages = JSON.parse(localStorage.getItem("notebook-pages")); + const initialPages = storedPages || defaultPages; + const [pages, setPages] = useState(initialPages); + const [currentPage, setCurrentPage] = useState({}); + const [deletedPages, setDeletedPages] = useState([]); + const location = useLocation(); + + pageId = storedPages ? storedPages.at(storedPages.length - 1).id : pageId; + + const isCover = () => currentPage && currentPage.id === 0; + const isPageExists = useCallback( + (id) => { + const pageIndex = pages.findIndex((page) => page.id === id); + return pageIndex === -1 ? false : true; + }, + [pages] + ); + + const addNewPage = useCallback(() => { + pageId++; + const newPage = { + id: pageId, + body: "", + title: `Page ${pageId}`, + url: `/page/${pageId}`, + }; + setPages((previous) => [...previous, newPage]); + }, []); + + const removePage = useCallback(() => { + const currentPageId = currentPage.id; + const pagesCopy = pages.slice(0); + const currentPageIndex = pages.findIndex( + (page) => page.id === currentPageId + ); + setDeletedPages((prev) => [...prev, currentPage]); + pagesCopy.splice(currentPageIndex, 1); + const newPages = pagesCopy.map((page) => { + if (page.id <= currentPageId) return page; + const newId = page.id - 1; + const newURL = `/page/${newId}`; + return { ...page, id: newId, url: newURL }; + }); + setCurrentPage(...newPages.filter((page) => page.id === currentPageId)); + setPages(newPages); + pageId = pageId - 1; + }, [pages, currentPage]); + + const restorePage = useCallback(() => { + const deletedPage = deletedPages.pop(); + const pagesCopy = pages.slice(0); + const restoredPageIndex = pagesCopy.findIndex( + (page) => page.id === deletedPage.id + ); + const newPages = pagesCopy.map((page) => { + if (page.id < deletedPage.id) return page; + const newId = page.id + 1; + const newURL = `/page/${newId}`; + return { ...page, id: newId, url: newURL }; + }); + newPages.splice(restoredPageIndex, 0, deletedPage); + setCurrentPage(...newPages.filter((page) => page.id === deletedPage.id)); + setPages(newPages); + }, [pages, deletedPages]); + + useEffect(() => { + !isPageExists(1) && addNewPage(); + }, [isPageExists, addNewPage]); + + useEffect(() => { + const requestedPage = pages.find((page) => page.url === location.pathname); + if (requestedPage) { + setCurrentPage(requestedPage); + } else { + setCurrentPage(() => pages.find((page) => page.url === "/404")); + } + }, [location.pathname, pages]); + + useEffect(() => { + if (currentPage) document.title = `Notebook - ${currentPage.title}`; + }, [currentPage]); + + useEffect(() => { + setPages((prevPages) => { + return prevPages.map((page) => { + if (page.id !== currentPage.id) return page; + return { ...page, body: currentPage.body }; + }); + }); + }, [currentPage.id, currentPage.body]); + + useEffect(() => { + setPages((prevPages) => { + return prevPages.map((page) => { + if (page.id !== currentPage.id) return page; + return { ...page, title: currentPage.title }; + }); + }); + }, [currentPage.id, currentPage.title]); + + useEffect(() => { + localStorage.setItem("notebook-pages", JSON.stringify(pages)); + }, [pages]); + + return ( + <> +
+
+
+
+ + + } + /> + } /> + } /> + + } + /> + + } + path="/404" + /> + } /> + +
+
+