diff --git a/src/App.jsx b/src/App.jsx index 7f6839b..5ec7bfe 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -16,6 +16,7 @@ import Playground from './pages/Playground/Playground'; import Planner from './pages/Planner/Planner'; import Navbar from './components/Navbar/Navbar'; import NotificationSandbox from './pages/NotificationSandbox/NotificationSandbox'; +import Accounts from './pages/Accounts/Accounts'; import { AuthContextProvider, useAuthContext } from './common/AuthContext'; const { ADMIN_ROLE, USER_ROLE } = AUTH_ROLES.AUTH_ROLES; @@ -92,6 +93,13 @@ const App = () => { roles={[ADMIN_ROLE]} /> } /> + + } /> diff --git a/src/components/Accounts/ApprovedAccounts.jsx b/src/components/Accounts/ApprovedAccounts.jsx new file mode 100644 index 0000000..927c1b4 --- /dev/null +++ b/src/components/Accounts/ApprovedAccounts.jsx @@ -0,0 +1,67 @@ +import { NPOBackend } from '../../utils/auth_utils.js'; +import { useEffect, useState } from 'react'; +import { Box, Table, Thead, Tbody, Tr, Th, Td, TableContainer, Button, Checkbox, useDisclosure } from '@chakra-ui/react' +import { CloseIcon } from '@chakra-ui/icons' +import DeleteAccountModal from './DeleteAccountModal.jsx'; +import PropTypes from 'prop-types'; + +const ApprovedAccounts = ( {accountType} ) => { + const [approvedAccounts, setApprovedAccounts] = useState([]); + const { isOpen: isDeleteOpen, onOpen: onDeleteOpen, onClose: onDeleteClose } = useDisclosure(); + const [deleteItemId, setDeleteItemId] = useState(""); + + useEffect(() => { + const renderTable = async () => { + const { data } = await NPOBackend.get('/users/approved-accounts'); + setApprovedAccounts(data); + }; + renderTable(); + }, [approvedAccounts]) + + const handleDeleteClick = id => { + setDeleteItemId(id); + onDeleteOpen(); + } + + return ( + + + + + + + + + + + + + { + approvedAccounts.map((account, i) => ( + accountType === account.type ? ( + + + + + + + ) : ( + <> + ) + )) + } + +
NameEmailDeactivate
{account.firstName} {account.lastName}{account.email} + +
+
+ +
+ ) +} + +ApprovedAccounts.propTypes = { + accountType: PropTypes.string.isRequired, +}; + +export default ApprovedAccounts; \ No newline at end of file diff --git a/src/components/Accounts/DeleteAccountModal.jsx b/src/components/Accounts/DeleteAccountModal.jsx new file mode 100644 index 0000000..040ef34 --- /dev/null +++ b/src/components/Accounts/DeleteAccountModal.jsx @@ -0,0 +1,46 @@ +import PropTypes from 'prop-types'; +import { + Button, + Modal, + ModalBody, + ModalContent, + ModalOverlay, + ModalHeader, + ModalCloseButton, + ModalFooter, +} from '@chakra-ui/react'; +import { NPOBackend } from '../../utils/auth_utils.js'; + +const DeleteAccountModal = ({ isOpen, onClose, deleteItemId}) => { + const handleConfirmDelete = async idToDelete => { + try { + await NPOBackend.delete(`/users/${idToDelete}`); + onClose(); + } catch (error) { + console.error(error); + } + }; + + return ( + + + + Deactivate Account(s)? + + Are you sure? You cannot undo this action afterwards. + + + + + + + ); +}; + +DeleteAccountModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, + deleteItemId: PropTypes.string.isRequired, +}; + +export default DeleteAccountModal; diff --git a/src/components/Accounts/PendingAccounts.jsx b/src/components/Accounts/PendingAccounts.jsx new file mode 100644 index 0000000..bd775ae --- /dev/null +++ b/src/components/Accounts/PendingAccounts.jsx @@ -0,0 +1,74 @@ +import { NPOBackend } from '../../utils/auth_utils.js'; +import { useEffect, useState } from 'react'; +import { Table, Thead, Tbody, Tr, Th, Td, TableContainer, Button } from '@chakra-ui/react' +import { Checkbox } from '@chakra-ui/react' +import PropTypes from 'prop-types'; + +const PendingAccounts = ( {accountType} ) => { + const [pendingAccounts, setPendingAccounts] = useState([]); + + useEffect(() => { + const renderTable = async () => { + const { data } = await NPOBackend.get('/users/pending-accounts'); + setPendingAccounts(data); + }; + renderTable(); + }, [pendingAccounts]) + + const handleApproveUser = async (id) => { + try { + await NPOBackend.put(`/users/approve/${id}`); + } catch (error) { + console.log(error); + } + } + + const handleDeleteUser = async (id) => { + try { + await NPOBackend.delete(`/users/${id}`); + } catch (error) { + console.log(error); + } + } + + return ( + + + + + + + + + + + + { + pendingAccounts.map((account, i) => ( + accountType === account.type ? ( + + + + + + + ) : ( + <> + ) + ) + ) + } + +
NameEmailAction
{account.firstName} {account.lastName}{account.email} + + +
+
+ ) +} + +PendingAccounts.propTypes = { + accountType: PropTypes.string.isRequired, +}; + +export default PendingAccounts; \ No newline at end of file diff --git a/src/components/Navbar/Navbar.jsx b/src/components/Navbar/Navbar.jsx index 4b94714..038b201 100644 --- a/src/components/Navbar/Navbar.jsx +++ b/src/components/Navbar/Navbar.jsx @@ -51,6 +51,7 @@ const Navbar = ({ hasLoaded, isAdmin }) => { {makeNavTabs('Schedule', '/publishedSchedule')} {makeNavTabs('Catalog', '/catalog')} + {makeNavTabs('Accounts', '/accounts')} diff --git a/src/pages/Accounts/Accounts.jsx b/src/pages/Accounts/Accounts.jsx new file mode 100644 index 0000000..6b65ef8 --- /dev/null +++ b/src/pages/Accounts/Accounts.jsx @@ -0,0 +1,33 @@ +import PendingAccounts from "../../components/Accounts/PendingAccounts"; +import ApprovedAccounts from "../../components/Accounts/ApprovedAccounts"; +import { Box, Heading, Tabs, TabList, TabPanels, Tab, TabPanel} from '@chakra-ui/react' + +const Accounts = () => { + return ( + + + + Admins + Students + + + + + Pending Accounts + + Accounts + + + + Pending Accounts + + Accounts + + + + + + ); +} + +export default Accounts; \ No newline at end of file