Removed Groups
This commit is contained in:
parent
a1a3ca38c7
commit
3ae95cef00
18 changed files with 74 additions and 431 deletions
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||
|
||||
import Header from './components/Header';
|
||||
import MainPage from './components/MainPage';
|
||||
|
||||
import Form from './components/Form';
|
||||
import Login from './components/Login';
|
||||
|
|
@ -13,9 +14,6 @@ import Reset from './components/Reset';
|
|||
import JoinedOrgs from './components/JoinedOrgs';
|
||||
import OrgDashboard from './components/OrgDashboard';
|
||||
|
||||
import OwnedGroups from './components/OwnedGroups';
|
||||
import GroupDashboard from './componenets/GroupDashboard';
|
||||
|
||||
import NotFound from './components/NotFound';
|
||||
|
||||
function App() {
|
||||
|
|
@ -24,7 +22,7 @@ function App() {
|
|||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path='' element={<Header />}>
|
||||
<Route index />
|
||||
<Route index element={<MainPage />} />
|
||||
|
||||
<Route path='login' element={<Login />} />
|
||||
<Route path='register' element={<Register />} />
|
||||
|
|
@ -34,16 +32,11 @@ function App() {
|
|||
<Route path=':id' element={<Reset />} />
|
||||
</Route>
|
||||
|
||||
<Route path='org'>
|
||||
<Route path=''>
|
||||
<Route index element={<JoinedOrgs />} />
|
||||
<Route path=':id' element={<OrgDashboard />} />
|
||||
</Route>
|
||||
|
||||
<Route path='group'>
|
||||
<Route index element={<OwnedGroups />} />
|
||||
<Route path=':id' element={<GroupDashboard />} />
|
||||
</Route>
|
||||
|
||||
<Route path='*' element={<NotFound />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import axios from 'axios';
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
import { Typography, Grid, Stack, Box } from '@mui/material';
|
||||
|
||||
import Dashboard from './Dashboard';
|
||||
|
||||
function GroupDashboard() {
|
||||
const navigate = useNavigate();
|
||||
const { groupID } = useParams();
|
||||
|
||||
const [group, setGroup] = useState({
|
||||
groupID: '',
|
||||
groupName: '',
|
||||
groupMembers: [],
|
||||
createdAt: '',
|
||||
});
|
||||
const [rows, setRows] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
async function getData() {
|
||||
await axios
|
||||
.get(
|
||||
`${
|
||||
process.env.DOMAIN_ROOT
|
||||
}/group/${groupID}?token=${Cookies.get('token')}`
|
||||
)
|
||||
.then((response) => {
|
||||
const res = response.data;
|
||||
setGroup(() => {
|
||||
return {
|
||||
groupID: res.groupID,
|
||||
groupName: res.groupName,
|
||||
groupMembers: res.groupMembers,
|
||||
};
|
||||
});
|
||||
|
||||
const groupMembers = res.groupMembers.map(
|
||||
(member, index) => {
|
||||
return {
|
||||
id: index,
|
||||
firstName: member.firstName,
|
||||
lastName: member.lastName,
|
||||
nickname: member.nickname,
|
||||
namePronounciation: member.pronounciation,
|
||||
pronouns: member.pronouns,
|
||||
email: member.email,
|
||||
};
|
||||
}
|
||||
);
|
||||
setRows(() => groupMembers);
|
||||
})
|
||||
.catch((error) => {
|
||||
navigate('/');
|
||||
});
|
||||
}
|
||||
|
||||
getData();
|
||||
});
|
||||
|
||||
return (
|
||||
<Dashboard rows={rows}>
|
||||
<Typography variant='h6'>Groups/{group.groupName}</Typography>
|
||||
<Box sx={{ marginTop: '1vh' }}>
|
||||
<Grid container columns={{ xs: 3, md: 12 }}>
|
||||
<Grid item xs={3}>
|
||||
<Stack spacing={2}>
|
||||
<Typography variant='body1'>
|
||||
Group ID: {group.groupID}
|
||||
</Typography>
|
||||
<Typography variant='body1'>
|
||||
Members: {group.groupMembers.length}
|
||||
</Typography>
|
||||
<Typography variant='body1'>
|
||||
Created On: {group.createdAt}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Dashboard>
|
||||
);
|
||||
}
|
||||
|
||||
export default GroupDashboard;
|
||||
|
|
@ -8,18 +8,20 @@ import { Paper, Typography, Box, Stack } from '@mui/material';
|
|||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
function OrgUnit({ org }) {
|
||||
const { orgID, orgName, memberCount, orgCreatedAt } = org;
|
||||
const { orgID, orgName, memberCount, createdAt } = org;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Link to={orgID}>Name: {orgName}</Link>
|
||||
<Typography variant='h6'>
|
||||
<Link to={orgID}>Name: {orgName}</Link>
|
||||
</Typography>
|
||||
<Box>
|
||||
<Stack spacing={2} direction={{ xs: 'column', md: 'row' }}>
|
||||
<Typography variant='body1'>
|
||||
Members: {memberCount}
|
||||
</Typography>
|
||||
<Typography variant='body1'>
|
||||
Created On: {orgCreatedAt}
|
||||
Created On: {createdAt}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
|
@ -47,7 +49,7 @@ function JoinedOrgs() {
|
|||
orgID: org.orgID,
|
||||
orgName: org.orgName,
|
||||
memberCount: org.memberCount,
|
||||
orgCreatedAt: org.createdAt,
|
||||
createdAt: org.createdAt,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
|
|
|||
65
client/src/components/MainPage.jsx
Normal file
65
client/src/components/MainPage.jsx
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
import { Paper, Button, Typography, Stack, Box } from '@mui/material';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
function MainPage() {
|
||||
const theme = useTheme();
|
||||
|
||||
const [org, setOrg] = useState({});
|
||||
|
||||
const linkStyle = { textDecoration: 'none', color: 'inherit' };
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Paper
|
||||
sx={{
|
||||
...theme.typography.body2,
|
||||
padding: '2vh',
|
||||
color: theme.palette.text.secondary,
|
||||
flexGrow: 1,
|
||||
height: '30vh',
|
||||
margin: '2vh',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
{org && (
|
||||
<React.Fragment>
|
||||
<Typography variant='h6'>
|
||||
<Link to={`orgs/${org.orgID}`} style={linkStyle}>
|
||||
Your Organization: {org.orgName}
|
||||
</Link>
|
||||
</Typography>
|
||||
<Box margin={2}>
|
||||
<Stack spacing={2}>
|
||||
<Typography variant='body1'>
|
||||
Members: {org.memberCount}
|
||||
</Typography>
|
||||
<Typography variant='body1'>
|
||||
Created On: {org.createdAt}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Paper>
|
||||
<Paper
|
||||
sx={{
|
||||
...theme.typography.body2,
|
||||
padding: '2vh',
|
||||
textAlign: 'center',
|
||||
color: theme.palette.text.secondary,
|
||||
flexGrow: 1,
|
||||
height: '57vh',
|
||||
margin: '2vh',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
></Paper>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default MainPage;
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import axios from 'axios';
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
import { Paper, Typography, Box, Stack } from '@mui/material';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
function GroupUnit({ group }) {
|
||||
const { groupID, groupName, memberCount, groupCreatedAt } = group;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Link to={groupID}>Name: {groupName}</Link>
|
||||
<Box>
|
||||
<Stack spacing={2} direction={{ xs: 'column', md: 'row' }}>
|
||||
<Typography variant='body1'>
|
||||
Members: {memberCount}
|
||||
</Typography>
|
||||
<Typography variant='body1'>
|
||||
Created On: {groupCreatedAt}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
function JoinedOrgs() {
|
||||
const [groups, setGroups] = useState([]);
|
||||
const theme = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
async function getGroups() {
|
||||
axios
|
||||
.get(
|
||||
`${process.env.DOMAIN_ROOT}/auth/orgs?token=${Cookies.get(
|
||||
'token'
|
||||
)}`
|
||||
)
|
||||
.then((response) => {
|
||||
setGroups(() =>
|
||||
response.data.map((group) => {
|
||||
return {
|
||||
groupID: group.groupID,
|
||||
groupName: group.groupName,
|
||||
memberCount: group.memberCount,
|
||||
groupCreatedAt: group.createdAt,
|
||||
};
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getGroups();
|
||||
});
|
||||
|
||||
return (
|
||||
<Paper
|
||||
sx={{
|
||||
...theme.typography.body2,
|
||||
padding: '2vh',
|
||||
color: theme.palette.text.secondary,
|
||||
flexGrow: 1,
|
||||
height: '89vh',
|
||||
margin: '2vh',
|
||||
}}
|
||||
>
|
||||
<Typography variant='h6'>Groups</Typography>
|
||||
<Box sx={{ overflowY: 'auto' }}>
|
||||
{groups.map((group) => (
|
||||
<GroupUnit group={group} />
|
||||
))}
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
export default JoinedOrgs;
|
||||
|
|
@ -23,7 +23,6 @@ app.use(express.static(path.join(__dirname, 'public')));
|
|||
app.use(cors());
|
||||
|
||||
app.use('/api/auth', authRouter);
|
||||
app.use('/api/group', groupRouter);
|
||||
app.use('/api/org', orgRouter);
|
||||
|
||||
app.use(express.static(path.join(__dirname, '../client/build')));
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
await queryInterface.createTable('Groups', {
|
||||
groupID: {
|
||||
type: Sequelize.UUID,
|
||||
primaryKey: true,
|
||||
},
|
||||
groupName: {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
createdAt: {
|
||||
type: Sequelize.DATE,
|
||||
},
|
||||
updatedAt: {
|
||||
type: Sequelize.DATE,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async down(queryInterface, Sequelize) {
|
||||
await queryInterface.dropTable('Groups');
|
||||
},
|
||||
};
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
await queryInterface.addColumn('Groups', 'ownerID', {
|
||||
type: Sequelize.UUID,
|
||||
references: {
|
||||
model: 'Users',
|
||||
key: 'userID',
|
||||
},
|
||||
onUpdate: 'CASCADE',
|
||||
onDelete: 'SET NULL',
|
||||
});
|
||||
},
|
||||
|
||||
async down(queryInterface, Sequelize) {
|
||||
await queryInterface.removeColumn('Groups', 'ownerID');
|
||||
},
|
||||
};
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
await queryInterface.createTable('GroupMembers', {
|
||||
groupID: {
|
||||
type: Sequelize.UUID,
|
||||
primaryKey: true,
|
||||
},
|
||||
ownerID: {
|
||||
type: Sequelize.UUID,
|
||||
primaryKey: true,
|
||||
},
|
||||
createdAt: {
|
||||
allowNull: false,
|
||||
type: Sequelize.DATE,
|
||||
},
|
||||
updatedAt: {
|
||||
allowNull: false,
|
||||
type: Sequelize.DATE,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async down(queryInterface, Sequelize) {
|
||||
await queryInterface.dropTable('GroupMembers');
|
||||
},
|
||||
};
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
const { Model } = require('sequelize');
|
||||
|
||||
module.exports = (sequelize, DataTypes) => {
|
||||
class Group extends Model {
|
||||
static associate(models) {
|
||||
Group.belongsTo(models.User, {
|
||||
as: 'groupOwner',
|
||||
foreignKey: 'ownerID',
|
||||
onDelete: 'CASCADE',
|
||||
});
|
||||
Group.belongsToMany(models.User, {
|
||||
as: 'groupMembers',
|
||||
through: 'GroupMembers',
|
||||
foreignKey: 'groupID',
|
||||
onDelete: 'CASCADE',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Group.init(
|
||||
{
|
||||
groupID: {
|
||||
type: DataTypes.UUID,
|
||||
primaryKey: true,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
},
|
||||
groupName: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
createdAt: {
|
||||
type: DataTypes.DATE,
|
||||
},
|
||||
},
|
||||
{ sequelize }
|
||||
);
|
||||
|
||||
return Group;
|
||||
};
|
||||
|
|
@ -11,16 +11,6 @@ module.exports = (sequelize, DataTypes) => {
|
|||
foreignKey: 'userID',
|
||||
onDelete: 'CASCADE',
|
||||
});
|
||||
User.hasMany(models.Group, {
|
||||
as: 'ownedGroups',
|
||||
foreignKey: 'ownerID',
|
||||
onDelete: 'CASCADE',
|
||||
});
|
||||
User.belongsToMany(models.Group, {
|
||||
as: 'memberGroups',
|
||||
through: 'groupUsers',
|
||||
foreignKey: 'userID',
|
||||
});
|
||||
User.hasOne(models.Organization, {
|
||||
as: 'ownedOrg',
|
||||
foreignKey: 'ownerID',
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
const { User } = require('../../models/index');
|
||||
|
||||
async function AddGroupMember(req, res, next) {
|
||||
const user = req.user;
|
||||
const newUserID = req.body.newUserID;
|
||||
const groupID = req.params.groupID;
|
||||
|
||||
const result = await user.getOwnedGroups({ where: { groupID: groupID } });
|
||||
const newUser = await User.findByPk(newUserID);
|
||||
|
||||
if (result.length == 0) {
|
||||
return res.status(500).send('No group exists with that id.');
|
||||
}
|
||||
|
||||
await result[0].addGroupMember(newUser);
|
||||
|
||||
return res.send('User added to group.');
|
||||
}
|
||||
|
||||
module.exports = AddGroupMember;
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
async function CreateGroup(req, res, next) {
|
||||
const user = req.user;
|
||||
const groupName = req.body.groupName;
|
||||
|
||||
if (!groupName) {
|
||||
return res.status(400).send('Request missing required form fields.');
|
||||
}
|
||||
|
||||
const group = await user.createOwnedGroup({
|
||||
groupName: groupName,
|
||||
});
|
||||
|
||||
return res.send(group);
|
||||
}
|
||||
|
||||
module.exports = CreateGroup;
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
async function DeleteGroup(req, res, next) {
|
||||
const user = req.user;
|
||||
const groupID = req.params.groupID;
|
||||
|
||||
const result = await user.getOwnedGroups({ where: { groupID: groupID } });
|
||||
|
||||
if (!result) {
|
||||
return res.status(400).send('You do not own a group with that ID.');
|
||||
}
|
||||
|
||||
await result[0].destroy();
|
||||
|
||||
return res.send('Group deleted');
|
||||
}
|
||||
|
||||
module.exports = DeleteGroup;
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
async function GetGroup(req, res, next) {
|
||||
const user = req.user;
|
||||
const groupID = req.params.groupID;
|
||||
|
||||
const result = await user.getOwnedGroups({
|
||||
where: { groupID: groupID },
|
||||
include: [{ association: 'groupMembers', required: false }],
|
||||
});
|
||||
|
||||
if (result.length == 0) {
|
||||
return res.status(500).send('No group exists with that id.');
|
||||
}
|
||||
|
||||
return res.send(result[0]);
|
||||
}
|
||||
|
||||
module.exports = GetGroup;
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
const { User } = require('../../models/index');
|
||||
|
||||
async function RemoveGroupMember(req, res, next) {
|
||||
const user = req.user;
|
||||
const doomedUserID = req.body.doomedUserID;
|
||||
const groupID = req.params.groupID;
|
||||
|
||||
const result = await user.getOwnedGroups({ where: { groupID: groupID } });
|
||||
const doomedUser = await User.findByPk(doomedUserID);
|
||||
|
||||
if (result.length == 0) {
|
||||
return res.status(500).send('No group exists with that id.');
|
||||
}
|
||||
|
||||
await result[0].removeGroupMember(doomedUser);
|
||||
|
||||
return res.send('User added to group.');
|
||||
}
|
||||
|
||||
module.exports = RemoveGroupMember;
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
async function UpdateOrgDetails(req, res, next) {
|
||||
const user = req.user;
|
||||
const groupID = req.params.groupID;
|
||||
const groupName = req.body.groupName;
|
||||
|
||||
if (!groupName) {
|
||||
return res.status(400).send('Form missing required information.');
|
||||
}
|
||||
|
||||
const result = await user.getOwnedGroups({ where: { groupID: groupID } });
|
||||
await result[0].update({ groupName: groupName });
|
||||
|
||||
return res.send(result[0]);
|
||||
}
|
||||
|
||||
module.exports = UpdateOrgDetails;
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
var express = require('express');
|
||||
var router = express.Router();
|
||||
|
||||
const tokenAuth = require('../middleware/tokenAuth');
|
||||
const checkKnownUser = require('../middleware/checkKnownUser');
|
||||
|
||||
const CreateGroup = require('./group/CreateGroup');
|
||||
const DeleteGroup = require('./group/DeleteGroup');
|
||||
const UpdateGroupDetails = require('./group/UpdateGroupDetails');
|
||||
const GetGroup = require('./group/GetGroup');
|
||||
const AddGroupMember = require('./group/AddGroupMember');
|
||||
const RemoveGroupMember = require('./group/RemoveGroupMember');
|
||||
|
||||
router.post('/create', tokenAuth, CreateGroup);
|
||||
router.delete('/:groupID/delete', tokenAuth, DeleteGroup);
|
||||
router.patch('/:groupID/update', tokenAuth, UpdateGroupDetails);
|
||||
router.get('/:groupID', tokenAuth, GetGroup);
|
||||
router.post('/:groupID/add', tokenAuth, checkKnownUser, AddGroupMember);
|
||||
router.post('/:groupID/remove', tokenAuth, RemoveGroupMember);
|
||||
|
||||
module.exports = router;
|
||||
Reference in a new issue