GameInterface.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. 'use strict';
  2. const React = require('react/addons');
  3. const GameHeader = require('./GameHeader');
  4. const Chat = require('./Chat');
  5. const Modal = require('./Modal');
  6. const GameActions = require('../actions/GameActions');
  7. const GameStore = require('../stores/GameStore');
  8. const ChessboardInterface = require('./ChessboardInterface');
  9. const Immutable = require('immutable');
  10. const {Map} = Immutable;
  11. const GameInterface = React.createClass({
  12. propTypes: {
  13. io: React.PropTypes.object.isRequired,
  14. params: React.PropTypes.array.isRequired
  15. },
  16. getInitialState() {
  17. return {
  18. isOpponentAvailable: false,
  19. color: 'white',
  20. modal: Map({
  21. open: false,
  22. message: '',
  23. type: 'info',
  24. callbacks: {
  25. hide: this._hideModal,
  26. accept: this._acceptRematch,
  27. decline: this._declineRematch
  28. }
  29. }),
  30. soundsEnabled: false,
  31. gameOver: GameStore.getState().gameOver
  32. };
  33. },
  34. componentDidMount() {
  35. const {io, params} = this.props;
  36. io.emit('join', {
  37. token: params[0],
  38. time: params[1] * 60,
  39. inc: params[2]
  40. });
  41. io.on('token-invalid', () => this.setState({
  42. modal: this.state.modal
  43. .set('open', true)
  44. .set('message', 'Game link is invalid or has expired')
  45. .set('type', 'info')
  46. }));
  47. io.on('joined', data => {
  48. if (data.color === 'white') {
  49. io.emit('clock-run', {
  50. token: params[0],
  51. color: 'white'
  52. });
  53. } else {
  54. this.setState({color: 'black'});
  55. }
  56. this.setState({isOpponentAvailable: true});
  57. });
  58. io.on('full', () => {
  59. window.alert(
  60. 'This game already has two players. You have to create a new one.');
  61. window.location = '/';
  62. });
  63. io.on('player-resigned', data => {
  64. GameActions.gameOver({
  65. type: 'resign',
  66. winner: data.color === 'black' ? 'White' : 'Black'
  67. });
  68. });
  69. io.on('rematch-offered', () =>
  70. this._openModal('offer', 'Your opponent has sent you a rematch offer.'));
  71. io.on('rematch-declined', () =>
  72. this._openModal('info', 'Rematch offer has been declined.'));
  73. io.on('rematch-confirmed', () => {
  74. GameActions.rematch();
  75. this.setState({
  76. color: this.state.color === 'white' ? 'black' : 'white',
  77. modal: this.state.modal.set('open', false)
  78. }, () => {
  79. if (this.state.color === 'white') {
  80. io.emit('clock-run', {
  81. token: this.props.params[0],
  82. color: 'white'
  83. });
  84. }
  85. });
  86. });
  87. io.on('opponent-disconnected', () => {
  88. if (!this.state.gameOver.get('status')) {
  89. this._openModal('info', 'Your opponent has disconnected.');
  90. }
  91. this.setState({isOpponentAvailable: false});
  92. });
  93. GameStore.on('change', this._onGameChange);
  94. },
  95. componentWillUnmount() {
  96. GameStore.off('change', this._onGameChange);
  97. },
  98. render() {
  99. const {io, params} = this.props;
  100. const {color, soundsEnabled, gameOver, isOpponentAvailable} = this.state;
  101. const commonProps = {
  102. io: io,
  103. color: color,
  104. openModal: this._openModal,
  105. isOpponentAvailable: isOpponentAvailable
  106. };
  107. return (
  108. <div>
  109. <GameHeader
  110. {...commonProps}
  111. params={params}
  112. gameOver={gameOver.get('status')} />
  113. <label id="sounds-label">
  114. <input type="checkbox"
  115. checked={soundsEnabled}
  116. onChange={this._toggleSounds} />
  117. <span> Enable sounds</span>
  118. </label>
  119. <Chat
  120. {...commonProps}
  121. token={params[0]}
  122. soundsEnabled={soundsEnabled} />
  123. <ChessboardInterface
  124. {...commonProps}
  125. token={params[0]}
  126. soundsEnabled={soundsEnabled}
  127. gameOver={gameOver} />
  128. <Modal data={this.state.modal} />
  129. </div>
  130. );
  131. },
  132. _onGameChange() {
  133. this.setState({gameOver: GameStore.getState().gameOver});
  134. },
  135. _openModal(type, message) {
  136. this.setState({
  137. modal: this.state.modal
  138. .set('open', true)
  139. .set('message', message)
  140. .set('type', type)
  141. });
  142. },
  143. _hideModal() {
  144. this.setState({modal: this.state.modal.set('open', false)});
  145. },
  146. _acceptRematch() {
  147. const {io, params} = this.props;
  148. io.emit('rematch-confirm', {
  149. token: params[0],
  150. time: params[1] * 60,
  151. inc: params[2]
  152. });
  153. this._hideModal();
  154. },
  155. _declineRematch() {
  156. const {io, params} = this.props;
  157. io.emit('rematch-decline', {
  158. token: params[0]
  159. });
  160. this._hideModal();
  161. },
  162. _toggleSounds(e) {
  163. this.setState({
  164. soundsEnabled: !this.state.soundsEnabled
  165. });
  166. },
  167. });
  168. module.exports = GameInterface;