diff --git a/.gitignore b/.gitignore
index 028e2a6..9c301b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ public/bundle.js
package-lock.json
*hot-update.js
*hot-update.json
+env.sh
diff --git a/backend/auth.js b/backend/auth.js
new file mode 100644
index 0000000..e9768fd
--- /dev/null
+++ b/backend/auth.js
@@ -0,0 +1,30 @@
+const express = require('express');
+const router = express.Router();
+const User = require('../root/models').User;
+
+module.exports = (passport) => {
+ router.post('/register', (req, res) => {
+ console.log('here', req.body);
+ User.create({
+ username: req.body.username,
+ password: req.body.password
+ })
+ .then(user => {
+ res.json({success: true, user: user});
+ })
+ .catch(err => {
+ res.json({success: false, err: err});
+ });
+ });
+
+ router.post('/login', passport.authenticate('local'), (req, res) => {
+ res.json({success: true, user: req.user});
+ });
+
+ router.get('/logout', (req, res) => {
+ req.logout();
+ res.json({success: true});
+ });
+
+ return router;
+};
diff --git a/backend/routes.js b/backend/routes.js
index 9dd2215..ab1af14 100644
--- a/backend/routes.js
+++ b/backend/routes.js
@@ -1,11 +1,66 @@
const express = require('express');
const router = express.Router();
+const User = require('../root/models').User;
+const Post = require('../root/models').Post;
// YOUR API ROUTES HERE
+router.get('/:username', (req, res) => {
+ User.findOne({where: {username: req.params.username}})
+ .then(user => {
+ console.log('user when finding by username: ', user);
+ res.json({success: true, user: user});
+ })
+ .catch(err => {
+ res.json({success: false, err: err});
+ });
+});
+
+router.get('/', (req, res) => {
+ console.log('req user is: ************************', req.user);
+ User.findById(req.user.id)
+ .then(user => {
+ console.log('user when finding user on /: ', user);
+ res.json({success: true, user: user});
+ })
+ .catch(err => {
+ res.json({success: false, err: err});
+ });
+});
+
+router.post('/post/new', (req, res) => {
+ console.log('req user is ', req.user);
+ Post.create({
+ title: req.body.title,
+ content: req.body.content,
+ postId: req.body.postId,
+ userId: req.user.id
+ })
+ .then(post => {
+ res.json({success: true, post: post});
+ })
+ .catch(err => {
+ res.json({success: false, err: err});
+ });
+});
+
+router.get('/post/all', (req, res) => {
+ Post.findAll({where: {postId: null}})
+ .then(posts => {
+ res.json({success: true, posts: posts});
+ })
+ .catch(err => {
+ res.json({success: false, err: err});
+ });
+});
-// SAMPLE ROUTE
-router.use('/users', (req, res) => {
- res.json({ success: true });
+router.get('/post/:id', (req, res) => {
+ Post.findById(req.params.id)
+ .then(post => {
+ res.json({success: true, post: post});
+ })
+ .catch(err => {
+ res.json({success: false, err: err});
+ });
});
module.exports = router;
diff --git a/frontend/actions/index.js b/frontend/actions/index.js
index 2bba168..c6a45f0 100644
--- a/frontend/actions/index.js
+++ b/frontend/actions/index.js
@@ -1,3 +1,19 @@
// Action Creators
-// import * as types from './types';
+import * as types from './types';
+
+export function toggleLoginModal() {
+ return {type: types.TOGGLE_LOGIN_MODAL};
+}
+
+export function logout() {
+ return {type: types.LOGOUT};
+}
+
+export function login(user) {
+ return {type: types.LOGIN, user: user};
+}
+
+export function getPosts(posts) {
+ return {type: types.GET_POSTS, posts: posts};
+}
diff --git a/frontend/actions/types.js b/frontend/actions/types.js
index 9836597..5115571 100644
--- a/frontend/actions/types.js
+++ b/frontend/actions/types.js
@@ -1 +1,8 @@
/* Action types */
+export const TOGGLE_LOGIN_MODAL = 'TOGGLE_LOGIN_MODAL';
+
+export const LOGIN = 'LOGIN';
+
+export const LOGOUT = 'LOGOUT';
+
+export const GET_POSTS = 'GET_POSTS';
diff --git a/frontend/assets/stylesheets/base.scss b/frontend/assets/stylesheets/base.scss
index 1ddbba3..706b3c5 100644
--- a/frontend/assets/stylesheets/base.scss
+++ b/frontend/assets/stylesheets/base.scss
@@ -1,4 +1,12 @@
h1 {
font-family: helvetica;
font-weight: 200;
-}
\ No newline at end of file
+}
+
+.modal-container {
+ position: relative;
+}
+
+.modal-container .modal, .modal-container .modal-backdrop {
+ position: absolute;
+}
diff --git a/frontend/components/AuthModal.js b/frontend/components/AuthModal.js
new file mode 100644
index 0000000..f05fd0c
--- /dev/null
+++ b/frontend/components/AuthModal.js
@@ -0,0 +1,76 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Modal, Button } from 'react-bootstrap';
+import axios from 'axios';
+
+class AuthModal extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+
+ handleRegister() {
+ axios.post('http://localhost:3000/register', {username: this.username.value, password: this.password.value}, {withCredentials: true})
+ .then((response) => {
+ // console.log("response", response);
+ if(response.data.success) {
+ this.props.login(response.data.user);
+ this.props.toggleLoginModal();
+ } else {
+ console.log("register redirect error", response.data.err);
+ }
+ })
+ .catch((err) => {
+ console.log("register post request error", err);
+ });
+ }
+
+ handleLogin() {
+ axios.post('http://localhost:3000/login', {username: this.username.value, password: this.password.value}, {withCredentials: true})
+ .then((response) => {
+ // console.log("response", response.data.user);
+ if(response.data.success) {
+ this.props.login(response.data.user);
+ this.props.toggleLoginModal();
+ } else {
+ console.log("login redirect error", response.data.err);
+ }
+ })
+ .catch((err) => {
+ console.log("login post request error", err);
+ });
+ }
+
+ render() {
+ // console.log('this.props', this.props);
+ return(
+
+
+ Contained Modal
+
+
+ { this.username = input; }}/>
+ { this.password = input; }}/>
+
+
+
+
+
+
+ );
+ }
+}
+
+AuthModal.propTypes = {
+ isModalOpen: PropTypes.bool,
+ toggleLoginModal: PropTypes.func,
+ // username: PropTypes.string,
+ // password: PropTypes.string,
+ login: PropTypes.func,
+};
+
+export default AuthModal;
diff --git a/frontend/components/Feed.js b/frontend/components/Feed.js
new file mode 100644
index 0000000..8da990c
--- /dev/null
+++ b/frontend/components/Feed.js
@@ -0,0 +1,82 @@
+// import React from 'react';
+// import PropTypes from 'prop-types';
+// import axios from 'axios';
+//
+// const Feed = ( { getPosts } ) => {
+// const componentDidMount = () => {
+// axios.get('http://localhost:3000/post/all', {withCredentials: true})
+// .then((response) => {
+// console.log("response", response);
+// if(response.data.success) {
+// getPosts(response.data.posts);
+// } else {
+// console.log("posts error", response.data.err);
+// }
+// })
+// .catch((err) => {
+// console.log("get posts error", err);
+// });
+// };
+//
+// return (
+//
+//
Post
+//
Post
+//
Post
+//
Post
+//
Post
+//
Post
+//
Post
+//
+// );
+// };
+//
+// Feed.propTypes = {
+// getPosts: PropTypes.func,
+// };
+//
+//
+// export default Feed;
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import axios from 'axios';
+import { Link }from 'react-router-dom';
+
+class Feed extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+
+ componentDidMount() {
+ axios.get('http://localhost:3000/post/all', {withCredentials: true})
+ .then((response) => {
+ console.log("response", response);
+ if(response.data.success) {
+ this.props.getPosts(response.data.posts);
+ } else {
+ console.log("posts error", response.data.err);
+ }
+ })
+ .catch((err) => {
+ console.log("get posts error", err);
+ });
+ }
+
+ render() {
+ console.log(this.props.posts, 'here in feed with the posts!!!!!!!!');
+ return(
+
+ Hello Posts
+ {this.props.posts.map((elem) =>
{elem.title} - {elem.content} by {elem.userId} at {elem.createdAt})}
+
+ );
+ }
+}
+
+Feed.propTypes = {
+ getPosts: PropTypes.func,
+ posts: PropTypes.array,
+};
+
+export default Feed;
diff --git a/frontend/components/Header.js b/frontend/components/Header.js
new file mode 100644
index 0000000..4504552
--- /dev/null
+++ b/frontend/components/Header.js
@@ -0,0 +1,16 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const Header = ( { } ) => {
+ return (
+
+
+
+ );
+};
+
+Header.propTypes = {
+};
+
+
+export default Header;
diff --git a/frontend/components/NewPost.js b/frontend/components/NewPost.js
new file mode 100644
index 0000000..f934fe4
--- /dev/null
+++ b/frontend/components/NewPost.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Button } from 'react-bootstrap';
+import axios from 'axios';
+
+class NewPost extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+
+ submitPost() {
+ axios.post('http://localhost:3000/post/new', {title: this.title.value, content: this.content.value}, {withCredentials: true})
+ .then((response) => {
+ // console.log("response", response.data.user);
+ if(response.data.success) {
+ console.log('hey');
+ this.props.history.push('/');
+ } else {
+ console.log("post error", response.data.err);
+ }
+ })
+ .catch((err) => {
+ console.log("submit post request error", err);
+ });
+ }
+
+ render() {
+ return(
+
+
+ { this.title = input; }}/>
+
+
+ );
+ }
+}
+
+NewPost.propTypes = {
+ history: PropTypes.object,
+};
+
+export default NewPost;
diff --git a/frontend/components/PostPage.js b/frontend/components/PostPage.js
new file mode 100644
index 0000000..4c935dd
--- /dev/null
+++ b/frontend/components/PostPage.js
@@ -0,0 +1,87 @@
+// import React from 'react';
+// import PropTypes from 'prop-types';
+// // import { Button } from 'react-bootstrap';
+// import axios from 'axios';
+//
+// class PostPage extends React.Component {
+// constructor(props) {
+// super(props);
+// this.state = {
+// post: {}
+// };
+// }
+//
+// componentDidMount() {
+// // console.log('this', this.props.location.pathname);
+// axios.get(`http://localhost:3000${this.props.location.pathname}`, {withCredentials: true})
+// .then((response) => {
+// console.log("response", response);
+// if(response.data.success) {
+// this.setState({
+// post: response.data.post
+// });
+// } else {
+// console.log("posts error", response.data.err);
+// }
+// })
+// .catch((err) => {
+// console.log("get posts error", err);
+// });
+// }
+//
+// render() {
+// console.log(this.state);
+// return(
+//
+//
{this.state.post.title}
+//
{this.state.post.createdAt}
+//
{this.state.post.content}
+//
+// );
+// }
+// }
+//
+// PostPage.propTypes = {
+// history: PropTypes.object,
+// location: PropTypes.object,
+// };
+//
+// export default PostPage;
+
+import PropTypes from 'prop-types';
+import React from 'react';
+import { connect } from 'react-redux';
+import * as actions from '../actions/index';
+
+const PostPage = ({ history }) => {
+ console.log('history is', history);
+ return (
+
+ hi
+
+ );
+};
+
+PostPage.propTypes = {
+ history: PropTypes.object,
+};
+
+const mapStateToProps = (state) => {
+ // console.log(state);
+ return {
+ // isModalOpen: state.toggleLoginModal.isModalOpen,
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ toggleLoginModal: () => {
+ dispatch(actions.toggleLoginModal());
+ },
+ };
+};
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(PostPage);
diff --git a/frontend/components/SideBar.js b/frontend/components/SideBar.js
new file mode 100644
index 0000000..a020ac1
--- /dev/null
+++ b/frontend/components/SideBar.js
@@ -0,0 +1,59 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Button } from 'react-bootstrap';
+import axios from 'axios';
+// import { Link } from 'react-router-dom';
+
+
+const SideBar = ( { toggleLoginModal, username, logout, history } ) => {
+ const handleLogout = () => {
+ axios.get('http://localhost:3000/logout', {withCredentials: true})
+ .then((response) => {
+ console.log("response", response);
+ if(response.data.success) {
+ logout();
+ } else {
+ console.log("logout redirect error", response.data.err);
+ }
+ })
+ .catch((err) => {
+ console.log("logout get request error", err);
+ });
+ };
+
+ const handleSubmitPost = () => {
+ if(username.length > 0) {
+ console.log('hello user', history);
+ history.push('/post/new');
+ } else {
+ toggleLoginModal();
+ }
+ };
+
+ return (
+
+
+ {username.length > 0
+ ?
+
Welcome {username}
+
+ {/*
New Post */}
+
+ :
+ }
+
+
+
+ );
+};
+
+SideBar.propTypes = {
+ isModalOpen: PropTypes.bool,
+ toggleLoginModal: PropTypes.func,
+ username: PropTypes.string,
+ logout: PropTypes.func,
+ history: PropTypes.object,
+};
+
+
+export default SideBar;
diff --git a/frontend/containers/AppContainer.js b/frontend/containers/AppContainer.js
index 7c29205..9f6a30b 100644
--- a/frontend/containers/AppContainer.js
+++ b/frontend/containers/AppContainer.js
@@ -1,28 +1,58 @@
import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
-import Title from '../components/Title';
+import Header from '../components/Header';
+import Feed from '../components/Feed';
+import SideBar from '../components/SideBar';
+import AuthModal from '../components/AuthModal';
+import * as actions from '../actions/index';
-const AppContainer = ({ name }) => {
+const AppContainer = ({ isModalOpen, toggleLoginModal, login, username, logout, history, getPosts, posts}) => {
return (
);
};
AppContainer.propTypes = {
- name: PropTypes.string,
+ isModalOpen: PropTypes.bool,
+ toggleLoginModal: PropTypes.func,
+ logout: PropTypes.func,
+ login: PropTypes.func,
+ username: PropTypes.string,
+ history: PropTypes.object,
+ getPosts: PropTypes.func,
+ posts: PropTypes.array,
};
const mapStateToProps = (state) => {
+ // console.log(state);
return {
- name: state.name
+ isModalOpen: state.toggleLoginModal.isModalOpen,
+ username: state.login.username,
+ posts: state.getPosts,
};
};
-const mapDispatchToProps = (/* dispatch */) => {
+const mapDispatchToProps = (dispatch) => {
return {
+ toggleLoginModal: () => {
+ dispatch(actions.toggleLoginModal());
+ },
+ logout: () => {
+ dispatch(actions.logout());
+ },
+ login: (user) => {
+ // console.log('here', user);
+ dispatch(actions.login(user));
+ },
+ getPosts: (posts) => {
+ dispatch(actions.getPosts(posts));
+ }
};
};
diff --git a/frontend/containers/Root.dev.js b/frontend/containers/Root.dev.js
index c0f8d69..4d2eb63 100644
--- a/frontend/containers/Root.dev.js
+++ b/frontend/containers/Root.dev.js
@@ -3,18 +3,29 @@ import React from 'react';
import {Provider} from 'react-redux';
import AppContainer from './AppContainer.js';
import DevTools from './DevTools';
+import { HashRouter, Route, Switch } from 'react-router-dom';
+import NewPost from '../components/NewPost';
+import PostPage from '../components/PostPage';
-export default function Root({ store }) {
+
+export default function Root({ store, history }) {
return (
-
+
);
}
Root.propTypes = {
- store: PropTypes.object.isRequired
+ store: PropTypes.object.isRequired,
+ history: PropTypes.object
};
diff --git a/frontend/reducers/index.js b/frontend/reducers/index.js
index 4d415fd..1b98fdb 100644
--- a/frontend/reducers/index.js
+++ b/frontend/reducers/index.js
@@ -1,8 +1,17 @@
-function rootReducer(state = {name: 'Horizons'}, action) {
- switch (action.type) {
- default:
- return state;
- }
-}
+import { routerReducer } from 'react-router-redux';
+import { combineReducers } from 'redux';
+import toggleModalReducer from './toggleModalReducer';
+// import logoutReducer from './logoutReducer';
+import loginReducer from './loginReducer';
+import postsReducer from './postsReducer';
+
+
+const rootReducer = combineReducers({
+ toggleLoginModal: toggleModalReducer,
+ getPosts: postsReducer,
+ login: loginReducer,
+ routing: routerReducer // this reducer is used by React Router in Redux
+});
+
export default rootReducer;
diff --git a/frontend/reducers/loginReducer.js b/frontend/reducers/loginReducer.js
new file mode 100644
index 0000000..930c069
--- /dev/null
+++ b/frontend/reducers/loginReducer.js
@@ -0,0 +1,19 @@
+function loginReducer(state = {username: "", password: ""}, action) {
+ // console.log('here 3', state, action);
+ switch (action.type) {
+ case 'LOGIN':
+ const newState = Object.assign({}, state);
+ newState.username = action.user.username;
+ newState.password = action.user.password;
+ return newState;
+ case 'LOGOUT':
+ const newState2 = Object.assign({}, state);
+ newState2.username = "";
+ newState2.password = "";
+ return newState2;
+ default:
+ return state;
+ }
+}
+
+export default loginReducer;
diff --git a/frontend/reducers/logoutReducer.js b/frontend/reducers/logoutReducer.js
new file mode 100644
index 0000000..6f5eba2
--- /dev/null
+++ b/frontend/reducers/logoutReducer.js
@@ -0,0 +1,13 @@
+function logoutReducer(state = {username: "", password: ""}, action) {
+ switch (action.type) {
+ case 'LOGOUT':
+ const newState = Object.assign({}, state);
+ newState.username = "";
+ newState.password = "";
+ return newState;
+ default:
+ return state;
+ }
+}
+
+export default logoutReducer;
diff --git a/frontend/reducers/postsReducer.js b/frontend/reducers/postsReducer.js
new file mode 100644
index 0000000..7af1b4c
--- /dev/null
+++ b/frontend/reducers/postsReducer.js
@@ -0,0 +1,13 @@
+function postsReducer(state = [], action) {
+ console.log('here 3', state, action);
+ switch (action.type) {
+ case 'GET_POSTS':
+ let newState = [...state];
+ newState = action.posts;
+ return newState;
+ default:
+ return state;
+ }
+}
+
+export default postsReducer;
diff --git a/frontend/reducers/toggleModalReducer.js b/frontend/reducers/toggleModalReducer.js
new file mode 100644
index 0000000..ad961b0
--- /dev/null
+++ b/frontend/reducers/toggleModalReducer.js
@@ -0,0 +1,12 @@
+function toggleModalReducer(state = {isModalOpen: false}, action) {
+ switch (action.type) {
+ case 'TOGGLE_LOGIN_MODAL':
+ const newState = Object.assign({}, state);
+ newState.isModalOpen = !newState.isModalOpen;
+ return newState;
+ default:
+ return state;
+ }
+}
+
+export default toggleModalReducer;
diff --git a/frontend/store/configureStore.dev.js b/frontend/store/configureStore.dev.js
index f87288c..4a35542 100644
--- a/frontend/store/configureStore.dev.js
+++ b/frontend/store/configureStore.dev.js
@@ -1,6 +1,7 @@
import { createStore, compose } from 'redux';
import rootReducer from '../reducers';
import DevTools from '../containers/DevTools';
+import createHistory from 'history/createBrowserHistory';
export function configureStore(initialState) {
return createStore(
@@ -11,3 +12,5 @@ export function configureStore(initialState) {
)
);
}
+
+export const history = createHistory();
diff --git a/package.json b/package.json
index 54019e8..a9855ed 100644
--- a/package.json
+++ b/package.json
@@ -14,25 +14,39 @@
"author": "",
"license": "ISC",
"dependencies": {
+ "axios": "^0.17.0",
"babel-core": "^6.24.1",
"babel-loader": "^6.4.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
+ "body-parser": "^1.18.2",
+ "cookie-parser": "^1.4.3",
+ "cookie-session": "^2.0.0-beta.3",
"css-loader": "^0.28.0",
"enzyme": "^2.8.1",
"expect": "^1.20.2",
"express": "^4.15.2",
+ "express-session": "^1.15.6",
+ "history": "^4.7.2",
"mocha": "^3.2.0",
"node-sass": "^4.5.2",
+ "passport": "^0.4.0",
+ "passport-local": "^1.0.0",
+ "pg": "^7.4.0",
+ "pg-hstore": "^2.3.2",
"prop-types": "^15.5.8",
"react": "^15.5.4",
- "react-dom": "^15.5.4",
+ "react-bootstrap": "^0.31.5",
+ "react-dom": "^15.6.2",
"react-redux": "^5.0.5",
+ "react-router-dom": "^4.2.2",
+ "react-router-redux": "^4.0.8",
"redux": "^3.7.2",
"redux-devtools": "^3.4.0",
"redux-devtools-dock-monitor": "^1.1.2",
"redux-devtools-log-monitor": "^1.3.0",
"sass-loader": "^6.0.3",
+ "sequelize": "^4.22.5",
"style-loader": "^0.16.1",
"webpack": "^2.3.3"
},
diff --git a/public/index.html b/public/index.html
index 9604aed..15a8c18 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2,10 +2,11 @@
+
Node + React Starter
-
\ No newline at end of file
+