diff --git a/src/assets/currentlyUnused/CardChart.jsx b/src/assets/currentlyUnused/CardChart.jsx new file mode 100644 index 0000000..631be3c --- /dev/null +++ b/src/assets/currentlyUnused/CardChart.jsx @@ -0,0 +1,493 @@ +// // import React, { useState, useEffect, useMemo } from 'react'; +// // import { +// // Box, +// // Card, +// // CardActions, +// // CardContent, +// // CardHeader, +// // IconButton, +// // List, +// // ListItem, +// // Paper, +// // Typography, +// // useMediaQuery, +// // } from '@mui/material'; +// // import MoreVertIcon from '@mui/icons-material/MoreVert'; +// // import CardLinearChart from './CardLinearChart'; +// // import { ErrorBoundary, useMode, usePageContext } from '../context'; +// // import useCardCronJob from './useCardCronJob'; +// // import initialCardData from '../data/initialCardData'; +// // import { format } from 'date-fns'; +// // import LoadingCardAnimation from '../assets/animations/LoadingCardAnimation'; +// // import styled from 'styled-components'; +// // import MDButton from './REUSABLE_COMPONENTS/MDBUTTON'; +// // import { useLoading } from '../context/hooks/useLoading'; + +// // const ChartArea = styled(Box)(({ theme }) => ({ +// // width: '100%', +// // height: '100%', +// // padding: theme.spacing(2), +// // display: 'flex', +// // alignItems: 'center', +// // justifyContent: 'center', +// // border: '1px solid #000', +// // borderRadius: '5px', +// // })); +// // const SquareChartContainer = styled(Box)(({ theme }) => ({ +// // position: 'relative', +// // width: '100%', +// // paddingTop: '100%', +// // overflow: 'hidden', +// // '& > *': { +// // position: 'absolute', +// // top: 0, +// // left: 0, +// // right: 0, +// // bottom: 0, +// // }, +// // })); + +// // const CardChart = ({ cardData = initialCardData }) => { +// // // STYLING AND MEDIA QUERY HOOKS +// // const { theme } = useMode(); +// // const isLgUp = useMediaQuery(theme.breakpoints.up('lg')); +// // const [imageUrl, setImageUrl] = useState(null); +// // const { startUpdates, pauseUpdates, resetData } = +// // useCardCronJob(initialCardData); +// // const formatTimestamp = (timestamp) => +// // format(new Date(timestamp), "MMM do, yyyy 'at' HH:mm"); +// // const [chartDimensions, setChartDimensions] = useState({ +// // width: 0, +// // height: 0, +// // }); +// // const { returnDisplay } = usePageContext(); +// // const { isLoading } = useLoading(); +// // useEffect(() => { +// // if (cardData?.imageUrl) { +// // console.log('Setting image url', cardData?.imageUrl); +// // setImageUrl(cardData?.image); +// // } +// // }, [cardData?.imageUrl]); + +// // const nivoReadyData = useMemo( +// // () => [ +// // { +// // id: cardData?.name || 'default', +// // data: cardData?.dailyPriceHistory?.map(({ timestamp, num }) => ({ +// // x: timestamp, +// // y: num, +// // })), +// // }, +// // ], +// // [cardData] +// // ); +// // const renderLoadingAnimation = () => +// // isLgUp && ; +// // useEffect(() => { +// // if (isLoading('fetchCollections')) { +// // console.log('Fetching collections'); +// // } +// // }, [isLoading('fetchCollections')]); +// // useEffect(() => { +// // const updateDimensions = () => { +// // const width = window.innerWidth < 500 ? window.innerWidth : 500; +// // const height = 300; +// // setChartDimensions({ width, height }); +// // }; + +// // window.addEventListener('resize', updateDimensions); +// // updateDimensions(); + +// // return () => { +// // window.removeEventListener('resize', updateDimensions); +// // }; +// // }, []); +// // const renderHeaderWithAnimation = () => { +// // return ( +// // +// // +// // +// // +// // } +// // title="Card Cron Job Simulator" +// // subheader={cardData?.name || 'Card Name'} +// // sx={{ +// // padding: theme.spacing(1), +// // margin: theme.spacing(1), +// // }} +// // /> +// // {isLgUp && renderLoadingAnimation()} +// // +// // ); +// // }; +// // return ( +// // +// // +// // +// // +// // {renderHeaderWithAnimation()} +// // + +// // +// // +// // {isLoading('fetchCollections') ? ( +// // returnDisplay() +// // ) : ( +// // +// // +// // +// // )} +// // +// // +// // + +// // +// // +// // {['Start Updates', 'Pause Updates', 'Reset Data'].map( +// // (text, index) => ( +// // { +// // if (text === 'Start Updates') startUpdates(); +// // else if (text === 'Pause Updates') pauseUpdates(); +// // else if (text === 'Reset Data') resetData(); +// // }} +// // color="primary" +// // variant="contained" +// // sx={{ +// // color: theme.palette.backgroundA.contrastText, +// // background: theme.palette.backgroundF.darker, +// // borderColor: theme.palette.backgroundB.darkest, +// // borderWidth: 2, +// // mt: 'auto', +// // flexGrow: 1, +// // justifySelf: 'bottom', +// // bottom: 0, +// // width: '100%', +// // '&:hover': { +// // color: theme.palette.backgroundA.contrastTextC, +// // fontWeight: 'bold', +// // background: theme.palette.backgroundF.dark, +// // borderColor: theme.palette.backgroundB.darkest, +// // border: `1px solid ${theme.palette.backgroundB.darkest}`, +// // }, +// // }} +// // > +// // {text} +// // +// // ) +// // )} +// // +// // +// // +// // +// // {cardData?.dailyPriceHistory?.map((entry, index) => ( +// // +// // +// // Quantity: {cardData?.quantity} +// // +// // +// // Price: ${entry?.num} +// // +// // +// // {formatTimestamp(entry?.timestamp)} +// // +// // +// // ))} +// // +// // +// // +// // +// // +// // +// // ); +// // }; + +// // export default CardChart; +// import React, { useState, useEffect, useMemo } from 'react'; +// import { +// Box, +// Card, +// CardContent, +// CardHeader, +// IconButton, +// List, +// ListItem, +// Paper, +// Typography, +// useTheme, +// useMediaQuery, +// CardActions, +// } from '@mui/material'; +// import MoreVertIcon from '@mui/icons-material/MoreVert'; +// import CardLinearChart from './CardLinearChart'; +// import { ErrorBoundary, useMode } from '../context'; +// import useCardCronJob from './useCardCronJob'; +// import initialCardData from '../data/initialCardData'; +// import { format } from 'date-fns'; +// import LoadingCardAnimation from '../assets/animations/LoadingCardAnimation'; +// import MDButton from './REUSABLE_COMPONENTS/MDBUTTON'; +// import { useLoading } from '../context/hooks/useLoading'; +// import styled from 'styled-components'; +// import uniqueTheme from './REUSABLE_COMPONENTS/unique/uniqueTheme'; +// import SimpleButton from './REUSABLE_COMPONENTS/unique/SimpleButton'; + +// const ChartArea = styled(Box)(({ theme }) => ({ +// width: '100%', +// height: '100%', +// padding: theme.spacing(2), +// display: 'flex', +// alignItems: 'center', +// justifyContent: 'center', +// border: '1px solid #000', +// borderRadius: '5px', +// })); + +// const SquareChartContainer = styled(Box)({ +// position: 'relative', +// flex: 1, +// overflow: 'hidden', +// }); + +// const CardChart = () => { +// const { theme } = useMode(); +// const isMobileView = useMediaQuery(theme.breakpoints.down('sm')); +// const isLgUp = useMediaQuery(theme.breakpoints.up('lg')); +// const { startUpdates, pauseUpdates, resetData } = +// useCardCronJob(initialCardData); +// const [cardData, setCardData] = useState(initialCardData); +// const { isLoading } = useLoading(); + +// const getResponsiveDimensions = () => { +// return isMobileView +// ? { width: window.innerWidth / 2, height: window.innerHeight * 0.5 } +// : { width: 500, height: 300 }; +// }; + +// const [chartDimensions, setChartDimensions] = useState( +// getResponsiveDimensions() +// ); + +// useEffect(() => { +// const handleResize = () => { +// setChartDimensions(getResponsiveDimensions()); +// }; + +// window.addEventListener('resize', handleResize); +// return () => window.removeEventListener('resize', handleResize); +// }, [isMobileView]); + +// const nivoReadyData = useMemo( +// () => [ +// { +// id: cardData.name || 'default', +// data: cardData.dailyPriceHistory.map(({ timestamp, num }) => ({ +// x: format(new Date(timestamp), 'Pp'), +// y: num, +// })), +// }, +// ], +// [cardData] +// ); + +// return ( +// +// +// +// +// +// +// ) +// } +// title="Card Cron Job Simulator" +// subheader={cardData.name || 'Card Name'} +// /> +// {!isMobileView && isLgUp && isLoading('fetchCollections') && ( +// +// )} +// +// +// +// +// +// + +// {isMobileView ? ( +// +// +// +// {cardData.dailyPriceHistory.map((entry, index) => ( +// +// +// Quantity: {cardData.quantity} +// +// +// Price: ${entry.num} +// +// +// {format( +// new Date(entry.timestamp), +// "MMM do, yyyy 'at' HH:mm" +// )} +// +// +// ))} +// +// +// +// ) : ( +// +// {['Start Updates', 'Pause Updates', 'Reset Data'].map( +// (action, index) => ( +// { +// if (action === 'Start Updates') startUpdates(); +// else if (action === 'Pause Updates') pauseUpdates(); +// else resetData(); +// }} +// > +// {action} +// +// ) +// )} +// +// )} +// +// +// ); +// }; + +// export default CardChart; diff --git a/src/assets/currentlyUnused/CardLinearChart.jsx b/src/assets/currentlyUnused/CardLinearChart.jsx new file mode 100644 index 0000000..421d50e --- /dev/null +++ b/src/assets/currentlyUnused/CardLinearChart.jsx @@ -0,0 +1,85 @@ +// import { Box, Tooltip, Typography, useMediaQuery } from '@mui/material'; + +// import { ResponsiveLine } from '@nivo/line'; +// import { useCallback, useMemo, useState } from 'react'; +// import { useMode } from '../context'; +// import styled from 'styled-components'; +// const ChartContainer = styled(Box)(({ theme }) => ({ +// display: 'flex', +// alignItems: 'center', +// justifyContent: 'center', +// width: '100%', +// height: 'auto', +// [theme.breakpoints.down('sm')]: { +// width: '150%', // Adjust width for mobile screens +// height: '300px', // Adjust height for mobile screens +// // transform: 'translateX(10%)', // Shift the chart to the right by 50% +// }, +// })); + +// const parseDate = (dateString) => { +// const date = new Date(dateString); +// if (isNaN(date.getTime())) { +// console.error(`Invalid date: ${dateString}`); +// return null; // or a sensible default, or throw an error, depending on your needs +// } +// return date; +// }; +// export const useEventHandlers = () => { +// const [hoveredData, setHoveredData] = useState(null); +// const handleMouseMove = useCallback((point) => { +// setHoveredData(point ? { x: point.data.x, y: point.data.y } : null); +// }, []); +// const handleMouseLeave = useCallback(() => setHoveredData(null), []); +// return { hoveredData, handleMouseMove, handleMouseLeave }; +// }; + +// const CardLinearChart = ({ nivoReadyData, dimensions }) => { +// const { theme } = useMode(); +// const processedData = useMemo(() => { +// return nivoReadyData?.map((series) => ({ +// ...series, +// data: series?.data?.map((point) => ({ +// ...point, +// x: parseDate(point?.x) || point?.x, +// })), +// })); +// }, [nivoReadyData]); + +// const chartProps = useMemo( +// () => ({ +// data: processedData, +// margin: { top: 20, right: 20, bottom: 20, left: 35 }, +// xScale: { +// type: 'time', +// format: 'time:%Y-%m-%dT%H:%M:%S.%LZ', +// useUTC: false, +// precision: 'second', +// }, +// axisBottom: { +// tickRotation: 0, +// legend: 'Time', +// legendOffset: 36, +// legendPosition: 'middle', +// tickSize: 5, +// tickPadding: 5, +// tickValues: 'every 2 days', +// format: '%b %d', +// }, +// enableSlices: 'x', +// yScale: { type: 'linear', min: 'auto', max: 'auto' }, +// }), +// [nivoReadyData, processedData] +// ); + +// if (!processedData || !processedData?.length) { +// return No data available; +// } +// return ( +// +// +// +// ); +// }; + +// export default CardLinearChart; diff --git a/src/assets/currentlyUnused/DataTableBodyCell.jsx b/src/assets/currentlyUnused/DataTableBodyCell.jsx new file mode 100644 index 0000000..bb4dd82 --- /dev/null +++ b/src/assets/currentlyUnused/DataTableBodyCell.jsx @@ -0,0 +1,57 @@ +// // prop-types is a library for typechecking of props +// import PropTypes from 'prop-types'; +// import MDBox from '../../../REUSABLE_COMPONENTS/MDBOX'; +// import { useMode } from '../../../../context'; +// import { Box } from '@mui/system'; + +// function DataTableBodyCell({ noBorder, align, children }) { +// const { theme } = useMode(); +// return ( +// +// +// {children} +// +// +// ); +// } + +// // Setting default values for the props of DataTableBodyCell +// DataTableBodyCell.defaultProps = { +// noBorder: false, +// align: 'left', +// }; + +// // Typechecking props for the DataTableBodyCell +// DataTableBodyCell.propTypes = { +// children: PropTypes.node.isRequired, +// noBorder: PropTypes.bool, +// align: PropTypes.oneOf(['left', 'right', 'center']), +// }; + +// export default DataTableBodyCell; diff --git a/src/assets/currentlyUnused/DataTableHeadCell.jsx b/src/assets/currentlyUnused/DataTableHeadCell.jsx new file mode 100644 index 0000000..d67a02d --- /dev/null +++ b/src/assets/currentlyUnused/DataTableHeadCell.jsx @@ -0,0 +1,113 @@ +// import { useMemo } from 'react'; +// import PropTypes from 'prop-types'; +// import { TableRow, Checkbox, Icon } from '@mui/material'; +// import MDBox from '../../../REUSABLE_COMPONENTS/MDBOX'; +// import MDTypography from '../../../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; +// import { useMode } from '../../../../context'; +// import FlexBetween from '../../../REUSABLE_COMPONENTS/FlexBetween'; + +// const DataTableHeadCell = ({ headerGroups, isSorted, setSortedValue }) => { +// const { theme } = useMode(); + +// const renderCellContent = (column, idx) => { +// const sorted = setSortedValue(column, isSorted); +// const shouldShowIcons = column.showIcons; + +// return ( +// +// +// +// {column.render('Header')} +// +// {shouldShowIcons && sorted && ( +// +// +// arrow_drop_up +// +// +// arrow_drop_down +// +// +// )} +// +// +// ); +// }; + +// return useMemo( +// () => ( +// <> +// {headerGroups.map((headerGroup, key) => ( +// +// {headerGroup.headers.map(renderCellContent)} +// +// ))} +// +// ), +// [ +// headerGroups, +// isSorted, +// setSortedValue, +// theme.palette.divider, +// theme.typography.fontWeightMedium, +// ] +// ); +// }; + +// DataTableHeadCell.propTypes = { +// headerGroups: PropTypes.array.isRequired, +// isSorted: PropTypes.bool.isRequired, +// setSortedValue: PropTypes.func.isRequired, +// }; + +// export default DataTableHeadCell; diff --git a/src/assets/currentlyUnused/DeckEditor.jsx b/src/assets/currentlyUnused/DeckEditor.jsx new file mode 100644 index 0000000..ddda4d6 --- /dev/null +++ b/src/assets/currentlyUnused/DeckEditor.jsx @@ -0,0 +1,17 @@ +// import React, { useState, useEffect } from 'react'; +// import { Paper, Typography, Box, useMediaQuery } from '@mui/material'; +// import { useMode } from '../../context'; +// import DeckForm from '../../components/forms/DeckForm'; + +// const DeckEditor = ({ deck, onClose }) => { +// const { theme } = useMode(); +// const isMobile = useMediaQuery(theme.breakpoints.down('sm')); + +// return ( +// +// {/* */} +// +// ); +// }; + +// export default DeckEditor; diff --git a/src/assets/currentlyUnused/index.jsx b/src/assets/currentlyUnused/index.jsx new file mode 100644 index 0000000..5dea71e --- /dev/null +++ b/src/assets/currentlyUnused/index.jsx @@ -0,0 +1,298 @@ +// /* eslint-disable @typescript-eslint/no-empty-function */ +// import { useMemo, useEffect, useState } from 'react'; +// import PropTypes from 'prop-types'; +// import { +// useTable, +// usePagination, +// useGlobalFilter, +// useAsyncDebounce, +// useSortBy, +// useRowSelect, +// } from 'react-table'; +// // @mui material components +// import Table from '@mui/material/Table'; +// import TableContainer from '@mui/material/TableContainer'; +// import TableRow from '@mui/material/TableRow'; +// import DataTableBodyCell from './DataTableBodyCell'; +// import { Box, Button, Checkbox, Grid, Paper, TableBody } from '@mui/material'; +// import PaginationComponent from './PaginationComponent'; +// import OptionsComponent from '../../../../components/forms/OptionsComponent'; +// import GenericActionButtons from '../../../../components/buttons/actionButtons/GenericActionButtons'; +// import { useMode } from '../../../../context'; +// import DataTableHeadCell from './DataTableHeadCell'; +// import FlexBetween from '../../../REUSABLE_COMPONENTS/FlexBetween'; +// const setSortedValue = (column, isSorted) => { +// let sortedValue; + +// if (isSorted && column.isSorted) { +// sortedValue = column.isSortedDesc ? 'desc' : 'asce'; +// } else if (isSorted) { +// sortedValue = 'none'; +// } else { +// sortedValue = false; +// } + +// return sortedValue; +// }; +// function DataTable({ +// entriesPerPage, +// canSearch, +// showTotalEntries, +// table, +// pagination, +// isSorted, +// noEndBorder, +// tableSize, +// }) { +// const { theme } = useMode(); +// const [showTotalPrice, setShowTotalPrice] = useState(window.innerWidth > 800); +// const [showSelection, setShowSelection] = useState(window.innerWidth > 500); +// useEffect(() => { +// const handleResize = () => { +// setShowTotalPrice(window.innerWidth > 800); +// setShowSelection(window.innerWidth > 500); +// }; +// window.addEventListener('resize', handleResize); +// return () => { +// window.removeEventListener('resize', handleResize); +// }; +// }, []); + +// const data = useMemo(() => table.data, [table.data]); +// const columns = useMemo(() => { +// let baseColumns = [ +// showSelection && { +// id: 'selection', +// showIcons: false, +// Header: ({ getToggleAllRowsSelectedProps }) => ( +// +// ), +// Cell: ({ row }) => , +// // Apply a fixed width to the checkbox column +// // width: 30, // Adjust the width as needed +// // minWidth: 30, // Ensure it doesn't get smaller than the set width +// // maxWidth: 30, // Ensure it doesn't get larger than the set width +// }, +// { Header: 'Name', accessor: 'name' }, +// { Header: 'Price', accessor: 'price' }, + +// { Header: 'Quantity', accessor: 'quantity', showIcons: false }, +// { +// id: 'action', +// Header: 'Action', +// accessor: 'action', +// showIcons: false, + +// Cell: ({ value }) => ( +// console.log('clicked')} +// onSuccess={() => console.log('success')} +// onFailure={(error) => console.log(error)} +// page={'Collection'} +// cardSize={'small'} +// variant="data-table" +// /> +// ), +// }, +// ]; +// if (tableSize !== 'large' && showTotalPrice) { +// baseColumns.push({ +// Header: 'Total Price', +// accessor: 'tPrice', +// }); +// } +// // Filter out any falsey values to remove the conditionally included columns when not shown +// return baseColumns.filter(Boolean); +// }, [showTotalPrice, showSelection, tableSize]); + +// const defaultPageSize = useMemo( +// () => entriesPerPage.defaultValue, +// [entriesPerPage] +// ); +// const pageSizeOptions = useMemo( +// () => entriesPerPage.entries, +// [entriesPerPage] +// ); + +// const { +// getTableProps, +// getTableBodyProps, +// headerGroups, +// prepareRow, +// page, +// canPreviousPage, +// canNextPage, +// pageOptions, +// gotoPage, +// nextPage, +// previousPage, +// setPageSize, +// setGlobalFilter, +// selectedFlatRows, +// toggleAllRowsSelected, +// state: { pageIndex, pageSize, globalFilter }, +// } = useTable( +// { +// columns, +// data, +// initialState: { pageIndex: 0, pageSize: entriesPerPage.defaultValue }, +// }, +// useGlobalFilter, +// useSortBy, +// usePagination, +// useRowSelect +// ); +// const [search, setSearch] = useState(globalFilter); + +// useEffect(() => { +// setGlobalFilter(search || undefined); +// }, [search, setGlobalFilter]); + +// useEffect(() => { +// setPageSize(defaultPageSize); +// }, [defaultPageSize, setPageSize]); + +// const handleSelectAllClick = (event) => { +// toggleAllRowsSelected(event.target.checked); +// }; + +// let entriesEnd; +// if (pageIndex === 0) { +// entriesEnd = pageSize; +// } else if (pageIndex === pageOptions.length - 1) { +// entriesEnd = data.length; +// } else { +// entriesEnd = pageSize * (pageIndex + 1); +// } + +// return ( +// +// +// {/* Search and Entries Per Page Options */} +// setSearch(e.target.value)} +// pageSize={pageSize} +// setPageSize={(size) => setPageSize(Number(size))} +// pageOptions={pageSizeOptions} +// /> +// {/* Table */} +// +// +// +// {}} +// headerGroups={headerGroups} +// isSorted={isSorted} +// setSortedValue={setSortedValue} +// /> +// +// {/* Table Body */} +// +// {page.map((row, key) => { +// prepareRow(row); +// return ( +// +// {' '} +// +// {row.cells.map((cell, idx) => ( +// +// {cell.render('Cell')} +// +// ))} +// +// +// ); +// })} +// +//
+//
+// {/* Pagination */} +// +// +// +//
+//
+// ); +// } + +// DataTable.propTypes = { +// entriesPerPage: PropTypes.shape({ +// defaultValue: PropTypes.number, +// entries: PropTypes.arrayOf(PropTypes.number), +// }).isRequired, +// canSearch: PropTypes.bool, +// showTotalEntries: PropTypes.bool, +// table: PropTypes.shape({ +// columns: PropTypes.array.isRequired, +// data: PropTypes.array.isRequired, +// }).isRequired, +// isSorted: PropTypes.bool, +// noEndBorder: PropTypes.bool, +// }; +// DataTable.defaultProps = { +// canSearch: false, +// showTotalEntries: true, +// isSorted: true, +// noEndBorder: false, +// }; + +// export default DataTable; diff --git a/src/components/buttons/actionButtons/ActionButton.jsx b/src/components/buttons/actionButtons/ActionButton.jsx index 148b7e1..1a1d779 100644 --- a/src/components/buttons/actionButtons/ActionButton.jsx +++ b/src/components/buttons/actionButtons/ActionButton.jsx @@ -32,11 +32,14 @@ const ActionButton = ({ labelValue, actionType, card, + variant, }) => { const { theme } = useMode(); const { isLoading } = useLoading(); + const adjustedButtonSize = variant === 'data-table' ? 'small' : buttonSize; + const { buttonLabel, buttonVariant } = getLabelAndVariant( - buttonSize, + adjustedButtonSize, labelValue, actionType ); @@ -54,8 +57,8 @@ const ActionButton = ({ return ( diff --git a/src/components/buttons/actionButtons/GenericActionButtons.jsx b/src/components/buttons/actionButtons/GenericActionButtons.jsx index 5700053..48e87ce 100644 --- a/src/components/buttons/actionButtons/GenericActionButtons.jsx +++ b/src/components/buttons/actionButtons/GenericActionButtons.jsx @@ -27,6 +27,7 @@ const GenericActionButtons = ({ onFailure, page, cardSize = 'md', + datatable = false, }) => { const { enqueueSnackbar } = useSnackbar(); // Add this line to use Notistack const { addOneToCollection, removeOneFromCollection } = @@ -81,6 +82,8 @@ const GenericActionButtons = ({ context={context} page={page} handleCardAction={() => handleAction('add', card, context)} + datatable={datatable} + variant={datatable ? 'data-table' : 'card'} /> ); }; @@ -92,6 +95,7 @@ const ActionButtons = ({ page, handleCardAction, variant, + datatable, }) => { const labelValue = typeof context === 'string' ? context : context?.pageContext; @@ -109,51 +113,48 @@ const ActionButtons = ({ height: '100%', }} > - - {variant !== 'data-table' && ( + }, + }} + > - )} - + + )} + @@ -162,12 +163,16 @@ const ActionButtons = ({ buttonSize={buttonSize} handleCardAction={handleCardAction} labelValue={'add'} // Assuming 'context' is intended to be used as 'labelValue' + variant={variant} + actionType="add" /> diff --git a/src/components/forms/reusable/RCZodForm.jsx b/src/components/forms/reusable/RCZodForm.jsx index fc03843..65930e0 100644 --- a/src/components/forms/reusable/RCZodForm.jsx +++ b/src/components/forms/reusable/RCZodForm.jsx @@ -7,6 +7,7 @@ import { Select, MenuItem, Chip, + useMediaQuery, } from '@mui/material'; import FormField from './FormField'; import ReusableLoadingButton from '../../buttons/other/ReusableLoadingButton'; @@ -26,6 +27,8 @@ const RCZodForm = ({ additionalData, }) => { const { theme } = useMode(); + const isMobile = useMediaQuery(theme.breakpoints.down('sm')); + const { formMethods, onSubmit, @@ -34,27 +37,8 @@ const RCZodForm = ({ currentForm, currentFormSchema, formState: { errors, isSubmitting }, - // getValues, - // handleSearchTermChange, } = useFormContext(); - // useEffect(() => { - // setFormSchema(schemaName); - // }, [setFormSchema, schemaName]); - // useEffect(() => { - // setFormSchema(schemaName); - // if (initialValues) { - // console.log('initialValues:', initialValues); - // formMethods.reset(initialValues); - // } - // }, [setFormSchema, schemaName, formMethods, initialValues]); - // useEffect(() => { - // // console.log('initialValues:', initialValues); - // console.log('SCHEMA NAME CHANGED TO:', schemaName); - // setFormSchema(schemaName); - // // When currentForm or schemaName changes, reset form with new initialValues or empty values - // formMethods.reset(initialValues || {}); - // }, [setFormSchema, schemaName, formMethods, initialValues]); const onFormSubmit = (data) => { onSubmit(data, additionalData); }; @@ -90,6 +74,9 @@ const RCZodForm = ({ '& .MuiSvgIcon-root': { color: theme.palette.text.primary, }, + ...(isMobile && { + fontSize: '0.875rem', // Adjust font size for mobile + }), }} > {field?.options?.map((option) => ( @@ -163,6 +150,11 @@ const RCZodForm = ({ component="form" onSubmit={formMethods.handleSubmit(onFormSubmit)} theme={theme} + sx={{ + ...(isMobile && { + padding: theme.spacing(3), // Reduce padding on mobile + }), + }} > {fields?.map(renderField)} } fullWidth + sx={{ + ...(isMobile && { + fontSize: '0.75rem', // Adjust button font size for mobile + }), + }} /> {additionalButtons && additionalButtons?.map((button, index) => ( diff --git a/src/layout/collection/collectionGrids/cards-datatable/PaginationComponent.jsx b/src/components/forms/search/PaginationComponent.jsx similarity index 89% rename from src/layout/collection/collectionGrids/cards-datatable/PaginationComponent.jsx rename to src/components/forms/search/PaginationComponent.jsx index c603d70..dcd69be 100644 --- a/src/layout/collection/collectionGrids/cards-datatable/PaginationComponent.jsx +++ b/src/components/forms/search/PaginationComponent.jsx @@ -1,10 +1,10 @@ // PaginationComponent.jsx import React from 'react'; -import MDPagination from '../../../REUSABLE_COMPONENTS/MDPAGINATION'; -import MDBox from '../../../REUSABLE_COMPONENTS/MDBOX'; -import MDInput from '../../../REUSABLE_COMPONENTS/MDINPUT'; +import MDPagination from '../../../layout/REUSABLE_COMPONENTS/MDPAGINATION'; +import MDBox from '../../../layout/REUSABLE_COMPONENTS/MDBOX'; +import MDInput from '../../../layout/REUSABLE_COMPONENTS/MDINPUT'; import Icon from '@mui/material/Icon'; -import MDTypography from '../../../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; +import MDTypography from '../../../layout/REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; const PaginationComponent = ({ pageOptions, diff --git a/src/components/forms/search/SearchComponent.jsx b/src/components/forms/search/SearchComponent.jsx index 678a44a..7290cbf 100644 --- a/src/components/forms/search/SearchComponent.jsx +++ b/src/components/forms/search/SearchComponent.jsx @@ -9,6 +9,7 @@ import { Menu, MenuItem, Paper, + useMediaQuery, } from '@mui/material'; import { useGetSearchData } from '../../../context/hooks/useGetSearchData'; import SearchResults from './SearchResults'; @@ -24,6 +25,8 @@ import SimpleCard from '../../../layout/REUSABLE_COMPONENTS/unique/SimpleCard'; import uniqueTheme from '../../../layout/REUSABLE_COMPONENTS/unique/uniqueTheme'; const SearchComponent = (pageContext) => { const { theme } = useMode(); + const isMobile = useMediaQuery(theme.breakpoints.down('sm')); + const itemsPerPage = 12; const [searchBarFocused, setSearchBarFocused] = useState(false); const { loadingSearchResults, searchSettings, setSearchSettings } = @@ -51,6 +54,11 @@ const SearchComponent = (pageContext) => { theme={uniqueTheme} hasTitle={false} isSearchFormHeader={true} + sx={{ + elevation: isMobile ? 0 : 3, // Remove elevation on mobile + p: isMobile ? 0 : theme.spacing(2), // Remove padding on mobile + boxShadow: isMobile ? 'none' : '0px 4px 4px rgba(0, 0, 0, 0.25)', + }} > { width: '90%', mx: 'auto', border: 'none', + ...(isMobile && { + // flexDirection: 'column', // Stack elements vertically on mobile + p: theme.spacing(2), + }), }} > { fontWeight: 'bold', color: theme.palette.backgroundB.dark, textTransform: 'uppercase', + marginBottom: isMobile ? theme.spacing(2) : 0, // Add bottom margin on mobile }} > Search Cards diff --git a/src/components/forms/search/SearchResults.jsx b/src/components/forms/search/SearchResults.jsx index 6be7eda..69c77a9 100644 --- a/src/components/forms/search/SearchResults.jsx +++ b/src/components/forms/search/SearchResults.jsx @@ -2,9 +2,9 @@ import React, { useMemo } from 'react'; import { Box, Grid } from '@mui/material'; import useGridItems from '../../../context/hooks/useGridItems'; import usePagination from '../../../context/hooks/usePagination'; -import PaginationComponent from '../../../layout/collection/collectionGrids/cards-datatable/PaginationComponent'; import LoadingIndicator from '../../../layout/LoadingIndicator'; import MDBox from '../../../layout/REUSABLE_COMPONENTS/MDBOX'; +import PaginationComponent from './PaginationComponent'; const SearchResults = ({ uniqueCards, diff --git a/src/context/MAIN_CONTEXT/DeckContext/useDeckManager.jsx b/src/context/MAIN_CONTEXT/DeckContext/useDeckManager.jsx index eb799ab..fd35e4b 100644 --- a/src/context/MAIN_CONTEXT/DeckContext/useDeckManager.jsx +++ b/src/context/MAIN_CONTEXT/DeckContext/useDeckManager.jsx @@ -166,6 +166,8 @@ const useDeckManager = () => { const existingCard = deck?.cards?.find( (card) => card.id === newCards[0].id ); + console.log('DECK', selectedDeck); + console.log('NEWW CARDS', newCards); const options = { beforeAction: () => { @@ -190,7 +192,7 @@ const useDeckManager = () => { const cardParams = { cards: [newCards] }; const fullParams = { ...cardParams, type: 'increment' }; performAction( - createApiUrl(`${selectedDeck?._id}/cards/update`), + createApiUrl(`${selectedDeckId}/cards/update`), 'PUT', fullParams, 'addCardsToDeck', @@ -200,10 +202,10 @@ const useDeckManager = () => { // ADD NEW CARD const cardParams = { cards: newCards }; const fullParams = { ...cardParams, type: 'addNew' }; - addCardToSelectedDeck(newCards); + // addCardToSelectedDeck(newCards); performAction( - createApiUrl(`${selectedDeck?._id}/cards/add`), + createApiUrl(`${selectedDeckId}/cards/add`), 'POST', fullParams, 'addCardsToDeck', @@ -212,7 +214,13 @@ const useDeckManager = () => { // updateSelectedDeck(cardParams); } }, - [performAction, createApiUrl, selectedDeckId, selectedDeck?._id] + [ + performAction, + createApiUrl, + selectedDeck, + selectedDeckId, + selectedDeck?._id, + ] ); const removeCardsFromDeck = useCallback( diff --git a/src/context/MAIN_CONTEXT/DeckContext/useSelectedDeck.jsx b/src/context/MAIN_CONTEXT/DeckContext/useSelectedDeck.jsx index a22c1a2..30f714b 100644 --- a/src/context/MAIN_CONTEXT/DeckContext/useSelectedDeck.jsx +++ b/src/context/MAIN_CONTEXT/DeckContext/useSelectedDeck.jsx @@ -19,10 +19,18 @@ const useSelectedDeck = () => { deckHasBeenSelected: false, deckHasBeenUpdated: false, }); + const [selectedDeckId, setSelectedDeckId] = useState(null); + // const selectedDeckId = useState(decks?.selectedId)[0]; + // const selectedDeck = decks.byId[selectedDeckId] || DEFAULT_DECK; + const prevSelectedDeckIdRef = useRef(null); - const selectedDeckId = useState(decks?.selectedId)[0]; - const selectedDeck = decks.byId[selectedDeckId] || DEFAULT_DECK; - + useEffect(() => { + prevSelectedDeckIdRef.current = selectedDeckId; + }, [selectedDeckId]); + const getSelectedDeck = useMemo( + () => decks.byId[decks?.selectedId], + [decks.byId, decks.selectedId] + ); const updateDeck = useCallback( (updatedDeck, deckId = selectedDeckId) => { setDecks((prev) => ({ @@ -36,7 +44,6 @@ const useSelectedDeck = () => { }, [setDecks, selectedDeckId] ); - const updateMultipleDecks = useCallback( (decksArray) => { setDecks((prev) => { @@ -61,16 +68,17 @@ const useSelectedDeck = () => { const handleSelectDeck = useCallback( (deck) => { const deckId = deck?._id; + console.log('SELECTED DECK ID', deckId); setDecks((prev) => ({ ...prev, selectedId: deckId, selectedDeck: deck, selectedDeckCards: deck?.cards, deckHasBeenSelected: true, - showDecks: true, + showDecks: !prev.showDecks, })); }, - [setDecks] + [setDecks, selectedDeckId] ); const addNewDeck = useCallback( (newDeck) => { @@ -99,7 +107,6 @@ const useSelectedDeck = () => { }, [setDecks] ); - const addCardToSelectedDeck = useCallback( (card) => { if (!selectedDeckId) return; @@ -111,12 +118,19 @@ const useSelectedDeck = () => { }, [decks.byId, selectedDeckId, updateDeck] ); + const prevDecksRef = useRef(); + useEffect(() => { + if (prevDecksRef.current) { + console.log('Collections data updated:', decks); + } + prevDecksRef.current = decks; + }, [decks]); // Dependency array ensures this runs only when collections change return { - selectedDeckId, - selectedDeck, + selectedDeckId: decks.selectedId, + selectedDeck: getSelectedDeck, allDecks: Object.values(decks.byId), - showDecks: decks.showDecks, + showDecks: !!decks.showDecks, deckHasBeenSelected: decks.deckHasBeenSelected, deckHasBeenUpdated: decks.deckHasBeenUpdated, diff --git a/src/context/MISC_CONTEXT/AppContext/AppContextProvider.jsx b/src/context/MISC_CONTEXT/AppContext/AppContextProvider.jsx index 1031e32..82a3b0f 100644 --- a/src/context/MISC_CONTEXT/AppContext/AppContextProvider.jsx +++ b/src/context/MISC_CONTEXT/AppContext/AppContextProvider.jsx @@ -42,20 +42,25 @@ export const AppContextProvider = ({ children }) => { (total, collection) => total + collection?.totalPrice, 0 ), + numCardsCollected: allCollections?.reduce((total, collection) => { + const collectionTotal = collection?.cards?.reduce( + (collectionTotal, card) => { + // Use the quantity property of each card, defaulting to 1 if not available + return collectionTotal + (card?.quantity || 1); + }, + 0 + ); + return total + collectionTotal; + }, 0), numCollections: allIds?.length || 0, topFiveCards: cardsWithQuantities ?.sort((a, b) => b.price - a.price) .slice(0, 5), - numCardsCollected: cardsWithQuantities?.length || 0, }; setCollectionMetaData(metaData); }, []); - useEffect(() => { - compileCollectionMetaData(); - }, [compileCollectionMetaData]); // Re-calculate metadata when allCollections changes - const isCardInContext = useCallback( (card) => { const cardsList = { @@ -102,6 +107,10 @@ export const AppContextProvider = ({ children }) => { useEffect(() => { compileCardsWithQuantities(); }, []); // Dependency array based on when you want to recalculate + useEffect(() => { + compileCollectionMetaData(); + }, [compileCollectionMetaData]); // Re-calculate metadata when allCollections changes + const appContextValues = useMemo( () => ({ Deck, diff --git a/src/context/constants.jsx b/src/context/constants.jsx index 3a99761..b511d2a 100644 --- a/src/context/constants.jsx +++ b/src/context/constants.jsx @@ -282,13 +282,7 @@ const defaultCollection = { userId: '', allXYValues: [], }, - nivoChartData: [ - { - id: '', - color: '', - data: [{ x: new Date(), y: 0 }], - }, - ], + nivoChartData: new Map(), newNivoChartData: [ { id: '', diff --git a/src/context/hooks/useGridItems.jsx b/src/context/hooks/useGridItems.jsx index aff2361..d562efe 100644 --- a/src/context/hooks/useGridItems.jsx +++ b/src/context/hooks/useGridItems.jsx @@ -33,7 +33,7 @@ const useGridItems = ({ )?.map((card, index) => ( ({ -// width: '100%', -// height: '100%', -// padding: theme.spacing(2), -// display: 'flex', -// alignItems: 'center', -// justifyContent: 'center', -// border: '1px solid #000', -// borderRadius: '5px', -// })); -// const SquareChartContainer = styled(Box)(({ theme }) => ({ -// position: 'relative', -// width: '100%', -// paddingTop: '100%', -// overflow: 'hidden', -// '& > *': { -// position: 'absolute', -// top: 0, -// left: 0, -// right: 0, -// bottom: 0, -// }, -// })); - -// const CardChart = ({ cardData = initialCardData }) => { -// // STYLING AND MEDIA QUERY HOOKS -// const { theme } = useMode(); -// const isLgUp = useMediaQuery(theme.breakpoints.up('lg')); -// const [imageUrl, setImageUrl] = useState(null); -// const { startUpdates, pauseUpdates, resetData } = -// useCardCronJob(initialCardData); -// const formatTimestamp = (timestamp) => -// format(new Date(timestamp), "MMM do, yyyy 'at' HH:mm"); -// const [chartDimensions, setChartDimensions] = useState({ -// width: 0, -// height: 0, -// }); -// const { returnDisplay } = usePageContext(); -// const { isLoading } = useLoading(); -// useEffect(() => { -// if (cardData?.imageUrl) { -// console.log('Setting image url', cardData?.imageUrl); -// setImageUrl(cardData?.image); -// } -// }, [cardData?.imageUrl]); - -// const nivoReadyData = useMemo( -// () => [ -// { -// id: cardData?.name || 'default', -// data: cardData?.dailyPriceHistory?.map(({ timestamp, num }) => ({ -// x: timestamp, -// y: num, -// })), -// }, -// ], -// [cardData] -// ); -// const renderLoadingAnimation = () => -// isLgUp && ; -// useEffect(() => { -// if (isLoading('fetchCollections')) { -// console.log('Fetching collections'); -// } -// }, [isLoading('fetchCollections')]); -// useEffect(() => { -// const updateDimensions = () => { -// const width = window.innerWidth < 500 ? window.innerWidth : 500; -// const height = 300; -// setChartDimensions({ width, height }); -// }; - -// window.addEventListener('resize', updateDimensions); -// updateDimensions(); - -// return () => { -// window.removeEventListener('resize', updateDimensions); -// }; -// }, []); -// const renderHeaderWithAnimation = () => { -// return ( -// -// -// -// -// } -// title="Card Cron Job Simulator" -// subheader={cardData?.name || 'Card Name'} -// sx={{ -// padding: theme.spacing(1), -// margin: theme.spacing(1), -// }} -// /> -// {isLgUp && renderLoadingAnimation()} -// -// ); -// }; -// return ( -// -// -// -// -// {renderHeaderWithAnimation()} -// - -// -// -// {isLoading('fetchCollections') ? ( -// returnDisplay() -// ) : ( -// -// -// -// )} -// -// -// - -// -// -// {['Start Updates', 'Pause Updates', 'Reset Data'].map( -// (text, index) => ( -// { -// if (text === 'Start Updates') startUpdates(); -// else if (text === 'Pause Updates') pauseUpdates(); -// else if (text === 'Reset Data') resetData(); -// }} -// color="primary" -// variant="contained" -// sx={{ -// color: theme.palette.backgroundA.contrastText, -// background: theme.palette.backgroundF.darker, -// borderColor: theme.palette.backgroundB.darkest, -// borderWidth: 2, -// mt: 'auto', -// flexGrow: 1, -// justifySelf: 'bottom', -// bottom: 0, -// width: '100%', -// '&:hover': { -// color: theme.palette.backgroundA.contrastTextC, -// fontWeight: 'bold', -// background: theme.palette.backgroundF.dark, -// borderColor: theme.palette.backgroundB.darkest, -// border: `1px solid ${theme.palette.backgroundB.darkest}`, -// }, -// }} -// > -// {text} -// -// ) -// )} -// -// -// -// -// {cardData?.dailyPriceHistory?.map((entry, index) => ( -// -// -// Quantity: {cardData?.quantity} -// -// -// Price: ${entry?.num} -// -// -// {formatTimestamp(entry?.timestamp)} -// -// -// ))} -// -// -// -// -// -// -// ); -// }; - -// export default CardChart; -import React, { useState, useEffect, useMemo } from 'react'; -import { - Box, - Card, - CardContent, - CardHeader, - IconButton, - List, - ListItem, - Paper, - Typography, - useTheme, - useMediaQuery, - CardActions, -} from '@mui/material'; -import MoreVertIcon from '@mui/icons-material/MoreVert'; -import CardLinearChart from './CardLinearChart'; -import { ErrorBoundary, useMode } from '../context'; -import useCardCronJob from './useCardCronJob'; -import initialCardData from '../data/initialCardData'; -import { format } from 'date-fns'; -import LoadingCardAnimation from '../assets/animations/LoadingCardAnimation'; -import MDButton from './REUSABLE_COMPONENTS/MDBUTTON'; -import { useLoading } from '../context/hooks/useLoading'; -import styled from 'styled-components'; -import uniqueTheme from './REUSABLE_COMPONENTS/unique/uniqueTheme'; -import SimpleButton from './REUSABLE_COMPONENTS/unique/SimpleButton'; - -const ChartArea = styled(Box)(({ theme }) => ({ - width: '100%', - height: '100%', - padding: theme.spacing(2), - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - border: '1px solid #000', - borderRadius: '5px', -})); - -const SquareChartContainer = styled(Box)({ - position: 'relative', - flex: 1, - overflow: 'hidden', -}); - -const CardChart = () => { - const { theme } = useMode(); - const isMobileView = useMediaQuery(theme.breakpoints.down('sm')); - const isLgUp = useMediaQuery(theme.breakpoints.up('lg')); - const { startUpdates, pauseUpdates, resetData } = - useCardCronJob(initialCardData); - const [cardData, setCardData] = useState(initialCardData); - const { isLoading } = useLoading(); - - const getResponsiveDimensions = () => { - return isMobileView - ? { width: window.innerWidth / 2, height: window.innerHeight * 0.5 } - : { width: 500, height: 300 }; - }; - - const [chartDimensions, setChartDimensions] = useState( - getResponsiveDimensions() - ); - - useEffect(() => { - const handleResize = () => { - setChartDimensions(getResponsiveDimensions()); - }; - - window.addEventListener('resize', handleResize); - return () => window.removeEventListener('resize', handleResize); - }, [isMobileView]); - - const nivoReadyData = useMemo( - () => [ - { - id: cardData.name || 'default', - data: cardData.dailyPriceHistory.map(({ timestamp, num }) => ({ - x: format(new Date(timestamp), 'Pp'), - y: num, - })), - }, - ], - [cardData] - ); - - return ( - - - - - - - ) - } - title="Card Cron Job Simulator" - subheader={cardData.name || 'Card Name'} - /> - {!isMobileView && isLgUp && isLoading('fetchCollections') && ( - - )} - - - - - - - - {isMobileView ? ( - - - - {cardData.dailyPriceHistory.map((entry, index) => ( - - - Quantity: {cardData.quantity} - - - Price: ${entry.num} - - - {format( - new Date(entry.timestamp), - "MMM do, yyyy 'at' HH:mm" - )} - - - ))} - - - - ) : ( - - {['Start Updates', 'Pause Updates', 'Reset Data'].map( - (action, index) => ( - { - if (action === 'Start Updates') startUpdates(); - else if (action === 'Pause Updates') pauseUpdates(); - else resetData(); - }} - > - {action} - - ) - )} - - )} - - - ); -}; - -export default CardChart; diff --git a/src/layout/CardLinearChart.jsx b/src/layout/CardLinearChart.jsx deleted file mode 100644 index 006513d..0000000 --- a/src/layout/CardLinearChart.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import { Box, Tooltip, Typography, useMediaQuery } from '@mui/material'; - -import { ResponsiveLine } from '@nivo/line'; -import { useCallback, useMemo, useState } from 'react'; -import { useMode } from '../context'; -import styled from 'styled-components'; -const ChartContainer = styled(Box)(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - width: '100%', - height: 'auto', - [theme.breakpoints.down('sm')]: { - width: '150%', // Adjust width for mobile screens - height: '300px', // Adjust height for mobile screens - // transform: 'translateX(10%)', // Shift the chart to the right by 50% - }, -})); - -const parseDate = (dateString) => { - const date = new Date(dateString); - if (isNaN(date.getTime())) { - console.error(`Invalid date: ${dateString}`); - return null; // or a sensible default, or throw an error, depending on your needs - } - return date; -}; -export const useEventHandlers = () => { - const [hoveredData, setHoveredData] = useState(null); - const handleMouseMove = useCallback((point) => { - setHoveredData(point ? { x: point.data.x, y: point.data.y } : null); - }, []); - const handleMouseLeave = useCallback(() => setHoveredData(null), []); - return { hoveredData, handleMouseMove, handleMouseLeave }; -}; - -const CardLinearChart = ({ nivoReadyData, dimensions }) => { - const { theme } = useMode(); - const processedData = useMemo(() => { - return nivoReadyData?.map((series) => ({ - ...series, - data: series?.data?.map((point) => ({ - ...point, - x: parseDate(point?.x) || point?.x, - })), - })); - }, [nivoReadyData]); - - const chartProps = useMemo( - () => ({ - data: processedData, - margin: { top: 20, right: 20, bottom: 20, left: 35 }, - xScale: { - type: 'time', - format: 'time:%Y-%m-%dT%H:%M:%S.%LZ', - useUTC: false, - precision: 'second', - }, - axisBottom: { - tickRotation: 0, - legend: 'Time', - legendOffset: 36, - legendPosition: 'middle', - tickSize: 5, - tickPadding: 5, - tickValues: 'every 2 days', - format: '%b %d', - }, - enableSlices: 'x', - yScale: { type: 'linear', min: 'auto', max: 'auto' }, - }), - [nivoReadyData, processedData] - ); - - if (!processedData || !processedData?.length) { - return No data available; - } - return ( - - - - ); -}; - -export default CardLinearChart; diff --git a/src/layout/PrivateRoute.jsx b/src/layout/PrivateRoute.jsx index c235a9b..dc5bd9b 100644 --- a/src/layout/PrivateRoute.jsx +++ b/src/layout/PrivateRoute.jsx @@ -5,10 +5,6 @@ import { useAuthContext } from '../context'; const PrivateRoute = ({ children }) => { const { isLoggedIn, user } = useAuthContext(); const navigate = useNavigate(); - - // if (!isLoggedIn) { - // return ; - // } useEffect(() => { if (user === null) { navigate('/login', { replace: true }); diff --git a/src/layout/REUSABLE_COMPONENTS/ProgressCircle.jsx b/src/layout/REUSABLE_COMPONENTS/ProgressCircle.jsx index b42d0fb..34649f9 100644 --- a/src/layout/REUSABLE_COMPONENTS/ProgressCircle.jsx +++ b/src/layout/REUSABLE_COMPONENTS/ProgressCircle.jsx @@ -4,7 +4,7 @@ import { Box, useTheme } from '@mui/material'; import PropTypes from 'prop-types'; import RCToolTip from './RCTOOLTIP/RCToolTip'; import { useMode } from '../../context'; -import useSkeletonLoader from '../collection/collectionGrids/cards-datatable/useSkeletonLoader'; +import useSkeletonLoader from './useSkeletonLoader'; const ProgressCircleSkeleton = ({ size = 120 }) => { const theme = useTheme(); diff --git a/src/layout/REUSABLE_COMPONENTS/RCInfoItem.jsx b/src/layout/REUSABLE_COMPONENTS/RCInfoItem.jsx index f93ac75..3e667aa 100644 --- a/src/layout/REUSABLE_COMPONENTS/RCInfoItem.jsx +++ b/src/layout/REUSABLE_COMPONENTS/RCInfoItem.jsx @@ -1,50 +1,5 @@ -// import React from 'react'; -// import { Grid, CardContent, useMediaQuery } from '@mui/material'; -// import { useTheme } from '@mui/material/styles'; -// import MDTypography from '../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; -// import { useMode } from '../../context'; - -// const RCInfoItem = ({ -// label, -// value, -// gridSizes = { xs: 12, sm: 6, md: 3 }, -// externalTheme = null, -// }) => { -// const { theme } = useMode(); -// const isMobileView = useMediaQuery(theme.breakpoints.down('sm')); - -// return ( -// -// -// -// {`${label}:`} -// -// -// {value} -// -// -// -// ); -// }; - -// export default RCInfoItem; import React from 'react'; import { Grid, CardContent, useMediaQuery, Skeleton } from '@mui/material'; -import { useTheme } from '@mui/material/styles'; import MDTypography from '../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; import { useMode } from '../../context'; @@ -64,7 +19,12 @@ const RCInfoItem = ({ display: 'flex', flexDirection: 'column', justifyContent: 'center', - height: '100%', + height: isMobileView ? 'auto' : '100%', // Adjust height for mobile + padding: isMobileView ? '8px' : '16px', // Reduce padding on mobile for less tall items + flexGrow: 1, + '&:last-child': { + paddingBottom: isMobileView ? '8px' : '16px', // Ensure the last child padding is reduced on mobile + }, }} > {label !== undefined && value !== undefined ? ( diff --git a/src/layout/REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIcon.jsx b/src/layout/REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIcon.jsx index 5cbfc0e..57d559d 100644 --- a/src/layout/REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIcon.jsx +++ b/src/layout/REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIcon.jsx @@ -5,13 +5,18 @@ import { useMode } from '../../../context'; const RCWrappedIcon = forwardRef(({ color, size, children, ...rest }, ref) => { const { theme } = useMode(); - return ; + return ( + + {children} + + ); }); RCWrappedIcon.displayName = 'RCWrappedIcon'; RCWrappedIcon.defaultProps = { color: 'black', + background: 'white', size: '3rem', }; diff --git a/src/layout/REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIconRoot.jsx b/src/layout/REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIconRoot.jsx index 9697256..223bace 100644 --- a/src/layout/REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIconRoot.jsx +++ b/src/layout/REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIconRoot.jsx @@ -5,6 +5,7 @@ import { useMode } from '../../../context'; export default styled(Box)(({ color }) => { const { theme } = useMode(); // const { color, size } = ownerstate; + return { borderRadius: '50%', width: 40, @@ -13,7 +14,8 @@ export default styled(Box)(({ color }) => { display: 'flex', alignItems: 'center', justifyContent: 'center', - backgroundColor: + color: color, + background: color === 'success' ? theme.palette.chartTheme.greenAccent.light : 'black', diff --git a/src/layout/REUSABLE_COMPONENTS/SkeletonVariants.jsx b/src/layout/REUSABLE_COMPONENTS/SkeletonVariants.jsx index fd453eb..59dad3e 100644 --- a/src/layout/REUSABLE_COMPONENTS/SkeletonVariants.jsx +++ b/src/layout/REUSABLE_COMPONENTS/SkeletonVariants.jsx @@ -10,7 +10,7 @@ import { Collapse, CardActionArea, } from '@mui/material'; -import useSkeletonLoader from '../collection/collectionGrids/cards-datatable/useSkeletonLoader'; +import useSkeletonLoader from './useSkeletonLoader'; import MDBox from './MDBOX'; import { useMode } from '../../context'; import { diff --git a/src/layout/REUSABLE_COMPONENTS/icons/DeckOfCardsIcon.jsx b/src/layout/REUSABLE_COMPONENTS/icons/DeckOfCardsIcon.jsx index ac73541..5fa7c11 100644 --- a/src/layout/REUSABLE_COMPONENTS/icons/DeckOfCardsIcon.jsx +++ b/src/layout/REUSABLE_COMPONENTS/icons/DeckOfCardsIcon.jsx @@ -2,13 +2,15 @@ import React from 'react'; import ReusableIconButton from './ReusableIconButton'; import deckIcon from '../../../assets/icons/deckIcon2.png'; -const DeckOfCardsIcon = () => { +const DeckOfCardsIcon = (color) => { return ( console.log('Deck icon clicked')} - color={'rgba(0, 0, 0, 0.54)'} + color={color || 'rgba(0, 0, 0, 0.54)'} + backgroundColor={color || 'rgba(0, 0, 0, 0.54)'} + // color={'rgba(0, 0, 0, 0.54)'} // size={48} // width={40} // height={40} diff --git a/src/layout/REUSABLE_COMPONENTS/unique/SimpleButton.jsx b/src/layout/REUSABLE_COMPONENTS/unique/SimpleButton.jsx index a485fc8..f6e4c9c 100644 --- a/src/layout/REUSABLE_COMPONENTS/unique/SimpleButton.jsx +++ b/src/layout/REUSABLE_COMPONENTS/unique/SimpleButton.jsx @@ -1,6 +1,13 @@ import React from 'react'; import { rgba } from 'polished'; - +import styled from 'styled-components'; +import { Box } from '@mui/material'; +const ButtonContainer = styled(Box)` + flex: 1; + display: flex; + justify-content: flex-end; + max-width: 50%; +`; const SimpleButton = ({ theme, children, @@ -96,10 +103,12 @@ const SimpleButton = ({ }; return ( - + + + ); }; diff --git a/src/layout/REUSABLE_COMPONENTS/unique/SimpleCard.jsx b/src/layout/REUSABLE_COMPONENTS/unique/SimpleCard.jsx index 043fba5..95e8a0a 100644 --- a/src/layout/REUSABLE_COMPONENTS/unique/SimpleCard.jsx +++ b/src/layout/REUSABLE_COMPONENTS/unique/SimpleCard.jsx @@ -129,12 +129,14 @@ const SimpleCard = ({ isHeroDisplay, heroText, heroIcon, + sx, ...rest }) => { const { theme: themeSettings } = useMode(); const isMobileView = useMediaQuery(themeSettings.breakpoints.down('sm')); const cardStyle = { // display: 'flex', + ...sx, width: '100%', padding: hasTitle ? 0 : theme.lenMd1, marginBottom: noBottomMargin ? 0 : theme.lenMd1, @@ -188,7 +190,7 @@ const SimpleCard = ({ variant="outlined" style={{ color: themeSettings.palette.primary.main, // Adjust color directly via theme - '& .MuiIcon-root': { fontSize: isMobileView ? '3rem' : '4rem' }, // Use theme to adjust icon size conditionally + '& .MuiIconRoot': { fontSize: isMobileView ? '3rem' : '4rem' }, // Use theme to adjust icon size conditionally }} > theme.spacing(1, 2)}; +`; +const HeaderContainer = styled(Box)` + flex: 1; + max-width: 50%; +`; const SimpleSectionHeader = ({ sectionName, userName, @@ -17,75 +28,81 @@ const SimpleSectionHeader = ({ const isMobileView = useMediaQuery(theme.breakpoints.down('sm')); return ( - - {/* Container for Section Name and Username adjusts direction based on lgDown */} + - - {sectionName} - - - {`${userName}'s Portfolio`} - - - - {/* Section Description */} - - {sectionDescription} - - - {/* Last Updated */} - + {sectionName} + + + {`${userName}'s Portfolio`} + + + - {`${lastUpdated}`} - - - + {/* Section Description */} + + {sectionDescription} + + + {/* Last Updated */} + + {`${lastUpdated}`} + + + + ); }; diff --git a/src/layout/collection/collectionGrids/cards-datatable/useSkeletonLoader.jsx b/src/layout/REUSABLE_COMPONENTS/useSkeletonLoader.jsx similarity index 100% rename from src/layout/collection/collectionGrids/cards-datatable/useSkeletonLoader.jsx rename to src/layout/REUSABLE_COMPONENTS/useSkeletonLoader.jsx diff --git a/src/layout/collection/collectionGrids/ChartGridLayout.jsx b/src/layout/collection/collectionGrids/ChartGridLayout.jsx index 961af6b..5e0ad4f 100644 --- a/src/layout/collection/collectionGrids/ChartGridLayout.jsx +++ b/src/layout/collection/collectionGrids/ChartGridLayout.jsx @@ -9,7 +9,6 @@ import { Box, } from '@mui/material'; import MDBox from '../../REUSABLE_COMPONENTS/MDBOX'; -import DataTable from './cards-datatable'; import { useMode, useStatisticsStore } from '../../../context'; import DashboardBox from '../../REUSABLE_COMPONENTS/DashboardBox'; import BoxHeader from '../../REUSABLE_COMPONENTS/BoxHeader'; @@ -19,38 +18,31 @@ import uniqueTheme from '../../REUSABLE_COMPONENTS/unique/uniqueTheme'; import { ChartArea } from '../../../pages/pageStyles/StyledComponents'; import useSelectedCollection from '../../../context/MAIN_CONTEXT/CollectionContext/useSelectedCollection'; import useTimeRange from '../../../components/forms/selectors/useTimeRange'; -import useSkeletonLoader from './cards-datatable/useSkeletonLoader'; +import useSkeletonLoader from '../../REUSABLE_COMPONENTS/useSkeletonLoader'; import ChartErrorBoundary from './cards-chart/ChartErrorBoundary'; import { ChartConfiguration } from './cards-chart/ChartConfigs'; -import IconStatWrapper from '../../REUSABLE_COMPONENTS/unique/IconStatWrapper'; import { TopCardsDisplayRow } from '../sub-components/TopCardsDisplayRow'; import LoadingOverlay from '../../LoadingOverlay'; import RCWrappedIcon from '../../REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIcon'; -import { - ResponsiveContainer, - CartesianGrid, - AreaChart, - BarChart, - Bar, - LineChart, - XAxis, - YAxis, - Legend, - Line, - Tooltip, - Area, -} from 'recharts'; +import { ResponsiveContainer } from 'recharts'; +import PricedDataTable from './cards-datatable/PricedDataTable'; +import preparePortfolioTableData from '../data/portfolioData'; const renderCardContainer = (content) => { return ( - + {content} ); }; -const ChartGridLayout = ({ selectedCards, removeCard, columns, data }) => { +const ChartGridLayout = ({ selectedCards, removeCard }) => { const { theme } = useMode(); const isXs = useMediaQuery(theme.breakpoints.down('sm')); const isLg = useMediaQuery(theme.breakpoints.up('lg')); @@ -72,52 +64,15 @@ const ChartGridLayout = ({ selectedCards, removeCard, columns, data }) => { if (!averagedData || !averagedData[selectedTimeRange]) { return ; } - // if (!averagedData || !averagedData[selectedTimeRange]) { - // return ( - // - // - // - // - // - // - // - // - // - // - // - // - // {[...Array(5)].map((_, index) => ( - // - // - // - // - // - // ))} - // - // - // - // ); - // } - const selectedChartData = useMemo(() => { const chartData = averagedData[selectedTimeRange]; return chartData || null; - }, [selectedCollection.averagedChartData, selectedTimeRange]); + }, [selectedCollection?.averagedChartData, selectedTimeRange]); + + const { data, columns } = useMemo( + () => preparePortfolioTableData(selectedCollection?.cards), + [selectedCollection?.cards] + ); useEffect(() => { console.log('DEBUG LOG, ', { selectedChartData, @@ -133,9 +88,17 @@ const ChartGridLayout = ({ selectedCards, removeCard, columns, data }) => { minute: '2-digit', }) : 'Loading...'; - + const entriesPerPage = { + defaultValue: 5, + entries: [5, 10, 15, 20], + }; return ( + {console.log('DEBUG LOG, ', { + selectedChartData, + markers, + selectedTimeRange, + })} { theme={uniqueTheme} hasTitle={false} isTableOrChart={true} - // cardTitle="Collection Card List" - // data={''} > { item xs={12} lg={5} - sx={{ display: 'flex', flexDirection: 'column' }} + sx={{ + display: 'flex', + flexDirection: 'column', + minHeight: '800px', + }} > { /> {renderCardContainer( - )} diff --git a/src/layout/collection/collectionGrids/cards-chart/ChartConfigs.jsx b/src/layout/collection/collectionGrids/cards-chart/ChartConfigs.jsx index 295371d..7cef160 100644 --- a/src/layout/collection/collectionGrids/cards-chart/ChartConfigs.jsx +++ b/src/layout/collection/collectionGrids/cards-chart/ChartConfigs.jsx @@ -106,13 +106,6 @@ export const ChartConfiguration = ({ stacked: false, // Changed to false unless stacking is needed reverse: false, }, - // yScale: { - // type: 'linear', - // min: 'auto', - // max: 'auto', - // stacked: true, - // reverse: false, - // }, curve: 'catmullRom', // This curve type can create smoother, more wavy lines motionConfig: 'wobbly', // A more dynamic motion configuration useMesh: true, stiffness: 90, diff --git a/src/layout/collection/collectionGrids/cards-chart/ChartErrorBoundary.jsx b/src/layout/collection/collectionGrids/cards-chart/ChartErrorBoundary.jsx index 761dd3d..b2fdf0f 100644 --- a/src/layout/collection/collectionGrids/cards-chart/ChartErrorBoundary.jsx +++ b/src/layout/collection/collectionGrids/cards-chart/ChartErrorBoundary.jsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react'; import { Box, Container, Icon, Typography, useMediaQuery } from '@mui/material'; -import useSkeletonLoader from '../cards-datatable/useSkeletonLoader'; +import useSkeletonLoader from '../../../REUSABLE_COMPONENTS/useSkeletonLoader'; import BoxHeader from '../../../REUSABLE_COMPONENTS/BoxHeader'; import { useMode } from '../../../../context'; diff --git a/src/layout/collection/collectionGrids/cards-datatable/DataTableBodyCell.jsx b/src/layout/collection/collectionGrids/cards-datatable/DataTableBodyCell.jsx deleted file mode 100644 index ff97b41..0000000 --- a/src/layout/collection/collectionGrids/cards-datatable/DataTableBodyCell.jsx +++ /dev/null @@ -1,57 +0,0 @@ -// prop-types is a library for typechecking of props -import PropTypes from 'prop-types'; -import MDBox from '../../../REUSABLE_COMPONENTS/MDBOX'; -import { useMode } from '../../../../context'; -import { Box } from '@mui/system'; - -function DataTableBodyCell({ noBorder, align, children }) { - const { theme } = useMode(); - return ( - - - {children} - - - ); -} - -// Setting default values for the props of DataTableBodyCell -DataTableBodyCell.defaultProps = { - noBorder: false, - align: 'left', -}; - -// Typechecking props for the DataTableBodyCell -DataTableBodyCell.propTypes = { - children: PropTypes.node.isRequired, - noBorder: PropTypes.bool, - align: PropTypes.oneOf(['left', 'right', 'center']), -}; - -export default DataTableBodyCell; diff --git a/src/layout/collection/collectionGrids/cards-datatable/DataTableHeadCell.jsx b/src/layout/collection/collectionGrids/cards-datatable/DataTableHeadCell.jsx deleted file mode 100644 index 8b87dc4..0000000 --- a/src/layout/collection/collectionGrids/cards-datatable/DataTableHeadCell.jsx +++ /dev/null @@ -1,113 +0,0 @@ -import { useMemo } from 'react'; -import PropTypes from 'prop-types'; -import { TableRow, Checkbox, Icon } from '@mui/material'; -import MDBox from '../../../REUSABLE_COMPONENTS/MDBOX'; -import MDTypography from '../../../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; -import { useMode } from '../../../../context'; -import FlexBetween from '../../../REUSABLE_COMPONENTS/FlexBetween'; - -const DataTableHeadCell = ({ headerGroups, isSorted, setSortedValue }) => { - const { theme } = useMode(); - - const renderCellContent = (column, idx) => { - const sorted = setSortedValue(column, isSorted); - const shouldShowIcons = column.showIcons; - - return ( - - - - {column.render('Header')} - - {shouldShowIcons && sorted && ( - - - arrow_drop_up - - - arrow_drop_down - - - )} - - - ); - }; - - return useMemo( - () => ( - <> - {headerGroups.map((headerGroup, key) => ( - - {headerGroup.headers.map(renderCellContent)} - - ))} - - ), - [ - headerGroups, - isSorted, - setSortedValue, - theme.palette.divider, - theme.typography.fontWeightMedium, - ] - ); -}; - -DataTableHeadCell.propTypes = { - headerGroups: PropTypes.array.isRequired, - isSorted: PropTypes.bool.isRequired, - setSortedValue: PropTypes.func.isRequired, -}; - -export default DataTableHeadCell; diff --git a/src/layout/collection/collectionGrids/cards-datatable/PricedDataTable.jsx b/src/layout/collection/collectionGrids/cards-datatable/PricedDataTable.jsx new file mode 100644 index 0000000..963d8b2 --- /dev/null +++ b/src/layout/collection/collectionGrids/cards-datatable/PricedDataTable.jsx @@ -0,0 +1,77 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { DataGrid, GridToolbar } from '@mui/x-data-grid'; +import { Box } from '@mui/material'; +import { useMode } from '../../../../context'; +import OptionsComponent from '../../../../components/forms/OptionsComponent'; +import GenericActionButtons from '../../../../components/buttons/actionButtons/GenericActionButtons'; +import { enqueueSnackbar } from 'notistack'; + +function PricedDataTable({ entriesPerPage, canSearch, table }) { + const { theme } = useMode(); + const [pageSize, setPageSize] = useState(entriesPerPage.defaultValue); + + useEffect(() => { + setPageSize(entriesPerPage.defaultValue); + }, [entriesPerPage.defaultValue]); + + return ( + + ({ id: index, ...row }))} + columns={table.columns} + pageSize={pageSize} + onPageSizeChange={(newPageSize) => setPageSize(newPageSize)} + rowsPerPageOptions={entriesPerPage.entries} + slots={{ toolbar: GridToolbar }} + slotProps={{ + toolbar: { + showQuickFilter: true, + }, + }} + initialState={{ + filter: { + filterModel: { + items: [], + quickFilterValues: [''], + }, + }, + }} + checkboxSelection + sx={{ + '& .MuiDataGrid-root': { + color: theme.palette.chartTheme.grey.dark, + border: 'none', + }, + '& .MuiDataGrid-cell': { + borderBottom: `1px solid ${theme.palette.chartTheme.grey.lightest} !important`, + }, + '& .MuiDataGrid-columnHeaders': { + borderBottom: `1px solid ${theme.palette.chartTheme.grey.lightest} !important`, + }, + '& .MuiDataGrid-columnSeparator': { + visibility: 'hidden', + }, + }} + /> + + ); +} + +PricedDataTable.propTypes = { + entriesPerPage: PropTypes.shape({ + defaultValue: PropTypes.number, + entries: PropTypes.arrayOf(PropTypes.number), + }).isRequired, + canSearch: PropTypes.bool, + table: PropTypes.shape({ + columns: PropTypes.array.isRequired, + data: PropTypes.array.isRequired, + }).isRequired, +}; + +PricedDataTable.defaultProps = { + canSearch: false, +}; + +export default PricedDataTable; diff --git a/src/layout/collection/collectionGrids/cards-datatable/index.jsx b/src/layout/collection/collectionGrids/cards-datatable/index.jsx deleted file mode 100644 index 8c371b9..0000000 --- a/src/layout/collection/collectionGrids/cards-datatable/index.jsx +++ /dev/null @@ -1,298 +0,0 @@ -/* eslint-disable @typescript-eslint/no-empty-function */ -import { useMemo, useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; -import { - useTable, - usePagination, - useGlobalFilter, - useAsyncDebounce, - useSortBy, - useRowSelect, -} from 'react-table'; -// @mui material components -import Table from '@mui/material/Table'; -import TableContainer from '@mui/material/TableContainer'; -import TableRow from '@mui/material/TableRow'; -import DataTableBodyCell from './DataTableBodyCell'; -import { Box, Button, Checkbox, Grid, Paper, TableBody } from '@mui/material'; -import PaginationComponent from './PaginationComponent'; -import OptionsComponent from '../../../../components/forms/OptionsComponent'; -import GenericActionButtons from '../../../../components/buttons/actionButtons/GenericActionButtons'; -import { useMode } from '../../../../context'; -import DataTableHeadCell from './DataTableHeadCell'; -import FlexBetween from '../../../REUSABLE_COMPONENTS/FlexBetween'; -const setSortedValue = (column, isSorted) => { - let sortedValue; - - if (isSorted && column.isSorted) { - sortedValue = column.isSortedDesc ? 'desc' : 'asce'; - } else if (isSorted) { - sortedValue = 'none'; - } else { - sortedValue = false; - } - - return sortedValue; -}; -function DataTable({ - entriesPerPage, - canSearch, - showTotalEntries, - table, - pagination, - isSorted, - noEndBorder, - tableSize, -}) { - const { theme } = useMode(); - const [showTotalPrice, setShowTotalPrice] = useState(window.innerWidth > 800); - const [showSelection, setShowSelection] = useState(window.innerWidth > 500); - useEffect(() => { - const handleResize = () => { - setShowTotalPrice(window.innerWidth > 800); - setShowSelection(window.innerWidth > 500); - }; - window.addEventListener('resize', handleResize); - return () => { - window.removeEventListener('resize', handleResize); - }; - }, []); - - const data = useMemo(() => table.data, [table.data]); - const columns = useMemo(() => { - let baseColumns = [ - showSelection && { - id: 'selection', - showIcons: false, - Header: ({ getToggleAllRowsSelectedProps }) => ( - - ), - Cell: ({ row }) => , - // Apply a fixed width to the checkbox column - // width: 30, // Adjust the width as needed - // minWidth: 30, // Ensure it doesn't get smaller than the set width - // maxWidth: 30, // Ensure it doesn't get larger than the set width - }, - { Header: 'Name', accessor: 'name' }, - { Header: 'Price', accessor: 'price' }, - - { Header: 'Quantity', accessor: 'quantity', showIcons: false }, - { - id: 'action', - Header: 'Action', - accessor: 'action', - showIcons: false, - - Cell: ({ value }) => ( - console.log('clicked')} - onSuccess={() => console.log('success')} - onFailure={(error) => console.log(error)} - page={'Collection'} - cardSize={'small'} - variant="data-table" - /> - ), - }, - ]; - if (tableSize !== 'large' && showTotalPrice) { - baseColumns.push({ - Header: 'Total Price', - accessor: 'tPrice', - }); - } - // Filter out any falsey values to remove the conditionally included columns when not shown - return baseColumns.filter(Boolean); - }, [showTotalPrice, showSelection, tableSize]); - - const defaultPageSize = useMemo( - () => entriesPerPage.defaultValue, - [entriesPerPage] - ); - const pageSizeOptions = useMemo( - () => entriesPerPage.entries, - [entriesPerPage] - ); - - const { - getTableProps, - getTableBodyProps, - headerGroups, - prepareRow, - page, - canPreviousPage, - canNextPage, - pageOptions, - gotoPage, - nextPage, - previousPage, - setPageSize, - setGlobalFilter, - selectedFlatRows, - toggleAllRowsSelected, - state: { pageIndex, pageSize, globalFilter }, - } = useTable( - { - columns, - data, - initialState: { pageIndex: 0, pageSize: entriesPerPage.defaultValue }, - }, - useGlobalFilter, - useSortBy, - usePagination, - useRowSelect - ); - const [search, setSearch] = useState(globalFilter); - - useEffect(() => { - setGlobalFilter(search || undefined); - }, [search, setGlobalFilter]); - - useEffect(() => { - setPageSize(defaultPageSize); - }, [defaultPageSize, setPageSize]); - - const handleSelectAllClick = (event) => { - toggleAllRowsSelected(event.target.checked); - }; - - let entriesEnd; - if (pageIndex === 0) { - entriesEnd = pageSize; - } else if (pageIndex === pageOptions.length - 1) { - entriesEnd = data.length; - } else { - entriesEnd = pageSize * (pageIndex + 1); - } - - return ( - - - {/* Search and Entries Per Page Options */} - setSearch(e.target.value)} - pageSize={pageSize} - setPageSize={(size) => setPageSize(Number(size))} - pageOptions={pageSizeOptions} - /> - {/* Table */} - - - - {}} - headerGroups={headerGroups} - isSorted={isSorted} - setSortedValue={setSortedValue} - /> - - {/* Table Body */} - - {page.map((row, key) => { - prepareRow(row); - return ( - - {' '} - - {row.cells.map((cell, idx) => ( - - {cell.render('Cell')} - - ))} - - - ); - })} - -
-
- {/* Pagination */} - - - -
-
- ); -} - -DataTable.propTypes = { - entriesPerPage: PropTypes.shape({ - defaultValue: PropTypes.number, - entries: PropTypes.arrayOf(PropTypes.number), - }).isRequired, - canSearch: PropTypes.bool, - showTotalEntries: PropTypes.bool, - table: PropTypes.shape({ - columns: PropTypes.array.isRequired, - data: PropTypes.array.isRequired, - }).isRequired, - isSorted: PropTypes.bool, - noEndBorder: PropTypes.bool, -}; -DataTable.defaultProps = { - canSearch: false, - showTotalEntries: true, - isSorted: true, - noEndBorder: false, -}; - -export default DataTable; diff --git a/src/layout/collection/collectionGrids/collections-list/CollectionListItem.jsx b/src/layout/collection/collectionGrids/collections-list/CollectionListItem.jsx index 9510cd2..2a908d1 100644 --- a/src/layout/collection/collectionGrids/collections-list/CollectionListItem.jsx +++ b/src/layout/collection/collectionGrids/collections-list/CollectionListItem.jsx @@ -6,6 +6,7 @@ import { CardContent, Grid, Tooltip, + useMediaQuery, } from '@mui/material'; import PropTypes from 'prop-types'; import MDBox from '../../../../layout/REUSABLE_COMPONENTS/MDBOX'; @@ -15,47 +16,14 @@ import useDialogState from '../../../../context/hooks/useDialogState'; import { useMode } from '../../../../context'; import CollectionDialog from '../../../../components/dialogs/CollectionDialog'; import LongMenu from '../../../../layout/navigation/LongMenu'; -import MDTypography from '../../../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; import RCChange from '../../../REUSABLE_COMPONENTS/RC/RCChange'; import RCInfoItem from '../../../REUSABLE_COMPONENTS/RCInfoItem'; -import { useVisibility } from '../../../../context/hooks/useVisibility'; import { roundToNearestTenth } from '../../../../context/Helpers'; -// const CollectionInfoItem = ({ label, value, theme }) => ( -// -// -// -// {`${label}:`} -// -// -// {value} -// -// -// -// ); - -// CollectionInfoItem.propTypes = { -// label: PropTypes.string.isRequired, -// value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, -// theme: PropTypes.object.isRequired, -// }; - const CollectionListItem = memo(({ collection }) => { const { theme } = useMode(); + const isMobile = useMediaQuery(theme.breakpoints.down('sm')); + const { deleteCollection } = useCollectionManager(); const { handleSelectCollection } = useSelectedCollection(); const { dialogState, openDialog, closeDialog } = useDialogState({ @@ -101,6 +69,10 @@ const CollectionListItem = memo(({ collection }) => { flexDirection: 'row', justifyContent: 'center', height: '100%', + ...(isMobile && + { + // flexDirection: 'column', // Stack elements vertically on mobile + }), }} > { flexDirection: 'row', justifyContent: 'center', flexGrow: 1, + ...(isMobile && { + flexDirection: 'column', // Adjust layout for mobile + }), }} > @@ -153,6 +128,10 @@ const CollectionListItem = memo(({ collection }) => { backgroundColor: theme.palette.success.main, mt: theme.spacing(1), mr: theme.spacing(1), + ...(isMobile && { + mt: theme.spacing(0.5), // Adjust margin top for mobile + mr: theme.spacing(0.5), // Adjust margin right for mobile + }), }} > {renderToolTip()} diff --git a/src/layout/collection/collectionGrids/collections-list/SelectCollectionHeader.jsx b/src/layout/collection/collectionGrids/collections-list/SelectCollectionHeader.jsx index 9002817..9b30a9c 100644 --- a/src/layout/collection/collectionGrids/collections-list/SelectCollectionHeader.jsx +++ b/src/layout/collection/collectionGrids/collections-list/SelectCollectionHeader.jsx @@ -6,8 +6,6 @@ import { useMode, useUserContext, } from '../../../../context'; -import { Card, Typography } from '@mui/joy'; -import useSkeletonLoader from '../cards-datatable/useSkeletonLoader'; import uniqueTheme from '../../../REUSABLE_COMPONENTS/unique/uniqueTheme'; import SimpleButton from '../../../REUSABLE_COMPONENTS/unique/SimpleButton'; import styled from 'styled-components'; @@ -28,12 +26,12 @@ const HeaderContainer = styled(Box)` max-width: 50%; `; -const ButtonContainer = styled(Box)` - flex: 1; - display: flex; - justify-content: flex-end; - max-width: 50%; -`; +// const ButtonContainer = styled(Box)` +// flex: 1; +// display: flex; +// justify-content: flex-end; +// max-width: 50%; +// `; const SelectCollectionHeader = ({ openNewDialog }) => { const { theme } = useMode(); @@ -51,31 +49,26 @@ const SelectCollectionHeader = ({ openNewDialog }) => { noBottomMargin={true} > - - - - - - { - setCurrentForm('addCollectionForm'); - openNewDialog(); - }} - > - Add New Collection - - + + { + setCurrentForm('addCollectionForm'); + openNewDialog(); + }} + > + Add New Collection + ); diff --git a/src/layout/collection/collectionGrids/collections-list/SelectCollectionList.jsx b/src/layout/collection/collectionGrids/collections-list/SelectCollectionList.jsx index 6e4300f..c460062 100644 --- a/src/layout/collection/collectionGrids/collections-list/SelectCollectionList.jsx +++ b/src/layout/collection/collectionGrids/collections-list/SelectCollectionList.jsx @@ -7,6 +7,7 @@ import { Grid, List, Skeleton, + useMediaQuery, } from '@mui/material'; import PropTypes from 'prop-types'; import { TransitionGroup } from 'react-transition-group'; @@ -16,11 +17,15 @@ import styled from 'styled-components'; import SimpleCard from '../../../REUSABLE_COMPONENTS/unique/SimpleCard'; import uniqueTheme from '../../../REUSABLE_COMPONENTS/unique/uniqueTheme'; import { CollectionListItemSkeleton } from '../../../REUSABLE_COMPONENTS/SkeletonVariants'; +import { useMode } from '../../../../context'; const SelectCollectionList = ({ openDialog, handleSelectAndShowCollection, }) => { + const { theme } = useMode(); + const isMobile = useMediaQuery(theme.breakpoints.down('sm')); // Detect mobile screen + const { allCollections, allIds, @@ -53,6 +58,14 @@ const SelectCollectionList = ({ onClick={() => { handleSelectAndShowCollection(collection); }} + sx={{ + ...(isMobile && { + boxShadow: 'none', // Remove shadow + '&:hover': { + boxShadow: 'none', + }, + }), + }} > @@ -95,6 +108,7 @@ const SelectCollectionList = ({ SelectCollectionList.propTypes = { openDialog: PropTypes.func.isRequired, + handleSelectAndShowCollection: PropTypes.func.isRequired, }; export default memo(SelectCollectionList); diff --git a/src/layout/collection/collectionGrids/collections-list/StatBoard.jsx b/src/layout/collection/collectionGrids/collections-list/StatBoard.jsx index 2b2a27f..14ed242 100644 --- a/src/layout/collection/collectionGrids/collections-list/StatBoard.jsx +++ b/src/layout/collection/collectionGrids/collections-list/StatBoard.jsx @@ -1,5 +1,5 @@ /* eslint-disable react/jsx-key */ -import { Box, Grid, Typography, Skeleton } from '@mui/material'; +import { Box, Grid, Typography, Skeleton, useMediaQuery } from '@mui/material'; // import PieChart from './statItems/PieChart'; import TotalPriceStatBox from './statItems/TotalPriceStatBox'; // import ValuDistributionCircle from './statItems/ValuDistributionCircle'; @@ -9,9 +9,7 @@ import uniqueTheme from '../../../REUSABLE_COMPONENTS/unique/uniqueTheme'; import { useAppContext, useMode } from '../../../../context'; import ValuDistributionCircle from './statItems/ValuDistributionCircle'; import PricedCardList from './statItems/PricedCardList'; -import PerformanceStatBox from './statItems/PerformanceStatBox'; import MDBox from '../../../REUSABLE_COMPONENTS/MDBOX'; -import styled from 'styled-components'; import TotalCardsCollectedStatBox from './statItems/TotalCardsCollectedStatBox'; import FlexBetween from '../../../REUSABLE_COMPONENTS/FlexBetween'; @@ -63,7 +61,9 @@ const DistCircle = () => { ); } return ( - + ); @@ -72,6 +72,7 @@ const DistCircle = () => { const PriceList = () => { const { theme } = useMode(); const colors = theme.palette.chartTheme; + const isMobile = useMediaQuery(theme.breakpoints.down('sm')); return ( @@ -80,6 +81,10 @@ const PriceList = () => { ); }; const StatBoard = () => { + const { theme } = useMode(); + const colors = theme.palette.chartTheme; + const isMobile = useMediaQuery(theme.breakpoints.down('sm')); + return ( { // spacing={2} sx={{ alignItems: 'flex-start', - maxHeight: '270px', - minHeight: '270px', - my: 2, + ...(isMobile + ? { + flexDirection: 'column', // Stack items vertically on mobile + maxHeight: 'none', // Remove maxHeight to allow content to flow + minHeight: 'none', // Adjust minHeight accordingly + my: 1, // Adjust vertical margin + } + : { + maxHeight: '270px', + minHeight: '270px', + my: 2, // Maintain original styling for larger screens + }), }} > {[, , ].map( @@ -102,10 +116,10 @@ const StatBoard = () => { {component} diff --git a/src/layout/collection/collectionGrids/collections-list/statItems/PricedCardList.jsx b/src/layout/collection/collectionGrids/collections-list/statItems/PricedCardList.jsx index faaecad..a6dc623 100644 --- a/src/layout/collection/collectionGrids/collections-list/statItems/PricedCardList.jsx +++ b/src/layout/collection/collectionGrids/collections-list/statItems/PricedCardList.jsx @@ -15,8 +15,20 @@ const PricedCardList = () => { const primary = colors.primary.dark; const greenAccent = colors.greenAccent.light; const { cardsWithQuantities } = useAppContext(); + // const topFiveCards = useMemo(() => { + // return cardsWithQuantities?.sort((a, b) => b.price - a.price).slice(0, 5); + // }, [cardsWithQuantities]); const topFiveCards = useMemo(() => { - return cardsWithQuantities?.sort((a, b) => b.price - a.price).slice(0, 5); + const uniqueCards = new Map(); + cardsWithQuantities.forEach((card) => { + if (!uniqueCards.has(card.id)) { + uniqueCards.set(card.id, card); + } + }); + + const uniqueCardsArray = Array.from(uniqueCards.values()); + + return uniqueCardsArray.sort((a, b) => b.price - a.price).slice(0, 5); }, [cardsWithQuantities]); const { data, columns } = useMemo( () => prepareTableData(topFiveCards), diff --git a/src/layout/collection/collectionGrids/collections-list/statItems/ValuDistributionCircle.jsx b/src/layout/collection/collectionGrids/collections-list/statItems/ValuDistributionCircle.jsx index b74ae5a..0998e90 100644 --- a/src/layout/collection/collectionGrids/collections-list/statItems/ValuDistributionCircle.jsx +++ b/src/layout/collection/collectionGrids/collections-list/statItems/ValuDistributionCircle.jsx @@ -1,12 +1,21 @@ /* eslint-disable max-len */ import React from 'react'; -import { Box, Typography } from '@mui/material'; +import { Box, Card, Typography } from '@mui/material'; import MDBox from '../../../../REUSABLE_COMPONENTS/MDBOX'; import { useMode } from '../../../../../context'; +import { PieChart, Pie, Tooltip, Cell, ResponsiveContainer } from 'recharts'; + import ProgressCircle from '../../../../REUSABLE_COMPONENTS/ProgressCircle'; +import BoxHeader from '../../../../REUSABLE_COMPONENTS/BoxHeader'; const ValuDistributionCircle = ({ collections }) => { const { theme } = useMode(); + const colors = theme.palette.chartTheme; + const grey = colors.grey.darkest; + const lightGrey = colors.grey.lightest; + const primary = colors.primary.dark; + const greenAccent = colors.greenAccent.light; + const collectionMetaData = collections?.reduce( (meta, collection) => { meta.totalValue += collection?.totalPrice; @@ -17,22 +26,27 @@ const ValuDistributionCircle = ({ collections }) => { }, { totalValue: 0, tooltips: [] } ); - - let cumulativePercent = 0; - const gradientStops = collections - .map((collection) => { - const valuePercent = - (collection?.totalPrice / collectionMetaData?.totalValue) * 100; - const stop = `${theme.palette.chartTheme.blueAccent.default} ${cumulativePercent}%, ${theme.palette.chartTheme.blueAccent.default} ${cumulativePercent + valuePercent}%`; - cumulativePercent += valuePercent; - return stop; - }) - .join(', '); - - const tooltipContent = collectionMetaData.tooltips.join('\n'); + const data = collections.map((collection) => ({ + name: collection.name, + value: collection.totalPrice, + })); + const COLORS = [ + theme.palette.chartTheme.blueAccent.default, + theme.palette.chartTheme.greenAccent.light, + '#FFBB28', + '#FF8042', + ]; return ( - + { flexDirection: 'column', borderRadius: theme.shape.borderRadius, minHeight: '270px', + maxHeight: 270, }} > - + {/* Collection Value Distribution - - + */} + + + acc + card.price, 0)}`} + colorVariant={greenAccent} + useSX={true} + titleVariant="h5" + paddingVariant={theme.spacing(2)} + sx={{ + color: greenAccent, + }} + /> + + + + + + `${name}: ${(percent * 100).toFixed(0)}%` + } + > + {data.map((entry, index) => ( + + ))} + + + + - Total Value: ${collectionMetaData.totalValue.toFixed(2)} + Total Value: $ + {collections.reduce((acc, cur) => acc + cur.totalPrice, 0).toFixed(2)} Includes extra misc expenditures and costs @@ -72,3 +128,39 @@ const ValuDistributionCircle = ({ collections }) => { }; export default ValuDistributionCircle; +// +// +// +// Collection Value Distribution +// +// +// +// Total Value: ${collectionMetaData.totalValue.toFixed(2)} +// +// +// Includes extra misc expenditures and costs +// +// +// diff --git a/src/layout/collection/data/collectionPortfolioData.jsx b/src/layout/collection/data/collectionPortfolioData.jsx index ae256ca..00aa978 100644 --- a/src/layout/collection/data/collectionPortfolioData.jsx +++ b/src/layout/collection/data/collectionPortfolioData.jsx @@ -1,130 +1,130 @@ -import Icon from '@mui/material/Icon'; -// Images -import MDTypography from '../../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; -import React from 'react'; -import GenericActionButtons from '../../../components/buttons/actionButtons/GenericActionButtons'; -import { useSnackbar } from 'notistack'; -const Name = ({ name }) => ( - - {name} - -); -const Price = ({ price }) => ( - - {price} - -); -const TPrice = ({ tPrice }) => ( - - {tPrice} - -); -const Quantity = ({ quantity }) => ( - - {quantity} - -); -export default function prepareTableData(selectedCards) { - const roundToNearestTenth = (value) => Math.round(value * 10) / 10; - const { enqueueSnackbar } = useSnackbar(); - const columns = React.useMemo( - () => [ - { - Header: 'Name', - accessor: 'name', - id: 'name', - Cell: ({ value }) => , - }, - { - Header: 'Price', - accessor: 'price', - id: 'price', - Cell: ({ value }) => , - }, - { - Header: 'Total Price', - accessor: 'tPrice', - id: 'tPrice', - Cell: ({ value }) => , - }, - { - Header: 'Quantity', - accessor: 'quantity', - id: 'quantity', - Cell: ({ value }) => , - }, - { - id: 'action', - Header: 'Action', - accessor: 'action', - Cell: ({ value }) => ( - console.log('clicked')} - onSuccess={() => - enqueueSnackbar( - { - title: 'Action successful', - message: `Card added to ${value} successfully.`, - }, - 'success', - null - ) - } - onFailure={(error) => - enqueueSnackbar( - { - title: 'Action failed', - message: `Failed to add card to ${value}.`, - }, - 'error', - error - ) - } - page={'Collection'} - cardSize={'small'} - /> - ), - }, - ], - [] - ); +// import Icon from '@mui/material/Icon'; +// // Images +// import MDTypography from '../../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; +// import React from 'react'; +// import GenericActionButtons from '../../../components/buttons/actionButtons/GenericActionButtons'; +// import { useSnackbar } from 'notistack'; +// const Name = ({ name }) => ( +// +// {name} +// +// ); +// const Price = ({ price }) => ( +// +// {price} +// +// ); +// const TPrice = ({ tPrice }) => ( +// +// {tPrice} +// +// ); +// const Quantity = ({ quantity }) => ( +// +// {quantity} +// +// ); +// export default function prepareTableData(selectedCards) { +// const roundToNearestTenth = (value) => Math.round(value * 10) / 10; +// const { enqueueSnackbar } = useSnackbar(); +// const columns = React.useMemo( +// () => [ +// { +// Header: 'Name', +// accessor: 'name', +// id: 'name', +// Cell: ({ value }) => , +// }, +// { +// Header: 'Price', +// accessor: 'price', +// id: 'price', +// Cell: ({ value }) => , +// }, +// { +// Header: 'Total Price', +// accessor: 'tPrice', +// id: 'tPrice', +// Cell: ({ value }) => , +// }, +// { +// Header: 'Quantity', +// accessor: 'quantity', +// id: 'quantity', +// Cell: ({ value }) => , +// }, +// { +// id: 'action', +// Header: 'Action', +// accessor: 'action', +// Cell: ({ value }) => ( +// console.log('clicked')} +// onSuccess={() => +// enqueueSnackbar( +// { +// title: 'Action successful', +// message: `Card added to ${value} successfully.`, +// }, +// 'success', +// null +// ) +// } +// onFailure={(error) => +// enqueueSnackbar( +// { +// title: 'Action failed', +// message: `Failed to add card to ${value}.`, +// }, +// 'error', +// error +// ) +// } +// page={'Collection'} +// cardSize={'small'} +// /> +// ), +// }, +// ], +// [] +// ); - const data = React.useMemo( - () => - selectedCards?.map((card) => ({ - ...card, - tPrice: roundToNearestTenth(card.totalPrice), - action: card, - })), - [selectedCards] - ); +// const data = React.useMemo( +// () => +// selectedCards?.map((card) => ({ +// ...card, +// tPrice: roundToNearestTenth(card.totalPrice), +// action: card, +// })), +// [selectedCards] +// ); - return { columns, data }; -} +// return { columns, data }; +// } diff --git a/src/layout/collection/data/portfolioData.jsx b/src/layout/collection/data/portfolioData.jsx new file mode 100644 index 0000000..26f4460 --- /dev/null +++ b/src/layout/collection/data/portfolioData.jsx @@ -0,0 +1,157 @@ +import React from 'react'; +import MDTypography from '../../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; +import GenericActionButtons from '../../../components/buttons/actionButtons/GenericActionButtons'; +import { useSnackbar } from 'notistack'; + +// Note: No changes needed for these components +const Name = ({ name }) => ( + + {name} + +); + +const Price = ({ price }) => ( + + {price} + +); + +const TPrice = ({ tPrice }) => ( + + {tPrice} + +); + +const Quantity = ({ quantity }) => ( + + {quantity} + +); + +export default function preparePortfolioTableData(selectedCards) { + const roundToNearestTenth = (value) => Math.round(value * 10) / 10; + const { enqueueSnackbar } = useSnackbar(); + + const columns = [ + { + field: 'name', + headerName: 'Name', + flex: 1, + renderCell: (params) => , + }, + { + field: 'price', + headerName: 'Price', + flex: 1, + renderCell: (params) => , + }, + { + field: 'tPrice', + headerName: 'Total Price', + flex: 1, + renderCell: (params) => ( + + ), + }, + { + field: 'quantity', + headerName: 'Quantity', + flex: 1, + renderCell: (params) => , + }, + // { + // field: 'action', + // headerName: 'Action', + // flex: 1, + // renderCell: (params) => ( + // console.log('clicked')} + // onSuccess={() => + // enqueueSnackbar('Action successful', { + // variant: 'success', + // }) + // } + // onFailure={(error) => + // enqueueSnackbar('Action failed', { + // variant: 'error', + // }) + // } + // page={'Collection'} + // cardSize={'small'} + // /> + // ), + // }, + { + field: 'action', + headerName: 'Action', + renderCell: (params) => ( + console.log('clicked')} + onSuccess={() => + enqueueSnackbar( + { + title: 'Action successful', + message: `Card added to ${params?.name || ''} successfully.`, + }, + 'success', + null + ) + } + onFailure={(error) => + enqueueSnackbar( + { + title: 'Action failed', + message: `Failed to add card to ${params?.name || ''}.`, + }, + 'error', + error + ) + } + page={'Collection'} + cardSize={'small'} + variant="data-table" + /> + ), + flex: 1, + }, + ]; + + const data = selectedCards?.map((card, index) => ({ + id: index, // Ensure each row has a unique 'id' field for DataGrid + ...card, + tPrice: roundToNearestTenth(card.totalPrice), + action: card, // You might need to adjust this based on what GenericActionButtons expects + })); + + return { columns, data }; +} diff --git a/src/layout/collection/index.jsx b/src/layout/collection/index.jsx index 8d489a1..67fac36 100644 --- a/src/layout/collection/index.jsx +++ b/src/layout/collection/index.jsx @@ -16,6 +16,7 @@ import DashboardBox from '../REUSABLE_COMPONENTS/DashboardBox'; import StatBoard from './collectionGrids/collections-list/StatBoard'; import { Tab, Tabs } from '@mui/material'; import RCHeader from '../REUSABLE_COMPONENTS/RCHeader'; +import preparePortfolioTableData from './data/portfolioData'; const CollectionsView = ({ openDialog, handleTabAndSelect }) => { const { theme } = useMode(); @@ -77,7 +78,11 @@ const CollectionPortfolio = () => { handleSelectCollection, } = useSelectedCollection(); const { dialogState, openDialog, closeDialog } = useDialogState(); - const { columns, data } = collectionPortfolioData(selectedCollection?.cards); + // const { columns, data } = collectionPortfolioData(selectedCollection?.cards); + const { columns, data } = preparePortfolioTableData( + selectedCollection?.cards + ); + const [activeTab, setActiveTab] = useState(0); const tabs = []; if (selectedCollectionId) { @@ -90,8 +95,12 @@ const CollectionPortfolio = () => { }; const handleSelectAndShowCollection = useCallback( (collection) => { - handleSelectCollection(collection._id); // Assume this function sets the selectedCollectionId + handleSelectCollection(collection); // Assume this function sets the selectedCollectionId setActiveTab(1); // Switch to Portfolio View tab + console.log('DEBUG LOG, ', { + selectedCollectionId: selectedCollectionId, + selectedCollection: selectedCollection, + }); }, [handleSelectCollection] ); diff --git a/src/layout/collection/sub-components/TopCardsDisplayRow.jsx b/src/layout/collection/sub-components/TopCardsDisplayRow.jsx index 8e3a4db..94ace25 100644 --- a/src/layout/collection/sub-components/TopCardsDisplayRow.jsx +++ b/src/layout/collection/sub-components/TopCardsDisplayRow.jsx @@ -6,6 +6,7 @@ import { CardContent, Typography, Box, + useMediaQuery, } from '@mui/material'; import { Swiper, SwiperSlide } from 'swiper/react'; import 'swiper/css'; @@ -26,6 +27,8 @@ import CardDetailsContainer from '../../../components/cards/CardDetailsContainer export const TopCardsDisplayRow = () => { const { theme } = useMode(); + const isMobileView = useMediaQuery(theme.breakpoints.down('sm')); + const { selectedCollection } = useSelectedCollection(); const [activeCardIndex, setActiveCardIndex] = useState(0); @@ -45,6 +48,7 @@ export const TopCardsDisplayRow = () => { padding: theme.spacing(2), background: theme.palette.backgroundB.darker, borderRadius: theme.shape.borderRadius, + flexDirection: isMobileView ? 'column' : 'row', // Stack items vertically on mobile }} > { { - const { theme } = useMode(); - - return ( - - - - - {deck ? 'Edit Deck' : 'Create New Deck'} - - - - {' '} - - - ); -}; - -export default DeckEditor; diff --git a/src/layout/deck/DeckListItem.jsx b/src/layout/deck/DeckListItem.jsx index 6082779..f03477e 100644 --- a/src/layout/deck/DeckListItem.jsx +++ b/src/layout/deck/DeckListItem.jsx @@ -1,136 +1,3 @@ -// import { -// Box, -// Card, -// CardActionArea, -// CardContent, -// Chip, -// Collapse, -// Grid, -// Typography, -// useMediaQuery, -// } from '@mui/material'; -// import { memo, useCallback, useEffect, useRef, useState } from 'react'; -// import { useFormContext, useMode } from '../../context'; -// import useDeckManager from '../../context/MAIN_CONTEXT/DeckContext/useDeckManager'; -// import useSelectedDeck from '../../context/MAIN_CONTEXT/DeckContext/useSelectedDeck'; -// import useDialogState from '../../context/hooks/useDialogState'; -// import PropTypes from 'prop-types'; -// import DeckBuilderIcon from '../REUSABLE_COMPONENTS/icons/DeckBuilderIcon'; -// import MDBox from '../REUSABLE_COMPONENTS/MDBOX'; -// import DeckEditor from './DeckEditor'; -// import MDTypography from '../REUSABLE_COMPONENTS/MDTYPOGRAPHY/MDTypography'; -// import useGridItems from '../../context/hooks/useGridItems'; -// import useLocalStorage from '../../context/hooks/useLocalStorage'; -// import { useLoading } from '../../context/hooks/useLoading'; -// import { defaultValues } from '../../context/simplified_constants'; -// import RCWrappedIcon from '../REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIcon'; -// import RCInfoItem from '../REUSABLE_COMPONENTS/RCInfoItem'; -// import { roundToNearestTenth } from '../../context/Helpers'; - -// const DeckListItem = ({ -// deck, -// cards, -// handleSelectAndShowDeck, -// isEditPanelOpen, -// }) => { -// const { theme } = useMode(); -// const { deleteDeck, hasFetchedDecks } = useDeckManager(); -// const { handleSelectDeck, allDecks, deckHasBeenSelected } = useSelectedDeck(); -// const { isLoading } = useLoading(); -// const pageContext = 'Deck'; // Context to pass to GenericCard -// const cardDisplay = useGridItems({ -// itemsPerPage: 8, // Define as per your requirement -// cards: cards, -// isLoading: isLoading('fetchDecks'), // Pass the actual loading state -// hasFetched: hasFetchedDecks, // Pass the actual loading state -// allItems: allDecks, // Pass the actual loading state -// validSelection: deckHasBeenSelected, -// type: 'deck', -// pageContext, -// deckId: deck?._id, -// }); -// const handleSelection = useCallback( -// (deck) => { -// console.log('Deck Selected:', deck); -// // handleSelectDeck(deck); -// handleSelectAndShowDeck(deck); -// }, -// [handleSelectAndShowDeck] -// ); - -// return ( -// -// -// handleSelection(deck)} -// sx={{ -// display: 'flex', -// flexDirection: 'row', -// justifyContent: 'center', -// flexGrow: 1, -// }} -// > -// -// -// -// -// -// -// -// -// -// -// -// -// -// handleSelection(deck)} /> -// {isEditPanelOpen && cardDisplay} -// {/* {renderCardDisplayOnUpdate()} */} -// -// {/* {isEditPanelOpen && cardDisplay} */} -// -// ); -// }; - -// DeckListItem.displayName = 'DeckListItem'; - -// DeckListItem.propTypes = { -// deck: PropTypes.object.isRequired, -// isEditPanelOpen: PropTypes.bool.isRequired, -// onToggleEditPanel: PropTypes.func.isRequired, -// }; - -// export default DeckListItem; import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import { @@ -139,15 +6,42 @@ import { CardContent, Grid, Collapse, + useMediaQuery, } from '@mui/material'; import MDBox from '../REUSABLE_COMPONENTS/MDBOX'; import DeckBuilderIcon from '../REUSABLE_COMPONENTS/icons/DeckBuilderIcon'; import RCInfoItem from '../REUSABLE_COMPONENTS/RCInfoItem'; -import DeckEditor from './DeckEditor'; import RCWrappedIcon from '../REUSABLE_COMPONENTS/RCWRAPPEDICON/RCWrappedIcon'; import { roundToNearestTenth } from '../../context/Helpers'; import { useMode } from '../../context'; +import GenericCard from '../../components/cards/GenericCard'; +import DeckForm from '../../components/forms/DeckForm'; +import DeckOfCardsIcon from '../REUSABLE_COMPONENTS/icons/DeckOfCardsIcon'; +import MoneyIcon from '../REUSABLE_COMPONENTS/icons/MoneyIcon'; +const AnimatedInfoItem = ({ label, value, theme, delay }) => { + const [checked, setChecked] = useState(false); + useEffect(() => { + const timer = setTimeout(() => { + setChecked(true); + }, delay); + return () => clearTimeout(timer); + }, [delay]); + + return ( + + + + ); +}; const DeckListItem = ({ deck, cards, @@ -155,6 +49,10 @@ const DeckListItem = ({ isEditPanelOpen, }) => { const { theme } = useMode(); + const isMobile = useMediaQuery(theme.breakpoints.down('sm')); + const colors = theme.palette.chartTheme; + const greenAccent = colors.greenAccent.light; + const infoItems = [ { label: 'Name', value: deck?.name }, { label: 'Value', value: `$${roundToNearestTenth(deck?.totalPrice)}` }, @@ -184,60 +82,94 @@ const DeckListItem = ({ sx={{ display: 'flex', flexDirection: 'column', - justifyContent: 'center', + justifyContent: 'flex-start', height: '100%', - minHeight: '8rem', + minHeight: '4rem', + flexGrow: 1, }} > - - - + + + + + + {/* */} + + + + + + {infoItems.map((item, index) => ( + + ))} + + + - - {infoItems.map((item, index) => ( - - ))} -
+ + + {/* handleSelectAndShowDeck(deck)} /> */} + + {/* */} + + - handleSelectAndShowDeck(deck)} /> + + {/* Adjust the spacing as needed */} + + + {cards && + cards.length > 0 && + cards.map((card) => ( + + {/* Adjust breakpoints as needed for responsive design */} + + + ))} + + + ); }; -const AnimatedInfoItem = ({ label, value, theme, delay }) => { - const [checked, setChecked] = useState(false); - - useEffect(() => { - const timer = setTimeout(() => { - setChecked(true); - }, delay); - return () => clearTimeout(timer); - }, [delay]); - - return ( - - - - ); -}; - AnimatedInfoItem.propTypes = { label: PropTypes.string.isRequired, value: PropTypes.string.isRequired, diff --git a/src/layout/deck/DeckPageHeader.jsx b/src/layout/deck/DeckPageHeader.jsx index 31c9b13..19ae521 100644 --- a/src/layout/deck/DeckPageHeader.jsx +++ b/src/layout/deck/DeckPageHeader.jsx @@ -1,6 +1,5 @@ import React from 'react'; import styled from 'styled-components'; -import useSkeletonLoader from '../collection/collectionGrids/cards-datatable/useSkeletonLoader'; import { Box, Card, Grid } from '@mui/material'; import { useFormContext, useMode, useUserContext } from '../../context'; import SimpleCard from '../REUSABLE_COMPONENTS/unique/SimpleCard'; @@ -62,37 +61,30 @@ const DeckPageHeader = ({ openAddDeckDialog }) => { }} > - - - - - */} + + {/* */} + { + setCurrentForm('addDeckForm'); + openAddDeckDialog(); + console.log('openAddDeckDialog'); + }} > - { - setCurrentForm('addDeckForm'); - openAddDeckDialog(); - console.log('openAddDeckDialog'); - }} - > - Add New Deck - - + Add New Deck + ); diff --git a/src/layout/deck/index.jsx b/src/layout/deck/index.jsx index dba5459..877d06e 100644 --- a/src/layout/deck/index.jsx +++ b/src/layout/deck/index.jsx @@ -1,253 +1,90 @@ +import React, { useCallback, useEffect, useState } from 'react'; import { Card, Collapse, Grid, Tab, Tabs } from '@mui/material'; import { useMode } from '../../context'; import MDBox from '../REUSABLE_COMPONENTS/MDBOX'; -import PageLayout from '../REUSABLE_COMPONENTS/PageLayout'; -import SearchComponent from '../../components/forms/search/SearchComponent'; -import DashboardBox from '../REUSABLE_COMPONENTS/DashboardBox'; +import DashboardLayout from '../REUSABLE_COMPONENTS/DashBoardLayout'; import DeckPageHeader from './DeckPageHeader'; -import useDialogState from '../../context/hooks/useDialogState'; +import SearchComponent from '../../components/forms/search/SearchComponent'; import DeckDialog from '../../components/dialogs/DeckDialog'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import useDialogState from '../../context/hooks/useDialogState'; import useSelectedDeck from '../../context/MAIN_CONTEXT/DeckContext/useSelectedDeck'; -import useLocalStorage from '../../context/hooks/useLocalStorage'; -import { DeckListItemSkeleton } from '../REUSABLE_COMPONENTS/SkeletonVariants'; import DeckListItem from './DeckListItem'; -import useDeckManager from '../../context/MAIN_CONTEXT/DeckContext/useDeckManager'; -import RCHeader from '../REUSABLE_COMPONENTS/RCHeader'; -import DashboardLayout from '../REUSABLE_COMPONENTS/DashBoardLayout'; -import RCCardList from '../REUSABLE_COMPONENTS/RCCARDLIST/RCCardList'; -import FlexBetween from '../REUSABLE_COMPONENTS/FlexBetween'; +import DashboardBox from '../REUSABLE_COMPONENTS/DashboardBox'; const DeckBuilder = () => { const { theme } = useMode(); - const { selectedDeck, selectedDeckId, allDecks, updateDeck, allIds } = - useSelectedDeck(); - const { fetchDecks } = useDeckManager(); - const [showAllDecks, setShowAllDecks] = useState(false); - const { dialogState, openDialog, closeDialog } = useDialogState({ - isEditDeckDialogOpen: false, - isAddDeckDialogOpen: false, - }); - // const toggleDeckVisibility = () => setShowAllDecks(!showAllDecks); - const [decks, setDecks] = useLocalStorage('decks', {}); - const [deckList, setDeckList] = useState([]); - const [openEditorDeckId, setOpenEditorDeckId] = useState(null); - const [activeTab, setActiveTab] = useState(0); - const tabs = []; - if (selectedDeckId) { - tabs.push(); - } - const handleChange = (event, newValue) => { - if (newValue === 0 || (newValue === 1 && selectedDeckId)) { - setActiveTab(newValue); - } - }; - const handleChangeTab = (event, newValue) => { - setActiveTab(newValue); - }; - const handleSelectAndShowDeck = useCallback( - (deckId) => { - setOpenEditorDeckId(openEditorDeckId === deckId ? null : deckId); - setActiveTab(1); // Switch to Portfolio View tab - }, - [openEditorDeckId] - ); - const numDecks = allIds?.length || 0; - const nonSkeletonCount = useRef(0); - - useEffect(() => { - if (!decks?.byId) return; - - const minItems = 5; - const numRequired = minItems - numDecks > 0 ? minItems - numDecks : 0; - nonSkeletonCount.current = numDecks; + const { selectedDeck, allDecks, handleSelectDeck } = useSelectedDeck(); + const { dialogState, openDialog, closeDialog } = useDialogState(); - // Map decks to include an 'action' property - const allSkeletonDecks = [...Array(numRequired).keys()].map((index) => ({ - component: ( - - ), - action: null, // Skeletons don't have an action - })); + const [activeTab, setActiveTab] = useState(0); // Now this will be dynamic based on allDecks - const combinedDecks = allDecks - ?.map((deck, index) => ({ - component: ( - - - handleSelectAndShowDeck(deck)} - />{' '} - - - ), - action: () => handleSelectAndShowDeck(deck._id), // Here we include the action - key: deck?._id || `deck-${index}`, - name: deck?.name, - description: deck?.description, - tags: deck?.tags, - color: deck?.color, - cards: deck?.cards, - image: deck?.cards?.image, - })) - .concat(allSkeletonDecks); - - setDeckList(combinedDecks); - }, [decks, showAllDecks, openEditorDeckId, handleSelectAndShowDeck]); + // Function to handle changing tabs + const handleChangeTab = (event, newValue) => { + const selectedDeck = allDecks[newValue]; // Get the deck corresponding to the new tab index + handleSelectDeck(selectedDeck); // Pass the selected deck to handleSelectDeck + setActiveTab(newValue); // Update the active tab state + }; - const preparedDecksData = deckList?.map((deck, index) => ({ - ...deck, - action: () => handleSelectAndShowDeck(deck._id), - })); return ( - - - openDialog('isAddDeckDialogOpen')} - /> - - + - - - {selectedDeckId && } - - - {activeTab === 0 && - allDecks?.map((deck) => ( - - {selectedDeck && ( - setActiveTab(0)} - /> - )} - - ))} - {activeTab === 1 && ( - - deck._id === openEditorDeckId)} - isEditPanelOpen={true} - handleSelectAndShowDeck={() => setActiveTab(1)} + + openDialog('isAddDeckDialogOpen')} /> - - )} - - - - {/* - + + + {/* Tabs and Search Component in the same row */} - - + - openDialog('isAddDeckDialogOpen')} - decks={allDecks} - /> - + {allDecks.map((deck, index) => ( + + ))} + - - - - + + - - - - - - openDialog('isAddDeckDialogOpen') - } - decks={decks} - /> - - - - {tabs} - - {activeTab === 1 && - openEditorDeckId && - deckList?.map((deck, index) => ( - - - - handleSelectAndShowDeck(deck._id) - } - /> - - - ))} - - - + + {allDecks.map((deck, index) => ( + + { + handleSelectDeck(deck); + setActiveTab(index); + }} + cards={deck.cards} + /> + + ))} - - */} + + { closeDialog('isAddDeckDialogOpen')} - deckData={null} // Assuming new deck dialog doesn't need deck data + deckData={null} isNew={true} /> diff --git a/src/layout/AnimatedFeatureCard.jsx b/src/layout/sections/AnimatedFeatureCard.jsx similarity index 91% rename from src/layout/AnimatedFeatureCard.jsx rename to src/layout/sections/AnimatedFeatureCard.jsx index 7a2b15b..cb34716 100644 --- a/src/layout/AnimatedFeatureCard.jsx +++ b/src/layout/sections/AnimatedFeatureCard.jsx @@ -6,11 +6,11 @@ import { CardListItem, CardUnorderedList, FeatureCard, -} from '../pages/pageStyles/StyledComponents'; -import { useMode } from '../context'; -import MDButton from './REUSABLE_COMPONENTS/MDBUTTON'; -import SimpleButton from './REUSABLE_COMPONENTS/unique/SimpleButton'; -import uniqueTheme from './REUSABLE_COMPONENTS/unique/uniqueTheme'; +} from '../../pages/pageStyles/StyledComponents'; +import { useMode } from '../../context'; +import MDButton from '../REUSABLE_COMPONENTS/MDBUTTON'; +import SimpleButton from '../REUSABLE_COMPONENTS/unique/SimpleButton'; +import uniqueTheme from '../REUSABLE_COMPONENTS/unique/uniqueTheme'; const AnimatedBox = animated(Box); diff --git a/src/layout/sections/FeatureCardsSection.jsx b/src/layout/sections/FeatureCardsSection.jsx index 7597a0e..afa51b5 100644 --- a/src/layout/sections/FeatureCardsSection.jsx +++ b/src/layout/sections/FeatureCardsSection.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { Grid } from '@mui/material'; import { useMediaQuery } from '@mui/material'; -import { AnimatedFeatureCard } from '../../layout/AnimatedFeatureCard'; +import { AnimatedFeatureCard } from './AnimatedFeatureCard'; import { useModalContext } from '../../context/UTILITIES_CONTEXT/ModalContext/ModalContext'; import { useMode } from '../../context'; import pages from '../../data/pages.json'; diff --git a/src/layout/sections/HeroSection.jsx b/src/layout/sections/HeroSection.jsx index e8b0aec..6ec9d71 100644 --- a/src/layout/sections/HeroSection.jsx +++ b/src/layout/sections/HeroSection.jsx @@ -30,12 +30,10 @@ import HeroSwiper from './HeroSwiper'; import FlexBetween from '../REUSABLE_COMPONENTS/FlexBetween'; import RCHeader from '../REUSABLE_COMPONENTS/RCHeader'; import styled from 'styled-components'; -import { ChartArea } from '../../pages/pageStyles/StyledComponents'; import { useCardStoreHook } from '../../context/hooks/useCardStore'; import useLocalStorage from '../../context/hooks/useLocalStorage'; -import { AspectRatio } from '@mui/joy'; import { useLoading } from '../../context/hooks/useLoading'; -import useSkeletonLoader from '../collection/collectionGrids/cards-datatable/useSkeletonLoader'; +import useSkeletonLoader from '../REUSABLE_COMPONENTS/useSkeletonLoader'; import { ResponsiveContainer, CartesianGrid, @@ -73,36 +71,6 @@ const HeroSection = () => { image: placeHolder, })); const cards = [...randomCards, ...defaultCards]; - // const swiperConfig = { - // effect: 'coverflow', - // grabCursor: true, - // centeredSlides: true, - // loop: true, - // resizeObserver: true, - // spaceBetween: 10, - // coverflowEffect: { - // stretch: 0, - // modifier: 1, - // rotate: 0, - // depth: 200, - // slideShadows: false, - // }, - // autoplay: { - // delay: 2500, - // disableOnInteraction: false, - // }, - // modules: [EffectCoverflow, Pagination, Navigation, Autoplay], - // scrollbar: { - // el: '.swiper-scrollbar', - // draggable: true, - // }, - // navigation: { - // nextEl: '.swiper-button-next', - // prevEl: '.swiper-button-prev', - // clickable: true, - // }, - // className: 'swiper_container', - // }; useEffect(() => setShouldShow(true), []); useEffect(() => fetchRandomCardsAndSet(), []); @@ -124,20 +92,17 @@ const HeroSection = () => { position: 'relative', minHeight: isMobileView ? 'calc(100vh - 64px)' : 'calc(100vh - 64px)', flexDirection: isMobileView ? 'column' : 'row', - // flexDirection: 'column', }} > { > - {/* */} - {/* */} - {/* */} diff --git a/src/layout/sections/HeroSwiper.jsx b/src/layout/sections/HeroSwiper.jsx index 40b80cb..6edae33 100644 --- a/src/layout/sections/HeroSwiper.jsx +++ b/src/layout/sections/HeroSwiper.jsx @@ -80,12 +80,9 @@ const HeroSwiper = ({ display: 'flex', justifyContent: isMobileView ? 'center' : 'flex-start', alignItems: isMobileView ? 'center' : 'center', - // position: 'relative', position: isMobileView ? 'absolute' : 'relative', - // height: isMobileView ? '100vh' : null, height: isMobileView ? 'calc(100vh - 64px)' : null, border: 'none', - // background: '#2d2d34', }} >