diff --git a/public/deckIcon1.png b/public/images/deckIcon1.png
similarity index 100%
rename from public/deckIcon1.png
rename to public/images/deckIcon1.png
diff --git a/public/logo192.png b/public/logo192.png
deleted file mode 100644
index fc44b0a..0000000
Binary files a/public/logo192.png and /dev/null differ
diff --git a/public/logo512.png b/public/logo512.png
deleted file mode 100644
index a4e47a6..0000000
Binary files a/public/logo512.png and /dev/null differ
diff --git a/public/manifest.json b/public/manifest.json
index 080d6c7..b6594c7 100644
--- a/public/manifest.json
+++ b/public/manifest.json
@@ -8,12 +8,12 @@
"type": "image/x-icon"
},
{
- "src": "logo192.png",
+ "src": "deckIcon2.png",
"type": "image/png",
"sizes": "192x192"
},
{
- "src": "logo512.png",
+ "src": "deckIcon2.png",
"type": "image/png",
"sizes": "512x512"
}
diff --git a/public/blue-eyes.jpeg b/public/monsterImages/blue-eyes.jpeg
similarity index 100%
rename from public/blue-eyes.jpeg
rename to public/monsterImages/blue-eyes.jpeg
diff --git a/public/exodia.webp b/public/monsterImages/exodia.webp
similarity index 100%
rename from public/exodia.webp
rename to public/monsterImages/exodia.webp
diff --git a/public/kuriboh.jpeg b/public/monsterImages/kuriboh.jpeg
similarity index 100%
rename from public/kuriboh.jpeg
rename to public/monsterImages/kuriboh.jpeg
diff --git a/public/neos.jpeg b/public/monsterImages/neos.jpeg
similarity index 100%
rename from public/neos.jpeg
rename to public/monsterImages/neos.jpeg
diff --git a/public/panther.png b/public/monsterImages/panther.png
similarity index 100%
rename from public/panther.png
rename to public/monsterImages/panther.png
diff --git a/public/red-eyes.jpeg b/public/monsterImages/red-eyes.jpeg
similarity index 100%
rename from public/red-eyes.jpeg
rename to public/monsterImages/red-eyes.jpeg
diff --git a/public/skull-servant.jpeg b/public/monsterImages/skull-servant.jpeg
similarity index 100%
rename from public/skull-servant.jpeg
rename to public/monsterImages/skull-servant.jpeg
diff --git a/public/temple.jpeg b/public/monsterImages/temple.jpeg
similarity index 100%
rename from public/temple.jpeg
rename to public/monsterImages/temple.jpeg
diff --git a/public/toon.png b/public/monsterImages/toon.png
similarity index 100%
rename from public/toon.png
rename to public/monsterImages/toon.png
diff --git a/public/screenshot.png b/public/siteImages/screenshot.png
similarity index 100%
rename from public/screenshot.png
rename to public/siteImages/screenshot.png
diff --git a/src/App.js b/src/App.js
index 457943f..db8da5c 100644
--- a/src/App.js
+++ b/src/App.js
@@ -36,40 +36,38 @@ const App = () => {
// const user = cookies?.user;
// const userId = user?.id;
const [currentPage, setCurrentPage] = useState('');
- // const { setContext } = useAppContext(); // Assuming useAppContext provides setContext
const { fetchAllCollectionsForUser, selectedCollection } =
useCollectionStore();
const { user, fetchUser } = useUserContext();
const userId = user?.id;
- console.log('user', user);
- console.log('userId', userId);
const [showLoginDialog, setShowLoginDialog] = useState(false);
const { allDecks, fetchAllDecksForUser, selectedDeck } = useDeckStore();
const { fetchUserCart, cartData } = useCartStore();
const { isLoading, setIsLoading } = useUtilityContext();
- const handleLoginSuccess = (isLoggedIn, userId) => {
- // Close the dialog and perform other actions if needed
- setShowLoginDialog(false);
- console.log('isLoggedIn', isLoggedIn);
- console.log('userId', userId);
- };
// useEffect(() => {
// getRandomCardImages(10); // Fetch 10 random images on app start
// }, []); // Add this useEffect
+ const handleLoginSuccess = (isLoggedIn, userId) => {
+ setShowLoginDialog(false);
+ setIsLoading(false);
+ // Perform other actions after login
+ };
+
useEffect(() => {
- // Open the login dialog if there's no userId
+ // Open the login dialog and pause splash page if there's no userId
if (!userId) {
- setIsLoading(false);
setShowLoginDialog(true);
+ setIsLoading(true); // Continue showing splash page
} else {
setShowLoginDialog(false);
+ setIsLoading(false); // Hide splash page
}
}, [userId]);
useEffect(() => {
- if (userId) {
+ if (userId && typeof userId === 'string') {
fetchAllCollectionsForUser()
.then(() => {
setIsLoading(false);
@@ -84,20 +82,24 @@ const App = () => {
// console.log('Checking userId in useEffect:', userId);
// setShowLoginDialog(!userId);
// }, [userId]);
+ useEffect(() => {
+ if (userId && typeof userId === 'string') {
+ fetchAllDecksForUser()
+ .then(() => {
+ setIsLoading(false);
+ })
+ .catch((error) => console.error('Error fetching decks:', error));
+ }
+ }, [userId, fetchAllDecksForUser, selectedDeck, setIsLoading]);
// useEffect(() => {
- // if (user) {
- // fetchAllDecksForUser(user?.id).catch((err) =>
- // console.error('Failed to get all decks:', err)
- // );
- // }
- // }, [fetchAllDecksForUser]);
- // useEffect(() => {
- // if (user) {
- // fetchUserCart(user?.id).catch((err) =>
- // console.error('Failed to get cart:', err)
- // );
+ // if (userId && typeof userId === 'string') {
+ // fetchUserCart()
+ // .then(() => {
+ // setIsLoading(false);
+ // })
+ // .catch((error) => console.error('Error fetching cart:', error));
// }
- // }, [fetchUserCart]);
+ // }, [userId, fetchUserCart, cartData, setIsLoading]);
// Handle initial loading state
useEffect(() => {
@@ -124,10 +126,6 @@ const App = () => {
) : (
- {console.log(
- 'Login Dialog should be:',
- showLoginDialog ? 'Open' : 'Closed'
- )}
setShowLoginDialog(false)}
@@ -179,7 +177,7 @@ const App = () => {
} />
{/* Add a Route for 404 Not Found page if needed */}
-
+ {/* */}
)}
diff --git a/src/assets/themeSettings.jsx b/src/assets/themeSettings.jsx
index e3c7751..f4c437e 100644
--- a/src/assets/themeSettings.jsx
+++ b/src/assets/themeSettings.jsx
@@ -69,6 +69,8 @@ export const themeSettings = (mode) => {
},
success: {
light: colors.greenAccent[100],
+ lighter: colors.greenAccent[200],
+ evenLighter: colors.greenAccent[300],
main: colors.greenAccent[500],
dark: colors.greenAccent[200],
contrastText: '#fff',
@@ -85,41 +87,50 @@ export const themeSettings = (mode) => {
hover: mode === 'dark' ? colors.grey[800] : colors.grey[200],
},
},
- // chart: {
- // palette: {
- // primary: {
- // main: colors.greenAccent[500],
- // light: colors.greenAccent[300],
- // dark: colors.greenAccent[700],
- // contrastText: '#fff',
- // },
- // secondary: {
- // main: colors.greenAccent[200],
- // light: colors.greenAccent[100],
- // dark: colors.greenAccent[400],
- // contrastText: '#000',
- // },
- // background: {
- // paper: colors.greenAccent[100],
- // default: colors.greenAccent[200],
- // },
- // text: {
- // primary: colors.greenAccent[800],
- // secondary: colors.greenAccent[600],
- // },
- // chartColors: [
- // colors.greenAccent[500],
- // colors.greenAccent[400],
- // colors.greenAccent[300],
- // colors.greenAccent[200],
- // colors.greenAccent[100],
- // ],
- // },
- // typography: {
- // // Define typography styles if needed
- // },
- // },
-
+ chart: {
+ axis: {
+ domain: {
+ line: {
+ stroke: colors.greenAccent[800],
+ strokeWidth: 1,
+ },
+ },
+ ticks: {
+ line: {
+ stroke: colors.greenAccent[700],
+ strokeWidth: 1,
+ },
+ text: {
+ fill: colors.greenAccent[900],
+ fontSize: 12,
+ },
+ },
+ },
+ grid: {
+ line: {
+ stroke: colors.greenAccent[200],
+ strokeWidth: 1,
+ },
+ },
+ legends: {
+ text: {
+ fill: colors.greenAccent[800],
+ fontSize: 12,
+ },
+ },
+ tooltip: {
+ container: {
+ background: colors.greenAccent[100],
+ color: colors.greenAccent[800],
+ fontSize: 12,
+ borderRadius: 4,
+ boxShadow: '0 2px 4px rgba(0,0,0,0.25)',
+ },
+ },
+ points: {
+ borderColor: colors.greenAccent[800],
+ },
+ },
spacing: (factor) => `${0.25 * factor}rem`,
shape: {
borderRadius: 4,
diff --git a/src/components/buttons/actionButtons/CardActionButtons.jsx b/src/components/buttons/actionButtons/CardActionButtons.jsx
index 1e1314f..e0a2ea8 100644
--- a/src/components/buttons/actionButtons/CardActionButtons.jsx
+++ b/src/components/buttons/actionButtons/CardActionButtons.jsx
@@ -17,6 +17,10 @@ import { useDeckStore } from '../../../context/DeckContext/DeckContext';
import { useCartStore } from '../../../context/CartContext/CartContext';
import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline';
import DeleteIcon from '@material-ui/icons/Delete';
+import {
+ AddCircleOutlineOutlined,
+ RemoveCircleOutlineOutlined,
+} from '@mui/icons-material';
const cardOtherLogger = new Logger([
'Action',
'Card Name',
@@ -35,9 +39,30 @@ const CardActionButtons = ({
// const { contextProps, isContextAvailable } = useAppContext(context);
const isLargeScreen = useMediaQuery(theme.breakpoints.up('lg'));
- const { addOneToCollection, removeOneFromCollection } = useCollectionStore();
- const { addOneToDeck, removeOneFromDeck } = useDeckStore();
- const { addOneToCart, removeOneFromCart } = useCartStore();
+ const { addOneToCollection, removeOneFromCollection, selectedCollection } =
+ useCollectionStore();
+ const { addOneToDeck, removeOneFromDeck, selectedDeck } = useDeckStore();
+ const { addOneToCart, removeOneFromCart, cartData } = useCartStore();
+
+ // modified to work with any context
+ // Function to check if a card is in a specific context
+ const isCardInContext = useCallback(() => {
+ switch (context) {
+ case 'Collection':
+ return !!selectedCollection?.cards?.find(
+ (c) => c?.card?.id === card?.id
+ );
+ case 'Deck':
+ return !!selectedDeck?.cards?.find((c) => c?.card?.id === card?.id);
+ case 'Cart':
+ return !!cartData?.cart?.find((c) => c?.card?.id === card?.id);
+ default:
+ return false;
+ }
+ }, [card.id, context, selectedCollection, selectedDeck, cartData]);
+
+ const isInContext = isCardInContext();
+
const styles = {
box: {
display: 'flex',
@@ -147,75 +172,43 @@ const CardActionButtons = ({
performAction(REMOVE_ALL, card);
closeModal?.();
};
-
return (
-
- {!isLargeScreen && (
- <>
-
-
+ {isInContext ? (
+
+
+ handleAddClick()}
>
-
- {`In ${context}: `}
-
-
- {card.quantity}
-
-
-
-
-
- +
-
-
- -
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+ handleRemoveOne()}
+ >
+
+
- >
+
+ ) : (
+ handleAddClick()}
+ >
+ Add to {context}
+
)}
-
- {`Add to ${context}`}
-
-
- {`Remove from ${context}`}
-
);
};
diff --git a/src/components/buttons/actionButtons/GenericActionButtons.jsx b/src/components/buttons/actionButtons/GenericActionButtons.jsx
index cf898e9..4db760a 100644
--- a/src/components/buttons/actionButtons/GenericActionButtons.jsx
+++ b/src/components/buttons/actionButtons/GenericActionButtons.jsx
@@ -47,122 +47,3 @@ const GenericActionButtons = ({ card, context }) => {
};
export default GenericActionButtons;
-
-// import React, { useContext } from 'react';
-// import CardActionButtons from './CardActionButtons';
-// import useAppContext from '../../../context/hooks/useAppContext';
-// import { ModalContext } from '../../../context/ModalContext/ModalContext';
-// import { Box } from '@mui/material';
-
-// const GenericActionButtons = ({ card, context }) => {
-// const contextProps = useAppContext(); // Assuming useAppContext returns the context object
-// const { closeModal, isModalOpen, setModalOpen } = useContext(ModalContext);
-
-// if (!contextProps) {
-// return (
-// Provider not found for {context}
-// );
-// }
-
-// let modifiedContextProps = contextProps[context];
-
-// if (!modifiedContextProps) {
-// return (
-//
-// Invalid context provided: {context}
-//
-// );
-// }
-
-// return (
-//
-// setModalOpen(false)}
-// open={isModalOpen}
-// />
-//
-// );
-// };
-
-// export default GenericActionButtons;
-
-// import React, { useContext, useEffect } from 'react';
-// import { makeStyles } from '@mui/styles';
-// import GenericCardModal from '../../modals/GenericCardModal';
-// import CardActionButtons from './CardActionButtons';
-// import useAppContext from '../../../context/hooks/useAppContext';
-// import { ModalContext } from '../../../context/ModalContext/ModalContext';
-
-// const useStyles = makeStyles({
-// root: {
-// display: 'flex',
-// flexDirection: 'column',
-// justifyContent: 'space-evenly',
-// height: '100%',
-// },
-// });
-
-// const GenericActionButtons = ({
-// card,
-// context,
-// open,
-// openModal,
-// // closeModal,
-// // isModalOpen,
-// // setModalOpen,
-// }) => {
-// const classes = useStyles();
-// const [contextProps, isContextAvailable] = useAppContext(context);
-// const {
-// openModalWithCard,
-// closeModal,
-// isModalOpen,
-// setModalOpen,
-// modalContent,
-// } = useContext(ModalContext);
-// if (!isContextAvailable) {
-// console.error(`The component isn't wrapped with the ${context}Provider`);
-// return null; // Consider rendering an error boundary or user-friendly error message instead.
-// }
-
-// // Ensure contextProps is an object with the expected methods before using them
-// if (
-// typeof contextProps !== 'object' ||
-// typeof contextProps[context] !== 'object'
-// ) {
-// console.error(`Invalid contextProps provided for the context: ${context}`);
-// return null; // Consider rendering an error boundary or user-friendly error message instead.
-// }
-
-// return (
-//
-// setModalOpen(false)}
-// open={open}
-// />
-// {/* */}
-//
-// );
-// };
-
-// export default GenericActionButtons;
diff --git a/src/components/Auth/SignupSwitch.jsx b/src/components/buttons/other/SignupSwitch.jsx
similarity index 100%
rename from src/components/Auth/SignupSwitch.jsx
rename to src/components/buttons/other/SignupSwitch.jsx
diff --git a/src/components/cards/GenericCard.jsx b/src/components/cards/GenericCard.jsx
index 8c6ceea..156c962 100644
--- a/src/components/cards/GenericCard.jsx
+++ b/src/components/cards/GenericCard.jsx
@@ -40,9 +40,6 @@ const StyledCard = styled(Card)(({ theme }) => ({
const GenericCard = React.forwardRef((props, ref) => {
const { theme } = useMode();
const { card, context, setClickedCard } = props;
- // const isLargeScreen = useMediaQuery(theme.breakpoints.up('lg'));
-
- const { selectedCollection } = useCollectionStore();
const { openModalWithCard, setModalOpen } = useContext(ModalContext);
const { setHoveredCard, setIsPopoverOpen, hoveredCard } =
useContext(PopoverContext);
@@ -117,126 +114,3 @@ const GenericCard = React.forwardRef((props, ref) => {
GenericCard.displayName = 'GenericCard';
export default GenericCard;
-
-// import React, { useContext, useEffect } from 'react';
-// import { Card, CardContent, CardActions, Typography } from '@mui/material';
-// import CardMediaSection from '../media/CardMediaSection';
-// import GenericActionButtons from '../buttons/actionButtons/GenericActionButtons';
-// import placeholderImage from '../../assets/images/placeholder.jpeg';
-// import { useStyles } from './cardStyles';
-// import { useCollectionStore } from '../../context/CollectionContext/CollectionContext';
-// import { ModalContext } from '../../context/ModalContext/ModalContext';
-// import { PopoverContext } from '../../context/PopoverContext/PopoverContext';
-
-// const GenericCard = React.forwardRef((props, ref) => {
-// const {
-// card,
-// context,
-// // isModalOpen,
-// // setModalOpen,
-// // hoveredCard,
-// // setHoveredCard,
-// // setIsPopoverOpen,
-// setClickedCard,
-// } = props;
-// const classes = useStyles();
-// const { selectedCollection } = useCollectionStore();
-// const {
-// openModalWithCard,
-// closeModal,
-// isModalOpen,
-// setModalOpen,
-// modalContent,
-// } = useContext(ModalContext);
-// const { setHoveredCard, setIsPopoverOpen, hoveredCard } =
-// useContext(PopoverContext);
-
-// const requiresDoubleButtons = context === 'Deck' || context === 'Collection'; // Added this line
-// const checkCardInCollection = () => {
-// if (selectedCollection) {
-// const cardIds = selectedCollection?.cards?.map((card) => card.id);
-// return cardIds?.includes(card.id);
-// }
-// return false;
-// };
-
-// const handleClick = () => {
-// const cardIsInCollection = checkCardInCollection();
-// console.log('Modal opened with card:', card);
-// openModalWithCard(card);
-// console.log('Card is in collection:', cardIsInCollection);
-
-// setModalOpen(true);
-// setIsPopoverOpen(false);
-// };
-// // setIsPopoverOpen(false);
-
-// // Function to handle hover interactions with the card
-// // const handleInteraction = (hoverState) => {
-// // if (!isModalOpen) {
-// // setHoveredCard((prev) => (hoverState ? card : null));
-// // setIsPopoverOpen(hoverState);
-// // }
-// // };
-// const handleInteraction = (hoverState) => {
-// if (!isModalOpen) {
-// setHoveredCard(hoverState ? card : null);
-// setIsPopoverOpen(hoverState);
-// }
-// };
-// // Effect to close popover when modal is open or reactivate when modal closes
-// useEffect(() => {
-// setIsPopoverOpen(isModalOpen ? false : hoveredCard === card);
-// if (isModalOpen) {
-// setHoveredCard(null);
-// }
-// }, [isModalOpen, hoveredCard, card, setIsPopoverOpen, setHoveredCard]);
-
-// // Get the card image URL, or use placeholder if not available
-// const imgUrl = card?.card_images?.[0]?.image_url || placeholderImage;
-// const price = `Price: ${card?.card_prices?.[0]?.tcgplayer_price || 'N/A'}`;
-// console.log(typeof handleInteraction); // Should log 'function'
-
-// return (
-//
-//
-//
-// {card?.name}
-//
-// {price}
-//
-//
-//
-// {requiresDoubleButtons ? (
-// <>
-//
-// {/* TODO fix card to display buttons for both collections and decks */}
-// >
-// ) : (
-//
-// )}
-//
-//
-// );
-// });
-
-// GenericCard.displayName = 'GenericCard';
-
-// export default GenericCard;
diff --git a/src/components/chart/ChartTooltip.jsx b/src/components/chart/ChartTooltip.jsx
index c5dee1b..f9717a9 100644
--- a/src/components/chart/ChartTooltip.jsx
+++ b/src/components/chart/ChartTooltip.jsx
@@ -1,9 +1,7 @@
import React from 'react';
import { makeStyles, Tooltip, Typography } from '@mui/material';
-// Define your styles here
const useStyles = makeStyles((theme) => ({
- // ... your other styles
tooltipTarget: {
cursor: 'pointer', // Change the cursor to indicate it's hoverable
},
diff --git a/src/components/chart/LinearChart.js b/src/components/chart/LinearChart.js
index 3e6ab33..f8618af 100644
--- a/src/components/chart/LinearChart.js
+++ b/src/components/chart/LinearChart.js
@@ -1,22 +1,22 @@
import React, { useState, useMemo, useCallback } from 'react';
import { ResponsiveLine } from '@nivo/line';
import { Typography, Box, Tooltip, useTheme } from '@mui/material';
-import { styled } from '@mui/material/styles';
import ChartErrorBoundary from '../reusable/ChartErrorBoundary';
-import { tokens } from '../../assets/tokens';
import { useMode } from '../../context/hooks/colormode';
-
-const AxisLabel = styled(Typography)(({ theme, axis }) => ({
- position: 'absolute',
- [axis === 'x' ? 'bottom' : 'top']: 0,
- [axis === 'x' ? 'left' : 'right']: '50%',
- transform:
- axis === 'x' ? 'translateX(-50%)' : 'translateY(-50%) rotate(-90deg)',
- textAlign: 'center',
- margin: theme.spacing(2),
- fontSize: '1rem',
- fontWeight: 'bold',
- color: theme.palette.text.primary,
+import { makeStyles } from '@mui/styles';
+const useStyles = makeStyles((theme) => ({
+ axisLabel: {
+ position: 'absolute',
+ textAlign: 'center',
+ margin: theme.spacing(2),
+ fontSize: '1rem',
+ fontWeight: 'bold',
+ color: theme.palette.text.primary,
+ },
+ chartContainer: {
+ width: '100%',
+ height: 'auto',
+ },
}));
const CustomTooltip = ({ point }) => {
@@ -62,32 +62,19 @@ const LinearChart = ({
timeRange,
}) => {
const { theme } = useMode();
- // const colors = tokens(theme.palette.mode);
- const greenAccent = {
- 100: '#dbf5ee',
- 200: '#b7ebde',
- 300: '#94e2cd',
- 400: '#70d8bd',
- 500: '#4cceac',
- 600: '#3da58a',
- 700: '#2e7c67',
- 800: '#1e5245',
- 900: '#0f2922',
- };
+ const classes = useStyles(theme);
const [isZoomed, setIsZoomed] = useState(false);
const { handleMouseMove, handleMouseLeave } = useEventHandlers();
-
- // const { tickValues, xFormat } = useMemo(() => {
- // const timeFormats = {
- // '2 hours': { format: '%H:%M', ticks: 'every 15 minutes' },
- // '24 hours': { format: '%H:%M', ticks: 'every 1 hour' },
- // '7 days': { format: '%b %d', ticks: 'every 1 day' },
- // '1 month': { format: '%b %d', ticks: 'every 3 days' },
- // default: { format: '%b %d', ticks: 'every 1 day' },
- // };
- // return timeFormats[timeRange] || timeFormats.default;
- // }, [timeRange]);
-
+ if (
+ !Array.isArray(filteredChartData) ||
+ filteredChartData.some((d) => !d.x || !d.y)
+ ) {
+ return (
+
+ No valid data available
+
+ );
+ }
const { tickValues, xFormat } = useMemo(() => {
let format, ticks;
switch (timeRange) {
@@ -97,11 +84,11 @@ const LinearChart = ({
break;
case '24 hours':
format = '%H:%M';
- ticks = 'every 1 hour';
+ ticks = 'every hour';
break;
case '7 days':
format = '%b %d';
- ticks = 'every 1 day';
+ ticks = 'every day';
break;
case '1 month':
format = '%b %d';
@@ -109,31 +96,37 @@ const LinearChart = ({
break;
default:
format = '%b %d';
- ticks = 'every 1 day';
+ ticks = 'every day';
}
return { tickValues: ticks, xFormat: `time:${format}` };
}, [timeRange]);
-
- if (
- !Array.isArray(filteredChartData) ||
- filteredChartData.some((d) => !d.x || !d.y)
- ) {
- return (
-
- No valid data available
-
- );
- }
+ const currentTime = new Date().getTime();
+ const dataWithinTimeRange = useMemo(() => {
+ return nivoReadyData.map((series) => ({
+ ...series,
+ data: series?.data.filter((dataPoint) => {
+ const dataPointTime = new Date(dataPoint?.x).getTime();
+ const isWithinRange = dataPointTime >= currentTime - timeRange;
+ // Detailed logging
+ // console.log(
+ // `Data Point: ${new Date(
+ // dataPointTime
+ // ).toISOString()}, Current Time: ${new Date(
+ // currentTime
+ // ).toISOString()}, Within Range: ${isWithinRange}`
+ // );
+ return isWithinRange;
+ }),
+ }));
+ }, [nivoReadyData, timeRange]);
const chartProps = {
- // theme: theme.chart,
margin: { top: 50, right: 110, bottom: 50, left: 60 },
- data: nivoReadyData,
+ data: dataWithinTimeRange,
animate: true,
motionStiffness: 90,
motionDamping: 15,
background: '#2c2121',
-
xScale: {
type: 'time',
format: '%Y-%m-%dT%H:%M:%S.%LZ',
@@ -151,7 +144,6 @@ const LinearChart = ({
tickValues: tickValues,
},
yScale: { type: 'linear', min: 'auto', max: 'auto' },
-
axisLeft: {
orient: 'left',
legend: 'Value ($)',
@@ -163,76 +155,28 @@ const LinearChart = ({
},
pointSize: 8,
pointBorderWidth: 2,
-
pointColor: theme.palette.success.light,
colors: theme.palette.primaryDark.main,
lineWidth: 3,
curve: 'monotoneX',
useMesh: true,
- theme: {
- chart: {
- axis: {
- domain: {
- line: {
- stroke: greenAccent[800],
- strokeWidth: 1,
- },
- },
- ticks: {
- line: {
- stroke: greenAccent[700],
- strokeWidth: 1,
- },
- text: {
- fill: greenAccent[900],
- fontSize: 12,
- },
- },
- },
- grid: {
- line: {
- stroke: greenAccent[200],
- strokeWidth: 1,
- },
- },
- legends: {
- text: {
- fill: greenAccent[800],
- fontSize: 12,
- },
- },
- tooltip: {
- container: {
- background: greenAccent[100],
- color: greenAccent[800],
- fontSize: 12,
- borderRadius: 4,
- boxShadow: '0 2px 4px rgba(0,0,0,0.25)',
- },
- },
- points: {
- borderColor: greenAccent[800],
- },
- },
- },
+ theme: theme.chart,
+ // onMouseMove: (point) => setIsZoomed(point ? true : false),
+ // onMouseLeave: () => setIsZoomed(false),
onMouseMove: handleMouseMove,
onMouseLeave: handleMouseLeave,
onClick: () => setIsZoomed(!isZoomed),
tooltip: CustomTooltip,
- // sliceTooltip: ({ slice }) => {
- // const point = slice.points.find(
- // (p) => p.id === 'Data' && p.data.x === latestData.x
- // );
- // xFormat,
- // tickValues,
};
return (
-
+
+ {/*
*/}
- {/*
Time
-
Value ($) */}
);
diff --git a/src/components/chart/PortfolioChart.jsx b/src/components/chart/PortfolioChart.jsx
index 8c25bd6..1a8b659 100644
--- a/src/components/chart/PortfolioChart.jsx
+++ b/src/components/chart/PortfolioChart.jsx
@@ -59,19 +59,32 @@ const PortfolioChart = () => {
() => handleThresholdUpdate(lastUpdateTime, setLastUpdateTime),
[lastUpdateTime]
);
+ // const filteredChartData2 = useMemo(
+ // () => getFilteredData2(selectedCollection),
+ // [selectedCollection]
+ // );
+ // const rawData2 = useMemo(
+ // () => groupAndAverageData(filteredChartData2, threshold),
+ // [filteredChartData2, threshold]
+ // );
+ // const nivoReadyData2 = useMemo(
+ // () => convertDataForNivo2(rawData2),
+ // [rawData2]
+ // );
const filteredChartData2 = useMemo(
- () => getFilteredData2(selectedCollection),
- [selectedCollection]
+ () => getFilteredData2(selectedCollection, timeRange), // Adjust to filter data based on timeRange
+ [selectedCollection, timeRange]
);
+
const rawData2 = useMemo(
- () => groupAndAverageData(filteredChartData2, threshold),
- [filteredChartData2, threshold]
+ () => groupAndAverageData(filteredChartData2, threshold, timeRange), // Adjust to group and average data based on timeRange
+ [filteredChartData2, threshold, timeRange]
);
+
const nivoReadyData2 = useMemo(
() => convertDataForNivo2(rawData2),
[rawData2]
);
-
console.log('Selected Collection:', selectedCollection);
console.log('Filtered Chart Data:', filteredChartData2);
console.log('Raw Data:', rawData2);
@@ -118,11 +131,9 @@ const PortfolioChart = () => {
{
nivoReadyData={nivoReadyData2}
filteredChartData={filteredChartData2}
latestData={latestData}
+ timeRange={timeRange}
dimensions={chartDimensions}
timeRanges={timeRange}
/>
diff --git a/src/components/collection/CardPortfolio.jsx b/src/components/collection/CardPortfolio.jsx
index aa2b248..a1c9164 100644
--- a/src/components/collection/CardPortfolio.jsx
+++ b/src/components/collection/CardPortfolio.jsx
@@ -1,9 +1,9 @@
import React, { useEffect, useRef, useState } from 'react';
import SelectCollection from './SelectCollection';
-import PortfolioContent from '../../containers/collectionPageContainers/PortfolioContent';
+import PortfolioContent from './PortfolioContent';
import { Box, Typography } from '@mui/material';
-import CollectionContainer from '../../containers/collectionPageContainers/CollectionContainer';
import { useCollectionStore } from '../../context/CollectionContext/CollectionContext';
+import { CollectionContainer } from '../../pages/pageStyles/StyledComponents';
// import UpdateChartData from './UpdateChartData';
const CardPortfolio = ({ allCollections }) => {
@@ -70,18 +70,7 @@ const CardPortfolio = ({ allCollections }) => {
) : showPortfolio ? (
) : (
@@ -89,7 +78,6 @@ const CardPortfolio = ({ allCollections }) => {
display="flex"
alignItems="center"
justifyContent="center"
- // minHeight="100vh"
backgroundColor="#f1f1f1"
>
No Collection Selected
diff --git a/src/containers/collectionPageContainers/PortfolioContent.jsx b/src/components/collection/PortfolioContent.jsx
similarity index 74%
rename from src/containers/collectionPageContainers/PortfolioContent.jsx
rename to src/components/collection/PortfolioContent.jsx
index 2a7d5d2..66f7773 100644
--- a/src/containers/collectionPageContainers/PortfolioContent.jsx
+++ b/src/components/collection/PortfolioContent.jsx
@@ -1,10 +1,12 @@
import React from 'react';
import { Box, Container, Grid, Paper, useTheme } from '@mui/material';
-import PortfolioListContainer from './PortfolioListContainer';
-import PortfolioChartContainer from './PortfolioChartContainer';
-import HeaderTitle from '../../components/reusable/HeaderTitle';
+import HeaderTitle from '../reusable/HeaderTitle';
import { useCollectionStore } from '../../context/CollectionContext/CollectionContext';
import { useMode } from '../../context/hooks/colormode';
+// eslint-disable-next-line max-len
+import CollectionPortfolioChartContainer from '../../containers/collectionPageContainers/CollectionPortfolioChartContainer';
+// eslint-disable-next-line max-len
+import CollectionPortfolioListContainer from '../../containers/collectionPageContainers/CollectionPortfolioListContainer';
const PortfolioContent = ({ error, selectedCards, removeCard }) => {
const { theme } = useMode();
@@ -35,6 +37,7 @@ const PortfolioContent = ({ error, selectedCards, removeCard }) => {
flexDirection: 'column',
margin: 'auto',
width: '100%',
+ padding: theme.spacing(2),
borderRadius: theme.shape.borderRadius,
}}
>
@@ -42,6 +45,7 @@ const PortfolioContent = ({ error, selectedCards, removeCard }) => {
title={selectedCollection?.name}
size="large"
location="center"
+ theme={theme}
/>
{
sx={{
width: '100%',
maxWidth: '100vw',
+ // minHeight: '100%',
justifyContent: 'center',
margin: 'auto',
}}
@@ -57,16 +62,18 @@ const PortfolioContent = ({ error, selectedCards, removeCard }) => {
-
-
-
+
diff --git a/src/components/collection/SelectCollection.jsx b/src/components/collection/SelectCollection.jsx
index ba03979..76e38ba 100644
--- a/src/components/collection/SelectCollection.jsx
+++ b/src/components/collection/SelectCollection.jsx
@@ -7,22 +7,63 @@ import SimpleReusableButton from '../reusable/SimpleReusableButton';
import SelectCollectionList from '../grids/collectionGrids/SelectCollectionList';
import CreateOrEditCollectionDialog from '../dialogs/CreateOrEditCollectionDialog';
import { useCollectionStore } from '../../context/CollectionContext/CollectionContext';
+import { useMode } from '../../context/hooks/colormode';
+import StatBox from '../other/dataDisplay/StatBox';
+import StatisticsArea from '../other/dataDisplay/StatisticsArea';
+import {
+ MainContainer,
+ MainContainer2,
+ MainContainer3,
+} from '../../pages/pageStyles/StyledComponents';
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
+ margin: 'auto',
+ padding: theme.spacing(4),
alignItems: 'stretch',
- height: '100%',
+ height: '80vh',
+ width: '100%',
+ backgroundColor: theme.palette.background.paper,
+ borderRadius: theme.shape.borderRadius,
// width: '50vw',
- padding: theme.spacing(2),
},
button: {
marginBottom: theme.spacing(2),
+ margin: theme.spacing(2),
+ padding: theme.spacing(2),
},
list: {
flexGrow: 1,
+ overflowY: 'auto',
+ overflowX: 'hidden',
+ padding: theme.spacing(2),
+ borderRadius: theme.shape.borderRadius,
+ backgroundColor: theme.palette.success.evenLighter,
+ boxShadow: theme.shadows[3],
+ width: '100%',
+ },
+ middleContainer: {
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ // marginTop: theme.spacing(1),
+ // alignSelf: 'start',
+ justifySelf: 'center',
+ alignItems: 'center',
+ gap: theme.spacing(2),
+ padding: theme.spacing(4),
+ borderRadius: theme.shape.borderRadius,
+ backgroundColor: theme.palette.background.quinternary,
+ boxShadow: theme.shadows[3],
+ width: '80%',
+ height: '100%',
+ // margin: 0,
+ // marginLeft: theme.spacing(2),
+ // marginRight: theme.spacing(2),
+ // height: '100%',
},
}));
@@ -31,9 +72,8 @@ const SelectCollection = ({
setShowCollections,
setShowPortfolio,
}) => {
- const classes = useStyles();
- const [cookies] = useCookies(['userCookie']);
- const userId = cookies.userCookie?.userId;
+ const theme = useMode();
+ const classes = useStyles(theme);
const [isDialogOpen, setDialogOpen] = useState(false);
const [isNew, setIsNew] = useState(false);
const { setSelectedCollection, selectedCollection } = useCollectionStore();
@@ -80,37 +120,56 @@ const SelectCollection = ({
}, [selectedCollection]);
return (
-
- Choose a Collection
-
- Add New Collection
-
-
-
openDialog(false)} // Indicate that this is not a new collection
+
+
+
+ Choose a Collection
+
+ {/*
+
+ {/* */}
+ {/* */}
+
+
+ Add New Collection
+
+
+
+ openDialog(false)} // Indicate that this is not a new collection
+ />
+
+
-
-
+
);
};
diff --git a/src/components/dialogs/LoginDialog.jsx b/src/components/dialogs/LoginDialog.jsx
index d30529f..2095580 100644
--- a/src/components/dialogs/LoginDialog.jsx
+++ b/src/components/dialogs/LoginDialog.jsx
@@ -7,7 +7,7 @@ import {
IconButton,
} from '@mui/material';
import LoginForm from '../forms/LoginForm';
-import SignupSwitch from '../Auth/SignupSwitch';
+import SignupSwitch from '../buttons/other/SignupSwitch';
import Brightness4Icon from '@mui/icons-material/Brightness4';
import Brightness7Icon from '@mui/icons-material/Brightness7';
import { useMode } from '../../context/hooks/colormode';
diff --git a/src/components/forms/customerCheckoutForm/CartActions.jsx b/src/components/forms/customerCheckoutForm/CartActions.jsx
index 65ba644..d52b3b0 100644
--- a/src/components/forms/customerCheckoutForm/CartActions.jsx
+++ b/src/components/forms/customerCheckoutForm/CartActions.jsx
@@ -3,10 +3,10 @@ import { Box } from '@mui/material';
import CartSummary from '../../other/dataDisplay/CartSummary';
import OrderSubmitButton from '../../buttons/other/OrderSubmitButton';
-const CartActions = ({ quantity, getTotalCost, handleModalOpen }) => {
+const CartActions = ({ quantity, totalCost, handleModalOpen }) => {
return (
-
+
);
diff --git a/src/components/forms/customerCheckoutForm/CustomerForm.js b/src/components/forms/customerCheckoutForm/CustomerForm.js
index 7be8582..ad33c81 100644
--- a/src/components/forms/customerCheckoutForm/CustomerForm.js
+++ b/src/components/forms/customerCheckoutForm/CustomerForm.js
@@ -15,7 +15,7 @@ const CustomerForm = () => {
setModalOpen,
modalContent,
} = useContext(ModalContext);
- const { cartCardQuantity } = useCartStore();
+ const { cartCardQuantity, totalCost } = useCartStore();
const handleModalOpen = useCallback(() => setModalOpen(true), [setModalOpen]);
const handleModalClose = useCallback(
@@ -52,7 +52,7 @@ const CustomerForm = () => {
diff --git a/src/components/grids/collectionGrids/CardList.jsx b/src/components/grids/collectionGrids/CardList.jsx
index 787831d..4f3b7dc 100644
--- a/src/components/grids/collectionGrids/CardList.jsx
+++ b/src/components/grids/collectionGrids/CardList.jsx
@@ -39,9 +39,10 @@ const StyledContainer = styled(Container)(({ theme }) => ({
height: '100%',
alignItems: 'center',
background: theme.palette.background.dark,
+ padding: theme.spacing(2),
color: '#fff', // White text color
- padding: 2,
- borderRadius: 2,
+ // padding: 2,
+ borderRadius: 4,
}));
// const Paper = styled(MuiPaper)(({ theme }) => ({
diff --git a/src/components/grids/collectionGrids/SelectCollectionList.jsx b/src/components/grids/collectionGrids/SelectCollectionList.jsx
index 7b5de9b..de39e38 100644
--- a/src/components/grids/collectionGrids/SelectCollectionList.jsx
+++ b/src/components/grids/collectionGrids/SelectCollectionList.jsx
@@ -14,7 +14,10 @@ import { useCookies } from 'react-cookie';
import PropTypes from 'prop-types';
import LoadingIndicator from '../../reusable/indicators/LoadingIndicator';
import { useCollectionStore } from '../../../context/CollectionContext/CollectionContext';
-
+import { useStatisticsStore } from '../../../context/StatisticsContext/StatisticsContext';
+import { useMode } from '../../../context/hooks/colormode';
+import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
+import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
const useStyles = makeStyles((theme) => ({
listItem: {
display: 'flex',
@@ -23,6 +26,7 @@ const useStyles = makeStyles((theme) => ({
padding: theme.spacing(2),
backgroundColor: '#ffffff',
borderRadius: '8px',
+ width: '100%',
marginBottom: theme.spacing(2),
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)',
},
@@ -49,12 +53,19 @@ const useStyles = makeStyles((theme) => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
+ width: '100%',
justifyContent: 'center',
padding: theme.spacing(1),
},
gridItemText: {
fontWeight: 'bold',
},
+ positivePerformance: {
+ color: 'green',
+ },
+ negativePerformance: {
+ color: 'red',
+ },
}));
const SelectCollectionList = ({
@@ -62,14 +73,37 @@ const SelectCollectionList = ({
openDialog,
collectionIdFromDialog,
}) => {
+ const { theme } = useMode();
const classes = useStyles();
- const { allCollections, setSelectedCollection, selectedCollection } =
- useCollectionStore();
- const [cookies] = useCookies(['userCookie']);
+ const {
+ setSelectedCollection,
+ selectedCollection,
+ allCollections,
+ setAllCollections,
+ } = useCollectionStore();
+ const { stats } = useStatisticsStore();
const [isLoading, setIsLoading] = useState(false);
- // const userId = cookies.userCookie?.id;
- // const [collections, setCollections] = useState([]);
-
+ const twentyFourHourChange = stats.twentyFourHourAverage;
+ console.log('STATS:', stats);
+ function roundToNearestTenth(num) {
+ return Math.round(num * 10) / 10;
+ }
+ console.log('TWENTY FOUR HOUR CHANGE:', twentyFourHourChange);
+ // const handleSelect = useCallback(
+ // (selectedId) => {
+ // const selected = allCollections.find(
+ // (collection) => collection._id === selectedId
+ // );
+ // if (!selected) {
+ // console.error('Collection not found with ID:', selectedId);
+ // // Handle the error accordingly, maybe set an error state here
+ // return;
+ // }
+ // setSelectedCollection(selected);
+ // onSave(selected);
+ // },
+ // [allCollections, onSave, setSelectedCollection]
+ // );
const handleSelect = useCallback(
(selectedId) => {
const selected = allCollections.find(
@@ -77,13 +111,30 @@ const SelectCollectionList = ({
);
if (!selected) {
console.error('Collection not found with ID:', selectedId);
- // Handle the error accordingly, maybe set an error state here
return;
}
setSelectedCollection(selected);
onSave(selected);
+
+ // Find the index of the selected collection
+ const selectedIndex = allCollections.findIndex(
+ (collection) => collection._id === selectedId
+ );
+
+ if (selectedIndex > 0) {
+ // Create a new array with the selected collection moved to the 0 index
+ const reorderedCollections = [
+ selected,
+ ...allCollections.slice(0, selectedIndex),
+ ...allCollections.slice(selectedIndex + 1),
+ ];
+
+ // Update the state with the reordered collections
+ // You need to implement a method in your context to handle this update
+ setAllCollections(reorderedCollections);
+ }
},
- [allCollections, onSave, setSelectedCollection]
+ [allCollections, onSave, setSelectedCollection, setAllCollections]
);
const handleOpenDialog = useCallback(
@@ -122,21 +173,36 @@ const SelectCollectionList = ({
Value:
{/* Replace with actual value */}
- ${collection?.currentValue}
+
+ ${roundToNearestTenth(collection?.totalPrice)}
+
Performance:
- {/* Replace with actual data */}
- {collection?.performance} %
+
+ {twentyFourHourChange?.percentageChange > 0 ? (
+
+ ) : (
+
+ )}
+ {twentyFourHourChange?.percentageChange}%
+
Cards:
{/* Replace with actual count */}
- {collection?.numberOfCards}
+ {collection?.totalQuantity}
diff --git a/src/components/headings/footer/Footer.js b/src/components/headings/footer/Footer.js
index 812d5cd..5de1bc3 100644
--- a/src/components/headings/footer/Footer.js
+++ b/src/components/headings/footer/Footer.js
@@ -1,54 +1,54 @@
-import React from 'react';
-import styled from 'styled-components';
-
-const FooterWrapper = styled.footer`
- background-color: #2c3e50;
- color: #ecf0f1;
- padding: 1.5rem;
- bottom: 0;
- margin-top: 100%;
- text-align: center;
- width: 100%;
- height: 5rem;
- box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1);
- z-index: 1000;
-
- @media (min-width: 768px) {
- padding: 2rem;
- text-align: left;
- }
-`;
-
-const FooterText = styled.p`
- margin: 0; /* Remove default margin */
- font-size: 0.9em;
-
- /* Hover effects */
- &:hover {
- color: #f39c12; /* Change color on hover */
- transition: color 0.3s ease; /* Smooth transition */
- }
-`;
-
-const FooterLink = styled.a`
- color: #ecf0f1;
- text-decoration: none;
-
- &:hover {
- color: #f39c12;
- transition: color 0.3s ease;
- }
-`;
-
-const Footer = () => {
- return (
-
-
- © {new Date().getFullYear()} Reed Vogt | Designed with ❤️ by
- ReedVogt.com
-
-
- );
-};
-
-export default Footer;
+// import React from 'react';
+// import styled from 'styled-components';
+
+// const FooterWrapper = styled.footer`
+// background-color: #2c3e50;
+// color: #ecf0f1;
+// padding: 1.5rem;
+// bottom: 0;
+// margin-top: 100%;
+// text-align: center;
+// width: 100%;
+// height: 5rem;
+// box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1);
+// z-index: 1000;
+
+// @media (min-width: 768px) {
+// padding: 2rem;
+// text-align: left;
+// }
+// `;
+
+// const FooterText = styled.p`
+// margin: 0; /* Remove default margin */
+// font-size: 0.9em;
+
+// /* Hover effects */
+// &:hover {
+// color: #f39c12; /* Change color on hover */
+// transition: color 0.3s ease; /* Smooth transition */
+// }
+// `;
+
+// const FooterLink = styled.a`
+// color: #ecf0f1;
+// text-decoration: none;
+
+// &:hover {
+// color: #f39c12;
+// transition: color 0.3s ease;
+// }
+// `;
+
+// const Footer = () => {
+// return (
+//
+//
+// © {new Date().getFullYear()} Reed Vogt | Designed with ❤️ by
+// ReedVogt.com
+//
+//
+// );
+// };
+
+// export default Footer;
diff --git a/src/components/modals/cardModal/GenericCardModal.jsx b/src/components/modals/cardModal/GenericCardModal.jsx
index 4161d78..2ccb977 100644
--- a/src/components/modals/cardModal/GenericCardModal.jsx
+++ b/src/components/modals/cardModal/GenericCardModal.jsx
@@ -61,24 +61,22 @@ const GenericCardModal = ({ open, card, context }) => {
{card?.name}
- {requiresDoubleButtons && (
- <>
-
-
- >
- )}
+ <>
+
+
+ >
{
+ const { detailsModalShow, closeDetailsModal, detailsModalData } =
+ useContext(ProjectContext);
+ const { allIcons } = useResumeContext();
+
+ const tech = detailsModalData?.technologies?.map((iconDetail, i) => {
+ // Get the actual React component from our mapping using the class field
+ const IconComponent = allIcons[iconDetail.class];
+
+ return (
+
+ {IconComponent && }
+
+ {iconDetail.name}
+
+
+ );
+ });
+
+ return (
+
+
+
+
+
+
+ {detailsModalData?.startDate}
+
+ {detailsModalData?.title}
+
+
+
+
+ {detailsModalData?.url && (
+
+
+
+ View Live
+
+
+ )}
+ {detailsModalData?.readmeurl && (
+
+
+
+ View on GitHub
+
+
+ )}
+
+
+
+
+
+ {detailsModalData?.description}
+
+
+ {detailsModalData?.images?.map((imgSrc, idx) => (
+
+ ))}
+
+
+
+ Technologies Used:
+
+ {tech}
+
+
+
+
+ );
+};
+
+export default ProjectDetailsModal;
diff --git a/src/components/other/InputComponents/CollectionStatisticsSelector.jsx b/src/components/other/InputComponents/CollectionStatisticsSelector.jsx
index c55a545..3ff9a81 100644
--- a/src/components/other/InputComponents/CollectionStatisticsSelector.jsx
+++ b/src/components/other/InputComponents/CollectionStatisticsSelector.jsx
@@ -10,120 +10,87 @@ import {
} from '@mui/material';
import { getFilteredData2 } from '../../reusable/chartUtils';
import { useCollectionStore } from '../../../context/CollectionContext/CollectionContext';
+import { useStatisticsStore } from '../../../context/StatisticsContext/StatisticsContext';
+import StatCard from '../dataDisplay/StatCard';
-function calculatePriceChanges(data) {
- const sortedData = data.sort((a, b) => new Date(a.x) - new Date(b.x));
- const latestDataPoint = sortedData[sortedData.length - 1];
- const latestTime = new Date(latestDataPoint.x).getTime();
- const twentyFourHoursAgo = latestTime - 24 * 60 * 60 * 1000;
+// const CollectionStatisticsSelector = ({ data, timeRange, stats }) => {
+// const [selectedStat, setSelectedStat] = useState('');
+// // const stats = useMemo(
+// // () => calculateStatistics(data, timeRange), // Recalculate statistics based on timeRange
+// // [data, timeRange]
+// // );
+// // const stats = useMemo(() => {
+// // return calculateStatistics(data, timeRange);
+// // }, [data, timeRange]);
+// // const stats = useMemo(
+// // () => calculateStatistics(data, timeRange),
+// // [data, timeRange]
+// // );
+// const handleChange = (event) => setSelectedStat(event.target.value);
- // Find the data point closest to 24 hours before the latest data point
- let closestIndex = -1;
- let closestTimeDifference = Number.MAX_SAFE_INTEGER;
+// const StatCard = ({ title, value }) => (
+//
+//
+//
+// {title}
+//
+//
+// {value}
+//
+//
+//
+// );
- for (let i = 0; i < sortedData.length - 1; i++) {
- const time = new Date(sortedData[i].x).getTime();
- const timeDifference = Math.abs(time - twentyFourHoursAgo);
+// return (
+//
+//
+//
+// Select Statistic
+//
+// High Point
+// Low Point
+// 24 Hour Average
+// Average
+// Volume
+// Volatility
+//
- if (timeDifference < closestTimeDifference) {
- closestTimeDifference = timeDifference;
- closestIndex = i;
- }
- }
+//
+// {selectedStat && (
+//
+//
+//
+// )}
+//
+//
+// );
+// };
- if (closestIndex !== -1) {
- const pastPrice = sortedData[closestIndex].y;
- // console.log('pastPrice', pastPrice);
- const priceChange = latestDataPoint.y - pastPrice;
- console.log('priceChange', priceChange);
- const percentageChange = ((priceChange / pastPrice) * 100).toFixed(2);
- // console.log('percentageChange', percentageChange);
+// export default CollectionStatisticsSelector;
- return [
- {
- startDate: sortedData[closestIndex].x,
- lowPoint: pastPrice.toFixed(2),
- highPoint: latestDataPoint?.y?.toFixed(2),
- endDate: latestDataPoint?.x,
- priceChange: priceChange.toFixed(2),
- percentageChange: `${percentageChange}%`,
- priceIncreased: priceChange > 0,
- },
- ];
- }
-
- return [];
-}
-
-export const calculateStatistics = (data, timeRange) => {
- if (!data || data.length === 0) return {};
- const filteredData = data?.data?.filter(
- (item) => new Date(item?.x).getTime() >= Date.now() - timeRange
- );
- if (filteredData.length === 0) return {};
- let highPoint = 0;
- let lowPoint = 0;
- let sum = 0;
- let averageData = 0;
- let average = 0;
- let volume = 0;
- let mean = 0;
- let squaredDiffs = 0;
- let volatility = 0;
- // const filteredData2 = getFilteredData2(data, timeRange);
- // console.log('filteredData2', filteredData2);
- // console.log('filteredData', filteredData);
- for (const data of filteredData) {
- highPoint = Math.max(...filteredData.map((item) => item.y));
- lowPoint = Math.min(...filteredData.map((item) => item.y));
- sum = filteredData.reduce((acc, curr) => acc + curr.y, 0);
- averageData = calculatePriceChanges(filteredData);
- average = sum / filteredData.length || 0;
- volume = filteredData.length;
- mean = sum / volume;
- squaredDiffs = filteredData.map((item) => {
- const diff = item.y - mean;
- return diff * diff;
- });
- volatility = Math.sqrt(squaredDiffs.reduce((a, b) => a + b, 0) / volume);
- }
-
- return {
- highPoint: highPoint.toFixed(2),
- lowPoint: lowPoint.toFixed(2),
- twentyFourHourAverage: {
- startDate: averageData[0]?.startDate,
- endDate: averageData[0]?.endDate,
- lowPoint: averageData[0]?.lowPoint,
- highPoint: averageData[0]?.highPoint,
- priceChange: averageData[0]?.priceChange,
- percentageChange: averageData[0]?.percentageChange,
- priceIncreased: averageData[0]?.priceIncreased,
- },
- average: average?.toFixed(2),
- volume,
- volatility: volatility?.toFixed(2),
- };
-};
-
-const CollectionStatisticsSelector = ({ data, timeRange, stats }) => {
+const CollectionStatisticsSelector = () => {
const [selectedStat, setSelectedStat] = useState('');
+ const { stats } = useStatisticsStore();
const handleChange = (event) => setSelectedStat(event.target.value);
- const StatCard = ({ title, value }) => (
-
-
-
- {title}
-
-
- {value}
-
-
-
- );
-
return (
{
alignItems: 'center',
gap: 2,
width: '100%',
- // padding: 2,
}}
>
{
Average
Volume
Volatility
+ {/* Other MenuItems */}
{selectedStat && (
diff --git a/src/components/other/InputComponents/CustomSelector.js b/src/components/other/InputComponents/CustomSelector.js
index 2724fa2..1e1e692 100644
--- a/src/components/other/InputComponents/CustomSelector.js
+++ b/src/components/other/InputComponents/CustomSelector.js
@@ -3,11 +3,6 @@ import { Grid, FormControl, InputLabel, Select, MenuItem } from '@mui/material';
import { useMode } from '../../../context/hooks/colormode';
const CustomSelector = ({ label, name, value, handleChange, values }) => {
- // const handleChange = (event) => {
- // setValue(
- // event.target.value.toLowerCase() === 'unset' ? '' : event.target.value
- // );
- // };
const defaultValue = value || 'Unset';
if (!values) {
diff --git a/src/components/other/InputComponents/UpdateStatusBox2.jsx b/src/components/other/InputComponents/UpdateStatusBox2.jsx
index 53d7a35..709ec49 100644
--- a/src/components/other/InputComponents/UpdateStatusBox2.jsx
+++ b/src/components/other/InputComponents/UpdateStatusBox2.jsx
@@ -93,17 +93,6 @@ const UpdateStatusBox2 = ({ socket }) => {
}
};
- // const sendUpdateRequest = () => {
- // if (socket) {
- // socket.emit('STATUS_UPDATE_REQUEST', {
- // message: 'Requesting status update...',
- // data: listOfMonitoredCards,
- // });
- // }
- // };
-
- // Styling for dark theme
-
return (
diff --git a/src/components/other/dataDisplay/CartSummary.js b/src/components/other/dataDisplay/CartSummary.js
index 3a9ac05..f7ff1d4 100644
--- a/src/components/other/dataDisplay/CartSummary.js
+++ b/src/components/other/dataDisplay/CartSummary.js
@@ -1,9 +1,9 @@
import React from 'react';
import { Box, Typography } from '@mui/material';
-const CartSummary = ({ quantity, getTotalCost }) => {
+const CartSummary = ({ quantity, totalCost }) => {
console.log('CARTSUMMARY QUANTITY:', quantity);
- console.log('CARTSUMMARY GETTOTALCOST:', getTotalCost);
+ console.log('CARTSUMMARY GETTOTALCOST:', totalCost);
return (
@@ -12,7 +12,7 @@ const CartSummary = ({ quantity, getTotalCost }) => {
Grand Total:
- ${getTotalCost}
+ ${totalCost}
);
diff --git a/src/components/other/dataDisplay/ProgressCircle.jsx b/src/components/other/dataDisplay/ProgressCircle.jsx
index 50638ed..8652369 100644
--- a/src/components/other/dataDisplay/ProgressCircle.jsx
+++ b/src/components/other/dataDisplay/ProgressCircle.jsx
@@ -1,5 +1,5 @@
import { Box, useTheme } from '@mui/material';
-import { tokens } from '../styles/theme';
+import { tokens } from '../../../assets/tokens';
const ProgressCircle = ({ progress = '0.75', size = '40' }) => {
const theme = useTheme();
diff --git a/src/components/other/dataDisplay/StatBox.jsx b/src/components/other/dataDisplay/StatBox.jsx
index 2aa5798..1a10c72 100644
--- a/src/components/other/dataDisplay/StatBox.jsx
+++ b/src/components/other/dataDisplay/StatBox.jsx
@@ -1,6 +1,6 @@
import { Box, Typography, useTheme } from '@mui/material';
-import { tokens } from '../styles/theme';
import ProgressCircle from './ProgressCircle';
+import { tokens } from '../../../assets/tokens';
const StatBox = ({ title, subtitle, icon, progress, increase }) => {
const theme = useTheme();
diff --git a/src/components/other/dataDisplay/StatCard.jsx b/src/components/other/dataDisplay/StatCard.jsx
new file mode 100644
index 0000000..8e13c1e
--- /dev/null
+++ b/src/components/other/dataDisplay/StatCard.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Card, CardContent, Typography } from '@mui/material';
+
+const StatCard = ({ title, value }) => (
+
+
+
+ {title}
+
+
+ {value}
+
+
+
+);
+
+export default StatCard;
diff --git a/src/components/other/dataDisplay/TopCardsDisplay.jsx b/src/components/other/dataDisplay/TopCardsDisplay.jsx
index be8a8da..e0aa429 100644
--- a/src/components/other/dataDisplay/TopCardsDisplay.jsx
+++ b/src/components/other/dataDisplay/TopCardsDisplay.jsx
@@ -19,6 +19,8 @@ import { makeStyles } from '@mui/styles';
import { ModalContext } from '../../../context/ModalContext/ModalContext';
import GenericCard from '../../cards/GenericCard';
import {
+ MainContainer2b,
+ MainContainerb,
MainContainer2,
MainContainer,
} from '../../../pages/pageStyles/StyledComponents';
@@ -56,10 +58,10 @@ const CarouselCard = ({ card }) => {
- {card.name}
+ {card?.name}
- {card.description}
+ {card?.description}
Price: ${card?.latestPrice?.num ?? 'N/A'}
diff --git a/src/components/reusable/HeaderTitle.jsx b/src/components/reusable/HeaderTitle.jsx
index b70c0da..f08ca3c 100644
--- a/src/components/reusable/HeaderTitle.jsx
+++ b/src/components/reusable/HeaderTitle.jsx
@@ -1,8 +1,10 @@
// components/reusable/HeaderTitle.jsx
import { Typography, Container } from '@mui/material';
import React from 'react';
+import { useMode } from '../../context/hooks/colormode';
const HeaderTitle = ({ title, size = 'extraSmall', location = 'left' }) => {
+ const { theme } = useMode();
const sizes = {
huge: { fontSize: '2.5rem', lineHeight: '3rem' },
large: { fontSize: '1.75rem', lineHeight: '2.25rem' },
@@ -19,11 +21,14 @@ const HeaderTitle = ({ title, size = 'extraSmall', location = 'left' }) => {
};
const containerStyles = {
- backgroundColor: (theme) => theme.palette.background.default,
+ backgroundColor: theme.palette.background.quaternary,
+ width: '50%',
+ border: `1px solid ${theme.palette.text.primary}`,
+ borderRadius: theme.shape.borderRadius,
padding: 2,
transition: 'background-color 0.3s ease',
'&:hover': {
- backgroundColor: (theme) => theme.palette.background.paper,
+ backgroundColor: theme.palette.text.main,
},
};
@@ -34,11 +39,11 @@ const HeaderTitle = ({ title, size = 'extraSmall', location = 'left' }) => {
fontWeight: 700,
letterSpacing: '0.05em',
margin: '0 auto',
- color: (theme) => theme.palette.text.primary,
+ color: 'white',
textShadow: '1px 1px 2px rgba(0, 0, 0, 0.2)',
transition: 'color 0.3s ease',
'&:hover': {
- color: (theme) => theme.palette.secondary.main,
+ color: (theme) => theme.palette.text.main,
},
};
diff --git a/src/components/reusable/icons/ChartsIcon.jsx b/src/components/reusable/icons/ChartsIcon.jsx
new file mode 100644
index 0000000..eb3ff70
--- /dev/null
+++ b/src/components/reusable/icons/ChartsIcon.jsx
@@ -0,0 +1,27 @@
+import StackedLineChartIcon from '@mui/icons-material/StackedLineChart';
+import { IconButton } from '@mui/material';
+
+const ChartsIcon = () => {
+ return (
+
+
+
+ );
+};
+
+export default ChartsIcon;
diff --git a/src/components/reusable/icons/MoneyIcon.jsx b/src/components/reusable/icons/MoneyIcon.jsx
new file mode 100644
index 0000000..f7e37c7
--- /dev/null
+++ b/src/components/reusable/icons/MoneyIcon.jsx
@@ -0,0 +1,38 @@
+import AttachMoneyIcon from '@mui/icons-material/AttachMoney';
+import { IconButton } from '@mui/material';
+
+const MoneyIcon = () => {
+ return (
+
+
+
+ );
+};
+
+export default MoneyIcon;
diff --git a/src/containers/collectionPageContainers/CollectionContainer.jsx b/src/containers/collectionPageContainers/CollectionContainer.jsx
deleted file mode 100644
index 81b1841..0000000
--- a/src/containers/collectionPageContainers/CollectionContainer.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import { makeStyles } from '@mui/styles';
-
-const useStyles = makeStyles((theme) => ({
- container: {
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'center',
- minHeight: '100vh',
- backgroundColor: '#f1f1f1',
- padding: theme.spacing(2),
- width: '100%',
- },
-}));
-
-const CollectionContainer = ({ children }) => {
- const classes = useStyles();
-
- return {children}
;
-};
-
-export default CollectionContainer;
diff --git a/src/containers/collectionPageContainers/PortfolioChartContainer.jsx b/src/containers/collectionPageContainers/CollectionPortfolioChartContainer.jsx
similarity index 73%
rename from src/containers/collectionPageContainers/PortfolioChartContainer.jsx
rename to src/containers/collectionPageContainers/CollectionPortfolioChartContainer.jsx
index f3cf490..c5352d2 100644
--- a/src/containers/collectionPageContainers/PortfolioChartContainer.jsx
+++ b/src/containers/collectionPageContainers/CollectionPortfolioChartContainer.jsx
@@ -2,29 +2,21 @@ import React, { useMemo } from 'react';
import { Box, Grid, Paper, Container, useTheme } from '@mui/material';
import PortfolioChart from '../../components/chart/PortfolioChart';
import TimeRangeSelector from '../../components/other/InputComponents/TimeRangeSelector';
-import CollectionStatisticsSelector, {
- calculateStatistics,
-} from '../../components/other/InputComponents/CollectionStatisticsSelector';
import UpdateStatusBox2 from '../../components/other/InputComponents/UpdateStatusBox2';
import TopCardsDisplay from '../../components/other/dataDisplay/TopCardsDisplay';
import { useChartContext } from '../../context/ChartContext/ChartContext';
import { useCollectionStore } from '../../context/CollectionContext/CollectionContext';
import { useCombinedContext } from '../../context/CombinedProvider';
+import { calculateStatistics } from '../../context/StatisticsContext/helpers';
+import CollectionStatisticsSelector from '../../components/other/InputComponents/CollectionStatisticsSelector';
+import { useStatisticsStore } from '../../context/StatisticsContext/StatisticsContext';
-const PortfolioChartContainer = ({ selectedCards, removeCard }) => {
+const CollectionPortfolioChartContainer = ({ selectedCards, removeCard }) => {
const theme = useTheme();
const { timeRange } = useChartContext();
const { allCollections } = useCollectionStore();
const { socket } = useCombinedContext();
-
- const data = allCollections.map((collection) => ({
- data: collection?.currentChartDataSets2,
- }));
- const dataForStats = data[0];
- const stats = useMemo(
- () => calculateStatistics(dataForStats, timeRange),
- [dataForStats, timeRange]
- );
+ const { stats } = useStatisticsStore();
return (
{
}}
>
{/* Updaters Row */}
-
+
-
+
@@ -56,7 +48,7 @@ const PortfolioChartContainer = ({ selectedCards, removeCard }) => {
{/* Main Grid Container */}
-
+
{/* Portfolio Chart Row */}
{
);
};
-export default PortfolioChartContainer;
+export default CollectionPortfolioChartContainer;
diff --git a/src/containers/collectionPageContainers/PortfolioListContainer.jsx b/src/containers/collectionPageContainers/CollectionPortfolioListContainer.jsx
similarity index 88%
rename from src/containers/collectionPageContainers/PortfolioListContainer.jsx
rename to src/containers/collectionPageContainers/CollectionPortfolioListContainer.jsx
index 579f87b..9be8bec 100644
--- a/src/containers/collectionPageContainers/PortfolioListContainer.jsx
+++ b/src/containers/collectionPageContainers/CollectionPortfolioListContainer.jsx
@@ -4,7 +4,7 @@ import CardList from '../../components/grids/collectionGrids/CardList';
import { useTheme } from '@mui/material/styles';
import { useMode } from '../../context/hooks/colormode';
-const PortfolioListContainer = ({ selectedCards, removeCard }) => {
+const CollectionPortfolioListContainer = ({ selectedCards, removeCard }) => {
const { theme } = useMode();
return (
@@ -30,4 +30,4 @@ const PortfolioListContainer = ({ selectedCards, removeCard }) => {
);
};
-export default PortfolioListContainer;
+export default CollectionPortfolioListContainer;
diff --git a/src/context/Auth/authContext.js b/src/context/Auth/authContext.js
index f130a86..5a7381d 100644
--- a/src/context/Auth/authContext.js
+++ b/src/context/Auth/authContext.js
@@ -50,11 +50,9 @@ export default function AuthProvider({ children, serverUrl }) {
const [user, setUser] = useState({});
const [error, setError] = useState(null);
const [token, setToken] = useState(null);
- // const isMounted = useRef(true);
const REACT_APP_SERVER = serverUrl || process.env.REACT_APP_SERVER;
- // Execute authentication actions like login, signup
const executeAuthAction = async (actionType, url, requestData) => {
setIsLoading(true);
try {
@@ -113,15 +111,13 @@ export default function AuthProvider({ children, serverUrl }) {
setUser({});
};
- // Validate token
- const validateToken = useCallback(async () => {
- // Validation logic here
- }, []);
+ // // Validate token
+ // const validateToken = useCallback(async () => {
+ // // Validation logic here
+ // }, []);
// Initialization logic to set user and token from cookies
useEffect(() => {
- // if (!isMounted.current) return;
-
const storedToken = cookies[AUTH_COOKIE];
const storedUser = cookies[USER_COOKIE];
@@ -150,586 +146,3 @@ export default function AuthProvider({ children, serverUrl }) {
);
}
-
-// import React, { useState, useEffect, useCallback, useRef } from 'react';
-// import jwt_decode from 'jwt-decode';
-// import axios from 'axios';
-// import { useCookies } from 'react-cookie';
-// import { useUtilityContext } from '../UtilityContext/UtilityContext';
-// // Initialize constants
-// const ONE_MINUTE = 60000;
-// const AUTH_COOKIE = 'auth';
-// const USER_COOKIE = 'userCookie';
-
-// export const AuthContext = React.createContext();
-
-// export default function AuthProvider({ children, serverUrl }) {
-// // State and Context Setup
-// const { directedResponses, fetchDirectedResponses } = useUtilityContext();
-// const [cookies, setCookie, removeCookie] = useCookies(['auth', 'userCookie']);
-// const [isLoading, setIsLoading] = useState(false);
-// const [isLoggedIn, setisLoggedIn] = useState(false);
-// const [user, setUser] = useState({});
-// const [users, setUsers] = useState([]);
-// const [error, setError] = useState(null);
-// const [token, setToken] = useState(undefined);
-// const [loginAttempts, setLoginAttempts] = useState(0);
-// const [lastAttemptTime, setLastAttemptTime] = useState(null);
-
-// const REACT_APP_SERVER = serverUrl || process.env.REACT_APP_SERVER;
-// const isMounted = useRef(true);
-
-// // Cleanup
-// useEffect(() => {
-// return () => {
-// isMounted.current = false;
-// };
-// }, []);
-// // Handle Login Attempts
-// useEffect(() => {
-// if (loginAttempts >= 2) {
-// const timerId = setTimeout(() => {
-// setLoginAttempts(0);
-// }, 60000); // Reset after 1 minute
-// return () => clearTimeout(timerId);
-// }
-// }, [loginAttempts]);
-// // Initialize and Validate Token
-// useEffect(() => {
-// if (isMounted.current) {
-// const queryToken = new URLSearchParams(window.location.search).get(
-// 'token'
-// );
-// const cookieToken = cookies.auth;
-// const activeToken = queryToken || cookieToken;
-// if (activeToken && activeToken !== token) {
-// validateToken(activeToken);
-// }
-// }
-// }, [validateToken, cookies.auth]);
-// // Utility Function to Set Login State
-// const setLoginState = useCallback(
-// (loggedIn, token, user, error = null) => {
-// setCookie('auth', token, { secure: true, sameSite: 'strict' });
-// setCookie('isLoggedIn', String(loggedIn), {
-// secure: true,
-// sameSite: 'strict',
-// });
-// setCookie(AUTH_COOKIE, token, { secure: true, sameSite: 'strict' });
-
-// if (user) {
-// setCookie('userCookie', JSON.stringify(user), {
-// secure: true,
-// sameSite: 'strict',
-// });
-// }
-// setisLoggedIn(loggedIn);
-// setToken(token);
-// setUser(user);
-// setError(error);
-// },
-// [setCookie]
-// );
-
-// const onLogin = async (username, password) => {
-// const currentTime = new Date().getTime();
-// const oneMinute = 60000; // 60 seconds * 1000 milliseconds
-
-// if (
-// loginAttempts < 2 ||
-// (lastAttemptTime && currentTime - lastAttemptTime > oneMinute)
-// ) {
-// // If under limit or last attempt was more than a minute ago, proceed
-// setLoginAttempts(loginAttempts + 1);
-// setLastAttemptTime(currentTime);
-
-// try {
-// const loginResult = await login(username, password);
-// if (loginResult?.loggedIn) {
-// if (onLogin) {
-// onLogin(); // Call the passed down function when login is successful
-// }
-// }
-// setisLoggedIn(loginResult?.loggedIn);
-// return loginResult;
-// } catch (error) {
-// console.error('Login failed:', error);
-// }
-// } else {
-// // If over the limit
-// setError('Too many login attempts. Please wait for 1 minute.');
-// }
-// };
-
-// // Reset the login attempts and time after a minute
-// useEffect(() => {
-// if (loginAttempts >= 2) {
-// const timerId = setTimeout(() => {
-// setLoginAttempts(0);
-// }, 60000); // 1 minute = 60000 milliseconds
-
-// return () => clearTimeout(timerId);
-// }
-// }, [loginAttempts]);
-
-// // In AuthProvider
-// const login = async (username, password) => {
-// console.log('Login method invoked');
-// setIsLoading(true);
-
-// try {
-// const signInResponse = await axios.post(
-// `${REACT_APP_SERVER}/api/users/signin`,
-// { username, password },
-// {
-// headers: {
-// 'Content-Type': 'application/json',
-// Authorization: `Bearer ${token}`,
-// },
-// }
-// );
-
-// console.log('Fetching directed responses...');
-// await fetchDirectedResponses();
-
-// // Do not call validateToken here.
-// return { loggedIn: isLoggedIn, token };
-// } catch (error) {
-// console.error(`Error during login: ${error}`);
-// setError('Login failed');
-// setLoginState(false, null, {}, 'Login failed');
-// } finally {
-// setIsLoading(false);
-// }
-// };
-
-// const validateToken = useCallback(async () => {
-// if (!isMounted.current) return;
-
-// setIsLoading(true);
-// try {
-// const latestSignInResponse = directedResponses.find(
-// (res) => res.eventType === 'SIGNIN'
-// );
-
-// if (
-// latestSignInResponse &&
-// latestSignInResponse.response.data.token !== token
-// ) {
-// const newToken = latestSignInResponse.response.data.token;
-// const decodedUser = jwt_decode(newToken);
-// setLoginState(true, newToken, decodedUser);
-// } else {
-// throw new Error('Token validation failed');
-// }
-// } catch (error) {
-// console.error(`Error during validateToken: ${error}`);
-
-// setError('Token validation failed');
-// setLoginState(false, null, {}, 'Token validation failed');
-// } finally {
-// setIsLoading(false);
-// }
-// }, [directedResponses, setLoginState, token]);
-
-// const signup = async (username, password, email, basic_info, role_data) => {
-// setIsLoading(true);
-// try {
-// const response = await axios.post(
-// `${REACT_APP_SERVER}/api/users/signup`,
-// {
-// login_data: { username, password, email, role_data },
-// basic_info,
-// }
-// );
-// await validateToken(response.data.token);
-// return response.data.token;
-// } catch (err) {
-// setError('Signup failed');
-// setLoginState(false, null, {}, 'Signup failed');
-// } finally {
-// setIsLoading(false);
-// }
-// };
-
-// const logout = () => {
-// removeCookie('auth');
-// removeCookie(AUTH_COOKIE);
-// setLoginState(false, null, {});
-// console.log('Logout method invoked');
-// };
-
-// // In AuthProvider
-// useEffect(() => {
-// if (isMounted.current) {
-// const queryToken = new URLSearchParams(window.location.search).get(
-// 'token'
-// );
-// const cookieToken = cookies[AUTH_COOKIE];
-// const activeToken = queryToken || cookieToken;
-
-// if (activeToken && activeToken !== token) {
-// validateToken(activeToken);
-// }
-// }
-// }, [validateToken, cookies[AUTH_COOKIE]]);
-
-// const contextValue = {
-// isLoading: isLoading,
-// isLoggedIn: isLoggedIn,
-// user: users.find((u) => u.id === user.id) || user,
-// users,
-// error,
-// login,
-// onLogin, // Add this line to pass it down
-// logout,
-// signup,
-// setUser,
-// setLoginState,
-// validateToken,
-// // updateUser,
-// };
-
-// return (
-// {children}
-// );
-// }
-
-// /**
-// * Handler function for processing login data.
-// *
-// * @param {Object} data - The data received from login API.
-// */
-// function processLoginData(data) {
-// // Validate the data before processing
-// if (!validateData(data, 'Login Response', 'processLoginData')) {
-// console.warn('Invalid login data. Aborting processLoginData.');
-// return;
-// }
-
-// // Extract relevant fields from the received data
-// const { token, user } = data;
-
-// if (token && user) {
-// // Save token and user information to state or local storage
-// localStorage.setItem('authToken', token);
-// // Perform other login success logic here
-// } else {
-// console.error('Missing essential fields in login data.');
-// }
-// }
-
-// /**
-// * Handler function for processing signup data.
-// *
-// * @param {Object} data - The data received from signup API.
-// */
-// function processSignupData(data) {
-// // Validate the data before processing
-// if (!validateData(data, 'Signup Response', 'processSignupData')) {
-// console.warn('Invalid signup data. Aborting processSignupData.');
-// return;
-// }
-
-// // Extract relevant fields from the received data
-// const { success, newUser } = data;
-
-// if (success && newUser) {
-// // Assume `newUser` contains essential user info
-// const { id, username } = newUser;
-
-// // Save the new user ID or perform other signup success logic here
-// // For example, redirect to login or a welcome page
-// } else {
-// console.error('Missing essential fields in signup data.');
-// }
-// }
-
-// import React, { useState, useEffect, useCallback, useRef } from 'react';
-// import jwt_decode from 'jwt-decode';
-// import axios from 'axios';
-// import { useCookies } from 'react-cookie';
-// import { useUtilityContext } from '../UtilityContext/UtilityContext';
-
-// const LOGGED_IN_COOKIE = 'loggedIn';
-// const AUTH_COOKIE = 'authToken';
-// const USER_COOKIE = 'user';
-
-// const processResponseData = (data, type) => {
-// if (!validateData(data, `${type} Response`, `process${type}Data`)) {
-// console.warn(
-// `Invalid ${type.toLowerCase()} data. Aborting process${type}Data.`
-// );
-// return;
-// }
-
-// if (type === 'Login') {
-// const token = data?.data?.token;
-// if (token) {
-// localStorage.setItem('authToken', token);
-// const decodedUser = jwt_decode(token);
-// return { token, user: decodedUser };
-// }
-// } else if (type === 'Signup') {
-// const { success, newUser } = data;
-// if (success && newUser) {
-// return { success, newUser };
-// }
-// }
-
-// console.error(`Missing essential fields in ${type.toLowerCase()} data.`);
-// return null;
-// };
-// const isEmpty = (obj) => {
-// return (
-// [Object, Array].includes((obj || {}).constructor) &&
-// !Object.entries(obj || {}).length
-// );
-// };
-// // Validator function
-// const validateData = (data, eventName, functionName) => {
-// const dataType = typeof data;
-// console.log(
-// `[Info] Received data of type: ${dataType} in ${functionName} triggered by event: ${eventName}`
-// );
-
-// if (data === null || data === undefined) {
-// console.warn(
-// `[Warning] Received null or undefined data in ${functionName} triggered by event: ${eventName}`
-// );
-// return false;
-// }
-
-// if (isEmpty(data)) {
-// console.error(
-// `[Error] Received empty data object or array in ${functionName} triggered by event: ${eventName}`
-// );
-// return false;
-// }
-
-// return true;
-// };
-
-// export const AuthContext = React.createContext();
-
-// const setCookies = (
-// setCookieFunc,
-// authCookie,
-// userCookie,
-// loggedInCookie,
-// loggedIn,
-// token,
-// user
-// ) => {
-// setCookieFunc(authCookie, token);
-// setCookieFunc(userCookie, JSON.stringify(user));
-// setCookieFunc(loggedInCookie, String(loggedIn));
-// };
-// export default function AuthProvider({ children, serverUrl }) {
-// const { directedResponses, fetchDirectedResponses } = useUtilityContext();
-// const [cookies, setCookie, removeCookie] = useCookies([
-// LOGGED_IN_COOKIE,
-// AUTH_COOKIE,
-// USER_COOKIE,
-// ]);
-// const [isLoading, setIsLoading] = useState(false);
-// const [isLoggedIn, setisLoggedIn] = useState(false);
-// const [user, setUser] = useState({});
-// const [error, setError] = useState(null);
-// const [token, setToken] = useState(undefined);
-// const isMounted = useRef(true);
-// const [loginAttempts, setLoginAttempts] = useState(0);
-
-// const REACT_APP_SERVER = serverUrl || process.env.REACT_APP_SERVER;
-
-// useEffect(
-// () => () => {
-// isMounted.current = false;
-// },
-// []
-// );
-
-// const setLoginState = useCallback(
-// (loggedIn, token, user, error = null) => {
-// setCookie(AUTH_COOKIE, token);
-// setCookie(USER_COOKIE, JSON.stringify(user));
-// setCookie(LOGGED_IN_COOKIE, String(loggedIn));
-// setisLoggedIn(loggedIn);
-// setToken(token);
-// setUser(user);
-// setError(error);
-// },
-// [setCookie]
-// );
-
-// const resetLoginAttempts = () =>
-// loginAttempts >= 2 && setTimeout(() => setLoginAttempts(0), 60000);
-// useEffect(resetLoginAttempts, [loginAttempts]);
-
-// const updateLoginState = useCallback(
-// (loggedIn, token, user, error = null) => {
-// setCookies(
-// setCookie,
-// AUTH_COOKIE,
-// USER_COOKIE,
-// LOGGED_IN_COOKIE,
-// loggedIn,
-// token,
-// user
-// );
-// setisLoggedIn(loggedIn);
-// setToken(token);
-// setUser(user);
-// setError(error);
-// },
-// [setCookie]
-// );
-
-// const validateToken = useCallback(async () => {
-// if (!isMounted.current) return;
-
-// setIsLoading(true);
-// try {
-// const latestSignInResponse = directedResponses.find(
-// (res) => res.eventType === 'SIGNIN'
-// );
-
-// if (
-// latestSignInResponse &&
-// latestSignInResponse.response.data.token !== token
-// ) {
-// const newToken = latestSignInResponse.response.data.token;
-// const decodedUser = jwt_decode(newToken);
-// setLoginState(true, newToken, decodedUser);
-// } else {
-// throw new Error('Token validation failed');
-// }
-// } catch (error) {
-// setError('Token validation failed');
-// setLoginState(false, null, {}, 'Token validation failed');
-// } finally {
-// setIsLoading(false);
-// }
-// }, [directedResponses, setLoginState, token]);
-// useEffect(() => {
-// const queryToken = new URLSearchParams(window.location.search).get('token');
-// const cookieToken = cookies[AUTH_COOKIE];
-// const activeToken = queryToken || cookieToken;
-// if (activeToken && activeToken !== token) {
-// validateToken(activeToken);
-// }
-// }, [validateToken, cookies[AUTH_COOKIE]]);
-
-// const safeRequest = useCallback(async (apiEndpoint, data, methodName) => {
-// try {
-// if (!validateData(data, apiEndpoint, methodName)) {
-// throw new Error(`Invalid data sent to API endpoint: ${apiEndpoint}`);
-// }
-// const response = await axios.post(apiEndpoint, data);
-// if (!validateData(response, apiEndpoint, methodName)) {
-// throw new Error(
-// `Invalid data received from API endpoint: ${apiEndpoint}`
-// );
-// }
-// return response.data;
-// } catch (error) {
-// console.error(`[Error] Failed to send request to: ${apiEndpoint}`, error);
-// setError({ message: error.message, source: methodName });
-// return null;
-// }
-// }, []);
-
-// const safeResponse = useCallback((data, eventName, handler) => {
-// try {
-// if (!validateData(data, eventName, handler.name)) {
-// throw new Error(`Invalid data received for event: ${eventName}`);
-// }
-// return handler(data);
-// } catch (error) {
-// console.error(`[Error] Failed to handle event: ${eventName}`, error);
-// setError({ message: error.message, source: eventName });
-// return null;
-// }
-// }, []);
-
-// const executeAuthAction = async (actionType, url, requestData) => {
-// const response = await safeRequest(
-// `${REACT_APP_SERVER}/api/users/${url}`,
-// requestData,
-// actionType.toLowerCase()
-// );
-
-// if (response) {
-// const processedData = safeResponse(
-// response,
-// actionType.toLowerCase(),
-// (data) => processResponseData(data, actionType)
-// );
-// if (processedData) {
-// setLoginState(
-// true,
-// processedData.token || null,
-// processedData.user || processedData.newUser || {}
-// );
-// }
-// }
-// };
-
-// const login = async (username, password) => {
-// const requestData = { username, password };
-// await executeAuthAction('Login', 'signin', requestData);
-// };
-
-// const signup = async (loginData, basicInfo, otherInfo) => {
-// const requestData = {
-// login_data: loginData,
-// basic_info: basicInfo,
-// ...otherInfo,
-// };
-// await executeAuthAction('Signup', 'signup', requestData);
-// };
-
-// const logout = () => {
-// removeCookie('auth');
-// removeCookie(AUTH_COOKIE);
-// setLoginState(false, null, {});
-// console.log('Logout method invoked');
-// };
-// // Add this in your Header component
-// useEffect(() => {
-// console.log('Value of isLoggedIn from context: ', isLoggedIn);
-// }, [isLoggedIn]);
-
-// useEffect(() => {
-// if (isMounted.current) {
-// const queryToken = new URLSearchParams(window.location.search).get(
-// 'token'
-// );
-// const cookieToken = cookies[AUTH_COOKIE];
-// const activeToken = queryToken || cookieToken;
-
-// if (activeToken && activeToken !== token) {
-// validateToken(activeToken);
-// }
-// }
-// }, [validateToken, cookies[AUTH_COOKIE]]);
-
-// const contextValue = {
-// isLoading,
-// isLoggedIn,
-// user,
-// // users,
-// error,
-// login,
-// // onLogin,
-// logout,
-// signup,
-// setUser,
-// setLoginState,
-// validateToken,
-// };
-
-// return (
-// {children}
-// );
-// }
diff --git a/src/context/CardContext/CardStore.js b/src/context/CardContext/CardStore.js
index 491c2fb..c818256 100644
--- a/src/context/CardContext/CardStore.js
+++ b/src/context/CardContext/CardStore.js
@@ -99,11 +99,6 @@ export const CardProvider = ({ children }) => {
initialStore,
cookies,
currentCart,
- // getCardQuantity: (cardId) => {
- // if
- // const card = cartData?.cart?.find((c) => c?.id === cardId);
- // return card?.quantity || 0;
- // },
setSearchData,
setDeckSearchData,
setSavedDeckData,
@@ -127,36 +122,3 @@ export const useCardStore = () => {
}
return context;
};
-
-// export const useCardStore = () => {
-// const context = useContext(CardContext);
-// if (!context) {
-// throw new Error('useCardStore must be used within a CardStoreProvider');
-// }
-// const {
-// cardsArray,
-// getCardData,
-// getRandomCard,
-// setCardsArray,
-// searchData,
-// setSearchData,
-// handleRequest,
-// deckSearchData,
-// setDeckSearchData,
-// savedDeckData,
-// setSavedDeckData,
-// } = context;
-// return {
-// cardsArray,
-// getCardData,
-// getRandomCard,
-// setCardsArray,
-// searchData,
-// setSearchData,
-// handleRequest,
-// deckSearchData,
-// setDeckSearchData,
-// savedDeckData,
-// setSavedDeckData,
-// };
-// };
diff --git a/src/context/CardImagesContext/CardImagesContext.jsx b/src/context/CardImagesContext/CardImagesContext.jsx
index 2f67d6f..aa1bd03 100644
--- a/src/context/CardImagesContext/CardImagesContext.jsx
+++ b/src/context/CardImagesContext/CardImagesContext.jsx
@@ -44,10 +44,8 @@ export const CardImagesProvider = ({ children }) => {
try {
const response = await fetchWrapper(BASE_API_URL + '/download', 'GET');
console.log('Response from fetchWrapper:', response);
-
// If response is already JSON
setCards(response.data); // Directly setting the response if it's already in the desired format
-
cards.forEach((card) => {
if (card.card_images && card.card_images.length > 0) {
// Adding a dummy GET parameter to bypass caching
@@ -56,10 +54,6 @@ export const CardImagesProvider = ({ children }) => {
setImages(imageUrl);
}
});
-
- // If response needs to be parsed as JSON
- // const jsonResponse = await response.json(); // Uncomment if response is in JSON format
- // setCards(jsonResponse); // Assuming jsonResponse is an array of cards
} catch (error) {
console.error('Error in downloadCardImages:', error);
setError(error.message);
diff --git a/src/context/CartContext/CartContext.js b/src/context/CartContext/CartContext.js
index 23b3748..19e5afc 100644
--- a/src/context/CartContext/CartContext.js
+++ b/src/context/CartContext/CartContext.js
@@ -10,6 +10,7 @@ import React, {
} from 'react';
import { useCookies } from 'react-cookie';
import { useCardStore } from '../CardContext/CardStore';
+import { useUserContext } from '../UserContext/UserContext';
export const CartContext = createContext({
cartData: {
@@ -28,6 +29,7 @@ export const CartContext = createContext({
});
export const CartProvider = ({ children }) => {
+ const { user } = useUserContext();
const [cartData, setCartData] = useState({
_id: '', // Cart id
cart: [], // Cart items
@@ -35,26 +37,124 @@ export const CartProvider = ({ children }) => {
totalPrice: 0, // Total price of items
});
const [cookies, setCookie] = useCookies(['user', 'cart']);
- const userId = cookies?.user?.id;
- const { getCardData } = useCardStore();
+
+ const userId = user?.id;
const isMounted = useRef(true);
+ const getCardQuantity = (cardId) => {
+ let totalItems = 0;
+ let quantityOfSameId = 0;
+ cartData.cart.forEach((item) => {
+ totalItems += item.quantity;
+ if (item.id === cardId) {
+ quantityOfSameId += item.quantity;
+ }
+ });
+ return { totalItems, quantityOfSameId };
+ };
+ // const getTotalCost = useCallback(() => {
+ // return cartData.cart.reduce(
+ // (acc, card) => acc + card.card_prices[0].tcgplayer_price * card.quantity,
+ // 0
+ // );
+ // }, [cartData.cart]);
+
+ const totalCost = useMemo(
+ () =>
+ cartData.cart.reduce(
+ (total, item) =>
+ total + item.quantity * item.card_prices[0].tcgplayer_price,
+ 0
+ ),
+ [cartData.cart]
+ );
+ const fetchFromServer = async (url, options = {}) => {
+ try {
+ const response = await fetch(
+ `${process.env.REACT_APP_SERVER}${url}`,
+ options
+ );
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ return await response.json();
+ } catch (error) {
+ console.error('Error fetching from server:', error);
+ throw error; // Rethrow the error for handling in calling functions
+ }
+ };
+
+ const createUserCart = useCallback(async () => {
+ try {
+ const newCartData = await fetchFromServer('/api/carts/createEmptyCart', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ userId }),
+ });
+ setCartDataAndCookie(newCartData);
+ } catch (error) {
+ console.error('Error creating cart:', error);
+ }
+ }, [userId, setCookie]);
+
+ const fetchUserCart = useCallback(async () => {
+ try {
+ const data = await fetchFromServer(`/api/carts/userCart/${userId}`);
+ setCartDataAndCookie(data);
+ } catch (error) {
+ console.error('Error fetching user cart:', error);
+ if (error.message.includes('404')) {
+ await createUserCart();
+ }
+ }
+ }, [userId, createUserCart]);
+
useEffect(() => {
+ if (userId && isMounted.current) {
+ fetchUserCart().catch(console.error);
+ }
return () => {
isMounted.current = false;
};
- }, []);
+ }, [userId, fetchUserCart]);
- const fetchFromServer = async (url, options = {}) => {
- const response = await fetch(
- `${process.env.REACT_APP_SERVER}${url}`,
- options
- );
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
+ const setCartDataAndCookie = (newCartData) => {
+ if (newCartData && Array.isArray(newCartData.cart)) {
+ setCartData(newCartData);
+ setCookie('cart', newCartData.cart, {
+ path: '/',
+ secure: true,
+ sameSite: 'none',
+ });
}
- return await response.json();
};
+
+ const getTotalCost = () => {
+ return cartData.cart.reduce(
+ (acc, card) => acc + card.card_prices[0].tcgplayer_price * card.quantity,
+ 0
+ );
+ };
+
+ useEffect(() => {
+ const totalQuantity = cartData.cart.reduce(
+ (total, item) => total + item.quantity,
+ 0
+ );
+ const calculatedTotalPrice = getTotalCost();
+
+ if (
+ cartData.quantity !== totalQuantity ||
+ cartData.totalPrice !== calculatedTotalPrice
+ ) {
+ setCartData((prevState) => ({
+ ...prevState,
+ quantity: totalQuantity,
+ totalPrice: calculatedTotalPrice,
+ }));
+ }
+ }, [cartData.cart]);
+ // Fetch user cart on mount and userId change
const updateCart = async (cartId, updatedCart) => {
if (!cartId) return;
const formattedCartData = {
@@ -70,71 +170,9 @@ export const CartProvider = ({ children }) => {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formattedCartData),
});
- // if (data && data.cart) {
- // setCartDataAndCookie(data.cart);
- // }
setCartDataAndCookie(data);
return data;
};
- const createUserCart = useCallback(
- async (userId) => {
- try {
- const newCartData = await fetchFromServer(
- '/api/carts/createEmptyCart',
- {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ userId }),
- }
- );
- // setCookie('cart', newCartData, {
- // // Changed this line
- // path: '/',
- // secure: true,
- // sameSite: 'none',
- // });
- setCartDataAndCookie(newCartData);
- return newCartData;
- } catch (error) {
- console.error('Error creating cart:', error);
- }
- },
- [setCookie]
- );
-
- const fetchUserCart = useCallback(
- async (userId) => {
- try {
- const data = await fetchFromServer(`/api/carts/userCart/${userId}`);
- // setCookie('cart', data.cart || [], {
- // path: '/',
- // secure: true,
- // sameSite: 'none',
- // });
- setCartDataAndCookie(data);
- return data;
- } catch (error) {
- if (error.message === 'HTTP error! status: 404') {
- await createUserCart(userId);
- } else {
- console.error('Error fetching user cart:', error);
- }
- }
- },
- [createUserCart]
- );
-
- const getCardQuantity = (cardId) => {
- let totalItems = 0;
- let quantityOfSameId = 0;
- cartData.cart.forEach((item) => {
- totalItems += item.quantity;
- if (item.id === cardId) {
- quantityOfSameId += item.quantity;
- }
- });
- return { totalItems, quantityOfSameId };
- };
const addOneToCart = async (cardInfo) => {
if (!cartData._id) return;
@@ -151,7 +189,6 @@ export const CartProvider = ({ children }) => {
console.log('UPDATED CART DATA:', updatedCartData);
if (updatedCartData) setCartData(updatedCartData);
};
-
const removeOneFromCart = async (cardInfo) => {
if (cartData.cart.some((item) => item.id === cardInfo.id)) {
const updatedCart = cartData.cart
@@ -165,93 +202,25 @@ export const CartProvider = ({ children }) => {
if (updatedCartData) setCartData(updatedCartData);
}
};
-
const deleteFromCart = async (cardInfo) => {
const updatedCart = cartData.cart.filter((item) => item.id !== cardInfo.id);
const updatedCartData = await updateCart(cartData._id, updatedCart);
if (updatedCartData) setCartData(updatedCartData);
};
-
- const setCartDataAndCookie = (newCartData) => {
- if (newCartData && Array.isArray(newCartData.cart)) {
- setCartData(newCartData);
- setCookie('cart', newCartData.cart, {
- path: '/',
- secure: true,
- sameSite: 'none',
- });
- }
- };
-
- useEffect(() => {
- if (userId && typeof userId === 'string' && isMounted.current) {
- fetchUserCart(userId)
- .then((data) => {
- if (isMounted.current && data && data.cart) {
- setCartDataAndCookie(data);
- }
- })
- .catch((error) => console.log('Error fetching user cart:', error));
- }
- return () => {
- isMounted.current = false;
- };
- }, [userId, fetchUserCart]);
- // useEffect(() => {
- // if (userId && typeof userId === 'string') {
- // // console.log('Fetching user cart');
- // fetchUserCart(userId)
- // .then((data) => {
- // if (data && data.cart) {
- // setCartDataAndCookie(data);
- // }
- // })
- // .catch((error) => console.log('Error fetching user cart:', error));
+ // const setCartDataAndCookie = (newCartData) => {
+ // if (newCartData && Array.isArray(newCartData.cart)) {
+ // setCartData(newCartData);
+ // setCookie('cart', newCartData.cart, {
+ // path: '/',
+ // secure: true,
+ // sameSite: 'none',
+ // });
// }
- // }, [userId, fetchUserCart]);
-
- const getTotalCost = useMemo(
- () =>
- cartData.cart.reduce(
- (total, item) =>
- total + item.quantity * item.card_prices[0].tcgplayer_price,
- 0
- ),
- [cartData.cart]
- );
-
- useEffect(() => {
- if (!isMounted.current) return;
-
- const totalQuantity = cartData.cart.reduce(
- (total, item) => total + item.quantity,
- 0
- );
-
- console.log('TOTAL QUANTITY:', totalQuantity);
- if (
- cartData.quantity !== totalQuantity ||
- cartData.totalPrice !== getTotalCost
- ) {
- setCartDataAndCookie((prevState) => ({
- ...prevState,
- quantity: totalQuantity,
- totalPrice: getTotalCost,
- }));
- }
- }, [cartData.cart, cartData.quantity, cartData.totalPrice, getTotalCost]);
-
- // const logUpdate = (funcName, newState) => {
- // console.log(`Update from ${funcName}:`, newState);
// };
const value = {
cartData,
getCardQuantity,
- // getCardQuantity: (cardId) => {
- // const card = cartData?.cart?.find((c) => c?.id === cardId);
- // return card?.quantity || 0;
- // },
cartCardQuantity: cartData.cart?.reduce(
(acc, card) => acc + card.quantity,
0
@@ -261,6 +230,8 @@ export const CartProvider = ({ children }) => {
(acc, card) => acc + card.card_prices[0].tcgplayer_price * card.quantity,
0
),
+ totalPrice: cartData.totalPrice,
+ totalCost,
addOneToCart: addOneToCart,
removeOneFromCart: removeOneFromCart,
deleteFromCart,
@@ -268,19 +239,48 @@ export const CartProvider = ({ children }) => {
fetchUserCart,
createUserCart,
};
+ // useEffect(() => {
+ // if (userId && typeof userId === 'string') {
+ // fetchUserCart(userId)
+ // .then((data) => {
+ // if (isMounted.current && data && data.cart) {
+ // setCartData(data); // Assuming data has the same structure as cartData
+ // }
+ // })
+ // .catch((error) => console.log('Error fetching user cart:', error));
+ // }
+ // return () => {
+ // isMounted.current = false;
+ // };
+ // }, [userId, fetchUserCart]);
+
+ // // Update cartData quantity and totalPrice when cart changes
+ // useEffect(() => {
+ // if (!isMounted.current) return;
+
+ // const totalQuantity = cartData.cart.reduce(
+ // (total, item) => total + item.quantity,
+ // 0
+ // );
+ // const calculatedTotalPrice = getTotalCost();
+
+ // if (
+ // cartData.quantity !== totalQuantity ||
+ // cartData.totalPrice !== calculatedTotalPrice
+ // ) {
+ // setCartData((prevState) => ({
+ // ...prevState,
+ // quantity: totalQuantity,
+ // totalPrice: calculatedTotalPrice,
+ // }));
+ // }
+ // }, [cartData.cart, getTotalCost]);
useEffect(() => {
console.log('CART CONTEXT: ', {
- cartData,
- // getTotalCost,
- // getCardQuantity,
- // fetchUserCart,
- // addOneToCart,
- // removeOneFromCart,
- // deleteFromCart,
- // createUserCart,
+ value,
});
- }, [cartData]);
+ }, [value]);
return {children} ;
};
diff --git a/src/context/CartContext/helpers.jsx b/src/context/CartContext/helpers.jsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/context/ChartContext/ChartContext.jsx b/src/context/ChartContext/ChartContext.jsx
index eefb826..f31ac8f 100644
--- a/src/context/ChartContext/ChartContext.jsx
+++ b/src/context/ChartContext/ChartContext.jsx
@@ -14,7 +14,6 @@ export const ChartProvider = ({ children }) => {
const [latestData, setLatestData] = useState(null);
const [timeRange, setTimeRange] = useState(86400000 || 24 * 60 * 60 * 1000); // Default to 24 hours
- // Correctly initialize timeRanges with the useState hook
const [timeRanges] = useState([
{ label: '2 hours', value: 720000 || 2 * 60 * 60 * 1000 },
{ label: '24 hours', value: 86400000 || 24 * 60 * 60 * 1000 },
@@ -24,11 +23,9 @@ export const ChartProvider = ({ children }) => {
const currentValue = timeRanges.find((option) => option.value === timeRange);
- // console.log('currentValue: ', currentValue);
const handleChange = (e) => {
- setTimeRange(e.target.value);
+ setTimeRange(e.target.value); // Update timeRange based on selection
};
-
return (
({
- x: entry?.timestamp, // x represents the timestamp
- y: entry?.num, // y represents the numerical value
- label: `Price at ${entry?.timestamp}`, // label can be customized as needed
- }));
-}
-
-const getAllCardPrices = (cards) =>
- cards.flatMap((card) => Array(card.quantity).fill(card.price));
-
-function filterUniqueDataPoints(dataArray) {
- const uniqueRecords = new Map();
-
- dataArray?.forEach((item) => {
- const key = `${item?.label}-${item?.x}-${item?.y}`;
- if (!uniqueRecords.has(key)) {
- uniqueRecords.set(key, item);
- }
- });
-
- return Array.from(uniqueRecords.values());
-}
-
export const CollectionProvider = ({ children }) => {
const [cookies] = useCookies(['user']);
const [selectedCollection, setSelectedCollection] = useState(
@@ -72,7 +61,7 @@ export const CollectionProvider = ({ children }) => {
const [openChooseCollectionDialog, setOpenChooseCollectionDialog] =
useState(false);
const userId = cookies?.user?.id;
- console.log('USER ID:', userId);
+ // console.log('USER ID:', userId);
const lastFetchedTime = useRef(null);
const fetchAndSetCollections = useCallback(async () => {
@@ -88,10 +77,8 @@ export const CollectionProvider = ({ children }) => {
if (!shouldFetch()) return;
try {
- if (!userId) {
- console.error('No user ID found.');
- return;
- }
+ if (!handleError(userId, 'User ID is missing.')) return;
+
lastFetchedTime.current = Date.now();
const response = await fetchWrapper(
createApiUrl(`${userId}/collections`),
@@ -102,9 +89,13 @@ export const CollectionProvider = ({ children }) => {
console.log('FETCHED COLLECTIONS:', collections);
if (collections.length > 0) {
- setAllCollections(collections);
- setCollectionData(collections[0]);
- setSelectedCollection(collections[0]);
+ const uniqueCollections = collections.map(
+ removeDuplicatesFromCollection
+ );
+
+ setAllCollections(uniqueCollections);
+ setCollectionData(uniqueCollections[0]);
+ setSelectedCollection(uniqueCollections[0]);
} else {
console.warn('No collections found.');
// Optionally, set a default or empty state if no collections are found
@@ -114,28 +105,34 @@ export const CollectionProvider = ({ children }) => {
}
}, [userId, setAllCollections, setCollectionData, setSelectedCollection]);
- const updateCollectionArray = (collections, newData) => {
- const index = collections.findIndex((c) => c._id === newData?._id);
- return index === -1
- ? [...collections, newData]
- : collections.map((c) => (c._id === newData?._id ? newData : c));
- };
-
const updateCollectionData = useCallback(
- (newData, collectionType) => {
+ (newData) => {
try {
- switch (collectionType) {
- case 'allCollections':
- setAllCollections((prev) => updateCollectionArray(prev, newData));
- break;
- case 'selectedCollection':
- setSelectedCollection(newData);
- break;
- case 'collectionData':
- setCollectionData(newData);
- break;
- default:
- console.warn('Unknown collection type for update:', collectionType);
+ // Function to safely check if an object has a property
+ const hasOwnProperty = (obj, prop) =>
+ Object.prototype.hasOwnProperty.call(obj, prop);
+
+ // Determine the type of the new data
+ if (
+ Array.isArray(newData) &&
+ newData.every((item) => hasOwnProperty(item, 'cards'))
+ ) {
+ // If newData is an array of objects each containing 'cards', assume it's 'allCollections'
+ setAllCollections((prev) => updateCollectionArray(prev, newData));
+ } else if (
+ newData &&
+ typeof newData === 'object' &&
+ hasOwnProperty(newData, 'cards')
+ ) {
+ // If newData is an object with a 'cards' property, assume it's 'selectedCollection'
+ setSelectedCollection(newData);
+ } else if (newData && typeof newData === 'object') {
+ // If newData is a general object, assume it's 'collectionData'
+ setCollectionData(newData);
+ } else {
+ console.warn(
+ 'Unable to determine the type of collection data for update.'
+ );
}
} catch (error) {
console.error('Error updating collection data:', error);
@@ -163,7 +160,6 @@ export const CollectionProvider = ({ children }) => {
return;
}
- // const payload = createPayload(newCollectionInfo, name, description, userId);
const payload = {
...newCollectionInfo,
name,
@@ -171,21 +167,9 @@ export const CollectionProvider = ({ children }) => {
userId,
};
const url = createApiUrl(`${userId}/collections`);
- console.log('Creating user collection with data:', {
- userId,
- newCollectionInfo,
- name,
- description,
- });
console.log('Payload for user collection:', payload);
-
const response = await fetchWrapper(url, 'POST', payload);
- console.log('6. Saved collection:', response);
- console.log('6. Saved collection:', response.data);
- console.log('6. Saved collection:', response.message);
- updateCollectionData(response.data, 'allCollections');
- updateCollectionData(response.data, 'collectionData');
- updateCollectionData(response.data, 'selectedCollection');
+ updateCollectionData(response.data);
};
const removeCollection = async (collection) => {
@@ -225,16 +209,12 @@ export const CollectionProvider = ({ children }) => {
}
if (!cardUpdate?.id) {
console.warn('Card ID is missing.', cardUpdate);
- // return collection?.cards;
}
// eslint-disable-next-line no-case-declarations
const cards = collection?.cards;
for (let i = 0; i < cards?.length; i++) {
// eslint-disable-next-line no-case-declarations
- // const cardIndex = selectedCollection?.cards?.findIndex(
- // (c) => c?.id === cardUpdate?.id
- // );
if (!cards[i]?.id) {
console.warn('Card ID is missing.', cards[i]);
continue;
@@ -281,14 +261,6 @@ export const CollectionProvider = ({ children }) => {
return cardsToUpdate;
};
- function replaceCardInArray(cardsArray, newCard, index) {
- return [
- ...cardsArray.slice(0, index),
- newCard,
- ...cardsArray.slice(index + 1),
- ];
- }
-
function getUpdatedCard(card, update, priceHistory, collectionId) {
const cardPrice = determineCardPrice(card, update);
const newChartDataEntry = createChartDataEntry(totalPrice);
@@ -311,42 +283,6 @@ export const CollectionProvider = ({ children }) => {
};
}
- function determineCardPrice(card, update) {
- if (update?.latestPrice?.num) return update.latestPrice.num;
- if (card.price) return card.price;
- return card.card_prices[0].tcgplayer_price;
- }
-
- function updatePriceHistory(card, update) {
- const newPriceHistoryEntry = createPriceHistoryObject(
- update?.latestPrice?.num
- );
- const lastPriceHistoryEntry =
- card?.priceHistory[card?.priceHistory?.length - 1];
-
- if (
- !lastPriceHistoryEntry ||
- lastPriceHistoryEntry?.num !== newPriceHistoryEntry?.num
- ) {
- return [...card.priceHistory, newPriceHistoryEntry];
- }
- return card?.priceHistory;
- }
-
- function createChartDataEntry(price) {
- return {
- x: moment().format('YYYY-MM-DD HH:mm'),
- y: price,
- };
- }
-
- function createPriceHistoryObject(price) {
- return {
- num: price,
- timestamp: new Date(),
- };
- }
-
// Helper function to get updated collection data
const getUpdatedCollectionData = (
collectionWithCards,
@@ -377,9 +313,12 @@ export const CollectionProvider = ({ children }) => {
name,
userId: userId, // Make sure 'userId' is defined in the scope
totalPrice: updatedTotalPrice || 0,
- totalCost: updatedTotalPrice ? updatedTotalPrice.toString() : '0',
- totalQuantity: cards.reduce((acc, card) => acc + (card.quantity || 0), 0),
- quantity: cards.length,
+ totalCost: updatedTotalPrice ? updatedTotalPrice?.toString() : '0',
+ totalQuantity: cards?.reduce(
+ (acc, card) => acc + (card?.quantity || 0),
+ 0
+ ),
+ quantity: cards?.length,
lastSavedPrice: {
num: collectionWithCards?.totalPrice || 0,
timestamp: collectionWithCards?.lastSavedPrice?.timeStamp || new Date(),
@@ -400,31 +339,6 @@ export const CollectionProvider = ({ children }) => {
};
};
- const getFilteredChartData = (chartData, updatedTotalPrice) => {
- const filteredChartData = {
- ...chartData,
- allXYValues: filterUniqueDataPoints(chartData?.allXYValues),
- datasets: chartData?.datasets.map((dataset) => ({
- ...dataset,
- data: dataset?.data.map((dataEntry) => ({
- ...dataEntry,
- xys: filterUniqueDataPoints(dataEntry?.xys),
- })),
- })),
- };
- return {
- ...filteredChartData,
- allXYValues: [
- ...filteredChartData.allXYValues,
- {
- label: `Update - ${new Date().toISOString()}`,
- x: new Date().toISOString(),
- y: updatedTotalPrice,
- },
- ],
- };
- };
-
const getUpdatedCollection = async (
collectionWithCards, // updated cards
cardUpdate, // updated card
@@ -655,21 +569,7 @@ export const CollectionProvider = ({ children }) => {
if (updatedCollection) {
console.log('UPDATED COLLECTION:', updatedCollection);
- // Update the relevant collections in the state/context
- updateCollectionData(
- updatedCollection?.restructuredCollection,
- 'allCollections'
- );
- if (collection._id === selectedCollection?._id) {
- updateCollectionData(
- updatedCollection?.restructuredCollection,
- 'selectedCollection'
- );
- }
- updateCollectionData(
- updatedCollection?.restructuredCollection,
- 'collectionData'
- );
+ updateCollectionData(updatedCollection?.restructuredCollection);
} else {
console.error('Failed to update collection.');
}
diff --git a/src/context/CollectionContext/helpers.jsx b/src/context/CollectionContext/helpers.jsx
new file mode 100644
index 0000000..4a045a8
--- /dev/null
+++ b/src/context/CollectionContext/helpers.jsx
@@ -0,0 +1,125 @@
+import moment from 'moment';
+
+export const transformPriceHistoryToXY = (collectionPriceHistory) => {
+ return collectionPriceHistory?.map((entry) => ({
+ x: entry?.timestamp, // x represents the timestamp
+ y: entry?.num, // y represents the numerical value
+ label: `Price at ${entry?.timestamp}`, // label can be customized as needed
+ }));
+};
+
+export const getAllCardPrices = (cards) =>
+ cards.flatMap((card) => Array(card.quantity).fill(card.price));
+
+export const filterUniqueDataPoints = (dataArray) => {
+ const uniqueRecords = new Map();
+
+ dataArray?.forEach((item) => {
+ const key = `${item?.label}-${item?.x}-${item?.y}`;
+ if (!uniqueRecords.has(key)) {
+ uniqueRecords.set(key, item);
+ }
+ });
+
+ return Array.from(uniqueRecords.values());
+};
+
+export const determineCardPrice = (card, update) => {
+ if (update?.latestPrice?.num) return update.latestPrice.num;
+ if (card.price) return card.price;
+ return card.card_prices[0].tcgplayer_price;
+};
+
+export const updatePriceHistory = (card, update) => {
+ const newPriceHistoryEntry = createPriceHistoryObject(
+ update?.latestPrice?.num
+ );
+ const lastPriceHistoryEntry =
+ card?.priceHistory[card?.priceHistory?.length - 1];
+
+ if (
+ !lastPriceHistoryEntry ||
+ lastPriceHistoryEntry?.num !== newPriceHistoryEntry?.num
+ ) {
+ return [...card.priceHistory, newPriceHistoryEntry];
+ }
+ return card?.priceHistory;
+};
+
+export const createChartDataEntry = (price) => {
+ return {
+ x: moment().format('YYYY-MM-DD HH:mm'),
+ y: price,
+ };
+};
+
+export const createPriceHistoryObject = (price) => {
+ return {
+ num: price,
+ timestamp: new Date(),
+ };
+};
+
+export const getFilteredChartData = (chartData, updatedTotalPrice) => {
+ const filteredChartData = {
+ ...chartData,
+ allXYValues: filterUniqueDataPoints(chartData?.allXYValues),
+ datasets: chartData?.datasets.map((dataset) => ({
+ ...dataset,
+ data: dataset?.data.map((dataEntry) => ({
+ ...dataEntry,
+ xys: filterUniqueDataPoints(dataEntry?.xys),
+ })),
+ })),
+ };
+ return {
+ ...filteredChartData,
+ allXYValues: [
+ ...filteredChartData.allXYValues,
+ {
+ label: `Update - ${new Date().toISOString()}`,
+ x: new Date().toISOString(),
+ y: updatedTotalPrice,
+ },
+ ],
+ };
+};
+
+export const replaceCardInArray = (cardsArray, newCard, index) => {
+ return [
+ ...cardsArray.slice(0, index),
+ newCard,
+ ...cardsArray.slice(index + 1),
+ ];
+};
+
+export const updateCollectionArray = (collections, newData) => {
+ const index = collections.findIndex((c) => c._id === newData?._id);
+ return index === -1
+ ? [...collections, newData]
+ : collections.map((c) => (c._id === newData?._id ? newData : c));
+};
+
+export const removeDuplicatesFromCollection = (collection) => {
+ const uniqueCardsMap = new Map();
+
+ collection.cards.forEach((card) => {
+ const uniqueKey = `${card.id}-${card.name}`;
+ if (!uniqueCardsMap.has(uniqueKey)) {
+ uniqueCardsMap.set(uniqueKey, card);
+ }
+ });
+
+ return {
+ ...collection,
+ cards: Array.from(uniqueCardsMap.values()),
+ };
+};
+
+export const handleError = (condition, errorMessage) => {
+ if (!condition) {
+ console.error(errorMessage);
+ return false;
+ }
+ return true;
+};
diff --git a/src/context/CronJobContext/CronJobContext.jsx b/src/context/CronJobContext/CronJobContext.jsx
index d28b60e..4c00b02 100644
--- a/src/context/CronJobContext/CronJobContext.jsx
+++ b/src/context/CronJobContext/CronJobContext.jsx
@@ -20,8 +20,6 @@ export const CronJobProvider = ({ children }) => {
const currentTime = new Date().getTime();
const timeDifference = currentTime - lastCronJobTriggerTime;
- // Define your cron job logic here
- // Example: Trigger an action if a certain time has elapsed
if (timeDifference >= 60000) {
// 60 seconds
setLastCronJobTriggerTime(currentTime);
diff --git a/src/context/DeckContext/DeckContext.js b/src/context/DeckContext/DeckContext.js
index deac22f..7983db8 100644
--- a/src/context/DeckContext/DeckContext.js
+++ b/src/context/DeckContext/DeckContext.js
@@ -272,7 +272,7 @@ export const DeckProvider = ({ children }) => {
useEffect(() => {
console.log('DECKCONTEXT:', contextValue);
const userId = cookies?.user?.id;
- if (userId) {
+ if (userId && typeof userId === 'string') {
fetchAndSetDecks();
}
}, [cookies?.user?.id, fetchAndSetDecks]);
diff --git a/src/context/ScraperContext/ScraperContext.js b/src/context/ScraperContext/ScraperContext.js
deleted file mode 100644
index 8422c71..0000000
--- a/src/context/ScraperContext/ScraperContext.js
+++ /dev/null
@@ -1,168 +0,0 @@
-/* eslint-disable @typescript-eslint/no-empty-function */
-import React, {
- createContext,
- useState,
- useEffect,
- useCallback,
- useContext,
- useRef,
-} from 'react';
-import { useCookies } from 'react-cookie';
-
-const defaultContextValue = {
- scrapeData: {
- _id: '',
- url: '',
- pricingData: [],
- pricingData2: [],
- listingGeneralInfo: {
- otherListings: '',
- lowestAvailablePrice: '',
- },
- listingSpotlightInfo: {
- spotlightCondition: '',
- spotlightPrice: '',
- spotlightShipping: '',
- spotlightSeller: '',
- },
- },
- setScrapeData: () => {},
- fetchExistingScrapeData: () => {},
- createScrapeData: () => {},
-};
-
-export const ScraperContext = createContext(defaultContextValue);
-
-export const ScrapeDataProvider = ({ children }) => {
- const [scrapeData, setScrapeData] = useState({
- _id: '',
- url: '',
- pricingData: [],
- pricingData2: [],
- listingGeneralInfo: {
- otherListings: '',
- lowestAvailablePrice: '',
- },
- listingSpotlightInfo: {
- spotlightCondition: '',
- spotlightPrice: '',
- spotlightShipping: '',
- spotlightSeller: '',
- },
- });
- const [scrapeDataBackup, setScrapeDataBackup] = useState({});
- const [loading, setLoading] = useState(false);
- const [error, setError] = useState(null);
- const [, setCookie] = useCookies(['userCookie', 'scrapeData']);
-
- const isMountedRef = useRef(true);
-
- useEffect(() => {
- return () => {
- isMountedRef.current = false;
- };
- }, []);
-
- const scrapeForData = async (cardName) => {
- try {
- const finalCardName = cardName || 'Dark Magician';
-
- const response = await fetch(
- `${
- process.env.REACT_APP_SERVER
- }/api/scrape?cardName=${encodeURIComponent(finalCardName)}`,
- {
- method: 'GET',
- }
- );
-
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
-
- const data = await response.json();
-
- if (data && data.pricingData) {
- // checking one property as an example
- setScrapeDataBackup(data);
- setScrapeData(data);
- }
-
- setCookie('scrapeData', data, { path: '/' });
- return data;
- } catch (error) {
- console.error('Error scraping data:', error);
- }
- };
-
- const fetchExistingScrapeData = useCallback(async () => {
- if (!isMountedRef.current) return;
-
- setLoading(true);
- setError(null);
-
- try {
- const response = await fetch(
- `${process.env.REACT_APP_SERVER}/api/scrape`
- );
- console.log('FETCH EXISTING SCRAPE DATA RESPONSE:', response);
- const data = await response.json();
- console.log('FETCH EXISTING SCRAPE DATA:', data);
- if (
- !response.ok ||
- response.headers.get('content-type') !== 'application/json'
- ) {
- setCookie('scrapeData', Array.isArray(data.scrape) ? data.scrape : [], {
- path: '/',
- });
- throw new Error(data.message || 'Server response was not ok.');
- }
-
- if (Array.isArray(data.scrape)) {
- setScrapeDataBackup(data.scrape);
- setScrapeData(data.scrape);
- setCookie('scrapeData', data.scrape, { path: '/' });
- }
- } catch (err) {
- if (isMountedRef.current) {
- setError(err.message);
- }
- } finally {
- if (isMountedRef.current) {
- setLoading(false);
- }
- }
- }, [setCookie]);
-
- useEffect(() => {
- console.log('SCRAPER CONTEXT (ScrapeProvider):', {
- scrapeData,
- loading,
- error,
- });
- }, [scrapeData, loading, error]);
-
- return (
-
- {children}
-
- );
-};
-
-export const useScraperStore = () => {
- const context = useContext(ScraperContext);
- if (!context) {
- throw new Error('useScraperStore must be used within a ScrapeDataProvider');
- }
-
- return context;
-};
diff --git a/src/context/StatisticsContext/StatisticsContext.jsx b/src/context/StatisticsContext/StatisticsContext.jsx
new file mode 100644
index 0000000..f126656
--- /dev/null
+++ b/src/context/StatisticsContext/StatisticsContext.jsx
@@ -0,0 +1,49 @@
+import React, { createContext, useContext, useState, useMemo } from 'react';
+import { useCollectionStore } from '../CollectionContext/CollectionContext';
+import { calculateStatistics } from './helpers';
+import { useChartContext } from '../ChartContext/ChartContext';
+
+const StatisticsContext = createContext();
+
+export const useStatisticsStore = () => useContext(StatisticsContext);
+// export const useStatisticsStore = () => {
+// const context = useContext(StatisticsContext);
+// if (!context) {
+// throw new Error(
+// 'useStatisticsStore must be used within a CollectionProvider'
+// );
+// }
+// return context;
+// };
+export const StatisticsProvider = ({ children }) => {
+ const { timeRange } = useChartContext();
+ const { allCollections } = useCollectionStore();
+
+ const dataForStats = allCollections
+ .map((collection) => collection.currentChartDataSets2)
+ .flat();
+
+ const stats = useMemo(
+ () => calculateStatistics({ data: dataForStats }, timeRange),
+ [dataForStats, timeRange]
+ );
+
+ console.log('stats', stats);
+ return (
+
+ {children}
+
+ );
+};
+
+// export const useStatisticsStore = () => {
+// const context = useContext(StatisticsContext);
+// if (!context) {
+// throw new Error(
+// 'useStatisticsStore must be used within a CollectionProvider'
+// );
+// }
+// return context;
+// };
+
+// Include calculateStatistics and calculatePriceChanges functions here
diff --git a/src/context/StatisticsContext/helpers.jsx b/src/context/StatisticsContext/helpers.jsx
new file mode 100644
index 0000000..4f4565a
--- /dev/null
+++ b/src/context/StatisticsContext/helpers.jsx
@@ -0,0 +1,98 @@
+export const calculatePriceChanges = (data) => {
+ if (!Array.isArray(data) || data.length === 0) return [];
+
+ const sortedData = data.sort((a, b) => new Date(a.x) - new Date(b.x));
+ const latestDataPoint = sortedData[sortedData.length - 1];
+ const latestTime = new Date(latestDataPoint.x).getTime();
+ const twentyFourHoursAgo = latestTime - 24 * 60 * 60 * 1000;
+
+ // Find the data point closest to 24 hours before the latest data point
+ let closestIndex = -1;
+ let closestTimeDifference = Number.MAX_SAFE_INTEGER;
+
+ for (let i = 0; i < sortedData.length - 1; i++) {
+ const time = new Date(sortedData[i].x).getTime();
+ const timeDifference = Math.abs(time - twentyFourHoursAgo);
+
+ if (timeDifference < closestTimeDifference) {
+ closestTimeDifference = timeDifference;
+ closestIndex = i;
+ }
+ }
+
+ if (closestIndex !== -1) {
+ const pastPrice = sortedData[closestIndex].y;
+ // console.log('pastPrice', pastPrice);
+ const priceChange = latestDataPoint.y - pastPrice;
+ // console.log('priceChange', priceChange);
+ const percentageChange = ((priceChange / pastPrice) * 100).toFixed(2);
+ // console.log('percentageChange', percentageChange);
+
+ return [
+ {
+ startDate: sortedData[closestIndex].x,
+ lowPoint: pastPrice.toFixed(2),
+ highPoint: latestDataPoint?.y?.toFixed(2),
+ endDate: latestDataPoint?.x,
+ priceChange: priceChange.toFixed(2),
+ percentageChange: `${percentageChange}%`,
+ priceIncreased: priceChange > 0,
+ },
+ ];
+ }
+
+ return [];
+};
+
+export const calculateStatistics = (data, timeRange) => {
+ if (!data || !Array.isArray(data.data) || data.data.length === 0) return {};
+
+ const filteredData = data?.data?.filter(
+ (item) => new Date(item?.x).getTime() >= Date.now() - timeRange
+ );
+ if (filteredData.length === 0) return {};
+ let highPoint = 0;
+ let lowPoint = 0;
+ let sum = 0;
+ let averageData = 0;
+ let average = 0;
+ let volume = 0;
+ let mean = 0;
+ let squaredDiffs = 0;
+ let volatility = 0;
+ // const filteredData2 = getFilteredData2(data, timeRange);
+ // console.log('filteredData2', filteredData2);
+ // console.log('filteredData', filteredData);
+ for (const data of filteredData) {
+ // console.log('data', data);
+ highPoint = Math.max(...filteredData.map((item) => item.y));
+ lowPoint = Math.min(...filteredData.map((item) => item.y));
+ sum = filteredData.reduce((acc, curr) => acc + curr.y, 0);
+ averageData = calculatePriceChanges(filteredData);
+ average = sum / filteredData.length || 0;
+ volume = filteredData.length;
+ mean = sum / volume;
+ squaredDiffs = filteredData.map((item) => {
+ const diff = item.y - mean;
+ return diff * diff;
+ });
+ volatility = Math.sqrt(squaredDiffs.reduce((a, b) => a + b, 0) / volume);
+ }
+
+ return {
+ highPoint: highPoint.toFixed(2),
+ lowPoint: lowPoint.toFixed(2),
+ twentyFourHourAverage: {
+ startDate: averageData[0]?.startDate,
+ endDate: averageData[0]?.endDate,
+ lowPoint: averageData[0]?.lowPoint,
+ highPoint: averageData[0]?.highPoint,
+ priceChange: averageData[0]?.priceChange,
+ percentageChange: averageData[0]?.percentageChange,
+ priceIncreased: averageData[0]?.priceIncreased,
+ },
+ average: average?.toFixed(2),
+ volume,
+ volatility: volatility?.toFixed(2),
+ };
+};
diff --git a/src/index.js b/src/index.js
index 0f2beed..cdefc91 100644
--- a/src/index.js
+++ b/src/index.js
@@ -21,10 +21,11 @@ import { AppContextProvider } from './context/AppContext/AppContextProvider';
import { useMode } from './context/hooks/colormode';
import { PopoverProvider } from './context/PopoverContext/PopoverContext';
import { CronJobProvider } from './context/CronJobContext/CronJobContext';
-import { CardImagesProvider } from './context/CardImagesContext/CardImagesContext';
+// import { CardImagesProvider } from './context/CardImagesContext/CardImagesContext';
import { BrowserRouter as Router } from 'react-router-dom';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
+import { StatisticsProvider } from './context/StatisticsContext/StatisticsContext';
const root = document.getElementById('root');
@@ -54,13 +55,15 @@ function Main() {
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
{/* */}
diff --git a/src/pages/CollectionPage.js b/src/pages/CollectionPage.js
index 2f611df..08e1908 100644
--- a/src/pages/CollectionPage.js
+++ b/src/pages/CollectionPage.js
@@ -9,13 +9,17 @@ import Subheader from '../components/reusable/Subheader';
import { useCollectionStore } from '../context/CollectionContext/CollectionContext';
import { ModalContext } from '../context/ModalContext/ModalContext';
import GenericCardModal from '../components/modals/cardModal/GenericCardModal';
-import { CollectionBanner } from './pageStyles/StyledComponents';
+import {
+ CollectionBanner,
+ CollectionContents,
+} from './pageStyles/StyledComponents';
+import { useMode } from '../context/hooks/colormode';
const HeroCenter = ({ decorative, title, subtitle }) => (
{
- const [{ user }] = useCookies(['user']);
+ const { theme } = useMode();
const { allCollections, selectedCollection, loading, error } =
useCollectionStore();
const { openModalWithCard, closeModal, isModalOpen, modalContent } =
useContext(ModalContext);
- const userId = user?.id;
if (loading) return ;
if (error) return ;
@@ -86,19 +89,21 @@ const CollectionPage = () => {
-
+
+ {/* */}
- {' '}
+ {/* */}
+
{isModalOpen && (
)}
diff --git a/src/pages/DeckBuilderPage.js b/src/pages/DeckBuilderPage.js
index f8f1e46..fc3cf64 100644
--- a/src/pages/DeckBuilderPage.js
+++ b/src/pages/DeckBuilderPage.js
@@ -11,6 +11,9 @@ import HeaderTitle from '../components/reusable/HeaderTitle';
import { useMode } from '../context/hooks/colormode';
import { DeckBuilderBanner } from './pageStyles/StyledComponents';
import useUpdateAppContext from '../context/hooks/useUpdateContext';
+import UserContext, {
+ useUserContext,
+} from '../context/UserContext/UserContext';
const HeroCenter2 = ({ title, subtitle }) => (
{
const [userDecks, setUserDecks] = useState([]);
- const { user } = useCookies(['user'])[0];
const { theme } = useMode();
const { fetchAllDecksForUser, allDecks, loading, error } = useDeckStore();
+ const { user } = useUserContext();
const { openModalWithCard, closeModal, isModalOpen, modalContent } =
useContext(ModalContext);
const userId = user?.id;
- // useUpdateAppContext(); // This will set the context to 'Deck' when this page is rendered
-
- console.log('userid', userId);
useEffect(() => {
fetchAllDecksForUser().catch((err) =>
console.error('Failed to get all decks:', err)
@@ -68,7 +68,7 @@ const DeckBuilderPage = () => {
}, [fetchAllDecksForUser]);
useEffect(() => {
- if (allDecks && userId) {
+ if (allDecks && userId && typeof userId === 'string') {
const filteredDecks = allDecks?.filter((deck) => deck?.userId === userId);
console.log('filteredDecks', filteredDecks);
setUserDecks(filteredDecks);
diff --git a/src/pages/HomePage.js b/src/pages/HomePage.js
index d690580..879ca82 100644
--- a/src/pages/HomePage.js
+++ b/src/pages/HomePage.js
@@ -27,6 +27,8 @@ import {
// import LoadingIndicator2 from '../components/reusable/indicators/LoadingIndicator2';
// import LoadingCardAnimation from '../assets/animations/LoadingCardAnimation';
import pages from './pages.json';
+import MoneyIcon from '../components/reusable/icons/MoneyIcon';
+import ChartsIcon from '../components/reusable/icons/ChartsIcon';
const CarouselImage = ({ image, caption }) => {
return (
@@ -63,7 +65,18 @@ const HomePage = () => {
const { openModalWithCard, closeModal, isModalOpen, modalContent } =
useContext(ModalContext);
const { initialState, carouselImages, tiers } = pages;
-
+ const getIconForTitle = (title) => {
+ switch (title) {
+ case 'Deck Builder':
+ return ;
+ case 'Collection Tracker':
+ return ;
+ case 'Store':
+ return ;
+ default:
+ return null;
+ }
+ };
return (
//
@@ -164,9 +177,7 @@ const HomePage = () => {
title={tier.title}
subheader={tier.subheader}
titleTypographyProps={{ align: 'center' }}
- action={
- tier.title === 'Deck Builder' ? : null
- }
+ action={getIconForTitle(tier.title)}
subheaderTypographyProps={{
align: 'center',
}}
diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js
index cb276a6..039ca34 100644
--- a/src/pages/ProfilePage.js
+++ b/src/pages/ProfilePage.js
@@ -94,7 +94,7 @@ const ProfilePage = () => {
// };
const handleStopCronJob = () => {
- if (userId) {
+ if (userId && typeof userId === 'string') {
handleRequestCronStop(userId);
console.log('STOPPING CRON JOB');
}
diff --git a/src/pages/StorePage.js b/src/pages/StorePage.js
index 549f7b9..0929dc2 100644
--- a/src/pages/StorePage.js
+++ b/src/pages/StorePage.js
@@ -10,6 +10,7 @@ import ErrorIndicator from '../components/reusable/indicators/ErrorIndicator';
import { StoreBanner, StoreTitle } from './pageStyles/StyledComponents';
import { themeSettings } from '../assets/themeSettings';
import { useMode } from '../context/hooks/colormode';
+import { useUserContext } from '../context/UserContext/UserContext';
const SearchContainer = () => {
return (
@@ -88,18 +89,15 @@ HeroCenter3.defaultProps = {
};
const StorePage = () => {
- const [cookies] = useCookies(['user']);
-
const { theme } = useMode();
const { fetchUserCart, loading, error } = useCartStore();
const { searchData } = useCardStore();
-
- const userId = cookies?.user?.id;
-
+ const { user } = useUserContext();
+ const userId = user?.id;
useEffect(() => {
- if (userId) {
- fetchUserCart(userId).catch((err) =>
- console.error('Failed to get user cart', err)
+ if (userId && typeof userId === 'string') {
+ fetchUserCart(userId).catch((error) =>
+ console.error('Failed to get user cart', error)
);
console.log('(STORE PAGE) -- (SEARCHDATA):', searchData);
}
diff --git a/src/pages/pageStyles/StyledComponents.jsx b/src/pages/pageStyles/StyledComponents.jsx
index 8b3013e..dc8bb21 100644
--- a/src/pages/pageStyles/StyledComponents.jsx
+++ b/src/pages/pageStyles/StyledComponents.jsx
@@ -7,6 +7,27 @@ export const AppContainer = styled('div')(({ theme }) => ({
flexDirection: 'column',
height: '100vh',
}));
+const StyledContainer = styled('div')(({ theme }) => ({
+ display: 'flex',
+ flexDirection: 'column',
+ alignSelf: 'start',
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginLeft: theme.spacing(2),
+ marginRight: theme.spacing(2),
+ // minHeight: '250vh',
+ flexGrow: 1,
+ // minHeight: '100%',
+ background: '#333',
+ // backgroundColor: '#f1f1f1',
+ padding: theme.spacing(4),
+ width: '100%',
+}));
+
+export const CollectionContainer = ({ children }) => {
+ return {children} ;
+};
+
export const MainContainer = styled('div')(({ theme }) => ({
background: '#222', // Dark background
padding: theme.spacing(2),
@@ -19,10 +40,38 @@ export const MainContainer = styled('div')(({ theme }) => ({
boxShadow: theme.shadows[3],
borderRadius: theme.shape.borderRadius,
}));
+// extra padding | gap
+export const MainContainerb = styled('div')(({ theme }) => ({
+ background: '#222', // Dark background
+ padding: theme.spacing(2),
+ marginBottom: theme.spacing(2),
+ maxHeight: '100%',
+ width: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ boxShadow: theme.shadows[3],
+ borderRadius: theme.shape.borderRadius,
+}));
export const MainContainer2 = styled('div')(({ theme }) => ({
background: '#333', // Dark background
padding: theme.spacing(2),
marginBottom: theme.spacing(2),
+ gap: theme.spacing(2),
+ maxHeight: '100%',
+ width: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ boxShadow: theme.shadows[3],
+ borderRadius: theme.shape.borderRadius,
+}));
+// extra padding + gap
+export const MainContainer2b = styled('div')(({ theme }) => ({
+ background: '#333', // Dark background
+ marginBottom: theme.spacing(2),
+ padding: theme.spacing(2),
+ gap: theme.spacing(2),
maxHeight: '100%',
width: '100%',
display: 'flex',
@@ -174,9 +223,31 @@ export const CollectionBanner = styled(Box)(({ theme }) => ({
flexDirection: 'column',
alignItems: 'center',
padding: theme.spacing(2.5),
- backgroundColor: '#f7f7f7',
+ // height: '100%',
+ width: '100%',
+ backgroundColor: theme.palette.background.paper,
+ // backgroundColor: '#f7f7f7',
+}));
+
+export const CollectionContentsStyles = styled(Box)(({ theme }) => ({
+ display: 'flex',
+ justifyContent: 'center',
+ // margin: '0 auto',
+ // flexDirection: 'column',
+ // alignItems: 'center',
+ // padding: theme.spacing(2.5),
+ height: '100%',
+ width: '100%',
+ // background: '#333',
+
+ // backgroundColor: theme.palette.background.main,
+ // backgroundColor: '#f7f7f7',
}));
+export const CollectionContents = ({ children }) => {
+ return {children} ;
+};
+
export const StoreBanner = styled(Box)(({ theme }) => ({
display: 'flex',
maxWidth: '100%',