diff --git a/src/app/tasks.coffee b/src/app/tasks.coffee
index 9ce05e1c89..a8667dc50b 100644
--- a/src/app/tasks.coffee
+++ b/src/app/tasks.coffee
@@ -2,6 +2,7 @@ scoring = require './scoring'
helpers = require './helpers'
_ = require 'underscore'
moment = require 'moment'
+character = require './character'
module.exports.view = (view) ->
view.fn 'taskClasses', (type, completed, value, repeat) ->
@@ -33,17 +34,6 @@ module.exports.view = (view) ->
module.exports.app = (appExports, model) ->
user = model.at('_user')
- user.on 'set', 'tasks.*.completed', (i, completed, previous, isLocal, passed) ->
- return if passed? && passed.cron # Don't do this stuff on cron
- direction = () ->
- return 'up' if completed==true and previous == false
- return 'down' if completed==false and previous == true
- throw new Error("Direction neither 'up' nor 'down' on checkbox set.")
-
- # Score the user based on todo task
- task = user.at("tasks.#{i}")
- scoring.score(model, i, direction())
-
appExports.addTask = (e, el, next) ->
type = $(el).attr('data-task-type')
list = model.at "_#{type}List"
@@ -172,12 +162,54 @@ module.exports.app = (appExports, model) ->
target.removeClass(oldContext)
target.addClass(newContext)
- appExports.score = (e, el, next) ->
+
+
+
+ ###
+ Call scoring functions for habits & rewards (todos & dailies handled below)
+ ###
+ appExports.score = (e, el) ->
+ task= model.at $(el).parents('li')[0]
+ taskObj = task.get()
direction = $(el).attr('data-direction')
- direction = 'up' if direction == 'true/'
- direction = 'down' if direction == 'false/'
- task = model.at $(el).parents('li')[0]
- scoring.score(model, task.get('id'), direction)
+
+ # set previous state for undo
+ model.set '_undo',
+ stats: _.clone user.get('stats')
+ task: _.clone taskObj
+
+ scoring.score(model, taskObj.id, direction)
+
+ ###
+ This is how we handle appExports.score for todos & dailies. Due to Derby's special handling of `checked={:task.completd}`,
+ the above function doesn't work so we need a listener here
+ ###
+ user.on 'set', 'tasks.*.completed', (i, completed, previous, isLocal, passed) ->
+ return if passed? && passed.cron # Don't do this stuff on cron
+ direction = if completed then 'up' else 'down'
+
+ # set previous state for undo
+ taskObj = _.clone user.get("tasks.#{i}")
+ taskObj.completed = previous
+ console.log taskObj
+ model.set '_undo',
+ stats: _.clone user.get('stats')
+ task: taskObj
+
+ scoring.score(model, i, direction)
+
+ ###
+ Undo
+ ###
+ appExports.undo = () ->
+ undo = model.get '_undo'
+ batch = character.BatchUpdate(model)
+ batch.startTransaction()
+ _.each undo.stats, (val, key) -> batch.set "stats.#{key}", val
+ taskPath = "tasks.#{undo.task.id}"
+ _.each undo.task, (val, key) -> batch.set "#{taskPath}.#{key}", val
+ batch.commit()
+ model.del '_undo'
appExports.tasksToggleAdvanced = (e, el) ->
$(el).next('.advanced-option').toggleClass('visuallyhidden')
diff --git a/styles/app/alerts.styl b/styles/app/alerts.styl
index 97f490cf52..4cf63147c9 100644
--- a/styles/app/alerts.styl
+++ b/styles/app/alerts.styl
@@ -60,4 +60,10 @@ borderDarken = 20%
background-position: center center
background-size: 14px
width: 14px
- height: 14px
\ No newline at end of file
+ height: 14px
+
+
+.undo-button
+ position:absolute
+ left:5px
+ top:5px
\ No newline at end of file
diff --git a/views/app/index.html b/views/app/index.html
index bcb06b775e..6a88e40aab 100644
--- a/views/app/index.html
+++ b/views/app/index.html
@@ -26,6 +26,9 @@