Skip to content

Commit

Permalink
feat: add left sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
pyphilia committed Feb 24, 2021
1 parent ca8f7e7 commit 2815432
Show file tree
Hide file tree
Showing 12 changed files with 335 additions and 88 deletions.
61 changes: 27 additions & 34 deletions src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ import {
Route,
Redirect,
} from 'react-router-dom';
import { withStyles } from '@material-ui/core';
import Header from './layout/Header';
import items from '../data/sample';
import SignUp from './SignUp';
import {
SIGN_UP_PATH,
SIGN_IN_PATH,
HOME_PATH,
ITEMS_PATH,
SHARED_ITEMS_PATH,
} from '../config/paths';
import SignIn from './SignIn';
import Home from './main/Home';
Expand All @@ -23,12 +22,9 @@ import MoveItemModal from './main/MoveItemModal';
import EditItemModal from './main/EditItemModal';
import CopyItemModal from './main/CopyItemModal';
import ShareItemModal from './main/ShareItemModal';
import SharedItems from './SharedItems';
import Main from './main/Main';

const styles = (theme) => ({
root: {
padding: theme.spacing(3),
},
});
// eslint-disable-next-line react/prefer-stateless-function
class App extends Component {
static propTypes = {
Expand All @@ -38,43 +34,40 @@ class App extends Component {
};

render() {
const { classes } = this.props;
return (
<>
<MoveItemModal />
<CopyItemModal />
<EditItemModal />
<ShareItemModal />
<Router>
<div>
<Header />
<main className={classes.root}>
<Switch>
<Route path={HOME_PATH} exact>
<Home />
</Route>
<Route path="/items/:itemId">
<ItemScreen items={items} />
</Route>
<Route path={SIGN_IN_PATH} exact>
<SignIn />
</Route>
<Route path={SIGN_UP_PATH} exact>
<SignUp />
</Route>
<Route path={ITEMS_PATH} exact>
<Home />
</Route>
<Redirect to={HOME_PATH} />
</Switch>
</main>
</div>
<Switch>
<Route path={SIGN_IN_PATH} exact>
<SignIn />
</Route>
<Route path={SIGN_UP_PATH} exact>
<SignUp />
</Route>
<Main>
<Route path={HOME_PATH} exact>
<Home />
</Route>
<Route path={SHARED_ITEMS_PATH} exact>
<SharedItems />
</Route>
<Route path="/items/:itemId">
<ItemScreen items={items} />
</Route>
<Route path={ITEMS_PATH} exact>
<Home />
</Route>
<Redirect to={HOME_PATH} />
</Main>
</Switch>
</Router>
</>
);
}
}

const StyledComponent = withStyles(styles)(App);

export default StyledComponent;
export default App;
3 changes: 3 additions & 0 deletions src/components/Root.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const theme = createMuiTheme({
},
secondary: { main: '#ffffff' },
},
zIndex: {
drawer: 1000,
},
});

const { store } = configureStore();
Expand Down
50 changes: 50 additions & 0 deletions src/components/SharedItems.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { List } from 'immutable';
import { SHARED_ITEMS_ID } from '../config/selectors';
import ItemsHeader from './main/ItemsHeader';
import Items from './main/Items';
import { getSharedItems } from '../actions/item';

const SharedItems = ({ activity, sharedItems, dispatchGetSharedItems }) => {
const { t } = useTranslation();

useEffect(() => {
if (!activity) {
// update dirty items
if (sharedItems.some(({ dirty }) => dirty)) {
dispatchGetSharedItems();
}
}
}, [activity, sharedItems, dispatchGetSharedItems]);

return (
<>
<ItemsHeader navigationRootText={t('Shared')} />
<Items
id={SHARED_ITEMS_ID}
title={t('Items Shared With Me')}
items={sharedItems}
/>
</>
);
};

const mapStateToProps = ({ item }) => ({
activity: Boolean(Object.values(item.get('activity').toJS()).flat().length),
sharedItems: item.get('shared'),
});

const mapDispatchToProps = {
dispatchGetSharedItems: getSharedItems,
};

SharedItems.propTypes = {
activity: PropTypes.bool.isRequired,
dispatchGetSharedItems: PropTypes.func.isRequired,
sharedItems: PropTypes.instanceOf(List).isRequired,
};

export default connect(mapStateToProps, mapDispatchToProps)(SharedItems);
70 changes: 50 additions & 20 deletions src/components/layout/Header.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,82 @@
import React from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import { AppBar, Toolbar, Typography, IconButton } from '@material-ui/core';
import MenuIcon from '@material-ui/icons/Menu';
import MenuOpenIcon from '@material-ui/icons/MenuOpen';
import IconButton from '@material-ui/core/IconButton';
import { AppBar, Toolbar, Typography } from '@material-ui/core';
import { AccountCircle } from '@material-ui/icons';
import { ReactComponent as GraaspLogo } from '../../resources/graasp-logo.svg';
import { APP_NAME } from '../../config/constants';
import { APP_NAME, HEADER_HEIGHT } from '../../config/constants';

const useStyles = makeStyles((theme) => ({
header: {
display: 'flex',
justifyContent: 'space-between',
zIndex: theme.zIndex.drawer + 1,
},
headerLeft: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
},
logo: {
height: '48px',
marginRight: theme.spacing(2),
height: '40px',
margin: theme.spacing(0, 2),
},
link: {
textDecoration: 'none',
color: 'inherit',
display: 'flex',
alignItems: 'center',
},
appBarBlank: {
height: HEADER_HEIGHT,
},
}));

