diff --git a/app/assets/javascripts/actions.js b/app/assets/javascripts/actions.js index c38335c..e9b088c 100644 --- a/app/assets/javascripts/actions.js +++ b/app/assets/javascripts/actions.js @@ -2,24 +2,93 @@ import 'whatwg-fetch'; // TYPES export const TODO_ITEMS_LOADING = 'TODO_ITEMS_LOADING'; +export const TODO_CREATE_ITEM = 'TODO_CREATE_ITEM'; +export const TODO_UPDATE_ITEM = 'TODO_UPDATE_ITEM'; +export const TODO_SOFT_UPDATE_ITEM = 'TODO_SOFT_UPDATE_ITEM'; +export const TODO_DELETE_ITEM = 'TODO_DELETE_ITEM'; export const TODO_ITEMS_RECEIVED = 'TODO_ITEMS_RECEIVED'; export const TODO_ITEMS_FAILURE = 'TODO_ITEMS_FAILURE'; // ACTION CREATORS +export function load() { + return async (dispatch) => { + try { + dispatch({ type: TODO_ITEMS_LOADING }); + + const response = await fetch('/todo_items', { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }); + const data = await response.json(); + dispatch({ type: TODO_ITEMS_RECEIVED, payload: { items: data } }); + } catch (e) { + console.error(e); + } + }; +} + export function create(todo) { return async (dispatch) => { try { - const response = await fetch( - '/todo_items', - { - method: 'POST', - body: JSON.stringify({ todo_item: todo }), - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, + dispatch({ type: TODO_CREATE_ITEM }); + + const response = await fetch('/todo_items', { + method: 'POST', + body: JSON.stringify({ todo_item: todo }), + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }); + const data = await response.json(); + dispatch({ type: TODO_ITEMS_RECEIVED, payload: { items: data } }); + } catch (e) { + console.error(e); + } + }; +} + +export function update(todo) { + return async (dispatch) => { + try { + dispatch({ type: TODO_UPDATE_ITEM }); + + const response = await fetch('/todo_items', { + method: 'PUT', + body: JSON.stringify({ todo_item: todo }), + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }); + const data = await response.json(); + dispatch({ type: TODO_ITEMS_RECEIVED, payload: { items: data } }); + } catch (e) { + console.error(e); + } + }; +} + +export function softUpdateItem(options) { + return { type: TODO_SOFT_UPDATE_ITEM, payload: options }; +} + +export function deleteItem(todo) { + return async (dispatch) => { + try { + dispatch({ type: TODO_DELETE_ITEM }); + + const response = await fetch('/todo_items', { + method: 'DELETE', + body: JSON.stringify({ todo_item: todo }), + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', }, - ); + }); const data = await response.json(); dispatch({ type: TODO_ITEMS_RECEIVED, payload: { items: data } }); } catch (e) { diff --git a/app/assets/javascripts/app.jsx b/app/assets/javascripts/app.jsx index a45707d..732b898 100644 --- a/app/assets/javascripts/app.jsx +++ b/app/assets/javascripts/app.jsx @@ -3,7 +3,13 @@ import { render } from 'react-dom'; import PropTypes from 'prop-types'; import { connect, Provider } from 'react-redux'; import 'whatwg-fetch'; -import { create } from './actions'; +import { + load as loadItems, + create as createItem, + update as updateItem, + softUpdateItem, + deleteItem, +} from './actions'; import configureStore from './configureStore'; // TODO: @@ -16,7 +22,11 @@ import configureStore from './configureStore'; class App extends Component { static propTypes = { - create: PropTypes.func.isRequired, + createItem: PropTypes.func.isRequired, + loadItems: PropTypes.func.isRequired, + updateItem: PropTypes.func.isRequired, + softUpdateItem: PropTypes.func.isRequired, + deleteItem: PropTypes.func.isRequired, newForm: PropTypes.shape({ text: PropTypes.string, }), @@ -33,44 +43,75 @@ class App extends Component { super(props); this.state = { - data: [], newForm: { ...this.props.newForm }, }; } async componentWillMount() { - const response = await fetch('/todo_items'); - const data = await response.json(); - - this.setState({ data }); + this.props.loadItems(); } handleNewChange = (e) => { this.setState({ newForm: { ...this.state.newForm, text: e.target.value }, }); - } + }; handleNewKeyUp = (e) => { if (e.keyCode === 13) { - this.props.create(this.state.newForm); + this.props.createItem(this.state.newForm); this.setState({ newForm: { ...this.props.newForm } }); } + }; + + handleEditChange = idx => (e) => { + const modifiedItems = this.props.todos.items; + modifiedItems[idx] = { + ...modifiedItems[idx], + text: e.target.value, + }; + + this.props.softUpdateItem({ items: modifiedItems }); } - render() { - // TODO: Once the data is loaded from Redux completely, remove this - const todos = this.props.todos.items.length ? this.props.todos.items : this.state.data; + handleEditKeyUp = idx => (e) => { + if (e.keyCode === 13) { + this.props.updateItem(this.props.todos.items[idx]); + } + }; + + itemChecked = idx => () => { + const item = this.props.todos.items[idx]; + this.props.updateItem({ + ...item, + is_done: !item.is_done, + }); + } + + deleteItem = idx => () => { + this.props.deleteItem(this.props.todos.items[idx]); + } + render() { return (

To Do Is Cool