Completed reponsive window sizes on desktop, tablet, and mobile (#18)

This commit is contained in:
Ceferino Patino 2022-04-02 14:04:35 -05:00 committed by GitHub
commit 47513f08db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 335 additions and 186 deletions

View file

@ -13,10 +13,31 @@ import {
TextField,
FormGroup,
} from '@mui/material';
import { styled } from '@mui/material/styles';
import OrgUnit from './utils/OrgUnit';
import StackItem from './utils/StackItem';
const Form = styled(FormGroup)(({ theme }) => ({
[theme.breakpoints.only('xs')]: {
column: true,
},
}));
const FormField = styled(TextField)(({ theme }) => ({
[theme.breakpoints.only('xs')]: {
column: true,
width: '75%',
},
}));
const FormButton = styled(Button)(({ theme }) => ({
disableElevation: true,
color: theme.palette.primary.main,
[theme.breakpoints.only('xs')]: {
column: true,
width: '25%',
},
}));
function MainPage() {
const navigate = useNavigate();
@ -30,17 +51,13 @@ function MainPage() {
const linkStyle = { textDecoration: 'none', color: 'inherit' };
useEffect(() => {
if (!Cookies.get('token')) {
if (Cookies.get('token')) {
getMemberOrgs();
getOwnedOrgs();
} else {
navigate('/login');
}
});
useEffect(() => {}, []);
useEffect(() => {
getMemberOrgs();
getOwnedOrgs();
}, []);
}, [navigate]);
function handleChange(e) {
const name = e.target.name;
@ -106,7 +123,6 @@ function MainPage() {
orgName: form.name,
})
.then(() => {
navigate('');
getOwnedOrgs();
});
}
@ -132,51 +148,43 @@ function MainPage() {
alignItems='center'
style={{ height: '95vh' }}
>
<Grid item xs={1} sm={3} md={3.5} />
<Grid item xs={10} sm={6} md={5}>
<Grid item xs={0.5} sm={2} md={4} />
<Grid item xs={11} sm={8} md={4}>
<Stack spacing={2}>
<StackItem text='Join an Organization'>
<form onSubmit={joinOrg}>
<FormGroup row>
<TextField
<Form>
<FormField
label='Organization ID'
name='id'
value={form.id}
onChange={handleChange}
sx={{ width: '75%' }}
/>
<Button
<FormButton
type='submit'
variant='outlined'
color='primary'
disableElevation
sx={{ width: '25%' }}
>
Join Organization
</Button>
</FormGroup>
</FormButton>
</Form>
</form>
</StackItem>
<StackItem text='Create an Organization'>
<form onSubmit={createOrg}>
<FormGroup row>
<TextField
<Form>
<FormField
label='Organization Name'
name='name'
value={form.name}
onChange={handleChange}
sx={{ width: '70%' }}
/>
<Button
<FormButton
type='submit'
variant='outlined'
color='primary'
disableElevation
sx={{ width: '30%' }}
>
Create Organization
</Button>
</FormGroup>
</FormButton>
</Form>
</form>
</StackItem>
<StackItem>
@ -214,7 +222,7 @@ function MainPage() {
</StackItem>
</Stack>
</Grid>
<Grid item xs={1} sm={3} md={3.5} />
<Grid item xs={0.5} sm={2} md={4} />
</Grid>
</Box>
</React.Fragment>

View file

@ -8,15 +8,25 @@ import {
Typography,
IconButton,
CssBaseline,
useMediaQuery,
} from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
import { ThemeProvider, createTheme } from '@mui/material/styles';
function Navbar({ token }) {
const linkStyle = { textDecoration: 'none', color: 'inherit' };
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const darkTheme = createTheme({
palette: {
mode: 'dark',
mode: prefersDarkMode ? 'dark' : 'light',
},
breakpoints: {
values: {
xs: 0,
sm: 768,
md: 1024,
},
},
});

View file

@ -63,7 +63,7 @@ function EditUser() {
token: Cookies.get('token'),
})
.then(() => {
navigate('/login');
navigate('/');
})
.catch((e) => setError(() => e.response.data));
}

View file

@ -11,16 +11,32 @@ import {
Box,
ButtonGroup,
Button,
Accordion,
AccordionSummary,
AccordionDetails,
useMediaQuery,
} from '@mui/material';
import { styled, useTheme } from '@mui/material/styles';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import Dashboard from '../utils/Dashboard';
const DynamicStack = styled(Stack)(({ theme }) => ({
[theme.breakpoints.up('sm')]: {
spacing: 2,
alignItems: 'flex-end',
},
}));
function OrgDashboard() {
const xs = useMediaQuery((theme) => theme.breakpoints.only('xs'));
const sm = useMediaQuery((theme) => theme.breakpoints.only('sm'));
const md = useMediaQuery((theme) => theme.breakpoints.only('md'));
const { orgID } = useParams();
const navigate = useNavigate();
const [org, setOrg] = useState({
orgID: '',
orgID: orgID,
orgName: '',
orgOwner: {
firstName: '',
@ -31,11 +47,24 @@ function OrgDashboard() {
createdAt: '',
memberCount: 0,
});
const [rows, setRows] = useState([]);
const [status, setStatus] = useState('');
const [selection, setSelection] = useState();
const [rows, setRows] = useState([
{
id: 'asdf',
firstName: 'asdf',
lastName: 'asdf',
nickname: 'asdf',
pronouns: 'asdf',
email: 'asdf',
},
]);
const [status, setStatus] = useState(true);
const [selection, setSelection] = useState(null);
const [open, setOpen] = useState(false);
const linkStyle = { textDecoration: 'none', color: 'inherit' };
const buttonGroupOrientation = () => {
if (xs) return 'vertical';
};
useEffect(() => {
async function getData() {
@ -131,6 +160,10 @@ function OrgDashboard() {
});
}
function handleOpen() {
setOpen((initial) => (initial ? false : true));
}
async function play(id) {
axios
.get(
@ -150,94 +183,110 @@ function OrgDashboard() {
}
return (
<Dashboard rows={rows} setSelection={setSelection} onClick={play}>
<Typography variant='h6'>Organizations/{org.orgName}</Typography>
<Box sx={{ marginTop: '1vh' }}>
<Grid container columns={{ xs: 3, md: 12 }}>
<Grid item xs={3}>
<Stack spacing={2}>
<Typography variant='body1'>
Organization ID: {org.orgID}
</Typography>
<Typography variant='body1'>
Members: {org.memberCount}
</Typography>
<Typography variant='body1'>
Created On: {org.createdAt}
</Typography>
</Stack>
</Grid>
<Grid item xs>
<Stack spacing={2}>
<Typography variant='body1'>
Owner:{' '}
{`${org.orgOwner.firstName} ${org.orgOwner.lastName}`}
</Typography>
<Typography variant='body1'>
Email: {org.orgOwner.email}
</Typography>
</Stack>
</Grid>
<Grid
item
container
direction='row'
justifyContent='flex-end'
alignItems='flex-end'
xs
>
<Stack spacing={2} alignItems='flex-end'>
{status ? (
<React.Fragment>
<ButtonGroup
variant='outlined'
aria-label='outlined button group'
>
<Button color='warning'>
<Link to='update' style={linkStyle}>
Edit {org.orgName}
</Link>
</Button>
<Dashboard
rows={rows}
setSelection={setSelection}
onClick={play}
open={open}
>
<Accordion expanded={open} onChange={handleOpen}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant='h6'>
Organizations/{org.orgName}
</Typography>
</AccordionSummary>
<AccordionDetails>
<Box sx={{ marginTop: '1vh' }} fullWidth>
<Grid
container
columns={{ xs: 3, sm: 12, md: 12 }}
spacing={1}
>
<Grid item xs={3}>
<Stack>
<Typography variant='body1'>
Organization ID: {org.orgID}
</Typography>
<Typography variant='body1'>
Members: {org.memberCount}
</Typography>
<Typography variant='body1'>
Created On: {org.createdAt}
</Typography>
</Stack>
</Grid>
<Grid item xs={3}>
<Stack>
<Typography variant='body1'>
Owner:{' '}
{`${org.orgOwner.firstName} ${org.orgOwner.lastName}`}
</Typography>
<Typography variant='body1'>
Email: {org.orgOwner.email}
</Typography>
</Stack>
</Grid>
<Grid item xs={3} sm={6} md={6}>
<DynamicStack spacing={1}>
{status ? (
<React.Fragment>
<ButtonGroup
variant='outlined'
orientation={buttonGroupOrientation()}
>
<Button color='warning'>
<Link
to='update'
style={linkStyle}
>
Edit {org.orgName}
</Link>
</Button>
<Button
color='error'
onClick={handleDelete}
>
Delete {org.orgName}
</Button>
</ButtonGroup>
<ButtonGroup
variant='outlined'
orientation={buttonGroupOrientation()}
>
<Button
color='success'
onClick={copyID}
>
Copy Org ID
</Button>
<Button
color='success'
onClick={copyJoinLink}
>
Copy Org Join Link
</Button>
<Button
color='error'
onClick={removeSelected}
>
Remove People
</Button>
</ButtonGroup>
</React.Fragment>
) : (
<Button
color='error'
onClick={handleDelete}
onClick={leaveOrg}
>
Delete {org.orgName}
Leave Org
</Button>
</ButtonGroup>
<ButtonGroup
variant='outlined'
aria-label='outlined button group'
>
<Button
color='success'
onClick={copyID}
>
Copy Org ID
</Button>
<Button
color='success'
onClick={copyJoinLink}
>
Copy Org Join Link
</Button>
<Button
color='error'
onClick={removeSelected}
>
Remove People
</Button>
</ButtonGroup>
</React.Fragment>
) : (
<Button color='error' onClick={leaveOrg}>
Leave Org
</Button>
)}
</Stack>
</Grid>
</Grid>
</Box>
)}
</DynamicStack>
</Grid>
</Grid>
</Box>
</AccordionDetails>
</Accordion>
</Dashboard>
);
}

View file

@ -1,13 +1,34 @@
import React from 'react';
import { Outlet } from 'react-router-dom';
import { Paper, Box, IconButton } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { Paper, Box, IconButton, useMediaQuery, Collapse } from '@mui/material';
import { styled } from '@mui/material/styles';
import { DataGrid } from '@mui/x-data-grid';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
function Dashboard({ children, rows, setSelection, onClick }) {
const theme = useTheme();
import MemberUnit from '../utils/MemberUnit';
const DynamicPaper = styled(Paper)(({ theme }) => ({
...theme.typography.body2,
padding: '2vh',
textAlign: 'center',
color: theme.palette.text.secondary,
flexGrow: 1,
margin: '0 2vh',
[theme.breakpoints.only('xs')]: {
height: '80vh',
},
[theme.breakpoints.only('sm')]: {
height: '80vh',
},
[theme.breakpoints.only('md')]: {
height: '82vh',
},
}));
function Dashboard({ children, rows, setSelection, onClick, open }) {
const xs = useMediaQuery((theme) => theme.breakpoints.only('xs'));
const sm = useMediaQuery((theme) => theme.breakpoints.only('sm'));
const md = useMediaQuery((theme) => theme.breakpoints.only('md'));
const columns = [
{ field: 'id', headerName: 'ID', flex: 1 },
@ -36,47 +57,46 @@ function Dashboard({ children, rows, setSelection, onClick }) {
{ field: 'email', headerName: 'Email', flex: 10, sortable: false },
];
function calculateCollapsedSize() {
if (xs) return '37vh';
if (sm) return '63vh';
if (md) return '68vh';
}
function calculateTableHeight() {
return open ? '64vh' : '100%';
}
return (
<React.Fragment>
<Paper
sx={{
...theme.typography.body2,
padding: '2vh',
color: theme.palette.text.secondary,
flexGrow: 1,
height: '20vh',
margin: '2vh',
overflow: 'auto',
}}
<Box sx={{ padding: '2vh' }}>{children}</Box>
<Collapse
collapsedSize={calculateCollapsedSize()}
in={open ? false : true}
>
{children}
<Outlet />
</Paper>
<Paper
sx={{
...theme.typography.body2,
padding: '2vh',
textAlign: 'center',
color: theme.palette.text.secondary,
flexGrow: 1,
height: '67vh',
margin: '2vh',
overflow: 'auto',
}}
>
<Box sx={{ height: '63vh' }}>
<DataGrid
rows={rows}
columns={columns}
pageSize={5}
rowsPerPageOptions={[5]}
onSelectionModelChange={(newSelection) => {
setSelection(newSelection.rows);
}}
checkboxSelection
/>
</Box>
</Paper>
<DynamicPaper>
{(xs || sm) &&
rows.map((member) => {
return (
<MemberUnit member={member} onClick={onClick} />
);
})}
{md && (
<Box height={calculateTableHeight()}>
<DataGrid
rows={rows}
columns={columns}
pageSize={5}
rowsPerPageOptions={[5]}
onSelectionModelChange={(newSelection) => {
setSelection(() => newSelection.rows);
}}
checkboxSelection
/>
</Box>
)}
</DynamicPaper>
</Collapse>
</React.Fragment>
);
}

View file

@ -16,8 +16,8 @@ function Form({ children }) {
alignItems='center'
style={{ height: '95vh' }}
>
<Grid item xs={1} sm={3} md={4} />
<Grid item xs={10} sm={6} md={4}>
<Grid item xs={0.5} sm={2} md={4} />
<Grid item xs={11} sm={8} md={4}>
<Paper
sx={{
...theme.typography.body2,
@ -30,7 +30,7 @@ function Form({ children }) {
<Outlet />
</Paper>
</Grid>
<Grid item xs={1} sm={3} md={4} />
<Grid item xs={0.5} sm={2} md={4} />
</Grid>
</Box>
</React.Fragment>

View file

@ -0,0 +1,48 @@
import React from 'react';
import {
Accordion,
AccordionSummary,
AccordionDetails,
Typography,
IconButton,
Grid,
} from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
function MemberUnit({ member, onClick }) {
const { id, firstName, lastName, nickname, pronouns, email } = member;
return (
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>
{firstName} {lastName} ({nickname}): {pronouns}
</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={1}>
<Grid item textAlign='left' xs={11} sm={11}>
<Typography variant='body1'>ID: {id}</Typography>
<Typography variant='body1'>Email: {email}</Typography>
</Grid>
<Grid item xs={1} sm={1} justifyContent='flex-end'>
<IconButton
size='large'
edge='start'
color='inherit'
aria-label='menu'
sx={{ mr: 2 }}
onClick={() => onClick(member.id)}
>
<PlayArrowIcon />
</IconButton>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
);
}
export default MemberUnit;

View file

@ -1,27 +1,33 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Stack, Box, Typography } from '@mui/material';
import {
Typography,
Accordion,
AccordionSummary,
AccordionDetails,
} from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
function OrgUnit({ org }) {
const { orgID, orgName, memberCount, createdAt } = org;
const linkStyle = { textDecoration: 'none', color: 'inherit' };
return (
<React.Fragment>
<Typography variant='h6'>
<Link to={`org/${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: {createdAt}
</Typography>
</Stack>
</Box>
</React.Fragment>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>
<Link to={`/org/${orgID}`} style={linkStyle}>
{orgName}
</Link>
</Typography>
</AccordionSummary>
<AccordionDetails>
<Typography variant='body1'>Members: {memberCount}</Typography>
<Typography variant='body1'>Created On: {createdAt}</Typography>
</AccordionDetails>
</Accordion>
);
}

View file

@ -8,7 +8,14 @@ import OrgUnit from './OrgUnit';
function Organizations({ retrieveOrgs }) {
const theme = useTheme();
const [orgs, setOrgs] = useState([]);
const [orgs, setOrgs] = useState([
{
orgID: 12341234,
orgName: 'Org',
memberCount: 15,
createdAt: 15,
},
]);
useEffect(() => {
retrieveOrgs(setOrgs);
@ -26,9 +33,10 @@ function Organizations({ retrieveOrgs }) {
}}
>
<Typography variant='h6'>Organizations</Typography>
<hr />
<Box sx={{ overflowY: 'auto' }}>
{orgs.map((org) => (
<OrgUnit org={org} />
{orgs.map((org, index) => (
<OrgUnit org={org} key={index} />
))}
</Box>
</Paper>