Electron と React でPomodoro Timerアプリを作ってみる

##はじめに
React.js, JSX, ElectronでPomodoro Technique（ポモドーロテクニック）を実践できるタイマーアプリを作ってみました。

[https://github.com/massa142/pomodoro](https://github.com/massa142/pomodoro)



![pomodoro_timer.png](https://qiita-image-store.s3.amazonaws.com/0/19111/8fdce4bf-ab6c-498f-9052-2ed7f6045087.png "pomodoro_timer.png")


##作った理由
PHPカンファレンス2015でのKenji Akiyamaさんの発表資料を見て、「Electron面白そう！ちょっと試してみよ」となったためです。
[Electronからクロスプラットフォーム・アプリケーションの歴史を考える](https://speakerdeck.com/artifactsauce/electronkarakurosupuratutohuomuapurikesiyonfalseli-shi-wokao-eru)

ただ作りたいものがパッと思いつかなかったので、Akiyamaさんと同じPomodoro Technique用のタイマーアプリをReact.jsで作ってみることにしました。

##Pomodoro Techniqueとは

> 1.達成しようとするタスクを選ぶ
2.キッチンタイマーで25分を設定する
3.タイマーが鳴るまでタスクに集中する
4.少し休憩する（5分程度でOK）
5.ステップ2～4を4回繰り返したら、少し長めに休憩する

[今日から始める生産性アップ術。ポモドーロ・テクニック再入門ガイド](http://www.lifehacker.jp/2014/07/140714pomodoro.html)

rebuild.fm ep.93でもちょっと話題にあがってました。
http://rebuild.fm/93/

##環境構築
ElectronもReactも今回初めて触ったので開発環境整えるのどうしようかなーと思ってたら、@Quramyさんが「[ぼくのかんがえたさいきょうのElectron](http://qiita.com/Quramy/items/90d61ff37ca1b95a7f6d)」開発環境を作ってくれていました。
ありがたくこのboilerplateを使わせて頂きました。

##内部構成

```
.
├── README.md
├── bower.json
├── bower_components
├── dist
├── gulpfile.js
├── node_modules
├── package.json
├── release
└── src
    ├── app.js
    ├── assets
    │   └── images
    │       ├── electron.svg
    │       └── electron2.svg
    ├── browser
    │   └── menu
    │       └── appMenu.js
    ├── renderer
    │   ├── bootstrap.js
    │   ├── components
    │   │   └── main.jsx
    │   └── index.html
    └── styles
        └── main.scss
``` 

###main.jsx
```
'use strict';

import React from 'react';
import notifier from 'node-notifier';

export class Main extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      isStart: false,
      isBreak: false,
      time: this.props.duration
    }
    this.handleStartClicked = ::this.handleStartClicked;
    this.handleResetClicked = ::this.handleResetClicked;
    this.tick = ::this.tick;
  }

  handleStartClicked() {
    if (!this.state.isStart) {
      this.interval = setInterval(this.tick, 1000);
      this.setState({isStart: true});
    } else {
      clearInterval(this.interval);
      this.setState({isStart: false});
    }
  }

  handleResetClicked() {
    this.reset();
  }

  tick() {
    this.setState({time: this.state.time - 1});
    if (this.state.time === 0) {
      this.finishEvent();
    }
  }

  finishEvent() {
    if (this.state.isBreak) {
      this.reset();
      this.notify('Break is over!');
    } else {
      this.break();
      this.notify('Good work!');
    }
  }

  break() {
    this.setState({
      isStart: true,
      isBreak: true,
      time: this.props.breakTime
    });
  }

  reset() {
    clearInterval(this.interval);
    this.setState({
      isStart: false,
      isBreak: false,
      time: this.props.duration
    });
  }

  notify(message) {
    notifier.notify({
      'title': 'Pomodoro Timer',
      'message': message
    });
  }

  converter = {
    s2m(s) {
      let minutes = Math.floor(s / 60);
      let seconds = s % 60;
      return ('0' + minutes.toString()).slice(-2) + ':' + ('0' + seconds.toString()).slice(-2);
    }
  };

  render() {
    return (
      <div className="container">
        <div className="jumbotron main">
          <h2>Pomodoro Timer</h2>
          <img src={this.state.isBreak ? "../assets/images/electron2.svg" : "../assets/images/electron.svg"} alt="" width="128px"></img>
          <h2>{this.converter.s2m(this.state.time)}</h2>
          <div>
            <button type="button" className="btn btn-primary" onClick={this.handleStartClicked}>
              {this.state.isStart ? "Pause" : "Start"}
            </button>
            <button type="button" className="btn btn-warning" onClick={this.handleResetClicked}>Reset</button>
          </div>
        </div>
      </div>
    );
  }
}

Main.defaultProps = {
  duration: 1500,
  breakTime: 300
};
```

##感想
+ 本当にデスクトップアプリケーションが簡単に作れた。楽しい！
+ @Quramyさんのboilerplateは本当にさいきょう。すごい！
+ Electronで作ったアプリがApp Storeに登録できるようになってる。未来感すごい！ [https://github.com/atom/electron/blob/master/docs/tutorial/mac-app-store-submission-guide.md](https://github.com/atom/electron/blob/master/docs/tutorial/mac-app-store-submission-guide.md)