Skip to content

Commit

Permalink
Merge pull request #1 from AlexSciFier/dev
Browse files Browse the repository at this point in the history
Update to version 1.1.0
  • Loading branch information
AlexSciFier authored Aug 17, 2022
2 parents 7574ca8 + c180927 commit 4aa7664
Show file tree
Hide file tree
Showing 40 changed files with 939 additions and 163 deletions.
4 changes: 2 additions & 2 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "neonlink-frontend",
"version": "1.0.0",
"version": "1.1.0",
"private": true,
"dependencies": {
"@dnd-kit/core": "^6.0.5",
Expand Down
66 changes: 48 additions & 18 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import "./App.css";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import LoginPage from "./pages/login";
import LinksPage from "./pages/link";
import { useIsloggedIn } from "./context/isLoggedIn";
import SettingsPage from "./pages/settings";
import AddPage from "./pages/addBookmark";
import { Navigate, Outlet } from "react-router";
import { useEffect } from "react";
import React, { useEffect } from "react";
import { getJSON } from "./helpers/fetch";
import EditBookmark from "./pages/editBookmark";
import NotFound from "./pages/notFound";
import Dashboard from "./pages/dashboard";
import RegisterPage from "./pages/register";
import { APP_NAME } from "./helpers/constants";

const RegisterPage = React.lazy(() => import("./pages/register"));
const Dashboard = React.lazy(() => import("./pages/dashboard"));
const NotFound = React.lazy(() => import("./pages/notFound"));
const EditBookmark = React.lazy(() => import("./pages/editBookmark"));
const AddPage = React.lazy(() => import("./pages/addBookmark"));
const SettingsPage = React.lazy(() => import("./pages/settings"));
const LinksPage = React.lazy(() => import("./pages/link"));
const LoginPage = React.lazy(() => import("./pages/login"));

function PrivateWrapper({ profile }) {
return profile ? <Outlet /> : <Navigate to="/login" />;
}
Expand Down Expand Up @@ -54,10 +55,7 @@ function App() {
document.title = APP_NAME;
}, []);

if (isProfileLoading)
return (
<div className="w-screen h-screen gradient-animate overflow-auto"></div>
);
if (isProfileLoading) return <LoadScreen />;

const routes = [
{ path: "/", element: <Dashboard /> },
Expand All @@ -71,24 +69,56 @@ function App() {
<div className="w-screen h-screen bg-gradient-to-br from-cyan-600 to-fuchsia-600 overflow-auto dark:from-gray-900 dark:to-gray-900">
<Router>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route
path="/login"
element={
<React.Suspense fallback={<LoadScreen />}>
<LoginPage />
</React.Suspense>
}
/>

<Route path="/register" element={<RegisterPage />} />
<Route
path="/register"
element={
<React.Suspense fallback={<LoadScreen />}>
<RegisterPage />
</React.Suspense>
}
/>

{routes.map((route) => (
<Route
key={route.path}
element={<PrivateWrapper profile={profile} />}
>
<Route path={route.path} element={route.element} />
<Route
path={route.path}
element={
<React.Suspense fallback={<LoadScreen />}>
{route.element}
</React.Suspense>
}
/>
</Route>
))}

<Route path="*" element={<NotFound />} />
<Route
path="*"
element={
<React.Suspense fallback={<LoadScreen />}>
<NotFound />
</React.Suspense>
}
/>
</Routes>
</Router>
</div>
);
}

function LoadScreen() {
return (
<div className="w-screen h-screen gradient-animate overflow-auto"></div>
);
}
export default App;
95 changes: 95 additions & 0 deletions frontend/src/components/Modal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { XIcon } from "@heroicons/react/outline";
import React, { useContext } from "react";
import { useRef } from "react";
import { useEffect } from "react";
import { useState } from "react";
import { createContext } from "react";

const ModalContext = createContext();

function useModalContext() {
return useContext(ModalContext);
}

function ModalContextProvider({ children, onClose }) {
const [visible, setVisible] = useState(false);
useEffect(() => {
if (visible === false) onClose();
}, [visible]);

return (
<ModalContext.Provider value={{ visible, setVisible }}>
{children}
</ModalContext.Provider>
);
}

function Modal({ children, show = false, onClose }) {
return (
<ModalContextProvider onClose={onClose}>
<BaseModal show={show}>{children}</BaseModal>
</ModalContextProvider>
);
}

function BaseModal({ children, show }) {
const { visible, setVisible } = useModalContext();
const backdrop = useRef(null);
useEffect(() => {
setVisible(show);
}, [show]);

function handleMouseDown(e) {
let label = e.target;
if (label === backdrop.current) {
setVisible(false);
}
}

return (
<div
ref={backdrop}
onMouseDown={(e) => handleMouseDown(e)}
className={
visible === false
? "hidden"
: "fixed top-0 left-0 z-10 w-screen h-screen flex justify-center items-center backdrop-blur bg-black/10"
}
>
<div className="flex-1 flex flex-col gap-3 max-w-xl p-3 rounded-md shadow-xl border bg-white dark:bg-gray-800">
{children}
</div>
</div>
);
}

function Header({ children, closeButton = false }) {
const { setVisible } = useModalContext();
return (
<div className="flex gap-1 ">
<div className="flex-1">{children}</div>
{closeButton && (
<div
onClick={() => setVisible(false)}
className="w-6 h-6 cursor-pointer p-1 rounded-full hover:bg-black/10 dark:hover:bg-white/10"
>
<XIcon />
</div>
)}
</div>
);
}

