Skip to content

Commit

Permalink
refactor: update item card and item table, factor out buttons, delete…
Browse files Browse the repository at this point in the history
… items
  • Loading branch information
pyphilia committed Feb 4, 2021
1 parent f2b5347 commit 32e246e
Show file tree
Hide file tree
Showing 22 changed files with 432 additions and 208 deletions.
30 changes: 27 additions & 3 deletions src/actions/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
FLAG_SETTING_ITEM,
FLAG_EDITING_ITEM,
GET_SHARED_ITEMS_SUCCESS,
FLAG_DELETING_ITEMS,
DELETE_ITEMS_SUCCESS,
} from '../types/item';
import { getParentsIdsFromPath } from '../utils/item';
import { createFlag } from './utils';
Expand Down Expand Up @@ -129,13 +131,35 @@ export const createItem = (props) => async (dispatch) => {
}
};

export const deleteItem = (item) => async (dispatch) => {
export const deleteItem = (itemId) => async (dispatch) => {
try {
dispatch(createFlag(FLAG_DELETING_ITEM, true));
await Api.deleteItem(item.id);
await Api.deleteItem(itemId);
dispatch({
type: DELETE_ITEM_SUCCESS,
payload: item,
payload: { id: itemId },
});
} catch (e) {
console.error(e);
} finally {
dispatch(createFlag(FLAG_DELETING_ITEM, false));
}
};

export const deleteItems = (itemIds) => async (dispatch) => {
try {
dispatch(createFlag(FLAG_DELETING_ITEMS, true));

// choose corresponding call depending on number of items
if (itemIds.length === 1) {
await Api.deleteItem(itemIds);
} else {
await Api.deleteItems(itemIds);
}

dispatch({
type: DELETE_ITEMS_SUCCESS,
payload: itemIds,
});
} catch (e) {
console.error(e);
Expand Down
15 changes: 15 additions & 0 deletions src/api/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { API_HOST, ROOT_ID } from '../config/constants';
import {
buildCopyItemRoute,
buildDeleteItemRoute,
buildDeleteItemsRoute,
buildEditItemRoute,
buildGetChildrenRoute,
buildGetItemRoute,
Expand Down Expand Up @@ -87,6 +88,20 @@ export const deleteItem = async (id) => {
return res.json();
};

export const deleteItems = async (ids) => {
const res = await fetch(
`${API_HOST}/${buildDeleteItemsRoute(ids)}`,
DEFAULT_DELETE,
);

if (!res.ok) {
throw new Error((await res.json()).message);
}
await CacheOperations.deleteItems(ids);

return res.json();
};

// payload = {name, type, description, extra}
// querystring = {parentId}
export const editItem = async (item) => {
Expand Down
2 changes: 2 additions & 0 deletions src/api/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const buildPostItemRoute = (parentId) => {
return url;
};
export const buildDeleteItemRoute = (id) => `items/${id}`;
export const buildDeleteItemsRoute = (ids) =>
`items?${ids.map((id) => `id=${id}`).join('&')}`;
export const buildGetChildrenRoute = (id) => `items/${id}/children`;
export const buildGetItemRoute = (id) => `items/${id}`;
export const buildMoveItemRoute = (id) => `items/${id}/move`;
Expand Down
1 change: 1 addition & 0 deletions src/components/Root.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const theme = createMuiTheme({
primary: {
main: '#5050d2',
},
secondary: { main: '#ffffff' },
},
});

Expand Down
44 changes: 44 additions & 0 deletions src/components/common/DeleteButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { connect } from 'react-redux';
import { useTranslation } from 'react-i18next';
import Tooltip from '@material-ui/core/Tooltip';
import PropTypes from 'prop-types';
import IconButton from '@material-ui/core/IconButton';
import DeleteIcon from '@material-ui/icons/Delete';
import { deleteItems } from '../../actions/item';
import { ITEM_DELETE_BUTTON_CLASS } from '../../config/selectors';

const DeleteButton = ({ itemIds, dispatchDeleteItems, color }) => {
const { t } = useTranslation();

return (
<Tooltip title={t('Delete')}>
<IconButton
color={color}
className={ITEM_DELETE_BUTTON_CLASS}
aria-label="delete"
onClick={() => dispatchDeleteItems(itemIds)}
>
<DeleteIcon />
</IconButton>
</Tooltip>
);
};

DeleteButton.propTypes = {
itemIds: PropTypes.string.isRequired,
dispatchDeleteItems: PropTypes.func.isRequired,
color: PropTypes.string,
};

DeleteButton.defaultProps = {
color: '',
};

const mapDispatchToProps = {
dispatchDeleteItems: deleteItems,
};

const ConnectedComponent = connect(null, mapDispatchToProps)(DeleteButton);

export default ConnectedComponent;
42 changes: 42 additions & 0 deletions src/components/common/EditButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import IconButton from '@material-ui/core/IconButton';
import EditIcon from '@material-ui/icons/Edit';
import { useTranslation } from 'react-i18next';
import Tooltip from '@material-ui/core/Tooltip';
import { ITEM_MENU_EDIT_BUTTON_CLASS } from '../../config/selectors';
import { setEditModalSettings } from '../../actions/layout';

const Item = ({ itemId, dispatchSetEditModalSettings }) => {
const { t } = useTranslation();

const handleEdit = () => {
dispatchSetEditModalSettings({ open: true, itemId });
};

return (
<Tooltip title={t('Edit')}>
<IconButton
aria-label="edit"
className={ITEM_MENU_EDIT_BUTTON_CLASS}
onClick={handleEdit}
>
<EditIcon fontSize="small" />
</IconButton>
</Tooltip>
);
};

Item.propTypes = {
itemId: PropTypes.string.isRequired,
dispatchSetEditModalSettings: PropTypes.func.isRequired,
};

const mapDispatchToProps = {
dispatchSetEditModalSettings: setEditModalSettings,
};

const ConnectedComponent = connect(null, mapDispatchToProps)(Item);

export default ConnectedComponent;
42 changes: 42 additions & 0 deletions src/components/common/ShareButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import IconButton from '@material-ui/core/IconButton';
import ShareIcon from '@material-ui/icons/Share';
import { useTranslation } from 'react-i18next';
import Tooltip from '@material-ui/core/Tooltip';
import { ITEM_MENU_SHARE_BUTTON_CLASS } from '../../config/selectors';
import { setShareModalSettings } from '../../actions/layout';

const Item = ({ itemId, dispatchSetShareModalSettings }) => {
const { t } = useTranslation();

const handleShare = () => {
dispatchSetShareModalSettings({ open: true, itemId });
};

return (
<Tooltip title={t('Share')}>
<IconButton
aria-label="share"
className={ITEM_MENU_SHARE_BUTTON_CLASS}
onClick={handleShare}
>
<ShareIcon fontSize="small" />
</IconButton>
</Tooltip>
);
};

Item.propTypes = {
itemId: PropTypes.string.isRequired,
dispatchSetShareModalSettings: PropTypes.func.isRequired,
};

const mapDispatchToProps = {
dispatchSetShareModalSettings: setShareModalSettings,
};

const ConnectedComponent = connect(null, mapDispatchToProps)(Item);

export default ConnectedComponent;
2 changes: 1 addition & 1 deletion src/components/main/CustomCardHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const CustomCardHeader = ({ item }) => {
</Typography>
</div>
</div>
<ItemMenu item={item} />
<ItemMenu itemId={item.id} />
</div>
);
};
Expand Down
21 changes: 21 additions & 0 deletions src/components/main/EmptyItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import Typography from '@material-ui/core/Typography';
import { useTranslation } from 'react-i18next';
import { ITEMS_GRID_NO_ITEM_ID } from '../../config/selectors';

const EmptyItem = () => {
const { t } = useTranslation();

return (
<Typography
id={ITEMS_GRID_NO_ITEM_ID}
variant="subtitle1"
align="center"
display="block"
>
{t('This item is empty.')}
</Typography>
);
};

export default EmptyItem;
7 changes: 4 additions & 3 deletions src/components/main/Home.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
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';
Expand All @@ -15,8 +16,8 @@ class Home extends Component {
params: PropTypes.shape({ itemId: PropTypes.string }).isRequired,
}).isRequired,
activity: PropTypes.bool.isRequired,
ownItems: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
sharedItems: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
ownItems: PropTypes.instanceOf(List).isRequired,
sharedItems: PropTypes.instanceOf(List).isRequired,
t: PropTypes.func.isRequired,
dispatchGetSharedItems: PropTypes.func.isRequired,
};
Expand Down Expand Up @@ -62,7 +63,7 @@ class Home extends Component {
}

const mapStateToProps = ({ item }) => ({
activity: Object.values(item.get('activity').toJS()).flat().length,
activity: Boolean(Object.values(item.get('activity').toJS()).flat().length),
ownItems: item.get('own'),
sharedItems: item.get('shared'),
});
Expand Down
33 changes: 9 additions & 24 deletions src/components/main/Item.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import truncate from 'lodash.truncate';
import Card from '@material-ui/core/Card';
import CardMedia from '@material-ui/core/CardMedia';
import CardContent from '@material-ui/core/CardContent';
import CardActions from '@material-ui/core/CardActions';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import DeleteIcon from '@material-ui/icons/Delete';
import CustomCardHeader from './CustomCardHeader';
import { deleteItem } from '../../actions/item';
import {
DEFAULT_IMAGE_SRC,
DESCRIPTION_MAX_LENGTH,
} from '../../config/constants';
import {
buildItemCard,
ITEM_DELETE_BUTTON_CLASS,
} from '../../config/selectors';
import { buildItemCard } from '../../config/selectors';
import EditButton from '../common/EditButton';
import ShareButton from '../common/ShareButton';
import DeleteButton from '../common/DeleteButton';

const useStyles = makeStyles(() => ({
root: {
Expand All @@ -31,7 +27,7 @@ const useStyles = makeStyles(() => ({
},
}));

const Item = ({ item, dispatchDeleteItem }) => {
const Item = ({ item }) => {
const classes = useStyles();
const { id, name, description, extra } = item;

Expand All @@ -49,13 +45,9 @@ const Item = ({ item, dispatchDeleteItem }) => {
</Typography>
</CardContent>
<CardActions disableSpacing>
<IconButton
className={ITEM_DELETE_BUTTON_CLASS}
aria-label="delete"
onClick={() => dispatchDeleteItem(item)}
>
<DeleteIcon />
</IconButton>
<EditButton itemId={id} />
<ShareButton itemId={id} />
<DeleteButton itemIds={[id]} />
</CardActions>
</Card>
);
Expand All @@ -72,13 +64,6 @@ Item.propTypes = {
image: PropTypes.string.isRequired,
}).isRequired,
}).isRequired,
dispatchDeleteItem: PropTypes.func.isRequired,
};

const mapDispatchToProps = {
dispatchDeleteItem: deleteItem,
};

const ConnectedComponent = connect(null, mapDispatchToProps)(Item);

export default ConnectedComponent;
export default Item;
Loading

0 comments on commit 32e246e

Please sign in to comment.