Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce panes #11

Open
wants to merge 10 commits into
base: reselect2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

export const ADD_TODO = 'ADD_TODO'
export const COMPLETE_TODO = 'COMPLETE_TODO'
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'
export const SET_PANE_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'
export const CHANGE_THEME = 'CHANGE_THEME'
export const UPDATE_SEARCH = 'UPDATE_SEARCH';
export const UPDATE_PANE_SEARCH = 'UPDATE_SEARCH';
export const ADD_PANE = 'ADD_PANE'

/*
* other constants
Expand All @@ -22,6 +23,10 @@ export const VisibilityFilters = {
* action creators
*/

export function addPane() {
return { type: ADD_PANE };
}

export function addTodo(text) {
return { type: ADD_TODO, text }
}
Expand All @@ -30,17 +35,18 @@ export function completeTodo(index) {
return { type: COMPLETE_TODO, index }
}

export function setVisibilityFilter(filter) {
return { type: SET_VISIBILITY_FILTER, filter }
export function setPaneVisibilityFilter(paneIdx, filter) {
return { type: SET_PANE_VISIBILITY_FILTER, index: paneIdx, filter }
}

export function changeTheme() {
return { type: CHANGE_THEME };
}

export function updateSearch(searchTerm) {
export function updatePaneSearch(paneIdx, searchTerm) {
return {
type: UPDATE_SEARCH,
type: UPDATE_PANE_SEARCH,
index: paneIdx,
searchTerm
};
}
44 changes: 44 additions & 0 deletions components/Pane.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { PropTypes, Component } from 'react';
import { addTodo, completeTodo } from '../actions'
import AddTodo from './AddTodo';
import TodoList from './TodoList';
import Footer from './Footer';

class Pane extends Component {
render() {
const {
dispatch,
pane,
matchingVisibleTodosForPaneFactory,
updateSearch,
setVisibilityFilter,
...props
} = this.props;

const { visibilityFilter, searchTerm } = pane;

console.log("Rendering pane: ")
console.log(pane);

const visibleTodos = matchingVisibleTodosForPaneFactory(visibilityFilter, searchTerm);

return (
<div>
{pane.key}
Search: <input type="text" value={searchTerm} onChange={updateSearch} />
<br />
<AddTodo onAddClick={ text => dispatch(addTodo(text)) } />
<TodoList
todos={visibleTodos}
onTodoClick={ index => dispatch(completeTodo(index)) }
/>
<Footer
filter={visibilityFilter}
onFilterChange={setVisibilityFilter}
/>
</div>
);
}
}

export default Pane;
111 changes: 32 additions & 79 deletions containers/App.js
Original file line number Diff line number Diff line change
@@ -1,96 +1,49 @@
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { addTodo, completeTodo, setVisibilityFilter, changeTheme, VisibilityFilters, updateSearch } from '../actions'
import AddTodo from '../components/AddTodo'
import TodoList from '../components/TodoList'
import Footer from '../components/Footer'
import { setPaneVisibilityFilter, changeTheme, VisibilityFilters, updatePaneSearch, addPane } from '../actions'
import { memoize, createMemoizedFunction } from '../memoize'
import { createSelector, createStructuredSelector } from 'reselect';
import { appSelector } from '../selectors/AppSelector';
import Pane from '../components/Pane';

class App extends Component {

updateSearch = function(e) {
const { dispatch } = this.props;
dispatch(updateSearch(e.target.value));
}
class App extends Component {

render() {
console.log(this.props);
// Injected by connect() call:
const { dispatch, matchingVisibleTodos, currentTheme, searchTerm, visibilityFilter } = this.props
const { dispatch, panes, currentTheme, ...props } = this.props

var createUpdatePaneSearch = function(paneIdx) {
return (e) => {
dispatch(updatePaneSearch(paneIdx, e.target.value));
};
}

var createSetVisibilityFilter = function(paneIdx) {
return (filter) => {
dispatch(setPaneVisibilityFilter(paneIdx, filter));
}
}

let paneComponents = panes.map((pane, idx) =>
<Pane
key={pane.key}
dispatch={dispatch}
pane={pane}
updateSearch={createUpdatePaneSearch(idx)}
setVisibilityFilter={createSetVisibilityFilter(idx)}
{...props}
/>
);

return (
<div className={currentTheme}>
Search: <input type="text" value={searchTerm} onChange={this.updateSearch.bind(this)}/><br/>
<AddTodo
onAddClick={text =>
dispatch(addTodo(text))
} />
<TodoList
todos={matchingVisibleTodos}
onTodoClick={index =>
dispatch(completeTodo(index))
} />
<Footer
filter={visibilityFilter}
onFilterChange={nextFilter =>
dispatch(setVisibilityFilter(nextFilter))
} />
{paneComponents}
<button onClick={() => dispatch(addPane())}>Add Pane</button>
<button onClick={() => dispatch(changeTheme())}>Change Theme</button>
</div>
)
}
}

App.propTypes = {
todos: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
})),
visibilityFilter: PropTypes.oneOf([
'SHOW_ALL',
'SHOW_COMPLETED',
'SHOW_ACTIVE'
]).isRequired
}

