Todos Redux

by vikikamath

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>
<main></main>
<script id="filter" type="text/ractive">
	<ul>
  	{{#filters}}
    	<li class="{{#if active === .}}active{{/if}}" on-click="setVisible:{{.}}">{{.}}</li>
    {{/}}
  </ul>

</script>

<script id="todos" type="text/ractive">
		<div>
    	<input type="text" value="{{val}}" placeholder="Enter some text"/>
    </div>
    <button on-click="add">Add</button>
    <ul id="todos">
      {{#todos:i}}
        <li on-click="toggle:{{i}}" class="{{#if completed}}completed{{/if}}">{{text}}</li>
      {{/todos}}
    </ul>
</script>

<script id="app" type="text/ractive">
	<TodoList todos="{{store.getState().todos}}"/>
	<FilterList active="{{store.getState().visibility}}"/>
</script>

CSS

ul {
  list-style: none;
}

ul li {
   display: inline;
   margin: 1rem;
}

ul li.active {
  text-decoration: underline;
}

#todos li {
  display: block;
}

#todos li.completed {
  text-decoration: line-through;
}

JavaScript

// define actions
const setVisibility = (filter) => {
		return {
    	type: 'SELECT_FILTER'
    	,filter
    }
  	
  }
  
const addTodo = (text) => {
	return  {
  	type: 'ADD_TODO'
    ,text
  }
}

const toggleTodo = (index) => {
	return {
  	type: 'TOGGLE_TODO'
    ,index
  }
}

// define reducers

const visibility = (state={}, action) => {
	switch (action.type) {
  	case 'SELECT_FILTER':
    	//console.log('prev state', state)
    	return action.filter
    	
    default:
    	return state;
  }
}

const todos = (state =[], action) => {
	switch (action.type) {
  	case 'ADD_TODO':
    	console.log(state)
    	return [ 
      	...state
        ,{
        	text: action.text
          ,completed: false
        }
      ]
    case 'TOGGLE_TODO':
    	return state.map((todo, index)=>{
      	if (index === action.index) todo.completed = !todo.completed
        return todo;
      })
   default:
   		return state
  }
}

// define components

const TodoList = Ractive.extend({
	template: `#todos`
  ,oninit() {
  	var self = this;
    self.on('add', (e) => {
    	store.dispatch(addTodo(e.context.val));
    })
    self.on('toggle', (e) => {
    	console.log(e.index.i);
    	store.dispatch(toggleTodo(e.index.i))
    })
  }
  ,data() {
  	return {
    	val: undefined
    }
  }
})

const FilterList = Ractive.extend({
	template: `#filter`
  ,data() {
  	return {
    	filters: [
      	'ALL'
        ,'COMPLETE'
        ,'PENDING'
      ]
    }
   }
  ,oninit() {
  	var self = this;
    self.on('setVisible', (e) =>{
    	store.dispatch(setVisibility(e.context))
    })
  }
})

// describe initial state
const initialState = {
	todos: []
  ,visibility: 'ALL'
}

// define the store
const store = Redux.createStore(Redux.combineReducers({
	todos,
  visibility
}) ,initialState)

// subscribe to store changes
store.subscribe(() => app.update())

const app = new Ractive({
	el: 'main'
  ,template: `#app`
  ,components: {
  	FilterList
    ,TodoList
  }
  ,data() {
  	return {
    	store
   ...