diff --git a/Frontend/src/components/common/CustomModal.jsx b/Frontend/src/components/common/CustomModal.jsx new file mode 100644 index 00000000..d53bd866 --- /dev/null +++ b/Frontend/src/components/common/CustomModal.jsx @@ -0,0 +1,76 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { + Box, + Modal, + Container, + Typography, IconButton +} from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; + +/** + * Drawer navigation menu throughout the app + * @param props + * @returns {JSX.Element} + * @constructor + */ +const CustomModal = (props) => { + return ( + props.handleClose()} + aria-labelledby={props.labelledby} + > + + + + {props.modalTitle} + + props.handleClose()} + className='px-0 py-1 align-self-start' + > + + + + + {props.modalBody ? props.modalBody() : null} + {props.modalButton()} + + + ); +} + +const style = { + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: { + xs: '70vw', + sm: '55vw', + md: '40vw', + lg: '30vw' + }, + minHeight: '10vh', + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + backgroundColor: 'background.paper', + border: '2px solid #000', + boxShadow: 24, + padding: '1.5rem' +}; + +CustomModal.propTypes = { + open: PropTypes.bool, + handleClose: PropTypes.func, + labelledby: PropTypes.string, + modalTitle: PropTypes.string, + modalBody: PropTypes.func, + modalButton: PropTypes.func, +}; + +export default CustomModal; \ No newline at end of file diff --git a/Frontend/src/components/common/CustomTable.jsx b/Frontend/src/components/common/CustomTable.jsx new file mode 100644 index 00000000..4be0f2a6 --- /dev/null +++ b/Frontend/src/components/common/CustomTable.jsx @@ -0,0 +1,131 @@ +import React, {useState} from 'react'; +import { + TableContainer, + Paper, + Table, + TableBody, + TableRow, + TableCell, + Avatar, + Typography +} from '@mui/material'; +import PropTypes from 'prop-types'; +import DeleteIcon from '@mui/icons-material/Delete'; +import DropdownMenu from "../screens/WatchLists/DropdownMenu"; + + +/** + * Table to show the different assets in watchlist + * @returns {JSX.Element} + * @constructor + */ +const CustomTable = (props) => { + const [listDropdownIndex, setListDropdownIndex] = useState(0); + + return ( + + + + {props.assetsArray[props.selectedListIndex].map((row, index) => ( + + + + + + + {row.name} + + + + + {row.price} + + + + + {row.change} + + + + ]} + functionOptions={[ + () => {} + ]} + /> + + + ))} + +
+
+ ); +} + +CustomTable.propTypes = { + assetsArray: PropTypes.array, + selectedListIndex: PropTypes.number, + watchListsArray: PropTypes.array, + setWatchListsArray: PropTypes.func, +}; + +export default CustomTable; \ No newline at end of file diff --git a/Frontend/src/components/common/SearchField.jsx b/Frontend/src/components/common/SearchField.jsx new file mode 100644 index 00000000..66234cc3 --- /dev/null +++ b/Frontend/src/components/common/SearchField.jsx @@ -0,0 +1,54 @@ +import React from 'react'; +import TextField from '@mui/material/TextField'; +import {Container, InputAdornment, IconButton} from "@mui/material"; +import SearchIcon from '@mui/icons-material/Search'; + +//TODO: function for the search +const search = () => console.log('Searching for asset'); + +/** + * Component for the search field in the screens' header + * @returns {JSX.Element} + * @constructor + */ +const SearchField = () => { + return ( + + + + + + + ), + }} + /> + + ); +} + +export default SearchField; \ No newline at end of file diff --git a/Frontend/src/components/common/SideNavLeft.jsx b/Frontend/src/components/common/SideNavLeft.jsx new file mode 100644 index 00000000..136b5110 --- /dev/null +++ b/Frontend/src/components/common/SideNavLeft.jsx @@ -0,0 +1,143 @@ +import React from 'react'; +import {Link} from 'react-router-dom'; +import PropTypes from 'prop-types'; +import { + Box, + Drawer, + List, + ListItem, + ListItemIcon, + ListItemText +} from '@mui/material'; +import HomeIcon from '@mui/icons-material/Home'; +import AutoGraphIcon from '@mui/icons-material/AutoGraph'; +import ShutterSpeedIcon from '@mui/icons-material/ShutterSpeed'; +import SettingsIcon from '@mui/icons-material/Settings'; + +const drawerWidth = 12; // This is the value in rem units, for responsiveness +const routesArray = [ + {routeName: 'Home', path: '/', icon: }, + {routeName: 'Dashboard', path: '/dashboard', icon: }, + {routeName: 'Watchlists', path: '/watchlists', icon: }, + {routeName: 'Settings', path: '/settings', icon: }, +]; + +/** + * Drawer navigation menu throughout the app + * @param props + * @returns {JSX.Element} + * @constructor + */ +const SideNavLeft = (props) => { + const {window} = props; + + const handleNavLinkClick = () => { + props.setOpenInMobile(false) + }; + + const drawer = (routesArray) => ( + + + Application logo +

