├── .babelrc ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── PATENTS ├── README.md ├── build ├── app.js └── index.html ├── lib ├── apollo.js ├── config.js ├── index.html ├── js │ ├── app.js │ └── components │ │ ├── App │ │ ├── App.js │ │ ├── Description.js │ │ ├── Footer.js │ │ ├── Header.js │ │ ├── Hero.js │ │ ├── Login.js │ │ └── Register.js │ │ ├── GraphiQL │ │ └── GraphiQL.js │ │ └── Home │ │ ├── Body.js │ │ ├── Header.js │ │ ├── Home.js │ │ └── Logout.js └── server.js ├── package.json ├── src ├── apollo.js ├── config.js ├── index.html ├── js │ ├── app.js │ └── components │ │ ├── App │ │ ├── App.js │ │ ├── Description.js │ │ ├── Footer.js │ │ ├── Header.js │ │ ├── Hero.js │ │ ├── Login.js │ │ └── Register.js │ │ ├── GraphiQL │ │ └── GraphiQL.js │ │ └── Home │ │ ├── Body.js │ │ ├── Header.js │ │ ├── Home.js │ │ └── Logout.js └── server.js └── webpack └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | "es2015", 5 | "stage-0" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "plugins": [ 5 | "react", 6 | "jsx-a11y", 7 | "import", 8 | "flowtype" 9 | ], 10 | "rules": { 11 | "semi": ["error", "always"], 12 | "quotes": ["error", "single", {"allowTemplateLiterals": true}], 13 | "no-param-reassign": ["error", { "props": false }], 14 | "no-underscore-dangle": ["error", { "allowAfterThis": true }], 15 | "flowtype/boolean-style": [ 16 | 2, 17 | "boolean" 18 | ], 19 | "flowtype/define-flow-type": 1, 20 | "flowtype/delimiter-dangle": 0, 21 | "flowtype/generic-spacing": [ 22 | 2, 23 | "never" 24 | ], 25 | "flowtype/no-weak-types": 0, 26 | "flowtype/require-parameter-type": 0, 27 | "flowtype/require-return-type": 0, 28 | "flowtype/require-valid-file-annotation": 0, 29 | "flowtype/semi": 0, 30 | "flowtype/space-after-type-colon": [ 31 | 2, 32 | "always" 33 | ], 34 | "flowtype/space-before-generic-bracket": [ 35 | 2, 36 | "never" 37 | ], 38 | "flowtype/space-before-type-colon": [ 39 | 2, 40 | "never" 41 | ], 42 | "flowtype/type-id-match": 0, 43 | "flowtype/union-intersection-spacing": [ 44 | 2, 45 | "always" 46 | ], 47 | "flowtype/use-flow-type": 1, 48 | "flowtype/valid-syntax": 1, 49 | "react/jsx-filename-extension": 0, 50 | "react/jsx-no-target-blank": 0, 51 | "react/no-unescaped-entities": 0, 52 | "react/forbid-prop-types": 0, 53 | "react/require-default-props": 0, 54 | "class-methods-use-this": 0, 55 | "no-plusplus": 0, 56 | "no-underscore-dangle": 0, 57 | "react/no-array-index-key": 0, 58 | "react/prefer-stateless-function": 0 59 | }, 60 | "env": { 61 | "node": true, 62 | "mocha": true 63 | }, 64 | "settings": { 65 | "flowtype": { 66 | "onlyFilesWithFlowAnnotation": false 67 | } 68 | }, 69 | "globals": { 70 | "window": true, 71 | "localStorage": true 72 | } 73 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | npm-debug.log 4 | data/schema.graphql 5 | .idea/ 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For Relay Starter Kit software 4 | 5 | Copyright (c) 2013-2015, Facebook, Inc. 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, 9 | are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | * Neither the name Facebook nor the names of its contributors may be used to 19 | endorse or promote products derived from this software without specific 20 | prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 26 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional Grant of Patent Rights Version 2 2 | 3 | "Software" means the Relay Starter Kit software distributed by Facebook, Inc. 4 | 5 | Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software 6 | ("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable 7 | (subject to the termination provision below) license under any Necessary 8 | Claims, to make, have made, use, sell, offer to sell, import, and otherwise 9 | transfer the Software. For avoidance of doubt, no license is granted under 10 | Facebook's rights in any patent claims that are infringed by (i) modifications 11 | to the Software made by you or any third party or (ii) the Software in 12 | combination with any software or other technology. 13 | 14 | The license granted hereunder will terminate, automatically and without notice, 15 | if you (or any of your subsidiaries, corporate affiliates or agents) initiate 16 | directly or indirectly, or take a direct financial interest in, any Patent 17 | Assertion: (i) against Facebook or any of its subsidiaries or corporate 18 | affiliates, (ii) against any party if such Patent Assertion arises in whole or 19 | in part from any software, technology, product or service of Facebook or any of 20 | its subsidiaries or corporate affiliates, or (iii) against any party relating 21 | to the Software. Notwithstanding the foregoing, if Facebook or any of its 22 | subsidiaries or corporate affiliates files a lawsuit alleging patent 23 | infringement against you in the first instance, and you respond by filing a 24 | patent infringement counterclaim in that lawsuit against that party that is 25 | unrelated to the Software, the license granted hereunder will not terminate 26 | under section (i) of this paragraph due to such counterclaim. 27 | 28 | A "Necessary Claim" is a claim of a patent owned by Facebook that is 29 | necessarily infringed by the Software standing alone. 30 | 31 | A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, 32 | or contributory infringement or inducement to infringe any patent, including a 33 | cross-claim or counterclaim. 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Scaphold.io's React Apollo boilerplate 2 | 3 | Fork this boilerplate code to get started with GraphQL, React, and Apollo. 4 | 5 | **Quickstart:** 6 | 7 | 1) Go to Scaphold.io (https://scaphold.io). 8 | 9 | 2) Create an account and dataset. 10 | 11 | 3) Change the URL in the API manager (config.js) in the boilerplate to point to your unique Scaphold.io API URL. 12 | 13 | 5) Install dependencies: ```npm install``` 14 | 15 | 4) Run with: ```npm start``` 16 | 17 | 18 | **Deployment:** 19 | 20 | *Note: For development, you only need to run ```npm start```* 21 | 22 | Run ```npm run deploy```. 23 | 24 | This will run two scripts automatically: 25 | 26 | 1) ```npm run build``` to transpile ES6 code from the src/ directory to JavaScript in the lib/ directory. 27 | 28 | 2) ```npm run wp``` to set the environment variable ```process.env.NODE_ENV = 'production'```, allow webpack to build your code from lib/, and save it to the build/ directory. 29 | -------------------------------------------------------------------------------- /build/index.html: -------------------------------------------------------------------------------- 1 | React-Apollo Starter Kit for Scaphold.io -------------------------------------------------------------------------------- /lib/apollo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _apolloClient = require('apollo-client'); 8 | 9 | var _apolloClient2 = _interopRequireDefault(_apolloClient); 10 | 11 | var _config = require('./config'); 12 | 13 | var _config2 = _interopRequireDefault(_config); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | var networkInterface = (0, _apolloClient.createNetworkInterface)({ 18 | uri: _config2.default.scapholdUrl 19 | }); 20 | networkInterface.use([{ 21 | applyMiddleware: function applyMiddleware(req, next) { 22 | if (!req.options.headers) { 23 | req.options.headers = {}; // Create the header object if needed. 24 | } 25 | if (localStorage.getItem('token')) { 26 | req.options.headers.Authorization = 'Bearer ' + localStorage.getItem('token'); 27 | } 28 | next(); 29 | } 30 | }]); 31 | 32 | var client = new _apolloClient2.default({ 33 | networkInterface: networkInterface 34 | }); 35 | 36 | exports.default = client; -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Modify the config Scaphold URL to point to your specific app. 5 | * Find the URL at the top of the page on Scaphold.io once you've created an app. 6 | * Yup. It's that easy. 7 | */ 8 | 9 | var config = { 10 | scapholdUrl: 'https://us-west-2.api.scaphold.io/graphql/react-apollo-starter-kit' 11 | }; 12 | 13 | module.exports = config; -------------------------------------------------------------------------------- /lib/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | React-Apollo Starter Kit for Scaphold.io 10 | 11 | 16 | 17 | 18 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _react = require('react'); 4 | 5 | var _react2 = _interopRequireDefault(_react); 6 | 7 | var _reactDom = require('react-dom'); 8 | 9 | var _reactDom2 = _interopRequireDefault(_reactDom); 10 | 11 | var _reactRouter = require('react-router'); 12 | 13 | var _reactApollo = require('react-apollo'); 14 | 15 | var _App = require('./components/App/App'); 16 | 17 | var _App2 = _interopRequireDefault(_App); 18 | 19 | var _Home = require('./components/Home/Home'); 20 | 21 | var _Home2 = _interopRequireDefault(_Home); 22 | 23 | var _GraphiQL = require('./components/GraphiQL/GraphiQL'); 24 | 25 | var _GraphiQL2 = _interopRequireDefault(_GraphiQL); 26 | 27 | var _apollo = require('../apollo'); 28 | 29 | var _apollo2 = _interopRequireDefault(_apollo); 30 | 31 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 32 | 33 | _reactDom2.default.render(_react2.default.createElement( 34 | _reactApollo.ApolloProvider, 35 | { client: _apollo2.default }, 36 | _react2.default.createElement( 37 | _reactRouter.Router, 38 | { 39 | history: _reactRouter.browserHistory, 40 | routes: _reactRouter.routes, 41 | render: (0, _reactRouter.applyRouterMiddleware)() 42 | }, 43 | _react2.default.createElement(_reactRouter.Route, { path: '/', component: _App2.default }), 44 | _react2.default.createElement(_reactRouter.Route, { path: '/home', component: _Home2.default }), 45 | _react2.default.createElement(_reactRouter.Route, { path: '/graphiql', component: _GraphiQL2.default }) 46 | ) 47 | ), document.getElementById('root')); -------------------------------------------------------------------------------- /lib/js/components/App/App.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _templateObject = _taggedTemplateLiteral(['\n query GetUser($id: ID!) {\n getUser(id: $id) {\n id\n username\n }\n }\n'], ['\n query GetUser($id: ID!) {\n getUser(id: $id) {\n id\n username\n }\n }\n']); 10 | 11 | var _react = require('react'); 12 | 13 | var _react2 = _interopRequireDefault(_react); 14 | 15 | var _graphqlTag = require('graphql-tag'); 16 | 17 | var _graphqlTag2 = _interopRequireDefault(_graphqlTag); 18 | 19 | var _reactRouter = require('react-router'); 20 | 21 | var _apollo = require('../../../apollo'); 22 | 23 | var _apollo2 = _interopRequireDefault(_apollo); 24 | 25 | var _Header = require('./Header'); 26 | 27 | var _Header2 = _interopRequireDefault(_Header); 28 | 29 | var _Hero = require('./Hero'); 30 | 31 | var _Hero2 = _interopRequireDefault(_Hero); 32 | 33 | var _Description = require('./Description'); 34 | 35 | var _Description2 = _interopRequireDefault(_Description); 36 | 37 | var _Footer = require('./Footer'); 38 | 39 | var _Footer2 = _interopRequireDefault(_Footer); 40 | 41 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 42 | 43 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 44 | 45 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 46 | 47 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 48 | 49 | function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } 50 | 51 | var userQuery = (0, _graphqlTag2.default)(_templateObject); 52 | 53 | var App = function (_React$Component) { 54 | _inherits(App, _React$Component); 55 | 56 | function App(props) { 57 | _classCallCheck(this, App); 58 | 59 | var _this = _possibleConstructorReturn(this, (App.__proto__ || Object.getPrototypeOf(App)).call(this, props)); 60 | 61 | _this.state = { 62 | loading: true 63 | }; 64 | return _this; 65 | } 66 | 67 | _createClass(App, [{ 68 | key: 'componentDidMount', 69 | value: function componentDidMount() { 70 | var token = localStorage.getItem('token'); 71 | var user = JSON.parse(localStorage.getItem('user')); 72 | var userId = user ? user.id : null; 73 | if (token && userId) { 74 | // If we are logged in subscribe to the user and render the app. 75 | this.subscribeToUser(userId); 76 | } else { 77 | // We are not logged in so stop loading and render the landing page. 78 | this.setState({ // eslint-disable-line 79 | loading: false 80 | }); 81 | } 82 | } 83 | }, { 84 | key: 'subscribeToUser', 85 | value: function subscribeToUser(id) { 86 | var that = this; 87 | var observable = _apollo2.default.watchQuery({ 88 | query: userQuery, 89 | pollInterval: 60000, 90 | forceFetch: true, 91 | variables: { 92 | id: id 93 | } 94 | }); 95 | var subscription = observable.subscribe({ 96 | next: function next(result) { 97 | if (result && result.errors) { 98 | var unauthed = result.errors.reduce(function (acc, err) { 99 | return acc || err.status === 401; 100 | }, false); 101 | if (unauthed) { 102 | localStorage.clear(); 103 | that.setState({ 104 | user: result.data.getUser, 105 | loading: false 106 | }); 107 | } 108 | } else { 109 | localStorage.setItem('currentUsername', result.data.getUser.username); 110 | that.setState({ 111 | user: result.data.getUser, 112 | loading: false 113 | }); 114 | _reactRouter.browserHistory.push('/home'); 115 | } 116 | }, 117 | error: function error(_error) { 118 | console.log('Error subscribing to user: ' + _error.toString()); 119 | that.setState({ 120 | loading: false 121 | }); 122 | }, 123 | // Network error, etc. 124 | complete: function complete() { 125 | // console.log(`Subscription complete`); 126 | } 127 | }); 128 | this.setState({ 129 | userSubscription: subscription 130 | }); 131 | } 132 | }, { 133 | key: 'render', 134 | value: function render() { 135 | return _react2.default.createElement( 136 | 'div', 137 | null, 138 | _react2.default.createElement(_Header2.default, null), 139 | _react2.default.createElement(_Hero2.default, null), 140 | _react2.default.createElement(_Description2.default, null), 141 | _react2.default.createElement(_Footer2.default, null) 142 | ); 143 | } 144 | }]); 145 | 146 | return App; 147 | }(_react2.default.Component); 148 | 149 | App.propTypes = {}; 150 | 151 | exports.default = App; -------------------------------------------------------------------------------- /lib/js/components/App/Description.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _reactBootstrap = require('react-bootstrap'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 18 | 19 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 20 | 21 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 22 | 23 | var styles = { 24 | marketing: { 25 | margin: '40px 0', 26 | p: { 27 | marginTop: 28 28 | }, 29 | h4: { 30 | marginTop: 28 31 | } 32 | } 33 | }; 34 | 35 | var Description = function (_React$Component) { 36 | _inherits(Description, _React$Component); 37 | 38 | function Description() { 39 | _classCallCheck(this, Description); 40 | 41 | return _possibleConstructorReturn(this, (Description.__proto__ || Object.getPrototypeOf(Description)).apply(this, arguments)); 42 | } 43 | 44 | _createClass(Description, [{ 45 | key: 'render', 46 | // eslint-disable-line 47 | value: function render() { 48 | return _react2.default.createElement( 49 | _reactBootstrap.Row, 50 | { style: styles.marketing }, 51 | _react2.default.createElement( 52 | _reactBootstrap.Col, 53 | { smOffset: 2, sm: 4 }, 54 | _react2.default.createElement( 55 | 'h4', 56 | { style: styles.marketing.h4 }, 57 | _react2.default.createElement( 58 | 'a', 59 | { target: '_blank', href: 'https://facebook.github.io/react/' }, 60 | 'React.js Boilerplate' 61 | ) 62 | ), 63 | _react2.default.createElement( 64 | 'p', 65 | { style: styles.marketing.p }, 66 | 'This React.js boilerplate helps developers create modern, performant, and clean web apps with the help of Scaphold.io.' 67 | ), 68 | _react2.default.createElement( 69 | 'h4', 70 | { style: styles.marketing.h4 }, 71 | _react2.default.createElement( 72 | 'a', 73 | { target: '_blank', href: 'http://dev.apollodata.com/react/' }, 74 | 'React-Apollo' 75 | ) 76 | ), 77 | _react2.default.createElement( 78 | 'p', 79 | { style: styles.marketing.p }, 80 | 'Leverage the simplicity and power of Apollo Client and GraphQL to manage your application\'s data store.' 81 | ) 82 | ), 83 | _react2.default.createElement( 84 | _reactBootstrap.Col, 85 | { sm: 4 }, 86 | _react2.default.createElement( 87 | 'h4', 88 | { style: styles.marketing.h4 }, 89 | _react2.default.createElement( 90 | 'a', 91 | { target: '_blank', href: 'https://react-bootstrap.github.io/' }, 92 | 'React-Bootstrap' 93 | ) 94 | ), 95 | _react2.default.createElement( 96 | 'p', 97 | { style: styles.marketing.p }, 98 | 'Smoothe and creative components to fit the way you want your apps to be experienced.' 99 | ), 100 | _react2.default.createElement( 101 | 'h4', 102 | { style: styles.marketing.h4 }, 103 | _react2.default.createElement( 104 | 'a', 105 | { target: '_blank', href: 'https://webpack.github.io/docs/list-of-tutorials.html' }, 106 | 'Webpack' 107 | ) 108 | ), 109 | _react2.default.createElement( 110 | 'p', 111 | { style: styles.marketing.p }, 112 | 'Webpack is a module bundler that helps you serve your application in any environment with hot reloading.' 113 | ) 114 | ) 115 | ); 116 | } 117 | }]); 118 | 119 | return Description; 120 | }(_react2.default.Component); 121 | 122 | exports.default = Description; -------------------------------------------------------------------------------- /lib/js/components/App/Footer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _reactFontawesome = require('react-fontawesome'); 14 | 15 | var _reactFontawesome2 = _interopRequireDefault(_reactFontawesome); 16 | 17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 18 | 19 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 20 | 21 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 22 | 23 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 24 | 25 | var styles = { 26 | footer: { 27 | textAlign: 'center', 28 | paddingTop: 20, 29 | color: '#777', 30 | borderTop: '1px, solid, #e5e5e5' 31 | } 32 | }; 33 | 34 | var Footer = function (_React$Component) { 35 | _inherits(Footer, _React$Component); 36 | 37 | function Footer() { 38 | _classCallCheck(this, Footer); 39 | 40 | return _possibleConstructorReturn(this, (Footer.__proto__ || Object.getPrototypeOf(Footer)).apply(this, arguments)); 41 | } 42 | 43 | _createClass(Footer, [{ 44 | key: 'render', 45 | // eslint-disable-line 46 | value: function render() { 47 | return _react2.default.createElement( 48 | 'p', 49 | { style: styles.footer }, 50 | 'Made with ', 51 | _react2.default.createElement(_reactFontawesome2.default, { name: 'heart' }), 52 | ' from the Scaphold Team' 53 | ); 54 | } 55 | }]); 56 | 57 | return Footer; 58 | }(_react2.default.Component); 59 | 60 | exports.default = Footer; -------------------------------------------------------------------------------- /lib/js/components/App/Header.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _reactRouter = require('react-router'); 14 | 15 | var _reactBootstrap = require('react-bootstrap'); 16 | 17 | var _Login = require('./Login'); 18 | 19 | var _Login2 = _interopRequireDefault(_Login); 20 | 21 | var _Register = require('./Register'); 22 | 23 | var _Register2 = _interopRequireDefault(_Register); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 28 | 29 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 30 | 31 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 32 | 33 | var Header = function (_React$Component) { 34 | _inherits(Header, _React$Component); 35 | 36 | function Header(props) { 37 | _classCallCheck(this, Header); 38 | 39 | var _this = _possibleConstructorReturn(this, (Header.__proto__ || Object.getPrototypeOf(Header)).call(this, props)); 40 | 41 | _this.state = { 42 | showModal: false 43 | }; 44 | return _this; 45 | } 46 | 47 | _createClass(Header, [{ 48 | key: 'goToGraphiQL', 49 | value: function goToGraphiQL() { 50 | _reactRouter.browserHistory.push('/graphiql'); 51 | } 52 | }, { 53 | key: 'goHome', 54 | value: function goHome() { 55 | _reactRouter.browserHistory.push('/'); 56 | } 57 | }, { 58 | key: 'render', 59 | value: function render() { 60 | return _react2.default.createElement( 61 | _reactBootstrap.Navbar, 62 | { style: styles.navbar }, 63 | _react2.default.createElement( 64 | _reactBootstrap.Navbar.Header, 65 | null, 66 | _react2.default.createElement( 67 | _reactBootstrap.Navbar.Brand, 68 | null, 69 | _react2.default.createElement( 70 | _reactRouter.Link, 71 | { to: '/' }, 72 | 'Scaphold' 73 | ) 74 | ) 75 | ), 76 | _react2.default.createElement( 77 | _reactBootstrap.Nav, 78 | { pullRight: true }, 79 | _react2.default.createElement( 80 | _reactBootstrap.NavItem, 81 | { onClick: this.goHome }, 82 | 'Home' 83 | ), 84 | _react2.default.createElement( 85 | _reactBootstrap.NavItem, 86 | { onClick: this.goToGraphiQL }, 87 | 'GraphiQL' 88 | ), 89 | _react2.default.createElement(_Login2.default, null), 90 | _react2.default.createElement(_Register2.default, null) 91 | ) 92 | ); 93 | } 94 | }]); 95 | 96 | return Header; 97 | }(_react2.default.Component); 98 | 99 | exports.default = Header; 100 | 101 | 102 | var styles = { 103 | navbar: { 104 | marginBottom: 0 105 | } 106 | }; -------------------------------------------------------------------------------- /lib/js/components/App/Hero.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _reactBootstrap = require('react-bootstrap'); 14 | 15 | var _reactFontawesome = require('react-fontawesome'); 16 | 17 | var _reactFontawesome2 = _interopRequireDefault(_reactFontawesome); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 22 | 23 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 24 | 25 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 26 | 27 | var Hero = function (_React$Component) { 28 | _inherits(Hero, _React$Component); 29 | 30 | function Hero() { 31 | _classCallCheck(this, Hero); 32 | 33 | return _possibleConstructorReturn(this, (Hero.__proto__ || Object.getPrototypeOf(Hero)).apply(this, arguments)); 34 | } 35 | 36 | _createClass(Hero, [{ 37 | key: 'render', 38 | value: function render() { 39 | return _react2.default.createElement( 40 | _reactBootstrap.Row, 41 | null, 42 | _react2.default.createElement( 43 | _reactBootstrap.Col, 44 | { smOffset: 2, sm: 8 }, 45 | _react2.default.createElement( 46 | _reactBootstrap.Jumbotron, 47 | { style: styles.jumbotron }, 48 | _react2.default.createElement( 49 | 'h1', 50 | null, 51 | 'Welcome!' 52 | ), 53 | _react2.default.createElement('br', null), 54 | _react2.default.createElement( 55 | 'p', 56 | null, 57 | 'Here you\'ll find ', 58 | _react2.default.createElement( 59 | 'a', 60 | { href: 'https://scaphold.io', target: '_blank', style: styles.scaphold }, 61 | 'Scaphold.io' 62 | ), 63 | '\'s Boilerplate React-Apollo template \xA0', 64 | _react2.default.createElement(_reactFontawesome2.default, { name: 'smile-o' }) 65 | ), 66 | _react2.default.createElement('br', null), 67 | _react2.default.createElement( 68 | 'p', 69 | null, 70 | _react2.default.createElement( 71 | _reactBootstrap.Button, 72 | { bsStyle: 'primary', bsSize: 'large', target: '_blank', href: 'https://scaphold.io' }, 73 | 'Learn more ', 74 | _react2.default.createElement(_reactFontawesome2.default, { name: 'check' }) 75 | ), 76 | _react2.default.createElement( 77 | _reactBootstrap.Button, 78 | { style: styles.slack, bsSize: 'large', target: '_blank', href: 'http://slack.scaphold.io' }, 79 | 'Join our Slack ', 80 | _react2.default.createElement(_reactFontawesome2.default, { name: 'slack' }) 81 | ) 82 | ) 83 | ) 84 | ) 85 | ); 86 | } 87 | }]); 88 | 89 | return Hero; 90 | }(_react2.default.Component); 91 | 92 | exports.default = Hero; 93 | 94 | 95 | var styles = { 96 | jumbotron: { 97 | marginTop: 20, 98 | borderRadius: 10, 99 | textAlign: 'center' 100 | }, 101 | scaphold: { 102 | color: '#1DAAA0' 103 | }, 104 | slack: { 105 | color: 'white', 106 | backgroundColor: '#1DAAA0' 107 | } 108 | }; -------------------------------------------------------------------------------- /lib/js/components/App/Login.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _templateObject = _taggedTemplateLiteral(['\n mutation LoginUserMutation($data: LoginUserInput!) {\n loginUser(input: $data) {\n token\n user {\n id\n username\n }\n }\n }\n'], ['\n mutation LoginUserMutation($data: LoginUserInput!) {\n loginUser(input: $data) {\n token\n user {\n id\n username\n }\n }\n }\n']); 10 | 11 | var _react = require('react'); 12 | 13 | var _react2 = _interopRequireDefault(_react); 14 | 15 | var _reactApollo = require('react-apollo'); 16 | 17 | var _graphqlTag = require('graphql-tag'); 18 | 19 | var _graphqlTag2 = _interopRequireDefault(_graphqlTag); 20 | 21 | var _reactRouter = require('react-router'); 22 | 23 | var _reactBootstrap = require('react-bootstrap'); 24 | 25 | var _config = require('./../../../config'); 26 | 27 | var _config2 = _interopRequireDefault(_config); 28 | 29 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 30 | 31 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 32 | 33 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 34 | 35 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 36 | 37 | function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } 38 | 39 | var LoginUserMutation = (0, _graphqlTag2.default)(_templateObject); 40 | 41 | var Login = function (_React$Component) { 42 | _inherits(Login, _React$Component); 43 | 44 | function Login(props) { 45 | _classCallCheck(this, Login); 46 | 47 | var _this = _possibleConstructorReturn(this, (Login.__proto__ || Object.getPrototypeOf(Login)).call(this, props)); 48 | 49 | _this.state = { 50 | showModal: false, 51 | loginEmail: '', 52 | loginPassword: '', 53 | errors: [] 54 | }; 55 | _this.close = _this.close.bind(_this); 56 | _this.open = _this.open.bind(_this); 57 | _this._handleLoginEmailChange = _this._handleLoginEmailChange.bind(_this); 58 | _this._handleLoginPasswordChange = _this._handleLoginPasswordChange.bind(_this); 59 | _this.validateInput = _this.validateInput.bind(_this); 60 | _this.loginUser = _this.loginUser.bind(_this); 61 | return _this; 62 | } 63 | 64 | _createClass(Login, [{ 65 | key: 'close', 66 | value: function close() { 67 | this.setState({ showModal: false }); 68 | } 69 | }, { 70 | key: 'open', 71 | value: function open() { 72 | this.setState({ showModal: true }); 73 | } 74 | }, { 75 | key: '_handleLoginEmailChange', 76 | value: function _handleLoginEmailChange(e) { 77 | this.setState({ 78 | loginEmail: e.target.value 79 | }); 80 | } 81 | }, { 82 | key: '_handleLoginPasswordChange', 83 | value: function _handleLoginPasswordChange(e) { 84 | this.setState({ 85 | loginPassword: e.target.value 86 | }); 87 | } 88 | }, { 89 | key: 'validateInput', 90 | value: function validateInput() { 91 | return this.state.loginEmail && this.state.loginEmail.length && this.state.loginPassword && this.state.loginPassword.length; 92 | } 93 | }, { 94 | key: 'loginUser', 95 | value: function loginUser() { 96 | var _this2 = this; 97 | 98 | if (this.validateInput()) { 99 | this.props.login({ 100 | username: this.state.loginEmail, 101 | password: this.state.loginPassword 102 | }).then(function (_ref) { 103 | var data = _ref.data; 104 | 105 | if (!data.errors) { 106 | localStorage.setItem('token', data.loginUser.token); 107 | localStorage.setItem('user', JSON.stringify(data.loginUser.user)); 108 | _this2.setState({ errors: [] }); 109 | _reactRouter.browserHistory.push('/home'); 110 | } else { 111 | _this2.setState({ errors: data.errors }); 112 | } 113 | }).catch(function (errors) { 114 | _this2.setState({ errors: errors.graphQLErrors }); 115 | }); 116 | } else { 117 | this.setState({ 118 | errors: [{ 119 | message: 'Username or password was not filled out. Please fill out the required fields.' 120 | }] 121 | }); 122 | } 123 | } 124 | }, { 125 | key: 'render', 126 | value: function render() { 127 | return _react2.default.createElement( 128 | _reactBootstrap.NavItem, 129 | { onClick: this.open }, 130 | 'Login', 131 | _react2.default.createElement( 132 | _reactBootstrap.Modal, 133 | { show: this.state.showModal, onHide: this.close }, 134 | _react2.default.createElement( 135 | _reactBootstrap.Modal.Header, 136 | { closeButton: true }, 137 | _react2.default.createElement( 138 | _reactBootstrap.Modal.Title, 139 | null, 140 | 'Login Here!' 141 | ) 142 | ), 143 | _react2.default.createElement( 144 | _reactBootstrap.Modal.Body, 145 | null, 146 | _react2.default.createElement( 147 | 'div', 148 | { style: styles.errors }, 149 | this.state.errors.map(function (err, i) { 150 | return _react2.default.createElement( 151 | _reactBootstrap.Alert, 152 | { key: i, bsStyle: 'danger' }, 153 | err.message 154 | ); 155 | }) 156 | ), 157 | _react2.default.createElement( 158 | _reactBootstrap.Form, 159 | { horizontal: true }, 160 | _react2.default.createElement( 161 | _reactBootstrap.FormGroup, 162 | { controlId: 'formLoginEmail' }, 163 | _react2.default.createElement( 164 | _reactBootstrap.Col, 165 | { componentClass: _reactBootstrap.ControlLabel, smOffset: 1, sm: 2 }, 166 | 'Email' 167 | ), 168 | _react2.default.createElement( 169 | _reactBootstrap.Col, 170 | { sm: 8 }, 171 | _react2.default.createElement(_reactBootstrap.FormControl, { type: 'email', placeholder: 'Email', onChange: this._handleLoginEmailChange }) 172 | ) 173 | ), 174 | _react2.default.createElement( 175 | _reactBootstrap.FormGroup, 176 | { controlId: 'formLoginPassword' }, 177 | _react2.default.createElement( 178 | _reactBootstrap.Col, 179 | { componentClass: _reactBootstrap.ControlLabel, smOffset: 1, sm: 2 }, 180 | 'Password' 181 | ), 182 | _react2.default.createElement( 183 | _reactBootstrap.Col, 184 | { sm: 8 }, 185 | _react2.default.createElement(_reactBootstrap.FormControl, { type: 'password', placeholder: 'Password', onChange: this._handleLoginPasswordChange }) 186 | ) 187 | ) 188 | ) 189 | ), 190 | _react2.default.createElement( 191 | _reactBootstrap.Modal.Footer, 192 | null, 193 | _react2.default.createElement( 194 | _reactBootstrap.Button, 195 | { bsStyle: 'primary', type: 'submit', onClick: this.loginUser }, 196 | 'Login' 197 | ), 198 | _react2.default.createElement( 199 | _reactBootstrap.Button, 200 | { onClick: this.close }, 201 | 'Close' 202 | ) 203 | ) 204 | ) 205 | ); 206 | } 207 | }]); 208 | 209 | return Login; 210 | }(_react2.default.Component); 211 | 212 | var styles = { 213 | errors: { 214 | textAlign: 'left', 215 | color: 'red' 216 | } 217 | }; 218 | 219 | var LoginWithData = (0, _reactApollo.graphql)(LoginUserMutation, { 220 | props: function props(_ref2) { 221 | var mutate = _ref2.mutate; 222 | return { 223 | login: function login(data) { 224 | return mutate({ 225 | variables: { 226 | data: data 227 | } 228 | }); 229 | } 230 | }; 231 | } 232 | })(Login); 233 | exports.default = LoginWithData; -------------------------------------------------------------------------------- /lib/js/components/App/Register.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _templateObject = _taggedTemplateLiteral(['\n mutation CreateUserMutation($data: CreateUserInput!) {\n createUser(input: $data) {\n token\n changedUser {\n id\n username\n }\n }\n }\n'], ['\n mutation CreateUserMutation($data: CreateUserInput!) {\n createUser(input: $data) {\n token\n changedUser {\n id\n username\n }\n }\n }\n']); 10 | 11 | var _react = require('react'); 12 | 13 | var _react2 = _interopRequireDefault(_react); 14 | 15 | var _reactApollo = require('react-apollo'); 16 | 17 | var _graphqlTag = require('graphql-tag'); 18 | 19 | var _graphqlTag2 = _interopRequireDefault(_graphqlTag); 20 | 21 | var _reactRouter = require('react-router'); 22 | 23 | var _reactBootstrap = require('react-bootstrap'); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 28 | 29 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 30 | 31 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 32 | 33 | function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } 34 | 35 | var CreateUserMutation = (0, _graphqlTag2.default)(_templateObject); 36 | 37 | var Register = function (_React$Component) { 38 | _inherits(Register, _React$Component); 39 | 40 | function Register(props) { 41 | _classCallCheck(this, Register); 42 | 43 | var _this = _possibleConstructorReturn(this, (Register.__proto__ || Object.getPrototypeOf(Register)).call(this, props)); 44 | 45 | _this.state = { 46 | showModal: false, 47 | registerEmail: '', 48 | registerPassword: '', 49 | errors: [] 50 | }; 51 | 52 | _this.close = _this.close.bind(_this); 53 | _this.open = _this.open.bind(_this); 54 | _this._handleRegisterEmailChange = _this._handleRegisterEmailChange.bind(_this); 55 | _this._handleRegisterPasswordChange = _this._handleRegisterPasswordChange.bind(_this); 56 | _this.validateInput = _this.validateInput.bind(_this); 57 | _this.registerUser = _this.registerUser.bind(_this); 58 | return _this; 59 | } 60 | 61 | _createClass(Register, [{ 62 | key: 'close', 63 | value: function close() { 64 | this.setState({ showModal: false }); 65 | } 66 | }, { 67 | key: 'open', 68 | value: function open() { 69 | this.setState({ showModal: true }); 70 | } 71 | }, { 72 | key: 'validateInput', 73 | value: function validateInput() { 74 | return this.state.registerEmail && this.state.registerEmail.length && this.state.registerPassword && this.state.registerPassword.length; 75 | } 76 | }, { 77 | key: 'registerUser', 78 | value: function registerUser() { 79 | var _this2 = this; 80 | 81 | if (this.validateInput()) { 82 | this.props.register({ 83 | username: this.state.registerEmail, 84 | password: this.state.registerPassword 85 | }).then(function (_ref) { 86 | var data = _ref.data; 87 | 88 | if (!data.errors) { 89 | localStorage.setItem('token', data.createUser.token); 90 | localStorage.setItem('user', JSON.stringify(data.createUser.changedUser)); 91 | _this2.setState({ errors: [] }); 92 | _reactRouter.browserHistory.push('/home'); 93 | } else { 94 | _this2.setState({ errors: data.errors }); 95 | } 96 | }).catch(function (errors) { 97 | _this2.setState({ errors: errors.graphQLErrors }); 98 | }); 99 | } else { 100 | this.setState({ 101 | errors: [{ 102 | message: 'Username or password was not filled out. Please fill out the required fields.' 103 | }] 104 | }); 105 | } 106 | } 107 | }, { 108 | key: '_handleRegisterEmailChange', 109 | value: function _handleRegisterEmailChange(e) { 110 | this.setState({ 111 | registerEmail: e.target.value 112 | }); 113 | } 114 | }, { 115 | key: '_handleRegisterPasswordChange', 116 | value: function _handleRegisterPasswordChange(e) { 117 | this.setState({ 118 | registerPassword: e.target.value 119 | }); 120 | } 121 | }, { 122 | key: 'render', 123 | value: function render() { 124 | return _react2.default.createElement( 125 | _reactBootstrap.NavItem, 126 | { onClick: this.open }, 127 | 'Register', 128 | _react2.default.createElement( 129 | _reactBootstrap.Modal, 130 | { show: this.state.showModal, onHide: this.close }, 131 | _react2.default.createElement( 132 | _reactBootstrap.Modal.Header, 133 | { closeButton: true }, 134 | _react2.default.createElement( 135 | _reactBootstrap.Modal.Title, 136 | null, 137 | 'Register Here!' 138 | ) 139 | ), 140 | _react2.default.createElement( 141 | _reactBootstrap.Modal.Body, 142 | null, 143 | _react2.default.createElement( 144 | 'div', 145 | { style: styles.errors }, 146 | this.state.errors.map(function (err, i) { 147 | return _react2.default.createElement( 148 | _reactBootstrap.Alert, 149 | { key: i, bsStyle: 'danger' }, 150 | err.message 151 | ); 152 | }) 153 | ), 154 | _react2.default.createElement( 155 | _reactBootstrap.Form, 156 | { horizontal: true }, 157 | _react2.default.createElement( 158 | _reactBootstrap.Row, 159 | null, 160 | _react2.default.createElement( 161 | _reactBootstrap.FormGroup, 162 | { controlId: 'formRegisterEmail' }, 163 | _react2.default.createElement( 164 | _reactBootstrap.Col, 165 | { componentClass: _reactBootstrap.ControlLabel, smOffset: 1, sm: 2 }, 166 | 'Email' 167 | ), 168 | _react2.default.createElement( 169 | _reactBootstrap.Col, 170 | { sm: 8 }, 171 | _react2.default.createElement(_reactBootstrap.FormControl, { type: 'email', placeholder: 'Email', onChange: this._handleRegisterEmailChange }) 172 | ) 173 | ), 174 | _react2.default.createElement( 175 | _reactBootstrap.FormGroup, 176 | { controlId: 'formRegisterPassword' }, 177 | _react2.default.createElement( 178 | _reactBootstrap.Col, 179 | { componentClass: _reactBootstrap.ControlLabel, smOffset: 1, sm: 2 }, 180 | 'Password' 181 | ), 182 | _react2.default.createElement( 183 | _reactBootstrap.Col, 184 | { sm: 8 }, 185 | _react2.default.createElement(_reactBootstrap.FormControl, { type: 'password', placeholder: 'Password', onChange: this._handleRegisterPasswordChange }) 186 | ) 187 | ) 188 | ) 189 | ) 190 | ), 191 | _react2.default.createElement( 192 | _reactBootstrap.Modal.Footer, 193 | null, 194 | _react2.default.createElement( 195 | _reactBootstrap.Button, 196 | { bsStyle: 'primary', type: 'submit', onClick: this.registerUser }, 197 | 'Register' 198 | ), 199 | _react2.default.createElement( 200 | _reactBootstrap.Button, 201 | { onClick: this.close }, 202 | 'Close' 203 | ) 204 | ) 205 | ) 206 | ); 207 | } 208 | }]); 209 | 210 | return Register; 211 | }(_react2.default.Component); 212 | 213 | var styles = { 214 | errors: { 215 | textAlign: 'left', 216 | color: 'red' 217 | } 218 | }; 219 | 220 | var RegisterWithData = (0, _reactApollo.graphql)(CreateUserMutation, { 221 | props: function props(_ref2) { 222 | var mutate = _ref2.mutate; 223 | return { 224 | register: function register(data) { 225 | return mutate({ 226 | variables: { 227 | data: data 228 | } 229 | }); 230 | } 231 | }; 232 | } 233 | })(Register); 234 | exports.default = RegisterWithData; -------------------------------------------------------------------------------- /lib/js/components/GraphiQL/GraphiQL.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _graphiql = require('graphiql'); 14 | 15 | var _graphiql2 = _interopRequireDefault(_graphiql); 16 | 17 | var _isomorphicFetch = require('isomorphic-fetch'); 18 | 19 | var _isomorphicFetch2 = _interopRequireDefault(_isomorphicFetch); 20 | 21 | var _config = require('./../../../config'); 22 | 23 | var _config2 = _interopRequireDefault(_config); 24 | 25 | var _Header = require('./../App/Header'); 26 | 27 | var _Header2 = _interopRequireDefault(_Header); 28 | 29 | var _Header3 = require('./../Home/Header'); 30 | 31 | var _Header4 = _interopRequireDefault(_Header3); 32 | 33 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 34 | 35 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 36 | 37 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 38 | 39 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 40 | 41 | function graphQLFetcher(graphQLParams) { 42 | return (0, _isomorphicFetch2.default)(_config2.default.scapholdUrl, { 43 | method: 'post', 44 | headers: { 45 | 'Content-Type': 'application/json', 46 | Authorization: localStorage.token ? 'Bearer ' + localStorage.token : '' 47 | }, 48 | body: JSON.stringify(graphQLParams) 49 | }).then(function (response) { 50 | return response.json(); 51 | }); 52 | } 53 | 54 | var GraphiQLModule = function (_React$Component) { 55 | _inherits(GraphiQLModule, _React$Component); 56 | 57 | function GraphiQLModule() { 58 | _classCallCheck(this, GraphiQLModule); 59 | 60 | return _possibleConstructorReturn(this, (GraphiQLModule.__proto__ || Object.getPrototypeOf(GraphiQLModule)).apply(this, arguments)); 61 | } 62 | 63 | _createClass(GraphiQLModule, [{ 64 | key: 'render', 65 | value: function render() { 66 | var header = void 0; 67 | if (!localStorage.token) { 68 | header = _react2.default.createElement(_Header2.default, null); 69 | } else { 70 | header = _react2.default.createElement(_Header4.default, null); 71 | } 72 | 73 | return _react2.default.createElement( 74 | 'span', 75 | null, 76 | header, 77 | _react2.default.createElement(_graphiql2.default, { fetcher: graphQLFetcher }) 78 | ); 79 | } 80 | }]); 81 | 82 | return GraphiQLModule; 83 | }(_react2.default.Component); 84 | 85 | exports.default = GraphiQLModule; -------------------------------------------------------------------------------- /lib/js/components/Home/Body.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _reactBootstrap = require('react-bootstrap'); 14 | 15 | var _Description = require('../App/Description'); 16 | 17 | var _Description2 = _interopRequireDefault(_Description); 18 | 19 | var _reactFontawesome = require('react-fontawesome'); 20 | 21 | var _reactFontawesome2 = _interopRequireDefault(_reactFontawesome); 22 | 23 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 24 | 25 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 26 | 27 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 28 | 29 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 30 | 31 | var Body = function (_React$Component) { 32 | _inherits(Body, _React$Component); 33 | 34 | function Body() { 35 | _classCallCheck(this, Body); 36 | 37 | return _possibleConstructorReturn(this, (Body.__proto__ || Object.getPrototypeOf(Body)).apply(this, arguments)); 38 | } 39 | 40 | _createClass(Body, [{ 41 | key: 'render', 42 | value: function render() { 43 | var user = JSON.parse(localStorage.getItem('user')); 44 | var loggedInUser = user ? user.username : ''; 45 | 46 | return _react2.default.createElement( 47 | 'div', 48 | null, 49 | _react2.default.createElement( 50 | _reactBootstrap.Row, 51 | { style: styles.heading }, 52 | 'Welcome, you\'ve successfully logged in to ', 53 | _react2.default.createElement( 54 | 'a', 55 | { href: 'https://scaphold.io', target: '_blank', style: styles.scaphold }, 56 | 'Scaphold' 57 | ), 58 | '\'s React Apollo Starter Kit!' 59 | ), 60 | _react2.default.createElement( 61 | _reactBootstrap.Row, 62 | { style: styles.subheading }, 63 | _react2.default.createElement( 64 | _reactBootstrap.Col, 65 | { smOffset: 3, sm: 6 }, 66 | loggedInUser ? _react2.default.createElement( 67 | 'div', 68 | { style: styles.subheading.section }, 69 | 'Username: ', 70 | _react2.default.createElement( 71 | 'b', 72 | null, 73 | loggedInUser 74 | ) 75 | ) : '', 76 | _react2.default.createElement( 77 | 'div', 78 | { style: styles.subheading.section }, 79 | 'Feel free to poke around and check out the other functionality that this starter kit provides. We\'ve put together a couple tools for you to get this starter kit rolling.' 80 | ), 81 | _react2.default.createElement( 82 | 'div', 83 | { style: styles.subheading.section }, 84 | 'So by all means, modify the code, break it, and learn about the same awesome technology that Facebook is built on.' 85 | ), 86 | _react2.default.createElement( 87 | 'div', 88 | { style: styles.subheading.section }, 89 | _react2.default.createElement( 90 | _reactBootstrap.Button, 91 | { bsStyle: 'primary', bsSize: 'large', target: '_blank', href: 'https://scaphold.io' }, 92 | 'Learn more ', 93 | _react2.default.createElement(_reactFontawesome2.default, { name: 'check' }) 94 | ), 95 | _react2.default.createElement( 96 | _reactBootstrap.Button, 97 | { style: styles.slack, bsSize: 'large', target: '_blank', href: 'http://slack.scaphold.io' }, 98 | 'Join our Slack ', 99 | _react2.default.createElement(_reactFontawesome2.default, { name: 'slack' }) 100 | ) 101 | ) 102 | ) 103 | ), 104 | _react2.default.createElement(_Description2.default, null) 105 | ); 106 | } 107 | }]); 108 | 109 | return Body; 110 | }(_react2.default.Component); 111 | 112 | var styles = { 113 | heading: { 114 | padding: '100px 0 50px 0', 115 | fontSize: '25px', 116 | textAlign: 'center' 117 | }, 118 | subheading: { 119 | padding: '0 0 50px 0', 120 | fontSize: '18px', 121 | textAlign: 'center', 122 | section: { 123 | padding: '25px' 124 | } 125 | }, 126 | scaphold: { 127 | color: '#1DAAA0' 128 | }, 129 | slack: { 130 | color: 'white', 131 | backgroundColor: '#1DAAA0' 132 | } 133 | }; 134 | 135 | exports.default = Body; -------------------------------------------------------------------------------- /lib/js/components/Home/Header.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _reactApollo = require('react-apollo'); 14 | 15 | var _graphqlTag = require('graphql-tag'); 16 | 17 | var _graphqlTag2 = _interopRequireDefault(_graphqlTag); 18 | 19 | var _reactRouter = require('react-router'); 20 | 21 | var _reactBootstrap = require('react-bootstrap'); 22 | 23 | var _Logout = require('./Logout'); 24 | 25 | var _Logout2 = _interopRequireDefault(_Logout); 26 | 27 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 28 | 29 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 30 | 31 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 32 | 33 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 34 | 35 | var Header = function (_React$Component) { 36 | _inherits(Header, _React$Component); 37 | 38 | function Header(props) { 39 | _classCallCheck(this, Header); 40 | 41 | var _this = _possibleConstructorReturn(this, (Header.__proto__ || Object.getPrototypeOf(Header)).call(this, props)); 42 | 43 | _this.goToGraphiQL = _this.goToGraphiQL.bind(_this); 44 | _this.goHome = _this.goHome.bind(_this); 45 | return _this; 46 | } 47 | 48 | _createClass(Header, [{ 49 | key: 'goToGraphiQL', 50 | value: function goToGraphiQL() { 51 | _reactRouter.browserHistory.push('/graphiql'); 52 | } 53 | }, { 54 | key: 'goHome', 55 | value: function goHome() { 56 | _reactRouter.browserHistory.push('/home'); 57 | } 58 | }, { 59 | key: 'render', 60 | value: function render() { 61 | var user = JSON.parse(localStorage.getItem('user')); 62 | var loggedInUser = user ? user.username : ''; 63 | 64 | return _react2.default.createElement( 65 | _reactBootstrap.Navbar, 66 | { style: styles.navbar }, 67 | _react2.default.createElement( 68 | _reactBootstrap.Navbar.Header, 69 | null, 70 | _react2.default.createElement( 71 | _reactBootstrap.Navbar.Brand, 72 | null, 73 | _react2.default.createElement( 74 | _reactRouter.Link, 75 | { to: '/home' }, 76 | 'Scaphold' 77 | ) 78 | ) 79 | ), 80 | _react2.default.createElement( 81 | _reactBootstrap.Nav, 82 | { pullRight: true }, 83 | _react2.default.createElement( 84 | _reactBootstrap.NavItem, 85 | { onClick: this.goHome }, 86 | 'Home' 87 | ), 88 | _react2.default.createElement( 89 | _reactBootstrap.NavItem, 90 | { onClick: this.goToGraphiQL }, 91 | 'GraphiQL' 92 | ), 93 | _react2.default.createElement( 94 | _reactBootstrap.NavItem, 95 | null, 96 | loggedInUser 97 | ), 98 | _react2.default.createElement(_Logout2.default, null) 99 | ) 100 | ); 101 | } 102 | }]); 103 | 104 | return Header; 105 | }(_react2.default.Component); 106 | 107 | var styles = { 108 | navbar: { 109 | marginBottom: 0 110 | } 111 | }; 112 | 113 | exports.default = Header; -------------------------------------------------------------------------------- /lib/js/components/Home/Home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _reactBootstrap = require('react-bootstrap'); 14 | 15 | var _reactRouter = require('react-router'); 16 | 17 | var _Header = require('./Header'); 18 | 19 | var _Header2 = _interopRequireDefault(_Header); 20 | 21 | var _Body = require('./Body'); 22 | 23 | var _Body2 = _interopRequireDefault(_Body); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 28 | 29 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 30 | 31 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 32 | 33 | var Home = function (_React$Component) { 34 | _inherits(Home, _React$Component); 35 | 36 | function Home() { 37 | _classCallCheck(this, Home); 38 | 39 | return _possibleConstructorReturn(this, (Home.__proto__ || Object.getPrototypeOf(Home)).apply(this, arguments)); 40 | } 41 | 42 | _createClass(Home, [{ 43 | key: 'render', 44 | value: function render() { 45 | if (!localStorage.token) { 46 | _reactRouter.browserHistory.push('/'); 47 | } 48 | 49 | return _react2.default.createElement( 50 | 'div', 51 | null, 52 | _react2.default.createElement(_Header2.default, null), 53 | _react2.default.createElement(_Body2.default, null) 54 | ); 55 | } 56 | }]); 57 | 58 | return Home; 59 | }(_react2.default.Component); 60 | 61 | exports.default = Home; -------------------------------------------------------------------------------- /lib/js/components/Home/Logout.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _reactRouter = require('react-router'); 14 | 15 | var _reactBootstrap = require('react-bootstrap'); 16 | 17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 18 | 19 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 20 | 21 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 22 | 23 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 24 | 25 | var Logout = function (_React$Component) { 26 | _inherits(Logout, _React$Component); 27 | 28 | function Logout(props) { 29 | _classCallCheck(this, Logout); 30 | 31 | var _this = _possibleConstructorReturn(this, (Logout.__proto__ || Object.getPrototypeOf(Logout)).call(this, props)); 32 | 33 | _this.logoutUser = _this.logoutUser.bind(_this); 34 | return _this; 35 | } 36 | 37 | _createClass(Logout, [{ 38 | key: 'logoutUser', 39 | value: function logoutUser() { 40 | localStorage.clear(); 41 | _reactRouter.browserHistory.push('/'); 42 | } 43 | }, { 44 | key: 'render', 45 | value: function render() { 46 | return _react2.default.createElement( 47 | _reactBootstrap.NavItem, 48 | { onClick: this.logoutUser }, 49 | 'Logout' 50 | ); 51 | } 52 | }]); 53 | 54 | return Logout; 55 | }(_react2.default.Component); 56 | 57 | exports.default = Logout; -------------------------------------------------------------------------------- /lib/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var webpack = require('webpack'); // eslint-disable-line 6 | var WebpackDevServer = require('webpack-dev-server'); // eslint-disable-line 7 | var config = require('./config'); 8 | 9 | var APP_PORT = 3001; 10 | 11 | // Production version 12 | var compiler = webpack({ 13 | entry: path.join(process.cwd(), 'lib', 'js', 'app.js'), 14 | module: { 15 | loaders: [{ 16 | exclude: /node_modules/, 17 | // loader: 'babel-loader', 18 | test: /\.js$/ 19 | }] 20 | }, 21 | output: { 22 | path: path.join(process.cwd(), 'lib'), // sets our output directory to lib/ 23 | filename: 'app.js', // sets our output filename to server.js 24 | publicPath: '/js/' 25 | } 26 | }); 27 | 28 | var app = void 0; 29 | if (process.env.NODE_ENV !== 'production') { 30 | compiler = webpack({ 31 | entry: path.join(process.cwd(), 'src', 'js', 'app.js'), 32 | module: { 33 | loaders: [{ 34 | exclude: /node_modules/, 35 | loader: 'babel-loader', 36 | test: /\.js$/ 37 | }] 38 | }, 39 | output: { 40 | path: path.join(process.cwd(), 'src'), // sets our output directory to lib/ 41 | filename: 'app.js', // sets our output filename to server.js 42 | publicPath: '/' 43 | } 44 | }); 45 | 46 | app = new WebpackDevServer(compiler, { 47 | hot: true, 48 | contentBase: 'src/', 49 | publicPath: '/', 50 | proxy: { '/graphql': config.scapholdUrl }, 51 | stats: { 52 | colors: true 53 | } 54 | }); 55 | } else { 56 | app = new WebpackDevServer(compiler, { 57 | hot: false, 58 | contentBase: 'src/', 59 | publicPath: '/', 60 | proxy: { '/graphql': config.scapholdUrl }, 61 | stats: { 62 | colors: false 63 | } 64 | }); 65 | } 66 | 67 | // Serve static resources 68 | app.use('*', function (req, res) { 69 | fs.readFile(path.join(compiler.outputPath, 'index.html'), function (err, file) { 70 | if (err) { 71 | res.sendStatus(404); 72 | } else { 73 | res.send(file.toString()); 74 | } 75 | }); 76 | }); 77 | 78 | app.listen(APP_PORT, function () { 79 | console.log('App is now running on http://localhost:' + APP_PORT); 80 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-apollo-starter-kit", 3 | "description": "Scaphold.io's Starter Kit React and Apollo", 4 | "repository": "scaphold-io/react-apollo-starter-kit", 5 | "version": "0.1.0", 6 | "scripts": { 7 | "start": "babel-node ./src/server.js", 8 | "start:prod": "NODE_ENV=production node ./lib/server.js", 9 | "wp": "NODE_ENV=production webpack --config webpack/webpack.config.js --progress --color -p --display-error-details --verbose", 10 | "build": "cp src/index.html lib/ && babel src --out-dir lib --sourceRoot src", 11 | "buildw": "cp src/index.html lib/ && babel src --out-dir lib -w --sourceRoot src", 12 | "deploy": "npm run build && npm run wp" 13 | }, 14 | "dependencies": { 15 | "apollo-client": "^0.9.0", 16 | "babel-polyfill": "6.7.4", 17 | "babel-preset-stage-0": "6.5.0", 18 | "babel-relay-plugin": "0.8.1", 19 | "classnames": "2.2.4", 20 | "express": "^4.13.4", 21 | "graphiql": "^0.9.3", 22 | "graphql": "^0.9.1", 23 | "graphql-tag": "^1.2.4", 24 | "isomorphic-fetch": "^2.2.1", 25 | "react": "^15.4.2", 26 | "react-apollo": "^0.12.0", 27 | "react-bootstrap": "^0.30.2", 28 | "react-dom": "^15.4.2", 29 | "react-fontawesome": "^1.1.0", 30 | "react-router": "^2.8.1", 31 | "react-router-scroll": "^0.3.2" 32 | }, 33 | "devDependencies": { 34 | "babel-cli": "6.7.7", 35 | "babel-core": "^6.23.1", 36 | "babel-eslint": "^7.1.1", 37 | "babel-loader": "^6.3.2", 38 | "babel-preset-es2015": "^6.22.0", 39 | "babel-preset-react": "^6.5.0", 40 | "copy-webpack-plugin": "^4.0.1", 41 | "eslint": "^3.16.1", 42 | "eslint-config-airbnb": "^14.1.0", 43 | "eslint-plugin-flowtype": "^2.30.0", 44 | "eslint-plugin-import": "^2.2.0", 45 | "eslint-plugin-jsx-a11y": "^4.0.0", 46 | "eslint-plugin-react": "^6.10.0", 47 | "extract-text-webpack-plugin": "^1.0.1", 48 | "html-webpack-plugin": "^2.28.0", 49 | "static-site-generator-webpack-plugin": "^2.1.0", 50 | "webpack": "^2.2.1", 51 | "webpack-dev-server": "^2.4.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/apollo.js: -------------------------------------------------------------------------------- 1 | import ApolloClient, { createNetworkInterface } from 'apollo-client'; 2 | import config from './config'; 3 | 4 | const networkInterface = createNetworkInterface({ 5 | uri: config.scapholdUrl, 6 | }); 7 | networkInterface.use([{ 8 | applyMiddleware(req, next) { 9 | if (!req.options.headers) { 10 | req.options.headers = {}; // Create the header object if needed. 11 | } 12 | if (localStorage.getItem('token')) { 13 | req.options.headers.Authorization = `Bearer ${localStorage.getItem('token')}`; 14 | } 15 | next(); 16 | }, 17 | }]); 18 | 19 | const client = new ApolloClient({ 20 | networkInterface, 21 | }); 22 | 23 | export default client; 24 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Modify the config Scaphold URL to point to your specific app. 3 | * Find the URL at the top of the page on Scaphold.io once you've created an app. 4 | * Yup. It's that easy. 5 | */ 6 | 7 | const config = { 8 | scapholdUrl: 'https://us-west-2.api.scaphold.io/graphql/react-apollo-starter-kit', 9 | }; 10 | 11 | module.exports = config; -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | React-Apollo Starter Kit for Scaphold.io 10 | 11 | 16 | 17 | 18 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/js/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { applyRouterMiddleware, Router, Route, routes, browserHistory } from 'react-router'; 4 | import { ApolloProvider } from 'react-apollo'; 5 | import App from './components/App/App'; 6 | import Home from './components/Home/Home'; 7 | import GraphiQLModule from './components/GraphiQL/GraphiQL'; 8 | import client from '../apollo'; 9 | 10 | ReactDOM.render( 11 | 12 | 19 | 20 | 21 | 22 | 23 | , 24 | document.getElementById('root'), // eslint-disable-line 25 | ); 26 | -------------------------------------------------------------------------------- /src/js/components/App/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import gql from 'graphql-tag'; 3 | import { browserHistory } from 'react-router'; 4 | import client from '../../../apollo'; 5 | import Header from './Header'; 6 | import Hero from './Hero'; 7 | import Description from './Description'; 8 | import Footer from './Footer'; 9 | 10 | const userQuery = gql` 11 | query GetUser($id: ID!) { 12 | getUser(id: $id) { 13 | id 14 | username 15 | } 16 | } 17 | `; 18 | 19 | class App extends React.Component { 20 | constructor(props) { 21 | super(props); 22 | this.state = { 23 | loading: true, 24 | }; 25 | } 26 | 27 | componentDidMount() { 28 | const token = localStorage.getItem('token'); 29 | const user = JSON.parse(localStorage.getItem('user')); 30 | const userId = user ? user.id : null; 31 | if (token && userId) { 32 | // If we are logged in subscribe to the user and render the app. 33 | this.subscribeToUser(userId); 34 | } else { 35 | // We are not logged in so stop loading and render the landing page. 36 | this.setState({ // eslint-disable-line 37 | loading: false, 38 | }); 39 | } 40 | } 41 | 42 | subscribeToUser(id) { 43 | const that = this; 44 | const observable = client.watchQuery({ 45 | query: userQuery, 46 | pollInterval: 60000, 47 | forceFetch: true, 48 | variables: { 49 | id, 50 | }, 51 | }); 52 | const subscription = observable.subscribe({ 53 | next(result) { 54 | if (result && result.errors) { 55 | const unauthed = result.errors.reduce((acc, err) => ( 56 | acc || err.status === 401 57 | ), false); 58 | if (unauthed) { 59 | localStorage.clear(); 60 | that.setState({ 61 | user: result.data.getUser, 62 | loading: false, 63 | }); 64 | } 65 | } else { 66 | localStorage.setItem('currentUsername', result.data.getUser.username); 67 | that.setState({ 68 | user: result.data.getUser, 69 | loading: false, 70 | }); 71 | browserHistory.push('/home'); 72 | } 73 | }, 74 | error(error) { 75 | console.log(`Error subscribing to user: ${error.toString()}`); 76 | that.setState({ 77 | loading: false, 78 | }); 79 | }, // Network error, etc. 80 | complete() { 81 | // console.log(`Subscription complete`); 82 | }, 83 | }); 84 | this.setState({ 85 | userSubscription: subscription, 86 | }); 87 | } 88 | 89 | render() { 90 | return ( 91 |
92 |
93 | 94 | 95 |
97 | ); 98 | } 99 | } 100 | 101 | App.propTypes = {}; 102 | 103 | export default App; 104 | -------------------------------------------------------------------------------- /src/js/components/App/Description.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Row, Col } from 'react-bootstrap'; 3 | 4 | const styles = { 5 | marketing: { 6 | margin: '40px 0', 7 | p: { 8 | marginTop: 28, 9 | }, 10 | h4: { 11 | marginTop: 28, 12 | }, 13 | }, 14 | }; 15 | 16 | class Description extends React.Component { // eslint-disable-line 17 | render() { 18 | return ( 19 | 20 | 21 |

React.js Boilerplate

22 |

23 | This React.js boilerplate helps developers create modern, performant, 24 | and clean web apps with the help of Scaphold.io. 25 |

26 | 27 |

React-Apollo

28 |

29 | Leverage the simplicity and power of Apollo Client and GraphQL to manage 30 | your application's data store. 31 |

32 | 33 | 34 | 35 |

React-Bootstrap

36 |

37 | Smoothe and creative components to fit the way you want your apps to be experienced. 38 |

39 | 40 |

Webpack

41 |

42 | Webpack is a module bundler that helps you serve your application in any environment 43 | with hot reloading. 44 |

45 | 46 |
47 | ); 48 | } 49 | } 50 | 51 | export default Description; 52 | -------------------------------------------------------------------------------- /src/js/components/App/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import FontAwesome from 'react-fontawesome'; 3 | 4 | const styles = { 5 | footer: { 6 | textAlign: 'center', 7 | paddingTop: 20, 8 | color: '#777', 9 | borderTop: '1px, solid, #e5e5e5', 10 | }, 11 | }; 12 | 13 | class Footer extends React.Component { // eslint-disable-line 14 | render() { 15 | return ( 16 |

Made with from the Scaphold Team

17 | ); 18 | } 19 | } 20 | 21 | export default Footer; 22 | -------------------------------------------------------------------------------- /src/js/components/App/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link, browserHistory } from 'react-router'; 3 | import { Navbar, Nav, NavItem } from 'react-bootstrap'; 4 | import Login from './Login'; 5 | import Register from './Register'; 6 | 7 | class Header extends React.Component { 8 | constructor(props) { 9 | super(props); 10 | this.state = { 11 | showModal: false, 12 | }; 13 | } 14 | 15 | goToGraphiQL() { 16 | browserHistory.push('/graphiql'); 17 | } 18 | 19 | goHome() { 20 | browserHistory.push('/'); 21 | } 22 | 23 | render() { 24 | return ( 25 | 26 | 27 | 28 | Scaphold 29 | 30 | 31 | 37 | 38 | ); 39 | } 40 | } 41 | 42 | export default Header; 43 | 44 | const styles = { 45 | navbar: { 46 | marginBottom: 0, 47 | }, 48 | }; 49 | -------------------------------------------------------------------------------- /src/js/components/App/Hero.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Row, Col, Button, Jumbotron} from 'react-bootstrap'; 3 | import FontAwesome from 'react-fontawesome'; 4 | 5 | class Hero extends React.Component { 6 | render() { 7 | return ( 8 | 9 | 10 | 11 |

Welcome!

12 |
13 |

14 | Here you'll find Scaphold.io's Boilerplate React-Apollo template 15 |   16 |

17 |
18 |

19 | 20 | 21 |

22 |
23 | 24 |
25 | ); 26 | } 27 | } 28 | 29 | export default Hero; 30 | 31 | const styles = { 32 | jumbotron: { 33 | marginTop: 20, 34 | borderRadius: 10, 35 | textAlign: 'center' 36 | }, 37 | scaphold: { 38 | color: '#1DAAA0' 39 | }, 40 | slack: { 41 | color: 'white', 42 | backgroundColor: '#1DAAA0' 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /src/js/components/App/Login.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { graphql } from 'react-apollo'; 3 | import gql from 'graphql-tag'; 4 | import { browserHistory } from 'react-router'; 5 | import { Button, Modal, OverlayTrigger, NavItem, Form, FormControl, FormGroup, Row, Col, ControlLabel, Alert } from 'react-bootstrap'; 6 | import config from './../../../config'; 7 | 8 | const LoginUserMutation = gql ` 9 | mutation LoginUserMutation($data: LoginUserInput!) { 10 | loginUser(input: $data) { 11 | token 12 | user { 13 | id 14 | username 15 | } 16 | } 17 | } 18 | `; 19 | 20 | class Login extends React.Component { 21 | 22 | constructor(props) { 23 | super(props); 24 | this.state = { 25 | showModal: false, 26 | loginEmail: '', 27 | loginPassword: '', 28 | errors: [] 29 | }; 30 | this.close = this.close.bind(this); 31 | this.open = this.open.bind(this); 32 | this._handleLoginEmailChange = this._handleLoginEmailChange.bind(this); 33 | this._handleLoginPasswordChange = this._handleLoginPasswordChange.bind(this); 34 | this.validateInput = this.validateInput.bind(this); 35 | this.loginUser = this.loginUser.bind(this); 36 | } 37 | 38 | close() { 39 | this.setState({ showModal: false }); 40 | } 41 | 42 | open() { 43 | this.setState({ showModal: true }); 44 | } 45 | 46 | _handleLoginEmailChange(e) { 47 | this.setState({ 48 | loginEmail: e.target.value 49 | }); 50 | } 51 | 52 | _handleLoginPasswordChange(e) { 53 | this.setState({ 54 | loginPassword: e.target.value 55 | }); 56 | } 57 | 58 | validateInput() { 59 | return ( 60 | this.state.loginEmail && this.state.loginEmail.length && 61 | this.state.loginPassword && this.state.loginPassword.length 62 | ); 63 | } 64 | 65 | loginUser() { 66 | if (this.validateInput()) { 67 | this.props.login({ 68 | username: this.state.loginEmail, 69 | password: this.state.loginPassword 70 | }).then(({ data }) => { 71 | if (!data.errors) { 72 | localStorage.setItem('token', data.loginUser.token); 73 | localStorage.setItem('user', JSON.stringify(data.loginUser.user)); 74 | this.setState({ errors: [] }); 75 | browserHistory.push('/home'); 76 | } else { 77 | this.setState({ errors: data.errors }); 78 | } 79 | }).catch(errors => { 80 | this.setState({ errors: errors.graphQLErrors }); 81 | }); 82 | } else { 83 | this.setState({ 84 | errors: [{ 85 | message: 'Username or password was not filled out. Please fill out the required fields.' 86 | }] 87 | }); 88 | } 89 | } 90 | 91 | render() { 92 | return ( 93 | 94 | Login 95 | 96 | 97 | 98 | Login Here! 99 | 100 | 101 |
102 | {this.state.errors.map((err, i) => {err.message})} 103 |
104 |
105 | 106 | 107 | Email 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | Password 117 | 118 | 119 | 120 | 121 | 122 |
123 |
124 | 125 | 126 | 127 | 128 |
129 |
130 | ); 131 | } 132 | } 133 | 134 | const styles = { 135 | errors: { 136 | textAlign: 'left', 137 | color: 'red' 138 | } 139 | }; 140 | 141 | const LoginWithData = graphql(LoginUserMutation, { 142 | props: ({ mutate }) => ({ 143 | login: (data) => mutate({ 144 | variables: { 145 | data, 146 | }, 147 | }), 148 | }), 149 | })(Login); 150 | export default LoginWithData; 151 | -------------------------------------------------------------------------------- /src/js/components/App/Register.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { graphql } from 'react-apollo'; 3 | import gql from 'graphql-tag'; 4 | import { browserHistory } from 'react-router'; 5 | import { Button, Modal, NavItem, Form, FormControl, FormGroup, Row, Col, ControlLabel, Alert } from 'react-bootstrap'; 6 | 7 | const CreateUserMutation = gql ` 8 | mutation CreateUserMutation($data: CreateUserInput!) { 9 | createUser(input: $data) { 10 | token 11 | changedUser { 12 | id 13 | username 14 | } 15 | } 16 | } 17 | `; 18 | 19 | class Register extends React.Component { 20 | 21 | constructor(props) { 22 | super(props); 23 | 24 | this.state = { 25 | showModal: false, 26 | registerEmail: '', 27 | registerPassword: '', 28 | errors: [] 29 | }; 30 | 31 | this.close = this.close.bind(this); 32 | this.open = this.open.bind(this); 33 | this._handleRegisterEmailChange = this._handleRegisterEmailChange.bind(this); 34 | this._handleRegisterPasswordChange = this._handleRegisterPasswordChange.bind(this); 35 | this.validateInput = this.validateInput.bind(this); 36 | this.registerUser = this.registerUser.bind(this); 37 | } 38 | 39 | close() { 40 | this.setState({ showModal: false }); 41 | } 42 | 43 | open() { 44 | this.setState({ showModal: true }); 45 | } 46 | 47 | validateInput() { 48 | return ( 49 | this.state.registerEmail && this.state.registerEmail.length && 50 | this.state.registerPassword && this.state.registerPassword.length 51 | ); 52 | } 53 | 54 | registerUser() { 55 | if (this.validateInput()) { 56 | this.props.register({ 57 | username: this.state.registerEmail, 58 | password: this.state.registerPassword, 59 | }).then(({ data }) => { 60 | if (!data.errors) { 61 | localStorage.setItem('token', data.createUser.token); 62 | localStorage.setItem('user', JSON.stringify(data.createUser.changedUser)); 63 | this.setState({ errors: [] }); 64 | browserHistory.push('/home'); 65 | } else { 66 | this.setState({ errors: data.errors }); 67 | } 68 | }).catch((errors) => { 69 | this.setState({ errors: errors.graphQLErrors }); 70 | }); 71 | } else { 72 | this.setState({ 73 | errors: [{ 74 | message: 'Username or password was not filled out. Please fill out the required fields.' 75 | }] 76 | }); 77 | } 78 | } 79 | 80 | _handleRegisterEmailChange(e) { 81 | this.setState({ 82 | registerEmail: e.target.value 83 | }); 84 | } 85 | 86 | _handleRegisterPasswordChange(e) { 87 | this.setState({ 88 | registerPassword: e.target.value 89 | }); 90 | } 91 | 92 | render() { 93 | return ( 94 | 95 | Register 96 | 97 | 98 | 99 | Register Here! 100 | 101 | 102 |
103 | {this.state.errors.map((err, i) => {err.message})} 104 |
105 |
106 | 107 | 108 | 109 | Email 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | Password 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 |
127 | 128 | 129 | 130 | 131 |
132 |
133 | ); 134 | } 135 | } 136 | 137 | const styles = { 138 | errors: { 139 | textAlign: 'left', 140 | color: 'red' 141 | } 142 | }; 143 | 144 | const RegisterWithData = graphql(CreateUserMutation, { 145 | props: ({ mutate }) => ({ 146 | register: (data) => mutate({ 147 | variables: { 148 | data, 149 | }, 150 | }), 151 | }), 152 | })(Register); 153 | export default RegisterWithData; 154 | -------------------------------------------------------------------------------- /src/js/components/GraphiQL/GraphiQL.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import GraphiQL from 'graphiql'; 3 | import fetch from 'isomorphic-fetch'; 4 | import config from './../../../config'; 5 | import Header from './../App/Header'; 6 | import LoggedInHeader from './../Home/Header'; 7 | 8 | function graphQLFetcher(graphQLParams) { 9 | return fetch(config.scapholdUrl, { 10 | method: 'post', 11 | headers: { 12 | 'Content-Type': 'application/json', 13 | Authorization: localStorage.token ? `Bearer ${localStorage.token}` : '', 14 | }, 15 | body: JSON.stringify(graphQLParams), 16 | }).then(response => response.json()); 17 | } 18 | 19 | class GraphiQLModule extends React.Component { 20 | render() { 21 | let header; 22 | if (!localStorage.token) { 23 | header =
; 24 | } 25 | else { 26 | header = ; 27 | } 28 | 29 | return ( 30 | 31 | {header} 32 | 33 | 34 | ) 35 | } 36 | } 37 | 38 | export default GraphiQLModule; 39 | -------------------------------------------------------------------------------- /src/js/components/Home/Body.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Row, Col, Button} from 'react-bootstrap'; 3 | import Description from '../App/Description'; 4 | import FontAwesome from 'react-fontawesome'; 5 | 6 | class Body extends React.Component { 7 | render() { 8 | const user = JSON.parse(localStorage.getItem('user')); 9 | const loggedInUser = user ? user.username : ''; 10 | 11 | return ( 12 |
13 | 14 | Welcome, you've successfully logged in to Scaphold's React Apollo Starter Kit! 15 | 16 | 17 | 18 | { 19 | loggedInUser ? ( 20 |
21 | Username: {loggedInUser} 22 |
23 | ) : '' 24 | } 25 |
26 | Feel free to poke around and check out the other functionality that this starter kit provides. 27 | We've put together a couple tools for you to get this starter kit rolling. 28 |
29 |
30 | So by all means, modify the code, break it, and learn about the same awesome technology that Facebook is built on. 31 |
32 |
33 | 34 | 35 |
36 | 37 |
38 | 39 |
40 | ); 41 | } 42 | } 43 | 44 | const styles = { 45 | heading: { 46 | padding: '100px 0 50px 0', 47 | fontSize: '25px', 48 | textAlign: 'center' 49 | }, 50 | subheading: { 51 | padding: '0 0 50px 0', 52 | fontSize: '18px', 53 | textAlign: 'center', 54 | section: { 55 | padding: '25px' 56 | } 57 | }, 58 | scaphold: { 59 | color: '#1DAAA0' 60 | }, 61 | slack: { 62 | color: 'white', 63 | backgroundColor: '#1DAAA0' 64 | } 65 | }; 66 | 67 | export default Body; 68 | -------------------------------------------------------------------------------- /src/js/components/Home/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { graphql } from 'react-apollo'; 3 | import gql from 'graphql-tag'; 4 | import { Link, browserHistory } from 'react-router'; 5 | import { Navbar, Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; 6 | import Logout from './Logout'; 7 | 8 | class Header extends React.Component { 9 | constructor(props) { 10 | super(props); 11 | 12 | this.goToGraphiQL = this.goToGraphiQL.bind(this); 13 | this.goHome = this.goHome.bind(this); 14 | } 15 | 16 | goToGraphiQL() { 17 | browserHistory.push('/graphiql'); 18 | } 19 | 20 | goHome() { 21 | browserHistory.push('/home'); 22 | } 23 | 24 | render() { 25 | const user = JSON.parse(localStorage.getItem('user')); 26 | const loggedInUser = user ? user.username : ''; 27 | 28 | return ( 29 | 30 | 31 | 32 | Scaphold 33 | 34 | 35 | 41 | 42 | ); 43 | } 44 | } 45 | 46 | const styles = { 47 | navbar: { 48 | marginBottom: 0 49 | } 50 | }; 51 | 52 | export default Header; 53 | 54 | -------------------------------------------------------------------------------- /src/js/components/Home/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Button} from 'react-bootstrap'; 3 | import {browserHistory} from 'react-router'; 4 | import Header from './Header'; 5 | import Body from './Body'; 6 | 7 | class Home extends React.Component { 8 | render() { 9 | if (!localStorage.token) { 10 | browserHistory.push('/'); 11 | } 12 | 13 | return ( 14 |
15 |
16 | 17 |
18 | ); 19 | } 20 | } 21 | 22 | export default Home; 23 | -------------------------------------------------------------------------------- /src/js/components/Home/Logout.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { browserHistory } from 'react-router'; 3 | import { NavItem } from 'react-bootstrap'; 4 | 5 | class Logout extends React.Component { 6 | 7 | constructor(props) { 8 | super(props); 9 | this.logoutUser = this.logoutUser.bind(this); 10 | } 11 | 12 | logoutUser() { 13 | localStorage.clear(); 14 | browserHistory.push('/'); 15 | } 16 | 17 | render() { 18 | return ( 19 | Logout 20 | ); 21 | } 22 | } 23 | 24 | export default Logout; 25 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const webpack = require('webpack'); // eslint-disable-line 4 | const WebpackDevServer = require('webpack-dev-server'); // eslint-disable-line 5 | const config = require('./config'); 6 | 7 | const APP_PORT = 3001; 8 | 9 | // Production version 10 | let compiler = webpack({ 11 | entry: path.join(process.cwd(), 'lib', 'js', 'app.js'), 12 | module: { 13 | loaders: [ 14 | { 15 | exclude: /node_modules/, 16 | // loader: 'babel-loader', 17 | test: /\.js$/, 18 | }, 19 | ], 20 | }, 21 | output: { 22 | path: path.join(process.cwd(), 'lib'), // sets our output directory to lib/ 23 | filename: 'app.js', // sets our output filename to server.js 24 | publicPath: '/js/', 25 | }, 26 | }); 27 | 28 | let app; 29 | if (process.env.NODE_ENV !== 'production') { 30 | compiler = webpack({ 31 | entry: path.join(process.cwd(), 'src', 'js', 'app.js'), 32 | module: { 33 | loaders: [ 34 | { 35 | exclude: /node_modules/, 36 | loader: 'babel-loader', 37 | test: /\.js$/, 38 | }, 39 | ], 40 | }, 41 | output: { 42 | path: path.join(process.cwd(), 'src'), // sets our output directory to lib/ 43 | filename: 'app.js', // sets our output filename to server.js 44 | publicPath: '/', 45 | }, 46 | }); 47 | 48 | app = new WebpackDevServer(compiler, { 49 | hot: true, 50 | contentBase: 'src/', 51 | publicPath: '/', 52 | proxy: { '/graphql': config.scapholdUrl }, 53 | stats: { 54 | colors: true, 55 | }, 56 | }); 57 | } else { 58 | app = new WebpackDevServer(compiler, { 59 | hot: false, 60 | contentBase: 'src/', 61 | publicPath: '/', 62 | proxy: { '/graphql': config.scapholdUrl }, 63 | stats: { 64 | colors: false, 65 | }, 66 | }); 67 | } 68 | 69 | // Serve static resources 70 | app.use('*', (req, res) => { 71 | fs.readFile(path.join(compiler.outputPath, 'index.html'), (err, file) => { 72 | if (err) { 73 | res.sendStatus(404); 74 | } else { 75 | res.send(file.toString()); 76 | } 77 | }); 78 | }); 79 | 80 | app.listen(APP_PORT, () => { 81 | console.log(`App is now running on http://localhost:${APP_PORT}`); 82 | }); 83 | -------------------------------------------------------------------------------- /webpack/webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * COMMON WEBPACK CONFIGURATION 3 | */ 4 | 5 | const path = require('path'); 6 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 7 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 8 | // console.log('dir'); 9 | // console.log(path.resolve(process.cwd(), 'app/assets/styles')); 10 | 11 | module.exports = () => ({ 12 | entry: path.join(process.cwd(), 'lib', 'js', 'app.js'), 13 | plugins: [ 14 | new HtmlWebpackPlugin({ 15 | template: 'src/index.html', 16 | minify: { 17 | removeComments: true, 18 | collapseWhitespace: true, 19 | removeRedundantAttributes: true, 20 | useShortDoctype: true, 21 | removeEmptyAttributes: true, 22 | removeStyleLinkTypeAttributes: true, 23 | keepClosingSlash: true, 24 | minifyJS: true, 25 | minifyCSS: true, 26 | minifyURLs: true, 27 | }, 28 | inject: true, 29 | }), 30 | new CopyWebpackPlugin([ 31 | // { from: 'src/images', to: 'assets/images' }, 32 | ], { 33 | ignore: [], 34 | 35 | // By default, we only copy modified files during 36 | // a watch or webpack-dev-server build. Setting this 37 | // to `true` copies all files. 38 | copyUnmodified: true, 39 | }), 40 | ], 41 | module: { 42 | loaders: [ 43 | { 44 | exclude: /node_modules/, 45 | // loader: 'babel-loader', 46 | test: /\.js$/, 47 | }, 48 | ], 49 | }, 50 | output: { 51 | path: path.join(process.cwd(), 'build'), // sets our output directory to build/ 52 | filename: 'app.js', // sets our output filename to server.js 53 | publicPath: '/', 54 | }, 55 | }); 56 | --------------------------------------------------------------------------------