├── .gitignore ├── app ├── .meteor │ ├── .gitignore │ ├── release │ ├── platforms │ ├── .finished-upgraders │ ├── .id │ ├── packages │ └── versions ├── lib │ └── _namespace.jsx ├── scss.json ├── client │ ├── stylesheets │ │ └── main.scss │ ├── components │ │ ├── layouts │ │ │ └── main │ │ │ │ ├── MainLayout.jsx │ │ │ │ ├── MainFooter.jsx │ │ │ │ └── MainHeader.jsx │ │ ├── public │ │ │ └── Home.jsx │ │ ├── users │ │ │ ├── AuthErrors.jsx │ │ │ └── UserLogin.jsx │ │ └── general │ │ │ └── FormInput.jsx │ ├── head.html │ └── routes.jsx ├── server │ └── bootstrap.jsx └── tests │ └── jasmine │ └── client │ └── unit │ ├── spec_helpers.js │ └── UserLogin_spec.js ├── environments ├── build │ └── settings.json ├── local │ └── settings.json └── production │ └── settings.json ├── run.sh └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea/ -------------------------------------------------------------------------------- /app/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /app/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.1.0.3 2 | -------------------------------------------------------------------------------- /app/.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /app/lib/_namespace.jsx: -------------------------------------------------------------------------------- 1 | // This is the namespace for all components. 2 | C = {}; -------------------------------------------------------------------------------- /environments/build/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": {}, 3 | "private": {} 4 | } -------------------------------------------------------------------------------- /environments/local/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": {}, 3 | "private": {} 4 | } -------------------------------------------------------------------------------- /environments/production/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": {}, 3 | "private": {} 4 | } -------------------------------------------------------------------------------- /app/scss.json: -------------------------------------------------------------------------------- 1 | { 2 | "enableAutoprefixer": true, 3 | "autoprefixerOptions": { 4 | "browsers": ["> 5%"], 5 | "cascade": false 6 | } 7 | } -------------------------------------------------------------------------------- /app/client/stylesheets/main.scss: -------------------------------------------------------------------------------- 1 | @import '.meteor/local/build/programs/server/assets/packages/reywood_bootstrap3-sass/bootstrap'; 2 | 3 | // NAVBAR 4 | .navbar { 5 | margin-bottom: 0px; 6 | } -------------------------------------------------------------------------------- /app/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | -------------------------------------------------------------------------------- /app/client/components/layouts/main/MainLayout.jsx: -------------------------------------------------------------------------------- 1 | C.MainLayout = React.createClass({ 2 | render() { 3 | return ( 4 |
5 | {this.props.header} 6 | 7 | {this.props.content} 8 | 9 | {this.props.footer} 10 |
11 | ) 12 | } 13 | }); -------------------------------------------------------------------------------- /app/server/bootstrap.jsx: -------------------------------------------------------------------------------- 1 | if(Meteor.isServer) { 2 | 3 | Meteor.startup(() => { 4 | 5 | if (Meteor.users.find().count() === 0) { 6 | Accounts.createUser({ 7 | email: "ryancswapp@gmail.com", 8 | password: "foodbars" 9 | }); 10 | } 11 | 12 | }); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | 1fhfeq51kibzrp1keyvk7 8 | -------------------------------------------------------------------------------- /app/client/components/layouts/main/MainFooter.jsx: -------------------------------------------------------------------------------- 1 | C.MainFooter = React.createClass({ 2 | render() { 3 | return ( 4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 |
12 | ) 13 | } 14 | }); -------------------------------------------------------------------------------- /app/tests/jasmine/client/unit/spec_helpers.js: -------------------------------------------------------------------------------- 1 | TestUtils = React.addons.TestUtils; 2 | Simulate = TestUtils.Simulate; 3 | 4 | 5 | renderComponent = function (comp, props) { 6 | return TestUtils.renderIntoDocument( 7 | React.createElement(comp, props) 8 | ); 9 | }; 10 | 11 | simulateClickOn = function($el) { 12 | React.addons.TestUtils.Simulate.click($el[0]); 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #export VELOCITY_DEBUG=0 4 | 5 | # these are about to get canned 6 | #export JASMINE_CLIENT_UNIT=0 7 | #export JASMINE_SERVER_UNIT=0 8 | # 9 | #export JASMINE_CLIENT_INTEGRATION=1 10 | #export JASMINE_SERVER_INTEGRATION=1 11 | #export CUCUMBER=1 12 | # 13 | #if [ "$1" = "--test" ]; then 14 | # export CUCUMBER_TAIL=1; 15 | #fi 16 | 17 | cd app 18 | meteor $1 --settings ../environments/local/settings.json -------------------------------------------------------------------------------- /app/client/components/public/Home.jsx: -------------------------------------------------------------------------------- 1 | C.Home = React.createClass({ 2 | render() { 3 | return ( 4 |
5 |
6 |

React Meteor Template

7 |

A starting point for React apps built on Meteor

8 |
9 |
10 | ) 11 | } 12 | }); -------------------------------------------------------------------------------- /app/client/head.html: -------------------------------------------------------------------------------- 1 | 2 | React Meteor Template 3 | 4 | 5 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /app/client/routes.jsx: -------------------------------------------------------------------------------- 1 | FlowRouter.route("/", { 2 | name: 'Home', 3 | subscriptions(params) { 4 | 5 | }, 6 | action(params) { 7 | renderMainLayoutWith(); 8 | } 9 | }); 10 | 11 | FlowRouter.route("/login", { 12 | name: "Login", 13 | subscriptions(params) { 14 | 15 | }, 16 | action(params) { 17 | renderMainLayoutWith(); 18 | } 19 | }); 20 | 21 | function renderMainLayoutWith(component) { 22 | ReactLayout.render(C.MainLayout, { 23 | header: , 24 | content: component, 25 | footer: 26 | }); 27 | } -------------------------------------------------------------------------------- /app/client/components/users/AuthErrors.jsx: -------------------------------------------------------------------------------- 1 | C.AuthErrors = React.createClass({ 2 | propTypes: { 3 | errors: React.PropTypes.object 4 | }, 5 | render() { 6 | if (this.props.errors) { 7 | return ( 8 |
    9 | { 10 | _.values(this.props.errors).map((errorMessage) => { 11 | return
  • {errorMessage}
  • ; 12 | }) 13 | } 14 |
15 | ) 16 | } 17 | } 18 | }); -------------------------------------------------------------------------------- /app/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-platform 8 | react 9 | kadira:flow-router 10 | kadira:react-layout 11 | meteorhacks:flow-layout 12 | aldeed:collection2 13 | matb33:collection-hooks 14 | dburles:collection-helpers 15 | underscore 16 | fourseven:scss 17 | reywood:bootstrap3-sass 18 | http 19 | accounts-password 20 | 21 | ## I have commented out the testing packages because I don't like them 22 | ## to run while I'm developing. The more tests you add the slower your 23 | ## app gets. 24 | 25 | # sanjo:jasmine 26 | # velocity:html-reporter 27 | -------------------------------------------------------------------------------- /app/tests/jasmine/client/unit/UserLogin_spec.js: -------------------------------------------------------------------------------- 1 | describe("UserLogin", function () { 2 | var defProps, renderWithProps, component, el, $el; 3 | 4 | beforeEach(function() { 5 | defProps = { 6 | 7 | }; 8 | renderWithProps = function(props) { 9 | component = renderComponent(C.UserLogin, props); 10 | el = React.findDOMNode(component); 11 | $el = $(el); 12 | }; 13 | }); 14 | 15 | // Text 16 | 17 | it("should have the title Login", function() { 18 | renderWithProps({}); 19 | expect($el.find('h1').text()).toBe('Login'); 20 | }); 21 | 22 | // State 23 | 24 | it("should have a default state that holds an empty error object", function() { 25 | renderWithProps({}); 26 | expect(component.state.errors).toEqual({}); 27 | }); 28 | 29 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Meteor Template 2 | 3 | This is a boilerplate template for a Meteor.js app that uses React.js as the view layer 4 | 5 | ## NOTE 6 | 7 | The first time you run this app it will fail. This is because it is using the reywood:bootstrap3-sass package. If you restart the app after it crashes it will then work from that point on. Check out the "To use" section [here](https://atmospherejs.com/reywood/bootstrap3-sass) for more info. 8 | 9 | ## Install 10 | 11 | Run the following to get the bash file to work: 12 | 13 | ``` 14 | chmod +x ./run.sh 15 | ``` 16 | 17 | Now you can start the app with the following command: 18 | 19 | ``` 20 | ./run.sh 21 | ``` 22 | 23 | ## Included Packages 24 | 25 | react 26 | 27 | meteorhacks:flow-router 28 | 29 | kadira:react-layout 30 | 31 | meteorhacks:flow-layout 32 | 33 | aldeed:collection2 34 | 35 | matb33:collection-hooks 36 | 37 | dburles:collection-helpers 38 | 39 | underscore 40 | 41 | fourseven:scss 42 | 43 | reywood:bootstrap3-sass 44 | 45 | http 46 | 47 | accounts-password 48 | 49 | sanjo:jasmine 50 | 51 | velocity:html-reporter 52 | 53 | ## Included Components 54 | 55 | MainLayout 56 | 57 | MainHeader 58 | 59 | MainFooter 60 | 61 | UserLogin 62 | 63 | FormInput 64 | 65 | AuthErrors 66 | -------------------------------------------------------------------------------- /app/.meteor/versions: -------------------------------------------------------------------------------- 1 | accounts-base@1.2.0 2 | accounts-password@1.1.1 3 | aldeed:collection2@2.3.3 4 | aldeed:simple-schema@1.3.3 5 | autoupdate@1.2.1 6 | babel-compiler@5.8.3_1 7 | babel-runtime@0.1.3 8 | base64@1.0.3 9 | binary-heap@1.0.3 10 | blaze@2.1.2 11 | blaze-tools@1.0.3 12 | boilerplate-generator@1.0.3 13 | callback-hook@1.0.3 14 | check@1.0.5 15 | coffeescript@1.0.6 16 | cosmos:browserify@0.5.0 17 | dburles:collection-helpers@1.0.3 18 | ddp@1.1.0 19 | deps@1.0.7 20 | ejson@1.0.6 21 | email@1.0.6 22 | fastclick@1.0.3 23 | fourseven:scss@3.2.0 24 | geojson-utils@1.0.3 25 | html-tools@1.0.4 26 | htmljs@1.0.4 27 | http@1.1.0 28 | id-map@1.0.3 29 | jquery@1.11.3_2 30 | json@1.0.3 31 | jsx@0.1.5 32 | kadira:react-layout@1.2.0 33 | launch-screen@1.0.2 34 | livedata@1.0.13 35 | localstorage@1.0.3 36 | logging@1.0.7 37 | matb33:collection-hooks@0.7.13 38 | meteor@1.1.6 39 | meteor-platform@1.2.2 40 | meteorhacks:flow-layout@1.4.2 41 | meteorhacks:flow-router@1.19.0 42 | minifiers@1.1.5 43 | minimongo@1.0.8 44 | mobile-status-bar@1.0.3 45 | mongo@1.1.0 46 | npm-bcrypt@0.7.8_2 47 | observe-sequence@1.0.6 48 | ordered-dict@1.0.3 49 | random@1.0.3 50 | react@0.1.4 51 | react-meteor-data@0.1.2 52 | react-runtime@0.13.3_2 53 | react-runtime-dev@0.13.3_2 54 | react-runtime-prod@0.13.3_1 55 | reactive-dict@1.1.0 56 | reactive-var@1.0.5 57 | reload@1.1.3 58 | retry@1.0.3 59 | reywood:bootstrap3-sass@3.3.5_1 60 | routepolicy@1.0.5 61 | service-configuration@1.0.4 62 | session@1.1.0 63 | sha@1.0.3 64 | spacebars@1.0.6 65 | spacebars-compiler@1.0.6 66 | srp@1.0.3 67 | templating@1.1.1 68 | tracker@1.0.7 69 | ui@1.0.6 70 | underscore@1.0.3 71 | url@1.0.4 72 | webapp@1.2.0 73 | webapp-hashing@1.0.3 74 | -------------------------------------------------------------------------------- /app/client/components/general/FormInput.jsx: -------------------------------------------------------------------------------- 1 | C.FormInput = React.createClass({ 2 | propTypes: { 3 | hasError: React.PropTypes.bool, 4 | label: React.PropTypes.string, 5 | type: React.PropTypes.string, 6 | name: React.PropTypes.string, 7 | value: React.PropTypes.string, 8 | onKeyUp: React.PropTypes.func, 9 | onBlur: React.PropTypes.func 10 | }, 11 | shouldComponentUpdate() { 12 | return true; 13 | }, 14 | render() { 15 | const {type, label, name, value, onKeyUp, onBlur } = this.props; 16 | let inputType; 17 | 18 | var className = "form-group"; 19 | if (this.props.hasError) { 20 | className += " has-error"; 21 | } 22 | 23 | switch (type) { 24 | case "textarea": 25 | inputType = ( 26 | 27 | ); 28 | break; 29 | default: 30 | inputType = ( 31 | 32 | ); 33 | break; 34 | } 35 | 36 | 37 | return ( 38 |
39 | { label === "none" ? "" : } 40 | { inputType } 41 |
42 | ) 43 | 44 | } 45 | }); -------------------------------------------------------------------------------- /app/client/components/layouts/main/MainHeader.jsx: -------------------------------------------------------------------------------- 1 | C.MainHeader = React.createClass({ 2 | mixins: [ReactMeteorData], 3 | getMeteorData() { 4 | return { 5 | currentUser: Meteor.user() 6 | } 7 | }, 8 | handleLogout() { 9 | Meteor.logout(); 10 | }, 11 | render() { 12 | let loginButton; 13 | let { currentUser } = this.data; 14 | 15 | if (currentUser) { 16 | loginButton = ( 17 |
  • Logout
  • 18 | ) 19 | } else { 20 | loginButton = ( 21 |
  • Login
  • 22 | ) 23 | } 24 | 25 | return ( 26 | 46 | ) 47 | } 48 | }); -------------------------------------------------------------------------------- /app/client/components/users/UserLogin.jsx: -------------------------------------------------------------------------------- 1 | C.UserLogin = React.createClass({ 2 | mixins: [], 3 | PropTypes: { 4 | 5 | }, 6 | getInitialState() { 7 | return { 8 | errors: {} 9 | } 10 | }, 11 | getMeteorData() { 12 | return { 13 | 14 | } 15 | }, 16 | onSubmit(event) { 17 | event.preventDefault(); 18 | 19 | var email = $(event.target).find("[name=email]").val(); 20 | var password = $(event.target).find("[name=password]").val(); 21 | 22 | var errors = {}; 23 | 24 | if (!email) { 25 | errors.email = "Email required" 26 | } 27 | 28 | if (!password) { 29 | errors.password = "Password required" 30 | } 31 | 32 | this.setState({ 33 | errors: errors 34 | }); 35 | 36 | if (! _.isEmpty(errors)) { 37 | return; 38 | } 39 | 40 | Meteor.loginWithPassword(email, password, (err) => { 41 | if (err) { 42 | this.setState({ 43 | errors: {'none': err.reason} 44 | }); 45 | 46 | return; 47 | } else { 48 | FlowRouter.go('Home'); 49 | } 50 | }); 51 | }, 52 | render() { 53 | return ( 54 |
    55 |
    56 |
    57 |

    Login

    58 | 59 |
    60 | 61 | 62 | 63 | 64 | 65 |
    66 |
    67 |
    68 | ) 69 | } 70 | }); 71 | --------------------------------------------------------------------------------