From e701a60c2594847fd7c78f734326868bbea03b61 Mon Sep 17 00:00:00 2001 From: Reed Vogt Date: Fri, 1 Dec 2023 18:43:19 -0800 Subject: [PATCH] Refactor and Optimize Card Management Components and Contexts - Updated CardMediaAndDetails component to fetch and display card images. - Enhanced CardContext with PATCH request logic to update missing card data from YGOPRO API. - Implemented constructCardDifferencesPayload function for efficiently tracking card updates within collections. - Modified CartContext to prevent infinite loops and optimized state management. - Fixed server-side routes for card information retrieval and PATCH updates, ensuring proper data fetching and error handling. - Streamlined useEffect dependencies in various components to enhance performance and prevent redundant renders. --- README.md | 5 +- package.json | 2 + src/App.js | 193 +++++----- src/assets/deckIcon2.svg | 35 ++ src/assets/themeSettings.jsx | 3 + .../actionButtons/CardActionButtons.jsx | 152 ++++++-- .../actionButtons/GenericActionButtons.jsx | 12 +- .../buttons/other/OrderSubmitButton.js | 28 +- .../buttons/other/ThemeToggleButton.jsx | 2 +- src/components/cards/GenericCard.jsx | 112 ++++-- src/components/chart/PortfolioChart.jsx | 2 +- src/components/collection/CardPortfolio.jsx | 3 +- .../collection/PortfolioContent.jsx | 2 +- .../collection/SelectCollection.jsx | 17 +- .../customerCheckoutForm/CartActions.jsx | 15 - .../customerCheckoutForm/CustomerForm.js | 76 ++-- .../CustomerInfoFields.jsx | 20 +- .../grids/collectionGrids/CardList.jsx | 56 +-- .../collectionGrids/SelectCollectionList.jsx | 191 +++++----- .../storeSearchResultsGrid/ProductGrid.js | 55 +-- src/components/headings/header/Header.js | 127 +++++-- .../headings/header/menuItemsData.jsx | 18 +- src/components/headings/navigation/TopBar.jsx | 173 ++++++--- src/components/media/CardMediaAndDetails.jsx | 148 +++++++- src/components/media/CardMediaSection.js | 37 +- .../modals/cardModal/GenericCardModal.jsx | 8 +- .../modals/stripeModal/StripeCheckoutModal.js | 14 +- .../InputComponents/UpdateStatusBox2.jsx | 2 +- .../other/dataDisplay/CartSummary.js | 30 +- .../other/dataDisplay/CartTotal.jsx | 8 +- .../other/dataDisplay/TopCardsDisplay.jsx | 12 +- .../collectionGrids => reusable}/Logger.jsx | 0 .../TablePaginationActions.jsx | 2 +- .../reusable/icons/DeckBuilderIcon.jsx | 59 ++++ .../reusable/icons/DeckOfCardsIcon.jsx | 34 +- src/components/reusable/icons/MoneyIcon.jsx | 2 +- .../reusable/icons/ReusableIconButton.jsx | 40 +++ src/components/search/DeckSearch.js | 10 +- .../cartPageContainers/CartContainer.jsx | 48 ++- .../cartPageContainers/CartContent.js | 33 +- .../CartContentContainer.js | 26 -- .../CustomerFormContainer.js | 13 - .../CollectionPortfolioChartContainer.jsx | 2 +- src/context/AppContext/AppContextProvider.jsx | 8 + .../{Auth => AuthContext}/authContext.js | 108 +++++- src/context/CardContext/CardStore.js | 109 +++++- src/context/CartContext/CartContext.js | 89 +---- .../CollectionContext/CollectionContext.jsx | 87 ++++- .../CollectionContext/collectionUtility.jsx | 113 +----- src/context/CollectionContext/helpers.jsx | 130 +++++++ .../ColorModeProvider.jsx | 2 +- .../CombinedProvider.jsx | 66 +++- src/context/CronJobContext/CronJobContext.jsx | 16 +- src/context/DeckContext/DeckContext.js | 57 ++- src/context/DeckContext/helpers.jsx | 27 ++ src/context/Helpers.jsx | 64 +++- src/context/ModalContext/ModalContext.jsx | 21 +- src/context/PageContext/Page | 0 src/context/PageContext/PageContext.jsx | 45 +++ src/context/PopoverContext/PopoverContext.jsx | 5 + .../{ => SideBarContext}/SideBarProvider.jsx | 0 .../{ => SocketContext}/SocketProvider.jsx | 0 .../StatisticsContext/StatisticsContext.jsx | 23 +- src/context/UserContext/UserContext.js | 14 +- src/context/UtilityContext/UtilityContext.jsx | 15 +- src/context/hooks/auth.jsx | 2 +- src/context/hooks/colormode.jsx | 2 +- src/context/index.js | 41 +++ src/index.js | 51 +-- src/pages/CartPage.js | 332 +++++++++++++++--- src/pages/CollectionPage.js | 126 +++---- src/pages/DeckBuilderPage.js | 97 ++--- src/pages/HomePage.js | 15 +- src/pages/NotFoundPage.js | 38 ++ src/pages/ProfilePage.js | 16 +- src/pages/StorePage.js | 158 +++------ src/pages/index.js | 9 + src/pages/pageStyles/CarouselImage.jsx | 0 src/pages/pageStyles/HeroCenter.jsx | 60 ++++ src/pages/pageStyles/StyledComponents.jsx | 70 +++- src/pages/pages.json | 13 +- 81 files changed, 2553 insertions(+), 1303 deletions(-) create mode 100644 src/assets/deckIcon2.svg delete mode 100644 src/components/forms/customerCheckoutForm/CartActions.jsx rename src/components/{grids/collectionGrids => reusable}/Logger.jsx (100%) rename src/components/{grids/collectionGrids => reusable}/TablePaginationActions.jsx (97%) create mode 100644 src/components/reusable/icons/DeckBuilderIcon.jsx create mode 100644 src/components/reusable/icons/ReusableIconButton.jsx delete mode 100644 src/containers/cartPageContainers/CartContentContainer.js delete mode 100644 src/containers/cartPageContainers/CustomerFormContainer.js rename src/context/{Auth => AuthContext}/authContext.js (55%) rename src/context/{ => ColorModeContext}/ColorModeProvider.jsx (96%) rename src/context/{ => CombinedContext}/CombinedProvider.jsx (89%) create mode 100644 src/context/DeckContext/helpers.jsx create mode 100644 src/context/PageContext/Page create mode 100644 src/context/PageContext/PageContext.jsx rename src/context/{ => SideBarContext}/SideBarProvider.jsx (100%) rename src/context/{ => SocketContext}/SocketProvider.jsx (100%) create mode 100644 src/context/index.js create mode 100644 src/pages/NotFoundPage.js create mode 100644 src/pages/index.js create mode 100644 src/pages/pageStyles/CarouselImage.jsx create mode 100644 src/pages/pageStyles/HeroCenter.jsx 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 */} {/*