-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
);
diff --git a/frontend/modules/list/actions/ItemActions.js b/frontend/modules/list/actions/ItemActions.js
index b8102ee0..6de24a42 100644
--- a/frontend/modules/list/actions/ItemActions.js
+++ b/frontend/modules/list/actions/ItemActions.js
@@ -1,161 +1,193 @@
import { request } from '../../common/CustomSuperagent';
-import { serverURLs } from '../../common/config'
+import AppDispatcher from '../../common/AppDispatcher';
+import { ItemStore } from '../stores/ItemStore';
import ItemConstants from '../constants/ItemConstants';
+import ListConstants from '../constants/ListConstants';
+import { serverURLs } from '../../common/config'
-export const load = (list) => {
- return (dispatch) => {
+class ItemActions {
+ load_list(id) {
request()
- .get(serverURLs.list_item + '?list=' + list)
- .then(res => {
- dispatch({
- type: ItemConstants.ITEM_INIT,
- list: list,
- items: res.body.results
- })
- })
- .catch(err => {
- console.error(err.toString());
- })
+ .get(serverURLs.list_item + '?list=' + id)
+ .end((err, res) => {
+ if (!err && res) {
+ this.init(id, res.body);
+ } else {
+ console.error(err.toString());
+ console.error(res.body);
+ this.error(res.body);
+ }
+ });
+ }
+
+ save_list(data) {
+ let r = 'id' in data ?
+ request().put(serverURLs.list + data.id + '/') :
+ request().post(serverURLs.list) ;
+
+ r.send(data)
+ .end((err, res) => {
+ if (!err && res) {
+ var id = res.body.id;
+ this.handleSubmit(res.body.id);
+ } else {
+ console.error(err.toString());
+ console.error(res.body);
+ this.error(res.body);
+ }
+ });
}
-};
-export const add = (title, list) => {
- return (dispatch) => {
+ save_item(data) {
+ let r = 'id' in data ?
+ request().put(serverURLs.list_item + data.id + '/') :
+ request().post(serverURLs.list_item) ;
+
+ r.send(data)
+ .end((err, res) => {
+ if (!err && res) {
+ var id = res.body.id;
+ this.handleSubmit(res.body.id);
+ } else {
+ console.error(err.toString());
+ console.error(res.body);
+ this.error(res.body);
+ }
+ });
+ }
+
+ addItem(title) {
request()
.post(serverURLs.list_item)
.send({
title: title,
- list: list
+ list: ItemStore.getKey()
})
.end((err, res) => {
if (!err && res) {
- dispatch({
- type: ItemConstants.ITEM_ADD,
- list: list,
- id: res.body.id,
- title: res.body.title
+ AppDispatcher.dispatch({
+ actionType: ItemConstants.ITEM_ADD,
+ data: res.body
+ });
+ AppDispatcher.dispatch({
+ actionType: ListConstants.LIST_UPDATE_COUNT,
+ increment: 1
});
} else {
console.error(err.toString());
console.error(res.body);
+ this.error(res.body);
}
});
}
-};
-export const save = (id, title, list) => {
- return (dispatch) => {
+ save(item, text) {
request()
- .patch(serverURLs.list_item + id + "/")
- .send({title: title})
+ .patch(serverURLs.list_item + item.id + "/")
+ .send({ title: text })
.end((err, res) => {
if (!err && res) {
- dispatch({
- type: ItemConstants.ITEM_SAVE,
- list: list,
- id: id,
- title: res.body.title
+ AppDispatcher.dispatch({
+ actionType: ItemConstants.ITEM_SAVE,
+ item: item,
+ text: res.body.title
});
} else {
console.error(err.toString());
console.error(res.body);
+ this.error(res.body);
}
});
}
-};
-export const toggle = (id, completed, list) => {
- return (dispatch) => {
+ toggle(item) {
request()
- .patch(serverURLs.list_item + id + "/")
- .send({completed: completed})
+ .patch(serverURLs.list_item + item.id + "/")
+ .send({ completed: !item.completed })
.end((err, res) => {
if (!err && res) {
- dispatch({
- type: ItemConstants.ITEM_TOGGLE,
- list: list,
- id: id,
+ AppDispatcher.dispatch({
+ actionType: ItemConstants.ITEM_TOGGLE,
+ item: item,
});
} else {
console.error(err.toString());
console.error(res.body);
+ this.error(res.body);
}
});
}
-};
-export const toggleAll = (items, event, list) => {
- let ids = items.reduce(function (list, item) {
- if (item.completed !== event.target.checked) {
- list.push({
- id: item.id,
- completed: event.target.checked
- });
- }
- return list;
- }, []);
-
- return (dispatch) => {
+ toggleAll(checked) {
request()
.patch(serverURLs.bulk_list_item)
- .send(ids)
+ .send(ItemStore.getToogleItems(checked))
.end((err, res) => {
if (!err && res) {
- dispatch({
- type: ItemConstants.ITEM_TOGGLE_ALL,
- list: list,
- ids: ids
+ AppDispatcher.dispatch({
+ actionType: ItemConstants.ITEM_TOGGLE_ALL,
+ checked: checked
});
} else {
console.error(err.toString());
console.error(res.body);
+ this.error(res.body);
}
});
}
-};
-export const destroy = (id, list) => {
- return (dispatch) => {
+ destroy(item) {
request()
- .delete(serverURLs.list_item + id + "/")
+ .delete(serverURLs.list_item + item.id + "/")
.end((err, res) => {
if (!err && res) {
- dispatch({
- type: ItemConstants.ITEM_DELETE,
- id: id,
- list: list,
+ AppDispatcher.dispatch({
+ actionType: ItemConstants.ITEM_DELETE,
+ item: item,
+ });
+ AppDispatcher.dispatch({
+ actionType: ListConstants.LIST_UPDATE_COUNT,
+ increment: -1
});
} else {
console.error(err.toString());
console.error(res.body);
+ this.error(res.body);
}
});
}
-};
-
-export const clearCompleted = (items, event, list) => {
- let ids = items.reduce(function (list, item) {
- if (item.completed === true) {
- list.push(item.id);
- }
- return list;
- }, []);
- return (dispatch) => {
+ clearCompleted() {
+ var ids = ItemStore.getCheckedItems();
request()
.delete(serverURLs.bulk_list_item)
.send(ids)
.end((err, res) => {
if (!err && res) {
- dispatch({
- type: ItemConstants.ITEM_DELETE_COMPLETED,
- list: list,
- ids: ids,
+ AppDispatcher.dispatch({
+ actionType: ItemConstants.ITEM_DELETE_COMPLETED,
+ });
+ AppDispatcher.dispatch({
+ actionType: ListConstants.LIST_UPDATE_COUNT,
+ increment: -ids.length
});
} else {
console.error(err.toString());
console.error(res.body);
+ this.error(res.body);
}
});
}
-};
+
+ init(id, list) {
+ AppDispatcher.dispatch({
+ actionType: ItemConstants.ITEM_INIT,
+ id: id,
+ list: list
+ });
+ }
+}
+
+const ItemAction = new ItemActions();
+
+export default ItemAction;
diff --git a/frontend/modules/list/actions/ListActions.js b/frontend/modules/list/actions/ListActions.js
index 3557e0e3..d3268f09 100644
--- a/frontend/modules/list/actions/ListActions.js
+++ b/frontend/modules/list/actions/ListActions.js
@@ -1,83 +1,101 @@
import { request } from '../../common/CustomSuperagent';
import { serverURLs } from '../../common/config'
+import AppDispatcher from '../../common/AppDispatcher';
import ListConstants from '../constants/ListConstants';
-import history from '../../common/history'
-export const add = (title) => {
- return (dispatch) => {
+class ListActions {
+ add(title) {
request()
.post(serverURLs.list)
- .send({title: title})
+ .send({ title: title })
.end((err, res) => {
if (!err && res) {
- dispatch({
- type: ListConstants.LIST_ADD,
+ AppDispatcher.dispatch({
+ actionType: ListConstants.LIST_ADD,
id: res.body.id,
- title: res.body.title,
- item_count: 0
+ title: res.body.title
});
- history.push('/list/' + res.body.id);
} else {
console.error(err.toString());
console.error(res.body);
+ this.error(res.body);
}
});
}
-};
-export const save = (id, title) => {
- return (dispatch) => {
+ save(id, title) {
request()
.patch(serverURLs.list + id + "/")
- .send({title: title})
+ .send({ title: title })
.end((err, res) => {
if (!err && res) {
- dispatch({
- type: ListConstants.LIST_SAVE,
- id: id,
+ AppDispatcher.dispatch({
+ actionType: ListConstants.LIST_SAVE,
title: res.body.title
});
} else {
console.error(err.toString());
console.error(res.body);
+ this.error(res.body);
}
});
}
-};
-export const destroy = (id) => {
- return (dispatch) => {
+ destroy(id) {
request()
.delete(serverURLs.list + id + "/")
.end((err, res) => {
if (!err && res) {
- history.push('/list/');
- dispatch({
- type: ListConstants.LIST_DELETE,
+ AppDispatcher.dispatch({
+ actionType: ListConstants.LIST_DELETE,
id: id,
});
} else {
console.error(err.toString());
console.error(res.body);
+ this.error(res.body);
}
});
}
-};
-export const load = () => {
- return (dispatch) => {
+ load(id) {
+ request()
+ .get(serverURLs.list + id + '/')
+ .end((err, res) => {
+ if (!err && res) {
+ AppDispatcher.dispatch({
+ actionType: ListConstants.LIST_INIT,
+ id: res.body.id,
+ title: res.body.title,
+ item_count: res.body.item_count
+ });
+ } else {
+ console.error(err.toString());
+ console.error(res.body);
+ this.error(res.body);
+ }
+ });
+ }
+
+ init(active_list_id) {
request()
.get(serverURLs.list)
.end((err, res) => {
if (!err && res) {
- dispatch({
- type: ListConstants.LIST_INIT,
+ AppDispatcher.dispatch({
+ actionType: ListConstants.LIST_INIT,
lists: res.body.results,
+ active_list_id: active_list_id,
});
} else {
console.error(err.toString());
- // console.error(res.body);
+ console.error(res.body);
+ this.error(res.body);
}
});
}
-};
+}
+
+const ListAction = new ListActions();
+
+export default ListAction;
diff --git a/frontend/modules/list/components/AddItem.js b/frontend/modules/list/components/AddItem.js
deleted file mode 100755
index 95d45e1d..00000000
--- a/frontend/modules/list/components/AddItem.js
+++ /dev/null
@@ -1,65 +0,0 @@
-"use strict";
-
-import React from 'react'
-import PropTypes from 'prop-types'
-import { injectIntl, defineMessages } from 'react-intl'
-
-import {
- ENTER_KEY
-} from '../constants/ListStatus'
-
-class AddItem extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- title: '',
- };
- }
-
- handleChange = (event) => {
- this.setState({title: event.target.value});
- };
-
- handleKeyDown = (event) => {
- if (event.keyCode !== ENTER_KEY) {
- return;
- }
-
- event.preventDefault();
- let val = this.state.title.trim();
- if (val) {
- this.props.addItem(val);
- this.setState({title: ''});
- }
- };
-
- render() {
- const {formatMessage} = this.props.intl;
- const messages = defineMessages({
- item: {
- id: 'list.new-input-placeholder',
- description: 'Placeholder for inputting new items',
- defaultMessage: 'What do you need to buy?',
- },
- });
-
- return (
-
- )
- }
-}
-
-AddItem.propTypes = {
- addItem: PropTypes.func.isRequired,
- intl: PropTypes.object.isRequired
-};
-
-export default injectIntl(AddItem)
diff --git a/frontend/modules/list/components/Error.js b/frontend/modules/list/components/Error.js
deleted file mode 100755
index 3edd3e69..00000000
--- a/frontend/modules/list/components/Error.js
+++ /dev/null
@@ -1,32 +0,0 @@
-"use strict";
-
-import React from 'react'
-import PropTypes from 'prop-types'
-import { injectIntl, defineMessages } from 'react-intl'
-
-const Error = ({message, intl}) => {
- const messages = defineMessages({
- error: {
- id: 'list.error.message',
- description: 'Error!',
- defaultMessage: 'Something went wrong!',
- }
- });
-
- return (
-
-
-
- { intl.formatMessage(messages.error) }:
- { message }
-
-
- );
-};
-
-Error.propTypes = {
- message: PropTypes.string.isRequired,
- intl: PropTypes.object.isRequired
-};
-
-export default injectIntl(Error)
diff --git a/frontend/modules/list/components/GroceryList.js b/frontend/modules/list/components/GroceryList.js
index 1d47e78f..6a03666c 100644
--- a/frontend/modules/list/components/GroceryList.js
+++ b/frontend/modules/list/components/GroceryList.js
@@ -1,19 +1,60 @@
-"use strict";
-
import React from 'react'
-import PropTypes from 'prop-types'
import { injectIntl, defineMessages } from 'react-intl'
-import Items from '../containers/Items'
-import MyLists from './MyLists'
-import ListHeader from './ListHeader'
-import NewList from './NewList'
-import Error from './Error'
+import AuthStore from '../../account/stores/AuthStore'
+import ListAction from '../actions/ListActions'
+import { ListStore, CHANGE_EVENT, INIT_EVENT } from '../stores/ListStore'
+import ListContainer from '../../list/components/ListContainer'
+import MyLists from '../../list/components/MyLists'
+import ListHeader from '../../list/components/ListHeader'
+import NewList from '../../list/components/NewList'
require("./../css/grocery_list.scss");
-class GroceryList extends React.Component {
- render() {
+export default injectIntl(React.createClass({
+
+ getInitialState: function() {
+ return {
+ lists: ListStore.get_lists() || null,
+ active_list_id: ListStore.get_id() || null,
+ active_list_name: ListStore.get_name() || null,
+ };
+ },
+
+ componentDidMount: function() {
+ ListAction.init(this.props.params.list_id);
+ ListStore.addChangeListener(CHANGE_EVENT, this._onChange);
+ },
+
+ componentWillReceiveProps(nextProps) {
+ ListAction.init(nextProps.params.list_id);
+ },
+
+ componentWillUnmount: function() {
+ ListStore.removeChangeListener(CHANGE_EVENT, this._onChange);
+ },
+
+ _onChange: function() {
+ this.setState({
+ lists: ListStore.get_lists() || null,
+ active_list_id: ListStore.get_id() || null,
+ active_list_name: ListStore.get_name() || null,
+ });
+ },
+
+ addList: function(title) {
+ ListAction.add(title);
+ },
+
+ updateList: function(title) {
+ ListAction.save(this.state.active_list_id, title);
+ },
+
+ removeList: function() {
+ ListAction.destroy(this.state.active_list_id);
+ },
+
+ render: function() {
const { formatMessage } = this.props.intl;
const messages = defineMessages({
my_lists: {
@@ -28,56 +69,38 @@ class GroceryList extends React.Component {
},
});
- let { activeListID, lists, listActions, error } = this.props;
-
- let renderList = '';
- let list = lists.find(t => t.id == activeListID);
- if (activeListID && list) {
- renderList = (
-
+ var render_list = '';
+ if (this.state.active_list_id != null) {
+ render_list = (
+
-
+
{ formatMessage(messages.footer) }
);
} else {
- renderList = (
-
+ render_list = (
+
+
+
);
}
return (
-
- { error ? : '' }
- { renderList }
-
-
);
}
-}
-
-GroceryList.propTypes = {
- lists: PropTypes.arrayOf(PropTypes.shape({
- id: PropTypes.number.isRequired,
- title: PropTypes.string.isRequired,
- item_count: PropTypes.number.isRequired
- }).isRequired).isRequired,
- error: PropTypes.string,
- activeListID: PropTypes.string,
- listActions: PropTypes.object.isRequired,
- intl: PropTypes.object.isRequired,
-};
-
-export default injectIntl(GroceryList)
+}));
diff --git a/frontend/modules/list/components/ListContainer.js b/frontend/modules/list/components/ListContainer.js
new file mode 100755
index 00000000..923b058b
--- /dev/null
+++ b/frontend/modules/list/components/ListContainer.js
@@ -0,0 +1,192 @@
+import React from 'react'
+import { injectIntl, defineMessages } from 'react-intl'
+
+import ItemAction from '../actions/ItemActions'
+import { ItemStore, CHANGE_EVENT, INIT_EVENT } from '../stores/ItemStore'
+import ListFooter from './ListFooter'
+import ListItem from './ListItem'
+
+import {
+ ALL_ITEMS,
+ ACTIVE_ITEMS,
+ COMPLETED_ITEMS,
+ ENTER_KEY
+} from '../constants/ListStatus'
+
+export default injectIntl(React.createClass({
+ getInitialState: function () {
+ return {
+ nowShowing: ALL_ITEMS,
+ editing: null,
+ newItem: '',
+ items: ItemStore.getItems()
+ };
+ },
+
+ componentDidMount: function () {
+ if (this.props.list_id != null) {
+ ItemAction.load_list(this.props.list_id);
+ }
+ ItemStore.addChangeListener(INIT_EVENT, this._onChange);
+ ItemStore.addChangeListener(CHANGE_EVENT, this._onChange);
+ },
+
+ componentWillReceiveProps: function (nextProps) {
+ if (nextProps.list_id != this.props.list_id) {
+ ItemAction.load_list(nextProps.list_id);
+ }
+ },
+
+ componentWillUnmount: function() {
+ ItemStore.removeChangeListener(INIT_EVENT, this._onChange);
+ ItemStore.removeChangeListener(CHANGE_EVENT, this._onChange);
+ },
+
+ _onChange: function () {
+ this.setState({items: ItemStore.getItems()});
+ },
+
+ handleChange: function (event) {
+ this.setState({newItem: event.target.value});
+ },
+
+ handleNewListKeyDown: function (event) {
+ if (event.keyCode !== ENTER_KEY) {
+ return;
+ }
+
+ event.preventDefault();
+
+ var val = this.state.newItem.trim();
+
+ if (val) {
+ ItemAction.addItem(val);
+ this.setState({newItem: ''});
+ }
+ },
+
+ edit: function (item) {
+ this.setState({editing: item.id});
+ },
+
+ save: function (itemToSave, text) {
+ ItemAction.save(itemToSave, text);
+ this.setState({editing: null});
+ },
+
+ cancel: function () {
+ this.setState({editing: null});
+ },
+
+ filter_status: function (status) {
+ this.setState({nowShowing: status});
+ },
+
+ toggle: function (itemToToggle) {
+ ItemAction.toggle(itemToToggle);
+ },
+
+ toggleAll: function (event) {
+ var checked = event.target.checked;
+ ItemAction.toggleAll(checked);
+ },
+
+ destroy: function (item) {
+ ItemAction.destroy(item);
+ },
+
+ clearCompleted: function () {
+ ItemAction.clearCompleted();
+ },
+
+ render: function () {
+ const { formatMessage } = this.props.intl;
+ const messages = defineMessages({
+ item: {
+ id: 'list.new-input-placeholder',
+ description: 'Placeholder for inputting new items',
+ defaultMessage: 'What do you need to buy?',
+ },
+ });
+
+ var footer;
+ var main;
+ var items = this.state.items;
+
+ var shownItems = items.filter(function (item) {
+ switch (this.state.nowShowing) {
+ case ACTIVE_ITEMS:
+ return !item.completed;
+ case COMPLETED_ITEMS:
+ return item.completed;
+ default:
+ return true;
+ }
+ }, this);
+
+ var listItems = shownItems.map(function (item) {
+ return (
+
+ );
+ }, this);
+
+ var activeListCount = items.reduce(function (accum, item) {
+ return item.completed ? accum : accum + 1;
+ }, 0);
+
+ var completedCount = items.length - activeListCount;
+
+ if (activeListCount || completedCount) {
+ footer =
+
;
+ }
+
+ if (items.length) {
+ main = (
+
+ );
+ }
+
+ return (
+
+
+ { main }
+ { footer }
+
+ );
+ }
+}));
diff --git a/frontend/modules/list/components/ListFooter.js b/frontend/modules/list/components/ListFooter.js
index d19b4ae1..093f893f 100755
--- a/frontend/modules/list/components/ListFooter.js
+++ b/frontend/modules/list/components/ListFooter.js
@@ -1,9 +1,7 @@
-"use strict";
-
import React from 'react'
-import PropTypes from 'prop-types'
import classNames from 'classnames'
-import { injectIntl, defineMessages } from 'react-intl'
+
+import { injectIntl, defineMessages } from 'react-intl';
import {
ALL_ITEMS,
@@ -11,93 +9,85 @@ import {
COMPLETED_ITEMS
} from '../constants/ListStatus'
-const ListFooter = ({activeFilter, completedCount, itemCount, onClearCompleted, onFilterStatus, intl }) => {
- const { formatMessage } = intl;
- const messages = defineMessages({
- itemsLeft: {
- id: 'list.footer.items_left',
- description: 'Number of items left',
- defaultMessage: '{itemCount, plural, =0 {No items} one {1 item left} other {{itemCount} items left}}',
- },
- all: {
- id: 'list.footer.all',
- description: 'Show all items',
- defaultMessage: 'All',
- },
- completed: {
- id: 'list.footer.completed',
- description: 'Show only completed items',
- defaultMessage: 'Completed',
- },
- active: {
- id: 'list.footer.active',
- description: 'Show active items',
- defaultMessage: 'Active',
- },
- clearCompleted: {
- id: 'list.footer.clear_completed',
- description: 'Clear all completed list items',
- defaultMessage: 'Clear completed',
- }
- });
+export default injectIntl(React.createClass({
+ render: function () {
+ const { formatMessage } = this.props.intl;
+ const messages = defineMessages({
+ items_left: {
+ id: 'list.footer.items_left',
+ description: 'Number of items left',
+ defaultMessage: '{itemCount, plural, =0 {No items} one {1 item left} other {{itemCount} items left}}',
+ },
+ all: {
+ id: 'list.footer.all',
+ description: 'Show all items',
+ defaultMessage: 'All',
+ },
+ completed: {
+ id: 'list.footer.completed',
+ description: 'Show only completed items',
+ defaultMessage: 'Completed',
+ },
+ active: {
+ id: 'list.footer.active',
+ description: 'Show active items',
+ defaultMessage: 'Active',
+ },
+ clear_completed: {
+ id: 'list.footer.clear_completed',
+ description: 'Clear all completed list items',
+ defaultMessage: 'Clear completed',
+ }
+ });
+
+ var clearButton = null;
+ var nowShowing = this.props.nowShowing;
- let clearButton = null;
+ if (this.props.completedCount > 0) {
+ clearButton = (
+
+ );
+ }
- if (completedCount > 0) {
- clearButton = (
-
+ return (
+
+
+ { formatMessage(messages.items_left, {itemCount: this.props.count}) }
+
+
+ { clearButton }
+
);
}
-
- return (
-
-
- { formatMessage(messages.itemsLeft, {itemCount: itemCount}) }
-
-
- { clearButton }
-
- );
-};
-
-ListFooter.propTypes = {
- itemCount: PropTypes.number.isRequired,
- completedCount: PropTypes.number.isRequired,
- activeFilter: PropTypes.string.isRequired,
- onClearCompleted: PropTypes.func.isRequired,
- onFilterStatus: PropTypes.func.isRequired,
- intl: PropTypes.object.isRequired,
-};
-
-export default injectIntl(ListFooter)
+}));
diff --git a/frontend/modules/list/components/ListHeader.js b/frontend/modules/list/components/ListHeader.js
index db7d406b..44a8e875 100644
--- a/frontend/modules/list/components/ListHeader.js
+++ b/frontend/modules/list/components/ListHeader.js
@@ -1,98 +1,80 @@
-"use strict";
-
import React from 'react'
import classNames from 'classnames'
-import PropTypes from 'prop-types'
-import { injectIntl, defineMessages } from 'react-intl'
import {
ENTER_KEY,
ESCAPE_KEY
} from '../constants/ListStatus'
-class ListHeader extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- title: this.props.list.title || '',
+export default React.createClass({
+ getInitialState: function() {
+ return {
+ title: this.props.title || '',
editing: false,
};
- }
+ },
componentWillReceiveProps(nextProps) {
this.setState({
- title: nextProps.list.title,
+ title: nextProps.title,
editing: false,
});
- }
+ },
- handleDelete = (message) => {
- if (confirm(message)) {
- this.props.removeList(this.props.list.id)
+ delete_list: function () {
+ if (confirm("Are you sure you want to delete this list?")) {
+ this.props.removeList()
}
- };
+ },
- handleEdit = () => {
+ handleEdit: function () {
this.setState({editing: true});
- };
+ },
- handleChange = (event) => {
+ handleChange: function (event) {
if (this.state.editing) {
this.setState({title: event.target.value});
}
- };
+ },
- handleKeyDown = (event) => {
+ handleKeyDown: function (event) {
if (event.which === ESCAPE_KEY) {
this.setState({
- title: this.props.list.title,
+ title: this.props.title,
editing: false,
});
} else if (event.which === ENTER_KEY) {
this.handleSubmit(event);
}
- };
+ },
- handleSubmit = () => {
- let val = this.state.title.trim();
+ handleSubmit: function (event) {
+ var val = this.state.title.trim();
if (val) {
- this.props.updateList(this.props.list.id, val);
+ this.props.updateList(val);
this.setState({
- title: val,
+ editText: val,
editing: false,
});
} else {
this.setState({
- title: this.props.list.title,
+ editText: this.props.title,
editing: false,
});
}
- };
-
- render() {
- const { formatMessage } = this.props.intl;
- const messages = defineMessages({
- confirmDelete: {
- id: 'list_header.confirm_delete',
- description: 'Are you sure you want to delete this list?',
- defaultMessage: 'Are you sure you want to delete this list?',
- },
- });
+ },
+ render: function() {
return (
-
)
}
-}
-
-ListHeader.propTypes = {
- list: PropTypes.shape({
- id: PropTypes.number.isRequired,
- title: PropTypes.string.isRequired,
- item_count: PropTypes.number.isRequired
- }).isRequired,
- removeList: PropTypes.func.isRequired,
- updateList: PropTypes.func.isRequired,
- intl: PropTypes.object.isRequired,
-};
-
-export default injectIntl(ListHeader)
+});
diff --git a/frontend/modules/list/components/ListItem.js b/frontend/modules/list/components/ListItem.js
index 5a165d54..64ca75ef 100755
--- a/frontend/modules/list/components/ListItem.js
+++ b/frontend/modules/list/components/ListItem.js
@@ -1,67 +1,47 @@
-"use strict";
-
import React from 'react'
-import PropTypes from 'prop-types'
import classNames from 'classnames'
-import { injectIntl, defineMessages } from 'react-intl'
import {
ENTER_KEY,
ESCAPE_KEY
} from '../constants/ListStatus'
-class ListItem extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- title: this.props.item.title
- };
- }
-
- handleSubmit = (event) => {
- let val = this.state.title.trim();
+export default React.createClass({
+ handleSubmit: function (event) {
+ var val = this.state.editText.trim();
if (val) {
- this.props.onSave(this.props.item.id, val);
- this.props.onToggleEdit(null);
- this.setState({title: val});
+ this.props.onSave(val);
+ this.setState({editText: val});
} else {
- this.handleDestroy();
+ this.props.onDestroy();
}
- };
+ },
- handleEdit = () => {
- this.props.onToggleEdit(this.props.item.id);
- this.setState({title: this.props.item.title});
- };
+ handleEdit: function () {
+ this.props.onEdit();
+ this.setState({editText: this.props.item.title});
+ },
- handleDestroy = () => {
- this.props.onDestroy(this.props.item.id);
- };
-
- handleKeyDown = (event) => {
+ handleKeyDown: function (event) {
if (event.which === ESCAPE_KEY) {
- this.setState({title: this.props.item.title});
- this.props.onToggleEdit(null);
+ this.setState({editText: this.props.item.title});
+ this.props.onCancel(event);
} else if (event.which === ENTER_KEY) {
this.handleSubmit(event);
}
- };
+ },
- handleChange = (event) => {
+ handleChange: function (event) {
if (this.props.editing) {
- this.setState({title: event.target.value});
+ this.setState({editText: event.target.value});
}
- };
+ },
- handleToggle = () => {
- this.props.onToggle(
- this.props.item.id,
- !this.props.item.completed
- );
- };
+ getInitialState: function () {
+ return {editText: this.props.item.title};
+ },
- render() {
+ render: function () {
return (
-
- { this.props.item.title }
+
+ {this.props.item.title}
-
+
);
}
-}
-
-ListItem.propTypes = {
- item: PropTypes.shape({
- id: PropTypes.number.isRequired,
- title: PropTypes.string.isRequired,
- completed: PropTypes.bool.isRequired
- }).isRequired,
- onSave: PropTypes.func.isRequired,
- onDestroy: PropTypes.func.isRequired,
- onToggleEdit: PropTypes.func.isRequired,
- intl: PropTypes.object.isRequired,
-};
-
-export default injectIntl(ListItem)
+});
diff --git a/frontend/modules/list/components/ListItems.js b/frontend/modules/list/components/ListItems.js
deleted file mode 100755
index 85c406cd..00000000
--- a/frontend/modules/list/components/ListItems.js
+++ /dev/null
@@ -1,121 +0,0 @@
-"use strict";
-
-import React from 'react'
-import PropTypes from 'prop-types'
-import { injectIntl, defineMessages } from 'react-intl'
-
-import ListFooter from './ListFooter'
-import ListItem from './ListItem'
-import AddItem from './AddItem'
-
-import {
- ALL_ITEMS,
- ACTIVE_ITEMS,
- COMPLETED_ITEMS
-} from '../constants/ListStatus'
-
-class ListItems extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- nowShowing: ALL_ITEMS,
- editing: null,
- };
- }
-
- toggleEdit = (id) => {
- this.setState({editing: id});
- };
-
- filterStatus = (status) => {
- this.setState({nowShowing: status});
- };
-
- render() {
- let footer;
- let main;
- let items = this.props.items;
-
- let shownItems = items.filter(function (item) {
- switch (this.state.nowShowing) {
- case ACTIVE_ITEMS:
- return !item.completed;
- case COMPLETED_ITEMS:
- return item.completed;
- default:
- return true;
- }
- }, this);
-
- let listItems = shownItems.map(function (item) {
- return (
-
- );
- }, this);
-
- let activeListCount = items.reduce(function (accum, item) {
- return item.completed ? accum : accum + 1;
- }, 0);
-
- let completedCount = items.length - activeListCount;
-
- if (activeListCount || completedCount) {
- footer =
-
;
- }
-
- if (items.length) {
- main = (
-
- );
- }
-
- return (
-
-
- { main }
- { footer }
-
- );
- }
-}
-
-ListItems.propTypes = {
- items: PropTypes.arrayOf(PropTypes.shape({
- id: PropTypes.number.isRequired,
- title: PropTypes.string.isRequired,
- completed: PropTypes.bool.isRequired
- }).isRequired).isRequired,
- activeListID: PropTypes.string,
- itemActions: PropTypes.object.isRequired,
- intl: PropTypes.object.isRequired,
-};
-
-export default injectIntl(ListItems)
diff --git a/frontend/modules/list/components/MyLists.js b/frontend/modules/list/components/MyLists.js
index 58e19e79..51bde274 100755
--- a/frontend/modules/list/components/MyLists.js
+++ b/frontend/modules/list/components/MyLists.js
@@ -1,77 +1,60 @@
-"use strict";
-
import React from 'react'
-import PropTypes from 'prop-types'
-import { NavLink } from 'react-router-dom'
+import { Link } from 'react-router'
import { injectIntl, defineMessages } from 'react-intl'
-const MyLists = ({title, lists, intl}) => {
- const messages = defineMessages({
- no_lists: {
- id: 'my_lists.no_lists',
- description: 'No Lists to display',
- defaultMessage: 'No Lists to display',
- },
- new_list: {
- id: 'my_lists.new_list',
- description: 'Create a New List!',
- defaultMessage: 'Create a New List!',
- },
- });
+export default injectIntl(React.createClass({
+ render: function () {
+ const { formatMessage } = this.props.intl;
+ const messages = defineMessages({
+ no_lists: {
+ id: 'my_lists.no_lists',
+ description: 'No Lists to display',
+ defaultMessage: 'No Lists to display',
+ },
+ new_list: {
+ id: 'my_lists.new_list',
+ description: 'Create a New List!',
+ defaultMessage: 'Create a New List!',
+ },
+ });
+
+ if (this.props.data == null || this.props.data.length == 0) {
+ return (
+
+ );
+ }
+
+ var items = this.props.data.map(function(item) {
+ var link = '/list/' + item.id;
+ return (
+
+
{ item.item_count }
+ { item.title }
+
+ );
+ });
- if (lists === null || lists.length === 0) {
return (
+
+
);
}
-
- let items = lists.map(function(item) {
- let link = '/list/' + item.id;
- return (
-
- { item.item_count }
- { item.title }
-
- );
- });
-
- return (
-
-
-
- { title }
-
- { items }
-
- { intl.formatMessage(messages.new_list) }
-
-
-
- );
-};
-
-MyLists.propTypes = {
- title: PropTypes.string.isRequired,
- intl: PropTypes.object.isRequired,
- lists: PropTypes.arrayOf(PropTypes.shape({
- id: PropTypes.number.isRequired,
- title: PropTypes.string.isRequired,
- item_count: PropTypes.number.isRequired
- }).isRequired).isRequired,
-};
-
-export default injectIntl(MyLists)
+}));
diff --git a/frontend/modules/list/components/NewList.js b/frontend/modules/list/components/NewList.js
index 80e90a3e..063ed09c 100755
--- a/frontend/modules/list/components/NewList.js
+++ b/frontend/modules/list/components/NewList.js
@@ -1,38 +1,33 @@
-"use strict";
-
import React from 'react'
-import PropTypes from 'prop-types'
import { injectIntl, defineMessages } from 'react-intl'
import { ENTER_KEY } from '../constants/ListStatus'
-class NewList extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- title: this.props.title || '',
+export default injectIntl(React.createClass({
+ getInitialState: function() {
+ return {
+ value: this.props.value || '',
};
- }
+ },
- handleChange = (event) => {
- this.setState({title: event.target.value});
- };
+ handleChange: function (event) {
+ this.setState({value: event.target.value});
+ },
- handleKeyDown = (event) => {
+ handleKeyDown: function (event) {
if (event.which === ENTER_KEY) {
this.handleSubmit(event);
}
- };
+ },
- handleSubmit = () => {
- let val = this.state.title.trim();
+ handleSubmit: function (event) {
+ var val = this.state.value.trim();
if (val) {
this.props.addList(val);
}
- };
+ },
- render() {
+ render: function() {
const { formatMessage } = this.props.intl;
const messages = defineMessages({
header: {
@@ -62,7 +57,7 @@ class NewList extends React.Component {
autoFocus="true"
className="form-control"
placeholder={ formatMessage(messages.placeholder) }
- value={ this.state.title }
+ value={ this.state.value }
onChange={ this.handleChange }
onKeyDown={ this.handleKeyDown }
/>
@@ -73,13 +68,5 @@ class NewList extends React.Component {
>{ formatMessage(messages.button) }
)
- };
-}
-
-NewList.propTypes = {
- title: PropTypes.string,
- intl: PropTypes.object.isRequired,
- addList: PropTypes.func.isRequired,
-};
-
-export default injectIntl(NewList)
+ }
+}));
diff --git a/frontend/modules/list/constants/ErrorConstants.js b/frontend/modules/list/constants/ErrorConstants.js
deleted file mode 100644
index 3dfb736a..00000000
--- a/frontend/modules/list/constants/ErrorConstants.js
+++ /dev/null
@@ -1,4 +0,0 @@
-export default {
- LIST_ERROR_ADD: 'LIST_ERROR_ADD',
- LIST_ERROR_REMOVE: 'LIST_ERROR_REMOVE',
-};
\ No newline at end of file
diff --git a/frontend/modules/list/constants/ItemConstants.js b/frontend/modules/list/constants/ItemConstants.js
index ef4a9687..7be12463 100644
--- a/frontend/modules/list/constants/ItemConstants.js
+++ b/frontend/modules/list/constants/ItemConstants.js
@@ -1,10 +1,11 @@
-export default {
- ITEM_INIT: 'LIST_ITEM_INIT',
- ITEM_ADD: 'LIST_ITEM_ADD',
- ITEM_SAVE: 'LIST_ITEM_SAVE',
- ITEM_TOGGLE: 'LIST_ITEM_TOGGLE',
- ITEM_TOGGLE_ALL: 'LIST_ITEM_TOGGLE_ALL',
- ITEM_DELETE: 'LIST_ITEM_DELETE',
- ITEM_DELETE_COMPLETED: 'LIST_ITEM_DELETE_COMPLETED',
- ITEM_INDEX: 'ITEM',
-};
\ No newline at end of file
+import keyMirror from 'keymirror';
+
+export default keyMirror({
+ ITEM_INIT: null,
+ ITEM_ADD: null,
+ ITEM_SAVE: null,
+ ITEM_TOGGLE: null,
+ ITEM_TOGGLE_ALL: null,
+ ITEM_DELETE: null,
+ ITEM_DELETE_COMPLETED: null,
+});
\ No newline at end of file
diff --git a/frontend/modules/list/constants/ListConstants.js b/frontend/modules/list/constants/ListConstants.js
index 7b3aeb82..613a6ecd 100644
--- a/frontend/modules/list/constants/ListConstants.js
+++ b/frontend/modules/list/constants/ListConstants.js
@@ -1,7 +1,9 @@
-export default {
- LIST_INIT: 'LIST_INIT',
- LIST_ADD: 'LIST_ADD',
- LIST_SAVE: 'LIST_SAVE',
- // LIST_UPDATE_COUNT: 'LIST_UPDATE_COUNT',
- LIST_DELETE: 'LIST_DELETE',
-};
\ No newline at end of file
+import keyMirror from 'keymirror';
+
+export default keyMirror({
+ LIST_INIT: null,
+ LIST_ADD: null,
+ LIST_SAVE: null,
+ LIST_UPDATE_COUNT: null,
+ LIST_DELETE: null,
+});
\ No newline at end of file
diff --git a/frontend/modules/list/containers/Items.js b/frontend/modules/list/containers/Items.js
deleted file mode 100644
index 9ce30c43..00000000
--- a/frontend/modules/list/containers/Items.js
+++ /dev/null
@@ -1,70 +0,0 @@
-"use strict";
-
-import React from 'react'
-import PropTypes from 'prop-types'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import bindIndexToActionCreators from '../../common/bindIndexToActionCreators'
-import ListItems from '../components/ListItems'
-import * as ItemActions from '../actions/ItemActions'
-
-class Items extends React.Component {
- constructor(props) {
- super(props);
- }
-
- componentDidMount() {
- if (this.props.activeListID) {
- this.props.itemActions.load(this.props.activeListID);
- }
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.activeListID != this.props.activeListID) {
- this.props.itemActions.load(nextProps.activeListID);
- }
- }
-
- render() {
- let { activeListID, items, itemActions } = this.props;
- return (
-
- )
- }
-}
-
-Items.propTypes = {
- activeListID: PropTypes.string.isRequired,
- items: PropTypes.array.isRequired,
- itemActions: PropTypes.object.isRequired
-};
-
-const getItemsFromList = (lists, listId) => {
- let list = lists.find(t => t.id == listId);
- if (list) {
- return list.items
- }
-
- return []
-};
-
-const mapStateToProps = (state, props) => ({
- items: getItemsFromList(state.list.lists, props.activeListID)
-});
-
-const mapDispatchToProps = (dispatch, props) => ({
- itemActions: bindActionCreators(
- bindIndexToActionCreators(ItemActions, props.activeListID),
- dispatch
- ),
-});
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(Items);
diff --git a/frontend/modules/list/containers/List.js b/frontend/modules/list/containers/List.js
deleted file mode 100644
index 8e3ef3c8..00000000
--- a/frontend/modules/list/containers/List.js
+++ /dev/null
@@ -1,60 +0,0 @@
-"use strict";
-
-import React from 'react'
-import PropTypes from 'prop-types'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import authCheckRedirect from '../../common/authCheckRedirect'
-import GroceryList from '../components/GroceryList'
-import * as ListActions from '../actions/ListActions'
-
-class List extends React.Component {
- constructor(props) {
- super(props);
- }
-
- componentDidMount() {
- authCheckRedirect();
- this.props.listActions.load();
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.lists.length > 0 && nextProps.match.params.listId) {
- if (!(nextProps.lists.find(t => t.id == nextProps.match.params.listId))) {
- this.props.history.push('/list/');
- }
- }
- }
-
- render() {
- let { match, lists, listActions } = this.props;
- return (
-
- )
- }
-}
-
-List.propTypes = {
- lists: PropTypes.array.isRequired,
- match: PropTypes.object.isRequired,
- listActions: PropTypes.object.isRequired,
-};
-
-const mapStateToProps = state => ({
- lists: state.list.lists,
- error: state.list.error,
-});
-
-const mapDispatchToProps = dispatch => ({
- listActions: bindActionCreators(ListActions, dispatch),
-});
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(List);
diff --git a/frontend/modules/list/css/_error.scss b/frontend/modules/list/css/_error.scss
deleted file mode 100644
index 22f68927..00000000
--- a/frontend/modules/list/css/_error.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-
-.list-error {
- margin-top: 20px;
-}
diff --git a/frontend/modules/list/css/_list.scss b/frontend/modules/list/css/_list.scss
index 467e036f..b450885f 100644
--- a/frontend/modules/list/css/_list.scss
+++ b/frontend/modules/list/css/_list.scss
@@ -128,7 +128,6 @@
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
- top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
@@ -140,9 +139,6 @@
&:checked:after {
content: url('data:image/svg+xml;utf8,
');
}
- &:focus{
- outline:0;
- }
}
label {
white-space: pre-line;
diff --git a/frontend/modules/list/css/grocery_list.scss b/frontend/modules/list/css/grocery_list.scss
index f246834e..51fbc7a3 100644
--- a/frontend/modules/list/css/grocery_list.scss
+++ b/frontend/modules/list/css/grocery_list.scss
@@ -4,4 +4,3 @@
@import '_footer';
@import '_list_header';
@import '_list';
-@import '_error';
diff --git a/frontend/modules/list/reducers/ErrorReducer.js b/frontend/modules/list/reducers/ErrorReducer.js
deleted file mode 100644
index a31c0e11..00000000
--- a/frontend/modules/list/reducers/ErrorReducer.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import ErrorConstants from '../constants/ErrorConstants'
-
-const lists = (state = '', action) => {
- switch (action.type) {
- case ErrorConstants.LIST_ERROR_ADD:
- return action.error;
- case ErrorConstants.LIST_ERROR_REMOVE:
- return '';
- default:
- return state
- }
-};
-
-export default lists
diff --git a/frontend/modules/list/reducers/GroceryListReducer.js b/frontend/modules/list/reducers/GroceryListReducer.js
deleted file mode 100644
index 2e632986..00000000
--- a/frontend/modules/list/reducers/GroceryListReducer.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { combineReducers } from 'redux'
-import { default as lists } from './ListReducer'
-import { default as error } from './ErrorReducer'
-
-const list = combineReducers({
- lists,
- error
-});
-
-export default list
diff --git a/frontend/modules/list/reducers/ItemReducer.js b/frontend/modules/list/reducers/ItemReducer.js
deleted file mode 100644
index 2cab49f2..00000000
--- a/frontend/modules/list/reducers/ItemReducer.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import ItemConstants from '../constants/ItemConstants'
-
-const items = (state = [], action) => {
- switch (action.type) {
- case ItemConstants.ITEM_INIT:
- return action.items.map(listItem => {
- return { ...listItem }
- });
- case ItemConstants.ITEM_ADD:
- return [
- ...state,
- { ...action, completed: false }
- ];
- case ItemConstants.ITEM_SAVE:
- return state.map(item =>
- item.id === action.id ?
- { ...item, title: action.title } :
- item
- );
- case ItemConstants.ITEM_TOGGLE:
- return state.map(item =>
- item.id === action.id ?
- { ...item, completed: !item.completed } :
- item
- );
- case ItemConstants.ITEM_TOGGLE_ALL:
- let ids = [];
- for (let i in action.ids) {
- ids.push(action.ids[i].id)
- }
-
- return state.map(item =>
- ids.indexOf(item.id) > -1 ?
- { ...item, completed: !item.completed } :
- item
- );
- case ItemConstants.ITEM_DELETE:
- return state.filter(t => t.id !== action.id);
- case ItemConstants.ITEM_DELETE_COMPLETED:
- return state.filter(t => !(action.ids.indexOf(t.id) > -1));
- default:
- return state
- }
-};
-
-export default items
diff --git a/frontend/modules/list/reducers/ListReducer.js b/frontend/modules/list/reducers/ListReducer.js
deleted file mode 100644
index b59dd32d..00000000
--- a/frontend/modules/list/reducers/ListReducer.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import ListConstants from '../constants/ListConstants'
-import ItemConstants from '../constants/ItemConstants'
-import { default as items } from './ItemReducer'
-
-const lists = (state = [], action) => {
- switch (action.type) {
- case ListConstants.LIST_INIT:
- return action.lists.map(list => {
- let items = state.find(t => t.id === list.id);
- items = items ? items.items : [];
- return {...list, items: items}
- });
- case ListConstants.LIST_ADD:
- return [
- ...state,
- { ...action, items: [] }
- ];
- case ListConstants.LIST_SAVE:
- return state.map(list =>
- list.id === action.id ?
- { ...list, title: action.title } :
- list
- );
- case ListConstants.LIST_DELETE:
- return state.filter(t => t.id !== action.id);
- case (action.type.indexOf(ItemConstants.ITEM_INDEX) !== -1 ? action.type : '') :
- return state.map(list => {
- if (list.id == action.list){
- let newItems = items(list.items, action);
- return { ...list, items: newItems, item_count: newItems.length };
- }
- return list;
- });
- default:
- return state
- }
-};
-
-export default lists
diff --git a/frontend/modules/list/stores/ItemStore.js b/frontend/modules/list/stores/ItemStore.js
new file mode 100644
index 00000000..d0402ce9
--- /dev/null
+++ b/frontend/modules/list/stores/ItemStore.js
@@ -0,0 +1,143 @@
+import { EventEmitter } from 'events';
+
+import AppDispatcher from '../../common/AppDispatcher';
+import ItemConstants from '../constants/ItemConstants';
+
+export const INIT_EVENT = 'init';
+export const CHANGE_EVENT = 'change';
+export const ERROR_EVENT = 'error';
+
+var _key = '';
+var _items = [];
+
+class ItemStoreClass extends EventEmitter {
+ emitInit() {
+ this.emit(INIT_EVENT);
+ }
+
+ emitChange() {
+ this.emit(CHANGE_EVENT);
+ }
+
+ emitError() {
+ this.emit(ERROR_EVENT);
+ }
+
+ addChangeListener(event, callback) {
+ this.on(event, callback)
+ }
+
+ removeChangeListener(event, callback) {
+ this.removeListener(event, callback)
+ }
+
+ getItems() {
+ return _items;
+ }
+
+ getKey() {
+ return _key;
+ }
+
+ getToogleItems(checked) {
+ return _items.reduce(function (list, item) {
+ if (item.completed != checked) {
+ list.push({
+ id: item.id,
+ completed: checked
+ });
+ }
+ return list;
+ }, []);
+ }
+
+ getCheckedItems() {
+ return _items.reduce(function (list, item) {
+ if (item.completed == true) {
+ list.push(item.id);
+ }
+ return list;
+ }, []);
+ }
+}
+
+const ItemStore = new ItemStoreClass();
+
+// Here we register a callback for the dispatcher
+// and look for our various action types so we can
+// respond appropriately
+ItemStore.dispatchToken = AppDispatcher.register(action => {
+
+ switch (action.actionType) {
+
+ case ItemConstants.ITEM_INIT:
+ _key = action.id;
+ _items = action.list.results.map(function (item) {
+ return {
+ id: item.id,
+ title: item.title,
+ completed: item.completed
+ };
+ });
+ ItemStore.emitInit();
+ break;
+
+ case ItemConstants.ITEM_ADD:
+ _items = _items.concat({
+ id: action.data.id,
+ title: action.data.title,
+ completed: action.data.completed
+ });
+ ItemStore.emitChange();
+ break;
+
+ case ItemConstants.ITEM_SAVE:
+ _items = _items.map(function (item) {
+ if (item.id == action.item.id) {
+ item.title = action.text
+ }
+ return item;
+ });
+ ItemStore.emitChange();
+ break;
+
+ case ItemConstants.ITEM_TOGGLE:
+ _items = _items.map(function (item) {
+ if (item.id == action.item.id) {
+ item.completed = !item.completed
+ }
+ return item;
+ });
+ ItemStore.emitChange();
+ break;
+
+ case ItemConstants.ITEM_TOGGLE_ALL:
+ // Note: it's usually better to use immutable data structures since they're
+ // easier to reason about and React works very well with them. That's why
+ // we use map() and filter() everywhere instead of mutating the array themselves.
+ _items = _items.map(function (item) {
+ item.completed = action.checked;
+ return item;
+ });
+ ItemStore.emitChange();
+ break;
+
+ case ItemConstants.ITEM_DELETE:
+ _items = _items.filter(function (candidate) {
+ return candidate.id !== action.item.id;
+ });
+ ItemStore.emitChange();
+ break;
+
+ case ItemConstants.ITEM_DELETE_COMPLETED:
+ _items = _items.filter(function (item) {
+ return !item.completed;
+ });
+ ItemStore.emitChange();
+ break;
+
+ default:
+ }
+});
+
+module.exports.ItemStore = ItemStore;
diff --git a/frontend/modules/list/stores/ListStore.js b/frontend/modules/list/stores/ListStore.js
new file mode 100644
index 00000000..6f3b95eb
--- /dev/null
+++ b/frontend/modules/list/stores/ListStore.js
@@ -0,0 +1,123 @@
+import { EventEmitter } from 'events';
+import { browserHistory } from 'react-router'
+
+import AppDispatcher from '../../common/AppDispatcher';
+import ListConstants from '../constants/ListConstants';
+
+export const INIT_EVENT = 'init';
+export const CHANGE_EVENT = 'change';
+export const ERROR_EVENT = 'error';
+
+var _lists = '';
+var _list_id = '';
+var _list_name = '';
+
+class ListStoreClass extends EventEmitter {
+ emitInit() {
+ this.emit(INIT_EVENT);
+ }
+
+ emitChange() {
+ this.emit(CHANGE_EVENT);
+ }
+
+ emitError() {
+ this.emit(ERROR_EVENT);
+ }
+
+ addChangeListener(event, callback) {
+ this.on(event, callback)
+ }
+
+ removeChangeListener(event, callback) {
+ this.removeListener(event, callback)
+ }
+
+ get_id() {
+ return _list_id
+ }
+
+ get_name() {
+ return _list_name
+ }
+
+ get_lists() {
+ return _lists
+ }
+}
+
+const ListStore = new ListStoreClass();
+
+// Here we register a callback for the dispatcher
+// and look for our various action types so we can
+// respond appropriately
+ListStore.dispatchToken = AppDispatcher.register(action => {
+
+ switch(action.actionType) {
+
+ case ListConstants.LIST_INIT:
+ _list_id = action.active_list_id;
+ _lists = action.lists;
+ var list = _lists.filter(function(list) {
+ if (list.id == _list_id) {
+ return list;
+ }
+ });
+ if (list.length > 0) {
+ _list_name = list[0].title;
+ } else if (action.active_list_id > 0) {
+ browserHistory.replace('/list/');
+ }
+ ListStore.emitChange();
+ break;
+
+ case ListConstants.LIST_ADD:
+ _list_id = action.id;
+ _list_name = action.title;
+ ListStore.emitChange();
+ browserHistory.push('/list/' + _list_id);
+ break;
+
+ case ListConstants.LIST_SAVE:
+ _lists = _lists.map(function(list) {
+ if (list.id == _list_id) {
+ list.title = action.title;
+ }
+ return list;
+ });
+ _list_name = action.title;
+ ListStore.emitChange();
+ break;
+
+ case ListConstants.LIST_UPDATE_COUNT:
+ _lists = _lists.map(function(list) {
+ if (list.id == _list_id) {
+ list.item_count += action.increment;
+ }
+ return list;
+ });
+ ListStore.emitChange();
+ break;
+
+ case ListConstants.LIST_DELETE:
+ var remaining_lists = _lists.filter(function(list) {
+ if (action.id != list.id) {
+ return list;
+ }
+ });
+ _lists = remaining_lists;
+ var replace = '/list/';
+ if (_lists.length > 0) {
+ _list_id = _lists[0].id;
+ _list_name = _lists[0].title;
+ replace += _list_id;
+ }
+ ListStore.emitChange();
+ browserHistory.replace(replace);
+ break;
+
+ default:
+ }
+});
+
+module.exports.ListStore = ListStore;
diff --git a/frontend/modules/list/tests/Error.test.js b/frontend/modules/list/tests/Error.test.js
deleted file mode 100644
index ceae5d71..00000000
--- a/frontend/modules/list/tests/Error.test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import Error from '../components/Error';
-import createComponentWithIntl from '../../../jest_mocks/createComponentWithIntl.js';
-
-test('MyLists component test', () => {
- const component = createComponentWithIntl(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/frontend/modules/list/tests/Ingredients.test.js b/frontend/modules/list/tests/Ingredients.test.js
deleted file mode 100644
index f8ff7bf1..00000000
--- a/frontend/modules/list/tests/Ingredients.test.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import MyLists from '../components/MyLists';
-import createComponentWithIntlAndRouter from '../../../jest_mocks/createComponentWithIntlAndRouter.js';
-
-import listData from './listData';
-
-test('MyLists component test', () => {
- const component = createComponentWithIntlAndRouter(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('MyLists component test w/ no lists', () => {
- const component = createComponentWithIntlAndRouter(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/frontend/modules/list/tests/ListFooter.test.js b/frontend/modules/list/tests/ListFooter.test.js
deleted file mode 100644
index 42fb9f5b..00000000
--- a/frontend/modules/list/tests/ListFooter.test.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import React from 'react';
-import ListFooter from '../components/ListFooter';
-import createComponentWithIntl from '../../../jest_mocks/createComponentWithIntl.js';
-
-import {
- ALL_ITEMS,
- ACTIVE_ITEMS,
- COMPLETED_ITEMS
-} from '../constants/ListStatus'
-
-test('MyLists component test', () => {
- const mockClearCompleted = jest.fn();
- const mockFilterStatus = jest.fn();
- const component = createComponentWithIntl(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('MyLists component test w/ active filter', () => {
- const mockClearCompleted = jest.fn();
- const mockFilterStatus = jest.fn();
- const component = createComponentWithIntl(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('MyLists component test w/ completed filter', () => {
- const mockClearCompleted = jest.fn();
- const mockFilterStatus = jest.fn();
- const component = createComponentWithIntl(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/frontend/modules/list/tests/__snapshots__/Error.test.js.snap b/frontend/modules/list/tests/__snapshots__/Error.test.js.snap
deleted file mode 100644
index 45ed105d..00000000
--- a/frontend/modules/list/tests/__snapshots__/Error.test.js.snap
+++ /dev/null
@@ -1,22 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`MyLists component test 1`] = `
-
-
-
-
-
- Something went wrong!
- :
-
- There is an error!
-
-
-`;
diff --git a/frontend/modules/list/tests/__snapshots__/Ingredients.test.js.snap b/frontend/modules/list/tests/__snapshots__/Ingredients.test.js.snap
deleted file mode 100644
index 9218d2dd..00000000
--- a/frontend/modules/list/tests/__snapshots__/Ingredients.test.js.snap
+++ /dev/null
@@ -1,92 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`MyLists component test 1`] = `
-
-`;
-
-exports[`MyLists component test w/ no lists 1`] = `
-
-`;
diff --git a/frontend/modules/list/tests/__snapshots__/ListFooter.test.js.snap b/frontend/modules/list/tests/__snapshots__/ListFooter.test.js.snap
deleted file mode 100644
index 21b89774..00000000
--- a/frontend/modules/list/tests/__snapshots__/ListFooter.test.js.snap
+++ /dev/null
@@ -1,154 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`MyLists component test 1`] = `
-
-
- 6 items left
-
-
-
- Clear completed
-
-
-`;
-
-exports[`MyLists component test w/ active filter 1`] = `
-
-
- 6 items left
-
-
-
- Clear completed
-
-
-`;
-
-exports[`MyLists component test w/ completed filter 1`] = `
-
-
- 6 items left
-
-
-
- Clear completed
-
-
-`;
diff --git a/frontend/modules/list/tests/itemData.js b/frontend/modules/list/tests/itemData.js
deleted file mode 100644
index 94954b66..00000000
--- a/frontend/modules/list/tests/itemData.js
+++ /dev/null
@@ -1 +0,0 @@
-export default [{"id":4,"list":2,"title":"5","completed":true},{"id":5,"list":2,"title":"scv","completed":false},{"id":6,"list":2,"title":"r","completed":false},{"id":7,"list":2,"title":"3","completed":true}]
\ No newline at end of file
diff --git a/frontend/modules/list/tests/listData.js b/frontend/modules/list/tests/listData.js
deleted file mode 100644
index cfdf6ec5..00000000
--- a/frontend/modules/list/tests/listData.js
+++ /dev/null
@@ -1 +0,0 @@
-export default [{"id":1,"title":"The first test","slug":"1","pub_date":"October 17, 2017","author":"ryan","item_count":3},{"id":2,"title":"another test","slug":"sdfsdf","pub_date":"October 17, 2017","author":"ryan","item_count":4},{"id":3,"title":"test","slug":"test","pub_date":"October 17, 2017","author":"ryan","item_count":0}];
\ No newline at end of file
diff --git a/frontend/modules/news/components/News.js b/frontend/modules/news/components/News.js
index 8c48b4d3..f1349354 100644
--- a/frontend/modules/news/components/News.js
+++ b/frontend/modules/news/components/News.js
@@ -1,5 +1,5 @@
import React from 'react'
-import { Link } from 'react-router-dom'
+import { Link } from 'react-router'
import { Carousel } from 'react-bootstrap'
import {
injectIntl,
diff --git a/frontend/modules/recipe/actions/RecipeActions.js b/frontend/modules/recipe/actions/RecipeActions.js
deleted file mode 100644
index 224271b1..00000000
--- a/frontend/modules/recipe/actions/RecipeActions.js
+++ /dev/null
@@ -1,72 +0,0 @@
-import { request } from '../../common/CustomSuperagent';
-import { serverURLs } from '../../common/config'
-import RecipeConstants from '../constants/RecipeConstants';
-import history from '../../common/history'
-
-export const load = (id) => {
- return (dispatch) => {
- request()
- .get(serverURLs.recipe + id + "/")
- .then(res => dispatch({type: RecipeConstants.RECIPE_LOAD, data: res.body}))
- .catch(err => { console.error(err); history.push('/notfound'); })
- }
-};
-
-export const updateServings = (key, value, recipe) => {
- return (dispatch) => {
- dispatch({
- type: RecipeConstants.RECIPE_INGREDIENT_SERVINGS_UPDATE,
- value,
- recipe
- })
- }
-};
-
-export const resetServings = (event, recipe) => {
- return (dispatch) => {
- dispatch({
- type: RecipeConstants.RECIPE_INGREDIENT_SERVINGS_RESET,
- recipe
- })
- }
-};
-
-export const checkIngredient = (id, value, recipe) => {
- return (dispatch) => {
- dispatch({
- type: RecipeConstants.RECIPE_INGREDIENT_CHECK_INGREDIENT,
- id,
- value,
- recipe
- })
- }
-};
-
-export const checkSubRecipe = (id, value, recipe) => {
- return (dispatch) => {
- dispatch({
- type: RecipeConstants.RECIPE_INGREDIENT_CHECK_SUBRECIPE,
- id,
- value,
- recipe
- })
- }
-};
-
-export const checkAll = (event, recipe) => {
- return (dispatch) => {
- dispatch({
- type: RecipeConstants.RECIPE_INGREDIENT_CHECK_ALL,
- recipe
- })
- }
-};
-
-export const unCheckAll = (event, recipe) => {
- return (dispatch) => {
- dispatch({
- type: RecipeConstants.RECIPE_INGREDIENT_UNCHECK_ALL,
- recipe
- })
- }
-};
\ No newline at end of file
diff --git a/frontend/modules/recipe/actions/RecipeItemActions.js b/frontend/modules/recipe/actions/RecipeItemActions.js
deleted file mode 100644
index beee9e2d..00000000
--- a/frontend/modules/recipe/actions/RecipeItemActions.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import { request } from '../../common/CustomSuperagent';
-import { serverURLs } from '../../common/config'
-import RecipeConstants from '../constants/RecipeConstants';
-
-export const bulkAdd = (items, list) => {
- return (dispatch) => {
- const format = (i) => {
- let quantity = i.customQuantity ? i.customQuantity : i.quantity;
- quantity = i.quantity ? i.quantity + " " : '';
- let measurement = i.measurement ? i.measurement + " " : '';
- return quantity + measurement + i.title;
- };
-
- let checkedIngredients = items.ingredient_groups.map(item => {
- return item.ingredients.reduce((myList, ingredient) => {
- if (ingredient && ingredient.checked) {
- myList.push({list: list, title: format(ingredient)})
- }
- return myList
- }, []);
- });
-
- let checkedSubRecipe = items.subrecipes.reduce((myList, ingredient) => {
- if (ingredient && ingredient.checked) {
- myList.push({list: list, title: format(ingredient)})
- }
- return myList
- }, []);
-
- checkedIngredients = checkedIngredients.reduce((a, b) => a.concat(b), []).concat(checkedSubRecipe);
-
- if (checkedIngredients.length > 0) {
- dispatch({'type': RecipeConstants.RECIPE_LIST_LOADING});
- request()
- .post(serverURLs.bulk_list_item)
- .send(checkedIngredients)
- .then(res => {
- dispatch({type: RecipeConstants.RECIPE_LIST_COMPLETE});
- dispatch({
- type: RecipeConstants.RECIPE_INGREDIENT_UNCHECK_ALL,
- value: false,
- recipe: items.id
- })
- })
- .catch(err => { dispatch({type: RecipeConstants.RECIPE_LIST_ERROR}); })
- }
- }
-};
-
-export const reset = () => {
- return (dispatch) => {
- dispatch({
- type: RecipeConstants.RECIPE_LIST_BLANK,
- })
- }
-};
diff --git a/frontend/modules/recipe/components/Directions.js b/frontend/modules/recipe/components/Directions.js
index d5ca0b49..9e2cac17 100644
--- a/frontend/modules/recipe/components/Directions.js
+++ b/frontend/modules/recipe/components/Directions.js
@@ -1,27 +1,33 @@
import React from 'react'
-import PropTypes from 'prop-types'
-const Directions = ({ data }) => {
- let directions = data.map(function(direction) {
- return (
-
- { direction.title }
-
- );
- });
+class Directions extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ data: this.props.data || []
+ };
+ }
- return (
-
- { directions }
-
- );
-};
+ componentWillReceiveProps(nextProps) {
+ this.setState({data: nextProps.data});
+ }
-Directions.PropTypes = {
- data: PropTypes.shape({
- step: PropTypes.number.isRequired,
- title: PropTypes.string.isRequired,
- }).isRequired
-};
+ render() {
+ let directions = this.state.data.map(function(direction) {
+ return (
+
+ { direction.title }
+
+ );
+ });
+
+ return (
+
+ { directions }
+
+ );
+ }
+}
-export default Directions;
+module.exports = Directions;
diff --git a/frontend/modules/recipe/components/InfoPanel.js b/frontend/modules/recipe/components/InfoPanel.js
deleted file mode 100644
index 0ffaa3cd..00000000
--- a/frontend/modules/recipe/components/InfoPanel.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import {
- injectIntl,
- defineMessages,
-} from 'react-intl'
-
-import { Input } from '../../common/form/FormComponents'
-
-const RecipeHeader = ({ cookTime, prepTime, servings, customServings, info, updateServings, clearServings, intl }) => {
- const messages = defineMessages({
- servings: {
- id: 'recipe.servings',
- description: 'Servings',
- defaultMessage: 'Servings',
- },
- prep_time: {
- id: 'recipe.prep_time',
- description: 'Preparation time',
- defaultMessage: 'Prep time',
- },
- cooking_time: {
- id: 'recipe.cooking_time',
- description: 'Cooking time',
- defaultMessage: 'Cooking time',
- },
- minutes: {
- id: 'recipe.minutes',
- description: 'minutes',
- defaultMessage: 'minutes'
- },
- });
-
- let clearInput = '';
- if (servings != customServings && !!customServings) {
- clearInput = (
-
-
-
-
-
- )
- }
-
- return (
-
- );
-};
-
-RecipeHeader.PropTypes = {
- cookTime: PropTypes.number.isRequired,
- prepTime: PropTypes.number.isRequired,
- servings: PropTypes.number.isRequired,
- customServings: PropTypes.string,
- info: PropTypes.string.isRequired,
- updateServings: PropTypes.func.isRequired,
- clearServings: PropTypes.func.isRequired,
- intl: PropTypes.object.isRequired,
-};
-
-export default injectIntl(RecipeHeader);
diff --git a/frontend/modules/recipe/components/IngredientButtons.js b/frontend/modules/recipe/components/IngredientButtons.js
deleted file mode 100644
index 7ed4b505..00000000
--- a/frontend/modules/recipe/components/IngredientButtons.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import Spinner from 'react-spinkit';
-import { DropdownButton, MenuItem } from 'react-bootstrap'
-import {
- injectIntl,
- defineMessages,
-} from 'react-intl'
-
-import RecipeListStatusConstants from '../constants/RecipeListStatusConstants'
-
-const IngredientButtons = ({ lists, listStatus, bulkAdd, checkAll, unCheckAll, intl }) => {
- const messages = defineMessages({
- save: {
- id: 'recipe.recipe_ingredient_button.save',
- description: 'Save to list',
- defaultMessage: 'Add To'
- },
- check_all: {
- id: 'recipe.recipe_ingredient_button.check_all',
- description: 'Check All',
- defaultMessage: 'Check All'
- },
- clear: {
- id: 'recipe.recipe_ingredient_button.clear',
- description: 'Clear',
- defaultMessage: 'Clear'
- },
- });
-
- let listTitles = [];
- if (lists) {
- listTitles = lists.map(list => {
- return (
-
- )
- });
- }
-
- let checkmark = '';
- if (listStatus === RecipeListStatusConstants.LOADING) {
- checkmark = (
-
- )
- } else if (listStatus === RecipeListStatusConstants.COMPLETE) {
- checkmark = (
-
- );
- } else if (listStatus === RecipeListStatusConstants.ERROR) {
- checkmark = (
-
- );
- }
-
- let dropdown = (
-
- { listTitles }
-
- );
-
- return (
-
-
-
- { intl.formatMessage(messages.check_all) }
-
-
- { intl.formatMessage(messages.clear) }
-
- { listTitles.length > 0 ? dropdown : null }
-
- { checkmark }
-
- );
-};
-
-IngredientButtons.PropTypes = {
- lists: PropTypes.object.isRequired,
- listStatus: PropTypes.string.isRequired,
- bulkAdd: PropTypes.func.isRequired,
- checkAll: PropTypes.func.isRequired,
- unCheckAll: PropTypes.func.isRequired,
- intl: PropTypes.object.isRequired,
-};
-
-export default injectIntl(IngredientButtons);
diff --git a/frontend/modules/recipe/components/IngredientGroups.js b/frontend/modules/recipe/components/IngredientGroups.js
index 54e8712e..273a98a6 100644
--- a/frontend/modules/recipe/components/IngredientGroups.js
+++ b/frontend/modules/recipe/components/IngredientGroups.js
@@ -1,28 +1,38 @@
import React from 'react'
-import PropTypes from 'prop-types'
-
import Ingredients from './Ingredients'
-const IngredientGroups = ({ data, check }) => {
- let ingredientGroups = data.map(group => (
-
- { (group.title) ? { group.title } : null }
-
-
- ));
+class IngredientGroups extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ data: this.props.data || []
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({data: nextProps.data});
+ }
- return (
-
- { ingredientGroups }
-
- );
-};
+ render() {
+ let ingredientGroups = this.state.data.map(function(ingredientGroup) {
+ return (
+
+ { (ingredientGroup.title)
+ ? { ingredientGroup.title }
+ : null
+ }
+
+
+ );
+ }, this);
-IngredientGroups.PropTypes = {
- data: PropTypes.arrayOf(PropTypes.shape({
- title: PropTypes.string.isRequired,
- ingredients: PropTypes.object.isRequired,
- }).isRequired).isRequired
-};
+ return (
+
+ { ingredientGroups }
+
+ );
+ }
+}
-export default IngredientGroups;
+module.exports = IngredientGroups;
diff --git a/frontend/modules/recipe/components/Ingredients.js b/frontend/modules/recipe/components/Ingredients.js
index 2e2ecfb9..5a52054a 100644
--- a/frontend/modules/recipe/components/Ingredients.js
+++ b/frontend/modules/recipe/components/Ingredients.js
@@ -1,47 +1,55 @@
import React from 'react'
-import PropTypes from 'prop-types'
-import { Checkbox } from '../../common/form/FormComponents'
+class Ingredients extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ data: this.props.data || []
+ };
+
+ this.round = this.round.bind(this);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({data: nextProps.data});
+ }
+
+ round(number, precision) {
+ let factor = Math.pow(10, precision);
+ let tempNumber = number * factor;
+ let roundedTempNumber = Math.round(tempNumber);
+ return roundedTempNumber / factor;
+ };
+
+ render() {
+ let ingredients = this.state.data.map(function(ingredient) {
+ let quantity = this.round(ingredient.quantity, 3);
+
+ return (
+
+ { (ingredient.quantity !== 0)
+ ? { quantity }
+ : null
+ }
+ { (ingredient.measurement)
+ ? { ingredient.measurement }
+ : null
+ }
+ { (ingredient.title)
+ ? { ingredient.title }
+ : null
+ }
+
+ );
+ }, this);
-const Ingredients = ({ data, check }) => {
- let ingredients = data.map(function(ingredient) {
- let quantity = ingredient.customQuantity ? ingredient.customQuantity : ingredient.quantity;
return (
-
-
- { (ingredient.quantity !== 0)
- ? { quantity }
- : null
- }
- { (ingredient.measurement)
- ? { ingredient.measurement }
- : null
- }
- { (ingredient.title)
- ? { ingredient.title }
- : null
- }
-
+
);
- });
-
- return (
-
- );
-};
-
-Ingredients.PropTypes = {
- data: PropTypes.arrayOf(PropTypes.shape({
- quantity: PropTypes.number.isRequired,
- measurement: PropTypes.string.isRequired,
- title: PropTypes.string.isRequired,
- }).isRequired).isRequired
-};
-
-export default Ingredients;
+ }
+}
+
+module.exports = Ingredients;
diff --git a/frontend/modules/recipe/components/Ratings.js b/frontend/modules/recipe/components/Ratings.js
index 617aac2d..dc03c19d 100644
--- a/frontend/modules/recipe/components/Ratings.js
+++ b/frontend/modules/recipe/components/Ratings.js
@@ -1,32 +1,30 @@
import React from 'react'
-import PropTypes from 'prop-types'
require("./../css/ratings.scss");
-const Ratings = ({ stars }) => {
- if (stars > 5) {
- stars = 5;
- } else if (stars < 0) {
- stars = 0;
- }
-
- const full_stars = [...Array(stars).keys()].map(function(name, index) {
- return
;
- });
- const empty_stars = [...Array(5 - stars).keys()].map(function(name, index) {
- return
;
- });
+class Ratings extends React.Component {
+ render() {
+ let stars = this.props.stars ? this.props.stars : 0;
+ if (stars > 5) {
+ stars = 5;
+ } else if (stars < 0) {
+ stars = 0;
+ }
- return (
-
- { full_stars }
- { empty_stars }
-
- );
-};
+ const full_stars = [...Array(stars).keys()].map(function(name, index) {
+ return
;
+ });
+ const empty_stars = [...Array(5 - stars).keys()].map(function(name, index) {
+ return
;
+ });
-Ratings.propTypes = {
- stars: PropTypes.number.isRequired
-};
+ return (
+
+ { full_stars }
+ { empty_stars }
+
+ );
+ }
+}
-export default Ratings;
+module.exports = Ratings;
diff --git a/frontend/modules/recipe/components/Recipe.js b/frontend/modules/recipe/components/Recipe.js
new file mode 100644
index 00000000..a498a9c4
--- /dev/null
+++ b/frontend/modules/recipe/components/Recipe.js
@@ -0,0 +1,87 @@
+import React from 'react'
+import { Link, browserHistory } from 'react-router'
+import { request } from '../../common/CustomSuperagent';
+import {
+ injectIntl,
+ IntlProvider,
+ defineMessages,
+ formatMessage
+} from 'react-intl'
+
+import AuthStore from '../../account/stores/AuthStore'
+import MiniBrowse from '../../browse/components/MiniBrowse'
+import { serverURLs } from '../../common/config'
+import RecipeScheme from './RecipeScheme'
+
+require("./../css/recipe.scss");
+
+class Recipe extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ data: [],
+ user: this.getAuthUser()
+ };
+
+ this.loadRecipeFromServer = this.loadRecipeFromServer.bind(this);
+ this._onChange = this._onChange.bind(this);
+ this.getAuthUser = this.getAuthUser.bind(this);
+ }
+
+ loadRecipeFromServer(id) {
+ window.scrollTo(0, 0);
+ let url = serverURLs.recipe + id + "/";
+ request()
+ .get(url)
+ .end((err, res) => {
+ if (!err && res) {
+ this.setState({ data: res.body });
+ } else {
+ if (res.statusCode == 404) {
+ browserHistory.replace('/notfound');
+ } else {
+ console.error(url, err.toString());
+ }
+ }
+ })
+ }
+
+ componentDidMount() {
+ AuthStore.addChangeListener(this._onChange);
+ this.loadRecipeFromServer(this.props.params.recipe);
+ }
+
+ componentWillUnmount() {
+ AuthStore.removeChangeListener(this._onChange);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.loadRecipeFromServer(nextProps.params.recipe);
+ }
+
+ _onChange() {
+ this.setState({user: this.getAuthUser()});
+ }
+
+ getAuthUser() {
+ return AuthStore.getUser();
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+module.exports = Recipe;
diff --git a/frontend/modules/recipe/components/RecipeFooter.js b/frontend/modules/recipe/components/RecipeFooter.js
deleted file mode 100644
index 0506d289..00000000
--- a/frontend/modules/recipe/components/RecipeFooter.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import { Link } from 'react-router-dom'
-import {
- injectIntl,
- defineMessages,
-} from 'react-intl'
-
-const RecipeFooter = ({ id, source, username, updateDate, showEditLink, intl }) => {
- const messages = defineMessages({
- source: {
- id: 'recipe.source',
- description: 'Source of the recipe',
- defaultMessage: 'Source'
- },
- created_by: {
- id: 'recipe.created_by',
- description: 'Created by',
- defaultMessage: 'Created by'
- },
- last_updated: {
- id: 'recipe.last_updated',
- description: 'Last Updated',
- defaultMessage: 'Last Updated'
- },
- edit_recipe: {
- id: 'recipe.edit_recipe',
- description: 'Edit recipe button text',
- defaultMessage: 'Edit recipe'
- },
- });
-
- let hostname = '';
- if (source) {
- // Get Host name of a URL
- let a = document.createElement('a');
- a.href = source;
- hostname = a.hostname;
- }
-
- const sourceLink = (
-
- );
-
- const editLink = (
-
-
- { intl.formatMessage(messages.edit_recipe) }
-
-
- );
-
- return (
-
-
-
- { (source) ? sourceLink : null }
-
{ intl.formatMessage(messages.created_by) }: { username }
-
{ intl.formatMessage(messages.last_updated) }: { updateDate }
-
-
- { showEditLink ? editLink : null }
-
-
-
- );
-};
-
-RecipeFooter.PropTypes = {
- id: PropTypes.number.isRequired,
- source: PropTypes.string.isRequired,
- username: PropTypes.string.isRequired,
- updateDate: PropTypes.instanceOf(Date).isRequired,
- showEditLink: PropTypes.bool.isRequired,
- intl: PropTypes.object.isRequired,
-};
-
-export default injectIntl(RecipeFooter);
diff --git a/frontend/modules/recipe/components/RecipeHeader.js b/frontend/modules/recipe/components/RecipeHeader.js
deleted file mode 100644
index 0aec8727..00000000
--- a/frontend/modules/recipe/components/RecipeHeader.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-
-import Ratings from './Ratings'
-
-const RecipeHeader = ({ photo, title, rating }) => {
- if (photo) {
- return (
-
- );
- }
-
- return (
-
- );
-};
-
-RecipeHeader.PropTypes = {
- photo: PropTypes.object.isRequired,
- rating: PropTypes.number.isRequired,
- title: PropTypes.string.isRequired,
-};
-
-export default RecipeHeader;
diff --git a/frontend/modules/recipe/components/RecipeScheme.js b/frontend/modules/recipe/components/RecipeScheme.js
index 3772ea58..fd62e6e5 100644
--- a/frontend/modules/recipe/components/RecipeScheme.js
+++ b/frontend/modules/recipe/components/RecipeScheme.js
@@ -1,23 +1,161 @@
import React from 'react'
+import { Link, browserHistory } from 'react-router'
import {
injectIntl,
+ IntlProvider,
defineMessages,
+ formatMessage
} from 'react-intl'
import IngredientGroups from './IngredientGroups'
import SubRecipes from './SubRecipes'
import Directions from './Directions'
-import RecipeHeader from './RecipeHeader'
-import RecipeFooter from './RecipeFooter'
-import IngredientButtons from './IngredientButtons'
-import InfoPanel from './InfoPanel'
+import Ratings from './Ratings'
+import { Input } from '../../common/form/FormComponents'
require("./../css/recipe.scss");
class RecipeScheme extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ data: this.props.data
+ };
+
+ this.print = this.print.bind(this);
+ this.updateServings = this.updateServings.bind(this);
+ this.showRecipeImageHeader = this.showRecipeImageHeader.bind(this);
+ this.showRecipeImageThumb = this.showRecipeImageThumb.bind(this);
+ this.showEditLink = this.showEditLink.bind(this);
+ this.getDomain = this.getDomain.bind(this);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({ data: nextProps.data });
+ }
+
+ print() {
+ window.print();
+ }
+
+ updateServings(key, value) {
+ if (key === 'servings') {
+ if (value > 0) {
+ let data = this.state.data;
+
+ let multiplier = value / this.state.data.servings;
+ data.servings = value;
+
+ data.ingredient_groups.map((ingredient_group) => {
+ ingredient_group.ingredients.map((ingredient) => {
+ if (ingredient) {
+ ingredient.quantity = ingredient.quantity * multiplier;
+ }
+ return ingredient
+ });
+ });
+
+ data.subrecipes.map((ingredient) => {
+ if (ingredient) {
+ ingredient.quantity = ingredient.quantity * multiplier;
+ }
+ });
+
+ this.setState({
+ data: data
+ })
+ }
+ }
+ }
+
+ showRecipeImageHeader() {
+ if (this.state.data.photo) {
+ return (
+
+
+
+
{this.state.data.title}
+
+
+
+
+
+ );
+ } else {
+ return (
+
+
+
+
{this.state.data.title}
+
+
+
+
+ );
+ }
+ }
+
+ showRecipeImageThumb() {
+ if (this.state.data.photo_thumbnail) {
+ return (
+

+ );
+ } else {
+ return (
+

+ );
+ }
+ }
+
+ showEditLink() {
+ const {formatMessage} = this.props.intl;
+ const messages = defineMessages({
+ edit_recipe: {
+ id: 'recipe.edit_recipe',
+ description: 'Edit recipe button text',
+ defaultMessage: 'Edit recipe'
+ }
+ });
+
+ if (this.props.user !== null && (this.props.user.id === this.state.data.author)) {
+ return (
+
{ formatMessage(messages.edit_recipe) }
+ )
+ }
+ }
+
+ // Hack-a-licious!
+ getDomain(url) {
+ let a = document.createElement('a');
+ a.href = url;
+ return a.hostname;
+ }
+
render() {
- const { formatMessage } = this.props.intl;
+ const {formatMessage} = this.props.intl;
const messages = defineMessages({
+ servings: {
+ id: 'recipe.servings',
+ description: 'Servings',
+ defaultMessage: 'Servings',
+ },
+ prep_time: {
+ id: 'recipe.prep_time',
+ description: 'Preparation time',
+ defaultMessage: 'Prep time',
+ },
+ cooking_time: {
+ id: 'recipe.cooking_time',
+ description: 'Cooking time',
+ defaultMessage: 'Cooking time',
+ },
ingredients: {
id: 'recipe.ingredients',
description: 'Ingredients',
@@ -28,73 +166,108 @@ class RecipeScheme extends React.Component {
description: 'Directions',
defaultMessage: 'Directions',
},
+ source: {
+ id: 'recipe.source',
+ description: 'Source of the recipe',
+ defaultMessage: 'Source'
+ },
+ created_by: {
+ id: 'recipe.created_by',
+ description: 'Created by',
+ defaultMessage: 'Created by'
+ },
+ last_updated: {
+ id: 'recipe.last_updated',
+ description: 'Last Updated',
+ defaultMessage: 'Last Updated'
+ },
+ minutes: {
+ id: 'recipe.minutes',
+ description: 'minutes',
+ defaultMessage: 'minutes'
+ },
});
return (
-
+ { this.showRecipeImageHeader() }
-

+
-
-
-
-
+
+
+
+
+
+
+
+
+
{ this.state.data.info }
+
+
+
{ formatMessage(messages.ingredients) }
-
-
-
+
+
-
+
{ formatMessage(messages.directions) }
-
+
+
+
+
+
+
+
+
+ { (this.state.data.source) ?
+
+ : null
+ }
+
{ formatMessage(messages.created_by) }: { this.state.data.username }
+
{ formatMessage(messages.last_updated) }: { this.state.data.update_date }
+
+
+ { this.showEditLink() }
-
);
}
}
-export default injectIntl(RecipeScheme);
+module.exports = injectIntl(RecipeScheme);
diff --git a/frontend/modules/recipe/components/RecipeView.js b/frontend/modules/recipe/components/RecipeView.js
deleted file mode 100644
index 5380a8d0..00000000
--- a/frontend/modules/recipe/components/RecipeView.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-
-import Recipe from '../containers/Recipe'
-import MiniBrowse from '../../browse/components/MiniBrowse'
-
-const RecipeView = ({ match }) => (
-
-);
-
-RecipeView.PropTypes = {
- match: PropTypes.object.isRequired
-};
-
-export default RecipeView;
diff --git a/frontend/modules/recipe/components/SubRecipes.js b/frontend/modules/recipe/components/SubRecipes.js
index 9ae845a8..41ca310e 100644
--- a/frontend/modules/recipe/components/SubRecipes.js
+++ b/frontend/modules/recipe/components/SubRecipes.js
@@ -1,49 +1,45 @@
import React from 'react'
-import { Link } from 'react-router-dom'
-import PropTypes from 'prop-types'
+import { Link } from 'react-router'
-import { Checkbox } from '../../common/form/FormComponents'
+class SubRecipes extends React.Component {
+ constructor(props) {
+ super(props);
-const SubRecipes = ({ data, check }) => {
- let recipeLinks = data.map(function(recipeLink) {
- let quantity = recipeLink.customQuantity ? recipeLink.customQuantity : recipeLink.quantity;
- return (
-
-
- { (recipeLink.quantity !== 0)
- ? { quantity }
- : null
- }
- { (recipeLink.measurement)
- ? { recipeLink.measurement }
- : null
- }
- { (recipeLink.title)
- ? { recipeLink.title }
- : null
- }
-
- );
- });
+ this.state = {
+ data: this.props.data || []
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({data: nextProps.data});
+ }
- return (
-
- );
-};
+ render() {
+ let recipeLinks = this.state.data.map(function(recipeLink) {
+ return (
+
+ { (recipeLink.quantity !== 0)
+ ? { recipeLink.quantity }
+ : null
+ }
+ { (recipeLink.measurement)
+ ? { recipeLink.measurement }
+ : null
+ }
+ { (recipeLink.title)
+ ? { recipeLink.title }
+ : null
+ }
+
+ );
+ }, this);
-SubRecipes.PropTypes = {
- data: PropTypes.arrayOf(PropTypes.shape({
- child_recipe_id: PropTypes.number.isRequired,
- quantity: PropTypes.number.isRequired,
- measurement: PropTypes.string.isRequired,
- title: PropTypes.string.isRequired,
- }).isRequired).isRequired
-};
+ return (
+
+ );
+ }
+}
-export default SubRecipes;
+module.exports = SubRecipes;
diff --git a/frontend/modules/recipe/constants/RecipeConstants.js b/frontend/modules/recipe/constants/RecipeConstants.js
deleted file mode 100644
index ea05de5c..00000000
--- a/frontend/modules/recipe/constants/RecipeConstants.js
+++ /dev/null
@@ -1,14 +0,0 @@
-export default {
- RECIPE_LOAD: 'RECIPE_LOAD',
- RECIPE_INGREDIENT: 'RECIPE_INGREDIENT',
- RECIPE_INGREDIENT_CHECK_INGREDIENT: 'RECIPE_INGREDIENT_CHECK_INGREDIENT',
- RECIPE_INGREDIENT_CHECK_SUBRECIPE: 'RECIPE_INGREDIENT_CHECK_SUBRECIPE',
- RECIPE_INGREDIENT_CHECK_ALL: 'RECIPE_INGREDIENT_CHECK_ALL',
- RECIPE_INGREDIENT_UNCHECK_ALL: 'RECIPE_INGREDIENT_UNCHECK_ALL',
- RECIPE_INGREDIENT_SERVINGS_UPDATE: 'RECIPE_INGREDIENT_SERVINGS_UPDATE',
- RECIPE_INGREDIENT_SERVINGS_RESET: 'RECIPE_INGREDIENT_SERVINGS_RESET',
- RECIPE_LIST_BLANK: 'RECIPE_LIST_BLANK',
- RECIPE_LIST_LOADING: 'RECIPE_LIST_LOADING',
- RECIPE_LIST_COMPLETE: 'RECIPE_LIST_COMPLETE',
- RECIPE_LIST_ERROR: 'RECIPE_LIST_ERROR',
-};
\ No newline at end of file
diff --git a/frontend/modules/recipe/constants/RecipeListStatusConstants.js b/frontend/modules/recipe/constants/RecipeListStatusConstants.js
deleted file mode 100644
index 652b866e..00000000
--- a/frontend/modules/recipe/constants/RecipeListStatusConstants.js
+++ /dev/null
@@ -1,5 +0,0 @@
-export default {
- LOADING: 'loading',
- COMPLETE: 'complete',
- ERROR: 'error',
-};
\ No newline at end of file
diff --git a/frontend/modules/recipe/containers/Recipe.js b/frontend/modules/recipe/containers/Recipe.js
deleted file mode 100644
index da0981b5..00000000
--- a/frontend/modules/recipe/containers/Recipe.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
-
-import AuthStore from '../../account/stores/AuthStore'
-import Loading from '../../base/components/Loading'
-import RecipeScheme from '../components/RecipeScheme'
-import * as RecipeActions from '../actions/RecipeActions'
-import * as RecipeItemActions from '../actions/RecipeItemActions'
-import bindIndexToActionCreators from '../../common/bindIndexToActionCreators'
-
-require("./../css/recipe.scss");
-
-class Recipe extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- user: AuthStore.getUser()
- };
- }
-
- componentDidMount() {
- AuthStore.addChangeListener(this._onChange);
- this.props.recipeActions.load(this.props.match.params.recipe);
- }
-
- componentWillUnmount() {
- AuthStore.removeChangeListener(this._onChange);
- }
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.match.params.recipe !== this.props.match.params.recipe) {
- nextProps.recipeItemActions.reset();
- nextProps.recipeActions.load(nextProps.match.params.recipe);
- window.scrollTo(0, 0);
- }
- }
-
- _onChange = () => {
- this.setState({user: AuthStore.getUser()});
- };
-
- render() {
- let { lists, recipes, match, status } = this.props;
- let { recipeActions, recipeItemActions } = this.props;
- let data = recipes.find(t => t.id == match.params.recipe);
- if (data) {
- let showEditLink = (this.state.user !== null && this.state.user.id === data.author);
- return (
-
- );
- } else {
- return (
)
- }
- }
-}
-
-Recipe.propTypes = {
- recipes: PropTypes.array.isRequired,
- lists: PropTypes.array.isRequired,
- status: PropTypes.string.isRequired,
- match: PropTypes.object.isRequired,
- recipeActions: PropTypes.object.isRequired,
- recipeItemActions: PropTypes.object.isRequired,
-};
-
-const mapStateToProps = state => ({
- recipes: state.recipe.recipes,
- status: state.recipe.status,
- lists: state.list.lists,
-});
-
-const mapDispatchToProps = (dispatch, props) => ({
- recipeItemActions: bindActionCreators(RecipeItemActions, dispatch),
- recipeActions: bindActionCreators(
- bindIndexToActionCreators(RecipeActions, props.match.params.recipe),
- dispatch
- ),
-});
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(Recipe);
diff --git a/frontend/modules/recipe/css/recipe.scss b/frontend/modules/recipe/css/recipe.scss
index 0d8537b4..5619dc85 100644
--- a/frontend/modules/recipe/css/recipe.scss
+++ b/frontend/modules/recipe/css/recipe.scss
@@ -55,31 +55,12 @@
td {
text-align: center;
vertical-align: middle;
- .input-group {
- margin: auto;
- max-width: 80px;
- .input-group-btn {
- .btn-default {
- width: 20px;
- }
- .glyphicon {
- margin-left: -5px;
- font-size: 10px;
- };
- }
- .servings-textbox {
- input[type=number]::-webkit-inner-spin-button,
- input[type=number]::-webkit-outer-spin-button {
- -webkit-appearance: none;
- margin: 0;
- }
- .form-group {
- margin-bottom: 0;
- .form-control {
- display: inline-block;
- text-align: center;
- max-width: 80px;
- }
+ .servings-textbox {
+ .form-group {
+ margin-bottom: 0;
+ .form-control {
+ display: inline-block;
+ max-width: 75px;
}
}
}
@@ -101,65 +82,12 @@
height: 0;
line-height: 0;
}
- .directions {
+ .directions, .ingredients {
display: block;
li {
line-height: 1.7em;
}
}
- .ingredients {
- display: block;
- list-style-type: none;
- li {
- line-height: 22px;
- .checkbox-style {
- text-align: center;
- width: 30px;
- height: 30px;
- position: absolute;
- bottom: -25px;
- margin-left: -35px;
- border: none;
- -webkit-appearance: none;
- appearance: none;
- &:after {
- content: url('data:image/svg+xml;utf8,
');
- }
- &:checked:after {
- content: url('data:image/svg+xml;utf8,
');
- }
- &:focus{
- outline:0;
- }
- }
- }
- }
- .ingredients-save {
- display: block;
- margin-top: 15px;
- .btn-group {
- display: block;
- }
- .recipe-list-spinner {
- display: inline-block;
- margin-top: 5px;
- margin-left: 12px;
- .sk-circle:before {
- background-color: $gray;
- }
- }
- .glyphicon {
- margin-top: 5px;
- margin-left: 12px;
- font-size: 18px;
- &.glyphicon-ok {
- color: #3F9C35;
- }
- &.glyphicon-remove {
- color: #A33F1F;
- }
- }
- }
}
.ratings {
img {
@@ -260,3 +188,4 @@
}
}
}
+
diff --git a/frontend/modules/recipe/reducers/IngredientReducer.js b/frontend/modules/recipe/reducers/IngredientReducer.js
deleted file mode 100644
index 241f53a0..00000000
--- a/frontend/modules/recipe/reducers/IngredientReducer.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import RecipeConstants from '../constants/RecipeConstants'
-
-const ingredients = (state, cb) => {
- return state.map(ig => {
- return {
- ...ig,
- ingredients: ig.ingredients.map(ingredient => {
- return cb(ingredient)
- })
- }
- });
-};
-
-const merge = (state, action) => {
- let list = [];
- state.map((ig) => {
- ig.ingredients.map(ingredient => {
- if (ingredient.checked) {
- list.push(ingredient.id);
- }
- });
- });
-
- return ingredients(action.ingredient_groups, (i) => {
- let checked = list.includes(i.id);
- let factor = Math.pow(10, 3);
- let customQuantity = Math.round(i.quantity * factor * action.servings) / factor;
- return {...i, customQuantity: customQuantity, checked: checked}
- })
-};
-
-const recipes = (state = [], action) => {
- switch (action.type) {
- case RecipeConstants.RECIPE_LOAD:
- return state ? merge(state, action) : action;
- case RecipeConstants.RECIPE_INGREDIENT_CHECK_INGREDIENT:
- return ingredients(state, (i) => {
- if (i.id == action.id) {
- return {...i, checked: action.value}
- }
- return i
- });
- case RecipeConstants.RECIPE_INGREDIENT_CHECK_ALL:
- return ingredients(state, (i) => {
- return {...i, checked: true}
- });
- case RecipeConstants.RECIPE_INGREDIENT_UNCHECK_ALL:
- return ingredients(state, (i) => {
- return {...i, checked: false}
- });
- case RecipeConstants.RECIPE_INGREDIENT_SERVINGS_UPDATE:
- return ingredients(state, (i) => {
- let factor = Math.pow(10, 3);
- let custom = Math.round(i.quantity * factor * action.servings) / factor;
- return {...i, customQuantity: custom}
- });
- case RecipeConstants.RECIPE_INGREDIENT_SERVINGS_RESET:
- return ingredients(state, (i) => {
- return {...i, customQuantity: i.quantity}
- });
- default:
- return state;
- }
-};
-
-export default recipes
diff --git a/frontend/modules/recipe/reducers/RecipeListStatusReducer.js b/frontend/modules/recipe/reducers/RecipeListStatusReducer.js
deleted file mode 100644
index bec8d736..00000000
--- a/frontend/modules/recipe/reducers/RecipeListStatusReducer.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import RecipeConstants from '../constants/RecipeConstants'
-import RecipeListStatusConstants from '../constants/RecipeListStatusConstants'
-
-const status = (state = '', action) => {
- switch (action.type) {
- case RecipeConstants.RECIPE_LIST_LOADING:
- return RecipeListStatusConstants.LOADING;
- case RecipeConstants.RECIPE_LIST_COMPLETE:
- return RecipeListStatusConstants.COMPLETE;
- case RecipeConstants.RECIPE_LIST_ERROR:
- return RecipeListStatusConstants.ERROR;
- case RecipeConstants.RECIPE_LIST_BLANK:
- return '';
- default:
- return state
- }
-};
-
-export default status
diff --git a/frontend/modules/recipe/reducers/RecipeReducer.js b/frontend/modules/recipe/reducers/RecipeReducer.js
deleted file mode 100644
index 63de73a8..00000000
--- a/frontend/modules/recipe/reducers/RecipeReducer.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import RecipeConstants from '../constants/RecipeConstants'
-import { default as ingredient } from './IngredientReducer'
-import { default as subrecipes } from './SubRecipeReducer'
-
-const recipes = (state = [], action) => {
- switch (action.type) {
- case RecipeConstants.RECIPE_LOAD:
- let recipe = state.find(t => t.id === action.data.id);
- if (recipe) {
- return state.map(recipe => {
- if (recipe.id === action.data.id) {
- let customServings = action.data.servings;
- let servingMultiplier = 1;
- if (action.data.servings === recipe.servings) {
- customServings = recipe.customServings;
- servingMultiplier = recipe.customServings ? recipe.customServings / recipe.servings : 1;
- }
- let subRecipes = subrecipes(
- recipe.subrecipes,
- { subrecipes: action.data.subrecipes,
- servings: servingMultiplier,
- type: action.type }
- );
- let ingredients = ingredient(
- recipe.ingredient_groups,
- { ingredient_groups: action.data.ingredient_groups,
- servings: servingMultiplier,
- type: action.type }
- );
- return {
- ...action.data,
- customServings: customServings,
- subrecipes: subRecipes,
- ingredient_groups: ingredients
- };
- }
- return recipe;
- });
- } else {
- return [
- ...state,
- { ...action.data }
- ]
- }
- case RecipeConstants.RECIPE_INGREDIENT_SERVINGS_UPDATE:
- return state.map(recipe => {
- if (recipe.id == action.recipe){
- action.servings = action.value / recipe.servings;
- let subRecipes = subrecipes(recipe.subrecipes, action);
- let ingredients = ingredient(recipe.ingredient_groups, action);
- return {
- ...recipe,
- subrecipes: subRecipes,
- ingredient_groups: ingredients,
- customServings: action.value
- };
- }
- return recipe;
- });
- case RecipeConstants.RECIPE_INGREDIENT_SERVINGS_RESET:
- return state.map(recipe => {
- if (recipe.id == action.recipe){
- let subRecipes = subrecipes(recipe.subrecipes, action);
- let ingredients = ingredient(recipe.ingredient_groups, action);
- return {
- ...recipe,
- subrecipes: subRecipes,
- ingredient_groups: ingredients,
- customServings: recipe.servings
- };
- }
- return recipe;
- });
- case (action.type.indexOf(RecipeConstants.RECIPE_INGREDIENT) !== -1 ? action.type : '') :
- return state.map(recipe => {
- if (recipe.id == action.recipe){
- let subRecipes = subrecipes(recipe.subrecipes, action);
- let ingredients = ingredient(recipe.ingredient_groups, action);
- return {
- ...recipe,
- subrecipes: subRecipes,
- ingredient_groups: ingredients
- };
- }
- return recipe;
- });
- default:
- return state;
- }
-};
-
-export default recipes
diff --git a/frontend/modules/recipe/reducers/Reducer.js b/frontend/modules/recipe/reducers/Reducer.js
deleted file mode 100644
index d4688f68..00000000
--- a/frontend/modules/recipe/reducers/Reducer.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { combineReducers } from 'redux'
-import { default as recipes } from './RecipeReducer'
-import { default as status } from './RecipeListStatusReducer'
-
-const recipe = combineReducers({
- recipes,
- status
-});
-
-export default recipe
diff --git a/frontend/modules/recipe/reducers/SubRecipeReducer.js b/frontend/modules/recipe/reducers/SubRecipeReducer.js
deleted file mode 100644
index ab83beb3..00000000
--- a/frontend/modules/recipe/reducers/SubRecipeReducer.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import RecipeConstants from '../constants/RecipeConstants'
-
-const merge = (state, action) => {
- let list = [];
- state.map((i) => {
- if (i.checked) {
- list.push(i.id);
- }
- });
-
- return action.subrecipes.map(i => {
- let checked = list.includes(i.child_recipe_id);
- let factor = Math.pow(10, 3);
- let customQuantity = Math.round(i.quantity * factor * action.servings) / factor;
- return {...i, customQuantity: customQuantity, checked: checked}
- });
-};
-
-const subRecipes = (state = [], action) => {
- switch (action.type) {
- case RecipeConstants.RECIPE_LOAD:
- return state ? merge(state, action) : action;
- case RecipeConstants.RECIPE_INGREDIENT_CHECK_SUBRECIPE:
- return state.map(i => {
- if (i.child_recipe_id == action.id) {
- return {...i, checked: action.value}
- }
- return i
- });
- case RecipeConstants.RECIPE_INGREDIENT_CHECK_ALL:
- return state.map(i => {
- return {...i, checked: true}
- });
- case RecipeConstants.RECIPE_INGREDIENT_UNCHECK_ALL:
- return state.map(i => {
- return {...i, checked: false}
- });
- case RecipeConstants.RECIPE_INGREDIENT_SERVINGS_UPDATE:
- return state.map(i => {
- let factor = Math.pow(10, 3);
- let custom = Math.round(i.quantity * factor * action.servings) / factor;
- return {...i, customQuantity: custom}
- });
- case RecipeConstants.RECIPE_INGREDIENT_SERVINGS_RESET:
- return state.map(i => {
- return {...i, customQuantity: i.quantity}
- });
- default:
- return state;
- }
-};
-
-export default subRecipes
diff --git a/frontend/modules/recipe/tests/InfoPanel.test.js b/frontend/modules/recipe/tests/InfoPanel.test.js
deleted file mode 100644
index 43ac7b89..00000000
--- a/frontend/modules/recipe/tests/InfoPanel.test.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import InfoPanel from '../components/InfoPanel';
-import createComponentWithIntl from '../../../jest_mocks/createComponentWithIntl';
-
-test('Short Info Panel', () => {
- const mockUpdateServings = jest.fn();
- const component = createComponentWithIntl(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('Long Info Panel', () => {
- const mockUpdateServings = jest.fn();
- const longString = 'Lorem ipsum dolor sit amet, odio sem vel ' +
- 'nulla aliquam, vestibulum pellentesque at risus eros, at ' +
- 'leo mi urna quam, magna nunc vestibulum nibh condimentum ' +
- 'arcu. Eu nunc blandit arcu magna, morbi eleifend dolor, nam ' +
- 'ratione justo ullamcorper platea malesuada donec, fusce' +
- ' luctus varius. Vel ipsum nunc in justo, pulvinar magna ' +
- 'interdum ut nunc vestibulum. Lorem dui vitae. Lectus elit vel' +
- ' lorem purus, in tortor, mi diam mus venenatis sit bibendum eu.' +
- ' Odio nec lectus quisquam ac eleifend sem, arcu congue neque neque ' +
- 'nunc, nam maecenas, nec mauris pede erat dignissim, in gravida tempor.' +
- ' In amet mauris odio vitae montes. Nec vitae nostrud vestibulum, ' +
- 'at in tincidunt justo varius wisi ut, nullam wisi erat ' +
- 'lorem tempor ac. Lorem ipsum dolor sit amet, odio sem vel ' +
- 'nulla aliquam, vestibulum pellentesque at risus eros, at ' +
- 'leo mi urna quam, magna nunc vestibulum nibh condimentum ' +
- 'arcu. Eu nunc blandit arcu magna, morbi eleifend dolor, nam ' +
- 'ratione justo ullamcorper platea malesuada donec, fusce' +
- ' luctus varius. Vel ipsum nunc in justo, pulvinar magna ' +
- 'interdum ut nunc vestibulum. Lorem dui vitae. Lectus elit vel' +
- ' lorem purus, in tortor, mi diam mus venenatis sit bibendum eu.' +
- ' Odio nec lectus quisquam ac eleifend sem, arcu congue neque neque ' +
- 'nunc, nam maecenas, nec mauris pede erat dignissim, in gravida tempor.' +
- ' In amet mauris odio vitae montes. Nec vitae nostrud vestibulum, ' +
- 'at in tincidunt justo varius wisi ut, nullam wisi erat ' +
- 'lorem tempor ac.';
- const component = createComponentWithIntl(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/frontend/modules/recipe/tests/IngredientButtons.test.js b/frontend/modules/recipe/tests/IngredientButtons.test.js
deleted file mode 100644
index 4e7bfd53..00000000
--- a/frontend/modules/recipe/tests/IngredientButtons.test.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import React from 'react';
-import RecipeListStatusConstants from '../constants/RecipeListStatusConstants';
-import IngredientButtons from '../components/IngredientButtons';
-import createComponentWithIntlAndRouter from '../../../jest_mocks/createComponentWithIntlAndRouter';
-
-const lists = [{id: 1, title: 'title'},{id: 2, title: 'tütle'},];
-
-test('Ingredient Buttons Default', () => {
- const bulkAdd = jest.fn();
- const checkAll = jest.fn();
- const unCheckAll = jest.fn();
- const component = createComponentWithIntlAndRouter(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('Ingredient Buttons Loading', () => {
- const bulkAdd = jest.fn();
- const checkAll = jest.fn();
- const unCheckAll = jest.fn();
- const component = createComponentWithIntlAndRouter(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('Ingredient Buttons Complete', () => {
- const bulkAdd = jest.fn();
- const checkAll = jest.fn();
- const unCheckAll = jest.fn();
- const component = createComponentWithIntlAndRouter(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('Ingredient Buttons Error', () => {
- const bulkAdd = jest.fn();
- const checkAll = jest.fn();
- const unCheckAll = jest.fn();
- const component = createComponentWithIntlAndRouter(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/frontend/modules/recipe/tests/IngredientGroups.test.js b/frontend/modules/recipe/tests/IngredientGroups.test.js
deleted file mode 100644
index 528a43a1..00000000
--- a/frontend/modules/recipe/tests/IngredientGroups.test.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import IngredientGroups from '../components/IngredientGroups';
-import renderer from 'react-test-renderer';
-
-import data from './data';
-
-test('Ingredient Group component test', () => {
- const check = jest.fn();
- const component = renderer.create(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/frontend/modules/recipe/tests/Ingredients.test.js b/frontend/modules/recipe/tests/Ingredients.test.js
index 411860a7..400bd17b 100644
--- a/frontend/modules/recipe/tests/Ingredients.test.js
+++ b/frontend/modules/recipe/tests/Ingredients.test.js
@@ -5,9 +5,8 @@ import renderer from 'react-test-renderer';
import data from './data';
test('Ingredient component test', () => {
- const check = jest.fn();
const component = renderer.create(
-
+
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
diff --git a/frontend/modules/recipe/tests/RecipeFooter.test.js b/frontend/modules/recipe/tests/RecipeFooter.test.js
deleted file mode 100644
index 13da2aae..00000000
--- a/frontend/modules/recipe/tests/RecipeFooter.test.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import RecipeFooter from '../components/RecipeFooter';
-import createComponentWithIntlAndRouter from '../../../jest_mocks/createComponentWithIntlAndRouter';
-
-test('Test Footer without Edit Link', () => {
- const component = createComponentWithIntlAndRouter(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('Test Footer with Edit Link', () => {
- const component = createComponentWithIntlAndRouter(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/frontend/modules/recipe/tests/RecipeHeader.test.js b/frontend/modules/recipe/tests/RecipeHeader.test.js
deleted file mode 100644
index b736dd40..00000000
--- a/frontend/modules/recipe/tests/RecipeHeader.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import RecipeHeader from '../components/RecipeHeader';
-import createComponentWithIntl from '../../../jest_mocks/createComponentWithIntl.js';
-
-test('Test Header', () => {
- const component = createComponentWithIntl(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('Test Header w/ no Photo', () => {
- const component = createComponentWithIntl(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
-
-test('Test Header w/ bad rating', () => {
- const component = createComponentWithIntl(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/frontend/modules/recipe/tests/SubRecipes.test.js b/frontend/modules/recipe/tests/SubRecipes.test.js
deleted file mode 100644
index 626db85e..00000000
--- a/frontend/modules/recipe/tests/SubRecipes.test.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import SubRecipes from '../components/SubRecipes';
-import createComponentWithIntlAndRouter from '../../../jest_mocks/createComponentWithIntlAndRouter.js';
-
-import data from './data';
-
-test('Test Sub Recipes', () => {
- const check = jest.fn();
- const component = createComponentWithIntlAndRouter(
-
- );
- let tree = component.toJSON();
- expect(tree).toMatchSnapshot();
-});
diff --git a/frontend/modules/recipe/tests/__snapshots__/InfoPanel.test.js.snap b/frontend/modules/recipe/tests/__snapshots__/InfoPanel.test.js.snap
deleted file mode 100644
index e177d74f..00000000
--- a/frontend/modules/recipe/tests/__snapshots__/InfoPanel.test.js.snap
+++ /dev/null
@@ -1,151 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Long Info Panel 1`] = `
-
-
-
-
-
- Servings
- |
-
- Prep time
- |
-
- Cooking time
- |
-
-
-
-
-
-
-
- 200000
-
- |
-
- 200000
-
- minutes
- |
-
- 200000
-
- minutes
- |
-
-
-
-
-
- Lorem ipsum dolor sit amet, odio sem vel nulla aliquam, vestibulum pellentesque at risus eros, at leo mi urna quam, magna nunc vestibulum nibh condimentum arcu. Eu nunc blandit arcu magna, morbi eleifend dolor, nam ratione justo ullamcorper platea malesuada donec, fusce luctus varius. Vel ipsum nunc in justo, pulvinar magna interdum ut nunc vestibulum. Lorem dui vitae. Lectus elit vel lorem purus, in tortor, mi diam mus venenatis sit bibendum eu. Odio nec lectus quisquam ac eleifend sem, arcu congue neque neque nunc, nam maecenas, nec mauris pede erat dignissim, in gravida tempor. In amet mauris odio vitae montes. Nec vitae nostrud vestibulum, at in tincidunt justo varius wisi ut, nullam wisi erat lorem tempor ac. Lorem ipsum dolor sit amet, odio sem vel nulla aliquam, vestibulum pellentesque at risus eros, at leo mi urna quam, magna nunc vestibulum nibh condimentum arcu. Eu nunc blandit arcu magna, morbi eleifend dolor, nam ratione justo ullamcorper platea malesuada donec, fusce luctus varius. Vel ipsum nunc in justo, pulvinar magna interdum ut nunc vestibulum. Lorem dui vitae. Lectus elit vel lorem purus, in tortor, mi diam mus venenatis sit bibendum eu. Odio nec lectus quisquam ac eleifend sem, arcu congue neque neque nunc, nam maecenas, nec mauris pede erat dignissim, in gravida tempor. In amet mauris odio vitae montes. Nec vitae nostrud vestibulum, at in tincidunt justo varius wisi ut, nullam wisi erat lorem tempor ac.
-
-
-
-`;
-
-exports[`Short Info Panel 1`] = `
-
-
-
-
-
- Servings
- |
-
- Prep time
- |
-
- Cooking time
- |
-
-
-
-
-
-
-
- 8
-
- |
-
- 40
-
- minutes
- |
-
- 20
-
- minutes
- |
-
-
-
-
-
-`;
diff --git a/frontend/modules/recipe/tests/__snapshots__/IngredientButtons.test.js.snap b/frontend/modules/recipe/tests/__snapshots__/IngredientButtons.test.js.snap
deleted file mode 100644
index e0c28cff..00000000
--- a/frontend/modules/recipe/tests/__snapshots__/IngredientButtons.test.js.snap
+++ /dev/null
@@ -1,372 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Ingredient Buttons Complete 1`] = `
-
-
-
- Check All
-
-
- Clear
-
-
-
-
-
-`;
-
-exports[`Ingredient Buttons Default 1`] = `
-
-
-
- Check All
-
-
- Clear
-
-
-
-
-
-`;
-
-exports[`Ingredient Buttons Error 1`] = `
-
-
-
- Check All
-
-
- Clear
-
-
-
-
-
-`;
-
-exports[`Ingredient Buttons Loading 1`] = `
-
-
-
- Check All
-
-
- Clear
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
diff --git a/frontend/modules/recipe/tests/__snapshots__/IngredientGroups.test.js.snap b/frontend/modules/recipe/tests/__snapshots__/IngredientGroups.test.js.snap
deleted file mode 100644
index cf4b5fe5..00000000
--- a/frontend/modules/recipe/tests/__snapshots__/IngredientGroups.test.js.snap
+++ /dev/null
@@ -1,146 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Ingredient Group component test 1`] = `
-
-
-
- Chili
-
-
- -
-
-
- 1
-
-
-
- dash
-
-
-
- black pepper
-
-
-
-
-
-
- Spices
-
-
- -
-
-
- 1
-
-
-
- dash
-
-
-
- black pepper
-
-
-
-
-
-
- -
-
-
- 1
-
-
-
- dash
-
-
-
- black pepper
-
-
-
-
-
-`;
diff --git a/frontend/modules/recipe/tests/__snapshots__/Ingredients.test.js.snap b/frontend/modules/recipe/tests/__snapshots__/Ingredients.test.js.snap
index 1c45a11d..ef638802 100644
--- a/frontend/modules/recipe/tests/__snapshots__/Ingredients.test.js.snap
+++ b/frontend/modules/recipe/tests/__snapshots__/Ingredients.test.js.snap
@@ -7,21 +7,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -43,21 +28,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -79,21 +49,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -115,21 +70,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -151,21 +91,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -187,21 +112,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -223,21 +133,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -259,21 +154,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -295,21 +175,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -331,21 +196,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -367,21 +217,6 @@ exports[`Ingredient component test 1`] = `
-
@@ -403,21 +238,6 @@ exports[`Ingredient component test 1`] = `
-
diff --git a/frontend/modules/recipe/tests/__snapshots__/RecipeFooter.test.js.snap b/frontend/modules/recipe/tests/__snapshots__/RecipeFooter.test.js.snap
deleted file mode 100644
index e37f22af..00000000
--- a/frontend/modules/recipe/tests/__snapshots__/RecipeFooter.test.js.snap
+++ /dev/null
@@ -1,84 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Test Footer with Edit Link 1`] = `
-
-
-
-
-
- Created by
- :
-
-
- Last Updated
- :
- 2017-01-01
-
-
-
-
-
-`;
-
-exports[`Test Footer without Edit Link 1`] = `
-
-
-
-
-
- Created by
- :
-
-
- Last Updated
- :
- 2017-01-01
-
-
-
-
-
-`;
diff --git a/frontend/modules/recipe/tests/__snapshots__/RecipeHeader.test.js.snap b/frontend/modules/recipe/tests/__snapshots__/RecipeHeader.test.js.snap
deleted file mode 100644
index 759a461a..00000000
--- a/frontend/modules/recipe/tests/__snapshots__/RecipeHeader.test.js.snap
+++ /dev/null
@@ -1,134 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Test Header 1`] = `
-
-
-
-
- Tasty Chili
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Test Header w/ bad rating 1`] = `
-
-
-
-
- Tasty Chili
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`Test Header w/ no Photo 1`] = `
-
-
-
-
- Tasty Chili
-
-
-
-
-
-
-
-
-
-
-
-`;
diff --git a/frontend/modules/recipe/tests/__snapshots__/SubRecipes.test.js.snap b/frontend/modules/recipe/tests/__snapshots__/SubRecipes.test.js.snap
deleted file mode 100644
index 116366ea..00000000
--- a/frontend/modules/recipe/tests/__snapshots__/SubRecipes.test.js.snap
+++ /dev/null
@@ -1,84 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Test Sub Recipes 1`] = `
-
-`;
diff --git a/frontend/modules/recipe/tests/data.js b/frontend/modules/recipe/tests/data.js
index dfb29d22..7465f5a3 100644
--- a/frontend/modules/recipe/tests/data.js
+++ b/frontend/modules/recipe/tests/data.js
@@ -1 +1 @@
-export default {"id":1,"photo":null,"photo_thumbnail":null,"ingredients":[{"id":1,"title":"black pepper","quantity":1,"measurement":"dash","recipe":1},{"id":2,"title":"chili powder","quantity":4,"measurement":"tablespoons","recipe":1},{"id":3,"title":"cumin","quantity":1,"measurement":"tablespoon","recipe":1},{"id":4,"title":"dark kidney beans","quantity":1,"measurement":"can","recipe":1},{"id":5,"title":"diced tomatos","quantity":2,"measurement":"cans","recipe":1},{"id":6,"title":"green bell pepper","quantity":1,"measurement":"whole","recipe":1},{"id":7,"title":"ground pork","quantity":1,"measurement":"pound","recipe":1},{"id":8,"title":"ground sirloin","quantity":1,"measurement":"pound","recipe":1},{"id":9,"title":"kosher salt","quantity":1,"measurement":"dash","recipe":1},{"id":10,"title":"light kidney beans","quantity":1,"measurement":"can","recipe":1},{"id":11,"title":"serrano pepper ","quantity":1,"measurement":"whole","recipe":1},{"id":12,"title":"white onion","quantity":1,"measurement":"whole","recipe":1}],"ingredient_groups":[{"title":"Chili", "ingredients":[{"id":1,"title":"black pepper","quantity":1,"measurement":"dash","recipe":1}]},{"title":"Spices", "ingredients":[{"id":1,"title":"black pepper","quantity":1,"measurement":"dash","recipe":1}]},{"title":"", "ingredients":[{"id":1,"title":"black pepper","quantity":1,"measurement":"dash","recipe":1}]}],"subrecipes":[{"child_recipe_id":1,"title":"black pepper","quantity":1,"measurement":"dash","recipe":1},{"child_recipe_id":2,"title":"chili powder","quantity":4,"measurement":"tablespoons","recipe":1}],"directions":[{"id":1,"step":1,"title":"Brown the ground pork and ground sirlion in a medium pan. Add a teaspoon of sereano pepper while browning the meat. Season with kosher salt and pepper.","recipe":1},{"id":2,"step":2,"title":"Chop the onion, bell pepper and one Serrano pepper and place them in a large pot.","recipe":1},{"id":3,"step":3,"title":"Open up and drain both cans of kidney beans and add them to the large pot.","recipe":1},{"id":4,"step":4,"title":"Open up both cans of stewed chili style tomatoes and add them to the pot.","recipe":1},{"id":5,"step":5,"title":"Drain the grease away from the browned meat and add the meat to the pot.","recipe":1},{"id":6,"step":6,"title":"Pour in the tomato juice over the meat mixture.","recipe":1},{"id":7,"step":7,"title":"Add kosher salt, black pepper, two table spoons of chili powder, and two teaspoons of ground cumin. Stir well.","recipe":1},{"id":8,"step":8,"title":"Cook slowly over medium low heat for an hour. If it starts to bubble turn down the heat. Taste during the cooking process to check the seasoning add more to taste.","recipe":1}],"tags":[],"username":"ryan","title":"Tasty Chili","info":"This chili is requested every winter by friends and family. I have been making this chili every since I was a small child and learned from my grandma","source":"","prep_time":60,"cook_time":60,"servings":8,"rating":3,"pub_date":"May 21, 2011","update_date":"May 21, 2011","author":1,"cuisine":1,"course":2};
\ No newline at end of file
+export default {"id":1,"photo":null,"photo_thumbnail":null,"ingredients":[{"id":1,"title":"black pepper","quantity":1,"measurement":"dash","recipe":1},{"id":2,"title":"chili powder","quantity":4,"measurement":"tablespoons","recipe":1},{"id":3,"title":"cumin","quantity":1,"measurement":"tablespoon","recipe":1},{"id":4,"title":"dark kidney beans","quantity":1,"measurement":"can","recipe":1},{"id":5,"title":"diced tomatos","quantity":2,"measurement":"cans","recipe":1},{"id":6,"title":"green bell pepper","quantity":1,"measurement":"whole","recipe":1},{"id":7,"title":"ground pork","quantity":1,"measurement":"pound","recipe":1},{"id":8,"title":"ground sirloin","quantity":1,"measurement":"pound","recipe":1},{"id":9,"title":"kosher salt","quantity":1,"measurement":"dash","recipe":1},{"id":10,"title":"light kidney beans","quantity":1,"measurement":"can","recipe":1},{"id":11,"title":"serrano pepper ","quantity":1,"measurement":"whole","recipe":1},{"id":12,"title":"white onion","quantity":1,"measurement":"whole","recipe":1}],"directions":[{"id":1,"step":1,"title":"Brown the ground pork and ground sirlion in a medium pan. Add a teaspoon of sereano pepper while browning the meat. Season with kosher salt and pepper.","recipe":1},{"id":2,"step":2,"title":"Chop the onion, bell pepper and one Serrano pepper and place them in a large pot.","recipe":1},{"id":3,"step":3,"title":"Open up and drain both cans of kidney beans and add them to the large pot.","recipe":1},{"id":4,"step":4,"title":"Open up both cans of stewed chili style tomatoes and add them to the pot.","recipe":1},{"id":5,"step":5,"title":"Drain the grease away from the browned meat and add the meat to the pot.","recipe":1},{"id":6,"step":6,"title":"Pour in the tomato juice over the meat mixture.","recipe":1},{"id":7,"step":7,"title":"Add kosher salt, black pepper, two table spoons of chili powder, and two teaspoons of ground cumin. Stir well.","recipe":1},{"id":8,"step":8,"title":"Cook slowly over medium low heat for an hour. If it starts to bubble turn down the heat. Taste during the cooking process to check the seasoning add more to taste.","recipe":1}],"tags":[],"username":"ryan","title":"Tasty Chili","info":"This chili is requested every winter by friends and family. I have been making this chili every since I was a small child and learned from my grandma","source":"","prep_time":60,"cook_time":60,"servings":8,"rating":3,"pub_date":"May 21, 2011","update_date":"May 21, 2011","author":1,"cuisine":1,"course":2};
\ No newline at end of file
diff --git a/frontend/modules/recipe_form/actions/ImportActions.js b/frontend/modules/recipe_form/actions/ImportActions.js
index 7834d7b8..108f6536 100644
--- a/frontend/modules/recipe_form/actions/ImportActions.js
+++ b/frontend/modules/recipe_form/actions/ImportActions.js
@@ -3,7 +3,7 @@ import AppDispatcher from '../../common/AppDispatcher';
import RecipeConstants from '../constants/RecipeConstants';
import ImportConstants from '../constants/ImportConstants';
import { serverURLs } from '../../common/config'
-import history from '../../common/history'
+import { browserHistory } from 'react-router'
class RecipeActions {
importRecipe(url) {
@@ -29,7 +29,7 @@ class RecipeActions {
actionType: RecipeConstants.IMPORT,
recipe: result,
});
- history.push('/recipe/create');
+ browserHistory.push('/recipe/create');
}
} else {
console.error(err.toString());
diff --git a/frontend/modules/recipe_form/components/Auto.js b/frontend/modules/recipe_form/components/Auto.js
index 5e06eca3..ca291a2f 100644
--- a/frontend/modules/recipe_form/components/Auto.js
+++ b/frontend/modules/recipe_form/components/Auto.js
@@ -7,38 +7,36 @@ import {
formatMessage
} from 'react-intl';
-class Auto extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
+export var Auto = injectIntl(React.createClass({
+ getInitialState: function() {
+ return {
val: this.props.value || '',
data: this.props.data || [],
allowFilter: this.props.allowFilter !== false,
};
- }
+ },
componentWillReceiveProps(nextProps) {
if (nextProps.data !== this.state.data) {
this.setState({data: nextProps.data});
}
- }
+ },
- handleChange = event => {
+ handleChange(event) {
this.setState({val: event.target.value});
if(this.props.change) {
this.props.change(event.target.name, event.target.value);
}
- };
+ },
- handleSelect = value => {
+ handleSelect(value) {
this.setState({val: value});
if(this.props.change) {
this.props.change(this.props.name, value);
}
- };
+ },
- matchStateToTerm = (state, value) => {
+ matchStateToTerm (state, value) {
if (this.state.allowFilter) {
return (
state.toLowerCase().indexOf(value.toLowerCase()) !== -1
@@ -46,22 +44,22 @@ class Auto extends React.Component {
} else {
return true;
}
- };
+ },
- sortStates = (a, b, value) => {
+ sortStates (a, b, value) {
return (
a.toLowerCase().indexOf(value.toLowerCase()) >
b.toLowerCase().indexOf(value.toLowerCase()) ? 1 : -1
)
- };
+ },
- renderItems = items => {
+ renderItems (items) {
return items.map((item) => {
return item
})
- };
+ },
- render() {
+ render: function () {
const {formatMessage} = this.props.intl;
const messages = defineMessages({
loading: {
@@ -109,6 +107,4 @@ class Auto extends React.Component {
)
}
-}
-
-export default injectIntl(Auto)
+}));
diff --git a/frontend/modules/recipe_form/components/DataListItem.js b/frontend/modules/recipe_form/components/DataListItem.js
index 1e7e08b8..5c9a2f9d 100644
--- a/frontend/modules/recipe_form/components/DataListItem.js
+++ b/frontend/modules/recipe_form/components/DataListItem.js
@@ -8,7 +8,7 @@ import {
import RecipeActions from '../actions/RecipeActions'
import { TextArea, Input } from '../../common/form/FormComponents'
-import Auto from './Auto'
+import { Auto } from './Auto'
import { measurements } from '../../common/config'
class Direction extends React.Component {
diff --git a/frontend/modules/recipe_form/components/ImportForm.js b/frontend/modules/recipe_form/components/ImportForm.js
index 8296c1a4..0c6db2e0 100644
--- a/frontend/modules/recipe_form/components/ImportForm.js
+++ b/frontend/modules/recipe_form/components/ImportForm.js
@@ -5,8 +5,6 @@ import {
defineMessages,
formatMessage
} from 'react-intl';
-
-import authCheckRedirect from '../../common/authCheckRedirect'
import ImportActions from '../actions/ImportActions';
import { ImportStore, CHANGE_EVENT } from '../stores/ImportStore';
@@ -43,7 +41,6 @@ class ImportForm extends React.Component {
}
componentDidMount() {
- authCheckRedirect();
ImportActions.init();
ImportStore.addChangeListener(CHANGE_EVENT, this._onChange);
}
diff --git a/frontend/modules/recipe_form/components/RecipeForm.js b/frontend/modules/recipe_form/components/RecipeForm.js
index e02c8749..cf22aba4 100644
--- a/frontend/modules/recipe_form/components/RecipeForm.js
+++ b/frontend/modules/recipe_form/components/RecipeForm.js
@@ -1,4 +1,5 @@
import React from 'react'
+import { browserHistory } from 'react-router'
import {
injectIntl,
IntlProvider,
@@ -6,7 +7,6 @@ import {
formatMessage
} from 'react-intl';
import AuthStore from '../../account/stores/AuthStore'
-import authCheckRedirect from '../../common/authCheckRedirect'
import { RecipeStore, INIT_EVENT, ERROR_EVENT, CHANGE_EVENT } from '../stores/RecipeStore';
import RecipeActions from '../actions/RecipeActions';
@@ -47,8 +47,7 @@ class RecipeForm extends React.Component {
}
componentDidMount() {
- authCheckRedirect();
- RecipeActions.init(this.props.match.params.id);
+ RecipeActions.init(this.props.params.id);
RecipeActions.fetchRecipeList('');
RecipeStore.addChangeListener(INIT_EVENT, this._onInit);
RecipeStore.addChangeListener(CHANGE_EVENT, this._onChange);
@@ -68,7 +67,7 @@ class RecipeForm extends React.Component {
if (Object.keys(state.data).length > 0) {
const user = this.getAuthUser();
if (state.data.author !== user.id && state.data.id) {
- this.props.history.replace('/recipe/' + state.data.id);
+ browserHistory.replace('/recipe/' + state.data.id);
}
}
}
diff --git a/frontend/modules/recipe_form/components/TagList.js b/frontend/modules/recipe_form/components/TagList.js
index fbd42a9e..c215213c 100644
--- a/frontend/modules/recipe_form/components/TagList.js
+++ b/frontend/modules/recipe_form/components/TagList.js
@@ -1,34 +1,32 @@
import React from 'react'
-class TagList extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
+export default React.createClass({
+ getInitialState: function() {
+ return {
tags: this.props.tags || [],
input: this.unarrayify(this.props.tags || []),
errors: this.props.errors || false,
};
- }
+ },
- unarrayify = value => {
+ unarrayify(value) {
return value.map((tag, key) => {
return tag.title
}).join(', ');
- };
+ },
- arrayify = value => {
- let dict = [];
+ arrayify(value) {
+ var dict = [];
if (value) {
- let tags = value.split(',');
+ var tags = value.split(',');
for (let title in tags) {
dict.push({'title': tags[title].trim()})
}
}
return dict
- };
+ },
- handleChange = event => {
+ handleChange(event) {
this.setState({
tags: this.arrayify(event.target.value),
input: event.target.value
@@ -37,9 +35,9 @@ class TagList extends React.Component {
if(this.props.change) {
this.props.change(event.target.name, this.arrayify(event.target.value));
}
- };
+ },
- componentWillReceiveProps(nextProps) {
+ componentWillReceiveProps: function(nextProps) {
if (this.props.tags === undefined && this.props.tags != nextProps.tags) {
this.setState({
tags: nextProps.tags,
@@ -52,9 +50,9 @@ class TagList extends React.Component {
errors: nextProps.errors
});
}
- }
+ },
- render() {
+ render: function () {
let className = "form-group";
let errorMessage = false;
if (this.state.errors !== false) {
@@ -80,6 +78,4 @@ class TagList extends React.Component {
)
}
-}
-
-export default TagList
+});
diff --git a/frontend/modules/recipe_form/stores/RecipeStore.js b/frontend/modules/recipe_form/stores/RecipeStore.js
index 09467216..5516940c 100644
--- a/frontend/modules/recipe_form/stores/RecipeStore.js
+++ b/frontend/modules/recipe_form/stores/RecipeStore.js
@@ -1,5 +1,5 @@
import { EventEmitter } from 'events';
-import history from '../../common/history'
+import { browserHistory } from 'react-router'
import AppDispatcher from '../../common/AppDispatcher';
import RecipeConstants from '../constants/RecipeConstants';
@@ -126,7 +126,7 @@ RecipeStore.dispatchToken = AppDispatcher.register(action => {
break;
case RecipeConstants.SUBMIT:
- history.push('/recipe/' + action.new_recipe_id);
+ browserHistory.push('/recipe/' + action.new_recipe_id);
_formData = {};
_errors = false;
RecipeStore.emitChange();
diff --git a/frontend/modules/recipe_form/tests/__snapshots__/Ingredient.test.js.snap b/frontend/modules/recipe_form/tests/__snapshots__/Ingredient.test.js.snap
index 8ac3ac28..eb8b438f 100644
--- a/frontend/modules/recipe_form/tests/__snapshots__/Ingredient.test.js.snap
+++ b/frontend/modules/recipe_form/tests/__snapshots__/Ingredient.test.js.snap
@@ -57,7 +57,6 @@ exports[`IngredientList component test 1`] = `
>