diff --git a/src/actions/posts.js b/src/actions/posts.js index ca0a673..7ac8cf1 100644 --- a/src/actions/posts.js +++ b/src/actions/posts.js @@ -42,7 +42,7 @@ export const addPost = postData => async dispatch => { export const editPost = (id, postData) => async dispatch => { dispatch({ type: EDIT_POST_START }); try { - const success = await serverHandshake(true).put('/posts', { id, postData }); + const success = await serverHandshake(true).put(`/posts/${id}`, postData); dispatch({ type: EDIT_POST_SUCCESS, payload: success.data }); return success; } catch (error) { @@ -54,7 +54,7 @@ export const editPost = (id, postData) => async dispatch => { export const deletePost = id => async dispatch => { dispatch({ type: DELETE_POST_START }); try { - const success = await serverHandshake(true).delete('/posts', id); + const success = await serverHandshake(true).delete(`/posts/${id}`); dispatch({ type: DELETE_POST_SUCCESS, payload: success.data }); return success; } catch (error) { diff --git a/src/components/Dashboard/Dashboard.js b/src/components/Dashboard/Dashboard.js deleted file mode 100644 index f9cbf60..0000000 --- a/src/components/Dashboard/Dashboard.js +++ /dev/null @@ -1,49 +0,0 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { fetchUsers, fetchPosts, fetchCategories } from '../../actions'; -import PrivateRoute from '../PrivateRoute'; -import AppBar from '../AppBar'; -import NewPost from '../NewPost'; -import HowToCard from '../PreviewCard'; -import { getFilteredPosts } from '../../reducers'; -import Paper from '@material-ui/core/Paper'; - -class Dashboard extends Component { - componentDidMount() { - this.props.fetchUsers(); - this.props.fetchPosts(); - this.props.fetchCategories(); - } - - render() { - const { history, match, posts } = this.props; - - return ( -
- - - - {posts.allPosts && posts.allPosts.map(post => ( - - ))} - {posts.allPosts && posts.allPosts.map(post => ( - - ))} - -
- ); - } -} - -// category & user IDs can be added to the second argument of getFilteredPosts as well -// these should probably be handled via routes: -// category/:id -// user/:id -const mapStateToProps = ({ posts, searchInput }) => ({ - posts: getFilteredPosts(posts, { searchInput }) -}); - -export default connect( - mapStateToProps, - { fetchUsers, fetchPosts, fetchCategories } -)(Dashboard); diff --git a/src/components/Editor.js b/src/components/Editor.js deleted file mode 100644 index 2afa2bc..0000000 --- a/src/components/Editor.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import ReactQuill from 'react-quill'; -import { withStyles } from '@material-ui/core/styles'; -import 'react-quill/dist/quill.snow.css'; -import Fab from '@material-ui/core/Fab'; -import AddIcon from '@material-ui/icons/Add'; -import DeleteIcon from '@material-ui/icons/Delete'; -import Paper from '@material-ui/core/Paper' - -const styles = theme => ({ - fab: { - margin: theme.spacing.unit, - }, - extendedIcon: { - marginLeft: theme.spacing.unit, - }, - textarea: { - height: '50vh' - } -}); - -class Editor extends React.Component { - state = { - title: 'test', - body: '' , - creator_id: '1' - } - handleChange = (value) => { - this.setState({ body: value }); - } - - render() { - return ( -
- - - - { console.log('delete') }} > - - - { console.log('post') }} > - - -
- ) - } -} - -export default withStyles(styles)(Editor); diff --git a/src/components/EditorButtons.js b/src/components/EditorButtons.js new file mode 100644 index 0000000..cee6b14 --- /dev/null +++ b/src/components/EditorButtons.js @@ -0,0 +1,40 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import Fab from '@material-ui/core/Fab'; +import AddIcon from '@material-ui/icons/Add'; +import DeleteIcon from '@material-ui/icons/Delete'; + +const styles = theme => ({ + fab: { + margin: theme.spacing.unit, + }, + extendedIcon: { + marginLeft: theme.spacing.unit, + }, +}); + +function FloatingActionButtons(props) { + const { classes, handleSubmit, history } = props; + + const abortPost = () => { + history.replace('/dashboard'); + } + + return ( +
+ + + + + + +
+ ); +} + +FloatingActionButtons.propTypes = { + classes: PropTypes.object.isRequired, +}; + +export default withStyles(styles)(FloatingActionButtons); diff --git a/src/components/HowToCard.js b/src/components/HowToCard.js new file mode 100644 index 0000000..2e7d860 --- /dev/null +++ b/src/components/HowToCard.js @@ -0,0 +1,188 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; +import Card from '@material-ui/core/Card'; +import CardHeader from '@material-ui/core/CardHeader'; +// import CardMedia from '@material-ui/core/CardMedia'; +import CardContent from '@material-ui/core/CardContent'; +import CardActions from '@material-ui/core/CardActions'; +import Avatar from '@material-ui/core/Avatar'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import red from '@material-ui/core/colors/red'; +import FavoriteIcon from '@material-ui/icons/Favorite'; +import ShareIcon from '@material-ui/icons/Share'; +import MoreVert from '@material-ui/icons/MoreVert'; +import Delete from '@material-ui/icons/Delete'; +import Edit from '@material-ui/icons/Edit'; + +import ClickAwayListener from '@material-ui/core/ClickAwayListener'; +import Grow from '@material-ui/core/Grow'; +import Paper from '@material-ui/core/Paper'; +import Popper from '@material-ui/core/Popper'; + +import MenuItem from '@material-ui/core/MenuItem'; +import MenuList from '@material-ui/core/MenuList'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; + +const styles = theme => ({ + card: { + maxWidth: 500, + height: '100%', + display: 'flex', + flexDirection: 'column' + }, + cardWrapper: { + position: 'relative', + margin: '1rem auto', + [theme.breakpoints.up('sm')]: { + margin: '1rem', + width: 'calc(50% - 2rem)' + }, + [theme.breakpoints.up('md')]: { + width: 'calc(33.33% - 2rem)' + } + }, + menuItem: { + '&:focus': { + backgroundColor: theme.palette.primary.main + } + }, + media: { + height: 0, + paddingTop: '56.25%' // 16:9 + }, + actions: { + flexGrow: 1, + alignItems: 'flex-end' + }, + likes: { + marginBottom: '1rem' + }, + noHover: { + transition: '200ms', + '&:hover': { + backgroundColor: 'initial', + transform: 'scale(1.2)' + } + }, + avatar: { + backgroundColor: red[500], + fontSize: '95%' + } +}); + +class HowToCard extends React.Component { + state = { open: false }; + + handleToggle = () => { + this.setState(state => ({ open: !state.open })); + }; + + handleClose = event => { + if (this.anchorEl.contains(event.target)) { + return; + } + + this.setState({ open: false }); + }; + + handleDelete = () => { + this.props.delete(this.props.post.id); + }; + + handleEdit = () => { + const { match, history, post } = this.props; + const navigate = match.url.endsWith('new') ? history.replace : history.push; + navigate(`${match.url}/new`, [post]); + }; + + handleLike = () => { + const { edit, post } = this.props; + edit(post.id, { ...post, likes: post.likes + 1 }); + }; + + render() { + const { open } = this.state; + const { classes, user } = this.props; + const { title, body, updated_at, likes } = this.props.post; + const initials = user ? (user.firstName[0] + user.lastName[0]).toUpperCase() : 'X'; + + return ( +
+ + + {initials} + + } + action={ + { + this.anchorEl = node; + }} + aria-owns={open ? 'menu-list-grow' : undefined} + aria-haspopup="true" + onClick={this.handleToggle} + > + + + } + title={title} + subheader={updated_at} + /> + + {({ TransitionProps, placement }) => ( + + + + + + + + + + + + + + + + + + + + + )} + + {/* */} + + {body} + + + + + + {/* TODO: replace these with likes */} + {likes || 0} + + + + + +
+ ); + } +} + +HowToCard.propTypes = { + classes: PropTypes.object.isRequired +}; + +export default withStyles(styles)(HowToCard); diff --git a/src/components/NewPost.js b/src/components/NewPost.js deleted file mode 100644 index 797a47e..0000000 --- a/src/components/NewPost.js +++ /dev/null @@ -1,16 +0,0 @@ -import React, { Component } from 'react'; -import AppBar from './AppBar'; -import Editor from './Editor'; - -class NewPost extends Component { - render() { - return ( - - - - - ); - } -} - -export default NewPost; diff --git a/src/components/PreviewCard.js b/src/components/PreviewCard.js deleted file mode 100644 index bf501a6..0000000 --- a/src/components/PreviewCard.js +++ /dev/null @@ -1,93 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { withStyles } from '@material-ui/core/styles'; -import Card from '@material-ui/core/Card'; -import CardHeader from '@material-ui/core/CardHeader'; -import CardContent from '@material-ui/core/CardContent'; -import CardActions from '@material-ui/core/CardActions'; -// import Avatar from '@material-ui/core/Avatar'; -import IconButton from '@material-ui/core/IconButton'; -import OpenInBrowser from '@material-ui/icons/OpenInBrowser'; -import Typography from '@material-ui/core/Typography'; -import Fab from '@material-ui/core/Fab'; -import ShareIcon from '@material-ui/icons/Share'; -import FavoriteIcon from '@material-ui/icons/Favorite'; -import AccountCircle from '@material-ui/icons/AccountCircle'; //tmp - -const styles = theme => ({ - card: { - maxWidth: 400, - }, - media: { - height: 0, - paddingTop: '56.25%', // 16:9 - }, - actions: { - display: 'flex', - }, - expand: { - transform: 'rotate(0deg)', - marginLeft: 'auto', - transition: theme.transitions.create('transform', { - duration: theme.transitions.duration.shortest, - }), - }, - fab: { - margin: theme.spacing.unit, - }, - extendedIcon: { - marginRight: theme.spacing.unit, - }, -}); - - -const HowToCard = props => { - return ( - - { console.log(`User ${props.creator_id}`) }} /> - // - // Pass Avatar info here if applicable (when av can take user id) - } - action={ - { console.log(`Go to page ${props.id}`) }} > - - - } - title={props.title} /* Would be cool if this could be clickable */ - subheader={`Created: ${props.created_at}`} - /> - - - {props.body} - - - - { console.log(`Heart ${props.id}`) }}> - - - { console.log(`Share ${props.id}`) }}> - - - - - ); - }; - - -HowToCard.defaultProps = { - id: null, - title: '', - created_at: '', - body: '', - likes: '', - updated_at: '', - creator_id: '', - }; - -HowToCard.propTypes = { - classes: PropTypes.object.isRequired, -}; - -export default withStyles(styles)(HowToCard); \ No newline at end of file diff --git a/src/components/Root.js b/src/components/Root.js index cf22ba0..826a4f8 100644 --- a/src/components/Root.js +++ b/src/components/Root.js @@ -1,16 +1,14 @@ import React from 'react'; import { Provider } from 'react-redux'; import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; -import theme from '../theme'; import { MuiThemeProvider } from '@material-ui/core/styles'; import CssBaseline from '@material-ui/core/CssBaseline'; -import Dashboard from './Dashboard/Dashboard'; -import Register from './Register'; -import SearchContainer from './SearchContainer'; -import ViewHowTo from './ViewHowTo'; -import NewPost from './NewPost'; -import CompList from './Testing/CompList'; - +import PrivateRoute from './PrivateRoute'; +import Register from '../containers/Register'; +import Dashboard from '../containers/Dashboard'; +import NewPost from '../containers/NewPost'; +// import UserProfile from './UserProfile'; +import theme from '../theme'; const Root = ({ store }) => ( @@ -26,12 +24,10 @@ const Root = ({ store }) => ( }} /> - - - - - - {/* */} + + + {/* + */} diff --git a/src/components/SearchContainer.js b/src/components/SearchContainer.js deleted file mode 100644 index b52c1d6..0000000 --- a/src/components/SearchContainer.js +++ /dev/null @@ -1,40 +0,0 @@ -import React, { Component } from 'react'; -import AppBar from './AppBar'; -import HowToCard from './PreviewCard'; -import { Grid } from '@material-ui/core'; -import { Paper } from '@material-ui/core'; - -class NewPost extends Component { - render() { - return ( -
- - - - - - - - - - - - - - - - - - - - - - -

