From 5fbc38d61d7935a5c0aa76c66677cd62e894291d Mon Sep 17 00:00:00 2001 From: Myer Nore Date: Thu, 24 Aug 2017 05:06:32 -0400 Subject: [PATCH 1/4] add todomvc example redux - track view list #49 --- .babelrc | 10 +- package.json | 3 + src/{App.js => App.old.js} | 0 src/actions/index.js | 8 + src/actions/index.modified.js | 8 + src/actions/index.spec.js | 45 ++++ src/components/Footer.js | 72 +++++++ src/components/Footer.spec.js | 102 +++++++++ src/components/Header.js | 26 +++ src/components/Header.spec.js | 50 +++++ src/components/MainSection.js | 79 +++++++ src/components/MainSection.spec.js | 129 ++++++++++++ src/components/TodoItem.js | 66 ++++++ src/components/TodoItem.spec.js | 119 +++++++++++ src/components/TodoTextInput.js | 54 +++++ src/components/TodoTextInput.spec.js | 80 ++++++++ src/constants/ActionTypes.js | 6 + src/constants/ActionTypes.modified.js | 6 + src/constants/TodoFilters.js | 3 + src/containers/App.js | 32 +++ src/containers/App.modified.js | 32 +++ src/index.js | 21 +- src/index.old.js | 9 + src/reducers/index.js | 8 + src/reducers/todos.js | 55 +++++ src/reducers/todos.spec.js | 284 ++++++++++++++++++++++++++ yarn.lock | 140 ++++++++++++- 27 files changed, 1436 insertions(+), 11 deletions(-) rename src/{App.js => App.old.js} (100%) create mode 100644 src/actions/index.js create mode 100644 src/actions/index.modified.js create mode 100644 src/actions/index.spec.js create mode 100644 src/components/Footer.js create mode 100644 src/components/Footer.spec.js create mode 100644 src/components/Header.js create mode 100644 src/components/Header.spec.js create mode 100644 src/components/MainSection.js create mode 100644 src/components/MainSection.spec.js create mode 100644 src/components/TodoItem.js create mode 100644 src/components/TodoItem.spec.js create mode 100644 src/components/TodoTextInput.js create mode 100644 src/components/TodoTextInput.spec.js create mode 100644 src/constants/ActionTypes.js create mode 100644 src/constants/ActionTypes.modified.js create mode 100644 src/constants/TodoFilters.js create mode 100644 src/containers/App.js create mode 100644 src/containers/App.modified.js create mode 100644 src/index.old.js create mode 100644 src/reducers/index.js create mode 100644 src/reducers/todos.js create mode 100644 src/reducers/todos.spec.js diff --git a/.babelrc b/.babelrc index caee144..1ca78e5 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,11 @@ { - "presets": ["react-app", "es2015", "react"] + "presets": [ + "react-app", + "es2015", + "react", + "stage-0" + ], + "plugins": [ + "transform-class-properties" + ] } \ No newline at end of file diff --git a/package.json b/package.json index 87ba629..a1b392a 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,8 @@ "version": "0.2.0", "private": true, "dependencies": { + "babel-plugin-transform-class-properties": "^6.24.1", + "babel-preset-stage-0": "^6.24.1", "firebase": "^4.1.1", "material-ui": "next", "material-ui-icons": "^1.0.0-alpha.3", @@ -13,6 +15,7 @@ "redux": "^3.7.2", "redux-logger": "^3.0.6", "redux-thunk": "^2.2.0", + "todomvc-app-css": "^2.1.0", "uuid": "^3.0.1" }, "devDependencies": { diff --git a/src/App.js b/src/App.old.js similarity index 100% rename from src/App.js rename to src/App.old.js diff --git a/src/actions/index.js b/src/actions/index.js new file mode 100644 index 0000000..7d023b4 --- /dev/null +++ b/src/actions/index.js @@ -0,0 +1,8 @@ +import * as types from '../constants/ActionTypes' + +export const addTodo = text => ({ type: types.ADD_TODO, text }) +export const deleteTodo = id => ({ type: types.DELETE_TODO, id }) +export const editTodo = (id, text) => ({ type: types.EDIT_TODO, id, text }) +export const completeTodo = id => ({ type: types.COMPLETE_TODO, id }) +export const completeAll = () => ({ type: types.COMPLETE_ALL }) +export const clearCompleted = () => ({ type: types.CLEAR_COMPLETED }) diff --git a/src/actions/index.modified.js b/src/actions/index.modified.js new file mode 100644 index 0000000..79ce052 --- /dev/null +++ b/src/actions/index.modified.js @@ -0,0 +1,8 @@ +import * as types from '../constants/ActionTypes' + +export const addTrack = text => ({ type: types.ADD_TRACK, text }) +export const deleteTrack = id => ({ type: types.DELETE_TRACK, id }) +export const editTrack = (id, text) => ({ type: types.EDIT_TRACK, id, text }) +export const finishTrack = id => ({ type: types.FINISH_TRACK, id }) +export const clearAll = () => ({ type: types.CLEAR_ALL }) +export const startTrack = () => ({ type: types.START_TRACK }) diff --git a/src/actions/index.spec.js b/src/actions/index.spec.js new file mode 100644 index 0000000..06c894c --- /dev/null +++ b/src/actions/index.spec.js @@ -0,0 +1,45 @@ +import * as types from '../constants/ActionTypes' +import * as actions from './index' + +describe('todo actions', () => { + it('addTodo should create ADD_TODO action', () => { + expect(actions.addTodo('Use Redux')).toEqual({ + type: types.ADD_TODO, + text: 'Use Redux' + }) + }) + + it('deleteTodo should create DELETE_TODO action', () => { + expect(actions.deleteTodo(1)).toEqual({ + type: types.DELETE_TODO, + id: 1 + }) + }) + + it('editTodo should create EDIT_TODO action', () => { + expect(actions.editTodo(1, 'Use Redux everywhere')).toEqual({ + type: types.EDIT_TODO, + id: 1, + text: 'Use Redux everywhere' + }) + }) + + it('completeTodo should create COMPLETE_TODO action', () => { + expect(actions.completeTodo(1)).toEqual({ + type: types.COMPLETE_TODO, + id: 1 + }) + }) + + it('completeAll should create COMPLETE_ALL action', () => { + expect(actions.completeAll()).toEqual({ + type: types.COMPLETE_ALL + }) + }) + + it('clearCompleted should create CLEAR_COMPLETED action', () => { + expect(actions.clearCompleted()).toEqual({ + type: types.CLEAR_COMPLETED + }) + }) +}) diff --git a/src/components/Footer.js b/src/components/Footer.js new file mode 100644 index 0000000..aa01814 --- /dev/null +++ b/src/components/Footer.js @@ -0,0 +1,72 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters' + +const FILTER_TITLES = { + [SHOW_ALL]: 'All', + [SHOW_ACTIVE]: 'Active', + [SHOW_COMPLETED]: 'Completed' +} + +export default class Footer extends Component { + static propTypes = { + completedCount: PropTypes.number.isRequired, + activeCount: PropTypes.number.isRequired, + filter: PropTypes.string.isRequired, + onClearCompleted: PropTypes.func.isRequired, + onShow: PropTypes.func.isRequired + } + + renderTodoCount() { + const { activeCount } = this.props + const itemWord = activeCount === 1 ? 'item' : 'items' + + return ( + + {activeCount || 'No'} {itemWord} left + + ) + } + + renderFilterLink(filter) { + const title = FILTER_TITLES[filter] + const { filter: selectedFilter, onShow } = this.props + + return ( + onShow(filter)}> + {title} + + ) + } + + renderClearButton() { + const { completedCount, onClearCompleted } = this.props + if (completedCount > 0) { + return ( + + ) + } + } + + render() { + return ( + + ) + } +} diff --git a/src/components/Footer.spec.js b/src/components/Footer.spec.js new file mode 100644 index 0000000..55e3d32 --- /dev/null +++ b/src/components/Footer.spec.js @@ -0,0 +1,102 @@ +import React from 'react' +import { createRenderer } from 'react-test-renderer/shallow'; +import Footer from './Footer' +import { SHOW_ALL, SHOW_ACTIVE } from '../constants/TodoFilters' + +const setup = propOverrides => { + const props = Object.assign({ + completedCount: 0, + activeCount: 0, + filter: SHOW_ALL, + onClearCompleted: jest.fn(), + onShow: jest.fn() + }, propOverrides) + + const renderer = createRenderer() + renderer.render(