From 3eaf4740be2473147fb58181e6c532327fe04572 Mon Sep 17 00:00:00 2001 From: Radek Stepan Date: Sat, 16 Jan 2016 20:27:57 +0100 Subject: [PATCH] add a project form --- README.md | 6 +-- src/js/App.jsx | 13 ++--- src/js/components/AddProjectForm.jsx | 79 ++++++++++++++++++++++++++++ src/js/components/Space.jsx | 11 ++++ src/js/core/Store.js | 2 +- src/js/mixins/Page.js | 7 ++- src/js/mixins/lodash.js | 22 ++++++++ src/js/modules/github/request.js | 2 +- src/js/pages/AddProjectPage.jsx | 9 +++- src/js/pages/ProjectsPage.jsx | 1 - src/js/stores/appStore.js | 2 +- src/js/stores/projectsStore.js | 24 ++++++--- test/stats.js | 3 -- 13 files changed, 152 insertions(+), 29 deletions(-) create mode 100644 src/js/components/AddProjectForm.jsx create mode 100644 src/js/components/Space.jsx create mode 100644 src/js/mixins/lodash.js diff --git a/README.md b/README.md index 8abc25b..c2fb903 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ $ npm start # Server started on port 8080 ``` -##CHANGELOG +##Changelog -3.0.0 -- switch to React & Flux architecture +###v3.0.0 +- switch to React & Flux architecture \ No newline at end of file diff --git a/src/js/App.jsx b/src/js/App.jsx index bd77833..592201b 100644 --- a/src/js/App.jsx +++ b/src/js/App.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { RouterMixin, navigate } from 'react-mini-router'; import _ from 'lodash'; +import lodash from './mixins/lodash.js'; import ProjectsPage from './pages/ProjectsPage.jsx'; import MilestonesPage from './pages/MilestonesPage.jsx'; @@ -70,13 +71,14 @@ export default React.createClass({ }, // Route to a link. + // TODO: make this a named route. navigate: navigate }, // Show projects. projects() { document.title = 'Burnchart: GitHub Burndown Chart as a Service'; - actions.emit('projects.load'); + process.nextTick(() => { actions.emit('projects.load'); }); return ; }, @@ -92,6 +94,7 @@ export default React.createClass({ // Add a project. addProject() { + document.title = 'Add a project'; return ; }, @@ -114,13 +117,7 @@ export default React.createClass({ return
; } else { blank = true; - - // TODO: Hide any notifications. - // mediator.fire '!app/notify/hide' - - // Each page is starting in a loading state. - actions.emit('system.loading', true); - + actions.emit('system.loading', false); return this.renderCurrentRoute(); } } diff --git a/src/js/components/AddProjectForm.jsx b/src/js/components/AddProjectForm.jsx new file mode 100644 index 0000000..c319a09 --- /dev/null +++ b/src/js/components/AddProjectForm.jsx @@ -0,0 +1,79 @@ +import React from 'react'; + +import App from '../App.jsx'; + +import actions from '../actions/appActions.js'; + +import Icon from './Icon.jsx'; +import S from './Space.jsx'; + +export default React.createClass({ + + displayName: 'AddProjectForm.jsx', + + // Sign user in. + _onSignIn() { + actions.emit('user.signin'); + }, + + _onChange(evt) { + this.setState({ 'val': evt.target.value }); + }, + + _onKeyUp(evt) { + if (evt.key == 'Enter') { + this._onAdd(); + } + }, + + _onAdd() { + let [ owner, name ] = this.state.val.split('/'); + actions.emit('projects.add', { owner, name }); + // Redirect to the dashboard. + App.navigate('/'); + }, + + getInitialState() { + return { 'val': '' }; + }, + + render() { + let user; + if (!('uid' in this.props.user)) { + user = ( + If you'd like to add a private GitHub repo, + Sign In first. + ); + } + + return ( +
+
+

Add a Project

+

Type the name of a GitHub repository that has some + milestones with issues.{user}

+
+ +
+ + + + + + + +
+ + Add
+
+ +
+ Protip: To see if a milestone is on track or not, + make sure it has a due date assigned to it. +
+
+ ); + } + +}); diff --git a/src/js/components/Space.jsx b/src/js/components/Space.jsx new file mode 100644 index 0000000..5dbaf73 --- /dev/null +++ b/src/js/components/Space.jsx @@ -0,0 +1,11 @@ +import React from 'react'; + +export default React.createClass({ + + displayName: 'Space.jsx', + + render() { + return  ; + } + +}); diff --git a/src/js/core/Store.js b/src/js/core/Store.js index 53fbe8e..729abbe 100644 --- a/src/js/core/Store.js +++ b/src/js/core/Store.js @@ -54,7 +54,7 @@ export default class Store extends EventEmitter { let obj = this.get(key); if (_.isArray(obj)) { // TODO: Don't assume a string. - this.set(`${key}.${obj.length}`, val); + this.set(`${key}.${obj.length}`, val); // TODO: won't emit for root key return obj.length - 1; } else { this.set(key, [ val ]); diff --git a/src/js/mixins/Page.js b/src/js/mixins/Page.js index 0095bfa..15b6ca2 100644 --- a/src/js/mixins/Page.js +++ b/src/js/mixins/Page.js @@ -27,8 +27,11 @@ export default { return obj; }, - _onChange(store, val, key) {; - this.setState(this._getData(store)); + _onChange(store, val, key) { + // TODO: this is not the right approach! + if (this.isMounted()) { + this.setState(this._getData(store)); + } }, getInitialState() { diff --git a/src/js/mixins/lodash.js b/src/js/mixins/lodash.js new file mode 100644 index 0000000..7e5d10d --- /dev/null +++ b/src/js/mixins/lodash.js @@ -0,0 +1,22 @@ +import _ from 'lodash'; + +_.mixin({ + pluckMany: (source, keys) => { + if (!_.isArray(keys)) { + throw '`keys` needs to be an Array'; + } + + return _.map(source, (item) => { + let obj = {}; + for (let key of keys) { + obj[key] = item[key]; + } + return obj; + }); + }, + + isInt: (val) => { + return !isNaN(val) && parseInt(Number(val)) === val && + !isNaN(parseInt(val, 10)); + } +}); \ No newline at end of file diff --git a/src/js/modules/github/request.js b/src/js/modules/github/request.js index 3da97a9..15dd809 100644 --- a/src/js/modules/github/request.js +++ b/src/js/modules/github/request.js @@ -148,7 +148,7 @@ let isValid = (obj) => { let rules = { owner: (x) => { return (typeof x !== "undefined" && x !== null); }, name: (x) => { return (typeof x !== "undefined" && x !== null); }, - milestone: (x) => { return _.isFinite(x); } + milestone: (x) => { return _.isInt(x); } // mixin }; for (let key in obj) { diff --git a/src/js/pages/AddProjectPage.jsx b/src/js/pages/AddProjectPage.jsx index a51bfc4..2e54011 100644 --- a/src/js/pages/AddProjectPage.jsx +++ b/src/js/pages/AddProjectPage.jsx @@ -1,9 +1,12 @@ import React from 'react'; +import actions from '../actions/appActions.js'; + import Page from '../mixins/Page.js'; import Notify from '../components/Notify.jsx'; import Header from '../components/Header.jsx'; +import AddProjectForm from '../components/AddProjectForm.jsx'; export default React.createClass({ @@ -17,7 +20,11 @@ export default React.createClass({
-
+
+
+ +
+