Productively

The Productively timer helps users sustain a productive, 9 hour work day while following Pomodoro time management.

⬇️ Download for Mac!

then: ctrl click > open





Problems ➡️ Solutions

Problem (A): Organizing My Reducers

I started with one Timer reducer, used to control multiple types of timers (i.e. a work timer, short break timer, and long break timer).

I was initially switching between these timers in a long conditional statement in the Timer component. However, this code had a poor smell.


My reducer was very long, and included many actions that would be repetitive to each timer.

var defaultSate ={
  seconds: 1500,
  isRunning: false,
  cycleIndex: 0,
  initTimer: false,
  currentTimer: 0,
  onBreak: false,
  totalTime: 0,
  timeSinceInit: 0
}

function timer(state = defaultState, action){

  const i = action.currentTimer;

  switch(action.type){


    case 'INIT_WORK_TIMER' :

      return {
        ...
      }

    case 'INIT_SHORT_BREAK_TIMER' :

      return {
        ...
      }

    case 'INIT_LONG_BREAK_TIMER' :

      return {
        ...
      }

    case 'INIT_TIMER' :

      return {
        ...
      }

    case 'INCREMENT_TOTAL_TIME' :

      return {
        ...
      }

    case 'INCREMENT_TIME_SINCE_INIT' :

      return {
        ...
      }

    case 'RESET_TOTAL_TIME' :

      return {
        ...
      }

    case 'DECREMENT_TIMER':
      return [
      ...
      ]

    case 'PAUSE_TIMER' :

      return [
      ...
      ]

    case 'RESET_TIMER' :

      return [
        ...
      ]

    case 'INCREMENT_CYCLE_INDEX':

      return [
        ...
      ]

    default:
      return state;
  }
}

Solution (A): Organizing My Reducers

I proceeded to create a Master Timer that includes an array of “timerItem” objects.

var workTimerItem = {
  seconds: 1500,
  isRunning: false,
  cycleIndex: 0,
  id: 0
}

var shortBreakTimerItem = {
  seconds: 300,
  isRunning: false,
  cycleIndex: 0,
  id: 1
}

var longBreakTimerItem = {
  seconds: 1800,
  isRunning: false,
  cycleIndex: 0,
  id: 2
}

var timer = {
  timerItems: [workTimerItem, shortBreakTimerItem, longBreakTimerItem]
}

This has allowed me to more easily move between my different timers. The new reducers are now split into a “timerItem” Reducer and “timer” Reducer.

“timerItem” Reducer 👇

var workTimerItem = {
  seconds: 1500,
  isRunning: false,
  cycleIndex: 0,
  id: 0
}

var shortBreakTimerItem = {
  seconds: 300,
  isRunning: false,
  cycleIndex: 0,
  id: 1
}

var longBreakTimerItem = {
  seconds: 1800,
  isRunning: false,
  cycleIndex: 0,
  id: 2
}

var timer = {
  timerItems: [workTimerItem, shortBreakTimerItem, longBreakTimerItem]
}

function timerItem(state = timer.timerItems,action){
  const i = action.id;

  switch(action.type){

    case 'DECREMENT_TIMER':
      return [
        ...
      ]

    case 'PAUSE_TIMER' :

      return [
        ...
      ]

    case 'RESET_TIMER' :

      return [
        ...
      ]

    case 'INCREMENT_CYCLE_INDEX':

      return [
        ...
      ]

    default:
      return state;
  }
}

“timer” Reducer 👇

var defaultState = {
  initTimer: false,
  currentTimer: 0,
  onBreak: false,
  totalTime: 0,
  timeSinceInit: 0
}

function timer(state = defaultState, action){

  const i = action.currentTimer;

  switch(action.type){


    case 'INIT_WORK_TIMER' :

      return {
        ...
      }

    case 'INIT_SHORT_BREAK_TIMER' :

      return {
        ...
      }

    case 'INIT_LONG_BREAK_TIMER' :

      return {
        ...
      }

    case 'INIT_TIMER' :

      return {
        ...
      }

    case 'INCREMENT_TOTAL_TIME' :

      return {
        ...
      }

    case 'INCREMENT_TIME_SINCE_INIT' :

      return {
        ...
      }

    case 'RESET_TOTAL_TIME' :

      return {
        ...
      }

    default:
      return state;
  }
}

Results

This refactoring has made my code much more logical and organized.



Project Design


🔎 UX

I took a Job Story approach to my user experience.

👀 Visual

My first quick sketch was very simple and only implemented the final main timer with ring.

I then took this concept in addition to my job story and created a Sketch with material design.

I used Google’s material color guides.

In addition to their material shadow guides.

The original Sketch came out as the following…

and the final outcome (actual app)…

The bottom timeline arch is a visual representation of your day. Each small circle is a twenty five minute work timers, each followed by a five minute break timer (not represented on the arch timeline). The arch also includes three, thirty minute long break timers. A long break occurs after four consecutive work timers.

The top timer is used to visually represent your current timer. This time is represented both in minutes:seconds and by a deprecating ring.

⬇️ Download for Mac!

then: ctrl click > open

Conclusion

What Worked?
Redux state proved to be a very nice way to keep time and move between multiple timers.

What were your doubts going into the project?
Timeline for project completion.

What surprised you the most?
How quickly the styling came together.

What would you have done differently?
Further imbed the timer into the mac tray allowing for less upfront UI and a more streamlined user experience.

What did you learn while doing this project?
I learned how to create electron desktop apps and how to implement material design while improving my knowledge of Redux.

How will you use that information in the future?
I will further my Redux development and use both material design and desktop development.

More

See how I worked with React + Redux in my ride sharing discovery app 👉