Imagine you typed search

- {/* Search returned corpuse */} -
- ) - } - } - -export default NewPost; \ No newline at end of file diff --git a/src/components/UserProfile/UserProfile.js b/src/components/UserProfile.js similarity index 55% rename from src/components/UserProfile/UserProfile.js rename to src/components/UserProfile.js index 9739a43..3a887f7 100644 --- a/src/components/UserProfile/UserProfile.js +++ b/src/components/UserProfile.js @@ -1,24 +1,21 @@ import React, { Component } from 'react'; -import AppBar from '../AppBar'; +import MenuBar from '../containers/MenuBar'; import { Paper, Avatar } from '@material-ui/core'; -import PreviewCard from '../PreviewCard'; class NewPost extends Component { render() { return (
- -

Avi

- -

Users How-Tos

+ - - +

Avi

+
+

User How-Tos

) } } - - export default NewPost; \ No newline at end of file + + export default NewPost; diff --git a/src/components/UserProfile/Avatar.js b/src/components/UserProfile/Avatar.js deleted file mode 100644 index 341ebf7..0000000 --- a/src/components/UserProfile/Avatar.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { withStyles } from '@material-ui/core/styles'; -import Avatar from '@material-ui/core/Avatar'; - -const styles = { - avatar: { - margin: 10, - }, - bigAvatar: { - margin: 10, - width: 60, - height: 60, - }, -}; - -function ImageAvatars(props) { - const { classes } = props; - return ( - - ); -} - -ImageAvatars.propTypes = { - classes: PropTypes.object.isRequired, -}; - -export default withStyles(styles)(ImageAvatars); \ No newline at end of file diff --git a/src/components/ViewHowTo.js b/src/components/ViewHowTo.js deleted file mode 100644 index 7f105e6..0000000 --- a/src/components/ViewHowTo.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import AppBar from './AppBar'; -import { Paper, Avatar } from '@material-ui/core'; -import Fab from '@material-ui/core/Fab'; -import ShareIcon from '@material-ui/icons/Share'; -import FavoriteIcon from '@material-ui/icons/Favorite'; -import CommentIcon from '@material-ui/icons/Comment'; - -const ViewHowTo = props => { - return ( -
- -

{props.title}

- { console.log(`User ${props.creator_id}`) }}/> {/* Link to user profile */} - - {props.body} - - { console.log(`Heart ${props.id}`) }}> {/* idk */} - - - { console.log(`Share ${props.id}`) }}> {/* return address*/} - - - { console.log(`Add comment? ${props.id}`) }}> {/* send delete, change to delete?s */} - - Comment - -
- ) - } - - ViewHowTo.defaultProps = { - id: null, - title: 'Sample', - created_at: 'createdAt', - body: 'sampleBody', - likes: 100, - updated_at: 'updatedAt', - creator_id: 'creatorID', - }; - - export default ViewHowTo; \ No newline at end of file diff --git a/src/containers/Dashboard.js b/src/containers/Dashboard.js new file mode 100644 index 0000000..6685a90 --- /dev/null +++ b/src/containers/Dashboard.js @@ -0,0 +1,63 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { fetchUsers, fetchPosts, fetchCategories, editPost, deletePost } from '../actions'; +import { withStyles } from '@material-ui/core/styles'; +import MenuBar from './MenuBar'; +import HowToCard from '../components/HowToCard'; +import { getFilteredPosts } from '../reducers'; + +const styles = { + postsContainer: { + display: 'flex', + flexFlow: 'row wrap' + } +}; + +class Dashboard extends Component { + componentDidMount() { + this.props.fetchUsers(); + this.props.fetchPosts(); + this.props.fetchCategories(); + } + + render() { + const { classes, history, match, posts, users, editPost, deletePost } = this.props; + + return ( +
+
+ +
+
+
+ {posts.allPosts && + posts.allPosts.map(post => ( + + ))} +
+
+
+ ); + } +} + +// category & user IDs can be added to the second argument of getFilteredPosts as well +// these should probably be handled via routes: +// category/:id +// user/:id +const mapStateToProps = ({ posts, searchInput, users }) => ({ + posts: getFilteredPosts(posts, { searchInput }), + users +}); + +export default connect( + mapStateToProps, + { fetchUsers, fetchPosts, fetchCategories, editPost, deletePost } +)(withStyles(styles)(Dashboard)); diff --git a/src/components/AppBar.js b/src/containers/MenuBar.js similarity index 96% rename from src/components/AppBar.js rename to src/containers/MenuBar.js index 0cbac5c..54563d7 100644 --- a/src/components/AppBar.js +++ b/src/containers/MenuBar.js @@ -96,7 +96,7 @@ const styles = theme => ({ } }); -class PrimarySearchAppBar extends React.Component { +class PrimarySearchMenuBar extends React.Component { state = { anchorEl: null, mobileMoreAnchorEl: null @@ -152,7 +152,7 @@ class PrimarySearchAppBar extends React.Component { onClose={this.handleMenuClose} > Profile - Logout + Logout ); @@ -217,8 +217,8 @@ class PrimarySearchAppBar extends React.Component { />
- - + +
@@ -251,7 +251,7 @@ class PrimarySearchAppBar extends React.Component { } } -PrimarySearchAppBar.propTypes = { +PrimarySearchMenuBar.propTypes = { classes: PropTypes.object.isRequired }; @@ -260,4 +260,4 @@ const mapStateToProps = ({ searchInput }) => ({ searchInput }); export default connect( mapStateToProps, { updateInput } -)(withStyles(styles)(PrimarySearchAppBar)); +)(withStyles(styles)(PrimarySearchMenuBar)); diff --git a/src/containers/NewPost.js b/src/containers/NewPost.js new file mode 100644 index 0000000..6534821 --- /dev/null +++ b/src/containers/NewPost.js @@ -0,0 +1,65 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import ReactQuill from 'react-quill'; +import EditorButtons from '../components/EditorButtons'; +import 'react-quill/dist/quill.snow.css'; +import { addPost, editPost } from '../actions'; + +const initialPost = { title: '', body: '', id: null }; + +class NewPost extends Component { + state = { post: this.props.post }; + + handleTitle = ({ target: { value } }) => { + this.setState(({ post }) => ({ post: { ...post, title: value } })); + }; + + handleBody = value => { + this.setState(({ post }) => ({ post: { ...post, body: value } })); + }; + + handleSubmit = () => { + const { id } = this.state.post; + const { addPost, editPost, currentUser, history } = this.props; + + const div = document.createElement('div'); div.innerHTML = this.state.post.body; + const body = div.textContent || div.innerText || this.state.post; + const creator_id = currentUser.id; + + this.setState( + ({ post }) => ({ post: { ...post, body } }), + () => { + const postData = id ? this.state.post : { ...this.state.post, creator_id }; + + (Boolean(id) ? editPost(id, postData) : addPost(postData)).then(() => { + history.push('/dashboard'); + }); + + this.setState({ post: initialPost }); + } + ); + }; + + render() { + const { title, body } = this.state.post; + const { history } = this.props; + + return ( + + + + + + ); + } +} + +const mapStateToProps = (ownState, { location: { state } }) => ({ + post: state ? state[0] : initialPost, + currentUser: ownState.currentUser +}); + +export default connect( + mapStateToProps, + { addPost, editPost } +)(NewPost); diff --git a/src/components/Register.js b/src/containers/Register.js similarity index 95% rename from src/components/Register.js rename to src/containers/Register.js index 3d10cf6..3b73490 100644 --- a/src/components/Register.js +++ b/src/containers/Register.js @@ -12,7 +12,7 @@ import LockOutlinedIcon from '@material-ui/icons/LockOutlined'; import Paper from '@material-ui/core/Paper'; import Typography from '@material-ui/core/Typography'; import withStyles from '@material-ui/core/styles/withStyles'; -import RegisterRedirect from './RegisterRedirect'; +import RegisterRedirect from '../components/RegisterRedirect'; import { connect } from 'react-redux'; import { useInput } from '../hooks'; import { authLogin, authSignup } from '../actions'; @@ -56,7 +56,7 @@ const styles = theme => ({ } }); -const AuthForm = ({ classes, authLogin, authSignup, history: { push, replace }, location: { pathname } }) => { +const Register = ({ classes, authLogin, authSignup, history: { push, replace }, location: { pathname } }) => { const [email, setEmail, updateEmail] = useInput(); const [username, setUsername, updateUsername] = useInput(); const [password, setPassword, updatePassword] = useInput(); @@ -160,12 +160,11 @@ const AuthForm = ({ classes, authLogin, authSignup, history: { push, replace }, ); }; -AuthForm.propTypes = { - classes: PropTypes.object.isRequired, - handleSubmit: PropTypes.func.isRequired +Register.propTypes = { + classes: PropTypes.object.isRequired }; export default connect( null, { authLogin, authSignup } -)(withStyles(styles)(AuthForm)); +)(withStyles(styles)(Register)); diff --git a/src/reducers/currentUser.js b/src/reducers/currentUser.js index e66b34b..3a54f2d 100644 --- a/src/reducers/currentUser.js +++ b/src/reducers/currentUser.js @@ -1,9 +1,16 @@ import { LOGIN_SUCCESS, SIGNUP_SUCCESS } from "../actions/types"; -export default (state = null, action) => { +const loadUser = () => { + const serializedState = localStorage.getItem('currentUser'); + return Boolean(serializedState) ? JSON.parse(serializedState) : null; +}; + +export default (state = loadUser(), action) => { switch (action.type) { case SIGNUP_SUCCESS: case LOGIN_SUCCESS: + const serializedState = JSON.stringify(action.payload.currentUser); + localStorage.setItem('currentUser', serializedState); return action.payload.currentUser; default: return state; diff --git a/src/reducers/error.js b/src/reducers/error.js index 1db341f..45a4745 100644 --- a/src/reducers/error.js +++ b/src/reducers/error.js @@ -5,7 +5,11 @@ import { FETCH_CATEGORIES_FAILURE, ADD_CATEGORY_FAILURE, EDIT_CATEGORY_FAILURE, - DELETE_CATEGORY_FAILURE + DELETE_CATEGORY_FAILURE, + FETCH_POSTS_FAILURE, + ADD_POST_FAILURE, + EDIT_POST_FAILURE, + DELETE_POST_FAILURE } from '../actions/types'; export default (state, action) => { @@ -17,6 +21,10 @@ export default (state, action) => { case ADD_CATEGORY_FAILURE: case EDIT_CATEGORY_FAILURE: case DELETE_CATEGORY_FAILURE: + case FETCH_POSTS_FAILURE: + case ADD_POST_FAILURE: + case EDIT_POST_FAILURE: + case DELETE_POST_FAILURE: return action.payload.response ? action.payload.response.data.message : '?'; diff --git a/src/reducers/posts.js b/src/reducers/posts.js index 8f2fc4d..7772c34 100644 --- a/src/reducers/posts.js +++ b/src/reducers/posts.js @@ -2,9 +2,15 @@ import { FETCH_POSTS_SUCCESS, ADD_POST_SUCCESS, EDIT_POST_SUCCESS, DELETE_POST_S export default (state = [], action) => { switch (action.type) { + case EDIT_POST_SUCCESS: + const { id, changedPost } = action.payload; + return state.map(post => + post.id === id + ? changedPost + : post + ); case FETCH_POSTS_SUCCESS: case ADD_POST_SUCCESS: - case EDIT_POST_SUCCESS: case DELETE_POST_SUCCESS: return action.payload; default: @@ -15,10 +21,13 @@ export default (state = [], action) => { const getCategoryPosts = ({ posts_categories }, id) => posts_categories.reduce((acc, cur) => (cur.category_id === id ? [...acc, cur.post_id] : acc), []); -const getPostsBySearch = (state, filter) => ({ - ...state, - allPosts: state.allPosts.filter(({ title, body }) => title.includes(filter) || body.includes(filter)) -}); +const getPostsBySearch = (state, filter) => { + const pattern = new RegExp(filter, 'i'); + return { + ...state, + allPosts: state.allPosts.filter(({ title, body }) => pattern.test(title) || pattern.test(body)) + } +}; const getPostsByCategory = (state, id) => { console.log(state); diff --git a/src/reducers/status.js b/src/reducers/status.js index 11f3a0c..7ba1f36 100644 --- a/src/reducers/status.js +++ b/src/reducers/status.js @@ -19,7 +19,19 @@ import { EDIT_CATEGORY_FAILURE, DELETE_CATEGORY_START, DELETE_CATEGORY_SUCCESS, - DELETE_CATEGORY_FAILURE + DELETE_CATEGORY_FAILURE, + FETCH_POSTS_START, + FETCH_POSTS_SUCCESS, + FETCH_POSTS_FAILURE, + ADD_POST_START, + ADD_POST_SUCCESS, + ADD_POST_FAILURE, + EDIT_POST_START, + EDIT_POST_SUCCESS, + EDIT_POST_FAILURE, + DELETE_POST_START, + DELETE_POST_SUCCESS, + DELETE_POST_FAILURE } from '../actions/types'; export default (state = {}, action) => { @@ -59,6 +71,26 @@ export default (state = {}, action) => { case DELETE_CATEGORY_SUCCESS: case DELETE_CATEGORY_FAILURE: return { ...state, deletingCategory: false }; + case FETCH_POSTS_START: + return { ...state, fetchingPosts: true }; + case FETCH_POSTS_SUCCESS: + case FETCH_POSTS_FAILURE: + return { ...state, fetchingPosts: false }; + case ADD_POST_START: + return { ...state, addingPost: true }; + case ADD_POST_SUCCESS: + case ADD_POST_FAILURE: + return { ...state, addingPost: false }; + case EDIT_POST_START: + return { ...state, editingPost: true }; + case EDIT_POST_SUCCESS: + case EDIT_POST_FAILURE: + return { ...state, editingPost: false }; + case DELETE_POST_START: + return { ...state, deletingPost: true }; + case DELETE_POST_SUCCESS: + case DELETE_POST_FAILURE: + return { ...state, deletingPost: false }; default: return state; } diff --git a/src/reducers/users.js b/src/reducers/users.js index abf3d06..9d9fefb 100644 --- a/src/reducers/users.js +++ b/src/reducers/users.js @@ -3,7 +3,9 @@ import { FETCH_USERS_SUCCESS } from "../actions/types"; export default (state = [], action) => { switch (action.type) { case FETCH_USERS_SUCCESS: - return action.payload; + return action.payload.reduce( + (acc, cur) => ({ ...acc, [cur.id]: cur }), + {}); default: return state; }