const Header = () => {
const Header = ({ isMenuOpen, toggleMenu }) => {
const classes = useStyles();

const renderMenuIcon = () => {
if (isMenuOpen) {
return (
<IconButton onClick={() => toggleMenu(false)} color="inherit">
<MenuOpenIcon />
</IconButton>
);
}
return (
<IconButton onClick={() => toggleMenu(true)} color="inherit">
<MenuIcon />
</IconButton>
);
};

return (
<header>
<AppBar position="static">
<Toolbar className={classes.header}>
<AppBar position="fixed">
<Toolbar className={classes.header}>
<div className={classes.headerLeft}>
{renderMenuIcon()}
<Link to="/items" className={classes.link}>
<div className={classes.headerLeft}>
<GraaspLogo className={classes.logo} />
<Typography variant="h6" color="inherit">
{APP_NAME}
</Typography>
</div>
<GraaspLogo className={classes.logo} />
<Typography variant="h6" color="inherit">
{APP_NAME}
</Typography>
</Link>
<IconButton color="inherit">
<AccountCircle />
</IconButton>
</Toolbar>
</AppBar>
</header>
</div>
<IconButton color="inherit">
<AccountCircle />
</IconButton>
</Toolbar>
</AppBar>
);
};

Header.propTypes = {
toggleMenu: PropTypes.func.isRequired,
isMenuOpen: PropTypes.bool.isRequired,
};

export default Header;
11 changes: 9 additions & 2 deletions src/components/layout/Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ class Navigation extends Component {
item: PropTypes.instanceOf(Map).isRequired,
dispatchClearItem: PropTypes.func.isRequired,
t: PropTypes.func.isRequired,
rootText: PropTypes.string,
};

static defaultProps = {
rootText: null,
};

clearItem = () => {
Expand All @@ -30,13 +35,15 @@ class Navigation extends Component {
};

render() {
const { item, t } = this.props;
const { item, t, rootText } = this.props;
const parents = item?.get('parents');

return (
<Breadcrumbs aria-label="breadcrumb">
<Link color="inherit" href="/" to={HOME_PATH} onClick={this.clearItem}>
<Typography id={NAVIGATION_HOME_LINK_ID}>{t('Home')}</Typography>
<Typography id={NAVIGATION_HOME_LINK_ID}>
{rootText || t('My Items')}
</Typography>
</Link>
{[...parents]?.map(({ name, id }) => (
<Link key={id} to={buildItemPath(id)}>
Expand Down
29 changes: 4 additions & 25 deletions src/components/main/Home.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import React, { Component } from 'react';
import { List } from 'immutable';
import PropTypes from 'prop-types';
import Divider from '@material-ui/core/Divider';
import { connect } from 'react-redux';
import { withTranslation } from 'react-i18next';
import { withRouter } from 'react-router';
import ItemsHeader from './ItemsHeader';
import { setItem, getOwnItems, getSharedItems } from '../../actions/item';
import { setItem, getOwnItems } from '../../actions/item';
import Items from './Items';
import { OWNED_ITEMS_ID, SHARED_ITEMS_ID } from '../../config/selectors';
import { OWNED_ITEMS_ID } from '../../config/selectors';

class Home extends Component {
static propTypes = {
Expand All @@ -18,9 +17,7 @@ class Home extends Component {
}).isRequired,
activity: PropTypes.bool.isRequired,
ownItems: PropTypes.instanceOf(List).isRequired,
sharedItems: PropTypes.instanceOf(List).isRequired,
t: PropTypes.func.isRequired,
dispatchGetSharedItems: PropTypes.func.isRequired,
};

async componentDidMount() {
Expand All @@ -29,39 +26,23 @@ class Home extends Component {
}

async componentDidUpdate() {
const {
dispatchGetOwnItems,
dispatchGetSharedItems,
activity,
ownItems,
sharedItems,
} = this.props;
const { dispatchGetOwnItems, activity, ownItems } = this.props;

if (!activity) {
// update dirty items
if (ownItems.some(({ dirty }) => dirty)) {
dispatchGetOwnItems();
}
// update dirty items
if (sharedItems.some(({ dirty }) => dirty)) {
dispatchGetSharedItems();
}
}
}

render() {
const { ownItems, sharedItems, t } = this.props;
const { ownItems, t } = this.props;

return (
<>
<ItemsHeader />
<Items id={OWNED_ITEMS_ID} title={t('My Items')} items={ownItems} />
<Divider style={{ marginTop: 30, marginBottom: 30 }} />
<Items
id={SHARED_ITEMS_ID}
title={t('Items Shared With Me')}
items={sharedItems}
/>
</>
);
}
Expand All @@ -70,13 +51,11 @@ class Home extends Component {
const mapStateToProps = ({ item }) => ({
activity: Boolean(Object.values(item.get('activity').toJS()).flat().length),
ownItems: item.get('own'),
sharedItems: item.get('shared'),
});

const mapDispatchToProps = {
dispatchGetOwnItems: getOwnItems,
dispatchSetItem: setItem,
dispatchGetSharedItems: getSharedItems,
};

const ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)(Home);
Expand Down
Loading

0 comments on commit 2815432

Please sign in to comment.