diff --git a/auth/client/index.html b/auth/client/index.html index 22a662b..ac29ebf 100644 --- a/auth/client/index.html +++ b/auth/client/index.html @@ -3,7 +3,6 @@ -
diff --git a/auth/client/src/actions/index.js b/auth/client/src/actions/index.js index 616738f..f153afb 100644 --- a/auth/client/src/actions/index.js +++ b/auth/client/src/actions/index.js @@ -13,15 +13,7 @@ export function signinUser({ email, password }) { return function(dispatch) { // Submit email/password to the server axios.post(`${ROOT_URL}/signin`, { email, password }) - .then(response => { - // If request is good... - // - Update state to indicate user is authenticated - dispatch({ type: AUTH_USER }); - // - Save the JWT token - localStorage.setItem('token', response.data.token); - // - redirect to the route '/feature' - browserHistory.push('/feature'); - }) + .then(response => authUser(dispatch, response)) .catch(() => { // If request is bad... // - Show an error to the user @@ -33,16 +25,24 @@ export function signinUser({ email, password }) { export function signupUser({ email, password }) { return function(dispatch) { axios.post(`${ROOT_URL}/signup`, { email, password }) - .then(response => { - dispatch({ type: AUTH_USER }); - localStorage.setItem('token', response.data.token); - browserHistory.push('/feature'); - }) + .then(response => authUser(dispatch, response)) .catch(response => dispatch(authError(response.data.error))); } } -export function authError(error) { + +//refactoring actions optimization, external from (signinUser e signupUser) +export function authUser(dispatch, response) { + // If request is good... + // - Update state to indicate user is authenticated + dispatch({ type: AUTH_USER }); + // - Save the JWT token + localStorage.setItem('token', response.data.token); // localStorage is a Web API (DOM) we just set a name and pass the token + // - redirect to the route '/feature' + browserHistory.push('/feature'); +} + +export function authError(error) { //this action is external from (signinUser e signupUser) coz it's easier to share with these 2 (so no repeat) return { type: AUTH_ERROR, payload: error diff --git a/auth/client/src/components/app.js b/auth/client/src/components/app.js index 8807875..f968714 100644 --- a/auth/client/src/components/app.js +++ b/auth/client/src/components/app.js @@ -8,7 +8,7 @@ export default class App extends Component { return (
- {this.props.children} + {this.props.children} {/* has child routes to show*/}
); } diff --git a/auth/client/src/components/auth/signin.js b/auth/client/src/components/auth/signin.js index 0fffc0e..21925dc 100644 --- a/auth/client/src/components/auth/signin.js +++ b/auth/client/src/components/auth/signin.js @@ -1,14 +1,14 @@ import React, { Component } from 'react'; -import { reduxForm } from 'redux-form'; -import * as actions from '../../actions'; +import { reduxForm } from 'redux-form';// import the HOC from redux-form +import * as actions from '../../actions';//import actions creators class Signin extends Component { - handleFormSubmit({ email, password }) { - // Need to do something to log user in - this.props.signinUser({ email, password }); + + componentWillMount() {// clear the server err for every back and forth to the page for renderAlert() + this.props.authError(''); } - - renderAlert() { + +renderAlert() { // show up the err msg if it exists [funct called in render..] if (this.props.errorMessage) { return (
@@ -17,12 +17,19 @@ class Signin extends Component { ); } } + + handleFormSubmit({ email, password }) {//callback #1 + // Need to do something to log user in + this.props.signinUser({ email, password });//call the action creator + } + + render() { - const { handleSubmit, fields: { email, password }} = this.props; + const { handleSubmit, fields: { email, password }} = this.props;//hooks up handleSubmit (method from redux-form to the fields) return ( -
+ {/*hooks up handleSubmit to the callback #1*/}
@@ -45,4 +52,4 @@ function mapStateToProps(state) { export default reduxForm({ form: 'signin', fields: ['email', 'password'] -}, mapStateToProps, actions)(Signin); +}, mapStateToProps, actions)(Signin);//hooks up the actions creators diff --git a/auth/client/src/components/auth/signup.js b/auth/client/src/components/auth/signup.js index 345d2d9..8f3a5ea 100644 --- a/auth/client/src/components/auth/signup.js +++ b/auth/client/src/components/auth/signup.js @@ -2,10 +2,19 @@ import React, { Component } from 'react'; import { reduxForm } from 'redux-form'; import * as actions from '../../actions'; + //helper comp function, split strings when needed (to have the right string output from the field name in the loop) + function splitString(initialtext) { + let regex1 = RegExp(/(?=[A-Z])/); //has cap letter in + let are2words = regex1.test(initialtext); // check if true + let result= are2words ? initialtext.split(/(?=[A-Z])/).join(" ") : initialtext; + //console.log(initialtext, are2words); + return result + } + class Signup extends Component { - handleFormSubmit(formProps) { - // Call action creator to sign up the user! - this.props.signupUser(formProps); + + componentWillMount() {// clear the server err for every back and forth to the page for renderAlert() + this.props.authError(''); } renderAlert() { @@ -17,27 +26,50 @@ class Signup extends Component { ); } } + + handleFormSubmit(formProps) { + // Call action creator to sign up the user! + this.props.signupUser(formProps); + } + + + + // comp optimization + renderFieldsets(fieldlist){ + + let fieldsetArr = Object.values(fieldlist).map(fieldobj => ( +
+ + + {fieldobj.touched && fieldobj.error &&
{fieldobj.error}
} +
+ )); + return fieldsetArr; + } + render() { const { handleSubmit, fields: { email, password, passwordConfirm }} = this.props; return ( + {/* keeping this for didactic purpose
- {email.touched && email.error &&
{email.error}
} + {email.touched && email.error &&
{email.error}
} //if 2&&== true - return the last vale of the && seq [js trick]
- {password.touched && password.error &&
{password.error}
} + {password.touched && password.error &&
{password.error}
} //manage 2 type of err with 1 block
- {passwordConfirm.touched && passwordConfirm.error &&
{passwordConfirm.error}
} -
+ {passwordConfirm.touched && passwordConfirm.error &&
{passwordConfirm.error}
} +
*/} + {this.renderFieldsets(this.props.fields)} {this.renderAlert()}
@@ -45,10 +77,13 @@ class Signup extends Component { } } -function validate(formProps) { +function validate(formProps) {// the arg is provided by HOC redux-form [and is a obj of the fields-value] const errors = {}; - - if (!formProps.email) { + + //console.log(formProps); + + /* keeping this for didactic purpose + if (!formProps.email) { errors.email = 'Please enter an email'; } @@ -58,7 +93,18 @@ function validate(formProps) { if (!formProps.passwordConfirm) { errors.passwordConfirm = 'Please enter a password confirmation'; - } + }*/ + + //my compressed approach of the above + Object.keys(formProps).map(field => + { + if (!formProps[field]) { + //errors[field] = 'Please enter ' + (field === 'email' ? 'an ' : 'a ') + field; + errors[field] = `Please enter ${(field === 'email' ? 'an ' : 'a ') + splitString(field)}`; + } + } + ) + if (formProps.password !== formProps.passwordConfirm) { errors.password = 'Passwords must match'; diff --git a/auth/client/src/components/feature.js b/auth/client/src/components/feature.js index bc71398..d900211 100644 --- a/auth/client/src/components/feature.js +++ b/auth/client/src/components/feature.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import * as actions from '../actions'; +//import RequireAuth from './auth/require_auth'; ALT V just in case we want to use the HOC here class Feature extends Component { componentWillMount() { @@ -18,4 +19,5 @@ function mapStateToProps(state) { return { message: state.auth.message }; } -export default connect(mapStateToProps, actions)(Feature); +export default connect(mapStateToProps, actions)(Feature); +// ALT V just in case we wanna use HOC here not in the route, wrap like this RequireAuth(Feature) diff --git a/auth/client/src/components/header.js b/auth/client/src/components/header.js index e6c4166..29f76ea 100644 --- a/auth/client/src/components/header.js +++ b/auth/client/src/components/header.js @@ -11,7 +11,7 @@ class Header extends Component { } else { // show a link to sign in or sign up - return [ + return [ // returns an array of li (so don't have err without div, rendering multiple items at the same level)
  • Sign In
  • , diff --git a/auth/client/src/index.js b/auth/client/src/index.js index 1ec27bf..e7d9f9f 100644 --- a/auth/client/src/index.js +++ b/auth/client/src/index.js @@ -16,13 +16,13 @@ import reducers from './reducers'; import { AUTH_USER } from './actions/types'; const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore); -const store = createStoreWithMiddleware(reducers); +const store = createStoreWithMiddleware(reducers); // create store outside to get it before check the token const token = localStorage.getItem('token'); // If we have a token, consider the user to be signed in if (token) { // we need to update application state - store.dispatch({ type: AUTH_USER }); + store.dispatch({ type: AUTH_USER }); // we can dispatch the action to the reducers [so if user is already auth we know it] } ReactDOM.render( diff --git a/auth/client/src/reducers/auth_reducer.js b/auth/client/src/reducers/auth_reducer.js index 1e750f9..861d302 100644 --- a/auth/client/src/reducers/auth_reducer.js +++ b/auth/client/src/reducers/auth_reducer.js @@ -8,7 +8,7 @@ import { export default function(state = {}, action) { switch(action.type) { case AUTH_USER: - return { ...state, error: '', authenticated: true }; + return { ...state, error: '', authenticated: true }; // reset error in case user is auth case UNAUTH_USER: return { ...state, authenticated: false }; case AUTH_ERROR: diff --git a/auth/client/src/reducers/index.js b/auth/client/src/reducers/index.js index bec4976..5d68c58 100644 --- a/auth/client/src/reducers/index.js +++ b/auth/client/src/reducers/index.js @@ -1,9 +1,9 @@ import { combineReducers } from 'redux'; -import { reducer as form } from 'redux-form'; +import { reducer as form } from 'redux-form';// imp the reducer from redux-form and create an alias [... as form] to use a clearer name import authReducer from './auth_reducer'; const rootReducer = combineReducers({ - form, + form,// include the reducer from redux-form [form: form ES6 abbreviation] auth: authReducer }); diff --git a/auth/client/style/style.css b/auth/client/style/style.css index ee7dba2..86d18d1 100644 --- a/auth/client/style/style.css +++ b/auth/client/style/style.css @@ -1,3 +1,4 @@ .error { color: red; } +.captext { text-transform: capitalize;} diff --git a/auth/server/controllers/authentication.js b/auth/server/controllers/authentication.js index 58898ac..bf5cc1a 100644 --- a/auth/server/controllers/authentication.js +++ b/auth/server/controllers/authentication.js @@ -4,13 +4,13 @@ const config = require('../config'); function tokenForUser(user) { const timestamp = new Date().getTime(); - return jwt.encode({ sub: user.id, iat: timestamp }, config.secret); + return jwt.encode({ sub: user.id, iat: timestamp }, config.secret); // sub: and iat: are existing properties of jwt to be setted } exports.signin = function(req, res, next) { // User has already had their email and password auth'd // We just need to give them a token - res.send({ token: tokenForUser(req.user) }); + res.send({ token: tokenForUser(req.user) }); // req.user is returned from our Locastrategy in passport.js } exports.signup = function(req, res, next) { @@ -39,7 +39,7 @@ exports.signup = function(req, res, next) { user.save(function(err) { if (err) { return next(err); } - // Repond to request indicating the user was created + // Repond to request indicating the user was created and returning the user token res.json({ token: tokenForUser(user) }); }); }); diff --git a/auth/server/models/user.js b/auth/server/models/user.js index 11c93d8..acba23f 100644 --- a/auth/server/models/user.js +++ b/auth/server/models/user.js @@ -29,7 +29,7 @@ userSchema.pre('save', function(next) { }); }); -userSchema.methods.comparePassword = function(candidatePassword, callback) { +userSchema.methods.comparePassword = function(candidatePassword, callback) { // attach a new funct to our schema bcrypt.compare(candidatePassword, this.password, function(err, isMatch) { if (err) { return callback(err); } diff --git a/auth/server/router.js b/auth/server/router.js index 28dc265..901366e 100644 --- a/auth/server/router.js +++ b/auth/server/router.js @@ -2,11 +2,11 @@ const Authentication = require('./controllers/authentication'); const passportService = require('./services/passport'); const passport = require('passport'); -const requireAuth = passport.authenticate('jwt', { session: false }); +const requireAuth = passport.authenticate('jwt', { session: false });// session: false means we don't want cookies set (we use jwt) const requireSignin = passport.authenticate('local', { session: false }); module.exports = function(app) { - app.get('/', requireAuth, function(req, res) { + app.get('/', requireAuth, function(req, res) { // we say to use the requireAuth (we create above) to handle this route req before sendig a res res.send({ message: 'Super secret code is ABC123' }); }); app.post('/signin', requireSignin, Authentication.signin); diff --git a/auth/server/services/passport.js b/auth/server/services/passport.js index dc8d776..3de62eb 100644 --- a/auth/server/services/passport.js +++ b/auth/server/services/passport.js @@ -6,17 +6,17 @@ const ExtractJwt = require('passport-jwt').ExtractJwt; const LocalStrategy = require('passport-local'); // Create local strategy -const localOptions = { usernameField: 'email' }; +const localOptions = { usernameField: 'email' }; // just to set that if it searchs for user has to loook at email const localLogin = new LocalStrategy(localOptions, function(email, password, done) { // Verify this email and password, call done with the user // if it is the correct email and password // otherwise, call done with false User.findOne({ email: email }, function(err, user) { - if (err) { return done(err); } - if (!user) { return done(null, false); } + if (err) { return done(err); }// err in the operation + if (!user) { return done(null, false); } // no err but email (so user) not found // compare passwords - is `password` equal to user.password? - user.comparePassword(password, function(err, isMatch) { + user.comparePassword(password, function(err, isMatch) { //comparePassword is a method we created in user if (err) { return done(err); } if (!isMatch) { return done(null, false); } @@ -27,22 +27,22 @@ const localLogin = new LocalStrategy(localOptions, function(email, password, don // Setup options for JWT Strategy const jwtOptions = { - jwtFromRequest: ExtractJwt.fromHeader('authorization'), - secretOrKey: config.secret + jwtFromRequest: ExtractJwt.fromHeader('authorization'),//where to find the jtw (in this case header-authorization from the request) + secretOrKey: config.secret //what to use to decript the token (so we can have the user id back) }; // Create JWT strategy const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done) { // See if the user ID in the payload exists in our database - // If it does, call 'done' with that other + // If it does, call 'done' with that user // otherwise, call done without a user object - User.findById(payload.sub, function(err, user) { - if (err) { return done(err, false); } + User.findById(payload.sub, function(err, user) {// payload is the obj created with jwt.encode attached to the token in the db + if (err) { return done(err, false); } // if there is an err and we cannot find user (coz of the err) if (user) { - done(null, user); + done(null, user);// there is no err an we find a user } else { - done(null, false); + done(null, false);// there is no err but we don't find the user } }); }); diff --git a/hoc/index.html b/hoc/index.html index 22a662b..ac29ebf 100644 --- a/hoc/index.html +++ b/hoc/index.html @@ -3,7 +3,6 @@ -
    diff --git a/hoc/src/components/app.js b/hoc/src/components/app.js index 8807875..06d6f87 100644 --- a/hoc/src/components/app.js +++ b/hoc/src/components/app.js @@ -8,7 +8,7 @@ export default class App extends Component { return (
    - {this.props.children} + {this.props.children} {/* this coz the route of "resorces" component is called as child-route in the "App" component */}
    ); } diff --git a/hoc/src/components/header.js b/hoc/src/components/header.js index b91771f..2e41b82 100644 --- a/hoc/src/components/header.js +++ b/hoc/src/components/header.js @@ -4,7 +4,7 @@ import { connect } from 'react-redux'; import * as actions from '../actions'; class Header extends Component { - authButton() { + authButton() { // uses a function to return the right piece of component if (this.props.authenticated) { return ; } diff --git a/hoc/src/components/require_authentication.js b/hoc/src/components/require_authentication.js index 23c2523..078ff7a 100644 --- a/hoc/src/components/require_authentication.js +++ b/hoc/src/components/require_authentication.js @@ -1,9 +1,9 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; -export default function(ComposedComponent) { +export default function(ComposedComponent) { // as a HOC export a function with a class and not just a class class Authentication extends Component { - static contextTypes = { + static contextTypes = { // you have to create a contextTypes to get access here at the context (that is like props but accessible from everywhere) router: React.PropTypes.object } @@ -13,14 +13,14 @@ export default function(ComposedComponent) { } } - componentWillUpdate(nextProps) { + componentWillUpdate(nextProps) { // nextProps is a reference to the props when tehre's an update (life cicle method componentWillUpdate works so) if (!nextProps.authenticated) { this.context.router.push('/'); } } render() { - return + return // the HOC will render the passed component to compose, that can use props as an usual one } } @@ -28,5 +28,5 @@ export default function(ComposedComponent) { return { authenticated: state.authenticated }; } - return connect(mapStateToProps)(Authentication); + return connect(mapStateToProps)(Authentication); // so 'connect' compose 'Authentication' that compose te passed component (so 2 nested HOC) } diff --git a/hoc/src/index.js b/hoc/src/index.js index 97718b6..cd1aa6d 100644 --- a/hoc/src/index.js +++ b/hoc/src/index.js @@ -15,7 +15,7 @@ ReactDOM.render( - + {/* this is a nested route so the component will show just for the child route [and requireAuth is the HOC we created that augments the 'Resources' component ] */} diff --git a/middlewares/index.html b/middlewares/index.html index 22a662b..ac29ebf 100644 --- a/middlewares/index.html +++ b/middlewares/index.html @@ -3,7 +3,6 @@ -
    diff --git a/middlewares/src/components/user_list.js b/middlewares/src/components/user_list.js index ffecf3b..5cf7633 100644 --- a/middlewares/src/components/user_list.js +++ b/middlewares/src/components/user_list.js @@ -9,7 +9,7 @@ class UserList extends Component { renderUser(user) { return ( -
    +
    {/* added an id as a key*/}

    {user.name}

    {user.company.name}

    Website @@ -20,7 +20,7 @@ class UserList extends Component { render() { return (
    - {this.props.users.map(this.renderUser)} + {this.props.users.map(usr => this.renderUser(usr))} {/*is the same to call the callback map funct as [.map(this.renderUser]*/}
    ); } diff --git a/middlewares/src/index.js b/middlewares/src/index.js index bdecc8c..cea0116 100644 --- a/middlewares/src/index.js +++ b/middlewares/src/index.js @@ -7,7 +7,7 @@ import App from './components/app'; import reducers from './reducers'; import Async from './middlewares/async'; -const createStoreWithMiddleware = applyMiddleware(Async)(createStore); +const createStoreWithMiddleware = applyMiddleware(Async)(createStore); // compose the store with middlewares ReactDOM.render( diff --git a/middlewares/src/middlewares/async.js b/middlewares/src/middlewares/async.js index 9f39577..4f50f76 100644 --- a/middlewares/src/middlewares/async.js +++ b/middlewares/src/middlewares/async.js @@ -5,7 +5,7 @@ export default function({ dispatch }) { // we dont care about it, send it on if (!action.payload || !action.payload.then) { return next(action); - } + } // This case hadle no just another potential action that we don't want to treat here, but also the same(new) action in the new 'state' [and that's why we don't check for the action.type] // Make sure the action's promise resolves action.payload @@ -13,7 +13,7 @@ export default function({ dispatch }) { // create a new action with the old type, but // replace the promise with the reponse data const newAction = { ...action, payload: response }; - dispatch(newAction); + dispatch(newAction); /* dispatch the new action to the top of the middleware stack (so the action will be evalueted again and do some other operation if/when needed [not this one the case now but you never know]) and finally goes to reducers*/ }); } } diff --git a/middlewares/src/reducers/users.js b/middlewares/src/reducers/users.js index 37f4383..f54d79f 100644 --- a/middlewares/src/reducers/users.js +++ b/middlewares/src/reducers/users.js @@ -5,7 +5,7 @@ import { export default function(state = [], action) { switch (action.type) { case FETCH_USERS: - return [ ...state, ...action.payload.data ]; + return [ ...state, ...action.payload.data ]; // spread operator combine the prev state with the new one (payload) } return state; diff --git a/testing/src/components/comment_list.js b/testing/src/components/comment_list.js index 1032c89..0e2c78a 100644 --- a/testing/src/components/comment_list.js +++ b/testing/src/components/comment_list.js @@ -10,7 +10,7 @@ const CommentList = (props) => { }; function mapStateToProps(state) { - return { comments: state.comments }; + return { comments: state.commenti }; // it takes state.commenti and assigns to comments from use here as props } export default connect(mapStateToProps)(CommentList); diff --git a/testing/src/reducers/index.js b/testing/src/reducers/index.js index b44a7b8..1825202 100644 --- a/testing/src/reducers/index.js +++ b/testing/src/reducers/index.js @@ -2,7 +2,9 @@ import { combineReducers } from 'redux'; import commentsReducer from './comments'; const rootReducer = combineReducers({ - comments: commentsReducer + //commenti: (state = []) => state + commenti: commentsReducer + }); export default rootReducer; diff --git a/testing/test/components/comment_list_test.js b/testing/test/components/comment_list_test.js index 27fb515..8fee425 100644 --- a/testing/test/components/comment_list_test.js +++ b/testing/test/components/comment_list_test.js @@ -5,7 +5,7 @@ describe('CommentList', () => { let component; beforeEach(() => { - const props = { comments: ['New Comment', 'Other New Comment'] }; + const props = { commenti: ['New Comment', 'Other New Comment'] }; // it uses the real state 'commenti' and not the prorp from mapStateToProps of the component rendered component = renderComponent(CommentList, null, props); }); diff --git a/testing/test/test_helper.js b/testing/test/test_helper.js index 08bbc3c..778d074 100644 --- a/testing/test/test_helper.js +++ b/testing/test/test_helper.js @@ -14,26 +14,26 @@ global.document = jsdom.jsdom(''); global.window = global.document.defaultView; const $ = jquery(global.window); -// build 'renderComponent' helper that should render a given react class +// build 'renderComponent' helper that should render a given react class function renderComponent(ComponentClass, props, state) { - const componentInstance = TestUtils.renderIntoDocument( + const componentInstance = TestUtils.renderIntoDocument( // this testutil method create the component ready to be use in a DOM later [complete also with state and props passed by the main funct 'renderComponent'] ); - return $(ReactDOM.findDOMNode(componentInstance)); // produces HTML + return $(ReactDOM.findDOMNode(componentInstance)); // produces HTML [in the specified DOM, in this case that one created by jsdom and warpped in jquery] } // Build helper for simulating events -$.fn.simulate = function(eventName, value) { +$.fn.simulate = function(eventName, value) { //$.fn. creates a new jquery method for our jquery instance if (value) { - this.val(value); + this.val(value);// this is the jquery obj and the jq method .val(value) sets the value passed, nothing new here } - TestUtils.Simulate[eventName](this[0]); + TestUtils.Simulate[eventName](this[0]); // refer to react-addons-test-utils doc to undurstend this [react doc - addons - testutil] } // Set up chai-jquery -chaiJquery(chai, chai.util, $); +chaiJquery(chai, chai.util, $); // chaijq set up function, see doc if you want export { renderComponent, expect };