Skip to content

Commit

Permalink
55 accounts page basic functionality (#62)
Browse files Browse the repository at this point in the history
* added pending/all accounts table with admin/student tabs functionality

* move accounts pages to pages directory

* fixed minor import bug and added accounts page to navbar

---------

Co-authored-by: Cheryl Chen <[email protected]>
Co-authored-by: Cheryl Chen <[email protected]>
Co-authored-by: ThatMegamind <[email protected]>
  • Loading branch information
4 people authored Mar 21, 2024
1 parent db42b46 commit 0e5bd9a
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -92,6 +93,13 @@ const App = () => {
roles={[ADMIN_ROLE]}
/>
} />
<Route exact path='/accounts' element={
<ProtectedRoute
Component={Accounts}
redirectPath="/login"
roles={[ADMIN_ROLE]}
/>
} />
</Route>
</Routes>
</Router>
Expand Down
67 changes: 67 additions & 0 deletions src/components/Accounts/ApprovedAccounts.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<Box>
<TableContainer>
<Table variant='simple'>
<Thead>
<Tr>
<Th width="5%"><Checkbox isDisabled /></Th>
<Th>Name</Th>
<Th>Email</Th>
<Th>Deactivate</Th>
</Tr>
</Thead>
<Tbody>
{
approvedAccounts.map((account, i) => (
accountType === account.type ? (
<Tr key={i}>
<Td><Checkbox></Checkbox></Td>
<Td>{account.firstName} {account.lastName}</Td>
<Td>{account.email}</Td>
<Td>
<Button onClick={() => { handleDeleteClick(account.id) }} size='sm' variant='outline'><CloseIcon w={3} h={3} color='gray'/></Button>
</Td>
</Tr>
) : (
<></>
)
))
}
</Tbody>
</Table>
</TableContainer>
<DeleteAccountModal isOpen={isDeleteOpen} onClose={onDeleteClose} deleteItemId={deleteItemId} />
</Box>
)
}

ApprovedAccounts.propTypes = {
accountType: PropTypes.string.isRequired,
};

export default ApprovedAccounts;
46 changes: 46 additions & 0 deletions src/components/Accounts/DeleteAccountModal.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Deactivate Account(s)?</ModalHeader>
<ModalCloseButton />
<ModalBody>Are you sure? You cannot undo this action afterwards.</ModalBody>
<ModalFooter gap='3'>
<Button onClick={onClose}>Cancel</Button>
<Button onClick={() => handleConfirmDelete(deleteItemId)} colorScheme='red'>Delete</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
};

DeleteAccountModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
deleteItemId: PropTypes.string.isRequired,
};

export default DeleteAccountModal;
74 changes: 74 additions & 0 deletions src/components/Accounts/PendingAccounts.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<TableContainer>
<Table variant='simple'>
<Thead>
<Tr>
<Th width="5%"><Checkbox isDisabled /></Th>
<Th>Name</Th>
<Th>Email</Th>
<Th>Action</Th>
</Tr>
</Thead>
<Tbody>
{
pendingAccounts.map((account, i) => (
accountType === account.type ? (
<Tr key={i}>
<Td><Checkbox></Checkbox></Td>
<Td>{account.firstName} {account.lastName}</Td>
<Td>{account.email}</Td>
<Td>
<Button onClick={() => { handleApproveUser(account.id) }} mr={3} colorScheme='blue'>Accept</Button>
<Button onClick={() => { handleDeleteUser(account.id) }}>Decline</Button>
</Td>
</Tr>
) : (
<></>
)
)
)
}
</Tbody>
</Table>
</TableContainer>
)
}

PendingAccounts.propTypes = {
accountType: PropTypes.string.isRequired,
};

export default PendingAccounts;
1 change: 1 addition & 0 deletions src/components/Navbar/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const Navbar = ({ hasLoaded, isAdmin }) => {
<Image src="src/Logo.svg" marginRight={'48px'}></Image>
{makeNavTabs('Schedule', '/publishedSchedule')}
{makeNavTabs('Catalog', '/catalog')}
{makeNavTabs('Accounts', '/accounts')}
</Flex>
</HStack>
<Flex alignSelf={'right'} marginLeft={'auto'}>
Expand Down
33 changes: 33 additions & 0 deletions src/pages/Accounts/Accounts.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<Box>
<Tabs>
<TabList>
<Tab>Admins</Tab>
<Tab>Students</Tab>
</TabList>

<TabPanels>
<TabPanel>
<Heading>Pending Accounts</Heading>
<PendingAccounts accountType="admin" />
<Heading>Accounts</Heading>
<ApprovedAccounts accountType="admin" />
</TabPanel>
<TabPanel>
<Heading>Pending Accounts</Heading>
<PendingAccounts accountType="student" />
<Heading>Accounts</Heading>
<ApprovedAccounts accountType="student" />
</TabPanel>
</TabPanels>
</Tabs>
</Box>
);
}

export default Accounts;

0 comments on commit 0e5bd9a

Please sign in to comment.