Skip to content

Commit

Permalink
a bunch of stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Solazzi committed Dec 10, 2015
1 parent c8ceedc commit 033f8a5
Show file tree
Hide file tree
Showing 23 changed files with 591 additions and 100 deletions.
11 changes: 11 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"presets": [
"es2015-loose",
"react"
],
"env": {
"production": {
"plugins": ["external-helpers-2"]
}
}
}
6 changes: 3 additions & 3 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,23 @@
/**
* React
*/
"react/display-name": 1,
"react/display-name": 0,
"react/forbid-prop-types": 1,
"react/jsx-boolean-value": 1,
"react/jsx-closing-bracket-location": 1,
"react/jsx-curly-spacing": 1,
"react/jsx-handler-names": 1,
"react/jsx-indent-props": 1,
"react/jsx-key": 1,
"react/jsx-max-props-per-line": 1,
"react/jsx-max-props-per-line": 0,
"react/jsx-no-bind": 1,
"react/jsx-no-duplicate-props": 1,
"react/jsx-no-literals": 1,
"react/jsx-no-undef": 1,
"react/jsx-pascal-case": 1,
"react/jsx-quotes": 1,
"react/jsx-sort-prop-types": 1,
"react/jsx-sort-props": 1,
"react/jsx-sort-props": 0,
"react/jsx-uses-react": 1,
"react/jsx-uses-vars": 1,
"react/no-danger": 1,
Expand Down
8 changes: 4 additions & 4 deletions application/assets/javascripts/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
* @module actions
*/

import {ACTION_NAMES_CHANGE, ACTION_SELECTED_ADD} from './constants';
import {ACTION_ATTENDEES_CHANGE, ACTION_SELECTED_ADD} from './constants';

