diff --git a/README.md b/README.md index bb3a971..5b962db 100644 --- a/README.md +++ b/README.md @@ -94,11 +94,12 @@ Reed Vogt - LinkedIn -Project Site: https://65624888827a3700084a3478--enhanced-cardstore.netlify.app/ +Project Site: -Project Repo: https://github.com/reedoooo/enhanced-card-store#readme +Project Repo: ## Acknowledgements - [React](https://reactjs.org/) - [Stripe](https://stripe.com/) +- [Convertio](https://convertio.co/download/bde422f6082917756106e52b556e7245cfcfbe/) diff --git a/package.json b/package.json index 576afc4..e4ea0cf 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@fortawesome/fontawesome-free": "^6.4.0", @@ -23,6 +24,7 @@ "dayjs": "^1.11.9", "image-downloader": "^4.3.0", "jwt-decode": "^3.1.2", + "lodash": "^4.17.21", "material-ui-image": "^3.3.2", "moment": "^2.29.4", "react": "^17.0.2", diff --git a/src/App.js b/src/App.js index 798e0fe..2f7d1a1 100644 --- a/src/App.js +++ b/src/App.js @@ -1,143 +1,127 @@ -// External Imports -import React, { useContext, useEffect, useRef, useState } from 'react'; +// Note: Main App Component +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import { Helmet } from 'react-helmet'; +import { debounce } from 'lodash'; // Component Imports import Header from './components/headings/header/Header'; -import Footer from './components/headings/footer/Footer'; import PrivateRoute from './components/reusable/PrivateRoute'; +import LoginDialog from './components/dialogs/LoginDialog'; +// import Footer from './components/headings/footer/Footer'; // Page Imports -import SplashPage from './pages/SplashPage'; -import HomePage from './pages/HomePage'; -import StorePage from './pages/StorePage'; -import CartPage from './pages/CartPage'; -import ProfilePage from './pages/ProfilePage'; -import CollectionPage from './pages/CollectionPage'; -import DeckBuilderPage from './pages/DeckBuilderPage'; -import ThreeJsCube from './assets/animations/ThreeJsCube'; -import CardDeckAnimation from './assets/animations/CardDeckAnimation'; +import { + SplashPage, + HomePage, + StorePage, + CartPage, + ProfilePage, + CollectionPage, + DeckBuilderPage, + // ThreeJsCube, + // CardDeckAnimation, + NotFoundPage, +} from './pages'; -// Context Hooks Imports -import { useUserContext } from './context/UserContext/UserContext'; -import { useCollectionStore } from './context/CollectionContext/CollectionContext'; -import { useUtilityContext } from './context/UtilityContext/UtilityContext'; +import { + useUserContext, + useCollectionStore, + useUtilityContext, + useDeckStore, + useCartStore, + useCardImages, + useAuthContext, + usePageContext, +} from './context'; import { AppContainer } from './pages/pageStyles/StyledComponents'; -import { useCardImages } from './context/CardImagesContext/CardImagesContext'; -import { useCookies } from 'react-cookie'; -import { useDeckStore } from './context/DeckContext/DeckContext'; -import { useCartStore } from './context/CartContext/CartContext'; -import LoginDialog from './components/dialogs/LoginDialog'; -const App = () => { - // const { getRandomCardImages } = useCardImages(); // Add this line - // const [cookies] = useCookies(['user']); - // const user = cookies?.user; - // const userId = user?.id; - const [currentPage, setCurrentPage] = useState(''); +const App = () => { const { fetchAllCollectionsForUser, selectedCollection } = useCollectionStore(); - const { user, fetchUser } = useUserContext(); + const { fetchAllDecksForUser, selectedDeck } = useDeckStore(); + const { fetchUserCart } = useCartStore(); + const { user } = useUserContext(); + const { logout } = useAuthContext(); + const { isLoading, setIsLoading } = useUtilityContext(); + const { isPageLoading, setIsPageLoading } = usePageContext(); const userId = user?.id; - const [showLoginDialog, setShowLoginDialog] = useState(false); + const [showLoginDialog, setShowLoginDialog] = useState(!userId); + const logoutTimerRef = useRef(null); - const { allDecks, fetchAllDecksForUser, selectedDeck } = useDeckStore(); - const { fetchUserCart, cartData } = useCartStore(); - const { isLoading, setIsLoading } = useUtilityContext(); + const handleUserActivity = debounce(() => { + if (logoutTimerRef.current) clearTimeout(logoutTimerRef.current); + logoutTimerRef.current = setTimeout(logout, 1800000); // 30 minutes + }, 500); + + const debouncedLogout = useCallback( + debounce(() => { + if (logoutTimerRef.current) { + clearTimeout(logoutTimerRef.current); + } + logoutTimerRef.current = setTimeout(logout, 1800000); // 30 minutes + }, 500), + [logout] // Dependency for useCallback + ); + + // Call this function to reset the logout timer + const resetLogoutTimer = useCallback(() => { + debouncedLogout(); + }, [debouncedLogout]); - // useEffect(() => { - // getRandomCardImages(10); // Fetch 10 random images on app start - // }, []); // Add this useEffect const handleLoginSuccess = (isLoggedIn, userId) => { setShowLoginDialog(false); + setIsPageLoading(false); setIsLoading(false); + if (isLoggedIn && userId) { + resetLogoutTimer(); + } }; useEffect(() => { - if (!userId || typeof userId !== 'string') { - // Invalid or missing userId, show login dialog and hide splash page - setShowLoginDialog(true); - setIsLoading(false); - } else { - // Valid userId, hide login dialog and splash page - setShowLoginDialog(false); - setIsLoading(false); + // Set up event listeners for user activity + if (userId) { + window.addEventListener('mousemove', resetLogoutTimer); + window.addEventListener('keypress', resetLogoutTimer); } - }, [userId]); - useEffect(() => { - if (userId && typeof userId === 'string') { - fetchAllCollectionsForUser() - .then(() => { - setIsLoading(false); - }) - .catch((error) => { - console.error('Error fetching collections:', error); - setIsLoading(false); - }); - } - }, [userId, fetchAllCollectionsForUser, setIsLoading, selectedCollection]); - useEffect(() => { - if (userId && typeof userId === 'string') { - fetchAllDecksForUser() - .then(() => { - setIsLoading(false); - }) - .catch((error) => console.error('Error fetching decks:', error)); - setIsLoading(false); - } - }, [userId, fetchAllDecksForUser, selectedDeck, setIsLoading]); - useEffect(() => { - console.log('Checking userId in useEffect:', userId); - setShowLoginDialog(!userId); - }, [userId]); - // useEffect(() => { - // if (userId && typeof userId === 'string') { - // fetchUserCart() - // .then(() => { - // setIsLoading(false); - // }) - // .catch((error) => console.error('Error fetching cart:', error)); - // } - // }, [userId, fetchUserCart, cartData, setIsLoading]); + // Clean up event listeners + return () => { + window.removeEventListener('mousemove', resetLogoutTimer); + window.removeEventListener('keypress', resetLogoutTimer); + if (logoutTimerRef.current) { + clearTimeout(logoutTimerRef.current); + } + }; + }, [userId, resetLogoutTimer]); - // Handle initial loading state useEffect(() => { - if (!isLoading) { - setIsLoading(false); + if (userId) { + Promise.all([ + fetchAllCollectionsForUser(), + fetchAllDecksForUser(), + // fetchUserCart(), + ]) + .catch((error) => console.error('Error fetching data:', error)) + .finally(() => setIsLoading(false) && setIsPageLoading(false)); } - }, [isLoading, setIsLoading]); + }, [userId, fetchAllCollectionsForUser, fetchAllDecksForUser, fetchUserCart]); return ( <> - - - - - - {isLoading ? ( + {/* Helmet Configuration */} + {isLoading || isPageLoading ? ( ) : ( - + <> setShowLoginDialog(false)} onLogin={handleLoginSuccess} /> -
- {/* {setCurrentPage(useLocation())} */} - } /> } /> } /> @@ -174,13 +158,14 @@ const App = () => { } /> } /> - } /> - } /> - {/* Add a Route for 404 Not Found page if needed */} + {/* } /> */} + {/* } /> */} + } />{' '} + {/* 404 Not Found Route */} {/*