Portfolio

+ {routesArray.map((element, index) => ( + handleNavLinkClick()} + style={{textDecoration: 'none',}} + > + + + {element.icon} + + + + + ))} +
+
+ ); + + const container = window !== undefined ? () => window().document.body : undefined; + + return ( + + + {drawer(routesArray)} + + + {drawer(routesArray)} + + + ); +} + +SideNavLeft.propTypes = { + window: PropTypes.func, + openInMobile: PropTypes.bool, + setOpenInMobile: PropTypes.func, + handleDrawerToggle: PropTypes.func, + selectedNavLinkIndex: PropTypes.number +}; + +export default SideNavLeft; \ No newline at end of file diff --git a/Frontend/src/components/common/index.jsx b/Frontend/src/components/common/index.jsx new file mode 100644 index 00000000..920fa81f --- /dev/null +++ b/Frontend/src/components/common/index.jsx @@ -0,0 +1,11 @@ +import SideNavLeft from './SideNavLeft'; +import SearchField from './SearchField'; +import CustomModal from './CustomModal'; +import CustomTable from './CustomTable'; + +export { + SideNavLeft, + SearchField, + CustomModal, + CustomTable +} \ No newline at end of file diff --git a/Frontend/src/components/screens/WatchLists/AssetsList.jsx b/Frontend/src/components/screens/WatchLists/AssetsList.jsx index 176b4954..c5eb5352 100644 --- a/Frontend/src/components/screens/WatchLists/AssetsList.jsx +++ b/Frontend/src/components/screens/WatchLists/AssetsList.jsx @@ -10,7 +10,7 @@ import { } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; import PropTypes from 'prop-types'; -import CustomTable from '../../common/CustomTable'; +import {CustomTable} from '../../common/index'; const createData = (name, price, change) => { diff --git a/Frontend/src/components/screens/WatchLists/DropdownMenu.jsx b/Frontend/src/components/screens/WatchLists/DropdownMenu.jsx new file mode 100644 index 00000000..2148fd4e --- /dev/null +++ b/Frontend/src/components/screens/WatchLists/DropdownMenu.jsx @@ -0,0 +1,107 @@ +import React, {useState} from 'react'; +import PropTypes from 'prop-types'; +import { + Button, + Menu, + MenuItem, + Divider, + Typography, + Container +} from '@mui/material'; +import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; + +/** + * Component to display a dropdown with different actions + * @param props + * @returns {JSX.Element} + * @constructor + */ +const DropdownMenu = (props) => { + const [anchorEl, setAnchorEl] = useState(null); + const [open, setOpen] = useState(false); + + const handleClick = (event) => { + setOpen(true); + setAnchorEl(event.currentTarget); + props.setListDropdownIndex(props.listIndex); + }; + + const handleClose = () => { + setAnchorEl(null); + setOpen(false); + }; + + const onOptionClick = index => { + handleClose(); + props.functionOptions[index](); + }; + + return ( + + + + {props.menuOptions.map((option, index) => ( + + onOptionClick(index)} + > + + {props.iconOptions[index]} {option} + + + { + props.menuOptions.length - 1 === index + ? null + : + } + + ))} + + + ); +} + +DropdownMenu.propTypes = { + listIndex: PropTypes.number, + selectedListIndex: PropTypes.number, + listName: PropTypes.string, + setListDropdownIndex: PropTypes.func, + menuOptions: PropTypes.array, + iconOptions: PropTypes.array, + functionOptions: PropTypes.array +}; + +export default DropdownMenu; \ No newline at end of file