Skip to content

Commit

Permalink
Refactor application into folders
Browse files Browse the repository at this point in the history
  • Loading branch information
anatalph committed Oct 4, 2019
1 parent 1af604f commit 3d6e20e
Show file tree
Hide file tree
Showing 17 changed files with 390 additions and 10 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"goals-todos-api": "^1.0.0",
"react": "^16.10.1",
"react-dom": "^16.10.1",
"react-redux": "^7.1.1",
Expand Down
43 changes: 43 additions & 0 deletions src/actions/goals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import API from 'goals-todos-api'

export const ADD_GOAL = 'ADD_GOAL'
export const REMOVE_GOAL = 'REMOVE_GOAL'

function addGoal(goal) {
return {
type: ADD_GOAL,
goal
}
}

function removeGoal(id) {
return {
type: REMOVE_GOAL,
id
}
}

export function handleAddGoal(name, callback) {
return (dispatch) => {
return API.saveGoal(name)
.then((goal) => {
dispatch(addGoal(goal))
callback()
})
.catch(() => {
alert('An error occurred. Try again.')
})
}
}

export function handleDeleteGoal(goal) {
return (dispatch) => {
dispatch(removeGoal(goal.id))
return API.deleteGoal(goal.id)
.catch(() => {
dispatch(addGoal(goal))
alert('An error occurred. Try again.')
})
}
}

22 changes: 22 additions & 0 deletions src/actions/shared.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import API from 'goals-todos-api'

export const RECEIVE_DATA = 'RECEIVE_DATA'

function receiveDataAction(todos, goals) {
return {
type: RECEIVE_DATA,
todos,
goals
}
}

export function handleInitialData() {
return (dispatch) => {
return Promise.all([
API.fetchTodos(),
API.fetchGoals()
]).then(([todos, goals]) => {
dispatch(receiveDataAction(todos, goals))
})
}
}
61 changes: 61 additions & 0 deletions src/actions/todos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import API from 'goals-todos-api'

export const ADD_TODO = 'ADD_TODO'
export const REMOVE_TODO = 'REMOVE_TODO'
export const TOGGLE_TODO = 'TOGGLE_TODO'

function addTodo(todo) {
return {
type: ADD_TODO,
todo
}
}

function removeTodo(id) {
return {
type: REMOVE_TODO,
id
}
}

function toggleTodo(id) {
return {
type: TOGGLE_TODO,
id
}
}

export function handleDeleteTodo(todo) {
return (dispatch) => {
dispatch(removeTodo(todo.id))
return API.deleteTodo(todo.id)
.catch(() => {
dispatch(addTodo(todo))
alert('An error occurred. Try again.')
})
}
}

export function handleAddTodo(name, callback) {
return (dispatch) => {
return API.saveTodo(name)
.then((todo) => {
dispatch(addTodo(todo))
callback()
})
.catch(() => {
alert('An error occurred. Try again.')
})
}
}

export function handleToggle(id) {
return (dispatch) => {
dispatch(toggleTodo(id))
return API.saveTodoToggle(id)
.catch(() => {
dispatch(toggleTodo(id))
alert('An error occurred. Try again.')
})
}
}
40 changes: 31 additions & 9 deletions src/components/App.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
import React from 'react';