function Body({ children }) {
return <div>{children}</div>;
}

function Footer({ children }) {
return <div>{children}</div>;
}

Modal.Body = Body;
Modal.Header = Header;
Modal.Footer = Footer;

export default Modal;
24 changes: 18 additions & 6 deletions frontend/src/context/bookmarkList.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { createContext, useContext, useState } from "react";
import React, { createContext, useContext, useRef, useState } from "react";
import { deleteJSON, getJSON } from "../helpers/fetch";

const BookMarkList = createContext();
Expand All @@ -13,17 +13,27 @@ export function BookMarkListProvider({ children }) {
const [currentPage, setCurrentPage] = useState(1);
const [maxPage, setMaxPage] = useState(10);
const [errorBookmarks, setErrorBookmarks] = useState();
const abortController = useRef(null);

function abort() {
abortController.current.abort();
}

async function fetchBookmarks({ offset = 0, limit = 25, query, tag }) {
setIsBookmarksLoading(true);
setErrorBookmarks(undefined);

abortController.current = new AbortController();

let searchParams = new URLSearchParams();
searchParams.append("offset", offset);
searchParams.append("limit", limit);
if (query) searchParams.append("q", query);
if (tag) searchParams.append("tag", tag);
let res = await getJSON(`/api/bookmarks/?${searchParams.toString()}`);
let res = await getJSON(
`/api/bookmarks/?${searchParams.toString()}`,
abortController.current.signal
);
if (res.ok) {
let json = await res.json();
setBookmarkList(json.bookmarks);
Expand All @@ -36,10 +46,11 @@ export function BookMarkListProvider({ children }) {
}

async function deleteBookmark(id) {
let res = await deleteJSON(`/api/bookmarks/${id}`, {
credentials: "include",
method: "DELETE",
});
abortController.current = new AbortController();
let res = await deleteJSON(
`/api/bookmarks/${id}`,
abortController.current.signal
);
if (res.ok) {
setBookmarkList(bookmarkList.filter((item) => item.id !== id));
} else {
Expand All @@ -57,6 +68,7 @@ export function BookMarkListProvider({ children }) {
isBookmarksLoading,
fetchBookmarks,
deleteBookmark,
abort,
}}
>
{children}
Expand Down
35 changes: 29 additions & 6 deletions frontend/src/context/categoriesList.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { createContext, useContext, useEffect, useState } from "react";
import React, { createContext, useContext, useRef, useState } from "react";
import { deleteJSON, getJSON, postJSON, putJSON } from "../helpers/fetch";

const CategoriesList = createContext();
Expand All @@ -11,11 +11,13 @@ export function CategoriesListProvider({ children }) {
const [categories, setCategories] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState();
const abortController = useRef(null);

async function fetchCategories() {
setError(undefined);
setIsLoading(true);
let res = await getJSON(`/api/categories`);
abortController.current = new AbortController();
let res = await getJSON(`/api/categories`, abortController.current.signal);
if (res.ok) {
setCategories(await res.json());
} else {
Expand All @@ -27,7 +29,12 @@ export function CategoriesListProvider({ children }) {
async function addCategory(name, color) {
setError(undefined);
// setIsLoading(true);
let res = await postJSON("api/categories", { name, color });
abortController.current = new AbortController();
let res = await postJSON(
"api/categories",
{ name, color },
abortController.current.signal
);
if (res.ok) {
let id = await res.json();
setCategories([...categories, { id, name, color }]);
Expand All @@ -47,7 +54,12 @@ export function CategoriesListProvider({ children }) {
async function editCategory(id, name, color, position) {
setError(undefined);
// setIsLoading(true);
let res = await putJSON(`api/categories/${id}`, { name, color, position });
abortController.current = new AbortController();
let res = await putJSON(
`api/categories/${id}`,
{ name, color, position },
abortController.current.signal
);
if (res.ok) {
let idx = categories.findIndex((category) => category.id === id);
let arrayCopy = [...categories];
Expand All @@ -68,7 +80,11 @@ export function CategoriesListProvider({ children }) {
async function deleteCategory(id) {
setError(undefined);
// setIsLoading(true);
let res = await deleteJSON(`api/categories/${id}`);
abortController.current = new AbortController();
let res = await deleteJSON(
`api/categories/${id}`,
abortController.current.signal
);
if (res.ok) {
let filtered = categories.filter((item) => item.id !== id);
setCategories(filtered);
Expand All @@ -81,9 +97,11 @@ export function CategoriesListProvider({ children }) {
async function changePositions(idPositionPairArray) {
setError(undefined);
// setIsLoading(true);
abortController.current = new AbortController();
let res = await putJSON(
`api/categories/changePositions`,
idPositionPairArray
idPositionPairArray,
abortController.current.signal
);
if (res.ok) {
// setCategories(re);
Expand All @@ -93,6 +111,10 @@ export function CategoriesListProvider({ children }) {
// setIsLoading(false);
}

function abort() {
abortController.current.abort();
}

return (
<CategoriesList.Provider
value={{
Expand All @@ -105,6 +127,7 @@ export function CategoriesListProvider({ children }) {
editCategory,
setCategories,
changePositions,
abort,
}}
>
{children}
Expand Down
Loading

0 comments on commit 4aa7664

Please sign in to comment.