Merge backend + frontend #1
							
								
								
									
										39
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										39
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -23,6 +23,7 @@
 | 
			
		||||
        "react": "^18.2.0",
 | 
			
		||||
        "react-dom": "^18.2.0",
 | 
			
		||||
        "react-helmet-async": "^1.3.0",
 | 
			
		||||
        "react-router-dom": "^6.14.2",
 | 
			
		||||
        "react-scripts": "^5.0.1",
 | 
			
		||||
        "typescript": "^4.9.5",
 | 
			
		||||
        "web-vitals": "^2.1.4",
 | 
			
		||||
@@ -3743,6 +3744,14 @@
 | 
			
		||||
        "url": "https://opencollective.com/popperjs"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@remix-run/router": {
 | 
			
		||||
      "version": "1.7.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.2.tgz",
 | 
			
		||||
      "integrity": "sha512-7Lcn7IqGMV+vizMPoEl5F0XDshcdDYtMI6uJLQdQz5CfZAwy3vvGKYSUk789qndt5dEC4HfSjviSYlSoHGL2+A==",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@rollup/plugin-babel": {
 | 
			
		||||
      "version": "5.3.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
 | 
			
		||||
@@ -15342,6 +15351,36 @@
 | 
			
		||||
        "node": ">=0.10.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/react-router": {
 | 
			
		||||
      "version": "6.14.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.2.tgz",
 | 
			
		||||
      "integrity": "sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@remix-run/router": "1.7.2"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "react": ">=16.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/react-router-dom": {
 | 
			
		||||
      "version": "6.14.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.2.tgz",
 | 
			
		||||
      "integrity": "sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@remix-run/router": "1.7.2",
 | 
			
		||||
        "react-router": "6.14.2"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "react": ">=16.8",
 | 
			
		||||
        "react-dom": ">=16.8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/react-scripts": {
 | 
			
		||||
      "version": "5.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
    "react": "^18.2.0",
 | 
			
		||||
    "react-dom": "^18.2.0",
 | 
			
		||||
    "react-helmet-async": "^1.3.0",
 | 
			
		||||
    "react-router-dom": "^6.14.2",
 | 
			
		||||
    "react-scripts": "^5.0.1",
 | 
			
		||||
    "typescript": "^4.9.5",
 | 
			
		||||
    "web-vitals": "^2.1.4",
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,9 @@ import { Helmet, HelmetProvider } from "react-helmet-async";
 | 
			
		||||
// Authentication Context: Check if user is logged in or not
 | 
			
		||||
import { AuthContextProvider } from "./AuthContext";
 | 
			
		||||
 | 
			
		||||
// React router
 | 
			
		||||
import Router from "./Router";
 | 
			
		||||
 | 
			
		||||
function App() {
 | 
			
		||||
  return (
 | 
			
		||||
    <AuthContextProvider>
 | 
			
		||||
@@ -27,7 +30,9 @@ function App() {
 | 
			
		||||
          <title>Todo</title>
 | 
			
		||||
        </Helmet>
 | 
			
		||||
        <ThemeProvider>
 | 
			
		||||
          <Container maxWidth="md"></Container>
 | 
			
		||||
          <Container maxWidth="md">
 | 
			
		||||
            <Router />
 | 
			
		||||
          </Container>
 | 
			
		||||
        </ThemeProvider>
 | 
			
		||||
      </HelmetProvider>
 | 
			
		||||
    </AuthContextProvider>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								frontend/src/Router.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								frontend/src/Router.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
import { BrowserRouter, Routes } from "react-router-dom";
 | 
			
		||||
 | 
			
		||||
const Router = () => {
 | 
			
		||||
  <BrowserRouter>
 | 
			
		||||
    <Routes>{}</Routes>
 | 
			
		||||
  </BrowserRouter>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default Router;
 | 
			
		||||
							
								
								
									
										22
									
								
								frontend/src/components/RequireAuth.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								frontend/src/components/RequireAuth.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
import { useContext } from "react";
 | 
			
		||||
import { Navigate, useLocation } from "react-router-dom";
 | 
			
		||||
import { AuthContext } from "src/AuthContext";
 | 
			
		||||
 | 
			
		||||
interface IProps {
 | 
			
		||||
  children: React.ReactNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const RequireAuth = ({ children }: IProps) => {
 | 
			
		||||
  const { authenticated } = useContext(AuthContext);
 | 
			
		||||
 | 
			
		||||
  const location = useLocation();
 | 
			
		||||
 | 
			
		||||
  if (authenticated) {
 | 
			
		||||
    return <>{children}</>;
 | 
			
		||||
  } else {
 | 
			
		||||
    // re-route user back to login page if not logged in
 | 
			
		||||
    return <Navigate state={{ from: location }} to="/login/" />;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default RequireAuth;
 | 
			
		||||
							
								
								
									
										16
									
								
								frontend/src/components/ScrollToTop.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								frontend/src/components/ScrollToTop.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
import { useEffect } from "react";
 | 
			
		||||
import { useLocation } from "react-router";
 | 
			
		||||
 | 
			
		||||
const ScrollToTop = () => {
 | 
			
		||||
  const { pathname } = useLocation();
 | 
			
		||||
 | 
			
		||||
  // pathname changes => scroll to top
 | 
			
		||||
  // scrolling only on navigation
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    window.scrollTo(0, 0);
 | 
			
		||||
  }, [pathname]);
 | 
			
		||||
 | 
			
		||||
  return null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default ScrollToTop;
 | 
			
		||||
@@ -3,3 +3,7 @@
 | 
			
		||||
// expect(element).toHaveTextContent(/react/i)
 | 
			
		||||
// learn more: https://github.com/testing-library/jest-dom
 | 
			
		||||
import "@testing-library/jest-dom";
 | 
			
		||||
 | 
			
		||||
window.scrollTo = (x, y) => {
 | 
			
		||||
  document.documentElement.scrollTop = y;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user