From b729b5dfc701a1322464562474f3d10bc5578547 Mon Sep 17 00:00:00 2001 From: Nick Steinbaugh Date: Mon, 14 May 2018 23:38:41 -0600 Subject: [PATCH 1/7] Updated dependencies and replaced babel with tsc --- src/ReactBoilerplate/.editorconfig | 4 + src/ReactBoilerplate/.eslintrc | 81 +- src/ReactBoilerplate/.stylelintrc | 29 + src/ReactBoilerplate/Scripts/client.js | 44 +- .../ChangeEmailForm/ChangeEmailForm.js | 15 +- .../ChangePasswordForm/ChangePasswordForm.js | 15 +- .../Scripts/components/ErrorList.js | 17 +- .../components/ExternalLogin/ExternalLogin.js | 25 +- .../Scripts/components/ExternalLoginButton.js | 16 +- .../ForgotPasswordForm/ForgotPasswordForm.js | 15 +- .../Scripts/components/Form.js | 33 +- .../Scripts/components/Input.js | 63 +- .../Scripts/components/LoginForm/LoginForm.js | 15 +- .../components/RegisterForm/RegisterForm.js | 38 +- .../ResetPasswordForm/ResetPasswordForm.js | 36 +- .../Scripts/components/Spinner.js | 10 +- .../components/TwoFactor/SendCodeForm.js | 21 +- .../Scripts/components/TwoFactor/TwoFactor.js | 2 +- .../components/TwoFactor/VerifyCodeForm.js | 29 +- .../Scripts/components/index.js | 30 +- src/ReactBoilerplate/Scripts/config.js | 8 + .../Scripts/containers/App/App.js | 26 +- .../Scripts/containers/App/App.scss | 29 +- .../containers/App/Modals/TwoFactorModal.js | 4 +- .../containers/ConfirmEmail/ConfirmEmail.js | 6 +- .../ForgotPassword/ForgotPassword.js | 4 +- .../Scripts/containers/Home/Home.js | 2 +- .../Scripts/containers/Login/Login.js | 9 +- .../Manage/ChangePassword/ChangePassword.js | 4 +- .../Scripts/containers/Manage/Email/Email.js | 2 +- .../containers/Manage/Logins/Logins.js | 73 +- .../Scripts/containers/Manage/Manage.js | 7 +- .../Scripts/containers/Register/Register.js | 4 +- .../containers/ResetPassword/ResetPassword.js | 4 +- .../Scripts/containers/index.js | 32 +- .../Scripts/helpers/ApiClient.js | 6 +- src/ReactBoilerplate/Scripts/helpers/Html.js | 29 +- .../Scripts/redux/configureStore.js | 4 +- .../redux/middleware/clientMiddleware.js | 2 +- .../Scripts/redux/modules/account.js | 4 +- .../Scripts/redux/modules/externalLogin.js | 2 +- .../Scripts/redux/modules/manage/email.js | 8 +- .../redux/modules/manage/externalLogins.js | 2 +- .../Scripts/redux/modules/manage/security.js | 8 +- src/ReactBoilerplate/Scripts/redux/reducer.js | 2 +- src/ReactBoilerplate/Scripts/routes.js | 59 +- src/ReactBoilerplate/Scripts/server.js | 80 +- src/ReactBoilerplate/Scripts/utils/isEmpty.js | 4 +- .../Scripts/utils/modelState.js | 16 +- .../Scripts/utils/promise-window-server.js | 1 + .../Scripts/webpack/dev.config.js | 169 +- .../Scripts/webpack/prod.config.js | 180 +- src/ReactBoilerplate/gulpfile.js | 289 +- src/ReactBoilerplate/package-lock.json | 9556 ++++++++++++----- src/ReactBoilerplate/package.json | 100 +- src/ReactBoilerplate/tsconfig.json | 17 + 56 files changed, 7866 insertions(+), 3424 deletions(-) create mode 100644 src/ReactBoilerplate/.stylelintrc create mode 100644 src/ReactBoilerplate/tsconfig.json diff --git a/src/ReactBoilerplate/.editorconfig b/src/ReactBoilerplate/.editorconfig index bb1f190..097e288 100644 --- a/src/ReactBoilerplate/.editorconfig +++ b/src/ReactBoilerplate/.editorconfig @@ -5,5 +5,9 @@ root = true indent_style = space indent_size = 2 +[*.cs] +indent_style = space +indent_size = 4 + [*.md] trim_trailing_whitespace = false diff --git a/src/ReactBoilerplate/.eslintrc b/src/ReactBoilerplate/.eslintrc index fd71550..fdebf4b 100644 --- a/src/ReactBoilerplate/.eslintrc +++ b/src/ReactBoilerplate/.eslintrc @@ -4,35 +4,76 @@ "browser": true, "node": true }, - "parser": "babel-eslint", + "parser": "typescript-eslint-parser", "plugins": [ "react", - "import" + "import", + "typescript" ], "rules": { - "comma-dangle": 0, // not sure why airbnb turned this on. gross! - "indent": [2, 2, {"SwitchCase": 1}], - "react/prefer-stateless-function": 0, - "react/prop-types": 0, - "react/jsx-closing-bracket-location": 0, - "no-console": 0, - "prefer-template": 0, - "max-len": 0, - "no-underscore-dangle": [2, {"allow": ["__data"]}], - "global-require": 0, - "no-restricted-syntax": 0, - "linebreak-style": 0, - "react/jsx-filename-extension": 0, - "import/imports-first": 0, - "no-class-assign": 0 + "comma-dangle": "off", // Not sure why airbnb turned this on. Gross! + "indent": ["error", 2, {"SwitchCase": 1}], + "react/prefer-stateless-function": "off", + "react/prop-types": "off", + "react/jsx-closing-bracket-location": "off", + "no-console": "off", + "prefer-template": "off", + "max-len": "off", + "no-underscore-dangle": ["error", {"allow": ["__data"]}], + "global-require": "off", + "no-restricted-syntax": "off", + "linebreak-style": "off", + "react/jsx-filename-extension": "off", + "arrow-parens": ["error", "always"], + "no-plusplus": ["error", { "allowForLoopAfterthoughts": true }], + "jsx-a11y/anchor-is-valid": ["error", { + "specialLink": ["to"] // Allow "to" property in react-router-dom Link element + }], + "no-undef": "off", // TypeScript lint parser produces false positves; the compiler will error anyway + "no-unused-vars": "off", // TypeScript lint parser produces false positves; the compiler is set to error instead + "import/extensions": ["error", "ignorePackages", { + "js": "never", + "jsx": "never", + "ts": "never", + "tsx": "never" + }], + "react/sort-comp": ["error", { // Add type-annotations to the top + "order": [ + "static-methods", + "type-annotations", + "instance-variables", + "lifecycle", + "/^on.+$/", + "getters", + "setters", + "/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/", + "instance-methods", + "everything-else", + "rendering" + ] + }], + "typescript/adjacent-overload-signatures": ["error"], + "typescript/class-name-casing": ["error"], + "typescript/explicit-member-accessibility": ["error"], + "typescript/interface-name-prefix": ["error", "never"], + "typescript/member-delimiter-style": ["error"], + "typescript/no-angle-bracket-type-assertion": ["error"], + "typescript/no-array-constructor": ["error"], + "typescript/no-empty-interface": ["error"], + "typescript/no-inferrable-types": ["error"], + "typescript/no-unused-vars": ["error"], + "typescript/no-use-before-define": ["error"], + "typescript/type-annotation-spacing": ["error"] }, "settings": { - "import/parser": "babel-eslint", - "import/resolver": { + "import/parser": "typescript-eslint-parser", + "import/resolver": { "node": { - "moduleDirectory": ["node_modules", "Scripts"] + "moduleDirectory": ["node_modules", "Scripts"], + "extensions": [".js", ".jsx", ".ts", ".tsx"] } }, + "import/extensions": [".js", ".jsx", ".ts", ".tsx"], "no-underscore-dangle": { "allow": ["__data"] } diff --git a/src/ReactBoilerplate/.stylelintrc b/src/ReactBoilerplate/.stylelintrc new file mode 100644 index 0000000..77bc086 --- /dev/null +++ b/src/ReactBoilerplate/.stylelintrc @@ -0,0 +1,29 @@ +{ + "extends": [ + "stylelint-config-standard" + ], + "rules": { + 'selector-pseudo-class-no-unknown': [ true, { + ignorePseudoClasses: [ + 'export', + 'import', + 'global', + 'local' + ], + }], + 'property-no-unknown': [ true, { + ignoreProperties: [ + 'composes', + 'compose-with' + ], + }], + 'at-rule-no-unknown': [ true, { + ignoreAtRules: [ + 'each', + 'extend', + 'include', + 'mixin', + ], + }] + } +} diff --git a/src/ReactBoilerplate/Scripts/client.js b/src/ReactBoilerplate/Scripts/client.js index 704bc92..29b4851 100644 --- a/src/ReactBoilerplate/Scripts/client.js +++ b/src/ReactBoilerplate/Scripts/client.js @@ -1,21 +1,39 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { Router, browserHistory } from 'react-router'; -import getRoutes from './routes'; +import createHistory from 'history/createBrowserHistory'; import { Provider } from 'react-redux'; +import { ConnectedRouter } from 'react-router-redux'; +import { AppContainer } from 'react-hot-loader'; import configureStore from './redux/configureStore'; -import { syncHistoryWithStore } from 'react-router-redux'; import ApiClient from './helpers/ApiClient'; +import getRoutes from './routes'; + +// Need to import App directly from its file so that this module is dependent on it directly for HMR +import App from './containers/App/App'; const client = new ApiClient(); -const store = configureStore(window.__data, browserHistory, client); -const history = syncHistoryWithStore(browserHistory, store); +const history = createHistory(); +const store = configureStore(window.__data, history, client); + +const render = () => { + ReactDOM.render( + + + + + {getRoutes(store)} + + + + , + document.getElementById('content') + ); +}; + +// Render the App inside the store and HMR AppContainer +render(); -ReactDOM.render( - - - {getRoutes(store)} - - , - document.getElementById('content') -); +// Register to accept changes to the App +if (module.hot) { + module.hot.accept('./containers/App/App', () => { render(App); }); +} diff --git a/src/ReactBoilerplate/Scripts/components/ChangeEmailForm/ChangeEmailForm.js b/src/ReactBoilerplate/Scripts/components/ChangeEmailForm/ChangeEmailForm.js index 24281da..824ce09 100644 --- a/src/ReactBoilerplate/Scripts/components/ChangeEmailForm/ChangeEmailForm.js +++ b/src/ReactBoilerplate/Scripts/components/ChangeEmailForm/ChangeEmailForm.js @@ -47,12 +47,11 @@ class ChangeEmailForm extends Form { } } -ChangeEmailForm = reduxForm({ - form: 'changeEmail', - fields: ['currentPassword', 'email', 'emailConfirm'] -}, -(state) => state, -{ } +export default reduxForm( + { + form: 'changeEmail', + fields: ['currentPassword', 'email', 'emailConfirm'] + }, + (state) => state, + { } )(ChangeEmailForm); - -export default ChangeEmailForm; diff --git a/src/ReactBoilerplate/Scripts/components/ChangePasswordForm/ChangePasswordForm.js b/src/ReactBoilerplate/Scripts/components/ChangePasswordForm/ChangePasswordForm.js index 069fccf..13aa5b1 100644 --- a/src/ReactBoilerplate/Scripts/components/ChangePasswordForm/ChangePasswordForm.js +++ b/src/ReactBoilerplate/Scripts/components/ChangePasswordForm/ChangePasswordForm.js @@ -47,12 +47,11 @@ class ChangePasswordForm extends Form { } } -ChangePasswordForm = reduxForm({ - form: 'changePassword', - fields: ['oldPassword', 'newPassword', 'newPasswordConfirm'] -}, -(state) => state, -{ } +export default reduxForm( + { + form: 'changePassword', + fields: ['oldPassword', 'newPassword', 'newPasswordConfirm'] + }, + (state) => state, + { } )(ChangePasswordForm); - -export default ChangePasswordForm; diff --git a/src/ReactBoilerplate/Scripts/components/ErrorList.js b/src/ReactBoilerplate/Scripts/components/ErrorList.js index 83c7b54..eaf3287 100644 --- a/src/ReactBoilerplate/Scripts/components/ErrorList.js +++ b/src/ReactBoilerplate/Scripts/components/ErrorList.js @@ -11,14 +11,15 @@ class ErrorList extends Component { if (errors.length === 0) return null; return (
- {errors.map((err, i) => - ( -

- - {' '} - {err} -

- ))} + {errors.map((err) => + ( +

+ + {' '} + {err} +

+ )) + }
); } diff --git a/src/ReactBoilerplate/Scripts/components/ExternalLogin/ExternalLogin.js b/src/ReactBoilerplate/Scripts/components/ExternalLogin/ExternalLogin.js index bdc1e5e..3c435d0 100644 --- a/src/ReactBoilerplate/Scripts/components/ExternalLogin/ExternalLogin.js +++ b/src/ReactBoilerplate/Scripts/components/ExternalLogin/ExternalLogin.js @@ -20,22 +20,23 @@ class ExternalLogin extends Component { } = this.props; return (

- {loginProviders.map((loginProvider, i) => - ( - - - {' '} - - ))} + {loginProviders.map((loginProvider) => + ( + + + {' '} + + )) + }

); } } export default connect( -(state) => ({ loginProviders: state.externalLogin.loginProviders, location: state.routing.locationBeforeTransitions }), -{ authenticate } + (state) => ({ loginProviders: state.externalLogin.loginProviders, location: state.routing.locationBeforeTransitions }), + { authenticate } )(ExternalLogin); diff --git a/src/ReactBoilerplate/Scripts/components/ExternalLoginButton.js b/src/ReactBoilerplate/Scripts/components/ExternalLoginButton.js index 6a23a23..8638f60 100644 --- a/src/ReactBoilerplate/Scripts/components/ExternalLoginButton.js +++ b/src/ReactBoilerplate/Scripts/components/ExternalLoginButton.js @@ -5,11 +5,11 @@ const bootstrapSocial = require('bootstrap-social'); const fontAwesome = require('font-awesome/scss/font-awesome.scss'); export default (props) => -( - -); + ( + + ); diff --git a/src/ReactBoilerplate/Scripts/components/ForgotPasswordForm/ForgotPasswordForm.js b/src/ReactBoilerplate/Scripts/components/ForgotPasswordForm/ForgotPasswordForm.js index 281b9f7..5827f8d 100644 --- a/src/ReactBoilerplate/Scripts/components/ForgotPasswordForm/ForgotPasswordForm.js +++ b/src/ReactBoilerplate/Scripts/components/ForgotPasswordForm/ForgotPasswordForm.js @@ -45,12 +45,11 @@ class ForgotPasswordForm extends Form { } } -ForgotPasswordForm = reduxForm({ - form: 'forgotPassword', - fields: ['email'] -}, -(state) => state, -{ } +export default reduxForm( + { + form: 'forgotPassword', + fields: ['email'] + }, + (state) => state, + { } )(ForgotPasswordForm); - -export default ForgotPasswordForm; diff --git a/src/ReactBoilerplate/Scripts/components/Form.js b/src/ReactBoilerplate/Scripts/components/Form.js index 1995adb..9ef3361 100644 --- a/src/ReactBoilerplate/Scripts/components/Form.js +++ b/src/ReactBoilerplate/Scripts/components/Form.js @@ -1,8 +1,9 @@ import React, { Component } from 'react'; import { modelStateErrorToFormFields } from '../utils/modelState'; -import { ErrorList } from 'components'; +import ErrorList from './ErrorList'; class Form extends Component { + // eslint-disable-next-line class-methods-use-this modifyValues(values) { return values; } @@ -14,27 +15,27 @@ class Form extends Component { new Promise((resolve, reject) => { dispatch(action(this.modifyValues(values))) .then( - (result) => { - if (result.success) { - resolve(); - if (success) { - success(result); + (result) => { + if (result.success) { + resolve(); + if (success) { + success(result); + } + } else { + reject(modelStateErrorToFormFields(result.errors)); + if (error) { + error(result); + } } - } else { + }, + (result) => { reject(modelStateErrorToFormFields(result.errors)); if (error) { error(result); } } - }, - (result) => { - reject(modelStateErrorToFormFields(result.errors)); - if (error) { - error(result); - } - }); - }) - ); + ); + })); } renderGlobalErrorList() { const { diff --git a/src/ReactBoilerplate/Scripts/components/Input.js b/src/ReactBoilerplate/Scripts/components/Input.js index b63b723..cf38b74 100644 --- a/src/ReactBoilerplate/Scripts/components/Input.js +++ b/src/ReactBoilerplate/Scripts/components/Input.js @@ -1,17 +1,18 @@ -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; import classNames from 'classnames'; import { Glyphicon } from 'react-bootstrap'; class Input extends Component { - static propTypes = { - field: PropTypes.object.isRequired, - type: React.PropTypes.oneOf([ - 'password', - 'text', - 'option', - 'checkbox' - ]), - }; + // static propTypes = { + // // eslint-disable-next-line react/forbid-prop-types + // field: PropTypes.object.isRequired, + // type: React.PropTypes.oneOf([ + // 'password', + // 'text', + // 'option', + // 'checkbox' + // ]), + // }; buildFieldProps() { const { defaultChecked, @@ -34,22 +35,25 @@ class Input extends Component { onFocus }; } + + // eslint-disable-next-line class-methods-use-this renderErrorList(errors) { if (!errors) { return null; } return (
- {errors.map((err, i) => - ( -

- - {' '} - {err} -

- ))} + {errors.map((err) => + ( +

+ + {' '} + {err} +

+ )) + }
); } @@ -75,18 +79,21 @@ class Input extends Component { className="form-control" placeholder={this.props.label} {...this.buildFieldProps()}> - {options.map((option, i) => - ( - - ))} + {options.map((option) => + ( + + )) + } ); } renderCheckBox() { return (
- - +
); } @@ -95,7 +102,7 @@ class Input extends Component { let errors; if (this.props.field.touched && this.props.field.invalid) { hasError = true; - errors = this.props.field.error.errors; + errors = this.props.field.error.errors; // eslint-disable-line prefer-destructuring if (!Array.isArray(errors)) { console.error('The errors object does not seem to be an array of errors.'); // eslint-disable-line max-len errors = null; @@ -125,7 +132,7 @@ class Input extends Component { } return (
- {(this.props.type !== 'checkbox') && + {(this.props.type !== 'checkbox') && // eslint-disable-next-line jsx-a11y/label-has-for }
diff --git a/src/ReactBoilerplate/Scripts/components/LoginForm/LoginForm.js b/src/ReactBoilerplate/Scripts/components/LoginForm/LoginForm.js index 68ce65a..36a5f1b 100644 --- a/src/ReactBoilerplate/Scripts/components/LoginForm/LoginForm.js +++ b/src/ReactBoilerplate/Scripts/components/LoginForm/LoginForm.js @@ -35,12 +35,11 @@ class LoginForm extends Form { } } -LoginForm = reduxForm({ - form: 'login', - fields: ['userName', 'password', 'rememberMe'] -}, -(state) => ({ loginProviders: state.externalLogin.loginProviders }), -{ } +export default reduxForm( + { + form: 'login', + fields: ['userName', 'password', 'rememberMe'] + }, + (state) => ({ loginProviders: state.externalLogin.loginProviders }), + { } )(LoginForm); - -export default LoginForm; diff --git a/src/ReactBoilerplate/Scripts/components/RegisterForm/RegisterForm.js b/src/ReactBoilerplate/Scripts/components/RegisterForm/RegisterForm.js index 393518e..d6df53d 100644 --- a/src/ReactBoilerplate/Scripts/components/RegisterForm/RegisterForm.js +++ b/src/ReactBoilerplate/Scripts/components/RegisterForm/RegisterForm.js @@ -13,6 +13,8 @@ class RegisterForm extends Form { linkExternalLogin: this.props.externalLogin.externalAuthenticated }; } + + // eslint-disable-next-line class-methods-use-this onRemoveExternalAuthClick(action) { return (event) => { event.preventDefault(); @@ -21,8 +23,17 @@ class RegisterForm extends Form { } render() { const { - fields: { userName, email, password, passwordConfirm }, - externalLogin: { externalAuthenticated, externalAuthenticatedProvider, loginProviders } + fields: { + userName, + email, + password, + passwordConfirm + }, + externalLogin: { + externalAuthenticated, + externalAuthenticatedProvider, + loginProviders + } } = this.props; return (
@@ -34,7 +45,7 @@ class RegisterForm extends Form { + /> {' '}
@@ -100,6 +98,6 @@ class App extends Component { } export default connect( -state => ({ user: state.auth.user }), -{ logoff, pushState: push } + (state) => ({ user: state.auth.user, routing: state.routing }), + { logoff, pushState: push } )(App); diff --git a/src/ReactBoilerplate/Scripts/containers/App/App.scss b/src/ReactBoilerplate/Scripts/containers/App/App.scss index e5cc5f3..c4047d4 100644 --- a/src/ReactBoilerplate/Scripts/containers/App/App.scss +++ b/src/ReactBoilerplate/Scripts/containers/App/App.scss @@ -1,34 +1,33 @@ body { - padding-top: 50px; - padding-bottom: 20px; + padding-top: 50px; + padding-bottom: 20px; } -/* Wrapping element */ -/* Set some basic padding to keep content from hitting the edges */ +/* Wrapping element: Set some basic padding to keep content from hitting the edges */ .body-content { - padding-left: 15px; - padding-right: 15px; + padding-left: 15px; + padding-right: 15px; } /* Set widths on the form inputs since otherwise they're 100% wide */ input, select, textarea { - max-width: 280px; + max-width: 280px; } /* Carousel */ .carousel-caption { - z-index: 10 !important; + z-index: 10 !important; } - .carousel-caption p { - font-size: 20px; - line-height: 1.4; - } +.carousel-caption p { + font-size: 20px; + line-height: 1.4; +} @media (min-width: 768px) { - .carousel-caption { - z-index: 10 !important; - } + .carousel-caption { + z-index: 10 !important; + } } diff --git a/src/ReactBoilerplate/Scripts/containers/App/Modals/TwoFactorModal.js b/src/ReactBoilerplate/Scripts/containers/App/Modals/TwoFactorModal.js index 8310eda..4b23902 100644 --- a/src/ReactBoilerplate/Scripts/containers/App/Modals/TwoFactorModal.js +++ b/src/ReactBoilerplate/Scripts/containers/App/Modals/TwoFactorModal.js @@ -33,6 +33,6 @@ class TwoFactorModal extends Component { } export default connect( -state => ({ account: state.account }), -{ resetLoginState } + (state) => ({ account: state.account }), + { resetLoginState } )(TwoFactorModal); diff --git a/src/ReactBoilerplate/Scripts/containers/ConfirmEmail/ConfirmEmail.js b/src/ReactBoilerplate/Scripts/containers/ConfirmEmail/ConfirmEmail.js index 354b7f5..0e568b0 100644 --- a/src/ReactBoilerplate/Scripts/containers/ConfirmEmail/ConfirmEmail.js +++ b/src/ReactBoilerplate/Scripts/containers/ConfirmEmail/ConfirmEmail.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; class ConfirmEmail extends Component { render() { @@ -43,6 +43,6 @@ class ConfirmEmail extends Component { } export default connect( -(state) => ({ success: state.viewBag.success, change: state.viewBag.change }), -{ } + (state) => ({ success: state.viewBag.success, change: state.viewBag.change }), + { } )(ConfirmEmail); diff --git a/src/ReactBoilerplate/Scripts/containers/ForgotPassword/ForgotPassword.js b/src/ReactBoilerplate/Scripts/containers/ForgotPassword/ForgotPassword.js index 6d07172..89c2925 100644 --- a/src/ReactBoilerplate/Scripts/containers/ForgotPassword/ForgotPassword.js +++ b/src/ReactBoilerplate/Scripts/containers/ForgotPassword/ForgotPassword.js @@ -16,6 +16,6 @@ class ForgotPassword extends Component { } export default connect( -state => ({ user: state.auth.user }), -{ } + (state) => ({ user: state.auth.user }), + { } )(ForgotPassword); diff --git a/src/ReactBoilerplate/Scripts/containers/Home/Home.js b/src/ReactBoilerplate/Scripts/containers/Home/Home.js index f1dd04c..922982e 100644 --- a/src/ReactBoilerplate/Scripts/containers/Home/Home.js +++ b/src/ReactBoilerplate/Scripts/containers/Home/Home.js @@ -63,7 +63,7 @@ class Home extends Component { />

- Learn how Microsoft's Azure cloud platform allows you to build, + Learn how Microsoft's Azure cloud platform allows you to build, deploy, and scale web apps. Learn More diff --git a/src/ReactBoilerplate/Scripts/containers/Login/Login.js b/src/ReactBoilerplate/Scripts/containers/Login/Login.js index 62dd0ac..2845a96 100644 --- a/src/ReactBoilerplate/Scripts/containers/Login/Login.js +++ b/src/ReactBoilerplate/Scripts/containers/Login/Login.js @@ -2,14 +2,14 @@ import React, { Component } from 'react'; import { LoginForm } from 'components'; import { connect } from 'react-redux'; import { push } from 'react-router-redux'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; import { rehydrateLogin } from 'redux/modules/externalLogin'; class Login extends Component { componentWillReceiveProps(nextProps) { // if the user logged in, redirect the user. if (!this.props.user && nextProps.user) { - if (this.props.location.query.returnUrl) { + if (this.props.location.query && this.props.location.query.returnUrl) { this.props.pushState(this.props.location.query.returnUrl); } else { this.props.pushState('/'); @@ -38,7 +38,6 @@ class Login extends Component { // So, every the `pushState` call clears out `externalLogin`, we will // need to put it back in this.props.rehydrateLogin(nextProps.externalLogin); - return; } } render() { @@ -59,6 +58,6 @@ class Login extends Component { } export default connect( -state => ({ user: state.auth.user, externalLogin: state.externalLogin }), -{ pushState: push, rehydrateLogin } + (state) => ({ user: state.auth.user, externalLogin: state.externalLogin }), + { pushState: push, rehydrateLogin } )(Login); diff --git a/src/ReactBoilerplate/Scripts/containers/Manage/ChangePassword/ChangePassword.js b/src/ReactBoilerplate/Scripts/containers/Manage/ChangePassword/ChangePassword.js index 02a6f2f..8fe6ae8 100644 --- a/src/ReactBoilerplate/Scripts/containers/Manage/ChangePassword/ChangePassword.js +++ b/src/ReactBoilerplate/Scripts/containers/Manage/ChangePassword/ChangePassword.js @@ -16,6 +16,6 @@ class ChangePassword extends Component { } export default connect( -state => ({ user: state.auth.user }), -{ } + (state) => ({ user: state.auth.user }), + { } )(ChangePassword); diff --git a/src/ReactBoilerplate/Scripts/containers/Manage/Email/Email.js b/src/ReactBoilerplate/Scripts/containers/Manage/Email/Email.js index 0939cda..c5e49dc 100644 --- a/src/ReactBoilerplate/Scripts/containers/Manage/Email/Email.js +++ b/src/ReactBoilerplate/Scripts/containers/Manage/Email/Email.js @@ -43,7 +43,7 @@ class Email extends Component {

Email

- + Current email

{email}

diff --git a/src/ReactBoilerplate/Scripts/containers/Manage/Logins/Logins.js b/src/ReactBoilerplate/Scripts/containers/Manage/Logins/Logins.js index b0c054d..cdb19ea 100644 --- a/src/ReactBoilerplate/Scripts/containers/Manage/Logins/Logins.js +++ b/src/ReactBoilerplate/Scripts/containers/Manage/Logins/Logins.js @@ -60,21 +60,22 @@ class Logins extends Component {

Current logins

- {currentLogins.map((currentLogin, i) => - ( - - - - ))} + {currentLogins.map((currentLogin) => + ( + + + + )) + }
- - {' '} - -
+ + {' '} + +
@@ -84,21 +85,22 @@ class Logins extends Component {

Add another service to log in.

- {otherLogins.map((otherLogin, i) => - ( - - - - ))} + {otherLogins.map((otherLogin) => + ( + + + + )) + }
- - {' '} - -
+ + {' '} + +
@@ -109,6 +111,13 @@ class Logins extends Component { } export default connect( -state => ({ externalLogins: state.manage.externalLogins }), -{ loadExternalLogins, destroyExternalLogins, externalAuthenticate, clearExternalAuthentication, addExternalLogin, removeExternalLogin } + (state) => ({ externalLogins: state.manage.externalLogins }), + { + loadExternalLogins, + destroyExternalLogins, + externalAuthenticate, + clearExternalAuthentication, + addExternalLogin, + removeExternalLogin + } )(Logins); diff --git a/src/ReactBoilerplate/Scripts/containers/Manage/Manage.js b/src/ReactBoilerplate/Scripts/containers/Manage/Manage.js index 0a6c7a6..31a3597 100644 --- a/src/ReactBoilerplate/Scripts/containers/Manage/Manage.js +++ b/src/ReactBoilerplate/Scripts/containers/Manage/Manage.js @@ -4,9 +4,6 @@ import { Row, Col, Nav, NavItem } from 'react-bootstrap'; import { LinkContainer } from 'react-router-bootstrap'; class Manage extends Component { - static propTypes = { - children: PropTypes.object.isRequired - }; render() { return ( @@ -35,6 +32,6 @@ class Manage extends Component { } export default connect( -state => ({ user: state.auth.user }), -{ } + (state) => ({ user: state.auth.user }), + { } )(Manage); diff --git a/src/ReactBoilerplate/Scripts/containers/Register/Register.js b/src/ReactBoilerplate/Scripts/containers/Register/Register.js index 90b0a50..524cc7b 100644 --- a/src/ReactBoilerplate/Scripts/containers/Register/Register.js +++ b/src/ReactBoilerplate/Scripts/containers/Register/Register.js @@ -22,6 +22,6 @@ class Register extends Component { } export default connect( -state => ({ user: state.auth.user, externalLogin: state.externalLogin }), -{ pushState: push } + (state) => ({ user: state.auth.user, externalLogin: state.externalLogin }), + { pushState: push } )(Register); diff --git a/src/ReactBoilerplate/Scripts/containers/ResetPassword/ResetPassword.js b/src/ReactBoilerplate/Scripts/containers/ResetPassword/ResetPassword.js index 3eb2a68..0c8616e 100644 --- a/src/ReactBoilerplate/Scripts/containers/ResetPassword/ResetPassword.js +++ b/src/ReactBoilerplate/Scripts/containers/ResetPassword/ResetPassword.js @@ -16,6 +16,6 @@ class ResetPassword extends Component { } export default connect( -state => ({ user: state.auth.user }), -{ } + (state) => ({ user: state.auth.user }), + { } )(ResetPassword); diff --git a/src/ReactBoilerplate/Scripts/containers/index.js b/src/ReactBoilerplate/Scripts/containers/index.js index b0c0926..a6baaa9 100644 --- a/src/ReactBoilerplate/Scripts/containers/index.js +++ b/src/ReactBoilerplate/Scripts/containers/index.js @@ -1,16 +1,16 @@ -export App from './App/App'; -export Home from './Home/Home'; -export About from './About/About'; -export Contact from './Contact/Contact'; -export NotFound from './NotFound/NotFound'; -export Register from './Register/Register'; -export Login from './Login/Login'; -export ForgotPassword from './ForgotPassword/ForgotPassword'; -export ResetPassword from './ResetPassword/ResetPassword'; -export ConfirmEmail from './ConfirmEmail/ConfirmEmail'; -export Manage from './Manage/Manage'; -export ManageIndex from './Manage/Index/Index'; -export ManageSecurity from './Manage/Security/Security'; -export ManageChangePassword from './Manage/ChangePassword/ChangePassword'; -export ManageLogins from './Manage/Logins/Logins'; -export ManageEmail from './Manage/Email/Email'; +export { default as App } from './App/App'; +export { default as Home } from './Home/Home'; +export { default as About } from './About/About'; +export { default as Contact } from './Contact/Contact'; +export { default as NotFound } from './NotFound/NotFound'; +export { default as Register } from './Register/Register'; +export { default as Login } from './Login/Login'; +export { default as ForgotPassword } from './ForgotPassword/ForgotPassword'; +export { default as ResetPassword } from './ResetPassword/ResetPassword'; +export { default as ConfirmEmail } from './ConfirmEmail/ConfirmEmail'; +export { default as Manage } from './Manage/Manage'; +export { default as ManageIndex } from './Manage/Index/Index'; +export { default as ManageSecurity } from './Manage/Security/Security'; +export { default as ManageChangePassword } from './Manage/ChangePassword/ChangePassword'; +export { default as ManageLogins } from './Manage/Logins/Logins'; +export { default as ManageEmail } from './Manage/Email/Email'; diff --git a/src/ReactBoilerplate/Scripts/helpers/ApiClient.js b/src/ReactBoilerplate/Scripts/helpers/ApiClient.js index fd60918..63e5ad2 100644 --- a/src/ReactBoilerplate/Scripts/helpers/ApiClient.js +++ b/src/ReactBoilerplate/Scripts/helpers/ApiClient.js @@ -2,7 +2,7 @@ import superagent from 'superagent'; const methods = ['get', 'post', 'put', 'patch', 'del']; -class _ApiClient { +export default class ApiClient { constructor(req) { methods.forEach((method) => { this[method] = (path, { params, data } = {}) => new Promise((resolve, reject) => { @@ -25,7 +25,3 @@ class _ApiClient { }); } } - -const ApiClient = _ApiClient; - -export default ApiClient; diff --git a/src/ReactBoilerplate/Scripts/helpers/Html.js b/src/ReactBoilerplate/Scripts/helpers/Html.js index f05de56..d0e0321 100644 --- a/src/ReactBoilerplate/Scripts/helpers/Html.js +++ b/src/ReactBoilerplate/Scripts/helpers/Html.js @@ -1,27 +1,33 @@ -import React, { Component, PropTypes } from 'react'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import ReactDOM from 'react-dom/server'; import Helmet from 'react-helmet'; import serialize from 'serialize-javascript'; export default class Html extends Component { static propTypes = { - component: PropTypes.node, - store: PropTypes.object + component: PropTypes.node.isRequired, + store: PropTypes.shape({ + getState: PropTypes.func + }).isRequired }; render() { + /* eslint-disable react/no-danger */ const { component, store } = this.props; const content = component ? ReactDOM.renderToString(component) : ''; - const head = Helmet.rewind(); + const helmet = Helmet.renderStatic(); + const htmlAttrs = helmet.htmlAttributes.toComponent(); + const bodyAttrs = helmet.bodyAttributes.toComponent(); return ( - - {head.base.toComponent()} - {head.title.toComponent()} - {head.meta.toComponent()} - {head.link.toComponent()} - {head.script.toComponent()} + + {helmet.base.toComponent()} + {helmet.title.toComponent()} + {helmet.meta.toComponent()} + {helmet.link.toComponent()} + {helmet.script.toComponent()} - +