Skip to content

Commit

Permalink
feat: view, delete and add item
Browse files Browse the repository at this point in the history
  • Loading branch information
pyphilia committed Dec 4, 2020
1 parent bcdf11f commit 23211e3
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 60 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"propTypes": "static public field"
}
],
"react/state-in-constructor": ["error", "never"]
"react/state-in-constructor": ["error", "never"],
"no-console": [2, { "allow": ["error"] }]
}
}
38 changes: 27 additions & 11 deletions src/api/item.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
import { API_HOST } from '../config/constants';
import { DEFAULT_GET, DEFAULT_POST } from './utils';
import { DEFAULT_DELETE, DEFAULT_GET, DEFAULT_POST } from './utils';

// payload = {email}
export const getOwnItems = async () => {
const req = await fetch(`${API_HOST}/own`, {
const req = await fetch(`${API_HOST}/items/own`, {
...DEFAULT_GET,
headers: { 'Content-Type': 'application/json' },
});
// eslint-disable-next-line no-console
console.log(req);
return req.json();
};

// payload = {email}
export const createItem = async () => {
const req = await fetch(`${API_HOST}/items`, {
// payload = {name, type, description, extra}
// querystring = {parentId}
export const createItem = async ({
name,
type,
description,
extra,
parentId,
} = {}) => {
let url = `${API_HOST}/items`;
if (parentId) {
url += `?parentId=${parentId}`;
}
const req = await fetch(url, {
...DEFAULT_POST,
body: JSON.stringify({ name: 'myitem' }),
body: JSON.stringify({ name, type, description, extra }),
});
// eslint-disable-next-line no-console
console.log(await req.json());
return req.json();
};

// payload = {name, type, description, extra}
// querystring = {parentId}
export const deleteItem = async (id) => {
const req = await fetch(`${API_HOST}/items/${id}`, DEFAULT_DELETE);
return req.json();
};

// we need this function for navigation purposes: when you click on an item, you want to see its 'immediate' children
// eslint-disable-next-line import/prefer-default-export
export const fetchItemImmediateChildren = () => {};
5 changes: 5 additions & 0 deletions src/api/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ export const DEFAULT_POST = {
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
};

export const DEFAULT_DELETE = {
method: 'DELETE',
credentials: 'include',
};
47 changes: 25 additions & 22 deletions src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import items from '../data/sample';
import SignUp from './SignUp';
import { SIGN_UP_PATH, SIGN_IN_PATH } from '../config/paths';
import SignIn from './SignIn';
import { ItemProvider } from './context/item';

const useStyles = makeStyles((theme) => ({
root: {
Expand All @@ -23,29 +24,31 @@ function App() {
const classes = useStyles();
return (
<Router>
<div>
<Header />
<main className={classes.root}>
<Switch>
<Route path="/items" exact>
<Items items={items} />
</Route>
<Route path="/items/:itemId">
<Items items={items} />
</Route>
<Route path={SIGN_IN_PATH} exact>
<SignIn />
</Route>
<Route path={SIGN_UP_PATH} exact>
<SignUp />
</Route>
<Route path="/" exact>
<ItemProvider>
<div>
<Header />
<main className={classes.root}>
<Switch>
<Route path="/items" exact>
<Items />
</Route>
<Route path="/items/:itemId">
<Items items={items} />
</Route>
<Route path={SIGN_IN_PATH} exact>
<SignIn />
</Route>
<Route path={SIGN_UP_PATH} exact>
<SignUp />
</Route>
<Route path="/" exact>
<Redirect to="/items" />
</Route>
<Redirect to="/items" />
</Route>
<Redirect to="/items" />
</Switch>
</main>
</div>
</Switch>
</main>
</div>
</ItemProvider>
</Router>
);
}
Expand Down
64 changes: 64 additions & 0 deletions src/components/context/item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { getOwnItems, deleteItem } from '../../api/item';
import sampleItems from '../../data/sample';

const ItemContext = React.createContext();

class ItemProvider extends Component {
static propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
};

state = {
items: [],
};

async componentDidMount() {
const ownedItems = (await getOwnItems()) || sampleItems;
this.setState({ items: ownedItems });
}

addItem = (item) => {
const { items } = this.state;
this.setState({ items: [...items, item] });
};

setItems = (items) => {
this.setState({ items });
};

deleteItem = async (id) => {
const { items } = this.state;
const deletedItem = await deleteItem(id);
if (deletedItem.status === 404) {
return console.error(`Couldn't delete item ${id}`);
}
return this.setState({
items: items.filter(({ id: thisId }) => thisId !== id),
});
};

buildValue = () => {
const { items } = this.state;
return {
items,
addItem: this.addItem,
deleteItem: this.deleteItem,
};
};

render() {
const { children } = this.props;
return (
<ItemContext.Provider value={this.buildValue()}>
{children}
</ItemContext.Provider>
);
}
}

export { ItemProvider, ItemContext };
23 changes: 20 additions & 3 deletions src/components/main/CreateNewItem.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useContext } from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
Expand All @@ -10,6 +10,8 @@ import DialogTitle from '@material-ui/core/DialogTitle';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import Select from '@material-ui/core/Select';
import { createItem } from '../../api/item';
import { ItemContext } from '../context/item';

const useStyles = makeStyles((theme) => ({
dialogContent: {
Expand All @@ -26,6 +28,7 @@ const useStyles = makeStyles((theme) => ({

const CreateNewItem = ({ open, handleClose }) => {
const classes = useStyles();
const itemContext = useContext(ItemContext);
const [itemName, setItemName] = useState('');
const [itemType, setItemType] = useState('');
const [itemDescription, setItemDescription] = useState('');
Expand All @@ -47,7 +50,17 @@ const CreateNewItem = ({ open, handleClose }) => {
setItemImageUrl(event.target.value);
};

const submitNewItem = () => {};
const submitNewItem = async () => {
const { addItem } = itemContext;
const newItem = await createItem({
name: itemName,
type: itemType,
description: itemDescription,
extra: { image: itemImageUrl },
});

addItem(newItem);
};

return (
<Dialog
Expand Down Expand Up @@ -129,8 +142,12 @@ const CreateNewItem = ({ open, handleClose }) => {
};

CreateNewItem.propTypes = {
open: PropTypes.func.isRequired,
open: PropTypes.bool,
handleClose: PropTypes.func.isRequired,
};

CreateNewItem.defaultProps = {
open: false,
};

export default CreateNewItem;
14 changes: 11 additions & 3 deletions src/components/main/Item.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
Expand All @@ -8,8 +8,10 @@ import CardActions from '@material-ui/core/CardActions';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import FavoriteIcon from '@material-ui/icons/Favorite';
import DeleteIcon from '@material-ui/icons/Delete';
import ShareIcon from '@material-ui/icons/Share';
import CustomCardHeader from './CustomCardHeader';
import { ItemContext } from '../context/item';

const useStyles = makeStyles(() => ({
root: {
Expand All @@ -23,6 +25,7 @@ const useStyles = makeStyles(() => ({

const Item = ({ item }) => {
const classes = useStyles();
const { deleteItem } = useContext(ItemContext);
const { id, name, description, creator, type, extra } = item;

return (
Expand All @@ -33,7 +36,7 @@ const Item = ({ item }) => {
<Typography variant="body2" color="textSecondary" component="p">
{/* Line below is to limit how much description text is dispalyed, to create consistent card displays
But fix: There must be a better way of doing it */}
{`${description.split(' ').slice(0, 30).join(' ')}...`}
{`${description?.split(' ').slice(0, 30).join(' ')}...`}
</Typography>
</CardContent>
<CardActions disableSpacing>
Expand All @@ -43,6 +46,9 @@ const Item = ({ item }) => {
<IconButton aria-label="share">
<ShareIcon />
</IconButton>
<IconButton aria-label="delete" onClick={() => deleteItem(id)}>
<DeleteIcon />
</IconButton>
</CardActions>
</Card>
);
Expand All @@ -55,7 +61,9 @@ Item.propTypes = {
description: PropTypes.string.isRequired,
creator: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
extra: PropTypes.string.isRequired,
extra: PropTypes.shape({
image: PropTypes.string.isRequired,
}).isRequired,
}).isRequired,
};

Expand Down
41 changes: 21 additions & 20 deletions src/components/main/Items.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Grid from '@material-ui/core/Grid';
import ItemsHeader from './ItemsHeader';
import CreateNewItemButton from './CreateNewItemButton';
import Item from './Item';
import { ItemContext } from '../context/item';

const Items = ({ items }) => {
return (
<div>
<ItemsHeader />
<CreateNewItemButton />
<Grid container spacing={1}>
{items.map((item) => (
<Grid key={item.id} item xs={12} sm={6} md={4} lg={3} xl={2}>
<Item item={item} />
</Grid>
))}
</Grid>
</div>
);
};
class Items extends Component {
static contextType = ItemContext;

Items.propTypes = {
items: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
};
render() {
const { items } = this.context;
return (
<div>
<ItemsHeader />
<CreateNewItemButton />
<Grid container spacing={1}>
{items.reverse().map((item) => (
<Grid key={item.id} item xs={12} sm={6} md={4} lg={3} xl={2}>
<Item item={item} />
</Grid>
))}
</Grid>
</div>
);
}
}

export default Items;

0 comments on commit 23211e3

Please sign in to comment.