diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..e1d3c5df --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["es2015", "react"], + "plugins": ["transform-object-assign"] +} diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..1521c8b7 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +dist diff --git a/.eslintrc.js b/.eslintrc.js index ebf8b95b..ed360b75 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -32,6 +32,13 @@ module.exports = { "semi": [ "error", "never" - ] + ], + "jsx-quotes": [ + "error", + "prefer-double" + ], + "react/jsx-uses-vars": "error", + "react/jsx-uses-react": "error", + "react/jsx-no-bind": "error" } }; diff --git a/app/DevTools.jsx b/app/DevTools.jsx new file mode 100644 index 00000000..506a87a3 --- /dev/null +++ b/app/DevTools.jsx @@ -0,0 +1,16 @@ +import React from "react" + +import { createDevTools } from "redux-devtools" + +import LogMonitor from "redux-devtools-log-monitor" +import DockMonitor from "redux-devtools-dock-monitor" + +const DevTools = createDevTools( + + + +) + +export default DevTools diff --git a/app/actions/index.js b/app/actions/index.js new file mode 100644 index 00000000..bdab72a1 --- /dev/null +++ b/app/actions/index.js @@ -0,0 +1,8 @@ +import {SELECT_ITEM} from "../constants/actionTypes" + +export const selectItem = (id) => { + return { + type: SELECT_ITEM, + id: id + } +} diff --git a/app/components/Item.jsx b/app/components/Item.jsx new file mode 100644 index 00000000..ea07c98c --- /dev/null +++ b/app/components/Item.jsx @@ -0,0 +1,25 @@ +import React, { PropTypes } from "react" +import {ListItem} from "react-photonkit" + +const Item = ({ + text, + active, + handleClick +}) => ( +
+ +
+) + +Item.propTypes = { + text: PropTypes.string.isRequired, + active: PropTypes.bool.isRequired, + handleClick: PropTypes.func.isRequired +} + +export default Item diff --git a/app/components/ItemList.jsx b/app/components/ItemList.jsx new file mode 100644 index 00000000..d50880c8 --- /dev/null +++ b/app/components/ItemList.jsx @@ -0,0 +1,30 @@ +import React, { PropTypes } from "react" +import { Pane, ListGroup } from "react-photonkit" +import Item from "./Item" + +const ItemList = ({ + items, + handleItemClick +}) => ( + + + {items.map((todo) => { + return ( + + ) + })} + + +) + +ItemList.propTypes = { + items: PropTypes.array.isRequired, + handleItemClick: PropTypes.func.isRequired +} + +export default ItemList diff --git a/app/constants/actionTypes.js b/app/constants/actionTypes.js new file mode 100644 index 00000000..c2459e04 --- /dev/null +++ b/app/constants/actionTypes.js @@ -0,0 +1 @@ +export const SELECT_ITEM = "SELECT_ITEM" diff --git a/app/containers/SelectableItemList.jsx b/app/containers/SelectableItemList.jsx new file mode 100644 index 00000000..a1fb677b --- /dev/null +++ b/app/containers/SelectableItemList.jsx @@ -0,0 +1,19 @@ +import { connect } from "react-redux" +import { selectItem } from "../actions" +import ItemList from "../components/ItemList" + +const mapStateToProps = (state) => { + return { + items: state.items + } +} + +const mapDispatchToProps = (dispatch) => { + return { + handleItemClick: (id) => { + dispatch(selectItem(id)) + } + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(ItemList) diff --git a/app/index.html b/app/index.html index 26988b20..7f1c0fbe 100644 --- a/app/index.html +++ b/app/index.html @@ -5,15 +5,13 @@ Classroom Desktop 0.0.1 -

Hello World! 0.0.1

- - We are using node , - Chromium , - and Electron . +
diff --git a/app/index.jsx b/app/index.jsx new file mode 100644 index 00000000..46684516 --- /dev/null +++ b/app/index.jsx @@ -0,0 +1,35 @@ +import * as React from "react" +import * as ReactDOM from "react-dom" +import {Window, Toolbar, Content} from "react-photonkit" +import {createStore, compose} from "redux" +import { Provider } from "react-redux" +import isDev from "electron-is-dev" +import DevTools from "./DevTools" + +import reducer from "./reducers" +import SelectableItemList from "./containers/SelectableItemList" + +let devToolsInstance +if (isDev) { + devToolsInstance = +} + +const store = createStore(reducer, compose(DevTools.instrument())) + +const render = () => { + ReactDOM.render( + + + + + + + + {devToolsInstance} + + + , document.getElementById("app")) +} + +store.subscribe(render) +render() diff --git a/app/reducers/index.js b/app/reducers/index.js new file mode 100644 index 00000000..d2d2455a --- /dev/null +++ b/app/reducers/index.js @@ -0,0 +1,7 @@ +import { combineReducers } from "redux" + +import items from "./items" + +export default combineReducers({ + items +}) diff --git a/app/reducers/items.js b/app/reducers/items.js new file mode 100644 index 00000000..97446397 --- /dev/null +++ b/app/reducers/items.js @@ -0,0 +1,43 @@ +const initialState = [ + { + id: 1, + text: "Item 1", + active: false + }, + { + id: 2, + text: "Item 2", + active: true + } +] + +const item = (state, action) => { + switch (action.type) { + case "SELECT_ITEM": + if (action.id === state.id) { + return Object.assign({}, state, {active: !state.active}) + } else { + return state + } + default: + return state + } +} + +const items = (state, action) => { + if (typeof state === "undefined") { + return initialState + } + + switch (action.type) { + case "SELECT_ITEM": + return state.map((each) => { + return item(each, action) + }) + + default: + return state + } +} + +export default items diff --git a/app/renderer.js b/app/renderer.js deleted file mode 100644 index 31c58dc3..00000000 --- a/app/renderer.js +++ /dev/null @@ -1,5 +0,0 @@ -const logger = require("./renderer-logger") - -setInterval(() => { - logger.info("Browser log!") -}, 1000) diff --git a/package.json b/package.json index 021a5049..ed1760fe 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "main": "main.js", "scripts": { "start": "electron main.js", - "test": "node_modules/.bin/eslint . && node_modules/mocha/bin/mocha test", + "test": "node_modules/.bin/eslint --ext .js,.jsx . && node_modules/mocha/bin/mocha --compilers js:babel-core/register test", "build-mac": "electron-packager . Classroom --platform=darwin --arch=x64 --out=dist --overwrite" }, "repository": { @@ -23,16 +23,32 @@ "devDependencies": { "electron-packager": "^7.0.4", "electron-prebuilt": "^1.2.0", - "eslint": "^2.12.0", + "eslint": "^2.13.0", "eslint-config-standard": "^5.3.1", "eslint-plugin-promise": "^1.3.2", "eslint-plugin-react": "^5.2.1", - "eslint-plugin-standard": "^1.3.2" + "eslint-plugin-standard": "^1.3.2", + "redux-devtools": "^3.3.1", + "redux-devtools-dock-monitor": "^1.1.1", + "redux-devtools-log-monitor": "^1.0.11" }, "dependencies": { + "babel-plugin-transform-object-assign": "^6.8.0", + "babel-preset-es2015": "^6.9.0", + "babel-preset-react": "^6.5.0", + "babel-register": "^6.9.0", "chai": "^3.5.0", + "deep-freeze": "0.0.1", "electron-is-dev": "^0.1.1", "mocha": "^2.5.3", + "react": "^15.1.0", + "react-dom": "^15.1.0", + "react-photonkit": "^0.4.1", + "react-redux": "^4.4.5", + "react-router": "^2.4.1", + "react-router-redux": "^4.0.5", + "recompose": "^0.20.2", + "redux": "^3.5.2", "winston": "^2.2.0" } } diff --git a/test/actions.js b/test/actions.js new file mode 100644 index 00000000..ae3a8bdc --- /dev/null +++ b/test/actions.js @@ -0,0 +1,17 @@ +/* eslint-env mocha */ + +import { assert } from "chai" +import { SELECT_ITEM } from "../app/constants/actionTypes" +import { selectItem } from "../app/actions" + +describe("actions", () => { + it("should create an action to select an item", () => { + const id = 1 + const expectedAction = { + type: SELECT_ITEM, + id: id + } + + assert.deepEqual(expectedAction, selectItem(id)) + }) +}) diff --git a/test/dummy.js b/test/dummy.js deleted file mode 100644 index 90c8103e..00000000 --- a/test/dummy.js +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-env mocha */ - -const assert = require("chai").assert - -describe("arithmetic", () => { - describe("numbers", () => { - it("should add up correctly", () => { - assert.equal(2, 1 + 1) - }) - }) -}) diff --git a/test/dummyTwo.js b/test/dummyTwo.js deleted file mode 100644 index 39bfcc8d..00000000 --- a/test/dummyTwo.js +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-env mocha */ - -const assert = require("chai").assert - -describe("objects", () => { - describe("strings", () => { - it("should concatenate", () => { - assert.equal("helloworld", "hello" + "world") - }) - }) -}) diff --git a/test/reducers.js b/test/reducers.js new file mode 100644 index 00000000..bce77e20 --- /dev/null +++ b/test/reducers.js @@ -0,0 +1,71 @@ +/* eslint-env mocha */ + +import { assert } from "chai" +import { SELECT_ITEM } from "../app/constants/actionTypes" +import deepFreeze from "deep-freeze" + +import itemsReducer from "../app/reducers/items" + +describe("reducers", () => { + describe("items reducer", () => { + it("should return the initial state", () => { + let expectedState = [ + { + id: 1, + text: "Item 1", + active: false + }, + { + id: 2, + text: "Item 2", + active: true + } + ] + + assert.deepEqual( + expectedState, + itemsReducer(undefined, {}) + ) + }) + + it("should select the correct item", () => { + let initialState = [ + { + id: 1, + text: "Item 1", + active: false + }, + { + id: 2, + text: "Item 2", + active: true + } + ] + + let expectedState = [ + { + id: 1, + text: "Item 1", + active: true + }, + { + id: 2, + text: "Item 2", + active: true + } + ] + + let action = { + type: SELECT_ITEM, + id: 1 + } + + deepFreeze(initialState) + + assert.deepEqual( + expectedState, + itemsReducer(initialState, action) + ) + }) + }) +})