export function namesChangeAction(names = []) {
export function attendeeListChangeAction(attendeeList = []) {
return {
type: ACTION_NAMES_CHANGE,
names
type: ACTION_ATTENDEES_CHANGE,
attendeeList
};
}

Expand Down
45 changes: 41 additions & 4 deletions application/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,48 @@
*
*/

import React from 'react';
import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import Provider from 'react-redux';
import {Provider} from 'react-redux';

//redux stuff
import reducers from './reducers';

//container Components
import AttendeeListContainer from './components/attendee-list';
import EditForm from './components/edit-form';

const middlewares = [];
if (PRODUCTION === false) {
middlewares.push(createLogger({
collapsed: true
}));
}

const createStoreWithMiddleware = applyMiddleware(...middlewares)(createStore);
const store = createStoreWithMiddleware(reducers);

class App extends Component {

componentDidMount() {
}

render() {
return (
<section>
<EditForm />
<AttendeeListContainer />
</section>
);
}
}

ReactDOM.render(
<div>{'test'}</div>,
document.querySelector('#root')
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
36 changes: 36 additions & 0 deletions application/assets/javascripts/components/attendee-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Applicatino Container: List of attendees
*
* @author Marco Solazzi
* @copyright (c) Marco solazzi
* @module components/attendees-list
*/

import React, { Component } from 'react';
import { connect } from 'react-redux';

import Attendee from './attendee';

function mapStateToProps(state) {
return {
attendees: state.attendeeList
};
}

export class AttendeeList extends Component {

render() {
let items = this.props.attendees.map((attendee) => (
<Attendee details={attendee} key={attendee.id} />
));
return <ul>{items}</ul>;
}
}

AttendeeList.propTypes = {
attendees: React.PropTypes.array
};

export default connect(
mapStateToProps
)(AttendeeList);
15 changes: 15 additions & 0 deletions application/assets/javascripts/components/attendee.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Attendee diplayer
*
* @author Marco Solazzi
* @copyright (c) Marco Solazzi
* @module components/attendee
*/

import React from 'react';

export default ({
details
}) => (
<li className="c-attendee" id={'attendee-' + details.id}>{details.name}</li>
);
75 changes: 75 additions & 0 deletions application/assets/javascripts/components/edit-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Attendee edit form
*
* @author Marco Solazzi
* @copyright (c) AQuest
* @module components/edit-form
*/

import React, {Component} from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import {attendeeListChangeAction} from '../actions';


function mapStateToProps(state) {
return {
attendees: state.attendeeList
};
}

function mapDispatchToProps(dispatch) {
return {
updateAttendees: bindActionCreators(attendeeListChangeAction, dispatch)
};
}

export class EditForm extends Component {

handleSubmit(e) {
e.preventDefault();
const value = (this.refs.attendeeInput.value || '').trim();
const attendees = EditForm.filterAttendees(value)
.map((name, id) => {
return {id, name};
});

this.props.updateAttendees(attendees);

}

static filterAttendees(value = '') {
return value.split("\n")
.map((line) => line.replace(/[\s]+/g, ' ').trim())
.filter((line) => !!line.length);
}

getAttendees() {
return this.props.attendees.map((attendee) => attendee.name).join("\n").trim();
}

render() {

let attendees = this.getAttendees();

return (
<form action="" onSubmit={this.handleSubmit.bind(this)}>
<textarea cols="30" ref="attendeeInput" id="edit-form" name="edit-form" rows="10" defaultValue={attendees} />
<p>
<button type="submit">{'Save'}</button>
<button type="reset">{'Reset'}</button>
</p>
</form>
);
}
}

EditForm.propTypes = {
attendees: React.PropTypes.array,
updateAttendees: React.PropTypes.func.isRequired
};

export default connect(
mapStateToProps,
mapDispatchToProps
)(EditForm);
4 changes: 2 additions & 2 deletions application/assets/javascripts/constants.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/**
* Contants
* Constants
*
* @author Marco Solazzi
* @copyright (c) Marco Solazzi
* @module constants
*/

//ACTIONS
export const ACTION_NAMES_CHANGE = 'ACTION_NAMES_CHANGE';
export const ACTION_ATTENDEES_CHANGE = 'ACTION_ATTENDEES_CHANGE';

export const ACTION_SELECTED_ADD = 'ACTION_SELECTED_ADD';
10 changes: 5 additions & 5 deletions application/assets/javascripts/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
*/

import { combineReducers } from 'redux';
import {ACTION_NAMES_CHANGE, ACTION_SELECTED_ADD} from './constants';
import {ACTION_ATTENDEES_CHANGE, ACTION_SELECTED_ADD} from './constants';

export function namesReducer(state = [], action = {}) {
export function attendeeListReducer(state = [], action = {}) {

switch (action.type) {
case ACTION_NAMES_CHANGE:
return [...action.names];
case ACTION_ATTENDEES_CHANGE:
return [...action.attendeeList];
default:
return state;
}
Expand All @@ -32,7 +32,7 @@ export function selectedReducer(state = [], action = {}) {


export default combineReducers({
names: namesReducer,
attendeeList: attendeeListReducer,
selected: selectedReducer
});

3 changes: 3 additions & 0 deletions application/fixtures/api-test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"test": true
}
18 changes: 9 additions & 9 deletions application/test/actions.spec.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
import expect from 'expect';

import {ACTION_NAMES_CHANGE, ACTION_SELECTED_ADD} from '../assets/javascripts/constants';
import {namesChangeAction, selectedAddAction} from '../assets/javascripts/actions';
import {ACTION_ATTENDEES_CHANGE, ACTION_SELECTED_ADD} from '../assets/javascripts/constants';
import {attendeeListChangeAction, selectedAddAction} from '../assets/javascripts/actions';

describe('Test Actions', () => {


describe('Action name action', () => {

const names = ['John'];
const attendeeList = ['John'];
let action;

beforeEach(() => {
action = namesChangeAction(names);
action = attendeeListChangeAction(attendeeList);
});

it('should return an object', () => {
expect(action).toBeA(Object);
});

it('should match the change action action type', () => {
expect(action.type).toBe(ACTION_NAMES_CHANGE);
expect(action.type).toBe(ACTION_ATTENDEES_CHANGE);
});

it('should pass new names', () => {
expect(action.names).toEqual(names);
expect(action.attendeeList).toEqual(attendeeList);
});

it('should return an empty array by default', () => {
let defaultAction = namesChangeAction();
expect(defaultAction.names).toBeA(Array);
expect(defaultAction.names.length).toBe(0);
let defaultAction = attendeeListChangeAction();
expect(defaultAction.attendeeList).toBeA(Array);
expect(defaultAction.attendeeList.length).toBe(0);
});

});
Expand Down
37 changes: 37 additions & 0 deletions application/test/components/attendee-list.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import expect, { spyOn } from 'expect';
import React from 'react';
import TestUtils from 'react-addons-test-utils';

import {AttendeeList} from '../../assets/javascripts/components/attendee-list';

describe('Name Item Component Actions', () => {

let shallowRenderer, output;

const data = {
attendees: [{
id: 0,
name: 'John'
}, {
id: 1,
name: 'Jane'
}]
};

beforeEach(() => {
shallowRenderer = TestUtils.createRenderer();
shallowRenderer.render(<AttendeeList {...data} />);
output = shallowRenderer.getRenderOutput();
});

it('should render an unordered list', () => {
expect(output.type).toBe('ul');
});

it('should render <Attendee> components', () => {
output.props.children.forEach((prop, i) => {
expect(prop.props.details).toEqual(data.attendees[i]);
});
});

});
Loading

0 comments on commit 033f8a5

Please sign in to comment.