├── src ├── api │ ├── users.jsx │ └── _users.jsx ├── assets │ ├── sass │ │ ├── theme │ │ │ └── _config.scss │ │ └── _.scss │ ├── less │ │ └── _.less │ └── css │ │ ├── normalize.css │ │ └── main.css ├── components │ ├── errors │ │ ├── 404.jsx │ │ ├── 500.jsx │ │ └── index.jsx │ ├── Header.css │ ├── Footer.css │ ├── ui │ │ ├── index.jsx │ │ ├── button │ │ │ ├── Button.jsx │ │ │ └── __tests__ │ │ │ │ └── Button-test.jsx │ │ └── checkbox │ │ │ └── Checkbox.jsx │ ├── Footer.jsx │ ├── articles │ │ ├── Article.jsx │ │ └── ArticleList.jsx │ ├── Header.jsx │ ├── __tests__ │ │ └── Header-test.jsx │ └── users │ │ ├── UserItem.jsx │ │ └── UserList.jsx ├── containers │ ├── App.css │ ├── dashboard │ │ ├── Home.jsx │ │ ├── index.js │ │ ├── Dashboard.jsx │ │ ├── Sidebar.jsx │ │ ├── Users.jsx │ │ └── Articles.jsx │ ├── main │ │ ├── Home.jsx │ │ ├── index.js │ │ ├── Footer.jsx │ │ ├── Login.jsx │ │ └── Main.jsx │ └── App.jsx ├── reducers │ ├── user.d.js │ ├── article.d.js │ ├── index.jsx │ ├── user.jsx │ └── article.jsx ├── store │ ├── configureStore.jsx │ ├── configureStore.production.jsx │ └── configureStore.development.jsx ├── constants │ └── actionTypes.js ├── DevTools.jsx ├── routes.jsx ├── actions │ ├── user.jsx │ └── article.jsx └── index.js ├── .eslintignore ├── public ├── favicon.ico ├── manifest.json └── index.html ├── .flowconfig ├── .dockerignore ├── CHANGELOG.md ├── flow-typed ├── article.d.js ├── user.d.js └── base.d.js ├── .gitignore ├── config ├── jest │ ├── fileTransform.js │ └── cssTransform.js ├── docker │ └── Dockerfile ├── polyfills.js ├── paths.js ├── env.js ├── nginx │ ├── nginx.conf │ └── mime.types ├── webpackDevServer.config.js ├── webpack.config.dev.js └── webpack.config.prod.js ├── .eslintrc.json ├── scripts ├── test.js ├── start.js └── build.js ├── README.md ├── package.json └── README.react.md /src/api/users.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | -------------------------------------------------------------------------------- /src/assets/sass/theme/_config.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/errors/404.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | -------------------------------------------------------------------------------- /src/components/errors/500.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | -------------------------------------------------------------------------------- /src/components/errors/index.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | -------------------------------------------------------------------------------- /src/components/Header.css: -------------------------------------------------------------------------------- 1 | .header { 2 | border: 1px solid red; 3 | } 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | **/*.css 3 | **/*.html 4 | src/**/*-test.js 5 | -------------------------------------------------------------------------------- /src/assets/sass/_.scss: -------------------------------------------------------------------------------- 1 | $size: 1.2em; 2 | 3 | body { 4 | margin: $size; 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/react-boilerplate/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/components/Footer.css: -------------------------------------------------------------------------------- 1 | .footer { 2 | margin-top: 20px; 3 | border: 1px solid blue; 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/less/_.less: -------------------------------------------------------------------------------- 1 | @base: blue; 2 | 3 | body { 4 | color: @base; 5 | font-size: 14px; 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/App.css: -------------------------------------------------------------------------------- 1 | h1{ 2 | color: red; 3 | } 4 | 5 | .route { 6 | border: 1px solid green; 7 | margin: 10px 0; 8 | } -------------------------------------------------------------------------------- /src/components/ui/index.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | export Button from './button/Button' 3 | export Checkbox from './checkbox/Checkbox' 4 | -------------------------------------------------------------------------------- /src/reducers/user.d.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export type UserState = { 4 | users: Array, 5 | isFetching?: boolean 6 | } 7 | -------------------------------------------------------------------------------- /src/store/configureStore.jsx: -------------------------------------------------------------------------------- 1 | const store = require(`./configureStore.${process.env.NODE_ENV}`) 2 | export default store.default 3 | -------------------------------------------------------------------------------- /src/reducers/article.d.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export type ArticleState = { 4 | articles: Array
, 5 | isFetching?: boolean 6 | } 7 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/* 3 | .*/__test__/.* 4 | 5 | [include] 6 | ./src/ 7 | 8 | [libs] 9 | ./flow-typed/ 10 | 11 | [options] 12 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # system, ide 2 | .DS_Store 3 | .idea 4 | 5 | # src 6 | node_modules/ 7 | public/ 8 | scripts/ 9 | src/ 10 | .eslintignore 11 | .git* 12 | *.md 13 | -------------------------------------------------------------------------------- /src/containers/dashboard/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Home = () => ( 4 |
5 | Dashboard Main Page 6 |
7 | ) 8 | 9 | export default Home 10 | -------------------------------------------------------------------------------- /src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default class Header extends React.Component { 4 | render () { 5 | return
Footer
6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/main/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | class Home extends React.Component { 4 | render () { 5 | return
home
6 | } 7 | } 8 | 9 | export default Home 10 | -------------------------------------------------------------------------------- /src/containers/main/index.js: -------------------------------------------------------------------------------- 1 | import Home from './Home' 2 | import Main from './Main' 3 | import Login from './Login' 4 | 5 | export default { 6 | Layout: Main, 7 | Home, 8 | Login 9 | } 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # 0.1.0 (2016-10-18) 3 | 4 | 5 | ### Features 6 | 7 | * **lint:** pretty formatter and add lint run-script 7a2737e 8 | * switch sample app reducer, router, redux and etc b6e5553 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /flow-typed/article.d.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | declare type Article = { 4 | userId: number; 5 | id: number; 6 | title: string; 7 | body: string; 8 | }; 9 | 10 | declare type ArticleAction = BaseAction & { 11 | articles?: Array
; 12 | }; 13 | -------------------------------------------------------------------------------- /src/containers/dashboard/index.js: -------------------------------------------------------------------------------- 1 | import Home from './Home' 2 | import Dashboard from './Dashboard' 3 | import Articles from './Articles' 4 | import Users from './Users' 5 | 6 | export default { 7 | Layout: Dashboard, 8 | Home, 9 | Articles, 10 | Users 11 | } 12 | -------------------------------------------------------------------------------- /src/containers/main/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const Footer = ({ text }) => { 5 | return
{text}
6 | } 7 | 8 | Footer.propTypes = { 9 | text: PropTypes.string 10 | } 11 | 12 | export default Footer 13 | -------------------------------------------------------------------------------- /src/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | /* sample */ 3 | 4 | export const REQUEST_USERS: string = 'REQUEST_USERS' 5 | export const RECEIVE_USERS: string = 'RECEIVE_USERS' 6 | 7 | export const REQUEST_ARTICLES: string = 'REQUEST_ARTICLES' 8 | export const RECEIVE_ARTICLES: string = 'RECEIVE_ARTICLES' 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | coverage 8 | 9 | # production 10 | build 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | npm-debug.log 16 | v8.log 17 | 18 | # flowtype 19 | flow-typed/npm 20 | -------------------------------------------------------------------------------- /src/containers/main/Login.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Login = props => ( 4 |
5 |

Login Page

6 | 7 | 8 | 9 |
10 | ) 11 | 12 | export default Login 13 | -------------------------------------------------------------------------------- /src/containers/main/Main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Header from '../../components/Header' 4 | import Footer from './Footer' 5 | 6 | const Main = props => ( 7 |
8 |
9 | {props.children} 10 |
11 |
12 | ) 13 | 14 | export default Main 15 | -------------------------------------------------------------------------------- /flow-typed/user.d.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | declare type User = { 4 | id: number; 5 | name: string; 6 | username: string; 7 | email: string; 8 | address: Address; 9 | phone: string; 10 | website: string; 11 | company: Company; 12 | }; 13 | 14 | declare type UserAction = BaseAction & { 15 | users?: Array; 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/articles/Article.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | import React from 'react' 3 | 4 | export default class Article extends React.Component { 5 | render () { 6 | const { title, body } = this.props 7 | 8 | return ( 9 |
10 | {title} 11 |

{body}

12 |
13 | ) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DevTools.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createDevTools } from 'redux-devtools' 3 | import LogMonitor from 'redux-devtools-log-monitor' 4 | import DockMonitor from 'redux-devtools-dock-monitor' 5 | 6 | export default createDevTools( 7 | 8 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /src/containers/dashboard/Dashboard.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Header from '../../components/Header' 4 | import Sidebar from './Sidebar' 5 | 6 | const Dashboard = props => ( 7 |
8 |
9 |

Dashboard

10 | 11 | {props.children} 12 |
13 | ) 14 | 15 | export default Dashboard 16 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | // This is a custom Jest transformer turning file imports into filenames. 6 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 7 | 8 | module.exports = { 9 | process(src, filename) { 10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router' 3 | 4 | export default class Header extends React.Component { 5 | render () { 6 | return ( 7 |
8 | Home, 9 | login, 10 | dashboard 11 |
12 | ) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/reducers/index.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | import articleReducer from './article' 3 | import userReducer from './user' 4 | 5 | import type { ArticleState } from './article.d' 6 | import type { UserState } from './user.d' 7 | 8 | export type AppState = { 9 | articleReducer: ArticleState, 10 | userReducer: UserState 11 | } 12 | 13 | export default { 14 | articleReducer: articleReducer, 15 | userReducer: userReducer 16 | } 17 | -------------------------------------------------------------------------------- /flow-typed/base.d.js: -------------------------------------------------------------------------------- 1 | //@ flow 2 | 3 | declare type Geo = { 4 | lat: string; 5 | lng: string; 6 | }; 7 | 8 | declare type Address = { 9 | street: string; 10 | suite: string; 11 | city: string; 12 | zipcode: string; 13 | geo: Geo; 14 | } 15 | 16 | declare type Company = { 17 | name: string; 18 | catchPhrase: string; 19 | bs: string; 20 | } 21 | 22 | declare type BaseAction = { 23 | type: string; 24 | receivedAt?: Date; 25 | }; 26 | -------------------------------------------------------------------------------- /src/containers/dashboard/Sidebar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router' 3 | 4 | const Sidebar = ({ text }) => ( 5 |
6 |

SideBar

7 | {text} 8 |
    9 |
  • 10 | Users 11 |
  • 12 |
  • 13 | Articles 14 |
  • 15 |
16 |
17 | ) 18 | 19 | export default Sidebar 20 | -------------------------------------------------------------------------------- /src/api/_users.jsx: -------------------------------------------------------------------------------- 1 | /* sample redux action */ 2 | import axios from 'axios' 3 | import store from 'store' 4 | 5 | export const getUsers = () => { 6 | return axios 7 | .get('http://jsonplaceholder.typicode.com/users') 8 | .then(response => { 9 | store.dispatch({ 10 | type: 'GET_USERS', 11 | users: response.data 12 | }) 13 | 14 | return response 15 | }) 16 | .catch(err => { 17 | console.error(err) 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /config/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.11.5 2 | MAINTAINER maintainer@email.com 3 | 4 | WORKDIR /etc/nginx 5 | 6 | # Remove default conf 7 | RUN rm -v nginx.conf 8 | 9 | # Copy nginx.conf and mime.types 10 | COPY config/nginx /etc/nginx/ 11 | 12 | # Copy entrypoint 13 | # COPY build-tools/scripts/docker-entrypoint.sh /entrypoint.sh 14 | # RUN chmod +x /entrypoint.sh 15 | 16 | # Copy application 17 | COPY build/ /usr/share/nginx/html/ 18 | 19 | # ENTRYPOINT ["/entrypoint.sh"] 20 | 21 | EXPOSE 80 22 | 23 | CMD ["nginx", "-g", "daemon off;"] 24 | -------------------------------------------------------------------------------- /src/components/articles/ArticleList.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | import React from 'react' 3 | 4 | import Article from './Article' 5 | 6 | export default class ArticleList extends React.Component { 7 | render () { 8 | const { articles } = this.props 9 | 10 | return ( 11 |
12 |

Articles

13 |
    14 | {articles.map(article => { 15 | return
    16 | })} 17 |
18 |
19 | ) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/__tests__/Header-test.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // ref, https://github.com/facebook/jest/tree/master/examples/react 3 | // jest.unmock('../App.jsx'); 4 | 5 | import React from 'react' 6 | import { shallow } from 'enzyme' 7 | import expect from 'expect' 8 | import { Link } from 'react-router' 9 | 10 | import Header from '../Header.jsx' 11 | 12 | describe('
', () => { 13 | it('rendered component has Link', () => { 14 | const wrapper = shallow(
) 15 | expect(wrapper.find(Link)).toExist() 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /src/components/users/UserItem.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | /* sample */ 3 | import React from 'react' 4 | 5 | export default class UserItem extends React.Component { 6 | props: { 7 | id: number, 8 | name: string, 9 | username: string, 10 | email: string, 11 | address: Address, 12 | phone: string, 13 | website: string, 14 | company: Company, 15 | onClick?: (event: Event) => void 16 | } 17 | 18 | render () { 19 | const { name, email } = this.props 20 | 21 | return
  • {name}: {email}
  • 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "node": true, 5 | "es6": true 6 | }, 7 | "ecmaFeatures": { 8 | "modules": true, 9 | "destructuring": true 10 | }, 11 | "globals": { 12 | }, 13 | "plugins": [ 14 | "flowtype", 15 | "react" 16 | ], 17 | "extends": [ 18 | "standard", 19 | "standard-flow", 20 | "react-app" 21 | ], 22 | "settings": { 23 | "flowtype": { 24 | "onlyFilesWithFlowAnnotation": false 25 | } 26 | }, 27 | "rules": { 28 | "object-property-newline": "off" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/users/UserList.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | /* sample */ 3 | import React from 'react' 4 | 5 | import UserItem from './UserItem' 6 | 7 | export default class UserList extends React.Component { 8 | props: { 9 | users: Array 10 | } 11 | 12 | render () { 13 | const { users } = this.props 14 | 15 | return ( 16 |
    17 |

    Users

    18 |
      19 | {users.map((user: User) => { 20 | return 21 | })} 22 |
    23 |
    24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/containers/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import './App.css' 4 | 5 | export default class App extends React.Component { 6 | constructor (props) { 7 | super(props) 8 | 9 | this.state = { 10 | totalUserCount: 0 11 | } 12 | } 13 | 14 | render () { 15 | return ( 16 |
    17 | {this.props.children} 18 | {(() => { 19 | if (process.env.NODE_ENV === 'development') { 20 | const DevTools = require('../DevTools').default 21 | return 22 | } 23 | })()} 24 |
    25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /config/polyfills.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (typeof Promise === 'undefined') { 4 | // Rejection tracking prevents a common issue where React gets into an 5 | // inconsistent state due to an error, but it gets swallowed by a Promise, 6 | // and the user has no idea what causes React's erratic future behavior. 7 | require('promise/lib/rejection-tracking').enable(); 8 | window.Promise = require('promise/lib/es6-extensions.js'); 9 | } 10 | 11 | // fetch() polyfill for making API calls. 12 | require('whatwg-fetch'); 13 | 14 | // Object.assign() is commonly used with React. 15 | // It will use the native implementation if it's present and isn't buggy. 16 | Object.assign = require('object-assign'); 17 | -------------------------------------------------------------------------------- /src/store/configureStore.production.jsx: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, combineReducers } from 'redux' 2 | import thunk from 'redux-thunk' 3 | import { hashHistory } from 'react-router' 4 | import { routerMiddleware, routerReducer as routing } from 'react-router-redux' 5 | // import reducers from 'reducers'; 6 | 7 | import reducers from '../reducers' 8 | 9 | const router = routerMiddleware(hashHistory) 10 | 11 | const rootReducer = combineReducers({ 12 | ...reducers, 13 | routing: routing 14 | }) 15 | 16 | const enhancer = applyMiddleware(thunk, router) 17 | 18 | const configureStore = initialState => { 19 | return createStore(rootReducer, initialState, enhancer) 20 | } 21 | 22 | export default configureStore 23 | -------------------------------------------------------------------------------- /src/routes.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Route, IndexRoute } from 'react-router' 3 | 4 | import App from './containers/App' 5 | import Dashboard from './containers/dashboard' 6 | import Main from './containers/main' 7 | 8 | export default ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ) 21 | -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | process.env.NODE_ENV = 'test'; 4 | process.env.PUBLIC_URL = ''; 5 | 6 | // Makes the script crash on unhandled rejections instead of silently 7 | // ignoring them. In the future, promise rejections that are not handled will 8 | // terminate the Node.js process with a non-zero exit code. 9 | process.on('unhandledRejection', err => { 10 | throw err; 11 | }); 12 | 13 | // Ensure environment variables are read. 14 | require('../config/env'); 15 | 16 | const jest = require('jest'); 17 | const argv = process.argv.slice(2); 18 | 19 | // Watch unless on CI or in coverage mode 20 | if (!process.env.CI && argv.indexOf('--coverage') < 0) { 21 | argv.push('--watch'); 22 | } 23 | 24 | 25 | jest.run(argv); 26 | -------------------------------------------------------------------------------- /src/reducers/user.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | /* sample */ 3 | import * as actionTypes from '../constants/actionTypes' 4 | import type { UserState } from './user.d' 5 | 6 | const initial = { 7 | isFetching: false, 8 | users: [] 9 | } 10 | 11 | export default (state: UserState = initial, action: Object): UserState => { 12 | switch (action.type) { 13 | case actionTypes.REQUEST_USERS: 14 | state = Object.assign({}, state, { 15 | isFetching: true 16 | }) 17 | break 18 | case actionTypes.RECEIVE_USERS: 19 | state = Object.assign({}, state, { 20 | isFetching: false, 21 | users: action.users 22 | }) 23 | break 24 | default: 25 | break 26 | } 27 | 28 | return state 29 | } 30 | -------------------------------------------------------------------------------- /src/actions/user.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | /* sample redux action */ 3 | import axios from 'axios' 4 | import * as actionTypes from '../constants/actionTypes' 5 | 6 | export const requestUsers = (): UserAction => { 7 | return { 8 | type: actionTypes.REQUEST_USERS, 9 | receivedAt: new Date() 10 | } 11 | } 12 | 13 | const receiveUsers = (users: Array): UserAction => { 14 | return { 15 | type: actionTypes.RECEIVE_USERS, 16 | users: users, 17 | receivedAt: new Date() 18 | } 19 | } 20 | 21 | export const fetchUsers = () => { 22 | return (dispatch: Function) => { 23 | dispatch(requestUsers()) 24 | return axios 25 | .get('http://jsonplaceholder.typicode.com/users') 26 | .then(response => dispatch(receiveUsers(response.data))) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/ui/button/Button.jsx: -------------------------------------------------------------------------------- 1 | // ref - https://github.com/react-component/checkbox/blob/master/src/Checkbox.jsx 2 | /* sample */ 3 | import React, { Component } from 'react' 4 | 5 | export default class Header extends Component { 6 | constructor (props) { 7 | super(props) 8 | 9 | this.handleClick = this.handleClick.bind(this) 10 | } 11 | 12 | handleClick (e) { 13 | this.props.onClick({ 14 | target: { ...this.props }, 15 | stopPropagation () { 16 | e.stopPropagation() 17 | }, 18 | preventDefault () { 19 | e.preventDefault() 20 | } 21 | }) 22 | } 23 | 24 | render () { 25 | const props = { ...this.props } 26 | 27 | return 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/reducers/article.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | /* sample */ 3 | import * as actionTypes from '../constants/actionTypes' 4 | import type { ArticleState } from './article.d' 5 | 6 | const initial = { 7 | isFetching: false, 8 | articles: [] 9 | } 10 | 11 | export default ( 12 | state: ArticleState = initial, 13 | action: Object 14 | ): ArticleState => { 15 | switch (action.type) { 16 | case actionTypes.REQUEST_ARTICLES: 17 | state = Object.assign({}, state, { 18 | isFetching: true 19 | }) 20 | break 21 | case actionTypes.RECEIVE_ARTICLES: 22 | state = Object.assign({}, state, { 23 | isFetching: false, 24 | articles: action.articles 25 | }) 26 | break 27 | default: 28 | break 29 | } 30 | 31 | return state 32 | } 33 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { Router, hashHistory } from 'react-router' 4 | import { Provider } from 'react-redux' 5 | import { syncHistoryWithStore } from 'react-router-redux' 6 | 7 | /** 8 | * Customized CSS for App initilization 9 | */ 10 | import './assets/css/normalize.css' 11 | import './assets/less/_.less' 12 | import './assets/sass/_.scss' 13 | 14 | import routes from './routes' 15 | import configureStore from './store/configureStore' 16 | 17 | const store = configureStore() 18 | const history = syncHistoryWithStore(hashHistory, store) 19 | 20 | const App = () => ( 21 | 22 | 23 | 24 | ) 25 | 26 | render(, document.getElementById('root')) 27 | -------------------------------------------------------------------------------- /src/actions/article.jsx: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | /* sample redux action */ 3 | import axios from 'axios' 4 | import * as actionTypes from '../constants/actionTypes' 5 | 6 | export const requestArticles = (): ArticleAction => { 7 | return { 8 | type: actionTypes.REQUEST_ARTICLES, 9 | receivedAt: new Date() 10 | } 11 | } 12 | 13 | const receiveArticles = (articles: Array
    ): ArticleAction => { 14 | return { 15 | type: actionTypes.RECEIVE_ARTICLES, 16 | articles: articles, 17 | receivedAt: new Date() 18 | } 19 | } 20 | 21 | export const fetchArticles = () => { 22 | return (dispatch: Function) => { 23 | dispatch(requestArticles()) 24 | return axios 25 | .get('http://jsonplaceholder.typicode.com/posts') 26 | .then(response => dispatch(receiveArticles(response.data))) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/ui/checkbox/Checkbox.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | import { Component } from 'react' 3 | import PropTypes from 'prop-types' 4 | 5 | export default class Checkbox extends Component { 6 | constructor (props) { 7 | super(props) 8 | 9 | console.log('not implement yet') 10 | } 11 | } 12 | 13 | Checkbox.propTypes = { 14 | prefixCls: PropTypes.string, 15 | style: PropTypes.object, 16 | type: PropTypes.string, 17 | className: PropTypes.string, 18 | defaultChecked: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]), 19 | checked: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]), 20 | onChange: PropTypes.func 21 | } 22 | 23 | Checkbox.defaultProps = { 24 | prefixCls: 'rc-checkbox', 25 | style: {}, 26 | type: 'checkbox', 27 | className: '', 28 | defaultChecked: false, 29 | onChange: () => {} 30 | } 31 | -------------------------------------------------------------------------------- /src/components/ui/button/__tests__/Button-test.jsx: -------------------------------------------------------------------------------- 1 | /* sample */ 2 | 3 | import React from 'react' 4 | import { shallow } from 'enzyme' 5 | import sinon from 'sinon' 6 | import expect from 'expect' 7 | 8 | import Button from '../Button.jsx' 9 | 10 | describe('