function selectVisibleTodos(todos, filter) {
console.log("Recalculating selectTodos");
switch (filter) {
case VisibilityFilters.SHOW_ALL:
return todos
case VisibilityFilters.SHOW_COMPLETED:
return todos.filter(todo => todo.completed)
case VisibilityFilters.SHOW_ACTIVE:
return todos.filter(todo => !todo.completed)
}
}

function selectMatchingTodos(todos, search) {
console.log("Recalculating matchingTodos");
return todos.filter((todo) => { return todo.text.search(search) >= 0; });
}

const todosSelector = state => state.todos;
const visibilityFilterSelector = state => state.visibilityFilter;
const currentThemeSelector = state => state.currentTheme;
const searchTermSelector = state => state.searchTerm;

const visibleTodosSelector = createSelector(
[todosSelector, visibilityFilterSelector],
selectVisibleTodos
);

const matchingVisibleTodosSelector = createSelector(
[visibleTodosSelector, searchTermSelector],
selectMatchingTodos
);

const select = createStructuredSelector({
matchingVisibleTodos: matchingVisibleTodosSelector,
visibilityFilter: visibilityFilterSelector,
currentTheme: currentThemeSelector,
searchTerm: searchTermSelector
});

// Wrap the component to inject dispatch and state into it
export default connect(select)(App)
export default connect(appSelector)(App);
23 changes: 17 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,25 @@ import { render } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './containers/App'
import todoApp from './reducers'

let store = createStore(todoApp)
import { DevTools, LogMonitor, DebugPanel } from 'redux-devtools/lib/react';
import configureStore, {USE_DEV_TOOLS} from './store/configureStore'

let store = configureStore()
let rootElement = document.getElementById('root')

let debugPannel = USE_DEV_TOOLS ? (
<DebugPanel top right bottom>
<DevTools store={store} monitor={LogMonitor} />
</DebugPanel>) : null;


render(
<Provider store={store}>
<App />
</Provider>,
<div>
<Provider store={store}>
<App />
</Provider>
{debugPannel}

</div>,
rootElement
)
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
"homepage": "http://rackt.github.io/redux",
"dependencies": {
"classnames": "^2.1.2",
"lodash": "^3.10.1",
"react": "^0.14.0",
"react-dom": "^0.14.0",
"react-redux": "^4.0.0",
"redux": "^3.0.0",
"reselect": "^2.0.0"
"redux-devtools": "^2.1.5",
"reselect": "^2.0.0",
"uid": "0.0.2"
},
"devDependencies": {
"babel-core": "^5.6.18",
Expand Down
63 changes: 0 additions & 63 deletions reducers.js

This file was deleted.

10 changes: 10 additions & 0 deletions reducers/CurrentThemeReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { CHANGE_THEME } from '../actions'

export function currentTheme(state = 'theme-green', action) {
switch (action.type) {
case CHANGE_THEME:
return state == 'theme-green' ? 'theme-blue' : 'theme-green';
default:
return state
}
}
41 changes: 41 additions & 0 deletions reducers/PanesReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { combineReducers } from 'redux'
import { ADD_PANE, SET_PANE_VISIBILITY_FILTER, VisibilityFilters, UPDATE_PANE_SEARCH } from '../actions'
import combineCollectionReducers from './combineCollectionReducers'
import uid from 'uid';

const { SHOW_ALL } = VisibilityFilters

function searchTerm(state = '', action) {
switch (action.type) {
case UPDATE_PANE_SEARCH:
return action.searchTerm;
default:
return state;
}
}

function visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_PANE_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}

const paneElementReducer = combineReducers({
key: () => { return uid() },
visibilityFilter,
searchTerm
});

function paneCollectionReducer(state = [], action) {
switch(action.type) {
case ADD_PANE:
return state.concat(paneElementReducer(undefined, {type: null}));
default:
return state;
}
}

export const panes = combineCollectionReducers(paneCollectionReducer, paneElementReducer);
Loading