function App() {
return (
<div className="App">
Hello world
</div>
);
import React from 'react'
import ConnectedTodos from './Todos'
import ConnectedGoals from './Goals'
import { connect } from 'react-redux'
import {
handleInitialData
} from '../actions/shared'

class App extends React.Component {
componentDidMount() {
const { dispatch } = this.props

dispatch(handleInitialData())
}
render() {
const { loading } = this.props

if (loading === true) {
return <h3>Loading</h3>
}

return (
<div>
<ConnectedTodos />
<ConnectedGoals />
</div>
)
}
}

export default App;
export default connect((state) => ({
loading: state.loading
}))(App)
46 changes: 46 additions & 0 deletions src/components/Goals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react'
import { connect } from 'react-redux'
import List from './List'
import {
handleAddGoal,
handleDeleteGoal
} from '../actions/goals'

class Goals extends React.Component {
addItem = (event) => {
event.preventDefault()

this.props.dispatch(handleAddGoal(
this.input.value,
() => this.input.value = ''
))
}

removeItem = (goal) => {
this.props.dispatch(handleDeleteGoal(goal))
}

render() {
return (
<div>
<h1>Goals</h1>
<input
type="text"
placeholder="Add Goal"
ref={(input) => this.input = input}
/>
<button onClick={this.addItem}>
Add Goal
</button>
<List
items={this.props.goals}
remove={this.removeItem}
/>
</div>
)
}
}

export default connect((state) => ({
goals: state.goals
}))(Goals)
18 changes: 18 additions & 0 deletions src/components/List.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react'

export default function List(props) {
return (
<ul>
{props.items.map((item) => (
<li key={item.id}>
<span
onClick={() => props.toggle && props.toggle(item.id)}
style={{ textDecoration: item.complete ? 'line-through' : 'none' }}>
{item.name}
</span>
<button onClick={() => props.remove(item)}>X</button>
</li>
))}
</ul>
)
}
53 changes: 53 additions & 0 deletions src/components/Todos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react'
import { connect } from 'react-redux'
import List from './List'
import {
handleAddTodo,
handleDeleteTodo,
handleToggle
} from '../actions/todos'

class Todos extends React.Component {
addItem = (event) => {
event.preventDefault()

this.props.dispatch(handleAddTodo(
this.input.value,
() => this.input.value = ''
))
}

removeItem = (todo) => {
this.props.dispatch(handleDeleteTodo(todo))
}

toggleItem = (id) => {
this.props.dispatch(handleToggle(id))
}

render() {
const { todos } = this.props

return (
<div>
<h1>Todo List</h1>
<input
type="text"
placeholder="Add Todo"
ref={(input) => this.input = input} />
<button onClick={this.addItem}>
Add Todo
</button>
<List
items={todos}
remove={this.removeItem}
toggle={this.toggleItem}
/>
</div>
)
}
}

export default connect((state) => ({
todos: state.todos
}))(Todos)
13 changes: 12 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,16 @@ import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
import reducer from './reducers'
import middleware from './middleware'
import { Provider } from 'react-redux'
import { createStore } from 'redux'

ReactDOM.render(<App />, document.getElementById('root'));
const store = createStore(reducer, middleware)

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
,
document.getElementById('root'));
21 changes: 21 additions & 0 deletions src/middleware/checker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ADD_TODO } from '../actions/todos'
import { ADD_GOAL } from '../actions/goals'

const checker = (store) => (next) => (action) => {
if (
action.type === ADD_TODO &&
action.todo.name.toLowerCase().indexOf('bitcoin') !== -1
) {
return alert("Nope. That's a bad idea.")
}
if (
action.type === ADD_GOAL &&
action.goal.name.toLowerCase().indexOf('bitcoin') !== -1
) {
return alert("Nope. That's a bad idea.")
}

return next(action)
}

export default checker
10 changes: 10 additions & 0 deletions src/middleware/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import checker from './checker'
import logger from './logger'
import thunk from 'redux-thunk'
import { applyMiddleware } from 'redux'

export default applyMiddleware(
thunk,
checker,
logger
)
10 changes: 10 additions & 0 deletions src/middleware/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const logger = (store) => (next) => (action) => {
console.group(action.type)
console.log('The action: ', action)
const result = next(action)
console.log('The new state: ', store.getState())
console.groupEnd()
return result
}

export default logger
16 changes: 16 additions & 0 deletions src/reducers/goals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ADD_GOAL, REMOVE_GOAL } from '../actions/goals'

import { RECEIVE_DATA } from '../actions/shared'

export default function goals(state = [], action) {
switch (action.type) {
case ADD_GOAL:
return state.concat([action.goal])
case REMOVE_GOAL:
return state.filter((goal) => goal.id !== action.id)
case RECEIVE_DATA:
return action.goals
default:
return state
}
}
Loading

0 comments on commit 3d6e20e

Please sign in to comment.